3.15 视觉对战五子棋实战
一、项目概览:让机械臂完成视觉对战五子棋
如上面短视频演示的,我们将实现用机械臂完成视觉对战五子棋的应用。
本节课代码:点击下载
1.1 本章要解决的核心问题
本章聚焦三个工程问题:
- 如何把普通 USB 相机画面变成可用于机器人抓取的平面坐标
- 如何让机械臂理解“图像中的位置”并准确到达
- 如何把视觉检测、五子棋 AI 和机械臂控制串成完整闭环
1.2 物料清单
| 物料 | 参考图片 | 购买参考链接 |
|---|---|---|
| 带负压吸盘的六轴机械臂 | ![]() |
任意满足条件的机械臂即可 |
| USB 摄像头 | ![]() |
720P 以上即可 |
| 棋盘格 + 棋子 | ![]() |
参考棋盘尺寸:13 路围棋,棋盘尺寸:44 * 47 * 1.2 cm 。参考棋子大小:直径 2.2cm,厚度 0.6cm 。【京东】https://3.cn/2Ie-kzXN 「围棋套装 1913 路初学棋盘」 |
为什么使用普通 USB RGB 相机,而不是深度相机?
本项目使用的是普通 USB RGB 相机,不是深度相机,原因非常工程化:
- 棋盘和储棋区都是平面场景,且棋子高度固定
- 我们关心的是平面位置(x、y)与稳定抓取高度(z 预设),不依赖实时深度图
- 通过“透视标定 + 示教标定”,已能达到课程所需精度
- RGB 相机成本更低、部署更简单、兼容性更好
因此,这是一套“平面视觉 + 坐标映射”的低成本高可复用方案。
二、系统总架构与坐标变换主线
推荐相关课程:
2.1 全流程数据流
完整数据流可以概括为:
相机采集 → 透视校正 → YOLO 检测 → 网格映射/平面坐标 → 示教变换矩阵 → 机械臂执行
同时,AI 模块持续参与:
- 人类落子检测后更新棋盘状态
- AI 计算下一步落子点
- 机械臂从储棋区取子并放到棋盘目标格
2.2 坐标系关系
本项目有两条并行坐标链:
- 棋盘链路:棋盘相机像素 → 棋盘平面坐标(mm) → 机械臂基坐标(mm)
- 储棋链路:储棋区相机像素 → 储棋平面坐标(mm) → 机械臂基坐标(mm)
他么只是区域不同,原理一模一样,统一可以写成:
其中:
是平面坐标系中的点(棋盘或储棋区) 是机械臂基坐标系中的目标点 是通过示教点拟合得到的 变换矩阵
2.3 透视映射的核心直觉

