10 KiB
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。 - 固定旋转近似 RPY(X/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=true、rotation_sensitivity_passed=true:固定候选在 held-out 物理残差和旋转扰动中保持一致。
因此不得描述为“data-only 标定平移”或“动态数据已精确细化机械杆臂”。完整、机器可读的结论见 engineering_release_decision.json。
求解流程
- 统一原始数据导出。 使用 G90/HI13 设备时间作为主时间轴;host receive time 仅用于诊断。G90 保留 GGA 质量、GNHPR 基线及质量、BESTNAVA Doppler velocity,必要时 PVTSLNA;HI13 保留 system time、gyro、accel、姿态/四元数和 host receive time。
- R0 连续性与质量控制。 校验 checksum、RTK Fixed、设备时间单调性、IMU 覆盖、baseline jump 与测量间隔。轨迹连续性由 IMU 设备时间和预积分覆盖决定;孤立 HPR 缺失/Q5 只禁用或降权 HPR factor,不切断 IMU 轨迹。
- 旋转外参。 R1b 从基线与 IMU 动态估计 ANT1→ANT2 在 IMU 中的 2DoF 方向;R2V 用基线与高质量 Doppler 速度作独立诊断;R2G 使用水平静止场地中的基线+重力+地面水平先验补齐完整旋转。R2G 是本次正式固定旋转来源,旧 GNHPR 三轴手眼只作诊断。
- 节点状态图。 每个 GNSS node 包含
R,p,v,bg,ba的 15DoF 状态;相邻 node 由 covariance-whitened IMU preintegration 和 bias random walk 连接。BEST 约束 XYZ,GGA 仅在 BEST 缺失时约束 XY,Doppler 约束速度,HPR 是可选姿态/基线因子。 - 机械锚定的平移验证。 杆臂以机械值为基准,分别比较无先验 free、固定机械杆臂和软先验解。free 解只用于观测性诊断,不能因为数值收敛就替代机械值。
- 独立验证。 使用 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"