视觉标定
机器人配相机做视觉引导抓取时,要标定相机坐标与机器人坐标的关系,这一步叫手眼标定。
两种安装方式
| 类型 | 相机安装位置 | 适用 |
|---|---|---|
| 眼在手上(Eye-in-Hand) | 相机装在机器人末端 | 灵活变换视角,精度较高 |
| 眼在手外(Eye-to-Hand) | 相机装在固定支架 | 多机器人共用视野,视野稳定 |
标定流程
准备
- 打印一块标定板(棋盘格 / Charuco / ArUco)
- 固定标定板(眼在手上)或装到机器人末端(眼在手外)
- 连好相机并能在 IDE 中取到画面
执行
- 项目浏览器 → 机器人 → 右键 → 视觉标定
- 选相机实例和安装方式
- 按向导提示,让机器人走 10~20 个不同位姿,每次点一下「拍照」
- 系统自动算出相机与机器人的变换矩阵
- 保存为该机器人的视觉配置
验证
标定完后,在 3D 视口里打开视觉叠加:
- 相机检测到的物体应与 3D 场景里同位置吻合
- 误差通常在 1mm 以内,超过需要重新标定
使用标定结果
标定完成后,在程序里直接调:
Robot.MoveToDetectedPoint(camera, object_id)
系统自动把相机坐标转到机器人坐标,机器人运动到目标点。
常见问题
| 现象 | 原因 |
|---|---|
| 误差大(>5mm) | 标定位姿太相似,差异不够大 |
| 相机图像模糊 | 对焦/光照问题,先解决再标定 |
| 标定失败提示"外点过多" | 标定板部分被遮挡,或标定板变形 |
| 换相机后不对 | 手眼标定是相机+机器人成对的,换任一方都要重标 |
精度
达到的精度取决于:
- 相机分辨率(像素/mm)
- 标定板精度(推荐激光印刷、油墨不反光)
- 机器人定位重复性
- 标定位姿多样性
典型视觉抓取应用可达 ±0.5mm 左右。
手眼标定数学原理
Eye-in-Hand 模型
相机装在法兰, 相机坐标系到法兰的变换 ^{Flange}T_{Cam} 是待求常量. 标定板在世界坐标 (固定), 设标定板坐标系到世界 ^{World}T_{Board}. 每次拍照得到相机到标定板 ^{Cam}T_{Board}, 机器人读出 ^{World}T_{Flange}. 约束:
^{World}T_{Flange,i} · ^{Flange}T_{Cam} · ^{Cam}T_{Board,i} = ^{World}T_{Board}
取 2 次不同位姿 i 和 j, 两式消去 ^{World}T_{Board}:
A_i · X = X · B_i (即 AX = XB 问题)
其中 A_i = ^{World}T_{Flange,i}^{-1} · ^{World}T_{Flange,j}, B_i = ^{Cam}T_{Board,i} · ^{Cam}T_{Board,j}^{-1}, X = ^{Flange}T_{Cam} 是待求变换。
求解算法
经典算法 Tsai-Lenz (1989) / Shah-Ahmad / Park-Martin / Daniilidis 的对偶四元数法:
- Tsai: 旋转先解, 再平移, 精度中, 速度快
- Park: 用李代数 so(3) + R³, 精度高
- Daniilidis: 对偶四元数, 一次解出 R + t, 精度最高
Darra 默认用 Park, 典型残差 < 0.3 mm。
Eye-to-Hand 模型
相机装在固定支架, 标定板装到法兰上. 约束形式类似, 只是 X 的意义变为相机到世界的变换:
^{Cam}T_{Flange,i} · ^{Flange}T_{Board} = ^{Cam}T_{World} · ^{World}T_{Flange,i} · ^{Flange}T_{Board}
算法一致, 代码里只需换角色分配。
标定板选择
| 标定板 | 特征 | 精度 | 成本 |
|---|---|---|---|
| 棋盘格 (Checkerboard) | 简单, 经典, 要求整个板在视野内 | 0.1~0.3 mm | 低 |
| Charuco | 棋盘 + ArUco, 允许部分遮挡 | 0.05~0.2 mm | 低 |
| ArUco / AprilTag | 单独二维码, 可多张分散 | 0.3~1 mm | 低 |
| 圆点阵列 | 亚像素圆心定位, 精度高 | 0.05~0.1 mm | 中 |
| 激光印刷高精度板 | 厂家校准 | 0.01 mm | 高 (5000+ 元) |
对高精度应用 (< 0.5 mm TCP 误差), 推荐激光印刷圆点阵列。
标定数据采集策略
拍照位姿的选择直接决定标定精度. 建议:
- 10~20 个位姿, 至少 10 个
- 位姿覆盖整个工作空间 (不要堆在一角)
- 姿态多样化: 6 个自由度都有差异 > 20°
- 标定板在相机视野中心占 50~80% (太小精度低, 太大边缘畸变)
- 每个位姿 2~3 次拍照取平均 (减小单帧噪声)
Darra 向导会提示下一个建议位姿, 按提示走即可。
多相机同步
多相机系统 (双目 / 多目) 标定:
- 每个相机独立做手眼
- 统一到机器人 World 坐标系
- 多相机视图可融合定位 (鲁棒性 + 精度都提升)
在线验证
标定结束后, 视口叠加验证:
- 打开 3D 视口 → 视觉叠加
- 相机实时画面和 3D 场景并列
- 相机画面里检测到的物体边缘应与 3D 模型完美重合
- 偏差 > 2 mm → 标定失败, 重标
快速重标 (换相机 / 换镜头)
只换镜头 (焦距不变): 重做内参标定 (10 张棋盘格, 5 分钟), 不用重做外参手眼。
换相机机身: 全部重标 (内参 + 手眼)。
换镜头且焦距不同: 全部重标。
相机内参
手眼标定前必须先做相机内参标定, 获取:
| 内参 | 说明 |
|---|---|
| fx, fy | 焦距 (像素) |
| cx, cy | 主点 (像素) |
| k1, k2, k3 | 径向畸变 |
| p1, p2 | 切向畸变 |
内参用 10~20 张不同角度的棋盘格照片, OpenCV calibrateCamera 求解。Darra IDE 自带内参标定工具, 一键完成。
SCL 代码示例
VAR
HandEye : MC_VisionCalibration;
Visual : MC_VisionDetect;
pTarget : ROBOT_POS;
END_VAR
// 手眼标定 (只需做一次)
HandEye(
Robot := Robot1,
Camera := Cam1,
MountType := VISION_EYE_IN_HAND,
Method := CALIB_PARK,
BoardType := BOARD_CHARUCO,
BoardSize := (X := 9, Y := 6, Square := 25.0), // mm
Execute := bStartCal
);
// 使用 (生产时)
Visual(
Camera := Cam1,
Execute := bTrigger,
ObjectId := 1
);
IF Visual.Done AND Visual.Detected THEN
pTarget := Visual.DetectedPose; // 已自动变换到机器人 World
MoveL(Target := pTarget, Velocity := 100);
END_IF;
参数表
| 参数 | 类型 | 单位 | 默认 | 说明 |
|---|---|---|---|---|
| MountType | ENUM | - | EYE_IN_HAND | 安装类型 |
| Method | ENUM | - | PARK | Tsai/Park/Daniilidis |
| BoardType | ENUM | - | CHECKERBOARD | 标定板类型 |
| BoardSize X / Y | UINT | - | 9/6 | 棋盘格内角点数 |
| SquareSize | LREAL | mm | 25.0 | 格子边长 |
| MinPoses | UINT | - | 10 | 最少位姿数 |
| ResidualThreshold | LREAL | mm | 0.5 | 残差阈值 |
| CameraIntrinsics | MAT3X3 | - | - | 内参矩阵 (需先标) |
| DistCoeffs | LREAL[5] | - | - | 畸变系数 |
最佳实践
- 内参先行: 内参不准 = 手眼一定不准. 内参标定用 20 张以上
- 标定板高精度: 图书店打印的 A4 棋盘格误差 > 1 mm, 精度要求高必须买激光印刷
- 固定光源: 标定时关闭车间顶灯用工业光源, 光照变化严重影响精度
- 15 个位姿以上: 位姿少 → 标定结果不稳
- 温度稳定: 机器人和相机开机 30 min 再标
- 定期复检: 一个月复检一次, 精度衰减 > 0.3 mm 就重标
- 保存标定文件: 标定成功后自动保存到
vision_calib_YYYYMMDD.json, 历史追溯