4. 手眼标定:AX=XB问题求解、Tsai法与Park法对比
手眼标定,说白了就是让机器人知道自己手里拿的相机到底在哪儿。
我刚开始做这个的时候,觉得不就是解个方程嘛。后来发现,这个方程AX=XB,看着简单,坑可不少。今天咱们就把这个事儿聊透。
4.1 手眼标定的两种模式
先搞清楚场景。你想想看,相机装在机器人手上,这叫“眼在手上”。相机固定在天花板上看机器人动,这叫“眼在手外”。
两种场景下,AX=XB的含义其实一样:
- A:机器人末端从位姿1到位姿2的变换
- B:相机从位姿1到位姿2的变换
- X:相机到机器人末端的固定变换(我们要的)
嗯,这里要注意。A和B都是通过运动算出来的。A来自机器人正运动学,B来自相机外参估计。两个都有误差,所以X的求解是个统计问题。
4.2 AX=XB的数学本质
这个方程其实是个李群上的方程。为什么难?因为X既要满足旋转约束,又要满足平移约束。
展开写就是:
R_A * R_X = R_X * R_B
R_A * t_X + t_A = R_X * t_B + t_X
你看,旋转部分是个齐次方程。平移部分依赖于旋转解。所以一般先解旋转,再解平移。
核心思路:把非线性问题拆成两步。先解旋转矩阵,再代入求平移向量。两步都带最小二乘。
4.3 Tsai法:两步法经典
Tsai法是我个人比较喜欢的方法。它把旋转矩阵参数化成轴角表示,然后线性化求解。
具体步骤:
- 从多组A、B中提取旋转部分,构造线性方程组
- 用最小二乘解出旋转轴方向
- 反解出旋转角度,得到R_X
- 代入平移方程,解t_X
我在项目中遇到过一个问题:Tsai法对旋转角度很小的数据特别敏感。如果机器人每次只转几度,解出来的R_X会飘。所以我建议采集数据时,让机器人转大角度,至少30度以上。
我的习惯:采集20组以上数据,覆盖不同姿态。旋转角度尽量大,平移距离尽量大。数据越丰富,解越稳。
4.4 Park法:李代数上的优化
Park法走的是另一条路。它直接在李代数上做优化,把旋转和平移一起解。
Park法的核心:
- 把旋转矩阵映射到so(3)李代数上
- 构造一个关于X的代价函数
- 用迭代法(比如Levenberg-Marquardt)求解
说实话,Park法比Tsai法更鲁棒。因为它同时优化旋转和平移,不会出现误差传递的问题。
但代价是计算量大。嵌入式平台上跑起来有点吃力。我一般在PC上离线标定,用Park法。在线标定或者快速验证,用Tsai法就够了。
避坑指南:我曾经在Park法里忘了初始化。直接给单位矩阵当初值,结果迭代半天不收敛。后来改成先用Tsai法算个初值,再给Park法做精调,效果好了很多。
4.5 两种方法对比
| 对比项 | Tsai法 | Park法 |
|---|---|---|
| 求解方式 | 两步法,先旋转后平移 | 整体优化,旋转平移同时解 |
| 计算复杂度 | 低,可实时 | 高,需迭代 |
| 对噪声鲁棒性 | 中等,旋转误差会传递 | 较好,整体优化抑制噪声 |
| 数据要求 | 需要大角度运动 | 对运动幅度不敏感 |
| 适用场景 | 快速标定、嵌入式 | 高精度离线标定 |
4.6 代码实现要点
这里给个伪代码框架,你写的时候可以参考:
// Tsai法核心
function tsai_calibration(A_list, B_list):
// 1. 提取旋转矩阵
for each pair (A, B):
R_A = A[0:3, 0:3]
R_B = B[0:3, 0:3]
// 构造轴角方程
P_A = rotation_to_axis_angle(R_A)
P_B = rotation_to_axis_angle(R_B)
// 堆叠成线性方程组
H += cross_product_matrix(P_A + P_B)
g += P_B - P_A
// 2. 解最小二乘
P_X = H \ g
R_X = axis_angle_to_rotation(P_X)
// 3. 解平移
for each pair:
t_X = solve_translation(R_A, t_A, R_B, t_B, R_X)
return R_X, mean(t_X)
// Park法核心
function park_calibration(A_list, B_list):
// 1. 用Tsai法初始化
R_X_init, t_X_init = tsai_calibration(A_list, B_list)
// 2. 构造代价函数
function cost(X):
total = 0
for each (A, B):
error = A * X - X * B
total += norm(error)
return total
// 3. LM优化
X_opt = levenberg_marquardt(cost, [R_X_init, t_X_init])
return X_opt
小技巧:写代码时,记得把旋转矩阵归一化。数值误差会导致R_X不是正交矩阵,用SVD投影回SO(3)群上。
4.7 误差分析与补偿
标定完了,怎么知道准不准?我一般看两个指标:
- 重投影误差:用标定结果把3D点投影到图像上,看像素偏差
- 残差范数:把X代回AX=XB,看等式两边的差
如果误差大,先检查数据质量。我遇到过最坑的一次,是机器人运动学参数没校准,导致A矩阵本身就有问题。标了半天,越标越差。
补偿方法:
- 用多组数据做加权最小二乘,剔除离群点
- 对旋转和平移分别做RANSAC
- 最后用非线性优化做全局精调
嗯,说白了就是:数据要干净,方法要合适,结果要验证。这三步走下来,手眼标定基本不会出大问题。
可可精品资料库