4. 传感器配置:相机传感器(RGB、深度、语义分割)、Lidar传感器、IMU/GNSS传感器
好了,咱们进入正题。传感器配置这块,说白了就是给自动驾驶车装上「眼睛」和「耳朵」。我在项目里见过不少同学,上来就堆传感器,结果数据对不上,跑起来全是坑。今天咱们一个一个捋清楚。
4.1 相机传感器:RGB、深度、语义分割
相机是感知系统的基础。Carla里相机分三种:RGB、深度、语义分割。它们共用一套配置接口,但输出数据完全不同。
4.1.1 RGB相机
RGB相机最直观,输出就是彩色图像。我个人习惯用1920x1080分辨率,帧率设20。太高了CPU扛不住,太低了感知算法会卡顿。
# 配置RGB相机
rgb_camera_bp = blueprint_library.find('sensor.camera.rgb')
rgb_camera_bp.set_attribute('image_size_x', '1920')
rgb_camera_bp.set_attribute('image_size_y', '1080')
rgb_camera_bp.set_attribute('fov', '90')
rgb_camera_bp.set_attribute('sensor_tick', '0.05') # 20fps
# 挂载到车辆上
rgb_camera = world.spawn_actor(
rgb_camera_bp,
transform.Transform(
location=Location(x=1.5, z=2.4),
rotation=Rotation(pitch=-15)
),
attach_to=vehicle
)
4.1.2 深度相机
深度相机输出的是每个像素到物体的距离。嗯,这里要注意:Carla的深度数据是归一化到[0,1]的,需要自己换算成实际米数。
# 深度相机配置
depth_camera_bp = blueprint_library.find('sensor.camera.depth')
depth_camera_bp.set_attribute('image_size_x', '640')
depth_camera_bp.set_attribute('image_size_y', '480')
depth_camera_bp.set_attribute('fov', '90')
# 深度数据回调处理
def process_depth(image):
# 将归一化深度转为实际距离(米)
depth_data = np.array(image.raw_data)[:, :, 0]
depth_in_meters = depth_data * 1000.0 # Carla默认最大1000米
# 或者用官方方法
depth_in_meters = image.convert_to_color_vector()
4.1.3 语义分割相机
语义分割相机输出的是每个像素的标签ID。Carla内置了23个类别,比如道路、车辆、行人、建筑等。这个在训练感知模型时特别好用,相当于有了「标准答案」。
# 语义分割相机
seg_camera_bp = blueprint_library.find('sensor.camera.semantic_segmentation')
seg_camera_bp.set_attribute('image_size_x', '1280')
seg_camera_bp.set_attribute('image_size_y', '720')
# 标签映射表(部分)
LABEL_MAP = {
0: 'Unlabeled',
1: 'Road',
2: 'Sidewalk',
3: 'Building',
4: 'Wall',
5: 'Fence',
6: 'Pole',
7: 'TrafficLight',
8: 'TrafficSign',
9: 'Vegetation',
10: 'Terrain',
11: 'Sky',
12: 'Pedestrian',
13: 'Rider',
14: 'Car',
15: 'Truck',
16: 'Bus',
17: 'Train',
18: 'Motorcycle',
19: 'Bicycle',
20: 'Static',
21: 'Dynamic',
22: 'Other'
}
核心要点:三种相机可以同时挂载,互不干扰。但要注意CPU/GPU负载。我建议:训练时开全三种,测试时只开RGB和深度,节省资源。
4.2 Lidar传感器
Lidar是自动驾驶的「硬核」传感器。Carla支持多种Lidar模型,最常用的是32线和64线旋转式激光雷达。
4.2.1 基本配置
# 配置64线Lidar
lidar_bp = blueprint_library.find('sensor.lidar.ray_cast')
lidar_bp.set_attribute('channels', '64') # 线数
lidar_bp.set_attribute('range', '100') # 探测距离(米)
lidar_bp.set_attribute('points_per_second', '1000000') # 每秒点数
lidar_bp.set_attribute('rotation_frequency', '20') # 旋转频率(Hz)
lidar_bp.set_attribute('upper_fov', '15') # 上视角
lidar_bp.set_attribute('lower_fov', '-25') # 下视角
# 挂载到车顶中心
lidar = world.spawn_actor(
lidar_bp,
transform.Transform(
location=Location(x=0.0, z=2.5)
),
attach_to=vehicle
)
为什么选64线?说实话,32线也能用,但点云稀疏,远距离物体容易漏检。我在做高速场景测试时,64线明显更稳。当然,如果你只是做园区低速场景,32线完全够用。
4.2.2 点云数据处理
def process_lidar_data(point_cloud):
# 获取点云坐标(x, y, z)
points = np.frombuffer(point_cloud.raw_data, dtype=np.dtype('f4'))
points = np.reshape(points, (int(points.shape[0] / 4), 4))
# 过滤掉地面点(z < -1.5)
ground_mask = points[:, 2] > -1.5
filtered_points = points[ground_mask]
# 转换为Open3D格式可视化
import open3d as o3d
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(filtered_points[:, :3])
return pcd
4.3 IMU/GNSS传感器
IMU和GNSS是定位系统的核心。IMU提供加速度和角速度,GNSS提供经纬度坐标。两者配合使用,才能实现高精度定位。
4.3.1 IMU配置
# IMU传感器
imu_bp = blueprint_library.find('sensor.other.imu')
imu_bp.set_attribute('sensor_tick', '0.01') # 100Hz采样
imu = world.spawn_actor(
imu_bp,
transform.Transform(
location=Location(x=0.0, z=0.0) # 放在车辆质心
),
attach_to=vehicle
)
# IMU数据回调
def process_imu(data):
# 加速度(m/s²)
accel = data.accelerometer
# 角速度(rad/s)
gyro = data.gyroscope
# 朝向(四元数)
compass = data.compass
print(f"加速度: ({accel.x:.2f}, {accel.y:.2f}, {accel.z:.2f})")
4.3.2 GNSS配置
# GNSS传感器
gnss_bp = blueprint_library.find('sensor.other.gnss')
gnss_bp.set_attribute('sensor_tick', '1.0') # 1Hz更新
gnss_bp.set_attribute('noise_alt', '0.0') # 高度噪声
gnss_bp.set_attribute('noise_lat', '0.0') # 纬度噪声
gnss_bp.set_attribute('noise_lon', '0.0') # 经度噪声
gnss = world.spawn_actor(
gnss_bp,
transform.Transform(
location=Location(x=0.0, z=0.0)
),
attach_to=vehicle
)
# GNSS数据回调
def process_gnss(data):
lat = data.latitude
lon = data.longitude
alt = data.altitude
print(f"位置: ({lat:.6f}, {lon:.6f}, {alt:.2f}m)")
GNSS默认不带噪声,但你可以手动开启。我建议做仿真时加一点噪声,这样更接近真实情况。不过要注意,Carla的GNSS坐标是基于UE4世界的,不是真实经纬度。
4.4 传感器同步与时间戳
多传感器协同工作时,时间同步是个大问题。Carla提供了两种模式:固定时间步和异步模式。
# 设置固定时间步(推荐)
settings = world.get_settings()
settings.fixed_delta_seconds = 0.05 # 20fps
settings.synchronous_mode = True
world.apply_settings(settings)
# 同步模式下,所有传感器在同一时刻触发
world.tick() # 推进一帧
最佳实践:我强烈建议使用同步模式。异步模式下,相机和Lidar的时间戳可能差几十毫秒,这对融合算法是致命的。同步模式虽然慢一点,但数据对齐可靠。
4.5 传感器配置总结
| 传感器类型 | 推荐配置 | 输出频率 | 数据量 | 典型用途 |
|---|---|---|---|---|
| RGB相机 | 1920x1080, FOV 90° | 20fps | 中等 | 目标检测、车道线识别 |
| 深度相机 | 640x480, FOV 90° | 20fps | 低 | 距离估计、避障 |
| 语义分割 | 1280x720 | 20fps | 中等 | 训练数据生成 |
| Lidar | 64线, 100m范围 | 20Hz | 高 | 3D感知、建图 |
| IMU | 100Hz采样 | 100Hz | 极低 | 位姿估计 |
| GNSS | 1Hz更新 | 1Hz | 极低 | 全局定位 |
最后说一句:传感器配置没有「最好」,只有「最合适」。你想想看,做园区低速配送,32线Lidar加两个RGB相机就够了。但要做高速自动驾驶,64线Lidar加环视相机是标配。我在项目里一般先按「够用」配置,跑通后再根据需求增减。这样既不会浪费资源,也不会漏掉关键数据。
我的习惯:每次配置新传感器,我都会先跑一个「数据采集测试」,看看输出格式、频率、数据范围是否正常。这一步花不了10分钟,但能避免后面调试时抓狂。