3、3D相机标定实战:手眼标定(Eye-in-Hand vs Eye-to-Hand),标定流程与代码实现,精度验证方法

手眼标定,说白了就是让机器人知道「我的眼睛长在哪」。

你想想看,3D相机拍到了工件的位置,但机器人要去抓它。相机坐标系和机器人坐标系之间,差了一个变换关系。这个关系不搞清楚,你测再准也没用。

我刚开始做这个的时候,总觉得标定就是跑个算子完事。后来发现,标定流程、精度验证、甚至相机装在哪,都会直接影响最终效果。嗯,这一章咱们就把这些事彻底讲透。

3.1 两种安装方式:Eye-in-Hand vs Eye-to-Hand

先搞清楚一个基本问题:相机装在哪?

这决定了你的标定模型和算法路径。我见过不少新手,上来就套代码,结果标定结果一塌糊涂——其实就是装法没搞对。

对比项 Eye-in-Hand(眼在手上) Eye-to-Hand(眼在手外)
相机安装位置 固定在机器人末端(法兰盘) 固定在工作台上方或侧面
标定目标 求相机到末端(Tool)的变换 求相机到机器人基座(Base)的变换
标定方程 AX = XB AX = XB(形式相同,含义不同)
常用场景 小范围、高精度抓取、焊缝跟踪 大范围、料筐抓取、固定工位检测
优点 相机随动,视野灵活,可近距离测量 相机固定,标定一次长期使用
缺点 每次换工具需重新标定,对机械刚性要求高 视野固定,大工件可能需要多相机

核心记忆点:不管哪种方式,Halcon里用的都是同一个算子——hand_eye_calibration。区别在于你传入的位姿数据怎么组织。

3.2 标定流程:从拍照到解算

我个人习惯把流程拆成五步。每一步都有坑,咱们一个一个说。

Step 1:准备标定物

用Halcon的标定板。我建议用高精度陶瓷板,别用打印的纸板——3D相机对平面度敏感,纸板一翘曲,标定就偏了。

  • 标定板尺寸:根据视场大小选,一般占视场的1/3到1/2
  • 标定板文件:用gen_caltab生成,或者用Halcon自带的caltab_30mm.descr

Step 2:采集多组位姿

这一步最容易被忽视。很多人随便拍几张就开标,结果精度惨不忍睹。

我建议至少拍15-20组。而且位姿要覆盖整个工作空间:

  • 不同高度(Z方向拉开)
  • 不同角度(绕X、Y、Z旋转)
  • 不同位置(X、Y平面均匀分布)

我曾经踩过的坑:有一次标定结果一直不好,反复检查代码都没问题。后来发现,我拍的15张图里,有12张标定板都在视野正中间,角度几乎一样。这种数据解算出来的矩阵,外推误差极大。

Step 3:提取标定板位姿

用find_caltab和find_marks_and_pose提取标定板在相机坐标系下的位姿。

注意:3D相机如果是结构光或双目,这一步通常是在深度图上做,或者直接用点云拟合标定板平面。

* Halcon代码示例:提取标定板位姿
read_image (Image, 'calib_image_01')
find_caltab (Image, CaltabRegion, 'caltab_30mm.descr', 3, 112, 5)
find_marks_and_pose (Image, CaltabRegion, 'caltab_30mm.descr', \
                     StartCamParam, 128, 10, 18, 0.9, \
                     MarkRCoord, MarkCCoord, StartPose)

Step 4:记录机器人位姿

每次拍照时,同时记录机器人末端(或基座)的位姿。注意:

  • Eye-in-Hand:记录机器人末端在基座坐标系下的位姿
  • Eye-to-Hand:记录机器人末端在基座坐标系下的位姿(形式一样,但方程不同)

Step 5:执行标定

把所有数据喂给hand_eye_calibration。Halcon会自动解算出手眼变换矩阵。

* Halcon代码示例:手眼标定核心算子
* CalibDataID 是标定数据句柄,包含所有图像位姿和机器人位姿
hand_eye_calibration (CalibDataID, Errors, HandEyeMatrix)
* HandEyeMatrix 就是我们要的变换矩阵

小技巧:标定完成后,用Errors输出看一下重投影误差。如果大于0.5个像素,说明数据质量有问题,建议重新采集。

3.3 精度验证方法

标定完了,怎么知道准不准?

我见过很多人标完就跑,结果现场一抓就偏。验证这一步,不能省。

方法一:重投影误差验证

用标定结果把标定板角点反投回图像,看偏差。

  • 误差 < 0.3像素:优秀
  • 误差 0.3~0.8像素:可接受
  • 误差 > 1.0像素:重新标定

方法二:实际抓取验证(我最推荐的方法)

拿一个已知尺寸的工件,放在工作空间的不同位置,让机器人去抓。

  1. 在相机下拍工件,得到抓取位姿
  2. 机器人运动到该位姿
  3. 测量实际抓取位置与理论位置的偏差

我一般要求位置偏差 < 1mm,角度偏差 < 0.5°。如果达不到,优先检查标定数据分布是否合理。

方法三:重复性验证

同一个位姿,重复标定10次,看结果的波动范围。

  • 平移波动 < 0.2mm
  • 旋转波动 < 0.1°

如果波动大,说明机械刚性或相机噪声有问题。

3.4 知识结构总览

下面这张图,是我自己整理的手眼标定知识框架。每次做项目前,我都会对照着走一遍流程。

手眼标定知识结构总览 Eye-in-Hand(眼在手上) Eye-to-Hand(眼在手外) 标定流程(5步) ① 准备标定物 ② 采集多组位姿 ③ 提取标定板位姿 ④ 记录机器人位姿 ⑤ 执行标定 精度验证(3种方法) 重投影误差验证 目标:< 0.3像素 实际抓取验证 目标:< 1mm / 0.5° 重复性验证 目标:< 0.2mm / 0.1° 核心算子:hand_eye_calibration 标定质量 = 数据分布 × 标定板精度 × 机械重复性

3.5 常见问题与避坑指南

我曾经遇到过一个典型案例:客户现场标定结果一直不稳定,换了三次标定板都没用。最后发现是机器人末端法兰盘有0.1mm的轴向窜动。手眼标定对机械刚性非常敏感,尤其是Eye-in-Hand方案。如果你的机器人重复定位精度本身就不高(比如 > 0.05mm),标定结果很难做到1mm以内。

  • 标定数据太少?至少15组,20组以上更稳
  • 标定板不平?用陶瓷板,别用亚克力或纸板
  • 机器人抖动?拍照时让机器人静止1秒再触发
  • 标定结果发散?检查是否有位姿数据录入错误(比如把角度单位搞混了)

我的个人习惯:每次标定完,我都会用write_pose把手眼矩阵存成.dat文件,同时在项目文档里记录标定时的温度、机器人负载情况。别小看这些细节——有一次夏天和冬天标定结果差了0.3mm,就是因为热胀冷缩。