想象一下:汽车装配线上,搭载3D相机的机械臂精准抓取悬空的变速箱零件——这令人惊叹的精准协同背后,核心秘密正是 “手眼标定” 。当机器人需要“看懂”并“操作”三维世界时,手眼标定代码就是那双为其赋予空间感知与精度的无形之手。
为何手眼标定是3D视觉的基石?
在机器人3D视觉系统中,相机如同机器人的“眼睛”,机械臂是其“手臂”。然而,相机安装在机械手末端(Eye-in-Hand)或固定支架上(Eye-to-Hand)时,它所“看到”的三维点云坐标(相机坐标系)与机器人控制器“认为”的末端工具位置(工具坐标系)或基座位置(基坐标系)天然存在坐标系的鸿沟。
手眼标定背后的数学与流程
手眼标定的核心数学模型是一个经典的矩阵方程:AX = XB。
T_tool_cam 或相机到基坐标系的变换 T_base_cam)。标准标定流程(以Eye-in-Hand为例):
robot_pose_i: 机器人当前末端工具中心点(TCP)在基坐标系下的位姿(齐次变换矩阵 T_base_tool_i)。cam_pose_i: 通过图像处理和对标定板的PnP求解计算出的标定板在当前相机坐标系下的位姿(齐次变换矩阵 T_cam_board_i)。因为标定板固定,它在基坐标系下的位姿 T_base_board *应*是常量(忽略微小振动)。A_ij = inv(T_base_tool_i) * T_base_tool_j (从i到j,工具坐标系视角)。B_ij = inv(T_cam_board_i) * T_cam_board_j (从i到j,相机坐标系视角)。A_ij * X = X * B_ij (其中 X = T_tool_cam)。OpenCV中的 calibrateHandEye 函数提供多种解法:Tsai (经典稳定)Park (另一种解析法)Horaud (基于旋转向量)Andreff (基于激光跟踪仪等外置设备数据,精度高但复杂)Daniilidis (四元数法)求解这个超定方程组,得到最优的 T_tool_cam (X)。核心代码实现要点(概念性伪代码)
”`python
calibration_data = load_data(‘calibration_data.h5’) # 包含所有姿态的 robot_pose_i 和 cam_pose_i (标定板在相机坐标系下的位姿)
R_gripper2base = [] # 存储机器人运动旋转部分 (A_ij 的旋转) t_gripper2base = [] # 存储机器人运动平移部分 (A_ij 的平移) R_target2cam = [] # 存储相机运动旋转部分 (B_ij 的旋转) t_target2cam = [] # 存储相机运动平移部分 (B_ij 的平移)
for i in range(0, len(calibration_data) - 1): for j in range(i + 1, len(calibration_data)):
T_base_tool_i = calibration_data[i][‘robot_pose’] T_base_tool_j = calibration_data[j][‘robot_pose’] T_tool_i_tool_j = np.linalg.inv(T_base_tool_i) @ T_base_tool_j # 工具坐标系从i到j的运动
R_A = T_tool_i_tool_j[:3, :3] t_A = T_tool_i_tool_j[:3, 3] R_gripper2base.append(R_A) t_gripper2base.append(t_A)
T_cam_i_board = calibration_data[i][‘cam_pose’] # 标定板在姿态i时的相机坐标 T_cam_j_board = calibration_data[j][‘cam_pose’] # 标定板在姿态j时的相机坐标 T_board_cam_i = np.linalg.inv(T_cam_i_board) # 相机在姿态i时相对于标定板的位姿 T_board_cam_j = np.linalg.inv(T_cam_j_board) # 相机在姿态j时相对于标定板的位姿 T_cam_i_cam_j = T_board_cam_i @ np.linalg.inv(T_board_cam_j)