3、传感器基础:传感器类型概览、传感器Attachment规则、传感器Transform设置、传感器回调函数
好,咱们进入第三节。传感器这块,是自动驾驶仿真的「眼睛」和「耳朵」。没有传感器,车就是个瞎子。我在做项目时,经常看到新手一上来就堆传感器,结果数据乱成一锅粥。今天咱们就把传感器的基础打扎实。
3.1 传感器类型概览
Carla 里内置了十几种传感器。我按用途分了三类,你记一下:
- 视觉类:RGB相机、深度相机、语义分割相机、DVS事件相机
- 测距类:LIDAR(激光雷达)、RADAR(毫米波雷达)
- 状态类:GNSS(全球定位)、IMU(惯性测量单元)、速度计、碰撞检测器
我个人习惯,做城市道路场景时,至少配一套「前视RGB + 64线LIDAR + GNSS/IMU」。为什么?RGB看语义,LIDAR看距离,GNSS/IMU给位姿。三样凑齐,大部分算法都能跑。
小提示:DVS事件相机适合高速运动场景,但数据格式特殊,处理起来比较麻烦。新手可以先跳过。
3.2 传感器Attachment规则
传感器怎么「贴」到车上?Carla 提供了两种附着方式:
| 附着类型 | 说明 | 适用场景 |
|---|---|---|
AttachmentType.Rigid |
刚性附着,传感器与车体完全固定 | LIDAR、RADAR、相机(需要绝对稳定) |
AttachmentType.SpringArm |
弹簧臂附着,带缓冲效果 | 第三人称视角、跟拍相机 |
嗯,这里要注意:Rigid 是默认选项。SpringArm 我一般只用在调试视角上,不会用在正式数据采集里。为什么?因为弹簧臂会引入额外的运动延迟,你想想看,LIDAR 点云如果带了这个延迟,标定就全乱了。
避坑指南:我曾经在采集数据时,把LIDAR设成了SpringArm附着。结果点云和图像对不上,折腾了两天才发现是附着类型的问题。所以,量产数据采集,一律用Rigid。
3.3 传感器Transform设置
Transform 就是传感器的位置和朝向。说白了,就是告诉 Carla:「这个相机装在车顶哪个位置?朝哪个方向看?」
设置方式很简单:
# 创建一个相机,装在车顶前方
camera_bp = blueprint_library.find('sensor.camera.rgb')
camera_transform = carla.Transform(
carla.Location(x=1.5, z=2.4), # 车前方1.5米,高度2.4米
carla.Rotation(pitch=-15.0) # 向下倾斜15度
)
camera = world.spawn_actor(camera_bp, camera_transform, attach_to=vehicle)
这里有几个关键点:
- 坐标系:x向前,y向左,z向上。这是UE4的左手系,别搞反了。
- Rotation:pitch是俯仰(正数向上),yaw是偏航(正数向左转),roll是翻滚。
- 相对位置:Transform是相对于父级(车辆)的。车动了,传感器跟着动。
我建议你画个草图。把车看成一个长方体,传感器装在哪个角,坐标就是多少。我在项目中遇到过,有人把LIDAR的z设成了负数,结果传感器埋到地底下去了,啥也扫不到。
经验之谈:LIDAR一般装在车顶中心,z=2.0~2.5米。前视相机装在挡风玻璃后面,x=1.2~1.8米,z=1.2~1.5米。这个范围基本覆盖了大多数乘用车。
3.4 传感器回调函数
回调函数,是传感器数据流的「水龙头」。传感器每生成一帧数据,就会调用你注册的函数。你在这个函数里处理数据、保存数据、或者做可视化。
基本写法:
def process_image(image):
# image 是 sensor data 对象
array = np.frombuffer(image.raw_data, dtype=np.dtype("uint8"))
array = np.reshape(array, (image.height, image.width, 4))
# 去掉alpha通道
array = array[:, :, :3]
# 保存或处理
cv2.imwrite(f"frame_{image.frame}.png", array)
# 注册回调
camera.listen(process_image)
注意几个细节:
- 数据类型:不同传感器返回的数据类型不同。RGB返回
carla.Image,LIDAR返回carla.LidarMeasurement,GNSS返回carla.GNSSMeasurement。 - 帧率:回调函数会被频繁调用。如果你的处理逻辑太慢,会造成数据堆积。我一般会在回调里只做「轻量处理」,比如格式转换,然后丢到队列里,另起线程做保存。
- 线程安全:回调是在独立线程里跑的。如果你要更新UI或者写文件,记得加锁。
小技巧:可以用
image.save_to_disk()直接保存,但我不推荐。因为它的保存路径和命名规则不够灵活。自己写个保存函数,可控性更强。
好了,传感器基础就这些。说白了就是三件事:选对类型、贴对位置、接对回调。下一节咱们会深入讲RGB相机的具体配置,包括分辨率、FOV、曝光等参数。到时候你会看到,同样的场景,参数不同,拍出来的图天差地别。