Files
calibration/README.md
T

350 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# LiDARIMU 外参标定
用车上的**激光雷达(LiDAR)**与**惯性测量单元(IMU)**在连续行驶中的相对运动,估计二者之间的安装关系(外参),并估计两路传感器的时间差。
```text
p_IMU = T_IMU_lidar · p_lidar
```
实现包:`[imu_lidar/](imu_lidar/)`。文件职责说明:`[imu_lidar/文件职责说明.md](imu_lidar/文件职责说明.md)`
本仓库**只有这一条标定路径**(连续运动关键帧 + IMU 预积分)。不直接解析原始 `.rscap` / dlog,需先导出为中间格式。
---
## 0. 现状一览(先读)
| 项 | 说明 |
| ------------- | ------------------------------------------------------------------------ |
| **仓库做什么** | 输入标准中间格式(IMU CSV + 雷达会话),输出 LiDARIMU **正式安装外参** `T_IMU_lidar` 与时间偏置 `δt`。合格数据且过质量门 → 可交付(常规先交旋转 + δt;激励够再交可观平移);数据不合格或未过门 → `blocked`,不交外参 |
| **当前阶段** | 算法链路已闭环,合成自检通过;**尚缺合格实车数据验收**,故正式外参尚未对实车落盘交付(生产级原始录制→中间格式导出仍待完善) |
| **合成数据测什么** | 证明链路能跑通,并能收回**已知**旋转(yaw)与 δt;**不证明**实车安装精度或平移交付 |
| **旧车 S2 测什么** | 仅线下烟测:主机时间旧数据上流水线能否跑完;结果预期为 `blocked`**不当作外参真值** |
| **合格数据** | 见下方定义;拿到后即可按正式标定流程跑通,期望得到可交付外参(先旋转 + δt) |
### 什么叫合格数据
同时满足下列条件,才视为可用于正式标定(与旧车主机时间烟测数据区分):
| 类别 | 要求 |
| ------------ | ----------------------------------------------------------------------------- |
| **时间戳** | IMU、雷达均用**设备时间**写入中间格式的 `t` / `t_start`/`t_end`(可另留主机接收时间作排查,但标定主轴不用主机时) |
| **会话结构** | 单趟:`静止 2030 s``低速连续运动 38 min``再静止 1020 s`;运动含明显左右转(如「8」字 / 圆)及适量加减速 |
| **场景** | 有墙、柱、路缘等结构,避免空旷无特征;雷达帧率与点数正常、无明显大面积丢帧 |
| **覆盖** | 两路传感器覆盖**同一段**物理行驶;安装全程不得改动 |
| **格式** | 已导出本仓库中间格式:`imu.csv` + `lidar_session/`(见 [docs/V1_数据格式.md](docs/V1_数据格式.md) |
| **验证会话(建议)** | 另录一段独立路线 B,只做叠点/一致性检查,不参与求外参 |
**不算合格(举例):** 仅主机接收时间;只有静止、无转弯;IMU 与雷达不是同一趟;未导出中间格式;时间相关极弱仍强行当安装参数。
完整现场清单见 [docs/标定流程与采集清单.md](docs/标定流程与采集清单.md)。
### 合格数据拿到后 → 正式外参与预期效果
仓库目标产物就是**可安装使用的外参**(再加 δt)。合格数据过门后:
| 模式 | 跑法 | 正式交付内容 | 较现实预期 | 成功标志 |
| ----------------------- | ---------------------- | ----------- | --------------------------------- | ----------------------------------------- |
| `rotation_only`(第一步,必做) | `--mode rotation_only` | 旋转外参 + δt | 旋转约 **0.5°–2°**;δt 随同步与激励质量变化 | `summary.json``rotation_only_accepted` |
| `full_se3`(激励够再试) | `--mode full_se3` | 上一项 + 可观的平移 | 水平平移约数厘米~十几厘米;竖直常更差或不可观(需缓坡或垂直先验) | `full_se3_accepted`;否则旋转仍可交付、平移拒绝 |
交付前须叠点云 / 跨会话独立验证;`blocked` 一律不可用作安装参数。
**当前尚未完成的是「用合格实车数据跑出并验收这份外参」**,不是「合格数据也交不出外参」。
### 两类试验对照
| | 合成数据(默认 pytest / 一键复现) | 旧车 S2(线下,非默认测试) |
| ------- | -------------------------------------- | ---------------- |
| 目的 | 回归算法正确性 | 验证实车 IO/链路可跑 |
| 时间戳 | 可控、带已知 δt | 主机接收时间(非设备时间) |
| 是否合格数据 | 否(合成,仅对照) | **否**(主机时间,预期拒绝) |
| 期望结果 | `rotation_only_accepted`;δt / yaw 接近真值 | `blocked`(质量门拒绝) |
| 能否当安装参数 | 否 | **否** |
细节见 [tests/README.md](tests/README.md)。实现状态细表见 [docs/IMU-LiDAR标定.md](docs/IMU-LiDAR标定.md) §8。
---
## 目录
1. [现状一览(先读)](#0-现状一览先读)
2. [系统输入 / 输出](#1-系统输入--输出)
3. [一键复现(合成数据)](#2-一键复现合成数据)
4. [能求出什么](#3-能求出什么)
5. [方法概要](#4-方法概要)
6. [分步求值](#5-分步求值)
7. [程序流程](#6-程序流程)
8. [真实数据怎么跑](#7-真实数据怎么跑)
9. [结果判读](#8-结果判读)
10. [仓库结构与文档](#9-仓库结构与文档)
---
## 1. 系统输入 / 输出
### 输入
| 输入 | 说明 |
| --------- | --------------------------------------------------------------------- |
| `imu.csv` | 列:`t,gx,gy,gz,ax,ay,az`(秒;陀螺 rad/s;加速度 m/s²) |
| 雷达点云 | `frames_index.csv` + `frames/frame_XXXXX.npz`(点云米制) |
| 车辆配置 YAML | 轴向与时间语义;**不必事先填外参真值**(模板:`config/vehicle_installation.template.yaml` |
中间格式细节见 [docs/V1_数据格式.md](docs/V1_数据格式.md)。原始 `.rscap` 等需先导出。
### 输出(`--output` 目录)
| 文件 | 内容 |
| -------------------- | ---------------------------- |
| `T_IMU_lidar.json` | 外参矩阵、平移、四元数、欧拉角 |
| `time_offset.json` | δt,定义 `t_imu = t_lidar + δt` |
| `summary.json` | 状态、残差、可观性、各阶段细节 |
| `report_preview.png` | 一键复现时生成的简易指标图(可选) |
---
## 2. 一键复现(合成数据)
不需要实车数据。脚本会:**生成合成 IMU/雷达 → 跑标定 → 打印报告并出预览图 → 跑 pytest**。
**这一趟证明什么:** 全流程可复现;能收回合成真值中的旋转(yaw)与时间偏置。
**不证明什么:** 实车安装精度、平移外参可交付、主机时间旧数据可用。
### 推荐(Windows
```powershell
cd <本仓库根目录>
python -m pip install -e ".[dev]"
python -m pip install -e ".[open3d]" # 可选,配准更稳;未装则用内置 ICP
# 预览图需要 matplotlib(没有则跳过绑图,不影响标定)
python -m pip install matplotlib
powershell -File tools\reproduce_synthetic.ps1
```
只要标定、跳过测试:
```powershell
powershell -File tools\reproduce_synthetic.ps1 -SkipPytest
```
尝试完整六自由度模式:
```powershell
powershell -File tools\reproduce_synthetic.ps1 -Mode full_se3 -SkipPytest
```
### 等价 Python 入口
```powershell
python tools\reproduce_synthetic.py
python tools\reproduce_synthetic.py --mode full_se3 --skip-pytest
```
### 这一趟用了什么、产出什么
```text
INPUT
examples/synthetic_session/imu.csv
examples/synthetic_session/lidar/
config/vehicle_installation.template.yaml
examples/synthetic_session/meta.json # 合成真值(δt、yaw),仅用于对照
OUTPUT
examples/synthetic_session/out/T_IMU_lidar.json
examples/synthetic_session/out/time_offset.json
examples/synthetic_session/out/summary.json
examples/synthetic_session/out/report_preview.png
```
单独查看已有结果:
```powershell
python tools\show_calibration_report.py `
--summary examples\synthetic_session\out\summary.json `
--truth-meta examples\synthetic_session\meta.json `
--plot examples\synthetic_session\out\report_preview.png
```
### 配准结果 3D / 俯视可视化
蓝=目标帧,橙=源帧。
| 按键 | 作用 |
| --------------------- | ------------------------------------- |
| `1` / `2` / `3` / `4` | 原始 / IMU(X=I) / 雷达配准 B / 标定预测 `X⁻¹AX` |
| `N``]` | 下一运动对 |
| `P``[` | 上一运动对 |
```powershell
python tools\visualize_pair_3d.py `
--lidar examples\synthetic_session\lidar `
--imu examples\synthetic_session\imu.csv `
--summary examples\synthetic_session\out\summary.json `
--pair-index 0 `
--save-png examples\synthetic_session\out\pair0_overlay.png
```
`--pair-index` 只决定起始对;窗口内可继续按 `N`/`P` 切换。无 GUI 时加 `--no-gui`。封装:`tools\view_pair.ps1`
---
## 3. 能求出什么
| 结果 | 含义 | 说明 |
| ------- | ------------- | ------------------ |
| 旋转外参 | 雷达相对 IMU 的朝向差 | 常规主交付 |
| 时间偏置 δt | 两路时钟差(秒) | 与旋转一并给出 |
| 平移外参 | 安装位置差(米) | 激励足够且质量门通过才接受,否则置零 |
| 零偏等 | 辅助量 | 改善积分/优化,一般不当安装外参交付 |
---
## 4. 方法概要
1. 低速多转弯行驶(如「8」字),首尾各留静止段。
2. 雷达关键帧配准得相对运动 **B**
3. 同一时段 IMU 预积分得 **A**(先用旋转)。
4. 手眼关系:`R_A · R_X ≈ R_X · R_B`
5. 时间与旋转稳定后,若 `--mode full_se3` 且可观,再估计平移(用加速度预积分、重力、速度与时变零偏)。
---
## 5. 分步求值
| 步骤 | 交付 | 典型要求 |
| --- | ------- | ---------------------- |
| 第一步 | 旋转 + δt | 设备时间戳;静止 + 低速转弯;有结构的场景 |
| 第二步 | + 水平平移 | 更多转弯半径与加减速 |
| 第三步 | 完整六自由度 | 缓坡等俯仰激励,或垂直安装尺寸先验 |
- `--mode rotation_only`:第一步
- `--mode full_se3`:尝试完整刚体;平移仍可能被拒绝
质量门未通过时,不能当正式安装参数。
---
## 6. 程序流程
```text
读入 → 时间/IMU 质检 → 粗估 δt
→ 关键帧配准 B + IMU 预积分 A → 旋转手眼 R
→ 用 R 精修 δt(可交替组对)
→ 联合精修 R / 常值陀螺零偏
→(full_se3 且可观)重力、速度、时变零偏、平移 t
→ 写出 JSON
```
「可观」:程序检查转轴是否够多样、相对位移是否够丰富;不够则只保留旋转。
---
## 7. 真实数据怎么跑
```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
```
采集与现场清单:[docs/标定流程与采集清单.md](docs/标定流程与采集清单.md)。
旧车 S2 主机时间烟测(预期 `blocked`,不当交付):配置见 `config/s2_old_smoke.yaml`,步骤见 `[tests/README.md](tests/README.md)`
---
## 8. 结果判读
| `summary.json` 状态 | 含义 |
| ---------------------------------------- | ----------------- |
| `rotation_only_accepted` | 旋转可用(该模式下平移置零) |
| `full_se3_accepted` | 含平移的完整外参通过 |
| `full_se3_rejected_due_to_observability` | 旋转可用,平移未接受 |
| `blocked` | 前序失败,**不可用作安装参数** |
请同时看手眼残差、时间相关、可观性说明,并做点云叠加等独立验证。
---
## 9. 仓库结构与文档
```text
imu_lidar/ 标定算法与 CLI
config/ 车辆配置模板
docs/ 流程、数据格式、方法说明
tools/ 合成数据、一键复现、报告查看
tests/ 自动化测试
```
| 文档 | 内容 |
| ------------------------------------------------ | ---------------------- |
| [imu_lidar/文件职责说明.md](imu_lidar/文件职责说明.md) | 各源文件职责 |
| [imu_lidar/CHANGELOG.md](imu_lidar/CHANGELOG.md) | 算法改动记录 |
| [docs/标定流程与采集清单.md](docs/标定流程与采集清单.md) | 现场采集与分步流程(与现行实现对齐) |
| [docs/V1_数据格式.md](docs/V1_数据格式.md) | 中间数据格式 |
| [docs/IMU-LiDAR标定.md](docs/IMU-LiDAR标定.md) | 方法约定与实现状态 |
| [tests/README.md](tests/README.md) | 自动化测试说明 + S2 旧数据线下试验结果 |
改算法请同步更新 `imu_lidar/文件职责说明.md``CHANGELOG.md`;改安装/运行/对外说明时更新本文件。