# LiDAR–IMU 外参标定说明

**用途：** 方法约定与实现状态（深入阅读）。日常使用请先看根目录 [`README.md`](../README.md)。

本文说明标定目标、约定、流水线与实现状态。代码在 `imu_lidar/`。场地采集见 [`标定流程与采集清单.md`](标定流程与采集清单.md)。

---

## 1. 目标与约定

估计安装外参：

```text
p_IMU = T_IMU_lidar · p_lidar
```

约定：`T_A_B` 表示把 **B 系点**变换到 **A 系**。

相对运动手眼模型：

```text
A_ij ≈ IMU 在 [t_i, t_j] 的相对运动（预积分）
B_ij ≈ LiDAR 在同时间段的相对运动（关键帧配准）
A X ≈ X B
X = T_IMU_lidar
```

旋转子问题（常规主交付）：

```text
R_A R_X = R_X R_B
→ R_IMU_lidar
```

若已有完整六自由度外参，且另有 `T_RTK_lidar`，可链式得到：

```text
T_lidar_IMU = inverse(T_IMU_lidar)
T_RTK_IMU   = T_RTK_lidar @ T_lidar_IMU
```

**不要**把 IMU 加速度二次积分成轨迹，再当作绝对位姿去做完整六自由度手眼。

---

## 2. 交付分层

| 层级 | 交付 | 数据最低要求 |
|---|---|---|
| 第一步 | 旋转 + 时间偏置 δt | **设备时间戳**；静止 + 低速转弯 /「8」字；结构化场景 |
| 第二步 | 上一步 + 可观的水平平移 | 更多转弯半径与加减速 |
| 第三步 | 完整六自由度（含可靠竖直分量） | 缓坡俯仰激励，或外测垂直杆臂先验 |

可观性不过关 → 只交旋转，不强交“假精确”六自由度。  
仅主机接收时间、或残差未过门控的结果 → **不要当作正式安装参数**。

---

## 3. 总体原则

1. **时间同步优先于外参**：δt 未对齐时，旋转与平移都不可信。使用设备时间戳。
2. **先求旋转，再求平移**：旋转通常更稳；平面运动下竖直平移常常不可观。
3. **用连续运动标定**：停车多站、再靠站间长积分，不适合作为纯 IMU 外参主流程。
4. **可观性门控**：过不了就降级交付。
5. **残差小 ≠ 标定对**：需叠点云 / 跨会话等独立验证。
6. **首轮建议低速**：先保证配准与时间对齐；点云去畸变可选。
7. **安装参数不写死在源码**：轴向与时间语义进 YAML；机械尺寸可作检查，不能伪装成已标定平移。
8. **注意耦合**：时间相关峰很弱时，δt、航向角与陀螺零偏可能互相补偿，结果不可当真。

---

## 4. 流水线（现行实现）

```text
vehicle_config
  → timestamp_audit
  → imu_audit（静止零偏等）
  → time_offset：粗估 δt
  → keyframes / [可选] deskew
  → motion_pairs：完整 IMU 预积分 + 配准 B
  → rotation_handeye：加权求解 R
  → （有候选 R 时）精修 δt，必要时交替重建运动对
  → joint_optimizer：精修旋转与陀螺零偏；可观且 full_se3 时再估平移等
  → finalize
```

| 模块 | 文件 | 职责 |
|---|---|---|
| 配置 | `vehicle_config.py` | 读安装 YAML |
| IO | `imu_io.py` / `lidar_io.py` | 标准 CSV / 帧目录 |
| 质检 | `timestamp_audit.py` / `imu_audit.py` | 时间域、静止零偏 |
| δt | `time_offset.py` | 粗估 + 有符号精修 |
| 运动 | `keyframes.py` / `registration.py` / `lidar_deskew.py` | 关键帧、配准、可选去畸变 |
| IMU 侧 | `imu_preintegration.py` / `motion_pairs.py` | 预积分与运动对 |
| 求解 | `rotation_handeye.py` / `joint_optimizer.py` / `observability.py` | 手眼、联合精修、门控 |
| 编排 | `pipeline.py` / `cli.py` / `finalize.py` | 入口与落盘 |

