2. 手眼标定中的坐标系定义

任务目标

在机器人手眼标定中,所有计算都围绕坐标系之间的变换关系展开。本案例定义手眼标定涉及的四个核心坐标系,并建立它们之间的齐次变换矩阵链,为后续标定求解提供统一的数学表达基础。

坐标系定义

符号名称说明
{B}机器人基座坐标系固定在机器人底座,世界参考系
{E}工具(末端)坐标系固定在法兰盘或工具上
{C}相机坐标系固定在相机光心
{G}标定板坐标系固定在标定板角点平面

手眼标定分为两种构型:眼在手上(Eye-in-Hand)——相机固定在工具上,相机随机械臂运动;眼在手外(Eye-to-Hand)——相机固定在工作空间,标定板装在工具上。本案例以眼在手上构型为例建立变换链。

齐次变换矩阵链

眼在手上构型中,标定板固定于工作台,相机随工具运动。核心变换关系为:

^{B}T_{G} = ^{B}T_{E}(t) \cdot ^{E}T_{C} \cdot ^{C}T_{G}(t)

其中:

  • ^{B}T_{E}(t):机器人正运动学给出的末端位姿(随时间变化,已知)
  • ^{E}T_{C}:相机到工具的外参(固定不变,待求)
  • ^{C}T_{G}(t):相机观测标定板得到的外参(随时间变化,已知)
  • ^{B}T_{G}:标定板在基座坐标系中的位姿(固定不变)

对两个不同时刻 t₁、t₂ 分别建立方程并消去 ^{B}T_{G},即可得到经典手眼标定方程 AX = XB,其中 X = ^{E}T_{C} 为待求量。

齐次变换矩阵表示

任意坐标系间的变换用 4×4 齐次矩阵表示:

T = [ R  t ]
    [ 0  1 ]

其中 R 为 3×3 旋转矩阵,t 为 3×1 平移向量。本案例用 Python 的 numpy 实现矩阵构建与链式乘法验证。

完整实现代码

import numpy as np

def rot_x(theta):
    """绕X轴旋转theta弧度"""
    c, s = np.cos(theta), np.sin(theta)
    return np.array([[1, 0, 0],
                     [0, c, -s],
                     [0, s,  c]])

def rot_z(theta):
    """绕Z轴旋转theta弧度"""
    c, s = np.cos(theta), np.sin(theta)
    return np.array([[c, -s, 0],
                     [s,  c, 0],
                     [0,  0, 1]])

def make_t(R, t):
    """由旋转矩阵和平移向量构造4x4齐次矩阵"""
    T = np.eye(4)
    T[:3, :3] = R
    T[:3, 3] = t
    return T

# ===== 模拟两组已知数据(眼在手上) =====
# 时刻1:机器人末端位姿(基座→工具)
R_e1 = rot_z(0.3) @ rot_x(0.1)
t_e1 = np.array([0.5, 0.2, 0.4])
T_BE1 = make_t(R_e1, t_e1)

# 时刻1:相机观测标定板(相机→标定板)
R_g1 = rot_x(0.05) @ rot_z(-0.2)
t_g1 = np.array([0.1, -0.15, 0.6])
T_CG1 = make_t(R_g1, t_g1)

# 时刻2:机器人末端位姿
R_e2 = rot_z(0.5) @ rot_x(0.2)
t_e2 = np.array([0.45, 0.3, 0.35])
T_BE2 = make_t(R_e2, t_e2)

# 时刻2:相机观测标定板
R_g2 = rot_x(0.08) @ rot_z(-0.35)
t_g2 = np.array([0.12, -0.1, 0.55])
T_CG2 = make_t(R_g2, t_g2)

# ===== 验证变换链闭合性 =====
# 标定板在基座中的位姿应不随时间变化(理想情况下)
T_BG1 = T_BE1 @ T_CG1   # 注意:此处假设相机与工具重合(E=T_C为单位阵)
T_BG2 = T_BE2 @ T_CG2

print("时刻1 标定板在基座中的位姿:")
print(T_BG1)
print("\n时刻2 标定板在基座中的位姿:")
print(T_BG2)
print("\n两次计算差异(应接近零矩阵):")
print(T_BG1 - T_BG2)

运行与验证

运行方式:将上述代码保存为 coordinate_def.py,在已安装 numpy 的 Python 环境中执行:

python coordinate_def.py

验证方法:观察输出的两次标定板位姿矩阵差异。由于示例数据是人为构造的(未经过真实标定求解),两次结果不会完全一致,差异矩阵非零属正常现象。本案例的验证重点是:

  1. 代码能正确构建 4×4 齐次矩阵并完成链式乘法;
  2. 理解 ^{B}T_{G} = ^{B}T_{E} · ^{E}T_{C} · ^{C}T_{G} 的变换顺序;
  3. 确认当 ^{E}T_{C} 为单位阵(相机与工具重合)时,变换链退化为 ^{B}T_{G} = ^{B}T_{E} · ^{C}T_{G},即代码中 T_BE @ T_CG 的运算。

通过条件:程序无报错运行,输出两个 4×4 矩阵及差异矩阵,且差异矩阵中平移部分数量级与构造数据时人为设定的位姿变化量一致(说明变换链计算正确)。若需验证真实标定结果,需在后续案例中求解 ^{E}T_{C} 后再代入本变换链。

关键说明

本案例仅建立坐标系定义与变换链表示,不涉及标定求解。实际手眼标定中,^{B}T_{E} 由机器人控制器提供,^{C}T_{G} 由相机拍摄标定板后通过PnP求解获得,两者均为已知量;未知量 ^{E}T_{C} 的求解方法在后续案例中展开。