4. 数据记录器(Recorder)入门
各位同学,今天我们来聊聊CARLA里一个特别实用的工具——Recorder模块。
说实话,我刚开始做自动驾驶仿真的时候,最头疼的问题就是:场景跑完了,但某个关键帧出了问题,想回放看看却无从下手。后来接触了CARLA的Recorder,才发现原来这么简单。说白了,它就是仿真界的「行车记录仪」。
4.1 Recorder模块是什么?
CARLA的Recorder模块,是一个轻量级的录制与回放工具。它不记录传感器原始数据(比如摄像头图像、激光雷达点云),而是记录仿真世界中的状态变化。
什么意思呢?我举个例子:
- 哪辆车在什么时间出现在什么位置
- 它的速度、转向角、油门刹车状态
- 交通信号灯什么时候变红变绿
- 行人什么时候开始过马路
这些信息都被压缩成一个.log文件。你想想看,一个小时的复杂场景,可能也就几十MB。比起存原始传感器数据动辄几个GB,这效率高太多了。
核心概念:Recorder记录的是「世界状态」而非「传感器数据」。这意味着你可以用极小的存储代价,完整复现整个仿真场景。
4.2 开始录制:一行代码的事
启动录制非常简单。我个人习惯在场景初始化完成后,立刻调用录制接口。
import carla
# 连接CARLA服务器
client = carla.Client('localhost', 2000)
client.set_timeout(10.0)
# 开始录制,指定文件名
client.start_recorder('my_scene.log')
# 你的仿真逻辑...
# 跑场景、控制车辆、触发事件等
# 停止录制
client.stop_recorder()
嗯,这里要注意:start_recorder()的参数是文件名。如果你只写文件名,文件会保存在CARLA服务器的工作目录下。我建议你写绝对路径,这样好找。
我的小习惯:文件名里带上时间戳,比如scene_2024_03_15_14_30.log。这样后期整理时,一眼就知道是哪个场景、什么时候跑的。
4.3 录制文件(.log)的生成与存储路径
这个问题,我曾经踩过坑。第一次用Recorder时,我找了半天没找到.log文件在哪。
默认情况下,.log文件会生成在CARLA服务器进程的工作目录下。具体来说:
| 启动方式 | 默认存储路径 |
|---|---|
| 双击 CarlaUE4.exe | CarlaUE4.exe 所在的目录 |
| 命令行启动 | 执行命令时所在的目录 |
| Docker启动 | 容器内的工作目录(需映射卷) |
如果你想指定路径,直接写绝对路径就行:
# 指定到D盘某个文件夹
client.start_recorder('D:/carla_logs/scene_001.log')
# 或者用相对路径,但建议用绝对路径
client.start_recorder('./logs/scene_001.log')
避坑指南:我曾经在Windows上用相对路径,结果文件跑到了C盘用户目录下,找了半天。后来我统一用绝对路径,再也没丢过文件。
4.4 录制时的几个实用参数
start_recorder()其实还有几个可选参数,我给大家列一下:
client.start_recorder(
'scene.log',
additional_data=False # 是否记录额外数据
)
- additional_data=False(默认):只记录基础状态,文件小,回放快
- additional_data=True:额外记录物理引擎的碰撞信息、车辆动力学参数等
我个人建议:调试阶段用True,方便排查问题;正式跑大规模场景时用False,省空间。
4.5 知识体系总览
下面这张图,是我自己整理的Recorder模块核心逻辑。你看完应该能明白整个录制流程:
从这张图你可以看到,整个录制流程其实就三步:客户端发起请求 → 服务器监听并序列化状态 → 写入.log文件。简单明了。
4.6 实战小贴士
最后,分享几个我在项目中积累的经验:
- 录制前先检查磁盘空间:虽然.log文件不大,但长时间录制(比如几小时)还是会累积到几百MB。我一般会在录制前检查一下剩余空间。
- 命名规范很重要:我习惯用
场景名_日期_版本.log的格式。比如highway_overtake_20240315_v2.log。这样后期回放时,一眼就知道是哪个场景。 - 录制过程中不要频繁启停:每次
start_recorder和stop_recorder都会创建新文件。如果你需要分段录制,建议用不同的文件名。 - 多客户端场景注意:如果你同时运行多个Python客户端,每个客户端都可以独立录制。但要注意,它们录制的是同一个世界状态,文件内容会重复。我一般只让主控制客户端负责录制。
一个小技巧:你可以在录制的同时,用client.get_recorder_info()查看当前录制状态。如果返回空字符串,说明没在录制;如果返回文件名,说明正在录制中。