4、视觉传感器与标定:RGB-D相机原理、相机内参/外参标定、手眼标定
做机器人抓取,视觉传感器就是我们的眼睛。但说实话,光有眼睛还不够——你得知道这双眼睛的“度数”对不对,还得知道它长在脑袋的哪个位置。这就是标定的意义。
这一章,我们聚焦三个核心问题:RGB-D相机怎么工作的?相机自身的参数怎么标定?相机和机械臂之间的坐标关系怎么确定?
4.1 RGB-D相机原理:三种主流方案
RGB-D相机,说白了就是能同时输出彩色图和深度图的相机。我最早接触的是Kinect v1,那时候觉得这东西简直是黑科技。现在市面上主流方案有三种,各有各的脾气。
| 方案类型 | 代表产品 | 工作原理 | 典型量程 | 优缺点 |
|---|---|---|---|---|
| 结构光 | Kinect v1, Intel RealSense D415 | 投射红外散斑,通过变形计算深度 | 0.3m - 5m | 室内精度高,室外易受阳光干扰 |
| ToF(飞行时间) | Kinect v2, Azure Kinect | 发射调制光脉冲,测量往返时间 | 0.5m - 8m | 帧率高,多路径干扰需注意 |
| 双目立体视觉 | ZED, Intel RealSense D435i | 双摄像头视差匹配,三角测量 | 0.2m - 20m | 依赖纹理,弱纹理区域容易“瞎” |
嗯,这里要注意一个关键点:深度图不是直接测量出来的,而是通过某种数学模型算出来的。所以,标定就是给这个数学模型“校准刻度”。
4.2 相机内参标定:给眼睛配副眼镜
相机内参,描述的是“三维世界点怎么映射到二维像素”。说白了,就是相机的焦距、主点坐标和畸变系数。
我个人习惯用张正友标定法,一张棋盘格就能搞定。流程很简单:
- 打印一张棋盘格,贴在平板上
- 从不同角度拍15-20张照片
- 提取角点,建立对应关系
- 用最小二乘法求解内参矩阵和畸变系数
内参矩阵长这样:
K = [fx 0 cx
0 fy cy
0 0 1]
其中fx、fy是焦距(像素单位),cx、cy是主点坐标。畸变系数一般包括径向畸变k1、k2、k3和切向畸变p1、p2。
对于RGB-D相机,你还需要做“深度-彩色对齐”。因为深度传感器和彩色传感器通常不在同一个位置,它们的视野有视差。这一步通常由SDK完成,但如果你自己写驱动,就得手动做外参标定。
4.3 相机外参标定:把相机放到世界坐标系里
外参描述的是“相机坐标系”和“世界坐标系”之间的旋转和平移关系。说白了,就是相机在世界中的位置和朝向。
外参标定通常需要借助一个已知尺寸的标定物。我常用的方法是:
- 把棋盘格放在工作台面上,定义棋盘格坐标系为世界坐标系
- 拍摄一张包含棋盘格的图像
- 通过PnP算法求解相机相对于棋盘格的位姿
PnP问题的数学本质是:已知3D点(棋盘格角点)和对应的2D投影点,求解相机的外参矩阵[R|t]。
s * [u, v, 1]^T = K * [R|t] * [X, Y, Z, 1]^T
其中s是尺度因子,K是内参矩阵,[R|t]是外参矩阵。
你想想看,如果外参标定不准,你测出来的物体位置就是歪的。机械臂抓过去,要么抓空,要么撞上去。
4.4 手眼标定:让眼睛和手“对上话”
手眼标定,是机器人抓取里最绕、也最容易出错的一步。它解决的是“相机坐标系”和“机械臂基坐标系”之间的变换关系。
根据相机安装位置,分两种情况:
- Eye-in-Hand(眼在手上):相机装在机械臂末端,跟着臂一起动
- Eye-to-Hand(眼在手外):相机固定在工作台上,看机械臂干活
我最早做抓取时用的是Eye-in-Hand方案。标定原理是:让机械臂带着相机从不同角度拍同一个标定板,利用“闭环约束”求解手眼矩阵。
数学上,手眼标定要解一个形如AX=XB的方程:
A = 机械臂末端在基坐标系下的变换矩阵(从示教器读)
B = 标定板在相机坐标系下的变换矩阵(从图像算)
X = 相机在机械臂末端坐标系下的变换矩阵(待求)
标定步骤:
- 固定标定板在工作台上
- 控制机械臂走15-20个不同姿态
- 每个姿态记录:机械臂末端位姿 + 标定板图像
- 用Tsai-Lenz或Park-Martin算法求解AX=XB
下面这张图展示了手眼标定的核心逻辑:
4.5 标定精度验证:别让误差骗了你
标定做完,别急着用。我见过太多人标定完直接上抓取,结果误差大得离谱。验证方法很简单:
- 拿一个已知尺寸的物体(比如一个100mm的立方体),放在工作台上
- 用标定好的系统测量它的位置和姿态
- 和实际值对比,看误差有多大
一般来说,内参标定误差应该小于0.5像素,手眼标定误差应该小于2mm。如果超过这个范围,建议重新标定。
4.6 标定工具推荐
工欲善其事,必先利其器。这里列几个我常用的工具:
| 工具 | 用途 | 备注 |
|---|---|---|
| OpenCV cv::calibrateCamera() | 内参标定 | 支持棋盘格、圆点格 |
| OpenCV cv::solvePnP() | 外参标定 | 需要已知3D-2D对应点 |
| easy_handeye (ROS) | 手眼标定 | 支持Eye-in-Hand和Eye-to-Hand |
| Kalibr | 多相机联合标定 | 支持RGB-D相机内参+外参 |
嗯,这一章的内容就到这里。标定这件事,说白了就是“把误差控制在可接受范围内”。别追求理论上的完美,够用就行——但“够用”的标准,得靠你的实际抓取任务来定。