合并并完善双链路标定文档

This commit is contained in:
lichun.qu
2026-08-25 15:37:35 +08:00
parent 8358b3f933
commit d1fa69c89b
19 changed files with 462 additions and 1948 deletions
+32 -47
View File
@@ -1,69 +1,54 @@
# 车辆多传感器外参标定
本仓库同时维护两条独立的外参标定链路:LiDARIMU 与 RTKIMU。两条链路共享通用的几何IMU 预积分基础能力,但各自的观测模型、求解器、工具入口和验收结论独立管理
本仓库维护两条彼此独立的外参标定流程:**雷达–IMU** 和 **RTKIMU**。两条流程复用少量通用的几何IMU 读取和预积分代码,但不共用观测模型、求解器或验收结论
## 当前应如何使用
## 从这里开始
| 目标 | 推荐链路 | 当前可交付状态 |
| 目标 | 阅读文档 | 当前可交付范围 |
| --- | --- | --- |
| LiDAR 与 IMU 的旋转、时间对齐 | LiDAR–IMU | 旋转与主机桥接时间对齐可冻结;完整平移不可交付。 |
| RTK 天线相位中心与 IMU 的工程外参 | RTK–IMU | 旋转外参已求出,平移外参利用机械先验经动态数据一致性验证确定(不是纯靠数据求出)。 |
| 需要完整 RTK–IMU 工程候选和复现方式 | RTK–IMU | 先阅读 [README_RTK_IMU.md](README_RTK_IMU.md)。 |
| 标定雷达与 IMU | [雷达–IMU 标定](docs/雷达-IMU标定.md) | 旋转与时间关系已有实车候选;平移不可交付。 |
| 标定双天线 RTK 与 IMU | [RTKIMU 标定](docs/RTK-IMU标定.md) | 旋转已固定;杆臂以机械测量为基准,并完成动态一致性验证,尚未获得正式工程放行。 |
不要任何一条链路未通过的平移结果当作已标定的 6DoF 外参。结果的接受状态以对应 JSON gate 为准
不要任何一条流程中被拒绝的平移结果当作完整六自由度外参。是否接受结果,以相应结果 JSON 的 `accepted` 字段和门禁结论为准,而不是仅看优化是否收敛
## 为什么同时保留两条链路
## 两条流程的关系
LiDAR–IMU 链路通过点云相对运动与 IMU 预积分求手眼外参,适合旋转与时间对齐;但当前实车数据的加速度预积分位移,尤其 Z 分量,不足以支持可靠平移求解,且主要采集运动缺乏竖直激励。因此它的 `full_se3` 门禁未通过。
```text
雷达–IMU
点云相对运动 + IMU 预积分
→ 旋转与时间关系;平移受 IMU 位移误差和激励不足限制
RTKIMU 链路直接利用双天线基线、GNSS 位置和 Doppler 速度,并以机械测量给出天线相位中心相对 IMU 的绝对杆臂。它不是“用 RTK 替代 LiDAR”,而是针对 LiDAR–IMU 平移不可观的问题,采用更直接的天线位置/速度观测做工程外参验证。
RTKIMU
双天线基线 + GNSS 位置/速度 + IMU
→ 天线相位中心相对 IMU 的旋转和杆臂一致性验证
```
完整理由、两条模型的差异及当前结果见 [LiDAR→RTKIMU 决策说明](docs/lidar_imu_to_rtk_imu.md)
选择 RTK–IMU 不是用 RTK 替换雷达。它用于解决“雷达–IMU 的平移在当前实车数据上不可可靠交付”这一独立问题;RTK–IMU 的外参也不能自动转换为雷达–IMU 外参
## 仓库结构
```text
calibration/
├─ imu_lidar/ LiDAR–IMU 专用流程,以及双方共用基础模块
├─ rtk_imu/ RTKIMU 专用算法
├─ tools/ 两条链路的命令入口、导出和审计工具
├─ tests/ 自动化测试
├─ docs/ 详细方法、状态、采集与决策说明
├─ artifacts/ 受审核的结果快照;大过程文件仅保留本地
config/ 车辆安装与流程配置
├─ README.md 本页:仓库总览
└─ README_RTK_IMU.md RTKIMU 当前工程流程、结果与复现
├─ imu_lidar/ 雷达–IMU 专用算法和命令行入口
├─ rtk_imu/ RTKIMU 专用算法
├─ tools/ 原始数据导出、求解、审计和结果汇总入口
├─ docs/ 两份规范说明:雷达–IMU、RTK–IMU
├─ artifacts/ 已提交的结果摘要与审核证据
├─ config/ 车辆安装与流程配置
tests/ 自动化测试
```
`rtk_imu/`依赖下列 `imu_lidar/` 通用模块:
`rtk_imu/`允许复用 `imu_lidar/` 中的通用模块:`contracts.py``geometry.py``geodesy.py``imu_io.py``imu_preintegration.py``rotation_handeye.py`。它不依赖雷达专用的点云读取、去畸变、配准、雷达流程编排或雷达联合优化器。
- `contracts.py`:数据契约。
- `geometry.py`SO(3)、变换和坐标运算。
- `geodesy.py`:地理坐标到 ENU。
- `imu_io.py`IMU 读取。
- `imu_preintegration.py`IMU 预积分、bias 修正与 whitening。
- `rotation_handeye.py`:通用旋转手眼初值器。
## 数据与过程文件
RTKIMU 不得依赖 LiDAR 专用的 `lidar_io.py``lidar_deskew.py``registration.py``pipeline.py``phase_a.py``joint_optimizer.py`
原始 `.rscap`、统一导出数据、节点状态、检查点和调试中间结果只保留本地;仓库只提交可复核的代码、工具、配置、说明和结果摘要。RTK–IMU 的正式结果索引在 [artifacts/rtk_imu_calibration_v3/README.md](artifacts/rtk_imu_calibration_v3/README.md)
## 文档入口
## 开发与验证
| 文档 | 内容 |
| --- | --- |
| [README_RTK_IMU.md](README_RTK_IMU.md) | RTK–IMU 当前候选、状态、流程、审核证据和复现命令。 |
| [docs/lidar_imu_to_rtk_imu.md](docs/lidar_imu_to_rtk_imu.md) | 为什么 LiDAR–IMU 暂不能交平移、为什么引入 RTK–IMU、两者边界与共享代码。 |
| [rtk_imu/README.md](rtk_imu/README.md) | RTKIMU 包的代码职责与 import 边界。 |
| [docs/rtk_imu_multisource_v3.md](docs/rtk_imu_multisource_v3.md) | G90/HI13 统一导出及 R1b/R2V/R2G/R3 旋转链路。 |
| [docs/rtk_imu_engineering_6dof.md](docs/rtk_imu_engineering_6dof.md) | node-state factor graph、机械先验、验收门禁。 |
| [docs/IMU-LiDAR标定.md](docs/IMU-LiDAR标定.md) | LiDARIMU 方法与采集要求。 |
| [docs/20260808_LiDAR-IMU标定现状与问题.md](docs/20260808_LiDAR-IMU标定现状与问题.md) | LiDAR–IMU 当前问题、证据和历史处置记录。 |
```powershell
python -m pip install -e ".[dev]"
python -m pytest -q
```
## 结果与过程文件
`artifacts/rtk_imu_calibration_v3/` 中只提交审核结论及其关键证据。原始 `.rscap`、统一导出数据、节点状态、checkpoint、调试 JSON 与旧版本过程产物均通过 `.gitignore` 保持本地,不应随提交或推送传播。
每次改动前先确认使用哪一条链路;每次交付前先读取相应 release JSON 中的 accepted gate,而不是仅凭优化器收敛、残差下降或一个看似合理的 4×4 矩阵下结论。
## LiDARIMU 专用运行指南
[README_Lidar_IMU.md](README_Lidar_IMU.md) 保留 LiDAR–IMU 的独立运行命令、合成复现与输入输出说明;它是远端原 README 的专用化重命名,不再承担仓库总导航职责。
雷达点云处理需要时再安装可选依赖:`python -m pip install -e ".[open3d]"`
-184
View File
@@ -1,184 +0,0 @@
# LiDARIMU 外参标定
用连续行驶中的 LiDAR 与 IMU 相对运动,估计安装外参与时间偏置:
```text
p_IMU = T_IMU_lidar · p_lidar
```
**当前阶段:** 算法与合成自检已闭环;已提供 `tools/export_rscap_to_v1.py`N300 `.rscap` + H32 dlog/MSOP → 中间格式);**合格实车验收尚未完成**,故正式外参尚未对实车落盘交付。
---
## 先看什么(对外三份就够)
| 顺序 | 文档 | 用途 |
| --- | -------------------------------------- | -------------------- |
| 1 | **本 README** | 做什么、怎么跑、结果怎么判 |
| 2 | [docs/V1_数据格式.md](docs/V1_数据格式.md) | 中间格式 + 原始数据导出命令 |
| 3 | [docs/标定流程与采集清单.md](docs/标定流程与采集清单.md) | 现场怎么采(合格数据要求) |
其余(方法细述、测试说明、源码职责、CHANGELOG)给深入阅读 / 改代码时用,见文末。
---
## 1. 输入 / 输出
| 输入 | 说明 |
| --------- | ----------------------------------------------------------- |
| `imu.csv` | `t,gx,gy,gz,ax,ay,az`(秒;rad/sm/s²);`t` 用设备时间 |
| 雷达会话目录 | `frames_index.csv` + `frames/*.npz`(米制 XYZ |
| 车辆 YAML | 轴向与时间语义;外参真值可空(`config/vehicle_installation.template.yaml` |
| 输出 | 说明 |
| ------------------ | ---------------------- |
| `T_IMU_lidar.json` | 外参 |
| `time_offset.json` | `t_imu = t_lidar + δt` |
| `summary.json` | 状态、残差、可观性 |
新车原始数据导出(H32 dlog/zip + HI13 rscap):
```powershell
python tools\export_rscap_to_v1.py `
--imu-rscap path\to\hi13r4-imu.rscap `
--imu-kind hi13 `
--lidar-dlog path\to\session_or_recovered.zip `
--host-start 2026-08-08T17:40:05 `
--host-end 2026-08-08T17:45:15 `
--out path\to\session_v1 `
--require-difop
```
---
## 2. 一键复现(合成,不需实车)
```powershell
cd <本仓库根目录>
python -m pip install -e ".[dev]"
python -m pip install -e ".[open3d]" # 推荐
powershell -File tools\reproduce_synthetic.ps1
```
证明:链路可跑通,能收回已知 yaw / δt。
不证明:实车安装精度、平移可交付。
产物在 `examples/synthetic_session/out/`(含 `summary.json``motion_pairs.json`)。叠点查看:
```powershell
# 优先读取 summary 同目录的 motion_pairs.json,按需加载点云(无需重算配准)
python tools\visualize_pair_3d.py `
--lidar examples\synthetic_session\lidar `
--summary examples\synthetic_session\out\summary.json `
--pair-index 0
```
旧标定目录若缺少缓存,可只补导出运动对(不重求解外参):
```powershell
python tools\export_motion_pairs_for_viz.py `
--lidar path\to\lidar `
--imu path\to\imu.csv `
--summary path\to\out\summary.json
```
`1``4` 切换叠点模式;`N`/`P` 切换运动对。
---
## 3. 真实数据怎么跑
1. 按采集清单录制(设备时间;静止 + 低速转弯;有结构场景)
2. 导出中间格式(第1节命令)
3. 填写车辆 YAML 的轴向与时间语义
4. 标定:
```powershell
python -m imu_lidar.cli run `
--vehicle-config config\vehicle_installation.template.yaml `
--imu path\to\session_v1\imu.csv `
--lidar path\to\session_v1\lidar `
--output path\to\out `
--mode rotation_only `
--time-offset-search-s 2.0
```
1.`summary.json`,再叠点 / 用验证会话复核后才交付
| 模式 | 交付 | 成功标志 |
| ------------------- | ------- | --------------------------- |
| `rotation_only`(先做) | 旋转 + δt | `rotation_only_accepted` |
| `full_se3`(激励够再试) | + 可观平移 | `full_se3_accepted`(否则平移拒绝) |
| `summary.json` 状态 | 含义 |
| ---------------------------------------------- | ----------- |
| `rotation_only_accepted` / `full_se3_accepted` | 可进入验证 |
| `full_se3_rejected_due_to_observability` | 旋转可用,平移不交 |
| `blocked` | **不可作安装参数** |
预期量级:旋转约 0.5°–2°;水平平移数厘米~十几厘米;无坡时竖直常不可观。
---
## 4. 方法(一句话)
关键帧雷达配准得 **B**,同区间 IMU 预积分得 **A**,解 `R_A R_X ≈ R_X R_B`;再估 δt。可观时才在 `full_se3` 下交平移。
---
## 5. 试验边界(勿误读)
| | 合成 pytest | 旧车 S2 线下 |
| ------ | ------------------------ | ----------------- |
| 目的 | 回归算法 | 验证旧主机时间数据上链路能跑完 |
| 期望 | `rotation_only_accepted` | `blocked`**(预期)** |
| 当安装参数? | 否 | **否** |
细节:[tests/README.md](tests/README.md)。
---
## 6. 仓库结构与其余文档
```text
imu_lidar/ 算法与 CLI
config/ 车辆配置模板
docs/ 采集清单、数据格式、方法细述
tools/ 导出、合成复现、可视化
tests/ 自动化测试
```
| 文档 | 何时看 |
| ------------------------------------------------ | ---------------- |
| [docs/IMU-LiDAR标定.md](docs/IMU-LiDAR标定.md) | 要看方法约定与实现状态表 |
| [tests/README.md](tests/README.md) | 要看合成用例 / S2 烟测记录 |
| [imu_lidar/文件职责说明.md](imu_lidar/文件职责说明.md) | 要改源码 |
| [imu_lidar/CHANGELOG.md](imu_lidar/CHANGELOG.md) | 要查改动史 |
改算法请同步职责说明与 CHANGELOG;改对外用法请更新本 README。
-177
View File
@@ -1,177 +0,0 @@
# RTK-IMU 标定:流程、结果与复现
本文是本次 G90 双天线 RTK 与 HI13 IMU 标定的工程入口。算法代码在 `rtk_imu/`,命令入口在 `tools/`,正式审核结果在 `artifacts/rtk_imu_calibration_v3/`。原始 `.rscap`、统一导出数据、状态快照与 checkpoint 均只保留本地,不提交仓库。
## 一句话结论
RTK-IMU 旋转外参由双天线基线方向与水平静止重力约束获得;平移外参以机械测量为绝对基准,再通过 RTK+IMU 联合状态图、高动态转弯/坡道数据、独立 held-out 数据和旋转扰动测试进行一致性验证。
当前动态数据不足以独立高精度求出完整 XYZ 杆臂,因此它不是 data-only translation calibration。机械测量给出了杆臂的绝对值;在未参与标定的数据、转弯等杆臂敏感运动以及旋转外参扰动测试中,均未发现该机械外参存在明显矛盾或不稳定性。当前结果的正确表述是:**机械杆臂锚定,并经动态数据一致性验证的工程候选**。
## 当前工程候选与状态
坐标约定:`l_I = p_ANT1^I`,即 ANT1(主天线、左侧)相位中心在 IMU 坐标系中的位置。车体/RTK 安装坐标为:+X 为 ANT1(左)到 ANT2(右),+Y 为车辆前进方向且与 IMU +Y 同向,+Z 向上;GGA 参考点为 ANT1 相位中心,离地 `1.916499878 m`
- 固定旋转来源:`R2G_gravity_level_prior`
- 固定旋转近似 RPYX/Y/Z):`[0.454°, -0.003°, 0.012°]`
- 当前工程候选杆臂:`l_I = [-0.4518015159, -0.2644749820, 0.7314656115] m`
- 变换约定:`p_RTK = R_RTK_IMU * p_IMU + t_RTK_IMU`
- 对应候选 `T_RTK_IMU`(四舍五入到 6 位小数):
```text
[[ 1.000000, -0.000214, -0.000044, 0.451777],
[ 0.000214, 0.999969, -0.007929, 0.270363],
[ 0.000046, 0.007929, 0.999969, -0.729325],
[ 0.000000, 0.000000, 0.000000, 1.000000]]
```
当前门禁状态必须同时保留:
- `data_only_translation_accepted=false`:数据本身没有提供足够稳定的完整平移可观性。
- `engineering_translation_accepted=false`:独立传播验证仍存在公共加速度偏差,不能声称正式工程放行。
- `independent_extrinsic_sensitive_validation_passed=true`:杆臂敏感的高动态验证未发现机械杆臂冲突。
- `heldout_physical_validation_passed=true``rotation_sensitivity_passed=true`:固定候选在 held-out 物理残差和旋转扰动中保持一致。
因此不得描述为“data-only 标定平移”或“动态数据已精确细化机械杆臂”。完整、机器可读的结论见 [engineering_release_decision.json](artifacts/rtk_imu_calibration_v3/engineering_release_decision.json)。
## 求解流程
1. **统一原始数据导出。** 使用 G90/HI13 设备时间作为主时间轴;host receive time 仅用于诊断。G90 保留 GGA 质量、GNHPR 基线及质量、BESTNAVA Doppler velocity,必要时 PVTSLNAHI13 保留 system time、gyro、accel、姿态/四元数和 host receive time。
2. **R0 连续性与质量控制。** 校验 checksum、RTK Fixed、设备时间单调性、IMU 覆盖、baseline jump 与测量间隔。轨迹连续性由 IMU 设备时间和预积分覆盖决定;孤立 HPR 缺失/Q5 只禁用或降权 HPR factor,不切断 IMU 轨迹。
3. **旋转外参。** R1b 从基线与 IMU 动态估计 ANT1→ANT2 在 IMU 中的 2DoF 方向;R2V 用基线与高质量 Doppler 速度作独立诊断;R2G 使用水平静止场地中的基线+重力+地面水平先验补齐完整旋转。R2G 是本次正式固定旋转来源,旧 GNHPR 三轴手眼只作诊断。
4. **节点状态图。** 每个 GNSS node 包含 `R,p,v,bg,ba` 的 15DoF 状态;相邻 node 由 covariance-whitened IMU preintegration 和 bias random walk 连接。BEST 约束 XYZGGA 仅在 BEST 缺失时约束 XYDoppler 约束速度,HPR 是可选姿态/基线因子。
5. **机械锚定的平移验证。** 杆臂以机械值为基准,分别比较无先验 free、固定机械杆臂和软先验解。free 解只用于观测性诊断,不能因为数值收敛就替代机械值。
6. **独立验证。** 使用 circle、left-right、slope 的高动态非重叠窗口;再使用剩余 held-out 窗口、旋转 ±扰动敏感性、独立 innovation 和 propagation-bias root-cause audit 复核。
## 证据与限制
47 个非重叠标定窗口上的 free/fixed/prior 对比表明机械先验与数据拟合相容,但 posterior/prior 方差比没有显示足够的数据驱动细化,因此 `translation_refined_by_data=false`。剩余 267 个 frozen held-out 窗口的物理验证通过;然而独立传播创新在低速、低角速度区间同时出现位置和 Doppler 的同向偏差,等效为约 `0.20 m/s²` 的公共传播加速度误差。
该误差在 `|omega|` 很小时不能优先归因于杆臂速度项 `R*(omega × l)`,因此它不单独否决高动态杆臂敏感验证;但在传播模型根因关闭前,也不能把候选杆臂标为正式工程已放行。
主要审核证据:
- [47 窗口机械分支](artifacts/rtk_imu_calibration_v3/mechanical_prior_engineering_47_window.json)
- [held-out 验证](artifacts/rtk_imu_calibration_v3/mechanical_prior_engineering_heldout.json)
- [独立创新审计](artifacts/rtk_imu_calibration_v3/heldout_independent_innovation.json)
- [传播偏差根因审计](artifacts/rtk_imu_calibration_v3/propagation_bias_root_cause_audit.json)
- [旋转敏感性](artifacts/rtk_imu_calibration_v3/mechanical_prior_rotation_sensitivity.json)
## 如何复现
### 1. 准备环境和原始数据
```powershell
cd <repository-root>
python -m pip install -e ".[dev]"
```
将三批 G90/HI13 原始 `.rscap` 会话放到本机的数据位置。数据位置不写入仓库;`tools/export_rtk_imu_unified.py` 中的会话配对清单必须与实际采集文件一致。
```powershell
$OUT = "artifacts\rtk_imu_calibration_v3\reproduce"
python tools\export_rtk_imu_unified.py --output-root "$OUT\unified" --overwrite
$MANIFEST = "$OUT\unified\manifest.json"
```
导出后应检查每个会话目录中的 `export_summary.json`,并确认 `manifest.json` 中记录的传感器时间轴没有被 host receive time 替换。
### 2. 复现固定旋转
`<flat-static-session-id>` 必须是已确认地面水平、车辆静止的会话;可多次传入 `--level-static`。R2V 只作独立诊断,不替代 R2G。
```powershell
python tools\run_rtk_imu_multisource.py `
--manifest $MANIFEST `
--level-static <flat-static-session-id> `
--output "$OUT\r2g_multisource.json"
```
检查输出的 R2G 旋转与本 README 的近似 RPY 一致后,将该旋转固定为后续 node graph 的 `--rotation-rpy-deg 0.454 -0.003 0.012`。若 R2G 不一致,应停止,先复核天线方向、场地水平和时间/轴定义,不应继续求杆臂。
### 3. 复现窗口选择与无先验诊断
从 circle、left-right、slope 三类会话中选择高质量窗口;窗口不可共享 IMU/GNSS/HPR 样本。仓库提交的 `lever_information_window_selection*.json` 是本次审核所用选择结果,可用于对照。
```powershell
python tools\select_rtk_imu_windows_by_lever_information.py `
--manifest $MANIFEST `
--circle-session <circle-session-id> `
--left-right-session <left-right-session-id> `
--slope-session <slope-session-id> `
--output "$OUT\selection.json" `
--rotation-rpy-deg 0.454 -0.003 0.012
python tools\run_rtk_imu_node_graph_free_selected.py `
--manifest $MANIFEST `
--selection "$OUT\selection.json" `
--output "$OUT\free_baseline.json" `
--start-name all `
--rotation-rpy-deg 0.454 -0.003 0.012
```
free solve 的作用是输出边缘化杆臂信息、协方差、最弱方向和多初值稳定性;本次数据若仍未达到完整 XYZ 可观性,不得扩大无先验求解规模来强行放行。
### 4. 复现机械杆臂分支和 held-out 验证
固定工程候选杆臂并使用同一批非重叠标定窗口。`states.npz` 和 checkpoint-dir 是本地过程产物,应保持被 `.gitignore` 排除。
```powershell
python tools\run_rtk_imu_mechanical_prior_branch.py `
--manifest $MANIFEST `
--selection "$OUT\selection.json" `
--free-baseline "$OUT\free_baseline.json" `
--output "$OUT\mechanical_47_window.json" `
--state-output "$OUT\states.npz" `
--rotation-rpy-deg 0.454 -0.003 0.012
python tools\run_rtk_imu_mechanical_prior_heldout.py `
--manifest $MANIFEST `
--calibration-selection "$OUT\selection.json" `
--all-selection <all-nonoverlapping-selection.json> `
--engineering-result "$OUT\mechanical_47_window.json" `
--output "$OUT\heldout.json" `
--checkpoint-dir "$OUT\heldout_checkpoints" `
--rotation-rpy-deg 0.454 -0.003 0.012
```
随后运行独立 innovation、传播根因审计和旋转敏感性。它们不重新优化杆臂,不应被用于调 covariance、R2G 或机械先验。
```powershell
python tools\audit_rtk_imu_heldout_innovation.py `
--manifest $MANIFEST `
--calibration-selection "$OUT\selection.json" `
--all-selection <all-nonoverlapping-selection.json> `
--engineering-result "$OUT\mechanical_47_window.json" `
--output "$OUT\heldout_innovation.json" `
--rotation-rpy-deg 0.454 -0.003 0.012
python tools\audit_rtk_imu_propagation_bias_root_cause.py `
--manifest $MANIFEST `
--calibration-selection "$OUT\selection.json" `
--all-selection <all-nonoverlapping-selection.json> `
--engineering-result "$OUT\mechanical_47_window.json" `
--output "$OUT\propagation_bias_root_cause.json" `
--rotation-rpy-deg 0.454 -0.003 0.012
```
最终仅汇总已生成的结果,不在 release 阶段重新拟合:
```powershell
python tools\finalize_rtk_imu_engineering_release.py `
--calibration "$OUT\mechanical_47_window.json" `
--heldout-postfit "$OUT\heldout.json" `
--innovation "$OUT\heldout_innovation.json" `
--sensitivity <rotation_sensitivity.json> `
--convergence-retry <heldout_retry.json> `
--propagation-root-cause "$OUT\propagation_bias_root_cause.json" `
--output "$OUT\engineering_release_decision.json"
```
## 相关文件
- [RTK-IMU 代码包](rtk_imu/README.md)
- [多源导出与旋转 V3 说明](docs/rtk_imu_multisource_v3.md)
- [engineering 6DoF 说明](docs/rtk_imu_engineering_6dof.md)
- [历史链路审计](docs/rtk_imu_calibration.md)
- [正式结果索引](artifacts/rtk_imu_calibration_v3/README.md)
+1 -1
View File
@@ -14,4 +14,4 @@
- `translation_result.json`:杆臂、平移、齐次矩阵、协方差/秩、位置/速度残差、偏置和 LOO。
- `summary.json`:供程序读取的最终状态和候选矩阵。
当前 `all_sessions/summary.json``diagnostic_not_accepted`。其中平移约 `[0.771, 0.569, -21.073] m` 明显不具机械真实性,禁止用于车辆配置。完整解释见 `docs/rtk_imu_calibration.md`
当前 `all_sessions/summary.json``diagnostic_not_accepted`。其中平移约 `[0.771, 0.569, -21.073] m` 明显不具机械真实性,禁止用于车辆配置。完整解释见 [RTKIMU 标定说明](../../docs/RTK-IMU标定.md)
+18 -18
View File
@@ -1,24 +1,24 @@
# RTK-IMU V3 正式结果集
# RTKIMU V3 结果与审核证据
本目录只提交复现工程结论所需的审核结果。运行过程中的调试输出、状态快照、逐窗口 checkpoint 和旧版结果保留在本机,由仓库根目录 `.gitignore` 排除
本目录保存**已提交的审核快照**。它不是原始数据目录,也不是日常运行的输出目录;原始 `.rscap`、统一导出、节点状态、checkpoint 和调试文件均应保留在本地工作目录
## 当前结论
## 先读哪个文件
- 固定旋转来源:`R2G_gravity_level_prior`
- 工程候选杆臂:`l_I = p_ANT1^I = [-0.4518015159, -0.2644749820, 0.7314656115] m`
- `data_only_translation_accepted=false`
- `engineering_translation_accepted=false`,原因是独立传播验证仍受公共加速度偏差影响
- `independent_extrinsic_sensitive_validation_passed=true`;当前结果可描述为机械杆臂经动态数据一致性验证的工程候选,不得描述为 data-only 平移标定结果。
1. `engineering_release_decision.json`:唯一的最终结论,包含候选杆臂、两个互逆变换、验收状态、禁止的表述和全部证据路径
2. `mechanical_prior_engineering_47_window.json`:47 个非重叠标定窗口中,无先验、固定机械杆臂和机械软约束结果的对比
3. `mechanical_prior_engineering_heldout.json`:267 个独立留出窗口的物理残差与收敛情况
4. `heldout_independent_innovation.json``propagation_bias_root_cause_audit.json`:解释最终未放行的独立传播误差
## 文件说明
## 文件分组
- `engineering_release_decision.json`:最终状态、变换和放行判定。
- `mechanical_prior_engineering_47_window.json`:相同 47 个非重叠窗口上的 free/fixed/prior 对比。
- `node_graph_free_information_selected_mechanical.json`:冻结的无先验 free-solve 基线。
- `lever_information_window_selection*.json`:窗口选择及实际边缘信息复核。
- `mechanical_prior_engineering_heldout.json`:未参与标定窗口的 held-out 验证。
- `heldout_independent_innovation.json``heldout_nonconverged_retry.json`:独立创新与失败窗口重试结果。
- `mechanical_prior_rotation_sensitivity.json`:固定候选杆臂的旋转扰动敏感性结果。
- `propagation_bias_root_cause_audit.json`:独立传播公共加速度误差根因审计。
| 分组 | 文件 | 说明 |
| --- | --- | --- |
| 发布结论 | `engineering_release_decision.json` | 当前唯一的放行判断。 |
| 旋转与数据质量 | `multisource_result.json``bestnava_doppler_factor_yield_*.json``hpr_dropout_bridge_*.json` | 原始数据、旋转和双天线观测可用性的审核。 |
| 杆臂与选窗 | `lever_information_window_selection*.json``node_graph_free_information_selected_mechanical.json``mechanical_prior_engineering_47_window.json` | 无先验可观性、固定窗口及机械杆臂一致性。 |
| 独立验证 | `mechanical_prior_engineering_heldout.json``heldout_independent_innovation.json``heldout_nonconverged_retry.json``mechanical_prior_rotation_sensitivity.json` | 留出数据、创新、重试和旋转扰动检查。 |
| 根因和历史审计 | `propagation_bias_root_cause_audit.json``motion_excitation_*.json``factor_consistency_audit.json` 等 | 帮助理解过程和未解决问题;不替代发布结论。 |
结果 JSON 是审核快照;需要重新生成时应通过 `tools/` 中相应入口运行,且不得提交运行产生的 checkpoint 或 `.npz` 状态文件
`lever_information_window_selection.json` 记录 47 个标定窗口;`lever_information_window_selection_refined.json` 记录 314 个全部非重叠窗口,可从中扣除前者得到 267 个留出窗口。`mechanical_prior_engineering_47_window_states.npz` 是历史缓存,不是必需输入,也不应重新提交
当前结论、术语和可执行复现步骤见 [RTKIMU 标定](../../docs/RTK-IMU标定.md)。
@@ -1,209 +0,0 @@
# 20260808 HI13 + H32LiDARIMU 标定现状与问题
> 数据:`D:\data\calibration_usable_20260808`
> 可用会话:`sessions_v1_host_aligned`(三优先窗)
> 当前结果目录:各窗 `out_fixed_dt0/`
> 清单:`sessions_v1_host_aligned/calibration_manifest_fixed_dt0.json`
> 车辆配置:`config/vehicle_hi13_h32_20260808.yaml`
> 约定外参:`p_IMU = T_IMU_lidar · p_lidar`
---
## 1. 一句话结论
**旋转 + 主机桥接时间对齐可以冻结;平移(full_se3)尚不可正式交付。**
三窗 `rotation_only`(δt=0)结果跨窗一致,**不必因平移先验 Z 修正而重跑旋转**。
---
## 2. 当前可用结果(`out_fixed_dt0`
约定:`p_IMU = T_IMU_lidar · p_lidar`;本轮交付 **仅旋转**`t = [0,0,0]``time_offset_s = 0`
| 窗 | 状态 | δt | roll/pitch/yaw (°) | 手眼 RMS (°) | 手眼对数 | vs CAD prior |
|----|------|----|---------------------|--------------|----------|--------------|
| `priority_174005_174515` | `rotation_only_accepted` | 0 | 0.398 / +0.108 / **89.998** | 0.625 | 1374 | 0.413° |
| `priority_174905_175450` | 同上 | 0 | 0.316 / 0.352 / **90.002** | 0.293 | 1182 | 0.473° |
| `priority_175910_180530` | 同上 | 0 | 0.373 / 0.036 / **90.005** | 0.786 | 789 | 0.375° |
- 跨窗旋转互差约 **0.15°–0.47°**(相对三窗均值 ≤0.26°)。
- CAD/安装平移先验只用于后续 SE3 / 校验,不写入本轮交付 `T`
- 原始摘要:各窗 `out_fixed_dt0/summary.json`;总表 `calibration_manifest_fixed_dt0.json`
### 2.1 窗1 `priority_174005_174515` — `R_IMU_lidar`
- 路径:`...\priority_174005_174515\out_fixed_dt0\summary.json`
- rpy_deg_xyz`[-0.39806616272552936, 0.10842366761721789, 89.99788311264182]`
- quaternion_xyzw`[-0.0031254048203223084, -0.0017872288323561246, 0.7070914597978358, 0.707112936622415]`
```text
R =
[[ 3.6946588133e-05, -0.9999758655693408, -0.0069474393698490 ],
[ 0.9999982088237712, 2.3798651350e-05, 0.0018925598731371 ],
[-0.0018923488575947, -0.0069474968493909, 0.9999740753156198 ]]
t = [0, 0, 0]
```
### 2.2 窗2 `priority_174905_175450` — `R_IMU_lidar`
- 路径:`...\priority_174905_175450\out_fixed_dt0\summary.json`
- rpy_deg_xyz`[-0.31554362742542746, -0.35231680831805484, 90.00193338170823]`
- quaternion_xyzw`[0.00022698471903919405, -0.004121119694188399, 0.7071067019847445, 0.7070948146172911]`
```text
R =
[[-3.3743238552e-05, -0.9999848355714863, -0.0055070399001942 ],
[ 0.9999810938467022, 1.2097239027e-07, -0.0061491421465438 ],
[ 0.0061490495645171, -0.0055071432752239, 0.9999659297008071 ]]
t = [0, 0, 0]
```
### 2.3 窗3 `priority_175910_180530` — `R_IMU_lidar`
- 路径:`...\priority_175910_180530\out_fixed_dt0\summary.json`
- rpy_deg_xyz`[-0.37335575043737196, -0.03585856981709423, 90.00538974486676]`
- quaternion_xyzw`[-0.002082462199099642, -0.002525219418619018, 0.7071355299053291, 0.7070704554452735]`
```text
R =
[[-9.4068775206e-05, -0.9999787650354249, -0.0065161821101807 ],
[ 0.9999997997313592, -8.9988606603e-05, -0.0006264497522950 ],
[ 0.0006258500675082, -0.0065162397345547, 0.9999785732361544 ]]
t = [0, 0, 0]
```
### 相对历史失败轮次
| 轮次 | 问题 | 结果 |
|------|------|------|
| `sessions_v1_aligned` | 首帧强行对齐设备钟 | 三窗手眼失败,RMS ~9°–12° |
| 自由估 δt + signed refine | 窗3 δt 漂到 0.48 s;窗2 yaw≈19° | 跨窗 yaw 矛盾(81°/19°/93°) |
| **本轮 fixed δt=0** | 主机桥接后冻结时间 | 三窗 yaw≈90°,可互证 |
---
## 3. 已澄清并写入配置的坐标系 / 先验
### 3.1 车体与传感器
- 车体:X 前 / Y 左 / Z 上;雷达与 IMU 安装在 **X 正方向**(后轮轴前方)。
- CAD 图纸可能画成 +X 朝后,那只是读图坐标系,**不是**车体真实轴。
- IMUHI13 RFUX 右 / Y 前 / Z 上),原始数据不做轴向重映射。
- 雷达 NPZ:假定与车体一致(X 前 / Y 左 / Z 上)。
### 3.2 安装量(`translation_m`
| 传感器 | X / Y(后轮轴中心) | Z(离地) |
|--------|---------------------|-----------|
| IMU | 2.574 / 0.0365 m | 0.8925 + 0.294 = **1.1865 m** |
| 雷达 | 2.522 / 0.00002 m | 相位中心离地 **1.994999879 m** |
- 后轮轴中心离地:**294 mm**(Z 用离地高时加在 CAD 轴心高上)。
- 雷达 CAD `dZ=1.637499879 m`;相位中心离地还需加后轮轴离地 `0.294 m` 和相位中心偏移 `0.0635 m`,最终为 `1.994999879 m`
### 3.3 导出外参先验
- `R_IMU_lidar` ≈ yaw 90°:`[[0,-1,0],[1,0,0],[0,0,1]]`(软约束 σ=15°)。
- `t_IMU_lidar`**`[0.0365, -0.0518, 0.8085]` m**(相对 Z = 1.994999879 1.1865 = 0.808499879 m)。
- **旋转先验不因 Z 修正改变**;平移先验 Z 更新为 0.808499879 m。
---
## 4. 现存问题清单
### P1. IMU 预积分平移 `Δp` 不可用(阻塞正式平移)
- 现象:可视化模式 4 若用完整 `X⁻¹ A X`,橙/蓝点云常呈**上下错层**(Z 差米级~几十米)。
- 根因:加速度预积分缺少可靠重力/零偏处理,`t_A` 尤其 Z 发散;**不是旋转外参错了**。
- 旁证:相对 GICP 的旋转残差中位约 0.16°;`|t_A|` 中位却常 >1 m。
- 影响:`full_se3` / 依赖 IMU 位移的平移估计不可信。
- 缓解(已做):`visualize_pair_3d.py``rotation_only` 默认模式 4 = **R 共轭 + GICP 的 t_B**`--mode4-translation gicp|imu|auto`)。
### P2. 平面运动导致竖直平移弱可观
- 三优先窗以水平转弯为主,缺少缓坡/俯仰激励。
- 流水线门控已给出 `translation_accepted=false`
- 即使打开平移先验(σ≈5 cm),弱激励下结果易变成**先验回显**,不宜当标定成功。
### P3. 时间偏移若再自由估计会被带偏(已规避,需保持)
- 主机 UTC 桥接(MSOP/IMU `HostReceiveUtc`)后,两路已在同一时间轴,残差通常几十毫秒量级。
- 若再做有符号 δt 精修,会与错误/未收敛的 R 耦合,窗3 曾从约 −0.12 s 走到 **0.48 s**。
- **现行做法**:桥接会话使用 `--fixed-time-offset-s 0 --no-signed-time-refine`
### P4. 单窗低残差 ≠ 外参正确(历史教训)
- 自由 δt 轮次中,窗2 手眼 RMS 最低(~0.3°)但 yaw≈19°,与 CAD/其他窗差 60°+。
- 平面运动下 yaw 外参可出现多个能拟合 `R_A R_X ≈ R_X R_B` 的解。
- **必须**做跨窗一致性 + 可视化叠点,不能只看单窗 RMS。
### P5. 旋转软先验尚未做无先验对照
- 当前 σ=15°;笔记显示 Tsai 初值本身已接近(约 0.3°–1.1° RMS),不像纯先验硬拽。
- 仍缺一次:关闭先验或放大 `sigma_deg` 的对照,以排除「只是被拉到 90°」的疑虑。
### P6. 文档与操作约定未完全同步(工程)
- README 需明确写清:host-bridge 后固定 δt=0、禁用 signed refine、rotation_only 可视化用法。
- 交付物目前缺一版「冻结的联合/中位 R + 使用说明」JSON/报告(旋转可交,平移明确不交)。
---
## 5. 不该做 / 可以做
| 动作 | 建议 |
|------|------|
| 因 Z 先验修正重跑三窗 rotation_only | **不必**R 未依赖新 t |
| 正式交付 6-DOF / 信赖当前 `Δp` 估 t | **不要** |
| 试验性 `full_se3`(固定 R、δt=0、新 t 先验) | 可做,结果标「实验」 |
| 可视化验收模式 3 vs 4(gicp 平移) | **建议做** |
| 无先验 / 大 σ 旋转对照 | **建议做** |
| 冻结交付 `R` + `δt=0` 说明 | **建议做** |
| 补采缓坡或加强垂直尺寸约束后再估 t | 正式平移前需要 |
---
## 6. 建议下一步顺序
1. **验收旋转**:三窗抽转弯运动对,模式 3/4 叠点;可选无先验对照。
2. **定稿旋转**:三窗中位或联合手眼 → 交付 `R_IMU_lidar` +「δt=0(主机桥接)」说明;**明确不交 t**。
3. **工程收尾**:README 主机桥接配方;需要时再整理联合标定脚本入口。
4. **平移(靠后)**:改善 IMU 位移模型或改用更可靠的位移观测 + 竖直激励后,再用新 `t` 先验跑 SE3。
---
## 7. 常用路径与命令
```text
数据根:
D:\data\calibration_usable_20260808\sessions_v1_host_aligned\
结果:
...\priority_XXXX\out_fixed_dt0\summary.json
...\priority_XXXX\out_fixed_dt0\motion_pairs.json
...\calibration_manifest_fixed_dt0.json
```
```powershell
# 可视化(rotation_only 默认模式4用 GICP 平移)
python tools\visualize_pair_3d.py `
--lidar D:\data\calibration_usable_20260808\sessions_v1_host_aligned\priority_174005_174515\lidar `
--summary D:\data\calibration_usable_20260808\sessions_v1_host_aligned\priority_174005_174515\out_fixed_dt0\summary.json `
--pair-index 0
# 若要看「坏 Δp」导致的错层效果:
# --mode4-translation imu
```
---
## 8. 问题优先级(跟踪用)
| ID | 严重度 | 状态 | 标题 |
|----|--------|------|------|
| P1 | 高 | 未解决 | IMU `Δp` 不可用,阻塞正式平移 |
| P2 | 高 | 未解决 | 平面运动,竖直 t 弱可观 |
| P3 | 高 | 已规避 | 自由 δt / signed refine 带偏(需保持冻结) |
| P4 | 中 | 已吸收教训 | 单窗低残差不可单独验收 |
| P5 | 中 | 待做 | 无旋转先验对照 |
| P6 | 低 | 待做 | README/交付物同步 |
-195
View File
@@ -1,195 +0,0 @@
# LiDARIMU 外参标定说明
**用途:** 方法约定与实现状态(深入阅读)。日常使用请先看根目录 [`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
[静止 2030 s] → [低速激励 38 min] → [再静止 1020 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 → V1dlog 用 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) | 改代码 |
+241
View File
@@ -0,0 +1,241 @@
# RTKIMU 标定
本文是本仓库 RTK–IMU 标定的唯一规范说明,覆盖数据、方法、当前结果、限制和复现。它不使用项目内部阶段代号作为前提。
## 结论与适用范围
本次标定的正确表述是:**双天线方向和水平静止时的重力约束给出了固定旋转;天线相位中心到 IMU 的平移以机械测量为绝对基准,RTK 与 IMU 动态数据对该安装关系完成了独立一致性与稳定性验证。** 动态数据未能独立、精确地估计完整三维杆臂,但没有发现机械测量值与真实运动矛盾。
| 项目 | 当前值或状态 |
| --- | --- |
| 天线相位中心相对 IMU 的杆臂 `l_I` | `[-0.4518015159, -0.2644749820, 0.7314656115] m` |
| 固定旋转来源 | 水平静止时的双天线基线与重力约束 |
| 固定旋转近似 RPYX/Y/Z | `[0.454°, -0.003°, 0.012°]` |
| 仅由数据估计三维平移 | 未通过:`data_only_translation_accepted=false` |
| 正式工程平移验收 | 未通过:`engineering_translation_accepted=false` |
| 杆臂敏感的高动态独立验证 | 通过:未发现机械杆臂冲突 |
该候选可用于算法联调和工程验证,但不能称为“数据独立完成的完整六自由度标定”或“正式工程放行的外参”。低速、低角速度留出数据仍显示约 `0.20 m/s²` 的共同加速度传播误差;其根因未关闭前,工程放行保持为否。机器可读结论见 [工程发布决定](../artifacts/rtk_imu_calibration_v3/engineering_release_decision.json)。
## 安装与坐标定义
- 主天线为 ANT1,位于车辆前进方向左侧;从天线为 ANT2,位于右侧;两者平行安装。
- 双天线报文的 heading 是**主天线到从天线**的方向。
- IMU 的 `+Y` 指向车辆前进方向;天线基线因此指向车辆右侧。
- GGA 的参考点为 ANT1 相位中心,离地 `1.916499878 m`
- `l_I = p_ANT1^I` 表示从 IMU 原点指向 ANT1 相位中心、并在 IMU 坐标系表达的向量。
输出变换的定义为:
```text
p_RTK = R_RTK_IMU · p_IMU + t_RTK_IMU
p_IMU = R_RTK_IMUᵀ · p_RTK + l_I
t_RTK_IMU = -R_RTK_IMU · l_I
```
RTK 原点就是 ANT1,所以 `T_IMU_RTK` 的平移等于 `l_I`,两个变换必须互逆。下游实现必须按这些公式检查方向和符号。
## 原始数据与统一导出
使用三个日期的 G90 双天线 RTK 与 HI13 IMU 原始 `.rscap`。按捕获开始时间在 1.5 秒内配对,共导出 55 组会话;0815 的一组无匹配 HI13,已记录为 unmatched,不参与联合求解。
| 批次 | 配对会话 | GNHPR | BESTNAVA | PVTSLNA | Q4 双天线方向 | Fixed Doppler |
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
| 0808 | 18 | 46,180 | 8,291 | 5,993 | 45,606 | 8,128 |
| 0815 | 28 | 96,241 | 12,660 | 9,638 | 27,045 | 3,385 |
| 0819 | 9 | 15,717 | 2,029 | 1,427 | 14,976 | 1,930 |
旧导出以 GGA 为中心,将最近的 GNHPR 合并到同一行,且没有保留 BESTNAVA/PVTSLNA;这会把异步报文伪装成同时观测,也不能独立使用 GNSS 位置和 Doppler 速度。
新导出保留每条异步报文:
| 文件 | 内容 |
| --- | --- |
| `imu.npz` | HI13 `system_time`、三轴陀螺/加速度、RPY、四元数、磁场、PPS、温度、气压和主机接收时间 |
| `rtk.csv` | 各 GGA/GNHPR/BESTNAVA/PVTSLNA 的测量时间、质量、校验和和原始字段 |
| `export_summary.json` | 报文统计、四元数检查与跨时钟诊断 |
| `manifest.json` | 会话、批次、导出目录与未配对记录 |
HI13 `system_time` 是主时间轴。G90 的 GNSS UTC 或周/TOW 时间原样保留,并映射到此主时间轴;主机接收时间只用于时钟桥接、延迟和抖动诊断,绝不能作为采样时间。
## 求解与验证流程
```text
统一导出原始报文
→ 检查校验和、固定解、时间连续性和 IMU 预积分覆盖
→ 由双天线基线和重力固定旋转
→ 以节点状态图检查无机械先验时的杆臂可观性
→ 以机械杆臂为基准进行动态一致性验证
→ 使用未参与标定的数据和高动态转弯/坡道复核
```
### 旋转
双天线基线只提供两个方向自由度,不能单独推出完整三维姿态。因此旋转经过三类检查:
1. 连续高质量基线与 IMU 相对转动,检查基线在 IMU 中的方向。
2. 基线加高速近似直线 Doppler 速度,独立检查前向;因可用高速样本不足且与 IMU 航向存在不一致,它只作诊断。
3. 明确真实水平、车辆静止的会话中,基线确定横向,HI13 重力确定竖直,叉乘得到前向。这是当前固定旋转的正式来源。
旧式“直接把 GNHPR 三轴姿态与 IMU 做手眼”仅作诊断,不再作为正式外参。
### 平移与杆臂
每个 GNSS 节点包含姿态、位置、速度、陀螺偏置和加速度偏置。相邻节点由带协方差的 IMU 预积分连接;BESTNAVA 约束三维位置,Doppler 约束速度,GGA 只在 BEST 缺失时补充水平位置,双天线方向是可选姿态观测。GGA 的 MSL 高程绝不用于 ENU 的 Z 轴。
```text
p_ANT1^W = p_IMU^W + R_WI · l_I
v_ANT1^W = v_IMU^W + R_WI · ((ω - b_g) × l_I)
```
无机械先验求解只用来检查可观性:边缘化其他状态后,检查三维杆臂的信息矩阵、协方差、最弱方向和不同初值稳定性。本批数据不能稳定约束完整 XYZ,所以不会用其点估计替代机械值。
在同一批非重叠高动态窗口中,已比较无先验诊断解、固定机械杆臂和机械软约束解。机械值没有显著恶化位置、速度或双天线残差;但数据相对机械先验的信息增益不足,不能证明数据细化了杆臂。因此绝对值仍以机械测量为准。
## 如何使用结果
可以:固定本文旋转和机械杆臂,用于定位、融合或控制算法验证;并把“机械测量 + 动态一致性验证”写入配置或报告。
不能:把它描述为数据独立的三维平移标定、完整六自由度正式放行,或仅凭优化收敛就宣称杆臂真实。
## 结果文件与本地过程文件
`artifacts/rtk_imu_calibration_v3/` 是**本次提交的审核快照**,不是原始数据目录,也不是每次运行的工作目录。阅读顺序如下:
| 类别 | 主要文件 | 用途 |
| --- | --- | --- |
| 最终结论 | `engineering_release_decision.json` | 唯一的放行状态、候选杆臂、两个互逆变换和限制说明;下游首先读取它。 |
| 旋转证据 | `multisource_result.json` | 双天线方向、重力和速度诊断的旋转结果。 |
| 杆臂一致性 | `mechanical_prior_engineering_47_window.json` | 同一 47 个标定窗口上无先验、固定机械值和机械软约束三种结果的比较。 |
| 独立验证 | `mechanical_prior_engineering_heldout.json``heldout_independent_innovation.json` | 未参与标定的 267 个窗口的物理残差和独立传播创新。 |
| 稳定性与根因 | `mechanical_prior_rotation_sensitivity.json``propagation_bias_root_cause_audit.json` | 固定旋转扰动的影响,以及低速传播公共加速度误差的诊断。 |
| 固定选窗输入 | `lever_information_window_selection.json``lever_information_window_selection_refined.json` | 分别记录 47 个标定窗口和 314 个全部非重叠窗口;后者用于从中扣除 47 个标定窗口,得到 267 个留出窗口。 |
| 辅助审计 | `bestnava_doppler_factor_yield_*.json``hpr_dropout_bridge_*.json``motion_excitation_*.json` 等 | 记录数据保留率、双天线短缺口处理和运动激励检查;它们解释流程选择,不单独决定放行。 |
目录中还保留少量历史诊断和调试快照,文件名含 `debug``fast_diagnostic``p0` 或旧 node-graph 阶段。这些不是当前发布结论,阅读时应以 `engineering_release_decision.json` 及其 `evidence` 字段指向的文件为准。`mechanical_prior_engineering_47_window_states.npz` 是一次历史状态缓存;它不是复现的必要输入,也不应在后续运行中再次提交。
原始 `.rscap`、统一导出目录、运行中的 `.npz` 状态、checkpoint 和临时 JSON 应放在仓库外或被忽略的本地工作目录。不要把它们覆盖到 `artifacts/rtk_imu_calibration_v3/`,以免把正式审核快照和个人运行过程混在一起。
## 复现
### 复现范围
| 目标 | 是否需要原始数据 | 推荐操作 |
| --- | --- | --- |
| 核验当前发布结论 | 否 | 读取 `engineering_release_decision.json`,并按其 `evidence` 字段查看证据 JSON。 |
| 重做数据导出和固定旋转 | 是 | 按下文步骤 1–2 运行;结果应与本文的会话数、时间规则和旋转量级一致。 |
| 重做机械杆臂一致性与留出验证 | 是 | 按步骤 3–5 使用冻结选窗文件;计算量较大,所有输出放到本地工作目录。 |
| 生成新的工程结论 | 是,且需新的审核决策 | 不要复用或覆盖当前发布快照;应新建工作目录和结果目录,并重新执行完整门禁。 |
以下命令用于重建本次发布所依据的流程。原始数据路径不提交仓库;导出脚本目前的三批默认来源定义在 `tools/export_rtk_imu_unified.py``DEFAULT_SOURCES`。若本机原始数据不在这些位置,应先在该常量中仅替换本地路径,保持批次和文件配对规则不变。
### 1. 导出 55 组统一数据
```powershell
python -m pip install -e ".[dev]"
$WORK = "D:\data\rtk_imu_reproduce" # 本地工作目录,不提交
$UNIFIED = "$WORK\unified"
python tools\export_rtk_imu_unified.py --output-root $UNIFIED --overwrite
$MANIFEST = "$UNIFIED\manifest.json"
```
检查 `manifest.json`:应有 55 个配对会话,0815 的一个单独 G90 记录在 `unmatched`;每个会话应包含 `imu.npz``rtk.csv``export_summary.json`。确认 HI13 `system_time` 是主时间轴,主机接收时间没有成为观测采样时间。
### 2. 重建固定旋转
本次发布使用两个明确水平、车辆静止的会话。两个 `--level-static` 参数都必须提供:
```powershell
$ROTATION = "$WORK\rotation.json"
python tools\run_rtk_imu_multisource.py `
--manifest $MANIFEST `
--level-static 0819_20260819_072130 `
--level-static 0819_20260819_073045 `
--output $ROTATION
```
检查输出中“基线 + 重力 + 水平场地约束”的旋转是否接近 `[0.454°, -0.003°, 0.012°]`。如果差异明显,应停止后续步骤,先核对天线方向、会话是否真实水平和时间/坐标定义;不要直接求杆臂。
### 3. 选择并诊断 47 个标定窗口
本次种子运动分别是持续绕圈、左右转向和坡道。脚本会在不共享 IMU/GNSS/HPR 样本的前提下,按杆臂信息增益补充窗口;当前发布的固定结果为 47 个窗口。
```powershell
$SEL47 = "$WORK\selection_47.json"
python tools\select_rtk_imu_windows_by_lever_information.py `
--manifest $MANIFEST `
--circle-session 0808_20260808_092827 `
--left-right-session 0808_20260808_082148 `
--slope-session 0815_20260812_123424 `
--rotation-rpy-deg 0.4543066225 -0.0026392019 0.0122384129 `
--output $SEL47
$FREE47 = "$WORK\free_47.json"
python tools\run_rtk_imu_node_graph_free_selected.py `
--manifest $MANIFEST `
--selection $SEL47 `
--rotation-rpy-deg 0.4543066225 -0.0026392019 0.0122384129 `
--start-name all `
--output $FREE47
```
`$FREE47` 只用于确认无机械先验时的可观性和多初值稳定性;它不是可交付杆臂,也不应因此修改机械值。
### 4. 重做机械杆臂一致性比较
```powershell
$ENGINEERING = "$WORK\mechanical_47.json"
python tools\run_rtk_imu_mechanical_prior_branch.py `
--manifest $MANIFEST `
--selection $SEL47 `
--free-baseline $FREE47 `
--rotation-rpy-deg 0.4543066225 -0.0026392019 0.0122384129 `
--state-output "$WORK\mechanical_47_states.npz" `
--output $ENGINEERING
```
结果必须同时比较无先验、固定机械杆臂和机械软约束杆臂。`mechanical_47_states.npz` 仅为本地缓存,不提交。
### 5. 重做留出验证和发布汇总
本次留出验证使用 314 个冻结的全部非重叠窗口,其中 47 个是标定窗口、267 个是留出窗口。为了精确复现本次窗口划分,直接使用仓库中的 `lever_information_window_selection_refined.json`,不要重新选择或改变窗口。
```powershell
$ALL314 = "artifacts\rtk_imu_calibration_v3\lever_information_window_selection_refined.json"
$HELDOUT = "$WORK\heldout.json"
python tools\run_rtk_imu_mechanical_prior_heldout.py `
--manifest $MANIFEST `
--calibration-selection $SEL47 `
--all-selection $ALL314 `
--engineering-result $ENGINEERING `
--checkpoint-dir "$WORK\heldout_checkpoints" `
--rotation-rpy-deg 0.4543066225 -0.0026392019 0.0122384129 `
--output $HELDOUT
python tools\audit_rtk_imu_heldout_innovation.py `
--manifest $MANIFEST `
--calibration-selection $SEL47 `
--all-selection $ALL314 `
--engineering-result $ENGINEERING `
--rotation-rpy-deg 0.4543066225 -0.0026392019 0.0122384129 `
--output "$WORK\heldout_innovation.json"
python tools\audit_rtk_imu_propagation_bias_root_cause.py `
--manifest $MANIFEST `
--calibration-selection $SEL47 `
--all-selection $ALL314 `
--engineering-result $ENGINEERING `
--rotation-rpy-deg 0.4543066225 -0.0026392019 0.0122384129 `
--output "$WORK\propagation_bias_root_cause.json"
```
旋转敏感性、未收敛窗口重试和最终汇总属于发布级验证;它们不重新拟合杆臂。若要重新生成最终发布 JSON,必须连同上述审计结果、旋转敏感性结果和重试结果一起传给 `tools/finalize_rtk_imu_engineering_release.py`。在没有完成这些验证时,不得将本地结果标为成功。
## 代码边界与审核证据
RTK 专用代码位于 `rtk_imu/`,命令行和审计工具位于 `tools/`。它只复用 `imu_lidar/` 的通用几何、地理坐标、IMU 读取、预积分和旋转初始化模块;不依赖雷达点云、配准或雷达联合优化代码。
- [多源旋转结果](../artifacts/rtk_imu_calibration_v3/multisource_result.json)
- [47 窗口机械杆臂比较](../artifacts/rtk_imu_calibration_v3/mechanical_prior_engineering_47_window.json)
- [留出数据验证](../artifacts/rtk_imu_calibration_v3/mechanical_prior_engineering_heldout.json)
- [独立创新审计](../artifacts/rtk_imu_calibration_v3/heldout_independent_innovation.json)
- [传播误差根因审计](../artifacts/rtk_imu_calibration_v3/propagation_bias_root_cause_audit.json)
-109
View File
@@ -1,109 +0,0 @@
# V1 标准中间数据格式
**用途:** 标定程序读入的 CSV/NPZ 约定,以及新车原始数据如何导出。总览见根目录 [README](../README.md)。
## 从原始数据导出
**推荐(新 H32 + HI13):** HI13 `.rscap` + 雷达 Medulla dlog / recovered zipraw MSOP + DIFOP)。
```powershell
python tools\export_rscap_to_v1.py `
--imu-rscap path\to\hi13r4-imu.rscap `
--imu-kind hi13 `
--lidar-dlog path\to\session_or_dlog_or_recovered.zip `
--host-start 2026-08-08T17:40:05 `
--host-end 2026-08-08T17:45:15 `
--out path\to\session_v1 `
--frame-stride 5 `
--require-difop
```
`--lidar-dlog` 可为:标准 `dobject/`+`dobject_recording/` 目录,或 recovered zip`indices.log` + `data.bin`)。
`--imu-kind``hi13` / `n300` / `auto`(默认按文件名推断)。
`--host-start/end`:按本地墙钟切窗(仅裁剪;标定主轴仍是设备时间)。
默认 DObject`frontlidar-msop-raw``frontlidar-difop-raw`
**兼容旧 MSOP-only `.rscap`**
```powershell
python tools\export_rscap_to_v1.py `
--imu-rscap path\to\n300.rscap `
--lidar-rscap path\to\h32_msop.rscap `
--out path\to\session_v1 `
--frame-stride 1
```
产出:`imu.csv``lidar/`(含 `frames_index.csv`)、`export_summary.json`
标定主轴仍是**设备时间**;同时写出**主机 UTC 接收时间**,用于把雷达帧桥接到 IMU 设备钟(禁止把两边设备时间第一帧强行重合)。
## IMU
文件:`imu.csv``imu.npz`
### CSV
```text
t,gx,gy,gz,ax,ay,az,t_host_utc_s,receive_utc_ticks
0.000000000,0.01,-0.02,0.00,0.05,-0.03,9.81,1754646005.123,6389...
...
```
| 列 | 含义 | 单位 |
|---|---|---|
| t | IMU 设备时钟时间 | s |
| gx,gy,gz | 角速度 | rad/s |
| ax,ay,az | 比力/加速度 | m/s² |
| t_host_utc_s | 主机 UTC 接收时间(Unix | s |
| receive_utc_ticks | 同上,.NET UTC ticks | — |
### NPZ
数组:`t (N,)`, `gyro (N,3)`, `acc (N,3)`,含义同上。
> IMU 与 LiDAR 的时间原点可以不同。流水线会估计常值偏置:`t_imu = t_lidar + delta_t`。
## LiDAR
目录结构:
```text
lidar_session/
├── frames_index.csv
└── frames/
├── frame_00000.npz
├── frame_00001.npz
└── ...
```
### frames_index.csv
```text
frame_id,filename,t_start,t_end,host_receive_utc_ticks,t_host_utc_s,host_receive_utc_end_ticks,t_host_utc_end_s
0,frames/frame_00000.npz,10.000,10.100,6389...,1754646005.12,6389...,1754646005.22
```
| 列 | 含义 |
|---|---|
| t_start / t_end | H32 MSOP **设备时间**(秒) |
| t_host_utc_s / t_host_utc_end_s | 帧首/末包 **HostReceiveUtcTicks** → Unix 秒 |
也兼容旧列名 `file`。对齐脚本用主机 UTC 把 `t_*` 重写到 IMU 设备钟后再跑标定。
### 每帧 NPZ
- `points`: `float64/float32`,形状 `(N, 3)`LiDAR 直角坐标系,单位米
## 时间不同步能不能用?
可以,前提是:
1. 两边都覆盖同一段**有角速度激励**的物理运动(尤其是转弯);
2. 偏置近似为**常数**(短会话);
3. `--time-offset-search-s` 足够覆盖可能的偏移(默认 ±1 s,可加大)。
若两段数据完全不是同一趟行驶,或只有静止 IMU、没有重叠运动,则无法估 δt,标定会被 `blocked`
## 最小可用会话
- IMU:建议含静止段 + 运动段,采样率稳定
- LiDAR:建议 ≥ 20 帧,场景有墙/柱等结构,含转弯
-92
View File
@@ -1,92 +0,0 @@
# 从 LiDARIMU 平移困难到 RTKIMU 工程外参
本文解释为什么仓库同时保留 LiDAR–IMU 与 RTK–IMU 两条链路、为什么本轮将天线–IMU 外参的工程验证重心转向 RTK–IMU,以及两条链路如何避免互相混淆。
## 决策结论
保留两条链路,不删除 LiDAR–IMU。LiDARIMU 仍然是雷达与 IMU 旋转/时间关系的有效工具,也记录了平移失败的具体证据;RTK–IMU 是针对“天线相位中心到 IMU 的杆臂”采用的独立观测模型。它们共享基础数学与 IMU 预积分,但不共享求解器或验收结论。
当前 RTK–IMU 结果应描述为:**机械测量锚定的杆臂,经 RTK+IMU 动态数据一致性验证的工程候选**。它不是 data-only 平移标定,也不是已正式 engineering 放行的结果。
## LiDAR–IMU 为什么暂时不能交平移
LiDAR–IMU 链路将相邻关键帧的点云配准相对运动,与同一区间 IMU 预积分运动做手眼/联合优化。当前实车数据中旋转和时间关系可得到稳定结果,但平移受两个独立问题限制:
1. **IMU 位移预积分不可靠。** 加速度积分对重力与加速度零偏敏感;当前 `Δp` 尤其 Z 分量会发散。已有证据显示点云相对旋转残差中位约 `0.16°`,而 IMU 位移增量模长常大于 `1 m`,说明这不是单纯旋转误差。
2. **运动激励不足。** 现有重点窗口以水平转弯为主,缺少连续坡道/俯仰激励,竖直杆臂弱可观。即使加入很强的平移先验,求解也可能只是先验回显,而非数据观测。
因此 LiDAR–IMU 的状态是:旋转与时间对齐可用,`full_se3`/平移不可作为安装参数交付。详细证据在 [LiDARIMU 现状与问题](20260808_LiDAR-IMU标定现状与问题.md) 和 [问题清单](问题清单.md)。
## 为什么 RTK–IMU 更适合验证天线杆臂
RTK 直接给出天线相位中心的 GNSS 位置与 Doppler 速度;双天线还给出 ANT1→ANT2 基线方向。对固定旋转 `R_WI` 和杆臂 `l_I = p_ANT1^I`,观测模型为:
```text
p_ANT1^W = p_IMU^W + R_WI * l_I
v_ANT1^W = v_IMU^W + R_WI * ((omega - b_g) × l_I)
```
转弯时的 `omega × l_I`、加减速和坡道中的姿态变化,都会直接增强杆臂可观性;这比把加速度二次积分当作唯一位移来源更适合做天线–IMU 一致性检查。
双天线基线本身只有 2DoF 方向信息,不能凭空构造完整三轴姿态。本项目采用:
1. R1b:以基线和 IMU 动态估计 ANT1→ANT2 在 IMU 中的 2DoF 方向。
2. R2V:以基线和高质量 Doppler velocity 做独立诊断。
3. R2G:在确认水平的静止场地,以基线 + 重力 + 地面水平先验补齐完整旋转。
4. R3:跨会话、block-out、协方差和可观性复核。
正式固定旋转来源是 `R2G_gravity_level_prior`;旧式 GNHPR 三轴姿态手眼只保留为诊断,不作为正式外参。
## RTK–IMU 平移如何求解和验证
每个 GNSS node 使用 15DoF 状态 `(R,p,v,bg,ba)`,相邻 node 由 covariance-whitened IMU preintegration 与 bias random-walk 连接。因子包括:
- BESTNAVA:天线相位中心 XYZ
- GGA:仅在 BEST 缺失时约束 XY,不混用 MSL 高度到 ENU Z
- Doppler:天线速度;
- HPR:可选基线/姿态观测,direct 与短 bridge 使用不同协方差;
- 静止段:gravity candidate 与 ZUPT 分离,禁止将匀速直线误作 ZUPT。
杆臂的判断流程不是“优化器有数值就算成功”:
1. 先用无机械先验的 free solve 评估 Schur 边缘化后的 3×3 杆臂信息、协方差、最弱方向和多初值稳定性。
2. 若完整 XYZ 不可观,冻结 free 结果为诊断基线,不继续无限增加非线性 free solve。
3. 以机械测量作为绝对杆臂来源,比较 fixed-mechanical、soft-prior 与 free 的代价和物理残差。
4. 在 circle、left-right、slope 高动态窗口,以及与标定窗口不重叠的 held-out 数据上固定杆臂验证。
5. 做旋转扰动敏感性、独立 innovation 与 propagation root-cause audit;这些审计不重新优化杆臂。
## 本次结果应如何理解
- 当前固定工程候选:`l_I = [-0.4518015159, -0.2644749820, 0.7314656115] m`
- 机械测量决定杆臂绝对值;RTK+IMU 动态数据用于独立一致性和稳定性验证。
- 47 个非重叠标定窗口表明机械先验与数据拟合相容,但没有足够的数据驱动信息去有意义地细化机械值。
- held-out 物理验证和旋转敏感性通过;杆臂敏感的高动态数据没有发现机械外参明显冲突。
- 低速、低角速度独立传播仍有约 `0.20 m/s²` 的公共加速度偏差;这更像 propagation nuisance,而不是由 `omega × l` 消失后的杆臂错误造成。该问题尚未关闭,故 `engineering_translation_accepted=false`
这解释了两个同时成立的事实:机械外参没有被动态数据否定,但整个传播模型尚未达到正式放行标准。机器可读结果见 [工程 release 决策](../artifacts/rtk_imu_calibration_v3/engineering_release_decision.json)。
## 代码边界和共享模块
```text
imu_lidar/
lidar_io.py, lidar_deskew.py, registration.py, keyframes.py
motion_pairs.py, phase_a.py, pipeline.py, joint_optimizer.py
-> LiDARIMU 专用
rtk_imu/
rtk_io.py, rtk_attitude.py, rtk_imu_rotation.py
rtk_imu_multisource.py, rtk_imu_engineering.py, rtk_imu_node_graph.py
-> RTKIMU 专用
imu_lidar/contracts.py, geometry.py, geodesy.py, imu_io.py,
imu_preintegration.py, rotation_handeye.py
-> 两条链路可复用的基础能力
```
RTKIMU 只能 import 这 6 个共享模块,不应 import LiDAR 专用求解文件。命令入口都在 `tools/`,并按 `run_rtk_imu_*``audit_rtk_imu_*` 与 LiDAR 工具名称区分。
## 进一步工作
在宣称正式工程放行前,应优先关闭低速传播公共加速度偏差:区分图优化 nuisance accel bias 与可迁移物理 bias,复核静态 bias、重力泄漏和短时传播。不要用调机械先验、调 covariance 或扩大 free solve 来掩盖该问题。
RTK–IMU 的完整工程流程、当前变换和复现命令见 [README_RTK_IMU.md](../README_RTK_IMU.md)。
-168
View File
@@ -1,168 +0,0 @@
# RTK–IMU 标定链路审计与当前方案
> 2026-08-21 多源原始报文重构、R1b/R2V/R2G/R3 实现与三批数据实测结果,
> 见 [rtk_imu_multisource_v3.md](rtk_imu_multisource_v3.md)。本页保留旧式
> GGA/GNHPR 链路的审计背景;完整 HPR 手眼仍只允许作为诊断。
## 结论
当前数据可以验证“双天线基线方向与 IMU 的一致性”,但不能单独标定一个无歧义的完整三自由度 RTK 姿态外参。
G90 的 heading 表示主天线 ANT1 到从天线 ANT2 的基线方位。实车中主天线在左、从天线在右,因此该基线指向车体右侧,不是前进方向。IMU 的 +Y 指向车前;结合静止重力数据支持 IMU +Z 向上,可得到安装先验:IMU +X 指向车右,和 ANT1→ANT2 同向。
双天线只能观测这根基线的方位和仰角,绕基线自身的旋转不可观。GNHPR pitch 是横向基线的仰角,更接近车体横滚响应,不能当作坡道上的纵向车体 pitch;roll 字段也不是独立的第三姿态观测。因此,旧链路把 HPR 拼成完整 SO(3) 再做三轴手眼,是坡道 RMS、会话牵引和不稳定 yaw/pitch 的主要来源。
当前实现保留旧式完整 HPR 结果作为诊断量,但不允许它通过完整旋转门禁;平移在完整旋转通过前被硬冻结。
## 坐标系和参考点
统一输出约定:
```text
p_RTK = R_RTK_IMU p_IMU + t_RTK_IMU
```
RTK 车固坐标定义:
- +X:ANT1(主天线、左侧)→ ANT2(从天线、右侧),指向车右。
- +Y:车辆前进方向,与 IMU +Y 同向。
- +Z:车辆上方;静止重力数据支持 IMU +Z 向上。
- 该完整三轴定义包含机械安装先验;GNHPR 实际直接观测的只有 +X 基线。
位置参考点:
- GGA 为 ANT1/主天线相位中心。
- 相位中心离地高度为 1.916499878 m。
## 求解链路
### R0:协议、数据质量和时间
1. 校验 NMEA checksum。
2. GGA 位置只接收 Q=4 固定解。
3. GNHPR 姿态只接收 Q=4 固定解;Q=5 浮点解仅进入诊断统计,不参与标定。
4. 保留 GNHPR 自己的卫星数、差分龄期和基站号,不能再用 GGA 卫星数替代 HPR 质量。
5. 姿态使用 `hpr_measurement_utc_s` 映射后的 IMU 设备时间。
6. 遇到 HPR 无效、浮点、时间间隔异常或基线跳变时切断连续段,运动对不得跨断点。
### T0:残余时间偏移
只使用可观测的有符号 heading 角速度与 IMU `gyro_z` 做相关扫描。角速度模长会混入不可观的绕基线旋转,不再作为时间审计依据。
时间偏移只用于初始化/诊断。只有相关峰足够高、与次峰分离且峰宽足够窄时才应用,否则保持 0 s。
### R1:双天线基线一致性
对每个连续固定解片段构造 0.75 s、1.5 s、3.0 s 的相对运动。以安装先验 `u_IMU=[1,0,0]` 检验:
```text
angle(u_RTK(t0), u_RTK(t1))
≈ angle(u_IMU, ΔR_IMU(t0,t1) u_IMU)
```
该标量约束不虚构 RTK 的前向轴和上向轴。输出整体、逐会话 RMS/P95、分轴诊断及最坏时间区间。所有会话的总权重归一,避免高激励或样本更多的会话支配结果。
### R2:旧式完整 HPR 诊断
为兼容历史输出,将基线补成零 roll 的数学坐标架,再运行完整手眼。这个结果仅用于暴露符号错误、异常会话和旧结果变化,不能作为可交付外参。
LOO 删除一个会话后,会重新优化剩余会话的陀螺零偏,不再固定全量数据的 nuisance 参数。
### T1:平移
只有完整三自由度旋转“可观且通过”时,才允许进入杆臂和平移求解。当前条件不满足,因此:
- 不运行平移优化;
- 不输出 `translation_result.json`
- `t_RTK_IMU_m``T_RTK_IMU` 为 null
- 历史巨大 Z、米级不确定度和约 1 m/s 速度残差不再消耗优化时间。
## 当前 8 会话结果
结果目录:`artifacts/rtk_imu_calibration_v2/all_sessions`
```text
可观测基线一致性:
RMS / median / P95 = 0.593665 / 0.146040 / 1.212972 deg
priority_175910 RMS / P95 = 1.316292 / 2.472570 deg
slope RMS / P95 = 1.264514 / 2.475899 deg
最坏区间 = priority_175910,约 5.084 deg
baseline gate = passed
时间偏移:
全局候选 = +0.005 s
峰值相关 = 0.909019
近峰宽度 = [-0.110, +0.170] s
实际应用 = 0 s
旧式完整 HPR 诊断:
RPY = [-0.132765, -0.297433, -1.558358] deg
RMS / P95 = 1.172397 / 2.404977 deg
std = [0.615416, 0.437419, 3.687145] deg
priority_175910 re-optimized LOO = 1.698555 deg
max re-optimized LOO = 1.699427 deg(删除 slope
legacy numeric gate = failed
full attitude observable = false
平移:
frozen / not run
```
旧结果中的 `priority_175910` 条件 LOO 为 5.14°。严格剔除 Q5、会话等权、断段保护以及 LOO 重估零偏后,该会话完整诊断 LOO 降为 1.699°。它和坡道会话仍是主要异常源,但现在异常集中在基线仰角通道,而不是 heading:这更符合原始 HPR 中 Q5、低卫星数和 pitch 大幅波动的事实。
## 已排除或仍存在的漏洞
- 已修复:heading 误当车前方向。
- 已修复:GNHPR pitch 误当纵向车体 pitch。
- 已修复:不可观 roll 注入完整姿态。
- 已修复:Q5 浮点 HPR 进入标定。
- 已修复:HPR 质量字段在导出时丢失。
- 已修复:相对运动跨越无效段或跳变。
- 已修复:样本多的会话权重过大。
- 已修复:LOO 固定全量会话零偏。
- 已修复:时间相关使用三轴角速度模长。
- 已修复:旋转未通过仍继续优化平移。
- 仍存在:当前运动不能稳定地从 GGA 速度补全车前/车上方向。
- 仍存在:基线绕轴自由度没有独立传感器观测。
- 仍存在:`priority_175910` 和坡道的基线仰角存在局部异常。
## 如何得到可交付的完整旋转
按优先级建议:
1. 采一组专用数据:空旷区域、全程 RTK fixed、较长直线加减速、左右转、坡道上下行,保留原始 GGA/GNHPR/IMU 时间和全部质量字段。
2. 用高质量前向速度补第二根轴。只在速度足够高、航向变化平缓的区间用 GGA course,并在同一优化中建模 ANT1 杆臂、非完整车辆侧向速度约束和时间偏移。
3. 用静止重力补上向轴时,必须把“地面水平/车辆静止”写成显式先验,并将结果标记为安装先验约束解,而不是双天线数据独立解。
4. 若能取得 G90 内部融合后的完整 INS 姿态、第三天线、轮速/转角或可靠车体姿态源,优先作为第二独立方向。
5. 完整旋转通过留出验证后,才恢复平移;平移应同时估计杆臂、速度、加计偏置,并检查垂向高程基准。
当前数据上尝试用平滑 GGA 速度直接补全姿态,结果随平滑窗口明显变化,受低速、转弯杆臂和高程差分噪声影响,不能进入正式结果。
## 与主流开源方法的对应
- Kalibr:角速度相关适合作为时间偏移初始化,不应在宽峰时强行采用候选值。
- iKalibr:采用连续时间轨迹联合估计时空参数,并强调充分激励;适合后续专用数据。
- MINS:异步测量插值并把传感器外参、时间和 nuisance 状态一起估计。
- GICI-LIB:因子图中显式进行 GNSS/INS 初始化、质量控制和异常值处理。
本项目暂不直接引入这些大型框架,而是吸收其原则:先保证物理可观测性和数据质量,再进行联合优化;不能用自由状态吸收错误模型。
参考:
- Unicore N4 Reference Commands Manual
- Unicore UM982 User Manual
- https://github.com/Unsigned-Long/iKalibr
- https://github.com/ethz-asl/kalibr
- https://github.com/rpng/MINS
- https://github.com/chichengcn/gici-open
## 代码入口
- `rtk_imu/rtk_attitude.py`GNHPR 基线语义及零 roll 数学补全。
- `rtk_imu/rtk_io.py`RTK CSV、Q4/Q5 和 checksum 质量门禁。
- `rtk_imu/rtk_imu_rotation.py`:时间审计、连续段、基线审计、旧式诊断和重优化 LOO。
- `rtk_imu/rtk_imu_replay.py`:坐标定义、参考点、平移冻结和 JSON 输出。
- `tools/rscap_v2/g90_rtk.py`:原始 GNHPR 解析及质量字段。
- `tools/export_g90_rtk_to_sessions.py`GNHPR 质量字段导出。
- `tools/run_rtk_imu_calibration.py`:端到端命令行入口。
- `tests/test_rtk_imu_calibration.py`:轴定义、Q4/Q5、时间和预积分回归测试。
-108
View File
@@ -1,108 +0,0 @@
# RTKIMU Engineering 6DoF 分支
该分支与 V3 `data_only` 严格链路并列,不改变其门禁结论:
```text
data_only_6dof_accepted = false
```
工程分支固定使用真实水平静止场地得到的 R2G 旋转,默认参考值为
`RPY=[0.4543066, -0.0026392, 0.0122384] deg`,输出始终记录:
```text
rotation_source = R2G_gravity_level_prior
translation_conditional_on_rotation = true
```
## 条件模型
估计量是 `l_I = p_ANT1^I`。每个连续质量段使用 HI13 设备时间、raw gyro/acc 动态预积分,融合 RTK Fixed 的 GGA/BESTNAVA 位置、BESTNAVA Doppler velocity 和 Q4 GNHPR 的 ANT1→ANT2 基线。逐段 nuisance state 包含初始姿态、IMU 原点初始位置、速度、gyro bias 和 acc bias。HI13 absolute quaternion/RPY(尤其 absolute yaw)不进入机械外参因子;R2V 仅作诊断。
静止相关因子分为两类:
- `gravity_candidate`:连续约 1.5 s 的低角速度、gyro/acc 方差稳定且加速度模长接近重力;它不能等价为静止。
- `zupt_static`:在 gravity candidate 基础上,必须同时有至少约 1 s 的连续 BESTNAVA Doppler 速度接近 0。高速或匀速直线不会加入 ZUPT。
连续段复用 R0 质量断点:checksum 无效、定位非 Fixed、GNHPR 非 Q4、设备时间回跳、HPR 测量间隙、baseline jump、位置测量间隙或 IMU gap 都会切段,禁止跨断点预积分。 断后片段还必须至少包含 6 个求解节点且持续不少于 5 s;更短的局部欠约束微段不会跨断点拼接,而是直接不进入杆臂优化。
## 高程与残差口径
- GGA 只约束 XYGGA MSL altitude 不定义也不参与 ENU-Z。
- ENU-Z reference 只来自有效 Fixed BESTNAVA altitudeBESTNAVA 才约束 XYZ。
- 输出分别为 `gga_xy_residual``bestnava_xyz_residual``doppler_velocity_residual`。未进入 Z factor 的 GGA 高度不进入垂向残差统计。
## 可观性与验收
杆臂可观性不再使用全状态最小奇异向量。状态分为杆臂 `l` 与 nuisance state,对优化 Hessian 计算 Schur complement
```text
H_l_marg = H_ll - H_ln pinv(H_nn) H_nl
```
只对该 3×3 marginal lever information 做 SVD,并输出:
- `l_I_marginal_covariance_m2``l_I_std_m`
- `lever_information_singular_values`
- `lever_information_condition_number`
- `lever_precision_rank`
- `weakest_lever_direction_I`
门禁分为两层:
- `solver_health_gates` 只判断优化是否收敛、数值是否有限且残差未发散。
- `engineering_acceptance_gates` 使用更严格的杆臂 marginal std/information/rank/condition、BESTNAVA XYZ、GGA XY、Doppler velocity、LOO、bootstrap、旋转敏感性和可选手量一致性。
任一核心门禁失败时,`engineering_6dof_accepted=false`。没有完整执行 bootstrap 和 18 组旋转敏感性时,两项门禁明确为 false,不会把阶段性 base/LOO 结果误标为正式放行。
Bootstrap 按 session 有放回抽样,并保留重复 session 的 multiplicity;重复抽中的 session 会重复贡献其全部连续段。
## 机械杆臂软先验与双解输出
`--manual-l-i-m` 仅在同时提供 `--manual-l-i-std-m` 或完整
`--manual-l-i-covariance-m2` 时才成为白化高斯软因子。求解器始终先运行无先验
`free_solution`,再运行 `prior_constrained_solution`;输出还包含机械参考及两者到
参考的差值。当前活动 engineering 解为 prior-constrained 解(若启用),但 acceptance
额外要求 free-solve 也与机械参考一致,软先验不能掩盖不可观或数据矛盾。
示例(数值需使用实际机械测量的 1σ,不可把示例值当作默认):
```powershell
--manual-l-i-m -0.45072 -0.25682 0.73208 `
--manual-l-i-std-m <sigma_x_m> <sigma_y_m> <sigma_z_m>
```
## 坐标转换
```text
T_RTK_IMU: p_RTK = R_RTK_IMU p_IMU - R_RTK_IMU l_I
T_IMU_RTK: p_IMU = R_RTK_IMU^T p_RTK + l_I
```
RTK 原点是 ANT1,因此 `T_IMU_RTK.translation == l_I`,两矩阵必须互逆。
## 分阶段运行
第一阶段默认只运行 base fit、marginal observability、residual audit 和 LOO
```powershell
python tools/run_rtk_imu_engineering_6dof.py `
--manifest D:\data\rtk_imu_unified_v3\manifest.json `
--output artifacts/rtk_imu_calibration_v3/engineering_6dof_base_loo.json `
--session <session-a> `
--session <session-b> `
--session <session-c>
```
只有 base/LOO 合理后,才显式启动全量验证:
```powershell
python tools/run_rtk_imu_engineering_6dof.py `
--manifest D:\data\rtk_imu_unified_v3\manifest.json `
--output artifacts/rtk_imu_calibration_v3/engineering_6dof_full.json `
--session <session-a> `
--session <session-b> `
--session <session-c> `
--run-bootstrap --bootstrap-repetitions 40 --bootstrap-seed 0 `
--run-rotation-sensitivity
```
正式会话应覆盖直行加减速、左右转、坡道和明确水平静止段。不得为了运行时间降低验收门禁或把未完成验证标为成功。
-175
View File
@@ -1,175 +0,0 @@
# RTK–IMU 多源原始数据与旋转标定 V3
## 可行性结论
重构方向正确且必要。原始捕获中确实存在旧导出链路忽略的 BESTNAVA、
PVTSLNA 和 HI13 姿态/四元数。它们可以补充速度、质量、绝对姿态和静止
重力约束,但本批数据尚不能通过完整旋转门禁:
- BESTNAVA 约 0.81 Hz,严格高速样本很少。
- 当前动态主要是平面 yaw,R1b 的两个倾斜自由度仍弱可观。
- HI13 四元数与 GNSS 真北存在稳定但非机械的 yaw 偏差,可能来自磁偏角或
内部导航融合。
- 两个明确水平静止会话的 R2G 很稳定,但它是水平/重力先验约束解。
因此,本次重构显著提高了诊断能力,也防止错误外参进入平移;它没有把信息
不足包装成“标定成功”。
## 三批原始数据
扫描根目录:
- 0808D:\data\raw_serial_capture_v2,仅选 20260808。
- 0815D:\data\0815\raw_serial_capture_v2;目录实际包含 2026081214。
- 0819D:\data\0819\raw_serial_capture_v2。
按文件名捕获开始时间在 1.5 s 内一一配对:
| 批次 | G90/HI13 配对 | GNHPR | BESTNAVA | PVTSLNA | Q4 HPR | Fixed Doppler |
|---|---:|---:|---:|---:|---:|---:|
| 0808 | 18 | 46,180 | 8,291 | 5,993 | 45,606 | 8,128 |
| 0815 | 28 | 96,241 | 12,660 | 9,638 | 27,045 | 3,385 |
| 0819 | 9 | 15,717 | 2,029 | 1,427 | 14,976 | 1,930 |
共完成 55 组统一导出。0815 有一组 G90 没有匹配 HI13manifest 将其列为
unmatched。发现一条 NMEA 时间为 0913A:保留原始行,设备时间留空并隔离,
没有回退到 host receive time。
速度不等于高速激励。增加速度 ≥1.5 m/s、水平速度标准差 ≤0.25 m/s 后,
三个批次分别只剩 44、8、0 条候选。
## 统一导出
输出根目录:D:\data\rtk_imu_unified_v3。
每组捕获:
- imu.npzHI13 system_time、gyro、accel、RPY、WXYZ quaternion、磁场、
PPS stamp、温度、气压和 host receive UTC。
- rtk.csv:每条原生异步 GGA/GNHPR/BESTNAVA/PVTSLNA 单独成行,不再把
HPR/BEST/PVT 最近邻挂到 GGA。
- export_summary.json:原始捕获摘要、报文数量、四元数范数和设备到 host
的仿射时钟诊断。
- manifest.json:全部会话、批次、目录和 unmatched 记录。
时间规则:
1. HI13 system_time 是 IMU 主时间轴。
2. BESTNAVA/PVTSLNA 使用 GNSS week/TOW 和 leap seconds。
3. GGA/GNHPR 使用报文自己的 UTC time-of-day。
4. RTK GNSS 测量时刻通过 HI13 device→host 仿射模型映射进 HI13 设备时钟。
5. host receive time 只用于跨时钟桥接、延迟和抖动诊断,绝不替代采样时刻。
6. checksum 无效、时间畸形或非固定解记录保留,但不进入求解。
## 新旋转链路
### R1b:基线在 IMU 中的 2DoF 方向
对连续 Q4 GNHPR 基线和 HI13 陀螺相对旋转使用不变量:
angle(b_ENU(t0), b_ENU(t1))
= angle(b_IMU, DeltaR_IMU b_IMU)
估计 b_IMU 的两个倾斜自由度及逐会话陀螺零偏。安装信息只用于选择 +X
半球,并施加明确记录的弱 20° 先验。按会话等权,输出残差、协方差和信息
奇异值。
### R2V:基线 + Doppler velocity
筛选条件:
- BESTNAVA position 为 SOL_COMPUTED/NARROW_INT
- velocity 为 SOL_COMPUTED/DOPPLER_VELOCITY
- checksum 有效;
- 水平速度 ≥1.5 m/s、速度标准差 ≤0.25 m/s
- |IMU gyro_z| ≤3°/s
- 速度方向与横向基线接近正交;
- GNHPR Q4,并有时间邻近的合法 HI13 quaternion。
基线给车右,Doppler velocity 给车前,叉积给车上。HI13 quaternion 的
body/world 和 ENU/NED 候选全部评分,只保留残差最小者。该方法会把 HI13
导航 yaw 偏差带入候选,因此必须和 R2G 交叉验证。
### R2G:基线 + 水平静止重力
只允许调用方明确标记的水平静止会话。本次使用:
- 0819_20260819_072130flat_static_hdg207
- 0819_20260819_073045flat_static_hdg082
每 10 s 分块,要求 gyro norm ≤0.35°/s,且加速度模长距标准重力不超过
0.15 m/s²。R1b 提供车右,加速度中值提供车上,叉积得到车前。
### R3:稳定性与正式门禁
R2V/R2G 都输出:
- 样本和会话数量;
- SO(3) RMS/P95
- 旋转向量样本标准差和均值协方差;
- leave-one-session
- 10 样本或 10 s block-out。
只有 R1b 可观、R2V 和 R2G 各自稳定、二者差异 ≤2° 时,才将
translation_unlocked 设为 true。旧 GNHPR 三轴手眼不参与正式门禁。
## 首轮实测
R1b
b_IMU = [0.999999976, -0.000213959, -0.000044368]
tilt_yz = [-0.0123, -0.0025] deg
pairs = 2091
RMS / P95 = 0.8086 / 1.7105 deg
information singular values = [1.176e-2, 8.476e-4]
std = [27.77, 7.47] deg
gate = failed
点估计接近 +X 是安装先验与名义轴一致的结果;巨大协方差说明不能宣称
数据独立估出了这两个小角。
R2V
qualifying samples / sessions = 41 / 2
selected quaternion convention = HI13_q_body_to_ENU
RPY = [0.7532, 0.0708, -9.2944] deg
RMS / P95 = 1.8436 / 3.4975 deg
max leave-one-session = 3.4519 deg
gate = failed
R2G
level-static blocks / sessions = 53 / 2
RPY = [0.4543, -0.0026, 0.0122] deg
RMS / P95 = 0.2542 / 0.2732 deg
max leave-one-session = 0.2688 deg
gate = passed (level/gravity-prior constrained)
R2V 与 R2G 的 SO(3) 差异为 9.3119°。R3 最终:
full_rotation_accepted = false
translation_unlocked = false
## 下一轮数据要求
1. BESTNAVA 改为至少 10 Hz,并确认 Doppler velocity 与 GNHPR 使用同一
GNSS week/TOW 输出周期。
2. 每个日期都录制多段 ≥3 m/s、持续 20–30 s 的正向直线;包含不同方位,
避免单一磁环境和单一会话支配。
3. 为 R1b 增加可控的 roll/pitch 激励;只有平面 yaw 无法稳定估出横向
基线的两个微小倾斜角。
4. 每个日期至少录两种车头方位的明确水平静止段,检验 HI13 重力和绝对
quaternion 的跨日期稳定性。
5. 若 HI13 quaternion 的 yaw 来自磁融合,应获取其导航坐标定义、磁偏角
设置和融合状态;否则 R2V 只使用其 roll/pitchyaw 由 GNSS 基线和速度
决定。
6. 上述门禁通过前继续冻结杆臂和平移。
## 实现入口
- tools/rscap_v2/g90_rtk.pyGGA/GNHPR/BESTNAVA/PVTSLNA 和双 checksum。
- tools/rscap_v2/hi13_imu.pyHI91 system_time、惯性、姿态和四元数。
- tools/export_rtk_imu_unified.py55 组配对、原生异步导出和断点续导。
- rtk_imu/rtk_imu_multisource.pyR1b/R2V/R2G/R3。
- tools/run_rtk_imu_multisource.py:多源旋转命令行入口。
- artifacts/rtk_imu_calibration_v3/multisource_result.json:首轮 R3 结果。
-157
View File
@@ -1,157 +0,0 @@
# 纯 LiDAR–IMU:标定流程与采集清单
**用途:** 现场怎么采合格数据(看完根目录 [README](../README.md) 后再看本文即可)。
算法命令与结果判读以 README 为准;改动史见 [`imu_lidar/CHANGELOG.md`](../imu_lidar/CHANGELOG.md)。
仅有激光雷达与 IMU、无 RTK/绝对位姿时的推荐采集与流程要点。
目标外参:`p_IMU = T_IMU_lidar · p_lidar``T_A_B` 表示把 B 系点变到 A 系)。
---
## 1. 原则(先读)
1. **时间对齐优先**:时钟偏置未对准时,旋转与平移都不可信;正式数据用**设备时间戳**。
2. **先旋转,再平移**:旋转通常更稳;平面低速时竖直方向平移常常不可观。
3. **用连续运动**:停车多站适合 RTK 手眼,不适合作为纯 IMU 外参主流程。
4. **可观才交平移**:激励不够就只交旋转,不强交“假精确”六自由度。
5. **残差小 ≠ 标定对**:需叠点云、跨会话等独立验证。
相对运动模型:
```text
A ≈ IMU 预积分相对运动(关键帧区间)
B ≈ 雷达关键帧配准相对运动
R_A · R_X ≈ R_X · R_B → 先求旋转
完整模式且可观时再求平移 t
```
---
## 2. 端到端流程(与现行代码一致)
```text
确认轴向 / 单位 / 时间语义
→ 现场采集(首尾静止 + 低速多转弯;建议 ≥2 段独立会话)
→ 导出标准中间格式(imu.csv + lidar 会话目录)
→ 质检(时间 / IMU)不通过则停
→ 粗估时间偏置 δt
→ 关键帧 → 配准得 B;完整 IMU 预积分得 A(旋转/速度/位移增量)
→ 加权旋转手眼得 R
→ 用 R 精修 δt,必要时重新组对再解 R(可交替数轮)
→ 联合精修 R 与常值陀螺零偏
→ full_se3 且可观:再估重力、关键帧速度、时变零偏与平移 t
→ 写出 T / δt / summary → 叠点云 / 跨会话验证后交付
```
| 步骤 | 现行模块 | 说明 |
| --- | -------------------------------------------------------------------- | --------------------------------------- |
| 质检 | `timestamp_audit` / `imu_audit` | 含静止段陀螺零偏初值 |
| 时间 | `time_offset` | 模长相关粗估 + 有符号三轴精修 |
| 运动对 | `keyframes` / `registration` / `imu_preintegration` / `motion_pairs` | 预积分始终算满;手眼先用旋转 |
| 旋转 | `rotation_handeye` | 加权手眼 |
| 精修 | `joint_optimizer` / `observability` | `rotation_only` 到旋转为止;`full_se3` 可观才碰平移 |
点云去畸变(`lidar_deskew`)可选;低速首轮可不依赖。
---
## 3. 采集设计
### 3.1 单趟会话结构
```text
静止 2030 s → 连续运动 38 min → 再静止 1020 s
```
运动优先:低速「8」字 / 左右圆;再补加减速直线。
要可靠竖直方向外参时,另加缓坡(约 3°~8°,有效长度优先 ≥20~30 m),或改用外测垂直尺寸先验。
### 3.2 会话安排
| 会话 | 作用 |
| ----- | ---------------------------------- |
| A | 主标定 |
| B | 独立验证(**同一场地**换一条不完全相同的路线即可,不参与求外参) |
| C(可选) | 不同速度/路线,测稳定性 |
安装全程不得改动。多会话不要跨会话拼运动对。
### 3.3 录制字段(原始,勿先做姿态融合)
- IMU:设备时间、陀螺、加速度(建议同时留主机接收时间便于排查)
- LiDAR:每帧起止时间(最好有包级/逐点时间)、原始点云
中间格式见 `[V1_数据格式.md](V1_数据格式.md)`
---
## 4. 现场 Checklist
**出发前**
- [ ] 安装固定;草图/卷尺粗测仅作参考,不当真值
- [ ] 单位与轴向确认;设备时间可写盘
- [ ] 结构化路线(墙/杆/路缘),避开空旷无特征区
- [ ] 存储与供电充足
**录制中**
- [ ] 首尾静止;中间有明显左右转与加减速
- [ ] 不改安装、不切换时间源
- [ ] 记录会话 ID、天气、异常(急刹、掉包等)
**当场快查**
- [ ] IMU 静止段平稳,转弯时角速度明显
- [ ] 点云帧数/点数正常,无明显大面积丢帧
- [ ] 雷达与 IMU 时间覆盖同一时段
**回实验室**
- [ ] 已导出中间格式并通过质检
- [ ] 本次目标:`rotation_only` 还是尝试 `full_se3`
- [ ] 若要竖直方向:确认真有俯仰/高度激励,否则降级交付
---
## 5. 精度预期
| 量 | 较现实范围 | 说明 |
| ---------- | --------- | ---------------- |
| 旋转 | 约 0.5°–2° | 最精确部分 |
| 水平平移 | 数厘米~十几厘米 | 强依赖配准、激励与同步 |
| 竖直 / 部分杠杆臂 | 往往更差甚至不可观 | 无高度激励时无法得出“精确 z” |
如果条件有限,优先交付:**可靠旋转 + δt + 可观的平移分量(若有)+ 明确限制说明**。
满足条件后的模式与成功标志见根目录 [`README.md`](../README.md) §0。
---
## 6. 交付物建议
程序默认写出:`T_IMU_lidar.json``time_offset.json``summary.json`
完整报告目录还可补充:可观性结论、跨会话对比、运动对质量表、限制说明(尤其竖直方向与时间同步方式)。
```text
静止 + 激励录制(多会话)
→ 质检 → 估 δt → 关键帧 A/B → 先解 R
→ 精修 δt 与 R → 可观则求 t → 验证后交付
```
-209
View File
@@ -1,209 +0,0 @@
# 20260808 HI13 + H32LiDARIMU 标定现状与问题
> 数据:`D:\data\calibration_usable_20260808`
> 可用会话:`sessions_v1_host_aligned`(三优先窗)
> 当前结果目录:各窗 `out_fixed_dt0/`
> 清单:`sessions_v1_host_aligned/calibration_manifest_fixed_dt0.json`
> 车辆配置:`config/vehicle_hi13_h32_20260808.yaml`
> 约定外参:`p_IMU = T_IMU_lidar · p_lidar`
---
## 1. 一句话结论
**旋转 + 主机桥接时间对齐可以冻结;平移(full_se3)尚不可正式交付。**
三窗 `rotation_only`(δt=0)结果跨窗一致,**不必因平移先验 Z 修正而重跑旋转**。
---
## 2. 当前可用结果(`out_fixed_dt0`
约定:`p_IMU = T_IMU_lidar · p_lidar`;本轮交付 **仅旋转**`t = [0,0,0]``time_offset_s = 0`
| 窗 | 状态 | δt | roll/pitch/yaw (°) | 手眼 RMS (°) | 手眼对数 | vs CAD prior |
|----|------|----|---------------------|--------------|----------|--------------|
| `priority_174005_174515` | `rotation_only_accepted` | 0 | 0.398 / +0.108 / **89.998** | 0.625 | 1374 | 0.413° |
| `priority_174905_175450` | 同上 | 0 | 0.316 / 0.352 / **90.002** | 0.293 | 1182 | 0.473° |
| `priority_175910_180530` | 同上 | 0 | 0.373 / 0.036 / **90.005** | 0.786 | 789 | 0.375° |
- 跨窗旋转互差约 **0.15°–0.47°**(相对三窗均值 ≤0.26°)。
- CAD/安装平移先验只用于后续 SE3 / 校验,不写入本轮交付 `T`
- 原始摘要:各窗 `out_fixed_dt0/summary.json`;总表 `calibration_manifest_fixed_dt0.json`
### 2.1 窗1 `priority_174005_174515` — `R_IMU_lidar`
- 路径:`...\priority_174005_174515\out_fixed_dt0\summary.json`
- rpy_deg_xyz`[-0.39806616272552936, 0.10842366761721789, 89.99788311264182]`
- quaternion_xyzw`[-0.0031254048203223084, -0.0017872288323561246, 0.7070914597978358, 0.707112936622415]`
```text
R =
[[ 3.6946588133e-05, -0.9999758655693408, -0.0069474393698490 ],
[ 0.9999982088237712, 2.3798651350e-05, 0.0018925598731371 ],
[-0.0018923488575947, -0.0069474968493909, 0.9999740753156198 ]]
t = [0, 0, 0]
```
### 2.2 窗2 `priority_174905_175450` — `R_IMU_lidar`
- 路径:`...\priority_174905_175450\out_fixed_dt0\summary.json`
- rpy_deg_xyz`[-0.31554362742542746, -0.35231680831805484, 90.00193338170823]`
- quaternion_xyzw`[0.00022698471903919405, -0.004121119694188399, 0.7071067019847445, 0.7070948146172911]`
```text
R =
[[-3.3743238552e-05, -0.9999848355714863, -0.0055070399001942 ],
[ 0.9999810938467022, 1.2097239027e-07, -0.0061491421465438 ],
[ 0.0061490495645171, -0.0055071432752239, 0.9999659297008071 ]]
t = [0, 0, 0]
```
### 2.3 窗3 `priority_175910_180530` — `R_IMU_lidar`
- 路径:`...\priority_175910_180530\out_fixed_dt0\summary.json`
- rpy_deg_xyz`[-0.37335575043737196, -0.03585856981709423, 90.00538974486676]`
- quaternion_xyzw`[-0.002082462199099642, -0.002525219418619018, 0.7071355299053291, 0.7070704554452735]`
```text
R =
[[-9.4068775206e-05, -0.9999787650354249, -0.0065161821101807 ],
[ 0.9999997997313592, -8.9988606603e-05, -0.0006264497522950 ],
[ 0.0006258500675082, -0.0065162397345547, 0.9999785732361544 ]]
t = [0, 0, 0]
```
### 相对历史失败轮次
| 轮次 | 问题 | 结果 |
|------|------|------|
| `sessions_v1_aligned` | 首帧强行对齐设备钟 | 三窗手眼失败,RMS ~9°–12° |
| 自由估 δt + signed refine | 窗3 δt 漂到 0.48 s;窗2 yaw≈19° | 跨窗 yaw 矛盾(81°/19°/93°) |
| **本轮 fixed δt=0** | 主机桥接后冻结时间 | 三窗 yaw≈90°,可互证 |
---
## 3. 已澄清并写入配置的坐标系 / 先验
### 3.1 车体与传感器
- 车体:X 前 / Y 左 / Z 上;雷达与 IMU 安装在 **X 正方向**(后轮轴前方)。
- CAD 图纸可能画成 +X 朝后,那只是读图坐标系,**不是**车体真实轴。
- IMUHI13 RFUX 右 / Y 前 / Z 上),原始数据不做轴向重映射。
- 雷达 NPZ:假定与车体一致(X 前 / Y 左 / Z 上)。
### 3.2 安装量(`translation_m`
| 传感器 | X / Y(后轮轴中心) | Z(离地) |
|--------|---------------------|-----------|
| IMU | 2.574 / 0.0365 m | 0.8925 + 0.294 = **1.1865 m** |
| 雷达 | 2.522 / 0.00002 m | 相位中心离地 **1.994999879 m** |
- 后轮轴中心离地:**294 mm**(Z 用离地高时加在 CAD 轴心高上)。
- 雷达 CAD `dZ=1.637499879 m`;相位中心离地还需加后轮轴离地 `0.294 m` 和相位中心偏移 `0.0635 m`,最终为 `1.994999879 m`
### 3.3 导出外参先验
- `R_IMU_lidar` ≈ yaw 90°:`[[0,-1,0],[1,0,0],[0,0,1]]`(软约束 σ=15°)。
- `t_IMU_lidar`**`[0.0365, -0.0518, 0.8085]` m**(相对 Z = 1.994999879 1.1865 = 0.808499879 m)。
- **旋转先验不因 Z 修正改变**;平移先验 Z 更新为 0.808499879 m。
---
## 4. 现存问题清单
### P1. IMU 预积分平移 `Δp` 不可用(阻塞正式平移)
- 现象:可视化模式 4 若用完整 `X⁻¹ A X`,橙/蓝点云常呈**上下错层**(Z 差米级~几十米)。
- 根因:加速度预积分缺少可靠重力/零偏处理,`t_A` 尤其 Z 发散;**不是旋转外参错了**。
- 旁证:相对 GICP 的旋转残差中位约 0.16°;`|t_A|` 中位却常 >1 m。
- 影响:`full_se3` / 依赖 IMU 位移的平移估计不可信。
- 缓解(已做):`visualize_pair_3d.py``rotation_only` 默认模式 4 = **R 共轭 + GICP 的 t_B**`--mode4-translation gicp|imu|auto`)。
### P2. 平面运动导致竖直平移弱可观
- 三优先窗以水平转弯为主,缺少缓坡/俯仰激励。
- 流水线门控已给出 `translation_accepted=false`
- 即使打开平移先验(σ≈5 cm),弱激励下结果易变成**先验回显**,不宜当标定成功。
### P3. 时间偏移若再自由估计会被带偏(已规避,需保持)
- 主机 UTC 桥接(MSOP/IMU `HostReceiveUtc`)后,两路已在同一时间轴,残差通常几十毫秒量级。
- 若再做有符号 δt 精修,会与错误/未收敛的 R 耦合,窗3 曾从约 −0.12 s 走到 **0.48 s**。
- **现行做法**:桥接会话使用 `--fixed-time-offset-s 0 --no-signed-time-refine`
### P4. 单窗低残差 ≠ 外参正确(历史教训)
- 自由 δt 轮次中,窗2 手眼 RMS 最低(~0.3°)但 yaw≈19°,与 CAD/其他窗差 60°+。
- 平面运动下 yaw 外参可出现多个能拟合 `R_A R_X ≈ R_X R_B` 的解。
- **必须**做跨窗一致性 + 可视化叠点,不能只看单窗 RMS。
### P5. 旋转软先验尚未做无先验对照
- 当前 σ=15°;笔记显示 Tsai 初值本身已接近(约 0.3°–1.1° RMS),不像纯先验硬拽。
- 仍缺一次:关闭先验或放大 `sigma_deg` 的对照,以排除「只是被拉到 90°」的疑虑。
### P6. 文档与操作约定未完全同步(工程)
- README 需明确写清:host-bridge 后固定 δt=0、禁用 signed refine、rotation_only 可视化用法。
- 交付物目前缺一版「冻结的联合/中位 R + 使用说明」JSON/报告(旋转可交,平移明确不交)。
---
## 5. 不该做 / 可以做
| 动作 | 建议 |
|------|------|
| 因 Z 先验修正重跑三窗 rotation_only | **不必**R 未依赖新 t |
| 正式交付 6-DOF / 信赖当前 `Δp` 估 t | **不要** |
| 试验性 `full_se3`(固定 R、δt=0、新 t 先验) | 可做,结果标「实验」 |
| 可视化验收模式 3 vs 4(gicp 平移) | **建议做** |
| 无先验 / 大 σ 旋转对照 | **建议做** |
| 冻结交付 `R` + `δt=0` 说明 | **建议做** |
| 补采缓坡或加强垂直尺寸约束后再估 t | 正式平移前需要 |
---
## 6. 建议下一步顺序
1. **验收旋转**:三窗抽转弯运动对,模式 3/4 叠点;可选无先验对照。
2. **定稿旋转**:三窗中位或联合手眼 → 交付 `R_IMU_lidar` +「δt=0(主机桥接)」说明;**明确不交 t**。
3. **工程收尾**:README 主机桥接配方;需要时再整理联合标定脚本入口。
4. **平移(靠后)**:改善 IMU 位移模型或改用更可靠的位移观测 + 竖直激励后,再用新 `t` 先验跑 SE3。
---
## 7. 常用路径与命令
```text
数据根:
D:\data\calibration_usable_20260808\sessions_v1_host_aligned\
结果:
...\priority_XXXX\out_fixed_dt0\summary.json
...\priority_XXXX\out_fixed_dt0\motion_pairs.json
...\calibration_manifest_fixed_dt0.json
```
```powershell
# 可视化(rotation_only 默认模式4用 GICP 平移)
python tools\visualize_pair_3d.py `
--lidar D:\data\calibration_usable_20260808\sessions_v1_host_aligned\priority_174005_174515\lidar `
--summary D:\data\calibration_usable_20260808\sessions_v1_host_aligned\priority_174005_174515\out_fixed_dt0\summary.json `
--pair-index 0
# 若要看「坏 Δp」导致的错层效果:
# --mode4-translation imu
```
---
## 8. 问题优先级(跟踪用)
| ID | 严重度 | 状态 | 标题 |
|----|--------|------|------|
| P1 | 高 | 未解决 | IMU `Δp` 不可用,阻塞正式平移 |
| P2 | 高 | 未解决 | 平面运动,竖直 t 弱可观 |
| P3 | 高 | 已规避 | 自由 δt / signed refine 带偏(需保持冻结) |
| P4 | 中 | 已吸收教训 | 单窗低残差不可单独验收 |
| P5 | 中 | 待做 | 无旋转先验对照 |
| P6 | 低 | 待做 | README/交付物同步 |
+166
View File
@@ -0,0 +1,166 @@
# 雷达–IMU 标定
本文是本仓库雷达–IMU 标定的唯一规范说明,覆盖目标、数据格式、运行方式、当前实车结果和采集要求。
## 目标与当前结论
目标是求雷达坐标系到 IMU 坐标系的安装关系:
```text
p_IMU = T_IMU_lidar · p_lidar
```
`T_A_B` 表示把 B 坐标系中的点变换到 A 坐标系。流程利用连续行驶中的相对运动,而不是把 IMU 加速度二次积分的长时间轨迹当作绝对真值。
当前 2026-08-08 实车数据的结论是:**旋转和主机桥接后的时间关系可作为候选冻结;完整平移不可交付。** 不应把旋转结果和零平移拼成看似完整的 4×4 外参,更不能把当前 IMU 位移预积分用于正式平移标定。
| 项目 | 当前状态 |
| --- | --- |
| 连续运动雷达–IMU 流程 | 已实现并有合成测试 |
| 实车旋转候选 | 三个窗口一致,可用于进一步验证 |
| 实车时间关系 | 主机桥接后冻结为 `0 s`,不再自由精修 |
| 实车完整平移 | 不可观且受预积分位移误差影响,拒绝交付 |
## 方法概览
```text
设备时间与惯性质量检查
→ 估计或确认两传感器时间关系
→ 雷达关键帧配准得到相对运动
→ 同一时间区间的 IMU 预积分得到相对运动
→ 先求旋转手眼关系
→ 只有平移可观时才进入完整六自由度优化
```
对关键帧区间 `[i, j]`
```text
A_ij ≈ IMU 预积分相对运动
B_ij ≈ 雷达点云配准相对运动
A_ij · X ≈ X · B_ij
X = T_IMU_lidar
```
旋转子问题为 `R_A · R_X = R_X · R_B`。旋转通常比平移稳定:加速度偏置和重力方向的微小误差会在位移积分中快速累积,平面转弯又难以提供竖直杆臂信息。因此,完整六自由度只有在残差、跨会话一致性和可观性同时通过时才允许输出。
## 当前实车结果与限制
当前可用的三段优先窗口均在主机时间桥接后固定 `time_offset_s=0`,并禁用自由的有符号时间精修:
| 会话窗口 | roll / pitch / yaw(°) | 手眼旋转 RMS(°) |
| --- | --- | ---: |
| `priority_174005_174515` | `-0.398 / 0.108 / 89.998` | 0.625 |
| `priority_174905_175450` | `-0.316 / -0.352 / 90.002` | 0.293 |
| `priority_175910_180530` | `-0.373 / -0.036 / 90.005` | 0.786 |
三段旋转相互差约为 `0.15°–0.47°`。但以下问题阻止平移放行:
1. IMU 预积分的位移,尤其竖直分量,会出现米级甚至更大的漂移;它不能作为可靠平移观测。
2. 当前重点会话以平面转弯为主,缺少持续坡道或俯仰激励,竖直平移弱可观。
3. 允许时间偏移自由精修时,时间与旋转曾发生相互补偿,产生跨窗口矛盾的航向。因此桥接后的偏移固定为零,而不是再次为降低残差调整它。
4. 单一窗口残差小不等于外参正确;必须检查跨窗口一致性与点云叠加。
这也是仓库增加 RTK–IMU 流程的原因:不是替代雷达旋转标定,而是为天线相位中心到 IMU 的平移提供更直接的 GNSS 位置和速度观测。两条流程边界见仓库 [README](../README.md)。
## 输入、输出与配置
### 输入
```text
imu.csv
t,gx,gy,gz,ax,ay,az
单位:秒、rad/s、m/s²;t 应为设备时间
lidar_session/
frames_index.csv 帧编号、文件名、开始/结束时间
frames/frame_XXXXX.npz 米制 XYZ 点云
vehicle_installation.yaml
坐标轴、时间语义、可选机械安装信息
```
原始 HI13 IMU `.rscap` 和 H32 雷达 dlog/MSOP 可转换为上述格式:
```powershell
python tools\export_rscap_to_v1.py `
--imu-rscap path\to\hi13-imu.rscap `
--imu-kind hi13 `
--lidar-dlog path\to\session_or_recovered.zip `
--host-start 2026-08-08T17:40:05 `
--host-end 2026-08-08T17:45:15 `
--out path\to\session_v1 `
--require-difop
```
### 输出
| 文件 | 含义 |
| --- | --- |
| `T_IMU_lidar.json` | 通过验收时的外参;仅旋转模式下不能把其中平移当交付值 |
| `time_offset.json` | 定义为 `t_imu = t_lidar + δt` 的时间关系 |
| `summary.json` | 状态、残差、可观性和拒绝原因 |
| `motion_pairs.json` | 用于复核和点云可视化的相对运动对 |
## 运行与判读
安装依赖:
```powershell
python -m pip install -e ".[dev]"
python -m pip install -e ".[open3d]" # 点云处理需要时安装
```
先运行仅旋转模式:
```powershell
python -m imu_lidar.cli run `
--vehicle-config config\vehicle_installation.template.yaml `
--imu path\to\session_v1\imu.csv `
--lidar path\to\session_v1\lidar `
--output path\to\out `
--mode rotation_only `
--time-offset-search-s 2.0
```
| `summary.json` 状态 | 含义 |
| --- | --- |
| `rotation_only_accepted` | 旋转与时间关系可进入独立验证;不代表平移可用 |
| `full_se3_accepted` | 仅当完整平移可观且门禁通过时,才可交付完整外参 |
| `full_se3_rejected_due_to_observability` | 旋转可用,平移拒绝 |
| `blocked` | 时间、质量或模型门禁失败,不能作安装参数 |
合成复现可验证软件链路,不证明实车精度:
```powershell
powershell -File tools\reproduce_synthetic.ps1
python -m pytest -q
```
## 采集要求
单次有效会话建议:
```text
静止 20–30 s → 连续低速多方向转弯 3–8 min → 静止 1020 s
```
- 必须保留雷达和 IMU 的设备时间戳;不能仅依赖主机接收时间。
- 在结构化环境采集,保证点云配准具有稳定几何约束。
- 旋转标定优先包含左右圆或“8”字;直线加减速有助于时间和水平平移。
- 若要尝试完整平移,增加连续缓坡、俯仰或其他竖直激励;仅平面运动通常不足。
- 标定全过程不得改变两传感器安装关系。
## 代码结构
`imu_lidar/` 是雷达–IMU 专用实现:
| 组件 | 作用 |
| --- | --- |
| `cli.py``pipeline.py` | 命令行入口与流程编排 |
| `lidar_io.py``registration.py``keyframes.py` | 点云读取、配准和关键帧 |
| `timestamp_audit.py``imu_audit.py``time_offset.py` | 时间和 IMU 质量检查、时间关系估计 |
| `imu_preintegration.py``motion_pairs.py` | IMU 预积分与相对运动对 |
| `rotation_handeye.py``joint_optimizer.py``observability.py` | 旋转求解、联合优化和可观性门禁 |
| `finalize.py` | 结果写出 |
历史改动见 [imu_lidar/CHANGELOG.md](../imu_lidar/CHANGELOG.md),自动化测试说明见 [tests/README.md](../tests/README.md)。
+4 -4
View File
@@ -103,7 +103,7 @@
- **原本**:对外说明仍偶发「方案二」等旧称呼;根 README 缺少一眼可读的阶段 / 合成 vs 旧车 / 合格数据预期;烟测配置与对比脚本文件名带 `scheme2`
- **改成**
-`[README.md](../README.md)` 增加 §0「现状一览」;明确仓库只有一条连续运动标定路径。
- `[tests/README.md](../tests/README.md)``[docs/IMU-LiDAR标定.md](../docs/IMU-LiDAR标定.md)`、本目录说明同步边界与阶段。
- `[tests/README.md](../tests/README.md)``[docs/雷达-IMU标定.md](../docs/雷达-IMU标定.md)`、本目录说明同步边界与阶段。
- `config/s2_old_smoke.yaml``tools/compare_s2_runs.py` 替换旧 `*scheme2*` 命名。
---
@@ -131,7 +131,7 @@
### 文档同步 + 合成数据一键复现
- **原本**`docs/标定流程与采集清单.md` 仍偏旧版「待写代码 / 因子图设想」;根 README 缺少清晰的一键复现入口与输入输出总表。
- **原本**采集与流程说明仍偏旧版「待写代码 / 因子图设想」;根 README 缺少清晰的一键复现入口与输入输出总表。
- **改成**
- 采集清单与现行流水线对齐(完整预积分、δt↔R 交替、可观时再估平移)。
- 新增 `tools/reproduce_synthetic.py` / `.ps1``tools/show_calibration_report.py`;合成生成写入 `meta.json`;根 README 增加「系统输入输出 + 一键复现」。
@@ -148,8 +148,8 @@
- **原本**:根 README / `docs` / 包说明仍对照已删除的静站路径与内部阶段黑话;`pyproject` 仍声明已删除的 `static_station` 包。
- **改成**
- 删除旧静站文档;采集清单定为 `[docs/标定流程与采集清单.md](../docs/标定流程与采集清单.md)`
-`[README.md](../README.md)``[docs/IMU-LiDAR标定.md](../docs/IMU-LiDAR标定.md)`、本目录说明改为对外可读,只保留连续运动标定路径。
- 删除旧静站文档;采集清单并入规范说明
-`[README.md](../README.md)``[docs/雷达-IMU标定.md](../docs/雷达-IMU标定.md)`、本目录说明改为对外可读,只保留连续运动标定路径。
- `pyproject.toml` 仅保留 `imu_lidar` / `tools`
---
-82
View File
@@ -1,82 +0,0 @@
# `imu_lidar` 模块说明
**用途:**`imu_lidar/` 源码时查阅。对外用法见根目录 [`README.md`](../README.md)。
本包实现 LiDAR–IMU 外参标定:在连续行驶数据上选取关键帧,用 IMU 预积分与雷达配准构造相对运动对,求解安装外参。
```text
A ≈ 关键帧间 IMU 相对运动(预积分:旋转 / 速度增量 / 位移增量)
B ≈ 关键帧间雷达配准
解 R_A R_X = R_X R_B → 旋转外参(手眼阶段只用旋转)
再精修旋转与陀螺零偏;在完整六自由度模式下,可观时再估计平移等
```
入口:
```powershell
python -m imu_lidar.cli plan
python -m imu_lidar.cli run --vehicle-config ... --imu ... --lidar ... --output ...
```
整体流程由 `pipeline.py` 串联。
修改本目录代码时,请同步更新本说明,并在 [`CHANGELOG.md`](CHANGELOG.md) 追加「时间戳 + 原本 → 改成」。
---
## 流水线顺序与文件
| 顺序 | 文件 | 作用 |
| --- | ----------------------- | ----------------------------- |
| 0 | `contracts.py` | 公共数据类型与状态枚举 |
| 0 | `geometry.py` | 刚体变换与旋转工具 |
| 0 | `vehicle_config.py` | 读取并校验车辆 YAML |
| 1 | `imu_io.py` | 读标准 IMU 中间格式 |
| 1 | `lidar_io.py` | 读标准雷达会话目录 |
| 2 | `timestamp_audit.py` | 时间单调 / 频率 / 空洞检查 |
| 3 | `imu_audit.py` | 静止零偏、加速度模长检查、建议竖直轴 |
| 4 | `time_offset.py` | 粗估时间偏置 δt,并用旋转外参精修 |
| 5 | `registration.py` | 帧间点云配准 |
| 5 | `keyframes.py` | 按运动量抽取关键帧 |
| 5 | `lidar_deskew.py` | 可选点云去畸变(低速可关) |
| 6 | `imu_preintegration.py` | IMU 预积分(旋转及速度/位移增量、协方差、零偏雅可比) |
| 6 | `motion_pairs.py` | 构造运动对;手眼使用其中的旋转 |
| 6 | `motion_pairs_io.py` | 运动对 JSON 缓存读写(供可视化直读) |
| 7 | `rotation_handeye.py` | 加权旋转手眼 |
| 8 | `observability.py` | 旋转 / 平移可观性检查 |
| 8 | `joint_optimizer.py` | 联合精修;完整模式下可估计平移、重力、速度与时变零偏 |
| 9 | `finalize.py` | 写出结果 JSON(含 `motion_pairs.json` |
| — | `pipeline.py` | 编排全流程 |
| — | `cli.py` | 命令行入口 |
| — | `CHANGELOG.md` | 改动记录 |
---
## 运行模式要点
- **运动对**始终计算完整预积分量(旋转、速度增量、位移增量及不确定度)。
- `--mode rotation_only`:只精修旋转与常值陀螺零偏,交付旋转与时间偏置。
- `--mode full_se3`:当前完成 Phase-A 后明确拒绝平移;待 Phase-B/C 会话状态重构完成后再恢复完整 SE(3) 交付。
---
## 输入格式
```text
imu.csv # t,gx,gy,gz,ax,ay,az(建议设备时间)
lidar_session/
frames_index.csv # frame_id,filename,t_start,t_end
frames/frame_XXXXX.npz # points: (N,3) 米
```
原始 N300 `.rscap` + H32 dlog(或旧 MSOP `.rscap`)用仓库工具导出:`python tools/export_rscap_to_v1.py ...`(见 [`docs/V1_数据格式.md`](../docs/V1_数据格式.md))。
---
## 当前能力
- 本包是仓库**唯一**标定路径:质检 → 时间偏置 → 关键帧配对 → 旋转手眼 → 联合精修 →(可选)完整六自由度 → 报告
- 点云去畸变:可选
- 阶段与用法见根目录 [`README.md`](../README.md)
- 改动史:[`CHANGELOG.md`](CHANGELOG.md)
-13
View File
@@ -1,13 +0,0 @@
# RTK-IMU Calibration Package
`rtk_imu/` contains the independent RTK-IMU calibration pipeline: G90 observation I/O, antenna-baseline rotation, V1 replay, V3 multisource stages, engineering 6DoF, and the node-state factor graph.
## Boundary
This package may import only shared `imu_lidar` utilities: `contracts`, `geometry`, `geodesy`, `imu_io`, `imu_preintegration`, and the generic `rotation_handeye` initializer.
It must not import LiDAR-specific modules such as `lidar_io`, `lidar_deskew`, `registration`, `pipeline`, `phase_a`, or `joint_optimizer`. The LiDAR-IMU pipeline remains in `imu_lidar/`.
## Entrypoints
Use `tools/run_rtk_imu_*.py` and `tools/audit_rtk_imu_*.py`; these scripts import from `rtk_imu.*`.
For the engineering procedure, current result, acceptance boundary, and reproduction commands, see [`README_RTK_IMU.md`](../README_RTK_IMU.md).