4. 深度相机外参标定

外参标定,说白了就是搞清楚相机和机器人手臂之间的位置关系。你想想看,相机看到工件在空间里的坐标,但机器人要去抓它,这两个坐标系如果不统一,那抓取肯定偏到姥姥家去。

我刚开始做3D视觉引导项目时,就吃过这个亏。当时觉得标定差不多就行了,结果抓取精度死活上不去。后来才发现,外参差了2毫米,末端执行器就偏了5毫米。嗯,从那以后我再也不敢马虎了。

4.1 两种手眼配置:Eye-to-Hand vs Eye-in-Hand

先搞清楚基本概念。这两种配置,决定了你的标定流程和算法完全不同。

对比项 Eye-to-Hand(眼在手外) Eye-in-Hand(眼在手上)
相机安装位置 固定在工作台上方或侧面 固定在机器人末端法兰上
相机与机器人关系 相机固定,机器人运动 相机随机器人一起运动
标定目标矩阵 相机坐标系 → 机器人基坐标系 相机坐标系 → 机器人末端坐标系
标定方程形式 AX = XB(经典手眼方程) AX = XB(形式相同,但含义不同)
适用场景 大范围、高精度、固定工位 小范围、灵活、需要跟随视角

核心区别一句话:Eye-to-Hand标定的是相机到机器人基座的变换;Eye-in-Hand标定的是相机到机器人末端的变换。两者都解AX=XB,但A和B的构造方式不同。

4.2 手眼标定的数学原理:AX = XB

这个方程看着简单,但坑不少。我来拆解一下。

假设你让机器人运动到N个不同的位姿。在每个位姿下,你都能得到两组数据:

  • A矩阵:机器人末端相对于基座的变换(从机器人控制器读取)
  • B矩阵:标定板相对于相机的变换(从视觉算法计算)

对于相邻的两个位姿i和j,有:

A_ij = inv(T_base_end_i) * T_base_end_j
B_ij = inv(T_cam_calib_i) * T_cam_calib_j

其中:
A_ij:机器人从位姿i到位姿j的运动
B_ij:标定板从位姿i到位姿j的运动

手眼方程:A_ij * X = X * B_ij
X:就是我们要标定的外参矩阵

为什么是AX=XB?我个人习惯这样理解:机器人动了,相机看到的标定板也动了,这两个运动通过一个固定的变换X联系起来。说白了,X就是那个"翻译官"。

4.3 Eye-to-Hand标定实现步骤

我在项目中用过最多的就是Eye-to-Hand。为什么?因为稳定。相机固定不动,标定一次管很久。

  1. 准备标定板:Halcon里用calplate或者自定义的圆点标定板。我建议用陶瓷材质的,反光小,精度高。
  2. 安装相机:确保相机视野覆盖机器人工作区域。注意,不要让机器人本体遮挡视野。
  3. 采集数据:让机器人带着标定板运动到10~15个不同位姿。每个位姿下:
    • 记录机器人末端位姿(从控制器读取)
    • 拍摄标定板图像,计算标定板在相机坐标系下的位姿
  4. 构造A和B矩阵:按上面的公式计算相邻位姿间的变换。
  5. 求解X:Halcon里用hand_eye_calibration算子。
  6. 验证精度:用一组新的位姿数据做重投影误差验证。

我的经验:采集数据时,让机器人在视野的四个角落和中心各取几个位姿。姿态变化要大,平移和旋转都要有。我曾经只做了平移运动,结果标定出来的旋转分量误差很大,后来加了旋转运动才解决。

4.4 Eye-in-Hand标定实现步骤

Eye-in-Hand适合需要灵活视角的场景,比如焊接、喷涂。但标定过程稍微麻烦一点。

  1. 固定标定板:标定板放在工作台上固定不动。
  2. 安装相机:相机固定在机器人末端法兰上。
  3. 采集数据:让机器人运动到10~15个不同位姿,确保标定板始终在视野内。每个位姿下:
    • 记录机器人末端位姿
    • 拍摄标定板,计算标定板在相机坐标系下的位姿
  4. 构造A和B矩阵:注意!这里的A和B含义与Eye-to-Hand不同。
    • A_ij = inv(T_base_end_i) * T_base_end_j(相同)
    • B_ij = inv(T_cam_calib_i) * T_cam_calib_j(相同)
    • 但X的含义不同:X = T_cam_end(相机到末端的变换)
  5. 求解X:同样用hand_eye_calibration算子,但参数设置不同。

