搞机器人视觉引导这行,被问得最多的就是手眼标定。不少人在项目现场折腾了几天,代码也跑了、数据也采了、标定板也摆了,机械臂就是戳不准目标点,差个三五毫米很正常。这套东西的数学模型说穿了就是AX=XB,不算复杂,但当对象换成Intel RealSense D435相机加UR机械臂时,相机参数怎么配、位姿从哪读、数据怎么组织、解算结果怎么验,每一步都有看似不起眼、实则能把整个标定带沟里的细节。这篇文章把我在这套组合上的完整实操过程记录下来,包括那些让我多花了两三天才排查出来的错误,给正在做手眼标定、准备做手眼标定,以及标定完精度上不去的朋友一份能直接对着抄的避坑参考。
1. 标定之前先想清楚:这台D435到底装手上还是装外面
1.1 眼在手上和眼在手外的区别不只是安装位置
很多第一次做标定的人,拿到相机第一件事就是固定支架,然后就开始采数据,等解算结果不对了才回头想安装模式的问题。这个顺序是错的。手眼标定的第一步不是装相机,而是先明确自己做的是眼在手外(Eye-to-Hand)还是眼在手上(Eye-in-Hand),这两种模式虽然都是解AX=XB,但要求解的未知量完全不同,后续代码里A矩阵、B矩阵的组织方式也完全不一样。
眼在手外,相机固定在工作区上方或者侧面,标定求解的是相机坐标系到机器人基座坐标系的固定变换。这种模式的好处是相机视野固定,机械臂每次进视野工作,坐标链路就是一步变换,简单直接。坏处是相机一旦被撞、支架拧歪一点,整个变换关系就会失效,而且机械臂很容易遮挡相机视野里的目标。眼在手上,相机装在机械臂末端法兰上,跟着机械臂一起动,标定求解的是相机坐标系到机械臂末端坐标系的变换,也就是那个著名的X。这种模式的好处是可以通过机械臂运动调整相机视角,靠近工件看细节,灵活还避遮挡。
某品牌机械臂手眼标定的现场案例里,很多集成商默认把相机装到手臂末端,因为这样视觉引导装配更灵活。D435体积小、重量三百多克,装在UR末端完全不是问题。但我见过不止一个项目,相机装法用的是眼在手上,代码里却跑去套眼在手外的公式,最后解出来的矩阵数值看着不报错,实际应用时目标点偏得离谱。所以装之前,先把这句话写下来:这个项目到底是相机跟着机械臂动,还是相机固定不动?后面所有数据处理都围绕这个答案展开。
1.2 D435配UR的典型组合,以及模式选错会怎样
D435是Intel RealSense里的深度相机,RGB分辨率最高支持1920×1080,视野广、体积小,USB供电,配UR机械臂做视觉引导是实验室和产线上很常见的省事组合。但在手眼标定这件事上,D435有个特点容易忽略:它的RGB视野没有深度视野那么宽,标定板如果放得比较靠图像边缘,畸变和边缘画质会明显影响角点检测的亚像素精度。所以无论哪种安装模式,都要尽量让标定板在画面中央区域活动。
在UR上装D435,比较稳的做法是做一个轻量铝合金支架,把相机固定在法兰正前方,重心尽量靠近法兰轴线。支架刚度不够的话,机械臂稍微加减速,相机相对末端的位姿就会发生微小变化,而手眼矩阵默认这个变换是固定的,这部分变化最终全部转成定位误差。UR本身的重复定位精度不错,大体在±0.03到±0.1mm这个量级,但这是机械臂单方面的本领。手眼标定解决的是相机看到的点怎么换算到机械臂坐标系,如果安装基础松了,再准的机械臂也白搭。
模式选错之后最典型的症状是:标定结果里旋转矩阵的各项数值看起来正常,平移向量和实际安装结构的距离也差不多能对上,但定点验证时机械臂总是向着某个方向偏,偏多少还随着位置变化。这是因为眼在手外的公式里,X代表相机到基座的变换,眼在手上的公式里,X代表相机到末端的变换,两个X在AX=XB等式里的位置不一样。把数据喂错了等式,解出来的是一个数学上成立、物理上毫无意义的矩阵。这个坑最阴的地方就是不报错,只能靠验证发现。
2. 采数据前必须搞定的三件事:相机参数、标定板、UR位姿读取
2.1 D435相机参数:固定曝光、白平衡和分辨率里的坑
标定数据采集和拍照不是一个逻辑。拍照追求画面好看,标定追求角点检测稳定精确,所以D435的相机参数绝对不能保持默认自动模式。我遇到过最典型的问题就是自动曝光。标定板是黑白棋盘格或者黑白圆点板,机械臂带着相机在不同角度下观察,标定板表面反光情况差异很大,自动曝光会让画面亮度不断跳变,角点的亚像素定位也会跟着波动,最终导入手眼标定的标定板位姿每一组都带着细微误差。
正确的做法是在采集前手动把曝光时间固定下来。第一次调曝光时用realsense-viewer实时观察画面,把曝光调到标定板高光区域不泛白、暗部不吞黑的程度,之后整场标定不再修改。白平衡也建议固定,尤其是现场有混合光源时,自动白平衡会在不同角度让标定板的颜色发生偏移,虽然棋盘格检测对颜色不敏感,但后续如果做Halcon标定,灰度值变化会影响圆点轮廓提取。分辨率方面,标定没必要跑满1920×1080,我习惯用1280×720,检测速度更快,文件也更小,对精度没有明显损失。
还有一个特别容易踩的坑:不要开RGB和深度对齐,也不要用对齐之后的深度图去做标定板检测。D435的RGB模组和深度模组之间有物理距离,对齐后的深度图边缘经常有空洞,角点附近一旦出现空洞,检测坐标就废了。标定板角点检测老老实实用RGB图,深度信息只用来做后续反推Z值。
2.2 标定板选择和打印细节,检测失败时先查哪里
标定板是手眼标定里误差链条的物理基准。OpenCV系的标定常用不对称棋盘格,Halcon系常用圆点阵列板。我建议如果条件允许,做一块双面板,一面棋盘格一面圆点板,这样OpenCV和Halcon想用哪个用哪个。关键是标定板本身必须足够平整。直接拿A4纸打印贴纸箱上这种做法我见过很多,标定板表面一弯,整个标定板坐标系和物理实体的对应关系就崩了,标定出来的手眼矩阵必然带上这一层不确定度。
正确做法是把图案打印出来,用双面胶或者胶水平整贴到铝板、亚克力板或者玻璃板上,边角压平,干了之后再检测一遍图案是否有褶皱。棋盘格的边长不能太小,我用的棋盘格边长25mm,内角点8×6,相机距离标定板350到600mm范围内,画面里标定板至少占三分之一,角点数量才够做稳定的位姿估计。标定板离得太远会变小,角点检测虽然能出结果,但位姿的旋转和平移方差会显著变大。
检测失败是最常见的问题。出现这种情况不要急着去调算法参数,先按顺序检查:标定板区域是不是过曝或者过暗,高光反光是否把角点周围的白格染成一片;标定板是不是被机械臂或者其他物体遮挡了一部分;画面里有没有把标定板放得太靠边,边缘畸变导致角点特征变形。如果用的是棋盘格,还要注意不要出现只拍到部分棋盘的情况,部分可见会让检测程序报错或者输出错误的角点集合。另外,标定板的图案不要用普通打印机的省墨模式,灰度不均匀的棋盘格对亚像素提取极其不友好。
2.3 UR机械臂位姿读取:旋转矢量当成欧拉角的惨痛教训
手眼标定需要的机械臂位姿数据,在UR上有好几种拿法。最省事的是用ur_rtde库,在工控机上装好之后,通过以太网连接UR控制箱,调用getActualTCPPose()就能拿到当前工具坐标系位姿。也可以用socket方式去读secondary client interface接口的报文,解析机械臂实时状态。两条路都行,但有一个共同前提:不要手动从示教器上抄数字记录下来,抄错一个数整组数据就废了,而且事后基本发现不了。
UR返回的位姿是[x, y, z, rx, ry, rz],位置单位是米,rx、ry、rz看起来像三个角度,实际上它们是旋转矢量,也叫轴角表示。旋转矢量的方向代表旋转轴,模长代表旋转角度,单位是弧度。很多人第一次接触UR,直接把rx、ry、rz当成欧拉角填进手眼标定的旋转矩阵构造代码里,结果标定出来的矩阵完全没法看。欧拉角是三次绕轴旋转的组合,还分ZYX、ZYZ各种约定,不同厂家还不一样;旋转矢量则是另一种表示,转成旋转矩阵用OpenCV的cv2.Rodrigues一行搞定,根本不需要关心绕轴顺序。
还有一个必须提前处理的是TCP设置。如果机械臂末端装了夹爪,要先在示教器里把TCP参数设好,ur_rtde读出来的才是工具坐标系位姿,否则返回的是法兰位姿。我踩过一次非常隐蔽的坑:标定过程中没设置TCP,后续抓取程序却使用了工具坐标系,结果手眼矩阵在高度方向上偏了将近一个夹爪长度,水平方向却基本正常。这个现象很容易让人以为标定参数里某个符号写反了,排查了好几个小时,最后发现只是TCP没设置。所以读位姿之前,先确认你需要的到底是法兰位姿还是工具位姿,并且后续视觉坐标链路里每一步都用同一个约定。
3. 采集手眼标定数据的位姿策略:多少组、怎么摆位
3.1 为什么采了12组还是解不出稳定结果
手眼标定的数学最低要求是三组数据就能解,但实际标定中采12组还解不出稳定结果的案例比比皆是。问题基本不在数量,而在姿态多样性。AX=XB这个方程能稳定求解的前提是,数据里包含足够的旋转约束。如果机械臂带着相机只是在空间里平移,姿态始终差不多,或者标定板永远正对相机,那么方程的旋转部分就退化掉了,解出来的旋转矩阵噪声极大。
判断数据是否退化的一个实用方法:用OpenCV的calibrateHandEye分别跑Tsai和Daniilidis两种方法,如果两种方法解出来的结果(尤其是旋转部分)差得很远,先别怀疑算法,回去补数据。姿态多样性够了之后,不同方法之间的差异会明显缩小。另外,位姿变化的范围也很重要。如果所有数据都挤在很小的空间范围里,比如相机只是在100mm见方的区域里移动,机械臂微小位姿误差的占比会被放大,AX=XB方程的病态性就会暴露出来。数据要铺开,位置和姿态都要有显著变化。
还有一个容易被忽视的因素是标定板在整个采集中间的物理稳定性。标定板固定在工作台上就不能再碰,哪怕移动了一毫米,都等于有一组数据是在另一个世界坐标系下拍的,手眼解算会把这一毫米当成噪声分配给所有参数。做标定之前,把所有可能碰到标定板的人都通知一遍,特别是旁边的人来回走动碰到桌面这种细小事。
3.2 我实际操作的16组位姿布局参考
我在这套D435加UR的组合上,最终稳定复现的采集方案是16组位姿。标定板放在桌面上固定好,机械臂带着相机在标定板斜上方大概350到600mm的范围内运动,这个范围对应实际抓取作业的工作距离。
16组数据具体怎么摆:8组是相机基本正对标定板,但相机光心分别落在标定板的左、右、上、下、左上、左下、右上、右下这八个方向,形成明显的平移变化;4组让相机绕自身X轴倾斜20到35度,分别向左右两个方向;4组绕自身Y轴倾斜20到35度,让标定板在画面里产生明显的透视形变。另外在倾斜的这些组里,穿插两到三组在平面内旋转四五十度,也就是绕相机Z轴转了角度,让标定板图案相对图像坐标有一个明显的倾角。这样一套组合下来,平移、俯仰、滚转都有了,AX=XB的约束是充分的。
每一组数据采集前,机械臂运动到位之后至少等0.5秒再采图。UR的控制器虽然反应快,但机械结构和减速器到位后需要极短时间稳定下来。D435的RGB模组是滚动快门,机械臂还在抖动的时候采图,图像上的标定板会产生微小的卷帘快门畸变,角点位置就被拉歪了。等稳定的另外一个原因是位姿和时间戳同步,确保图像和UR读取到的位姿确实是同一个时刻。
3.3 每组数据怎么记录才能保证一一对应
数据记录这件事,听起来简单,翻车概率却很高。我的做法是在一个项目文件夹下建两个子目录,images目录放图像,poses目录放对应的位姿文件,命名从001开始递增,image_012.png一定对pose_012.npy。图像方保留原始分辨率,不要压缩,不要转格式。位姿文件里保存UR返回的完整六维数据,同时额外保存一个转换好的4×4齐次矩阵,避免后面换脚本时再去转换引发错误。
采集完之后做一个强制检查:图像数量和位姿数量必须严格相等,每一张图像都要能成功检测到标定板,只要有一组检测失败,就补采一组,不要想着后面用别的组代替。补采的时候新程序会写到编号14,这时不要手动把后面的文件名往前改,乱了顺序相当于把整组数据毁掉。如果确实有几组数据因为反光、遮挡、机械臂挡住标定板等原因重投影误差异常大,就在解算阶段把它们剔除掉,而不是在文件层面删文件重排。
手动示教器抄数的方式我强烈不建议,除了效率低之外,最危险的是不小心抄错行。比如第7组图像对应的是第8组位姿,这种错位在解算结果上表现为误差忽大忽小,非常难排查。用ur_rtde或者socket自动记录,从数据链路层面把这个风险关掉。
4. 解算环节的输入输出:OpenCV和Halcon各自的数据组织方式
4.1 手眼标定要的数据到底是哪几组矩阵
手眼标定要的数据,本质上就是多组成对的机械臂位姿和标定板位姿。以眼在手上为例,每一组数据包含两个变换:一个是机械臂末端坐标系在机器人基座坐标系下的位姿,记为T_base_gripper;另一个是标定板坐标系在相机坐标系下的位姿,记为T_cam_target。这里的T都是4×4齐次矩阵,包含旋转和平移。
解算X的过程可以用一个不变关系来理解:因为标定板固定不动,所以无论机械臂走到哪里,从基座坐标系到标定板坐标系的变换T_base_target始终是同一个值。而T_base_target又可以拆成T_base_gripper乘以T_gripper_cam再乘以T_cam_target,于是就有T_base_gripper_i * T_gripper_cam * T_cam_target_i等于常数。拿第i组和第j组相减消掉常数,就能整理成AX=XB的形式,这里的X就是T_gripper_cam,也就是相机相对机械臂末端的位姿。
数据组织上,OpenCV的calibrateHandEye函数接收四组数组:R_gripper2base、t_gripper2base、R_target2cam、t_target2cam。R_gripper2base是把UR读到的旋转矢量用cv2.Rodrigues转出来的旋转矩阵,t_gripper2base是UR读到的位置向量。R_target2cam和t_target2cam来自solvePnP,求解标定板坐标系在相机坐标系下的旋转和平移。solvePnP解出来的rvec也要先转成旋转矩阵,tvec的单位要和UR的位置单位统一,要么都是米,要么都是毫米,差了1000倍的结果很难发现。
标定完成之后,视觉目标从像素坐标换算到机械臂基座坐标的链路是这样的:像素坐标(u,v)通过相机内参反投影到相机坐标系得到P_cam,然后做P_gripper = T_gripper_cam * P_cam,再做P_base = T_base_gripper * P_gripper。如果是眼在手外,链路更短,P_base = T_base_cam * P_cam。这条链路每个环节的坐标系方向都要一致,我建议把所有变换都写成4×4矩阵再相乘,不要在脑子里来回翻转。
4.2 OpenCV calibrateHandEye和Halcon hand_eye_calibration的用法对比
OpenCV的calibrateHandEye是免费开源里最常用的解算函数,支持Tsai、Park、Horaud、Andreff、Daniilidis几种方法。实测下来Tsai和Park在姿态多样性足够的情况下结果都很稳,Daniilidis基于四元数,对姿态多样性的要求稍高,但有时候在噪声环境下反而更稳健。我的习惯是用Tsai作为主解,再用Daniilidis交叉验证,两个结果如果接近,说明数据质量靠谱。
Halcon带的手眼标定流程也很成熟,很多人因为后续要做复杂的机器视觉处理,直接整套都迁到Halcon上。Halcon里对标的是圆点标定板,需要先创建一个标定板描述文件descr,描述文件里写清楚每个圆点的位置和板子的尺寸参数。在Halcon的标定助手里选择标定板型号,填入标定板宽度,然后逐张图片做find_calib_object检测。标定板检测成功后得到的就是标定板在相机坐标系下的位姿,这个Pose和机械臂位姿一起输入hand_eye_calibration算子,最终得到手眼矩阵。
Halcon的坑主要在Pose的表述约定。Halcon里Pose有多种旋转顺序和类型,默认可能是什么顺序要查文档确认,不然机械臂位姿传进去之后解算结果会带上一个奇怪的旋转偏差。D435的RGB图像输入Halcon前,还要注意图像通道顺序和位深,Halcon读图像默认的通道顺序和OpenCV不一样。如果不打算用Halcon做后续视觉处理,单纯为了手眼标定去折腾Halcon反而增加工作量,OpenCV已经足够完成任务。
4.3 求解失败时按这个链路逐项排查
求解出错时,我的排查顺序是固定的,从数据源开始逐项确认,而不是一遍遍更换求解方法。
第一,检查图像和位姿是否严格一一对应,文件名对得上不代表内容对得上,如果某些组是手动补录的,要格外小心。第二,检查UR读出来的旋转矢量是否完成了Rodrigues转换,这一步出错在代码里非常隐蔽。第三,检查所有矩阵的方向约定,R_gripper2base是否都是base坐标系到gripper坐标系,R_target2cam是否都是标定板到相机,一旦有一组传反,整个AX=XB就变成解另一个未知量了。第四,检查单位,位置单位是米还是毫米,solvePnP的tvec和UR的xyz必须统一。第五,检查标定板检测的重投影误差,如果某些图像上角点检测的像素误差已经超过0.3个像素,先优化图像采集条件再重标。
还有一个非常高效的排查方法:写一小段3D可视化脚本,把所有组的机械臂末端位姿、相机检测到的标定板位姿、初算出来的手眼矩阵一起画到三维空间里。如果手眼矩阵方向正确,所有组的标定板位姿在空间里应该重合在一个固定位置;如果方向反了或者数据组织错了,标定板会散成一片。这种可视化手段比盯着矩阵数字猜有效得多,我后来每次标定都会跑一遍。
5. 标定做完先别急着抓取:三种验证方式逐个聊
5.1 新位姿下的标定板角点定点验证
标定解算完成,手眼矩阵拿到了,第一步验证一定不要用采集过的位姿。拿参与标定的图像和数据去验证,相当于开卷考试,重投影误差低是应该的,不能反映实际精度。正确的做法是让机械臂运动到一个新的位姿,让标定板重新出现在视野里,然后选标定板上的一个角点,把它的像素坐标通过内参、手眼矩阵、当前机械臂位姿换算成机器人基座坐标。
在UR示教器上,把机械臂末端移动到这个计算出来的坐标。注意这里要用针尖或者其他尖锐工具,不要直接用夹爪,夹爪的中心点不好目测。标定板平放,针尖从上方去碰那个角点,看是否真的扎在角点上。误差评估不要只测一个点,在标定板上选五个分布在不同位置的角点,每个点从不同机械臂位姿验证三次,记录针尖和角点的偏差。实测下来,平均偏差在1mm以内属于可以放手用的水平,1到2mm需要回去检查数据或者接受这个精度,大于2mm基本要重新排查。
做定点验证时还要注意运动方向的影响。UR从不同方向接近同一个点时,由于减速器回差,实际落点会有微小差别。所以验证和后续正式作业时,尽量保持同一个接近方向,这样误差是一致性的,反而好补偿。
5.2 实际抓取的验证要注意工具坐标系的干扰
定点验证通过之后,很多人直接进入实际抓取验证,然后发现机械臂抓偏了,第一反应就是手眼标定不行。其实实际抓取验证里混入了三个独立的误差源:视觉识别定位误差、手眼矩阵误差、机械臂TCP和夹爪抓取点误差。三者混在一起,出了问题无法直接定位到手眼标定。
所以实际抓取之前,先把TCP单独验证一遍。让机械臂带着夹爪走几个不同姿态,看夹爪的抓取中心在空间里是否保持不动,如果夹爪中心随姿态飘移,就是TCP设置有问题。TCP确认没问题,再用针尖代替夹爪做一次定点验证,把机械臂侧误差和视觉侧误差剥离开。最后才是带着夹爪去抓实际目标。
抓取验证还有一个隐蔽问题:物体识别程序给出的抓取点,和手眼标定用的特征点可能不是同一个点。比如视觉识别输出的是物体外接矩形中心,但实际抓取点应该在物体质心或者某个特征位置,这两个点之间如果有偏差,也会被误算到标定头上。验证时最好用视觉程序实际输出的抓取点去抓一个已知形状的物体,看偏差是否和标定的定点验证一致。
5.3 正确理解重复精度和绝对精度的差别
手眼标定解决的是不同坐标系之间变换关系的准确性问题,但机械臂最终能不能到那个坐标,还取决于机械臂自身的绝对定位精度。UR的重复定位精度很好,一般都在正负0.03到0.1mm这个量级,意思是同一段程序重复执行,每次到点的离散程度很小。但绝对定位精度是另一回事,它受臂长、负载、安装基础、环境温度影响,实际到点位置和理论计算位置之间可能存在更大的偏差。
这么理解:手眼标定把目标点的坐标算得很准,这个坐标是相对机器人基座的,但机械臂执行这个坐标时本身有绝对精度误差。重复精度高不等于绝对精度高,反过来也一样。视觉引导抓取场景里,目标定位误差两个毫米以内通常都能接受,因为夹爪本身有补偿量。如果做高精度装配,就必须额外标定机械臂的绝对精度,或者用外部测量设备修正。
验证时要做的是把两个误差分开认知。同一个视觉目标,机械臂从不同方向去碰它,落点之间的离散度反映的是重复精度和回差;落点相对目标真值的整体偏移,反映的是手眼标定加机械臂绝对精度的综合误差。别指望通过反复优化手眼标定来解决机械臂自身绝对精度的问题,两者不在一个层面。
6. 精度上不去的深度排查:一张完整的检查清单
6.1 从相机端排查:内参重标定、去畸变与温度漂移
精度上不去的时候,很多人第一时间怀疑算法选错了,或者数据量不够,但实际项目里相机端的因素往往更致命。D435出厂内参在生产线上标定过,出厂短期内可信,但这不代表它能一直用下去。相机经历过运输磕碰、镜头松动、长时间运行发热之后,内参都会发生偏移。D435的RGB模组和深度模组之间还有温漂问题,机器连续跑一个小时以上,塑胶件轻微热胀冷缩,内参就会有肉眼不可忽略的变化。
如果手眼标定做完之后横竖精度上不去,先把相机内参重新标定一遍。用前面说的25mm棋盘格,在距离相机300到800mm范围内,变换角度拍20到30张棋盘格照片,用OpenCV的calibrateCamera重新计算内参和畸变系数。重标完再重跑手眼标定,往往精度立刻就有改善。
坐标系处理方式也要保持一致。D435的RGB图像带有畸变,手眼标定时标定板检测如果直接用原始图像,那么后续视觉定位链路里也必须一直使用原始图像配合畸变系数,不要中途换用undistort之后的图。如果选择先做去畸变再做角点检测,那整个流程从标定到应用都要统一在去畸变后的图像域里。两种方式混用,等于把坐标系链路人为打乱,误差不会小。
6.2 从机械臂端排查:TCP设置、回差、安装刚性
机械臂端的排查优先级其实很高,但我见过太多人一上来就重采数据重解算,完全忽略机械臂本身。TCP设置错误是高频问题,标定时的参考坐标系和后续作业时的参考坐标系不一致,手眼矩阵就失去了意义。每次开始标定前,先在示教器上确认当前激活的TCP是不是你想用的那个,尤其当现场有多套夹具切换时,这个问题特别容易出现。
机械臂回差方面,UR的关节减速器在换向时会有微小的空程,虽然很小,但到了毫米级精度要求下就不能忽略。采集标定数据时,规律的移动方式能有效抑制回差影响,比如全部让机械臂从同一个方向逼近目标位姿,不要在采集中来回切换运动方向。验证时也保持同方向,这样回差带来的误差是一致的。
安装刚性排查有个特别简单的测试:标定完成后,不移动标定板,直接用手轻轻推一下相机支架,再采一组图像看一下重投影误差。如果推之前后误差变化很大,说明相机支架是挠性结构,机械臂高速运动时相机相对末端的位姿一直在漂。这种问题靠重新标定解决不了,只能换更结实的支架,或者在采集数据时把机械臂运动速度降下来。
6.3 从数据端排查:姿态退化、数量不足和记录错位
如果相机端和机械臂端都查过了,精度还是不行,那大概率问题还是出在数据端。最隐蔽的问题是姿态退化,数据组数足够,但所有姿态几乎一样,AX=XB的旋转约束实际不充分。应对方法就是用两种解法交叉验证,结果差异明显就回去补姿态,不需要猜测。
标定板在采集过程中被移动,也是精度杀手。哪怕只是有人碰了一下桌面,整组数据就废了。这种情况在机房和产线上很常见,旁边人来人往,桌面一震标定板就移位。防止方法是在采集开始前把标定板用双面胶或者重物固定住,固定好之后拍摄一张基准图像,采完所有组之后再拍一张同样的基准图像,对比两次标定板角点位置是否一致。任何漂移都能被发现。
最后就是数据清洗。解算之前,对每一组数据做一次重投影误差检查,把误差明显偏大的组单独剔除,看看剔除之后标定结果是否变稳定。如果去掉某一组数据之后结果大幅变化,说明这一组污染严重。不要舍不得删数据,16组里面剔掉两到三组异常数据,剩下的质量好的组足够得到稳定结果。
按照我个人这几年的实操经验,手眼标定百分之九十的坑都在数据侧,不在数学侧。把相机参数固定好、标定板放平整、位姿姿态摆够、UR的旋转矢量正确转换、数据记录严格对应,OpenCV跑出来的结果基本一次就能用。如果标定完还是不准,不要反复去换求解方法或者调算法的奇奇怪怪参数,回到原始数据逐项过一遍检查清单,通常比瞎试参数有效得多。这套流程也不只限于D435和UR,换成Piper、Aubo、艾利特这些机械臂,只是位姿读取接口变了,思路完全一致。希望这份记录能帮正在做工业机器人系统集成或者毕业设计的你少绕几个弯。