输入中间格式见 [V1_数据格式.md](V1_数据格式.md)。改动史见 [`imu_lidar/CHANGELOG.md`](../imu_lidar/CHANGELOG.md)。

### 运行示例

```powershell
python -m pip install -e ".[dev]"
python -m pip install -e ".[open3d]"   # 可选

python -m imu_lidar.cli plan --mode rotation_only

python -m imu_lidar.cli run `
  --vehicle-config config\vehicle_installation.template.yaml `
  --imu path\to\imu.csv `
  --lidar path\to\lidar_session `
  --output path\to\output `
  --mode rotation_only `
  --time-offset-search-s 2.0
```

合成自检：`python tools\generate_synthetic_session.py` 后跑 CLI，再 `python -m pytest -q`。

### 结果状态

| status | 含义 |
|---|---|
| `rotation_only_accepted` | 旋转过门，可交旋转与报告中的 δt |
| `full_se3_accepted` | 可观且联合优化通过，可交完整 `T` |
| `full_se3_rejected_due_to_observability` | 旋转可用，平移未接受 |
| `blocked` | 质检 / δt / 手眼残差等硬门失败，**不交付** |

`rotation_only` 模式下：不要把未标定的机械平移拼进 4×4 伪装成完整标定。

---

## 5. 采集要点

单趟动态会话：

```text
[静止 20–30 s] → [低速激励 3–8 min] → [再静止 10–20 s]
```

优先激励：

- 低速「8」字 / 左右圆（旋转主激励）
- 直线加减速（有助于时间对齐与水平平移）
- 缓坡（仅完整六自由度需要）：约 3°～8°，连续长度优先 ≥ 20～30 m

硬条件：IMU / LiDAR **设备时间戳**；结构化场景；标定全程安装不得改动。

更完整的现场清单见 [标定流程与采集清单.md](标定流程与采集清单.md)。

---

## 6. 数学上允许与禁止

禁止：加速度二次积分当真值轨迹；把只有旋转的相对运动硬补成完整六自由度；用最终外参反向筛边掩盖失败。

允许：预积分旋转手眼求旋转；在可观时用预积分残差联合估计平移，并精修零偏等辅助量。

---

## 7. 车辆配置

使用 `--vehicle-config vehicle_installation.yaml`。  
模板中安装平移/旋转保持未标定状态，直至实测确认；禁止写死某车杆臂冒充结果。

---

## 8. 实现状态（当前阶段）

本仓库**仅此一条**标定路径：连续运动关键帧 + IMU 预积分。对外总览与「合成 / 旧车 / 合格数据预期」见根目录 [`README.md`](../README.md) §0。

| 项 | 状态 |
|---|---|
| 连续运动关键帧标定流水线 | 已实现（现行唯一路径） |
| 加权预积分 / 加权手眼 | 已实现 |
| 旋转预积分因子 + 有符号 δt 精修 | 已实现 |
| 完整预积分（含速度/位移增量）与可观时的平移优化 | 已实现 |
| 可观性门控 / `rotation_only` | 已实现 |
| 合成数据 pytest / 一键复现 | 已实现（证明链路与已知 yaw/δt，不证明实车精度） |
| 旧车主机时间烟测（S2） | 线下可跑；预期 `blocked`，不当交付 |
| 设备时间新车数据正式验收 | **待做** |
| 原生存储一键导出为中间格式 | 已提供 `tools/export_rscap_to_v1.py`（N300 rscap + H32 dlog/MSOP → V1；dlog 用 DIFOP 通道角） |

细项见 [`imu_lidar/CHANGELOG.md`](../imu_lidar/CHANGELOG.md)。

---

## 9. 相关文档

| 内容 | 路径 | 备注 |
|---|---|---|
| 对外总览（优先） | 根目录 [`README.md`](../README.md) | 日常入口 |
| 采集清单 | [`标定流程与采集清单.md`](标定流程与采集清单.md) | 现场 |
| 数据格式 / 导出 | [`V1_数据格式.md`](V1_数据格式.md) | 中间格式 |
| 文件职责说明 | [`imu_lidar/文件职责说明.md`](../imu_lidar/文件职责说明.md) | 改代码 |
| 改动史 | [`imu_lidar/CHANGELOG.md`](../imu_lidar/CHANGELOG.md) | 改代码 |