相机通常是斜着拍棋盘,画面中的正方格会变成梯形。透视标定的作用是:
- 用 4 个角点求出单应矩阵
- 把“斜视图”拉正成“俯视图”
- 让像素位置可稳定映射到实际尺寸坐标
常用形式为:
三、标定逻辑与原理
3.1 标定分两层:相机透视标定 + 示教标定
本项目不是传统工业视觉中的完整手眼标定流程(例如经典
- 相机透视标定:解决“看准平面坐标”
- 示教标定:解决“到准机械臂坐标”
两步组合后,就能完成从视觉到抓取的坐标闭环。
3.2 相机透视标定(棋盘区与储棋区)
3.2.1 目标
把相机像素中的任意点映射到平面坐标(mm),用于后续网格定位和抓取定位。
3.2.2 操作思路
- 在图像里点击目标平面的四个角点
- 指定该平面的物理尺寸(mm)
- 计算透视矩阵并输出校正图
- 保存 YAML 参数,供主程序加载
3.2.3 相关脚本
calibration_scripts/2.calibrate_perspective_camera_qt.py:棋盘区透视标定calibration_scripts/3.live_cropped_feed.py:棋盘区透视效果验证calibration_scripts/7.calibrate_storage_camera.py:储棋区透视标定calibration_scripts/9.calibrate_storage_hand_eye.py:储棋区透视效果验证
3.2.4 典型输出
calibration_scripts/camera_calibration.yamlcalibration_scripts/storage_camera_calibration.yaml
包含四角点、平面尺寸、输出分辨率、透视矩阵等信息。
3.3 示教标定(棋盘区与储棋区)
3.3.1 目标
建立“平面坐标系 → 机械臂基坐标系”的刚体映射。
3.3.2 为什么叫示教标定
因为我们采用的是“人工示教点对齐”的方式:
- 在平面坐标系中选定若干已知点
- 手动/半自动控制机械臂末端到这些点的真实位置
- 记录点对后拟合变换矩阵
本质是点到点映射拟合,更容易教学和落地。
3.3.3 相关脚本
calibration_scripts/4.calibrate_hand_eye_qt_ros2.py:棋盘区示教标定calibration_scripts/9.calibrate_storage_hand_eye.py:储棋区示教标定calibration_scripts/6.chess_piece_robot_controller.py:整链路联调验证
3.3.4 典型输出
calibration_scripts/hand_eye_calibration.yamlcalibration_scripts/storage_hand_eye_calibration.yaml
文件中核心是
四、运行流程
4.1 准备工作
-
这个项目对机械臂精度要求较高,使用前需要紧固机械臂一些关节,降低间隙,尤其是:
- 底座:紧固底座驱动板四个螺丝
- 腰部:紧固侧边法兰螺丝
-
使用
Episode1 ros2包控制机械臂:ros2 run episode_controller interface --ros-args -p init_mode:=0 -p usb_index:=1注意,不是我们自己做的
py_episode,很多topic不一致。如要用,可自行修改对应名称。 -
桌面布局要求:
- 相机俯拍要求覆盖棋盘区域和储棋区(白纸区域)
- 相机、棋盘格、机械臂固定后,就不要调整他们的相对位置了,否则需要重新标定
| 主视图 | 俯拍 |
|---|---|
![]() |
![]() |
4.2 棋盘区相机透视标定

-
命令
python3 2.calibrate_perspective_camera_qt.py -c {camera_index}-
先用尺测量出机械臂末端可触达的棋盘区宽度和高度,比如我的是宽度为 12x10 的棋盘格,尺寸是
272x239 mm,填入 Board size。因为机械臂臂展有限,这个尺寸是测试出来的,你可以先随便选择一个,后面再通过示教标定程序试出来合适值
-
想象你站在机械臂的位置,然后按照
Bottom_left -> Bottom_right -> Top_right -> Top_left顺序点选棋盘格角点 -
四点选择后,点击
Transform按钮,计算变换矩阵,并Save calibration自动保存配置信息,比如我的:board_corners: - - 0.0 - 0.0 - - 272.0 - 0.0 - - 272.0 - 239.0 - - 0.0 - 239.0 board_size_mm: height: 239 width: 272 camera_resolution: height: 720 width: 1280 corner_names: - Bottom-Left - Bottom-Right - Top-Right - Top-Left output_size: height: 478 width: 544 ...
-
-
棋盘区透视效果验证:
python3 3.live_cropped_feed.py -c {camera_index}
- 设置
board Rows/Cols为你指定的,比如我们的是 11 x 13 (格子数量 +1) - 使用
Show grid overlay覆盖绿色网格检查 - 绿色线条必须和棋盘格匹配,否则重新透视标定,或者检查设置的参数
- 绿色线条必须和棋盘格匹配,否则重新透视标定,或者检查设置的参数
- 绿色线条必须和棋盘格匹配,否则重新透视标定,或者检查设置的参数
- 放置一些棋子在棋盘区,看一下映射效果
precision调整尽量使用我设置好的值,如果最后映射效果不错,即可关闭
- 设置
4.3 棋盘区示教标定

-
因为这个脚本需要使用 ROS2 相关包
source install/setup.bash cd src/episode_apps/calibration_scripts/ python3 4.calibrate_hand_eye_qt_ros2.py -
想象你站在机械臂的位置,按照左下角(P1)、右下角(P2)、左上角(P3)、右上角(P4)顺序调整
-
可以先将
Step size调大一些,比如 50mm,然后快速到达指定位置,粗定位,再调小,精定位。最后尽量保证吸盘中心在棋盘格角点中心,类似下图
-
保存点的坐标数据,然后回到默认位置(非常重要,否则途经点可能撞到棋盘),继续录入下一个点,直到所有 4 点数据全部录入,保存标定数据。
-
对于已经保存好的数据,需要重新微调(减少减速器间隙影响)
- 机械臂移动到 Home 位置
update一个点,move to位置,微调,使吸盘中心在棋盘格角点中心,保存- 操作下一个点
- 保存所有

-
-
验证 1:使用
Calculate and Move to Grid position按钮检查,是否可以让末端移动到指定的棋盘网格。 -
验证 2:使用
python3 6.chess_piece_robot_controller.py -c {camera_index},点选棋子,查看机械臂末端是否可以移动到棋子上方
4.4 储棋区透视标定

- 命令:
python3 7.calibrate_storage_camera.py -c {camera_index}-
类似棋盘区相机透视标定,想象你站在机械臂的位置,然后按照
Bottom_left -> Bottom_right -> Top_right -> Top_left顺序点选棋盘格角点,将储棋区四个角点选择出来 -
填写实际的储棋区尺寸,比如我的是
129x179mm这个储棋区尺寸也是试出来的(使用下一步的示教标定),如果面积太大了,机械臂可能到达不了(IK 无解)
-
预览,保存校准数据
-
4.5 储棋区示教标定

-
命令:
python3 9.calibrate_storage_hand_eye.py -c {camera_index} -
类似棋盘区示教标定,想象你站在机械臂的位置,按照左下角(P1)、右下角(P2)、右上角(P3)、左上角(P4)顺序调整
注意,和棋盘区示教标定不一样的是,最后两个点的顺序是反的,这个没有特殊原因,仅仅是代码写的时候没有同步。
-
然后类似的,也需要一个个角点微调,最后保存校准数据。
-
对于已经保存好的数据,需要重新微调(减少减速器间隙影响)
- 机械臂移动到 Home 位置
update一个点,move to位置,微调,使吸盘中心在棋盘格角点中心,保存- 操作下一个点
- 保存所有
-
验证:在检测结果上点选棋子,看看机械臂能否移动到正上面(有一点误差不要紧,感觉能抓起来即可)
如果这里误差感觉较大,可以重新进行:储棋区透视标定 和 示教标定 这两步,务必保证精度可用再往后走。
4.6 五子棋游戏体验
cd Gomoku_app
python3 main.py

- 这个程序可以设置行数和列数
- 可以设置谁先手
- 以及难度
Gomoku 引擎在项目中的角色
Gomoku_app/core_api_demo.py提供统一接口,屏蔽了内部搜索和评估细节。上层程序只需要:
- 写入人类落子
- 获取 AI 推荐落子
- 应用落子并检查胜负
这样视觉控制层和博弈算法层实现了解耦。
4.7 运行完整对弈主程序
4.7.1 上位机模式
-
关闭机械臂
Ros2控制,使用上位机控制
-
启动完整下棋程序:
python3 12.chess_demo_raw.py -c {camera_index}该程序与机械臂的通信,使用的是上位机 TCP 协议,不是 ROS2
-
鼠标放到摄像头窗口上,快捷键:
q:退出g:切换显示绿色网格效果p:打印棋盘状态o: 摆放测试,将储棋区棋子逐个放在棋盘上(从左下角开始)h:让机械臂回到默认等待位置
-
选择先手,为了提高检测准确度,储棋区只能用黑子
-
选择难度:因算力有限,一般选择 easy、normal 模式
-
一轮机器落子包含以下步骤:
- 相机采集当前画面
- YOLO 检测棋盘和储棋区棋子
- 识别人类新落子并更新棋盘状态
- AI 计算机器下一步落点
- 在储棋区定位可取棋子
- 机械臂吸取棋子
- 机械臂移动到目标格放置
- 检查胜负并进入下一轮

-
4.7.2 ROS2 模式(默认控制)
- 关闭上位机,使用
ros2控制机械臂:ros2 run episode_controller interface --ros-args -p init_mode:=0 -p usb_index:=1 - 打开 URDF RVIZ:
ros2 launch episode1_urdf_1113 launch.py python3 13.chess_demo_ros2.py -c {camera_index}运行下棋程序(界面与上位机一致)- RVIZ 中选择
MarkerArray,并选择对应topic

- 正常下棋,RVIZ 会映射状态
4.7.3 ROS2 模式(Moveit)
- 使用
python3 14.chess_demo_ros2_moveit.py -c {camera_index} - 操作与上述方法一致,只不过没有仿真可视化
五、总结
本章核心收获可以概括为三句话:
- 使用普通 USB RGB 相机,在平面固定高度场景下同样可以完成稳定抓取任务
- 通过“透视标定 + 示教标定”,建立从图像到机械臂动作的完整映射
- 将视觉、AI 与控制解耦后,可以在不同控制架构(Raw/ROS2/MoveIt)下复用同一业务逻辑
下一步你可以基于同样框架,把“五子棋”替换成任意“检测-抓取-放置”的平面任务。




