Files
calibration/README_RTK_IMU.md
T

10 KiB
Raw Blame History

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 位小数):
[[ 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=truerotation_sensitivity_passed=true:固定候选在 held-out 物理残差和旋转扰动中保持一致。

因此不得描述为“data-only 标定平移”或“动态数据已精确细化机械杆臂”。完整、机器可读的结论见 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),因此它不单独否决高动态杆臂敏感验证;但在传播模型根因关闭前,也不能把候选杆臂标为正式工程已放行。

主要审核证据:

如何复现

1. 准备环境和原始数据

cd <repository-root>
python -m pip install -e ".[dev]"

将三批 G90/HI13 原始 .rscap 会话放到本机的数据位置。数据位置不写入仓库;tools/export_rtk_imu_unified.py 中的会话配对清单必须与实际采集文件一致。

$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。

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 是本次审核所用选择结果,可用于对照。

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 排除。

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 或机械先验。

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 阶段重新拟合:

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"

相关文件