相机与 IMU 差 4ms:先查时间戳语义,不要先怪 MCU
在相机-IMU 标定或 VIO 日志中看到固定几毫秒偏差,很容易把问题归到 PX4 或串口同步。更常见的情况是:两条链路记录的根本不是同一个物理时刻。
先画出时间语义
IMU 常见时间点:
text
真实采样 → sensor sample timestamp → PX4 timestamp_sample
→ timesync 映射 → ROS header.stamp → callback receipt相机常见时间点:
text
trigger → 曝光开始/中心/结束 → sensor/driver PTS
→ userspace timestamp → ROS header.stamp → callback receipt如果 IMU 使用 sample time,而相机使用帧完成或 dequeue 时间,两者稳定相差几毫秒并不奇怪。
第一步:判断是不是整帧错位
先用频率做 sanity check。假设相机触发为 20 Hz:
text
一帧周期 = 1 / 20 s = 50 ms如果 sequence 真错了一帧,误差量级更接近 50 ms。观测只有 4 ms 或 9 ms,通常更像曝光/PTS 定义、驱动延迟或消费者内部时间修正,而不是整帧 sequence slip。
第二步:确认同步链本身是否稳定
查看:
has_sync是否持续成立;- raw offset 与 filtered offset 的抖动;
- IMU 消息率是否稳定;
- PPS / trigger sequence 是否连续;
- 串口是否存在第二个 reader 抢数据。
如果同步 offset 的 jitter 只有数百微秒,而偏差稳定在数毫秒,继续调同步滤波通常不会解决根因。
第三步:追相机 PTS 的定义
需要确认驱动给出的 PTS 对应:
- 外部 trigger 到达;
- 曝光开始;
- 曝光中心;
- 曝光结束;
- ISP 完成;
- buffer dequeue。
对 VIO 来说,通常希望使用与成像物理时刻相关的 timestamp,而不是用户态收到 buffer 的时间。若使用外部 CAMERA_TRIGGER,还要把 trigger sequence 与 frame sequence 持续绑定,不能只在启动时对齐一次。
第四步:检查 VINS 是否又估了一次 td
即使 ROS camera stamp 已经直接使用 trigger time,VINS 配置仍可能启用 estimate_td 并维护非零 td:
text
image_time_used_by_vins = image_stamp + td此时标定或优化结果看到的 residual,不再只反映消息 stamp 链路。排查时要同时查看运行时配置和日志,明确 td 是固定为 0、固定标定值,还是在线估计。
推荐排查顺序
- 用帧周期判断是否可能是 sequence slip;
- 验证 PPS/MAVLink offset 的稳定性;
- 对照 IMU sample time 与相机 PTS 的物理定义;
- 检查 trigger seq 到 frame seq 的对应;
- 检查 VINS
td/estimate_td; - 最后再讨论 MCU timestamp 生成逻辑。
这类问题的关键不是把所有 timestamp 都变成同一个数,而是让每个时间戳都明确回答:它代表哪个物理事件,属于哪个时钟域,经过了哪些转换。