# 手眼标定与多传感器时空同步实操手册：RealSense / ZED 2i / Livox Mid-360 与机械臂/四足联合标定

> 原文链接：https://robotics.hellobike.com/tutorials/camera-lidar-arm-hand-eye-calibration-guide
> 频道：tutorials | 更新日期：2026-10-21 | 标签：手眼标定, Eye-in-Hand, Eye-to-Hand, RealSense, Mid-360, 外参标定
> 核心摘要：从 Eye-in-Hand（眼在手上）与 Eye-to-Hand（眼在手外）坐标变换数学模型出发，给出基于 ROS 2 Humble、AprilTag、easy_handeye2 与 LiDAR-IMU 标定的完整工程步骤。

# 手眼标定与多传感器时空同步实操手册

在具身智能数据采集（VLA / Diffusion Policy）和视觉抓取（MoveIt 2 / GraspNet）中，**80% 的真机抓取失败并非源于算法精度不够，而是源于相机光学坐标系与机械臂基座/末端坐标系之间的外参偏差（超过 5mm 即可导致精细插拔或夹取失败）**。

---

## 1. 两种标定构型与方程定义

```text
【构型 A：Eye-in-Hand（眼在手上 / 腕部相机）】      【构型 B：Eye-to-Hand（眼在手外 / 头部或第三视角固定相机）】
  相机固联在机械臂末端法兰 (link6 / hand) 上，        相机固定在桌面支架或机器人头部/胸部，
  标定板固定在桌面上不动。                            标定板固联在机械臂夹爪末端随机械臂运动。
  求解目标：T_{gripper}^{camera} (X)                  求解目标：T_{base}^{camera} (X)
  核心方程：A_i * X = X * B_i                         核心方程：A_i * X = Z * B_i
```

### 黄金避坑法则：永远核对 `camera_color_optical_frame`
无论是 RealSense D435i/D405 还是 Stereolabs ZED 2i，图像像素 `(u, v)` 与深度值 `d` 反投影出的 3D 点 `(X, Y, Z)` 均定义在 **光学坐标系（`*_optical_frame`：Z 轴朝前指代景深、X 轴朝右、Y 轴朝下）**，而**不是**外壳连杆坐标系（`camera_link`：X 轴朝前、Y 轴朝左、Z 轴朝上）。标定节点中传入的 `tracking_base_frame` 必须填 `camera_color_optical_frame`。

---

## 2. 基于 ROS 2 Humble + AprilTag 的标准标定流程

### 2.1 启动相机与 AprilTag 检测节点

```bash
## 1. 启动 RealSense 相机并开启深度对齐到彩色图
ros2 launch realsense2_camera rs_launch.py \
  align_depth.enable:=true \
  pointcloud.enable:=true \
  rgb_camera.profile:=1280x720x30

## 2. 启动 AprilTag 36h11 标定板位姿解算节点（请用游标卡尺实测打印出来的黑色方框边长 size！）
ros2 run apriltag_ros apriltag_node --ros-args \
  -r image_rect:=/camera/camera/color/image_raw \
  -r camera_info:=/camera/camera/color/camera_info \
  -p family:=36h11 \
  -p size:=0.050
```

### 2.2 采样 18–25 组非退化姿态并求解蔡氏方程（Tsai-Lenz / Daniilidis）
采集姿态时必须覆盖**绕 X、Y、Z 三个轴的充分旋转（角度变化 `>= 25°`）**。若机械臂只做纯平移运动，旋转矩阵 `R_A` 为单位阵，手眼标定方程会严重病态退化！

```python
import cv2
import numpy as np

## R_gripper2base, t_gripper2base: 从机械臂正运动学 /tf (base_link -> link6) 读取的 N 组位姿
## R_target2cam, t_target2cam: 从 AprilTag (camera_color_optical_frame -> tag_0) 读取的 N 组位姿
R_cam2gripper, t_cam2gripper = cv2.calibrateHandEye(
    R_gripper2base,
    t_gripper2base,
    R_target2cam,
    t_target2cam,
    method=cv2.CALIB_HAND_EYE_PARK,
)
print("Rotation Matrix:\n", R_cam2gripper)
print("Translation Vector (m):\n", t_cam2gripper.T)
```

---

## 3. 标定精度闭环验收（重投影与点触测试）

切勿跑完标定直接存盘！必须执行以下两步定量验收：
1. **变换一致性残差检验**：计算所有采样点下标定板在 `base_link` 系下的坐标标准差 $\sigma_{xyz}$，合格标准为 **$\sigma_{xyz} < 2.0\text{ mm}$**。
2. **探针物理点触验证**：令机械臂夹爪闭合持握一根尖头马克笔，点击图像中标定板中心角点，将反投影三维点通过标定矩阵转换至 `base_link`，控制机械臂缓慢移动至该点上方 `5 mm` 处，目视核对笔尖与角点水平偏差是否在 `±2 mm` 以内。

## 原始参考来源 (Sources)

- [IntelRealSense ROS 2 Wrapper](https://github.com/IntelRealSense/realsense-ros)
- [MoveIt 2 Hand-Eye Calibration Tutorial](https://moveit.picknik.ai/main/doc/examples/hand_eye_calibration/hand_eye_calibration_tutorial.html)