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 依赖纹理,弱纹理区域容易“瞎”
我的经验:抓取场景里,结构光和ToF用得最多。如果你要在透明物体或高反光表面干活,双目反而更靠谱——因为结构光和ToF在这些材质上会“炸点”。

嗯,这里要注意一个关键点:深度图不是直接测量出来的,而是通过某种数学模型算出来的。所以,标定就是给这个数学模型“校准刻度”。

4.2 相机内参标定:给眼睛配副眼镜

相机内参,描述的是“三维世界点怎么映射到二维像素”。说白了,就是相机的焦距、主点坐标和畸变系数。

我个人习惯用张正友标定法,一张棋盘格就能搞定。流程很简单:

  1. 打印一张棋盘格,贴在平板上
  2. 从不同角度拍15-20张照片
  3. 提取角点,建立对应关系
  4. 用最小二乘法求解内参矩阵和畸变系数

内参矩阵长这样:

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 = 相机在机械臂末端坐标系下的变换矩阵(待求)

标定步骤:

  1. 固定标定板在工作台上
  2. 控制机械臂走15-20个不同姿态
  3. 每个姿态记录:机械臂末端位姿 + 标定板图像
  4. 用Tsai-Lenz或Park-Martin算法求解AX=XB
我的习惯:标定时让机械臂走“大范围、多角度”的姿态,不要只在小范围内转。我曾经因为姿态变化太小,导致方程病态,解出来的手眼矩阵误差超过5mm。后来我改成让末端在空间里画“8”字形轨迹,效果好了很多。

下面这张图展示了手眼标定的核心逻辑:

手眼标定核心逻辑 手眼标定核心逻辑(Eye-in-Hand) 机械臂基座 机械臂末端 RGB-D相机 标定板 已知:A 待求:X 已知:B 闭环约束:AX = XB A:从示教器读取的机械臂末端位姿 B:从图像计算得到的标定板位姿 X:待求的手眼矩阵(相机在末端坐标系下的位姿)

4.5 标定精度验证:别让误差骗了你

标定做完,别急着用。我见过太多人标定完直接上抓取,结果误差大得离谱。验证方法很简单:

  • 拿一个已知尺寸的物体(比如一个100mm的立方体),放在工作台上
  • 用标定好的系统测量它的位置和姿态
  • 和实际值对比,看误差有多大

一般来说,内参标定误差应该小于0.5像素,手眼标定误差应该小于2mm。如果超过这个范围,建议重新标定。

我曾经踩过的坑:有一次标定结果看起来很好,重投影误差只有0.3像素。但实际抓取时,机械臂总是偏5mm。查了两天才发现——标定板在打印时被拉伸了1.5%。从那以后,我每次打印棋盘格都会用游标卡尺量一下实际尺寸,再输入到标定程序里。

4.6 标定工具推荐

工欲善其事,必先利其器。这里列几个我常用的工具:

工具 用途 备注
OpenCV cv::calibrateCamera() 内参标定 支持棋盘格、圆点格
OpenCV cv::solvePnP() 外参标定 需要已知3D-2D对应点
easy_handeye (ROS) 手眼标定 支持Eye-in-Hand和Eye-to-Hand
Kalibr 多相机联合标定 支持RGB-D相机内参+外参

嗯,这一章的内容就到这里。标定这件事,说白了就是“把误差控制在可接受范围内”。别追求理论上的完美,够用就行——但“够用”的标准,得靠你的实际抓取任务来定。