注意:Eye-in-Hand标定中,标定板必须固定不动。如果标定板移动了,整个标定就废了。我曾经有一次没注意,标定板被风吹动了,结果标定出来的外参完全不对,排查了半天才发现。

4.5 Halcon实现代码示例

下面给出一段完整的Eye-to-Hand标定代码。我习惯把数据采集和标定分开写,这样调试方便。

* 创建标定数据模型
create_calib_data ('hand_eye_moving_cam', 'calibration_object', CalibDataID)
* 设置相机参数(内参已标定)
set_calib_data_cam_param (CalibDataID, 0, 'area_scan_division', CamParam)
* 设置标定板描述
set_calib_data_calib_object (CalibDataID, 0, 'calplate_30mm', CalibObjDescr)

* 循环添加标定位姿
for i := 1 to NumPoses by 1
    * 读取机器人末端位姿(从控制器获取)
    * 格式:[X, Y, Z, Rx, Ry, Rz] 或 4x4矩阵
    read_robot_pose (RobotPoses[i], RobotPose)
    
    * 读取标定板位姿(从图像计算)
    find_calib_object (Image, CalibDataID, 0, 0, i, [])
    get_calib_data_observ_pose (CalibDataID, 0, 0, i, CalibPose)
    
    * 添加到位姿列表
    tuple_concat (RobotPoseList, RobotPose, RobotPoseList)
    tuple_concat (CalibPoseList, CalibPose, CalibPoseList)
endfor

* 执行手眼标定
hand_eye_calibration (RobotPoseList, CalibPoseList, \
                      'moving_cam', 'nonlinear', \
                      'all', CamParam, CalibObjDescr, \
                      Error, HandEyePose)

* 输出结果
disp_message (WindowHandle, '标定误差: ' + Error + ' pixel', \
              'window', 12, 12, 'black', 'true')
disp_message (WindowHandle, '外参矩阵已保存', \
              'window', 12, 40, 'black', 'true')

关键参数说明:

  • 'moving_cam':表示相机运动(Eye-in-Hand用'moving_cam',Eye-to-Hand用'stationary_cam')
  • 'nonlinear':非线性优化,精度更高,但需要好的初始值
  • 'all':同时优化旋转和平移

4.6 标定精度验证与常见问题

标定完了,怎么知道准不准?我一般做三步验证:

  • 重投影误差:用标定结果把3D点投影到图像上,看偏差。Halcon的hand_eye_calibration会直接输出Error,一般小于0.5 pixel就算不错。
  • 抓取测试:让机器人去抓一个已知位置的工件。如果抓取偏差在允许范围内,说明标定有效。
  • 重复性测试:同一个位姿重复标定多次,看结果的波动。波动越小越好。

避坑指南:

  • 标定板不要太小,否则视野边缘的畸变会影响精度。我一般用30mm以上的标定板。
  • 采集位姿时,避免所有位姿都在同一个平面上。要有深度变化。
  • 机器人运动精度会影响标定结果。如果机器人本身重复定位精度差,标定结果也不会好。
  • 光照变化会影响标定板检测。建议用漫反射光源,避免强光直射。

4.7 知识结构图

下面这张图总结了手眼标定的核心逻辑,你可以对照着理解整个流程。

手眼标定知识结构图 手眼标定核心知识结构 Eye-to-Hand(眼在手外) Eye-in-Hand(眼在手上) 共同核心:AX = XB 手眼方程 数据采集:10~15个不同位姿 A矩阵:机器人运动 B矩阵:标定板运动 Halcon求解:hand_eye_calibration 验证:重投影误差 + 抓取测试 提示:两种配置的标定流程相同,但X矩阵的含义不同,采集数据时注意标定板是否固定

4.8 总结与个人建议

手眼标定是3D视觉引导项目的关键一步。我个人建议:

  • 优先选Eye-to-Hand:如果现场条件允许,固定相机比移动相机更稳定,标定一次能用很久。
  • 数据质量比数量重要:10个好的位姿胜过20个差的位姿。确保位姿分布均匀,姿态变化充分。
  • 标定后一定要验证:不要相信标定结果直接上线。用实际抓取测试来验证,这才是金标准。
  • 定期复标:相机松动、机器人磨损、温度变化都会影响外参。我一般建议每3个月复标一次。