1. 手眼标定问题概述
手眼标定(Hand-Eye Calibration)是机器人视觉和自动化领域的一个基础性问题。简单来说,就是确定安装在机器人末端执行器上的相机(或其他传感器)与机器人末端之间的相对位姿关系。这种标定在工业机器人、医疗机器人和自动驾驶等领域都有广泛应用。
在实际应用中,我们通常会遇到两种配置方式:
- 眼在手中(Eye-in-Hand):相机固定在机器人末端
- 眼在手外(Eye-to-Hand):相机固定在机器人工作空间中的某个固定位置
本文重点讨论Eye-in-Hand配置下的标定问题,其核心数学表达可以抽象为求解方程AX=XB,其中:
- A表示机器人末端执行器的运动变换
- B表示相机观测到的运动变换
- X就是我们要求解的相机相对于机器人末端的位姿变换
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 问题建模与数学表达
2.1 坐标系定义
首先我们需要明确几个关键坐标系:
- 机器人基坐标系(Base Frame)
- 末端执行器坐标系(Gripper Frame)
- 相机坐标系(Camera Frame)
- 标定板坐标系(Calibration Target Frame)
2.2 变换关系表达
对于Eye-in-Hand配置,当机器人末端移动时,相机会随之移动。设在时刻i和j,有以下变换关系:
- 机器人末端相对于基座的变换:Hg_i, Hg_j
- 相机相对于标定板的变换:Hc_i, Hc_j
- 相机相对于机器人末端的变换:X(待求)
根据坐标系变换关系,可以得到:
code复制Hgij = Hg_j^-1 * Hg_i
Hcij = Hc_j * Hc_i^-1
X * Hcij = Hgij * X
这就是经典的AX=XB问题。
2.3 问题分解
AX=XB可以分解为旋转和平移两部分求解:
- 旋转部分:R_A * R_X = R_X * R_B
- 平移部分:R_A * t_X + t_A = R_X * t_B + t_X
其中R表示旋转矩阵,t表示平移向量。
3. Tsai-Lenz算法详解
Tsai-Lenz算法是解决AX=XB问题的经典方法,由Roger Y. Tsai和Reinhard K. Lenz于1989年提出。该算法采用两步法:先求解旋转部分,再求解平移部分。
3.1 旋转求解
3.1.1 旋转向量表示
使用旋转向量(轴角表示法)来表达旋转:
- 对于Hgij,计算其旋转向量Pgij
- 对于Hcij,计算其旋转向量Pcij
根据旋转关系,可以得到方程:
code复制skew(Pgij + Pcij) * Pcg_ = Pcij - Pgij
其中skew()表示向量的反对称矩阵。
3.2.2 最小二乘求解
收集多组数据后,构建超定方程组:
code复制A * Pcg_ = b
其中:
- A由skew(Pgij+Pcij)堆叠而成
- b由Pcij-Pgij堆叠而成
使用SVD分解求解这个最小二乘问题,得到Pcg_。
3.2.3 旋转矩阵恢复
将解得的Pcg_归一化后,可以通过Rodrigues公式恢复出旋转矩阵Rcg:
code复制Pcg = 2 * Pcg_ / sqrt(1 + Pcg_'*Pcg_)
Rcg = quat2rot(Pcg/2)
3.2 平移求解
3.2.1 构建线性方程组
在求得旋转矩阵Rcg后,平移部分可以表示为:
code复制(Rgij - I) * Tcg = Rcg*Tcij - Tgij
其中:
- Rgij, Tgij来自Hgij
- Tcij来自Hcij
- Tcg是待求的平移向量
3.2.2 最小二乘求解
同样收集多组数据构建方程组:
code复制AA * Tcg = bb
使用SVD分解求解这个最小二乘问题,得到Tcg。
4. 李代数解法
4.1 李群与李代数基础
三维空间中的刚体运动属于特殊欧氏群SE(3),其对应的李代数为se(3)。李群和李代数之间通过指数映射和对数映射相互转换:
code复制exp: se(3) → SE(3)
log: SE(3) → se(3)
4.2 李代数下的AX=XB
将AX=XB两边取对数,可以得到:
code复制log(A) + Ad_A log(X) = log(X) + Ad_X log(B)
其中Ad表示伴随表示。
4.3 解析解推导
通过适当的数学处理,可以将上述方程转化为线性方程组求解。具体步骤包括:
- 将李代数元素表示为twist坐标
- 利用伴随表示的性质简化方程
- 构建关于X的线性方程组
- 使用最小二乘法求解
这种方法相比Tsai-Lenz算法,在数学上更为优雅,且能直接得到解析解表达式。
5. 实现细节与代码分析
5.1 OpenCV实现
OpenCV中提供了calibrateHandEye()函数,实现了多种手眼标定算法,包括Tsai-Lenz算法。其核心代码如下:
cpp复制void calibrateHandEyeTsai(const std::vector<Mat>& Hg, const std::vector<Mat>& Hc,
Mat& R_cam2gripper, Mat& t_cam2gripper)
{
// 旋转部分求解
Mat A, b;
for(size_t i=0; i<Hg.size(); i++) {
for(size_t j=i+1; j<Hg.size(); j++) {
Mat Hgij = homogeneousInverse(Hg[j]) * Hg[i];
Mat Hcij = Hc[j] * homogeneousInverse(Hc[i]);
Mat Pgij = 2*rot2quatMinimal(Hgij);
Mat Pcij = 2*rot2quatMinimal(Hcij);
skew(Pgij+Pcij).copyTo(A.push_back());
(Pcij - Pgij).copyTo(b.push_back());
}
}
// 求解旋转
Mat Pcg_ = A \ b; // 伪逆求解
Mat Pcg = 2 * Pcg_ / sqrt(1 + Pcg_'*Pcg_);
R_cam2gripper = quatMinimal2rot(Pcg/2.0);
// 平移部分求解
Mat AA, bb;
for(size_t i=0; i<Hg.size(); i++) {
for(size_t j=i+1; j<Hg.size(); j++) {
Mat Hgij = homogeneousInverse(Hg[j]) * Hg[i];
Mat Hcij = Hc[j] * homogeneousInverse(Hc[i]);
(Hgij(Rect(0,0,3,3)) - eye(3,3)).copyTo(AA.push_back());
(R_cam2gripper*Hcij(Rect(3,0,1,3)) - Hgij(Rect(3,0,1,3))).copyTo(bb.push_back());
}
}
t_cam2gripper = AA \ bb; // 伪逆求解
}
5.2 Python实现
以下是使用Python和transforms3d库实现的Tsai-Lenz算法:
python复制import numpy as np
import transforms3d as tfs
def skew(v):
return np.array([[0,-v[2],v[1]],
[v[2],0,-v[0]],
[-v[1],v[0],0]])
def tsai_handeye(Hgs, Hcs):
# 旋转部分
A, b = [], []
for i in range(len(Hgs)):
for j in range(i+1, len(Hgs)):
Hgij = np.linalg.inv(Hgs[j]) @ Hgs[i]
Hcij = Hcs[j] @ np.linalg.inv(Hcs[i])
Pgij = 2 * tfs.quaternions.mat2quat(Hgij[:3,:3])[1:]
Pcij = 2 * tfs.quaternions.mat2quat(Hcij[:3,:3])[1:]
A.append(skew(Pgij + Pcij))
b.append(Pcij - Pgij)
A = np.vstack(A)
b = np.vstack(b)
Pcg_ = np.linalg.pinv(A) @ b
Pcg = 2 * Pcg_ / np.sqrt(1 + Pcg_.T @ Pcg_)
Rcg = tfs.quaternions.quat2mat(np.concatenate([
[np.sqrt(1 - np.linalg.norm(Pcg/2)**2)], Pcg.flatten()/2]))
# 平移部分
AA, bb = [], []
for i in range(len(Hgs)):
for j in range(i+1, len(Hgs)):
Hgij = np.linalg.inv(Hgs[j]) @ Hgs[i]
Hcij = Hcs[j] @ np.linalg.inv(Hcs[i])
AA.append(Hgij[:3,:3] - np.eye(3))
bb.append(Rcg @ Hcij[:3,3:] - Hgij[:3,3:])
AA = np.vstack(AA)
bb = np.vstack(bb)
Tcg = np.linalg.pinv(AA) @ bb
return np.vstack([np.hstack([Rcg, Tcg]), [0,0,0,1]])
6. 实践注意事项
6.1 数据采集要点
- 运动多样性:机器人末端应进行充分的旋转和平移运动,确保运动覆盖各个方向
- 运动幅度:相邻位姿间的运动不宜过小,否则会增大噪声影响
- 数据量:建议至少采集10组以上数据,太少会导致求解不稳定
- 标定板观测:确保相机在每个位姿都能清晰看到标定板
6.2 常见问题排查
-
标定结果不稳定:
- 检查机器人运动是否充分
- 验证标定板检测精度
- 增加数据采集量
-
旋转部分求解误差大:
- 确保机器人末端有足够的旋转运动
- 检查机器人运动学参数是否正确
-
平移部分求解误差大:
- 确保机器人末端有足够的平移运动
- 检查标定板尺寸参数是否正确
6.3 精度验证方法
- 重投影误差:将标定结果用于重投影,计算误差
- 闭环验证:让机器人执行闭环运动,验证末端位置一致性
- 多方法对比:使用不同算法求解,比较结果一致性
7. 算法比较与选择
7.1 Tsai-Lenz vs 李代数方法
| 特性 | Tsai-Lenz算法 | 李代数方法 |
|---|---|---|
| 数学基础 | 旋转向量+最小二乘 | 李群李代数理论 |
| 求解方式 | 分步求解(先旋转后平移) | 联合求解 |
| 实现复杂度 | 中等 | 较高 |
| 数值稳定性 | 较好 | 优秀 |
| 数据要求 | 需要充分旋转运动 | 对运动多样性要求更高 |
7.2 其他算法简介
- Park-Martin方法:基于欧氏群上的优化
- Daniilidis方法:使用对偶四元数表示
- Andreff方法:基于视觉伺服框架
在实际应用中,Tsai-Lenz算法因其稳定性和实现简单性,通常作为首选方法。当对精度要求极高时,可考虑李代数方法或其他更先进的算法。
8. 扩展应用与前沿发展
手眼标定技术除了在传统工业机器人领域应用外,近年来也在以下领域得到扩展:
- 多传感器标定:如相机-激光雷达、相机-IMU等标定
- 医疗机器人:手术导航系统中的工具标定
- 自动驾驶:车载多传感器系统标定
- AR/VR:追踪设备与显示设备的标定
前沿研究方向包括:
- 基于深度学习的手眼标定方法
- 在线自适应标定技术
- 多机器人协同标定系统
