3. 数据回放验证概述
做自动驾驶回放闭环,第一关就是跟数据格式打交道。你想想看,车上那么多传感器——激光雷达、摄像头、毫米波雷达、IMU……每毫秒都在产生数据。怎么存、怎么读、怎么对齐时间戳,直接决定了你后面回放能不能「复现」当时的场景。
我个人习惯把数据格式分成两类:通用交换格式(比如 Rosbag、NuScenes、KITTI)和内部定制格式。今天咱们就把主流格式掰开揉碎聊一聊,再聊聊我自己设计自定义格式时踩过的坑。
3.1 Rosbag —— 最熟悉的“老朋友”
Rosbag 是 ROS 生态下的标准容器。说白了,它就是按时间顺序把 topic 消息一股脑儿塞进一个文件。我在项目中用过几百个 bag,最深的体会是:rosbag 的索引机制很轻量,但如果你录了 200GB 的 bag,想随机跳到第 37 分 12 秒?嗯,那加载速度会让你想砸键盘。
rosbag index 重建索引,回放时用 --clock 保持时间同步。
# 常用 rosbag 命令 (ROS1)
rosbag record -O my_scene.bag /camera/image_raw /lidar/points /imu/data
rosbag info my_scene.bag
rosbag play my_scene.bag --clock --rate 1.0
ROS2 的 bag 底层用了 SQLite3,元数据更丰富。我个人觉得 ROS2 bag 的随机访问比 ROS1 好不少,但跨版本兼容偶尔会出幺蛾子——我曾经因为 ROS2 的序列化 ID 不匹配,折腾了一下午才找到原因。
3.2 NuScenes 格式 —— 学术界的“标准答案”
NuScenes 数据集用的是 JSON + 二进制文件 的组合。它的核心是一张巨大的关系表:场景、样本、传感器、标注……全部用 token 关联。你想想看,这种设计对做算法训练非常友好,但直接拿来做回放?有点重。
我在做闭环验证时,曾经尝试把 NuScenes 格式直接喂给回放引擎。结果发现每次加载都要解析 JSON 并建立内存索引,启动时间比实际回放还长。后来我学乖了:只把 NuScenes 作为离线标注的中间格式,回放前转成更紧凑的二进制格式。
3.3 KITTI 格式 —— 简单粗暴,但够用
KITTI 的原始数据就是一堆 png + txt + calib 文件。每个文件夹代表一个“drive”,里面按时间戳命名。说实话,这种格式在 2012 年很前卫,但现在看,没有内聚的时间同步机制,全靠文件名里的毫秒数对齐。
我记得有一次用 KITTI 格式做回放,发现某个摄像头图像和激光雷达点云的时间戳差了 40 毫秒。查了半天,原来是文件系统拷贝时时间戳精度丢了。所以后来我只要用 KITTI 风格,一定会额外生成一个 timestamps.txt 并校验完整性。
3.4 自定义数据格式 —— 什么时候该自己造轮子?
你可能会问:有 Rosbag 和 NuScenes 为什么还要自己设计格式?我遇到过三种典型场景:
- 回放性能瓶颈: Rosbag 的序列化/反序列化开销大,高频传感器(如 128 线激光雷达 + 8 个摄像头)容易掉帧。
- 需要列式查询: 比如我只想回放所有“行人横穿马路”的场景,通用格式没法直接按语义过滤。
- 硬件在环(HIL)约束: 某些实时系统要求数据按微秒级时间片排列,且内存映射(mmap)友好。
下面是我目前在项目中使用的自定义格式骨架(简化版):
// 自定义回放格式 v2 (protobuf 风格描述)
message Frame {
uint64 timestamp_us = 1; // 全局时间戳
uint32 sensor_count = 2;
repeated SensorData sensors = 3;
optional bytes extra_meta = 4; // JSON 元数据
}
message SensorData {
uint32 sensor_id = 1;
bytes raw_data = 2; // 按 sensor 类型编码
uint32 data_len = 3;
// 可扩展字段
}
实际落地时,我会用 FlatBuffers 或 Cap'n Proto 做序列化,零拷贝反序列化对回放性能太重要了。你想想看,每毫秒要反序列化几十个传感器消息,如果每个都拷贝一次内存,CPU 很快就扛不住了。
3.5 格式选型对比
| 特性 | Rosbag (ROS1) | NuScenes | KITTI | 自定义 (Protobuf/FlatBuffers) |
|---|---|---|---|---|
| 随机访问 | 慢 (需扫描) | 中等 (JSON 索引) | 差 (依赖文件名) | 快 (时间戳索引) |
| 序列化开销 | 中等 | 高 (JSON 解析) | 低 (原始文件) | 极低 (零拷贝) |
| 跨平台 | 依赖 ROS | 好 | 好 | 好 |
| 扩展性 | 一般 | 好 (schema 灵活) | 差 | 优秀 (预留字段) |
| 工具链 | 丰富 | 中等 | 少 | 需自研 |
我个人建议:原型阶段用 Rosbag 或 NuScenes,快速验证。进入量产回放 pipeline 后,逐步迁移到自定义格式。但不管选哪种,时间同步和坐标系一致性永远是第一位的。