4. 其他传感器
好,咱们继续往下走。前面聊了相机和激光雷达,这两个是自动驾驶感知的「主力」。但光靠它们还不够,就像你开车不能只用眼睛看,还得有耳朵听、有身体感知颠簸,甚至得知道自己在哪条路上。
这一章,我把剩下的几个常用传感器一次性讲清楚。它们各自分工明确,有的负责测距,有的负责定位,有的负责「出事了赶紧上报」。嗯,咱们一个一个来。
4.1 雷达(Radar)—— 雨雾天的「硬汉」
雷达这东西,说白了就是靠发射电磁波并接收回波来测距测速。它不像激光雷达那样精细,但胜在稳定。我在项目中遇到过几次大雾天,激光雷达基本废了,但雷达依然坚挺。
CARLA 里的雷达传感器模拟得还挺像回事。它会返回一组点,每个点包含距离、方位角、仰角、速度等信息。
4.1.1 配置雷达
先看怎么挂载一个雷达:
blueprint = world.get_blueprint_library().find('sensor.other.radar')
blueprint.set_attribute('range', '50') # 探测距离 50 米
blueprint.set_attribute('horizontal_fov', '30') # 水平视场角 30 度
blueprint.set_attribute('vertical_fov', '10') # 垂直视场角 10 度
blueprint.set_attribute('points_per_second', '1500') # 每秒采样点数
radar = world.spawn_actor(blueprint, transform, attach_to=vehicle)
这里有个坑,我提醒一下:points_per_second 这个值别设太大。我曾经设成 10000,结果一跑起来 CPU 直接飙满。你想想看,每秒一万个点,每个点还要做数据处理,计算量不小。
4.1.2 雷达数据回调
雷达的数据回调长这样:
def on_radar_data(radar_data):
for detection in radar_data:
# detection 包含:
# depth —— 距离(米)
# azimuth —— 水平角(弧度)
# altitude —— 仰角(弧度)
# velocity —— 相对速度(米/秒)
print(f"距离: {detection.depth:.2f}m, 速度: {detection.velocity:.2f}m/s")
radar.listen(on_radar_data)
我个人习惯把雷达数据转成点云格式,和激光雷达的数据结构统一,这样下游处理模块就不用写两套代码了。
4.2 GNSS —— 我在哪?
GNSS 就是全球导航卫星系统,咱们平时说的 GPS 是它的一种。在 CARLA 里,GNSS 传感器直接返回经纬度和海拔高度。
配置很简单:
blueprint = world.get_blueprint_library().find('sensor.other.gnss')
blueprint.set_attribute('noise_alt_stddev', '0.5') # 高度噪声标准差
blueprint.set_attribute('noise_lat_stddev', '0.001') # 纬度噪声
blueprint.set_attribute('noise_lon_stddev', '0.001') # 经度噪声
gnss = world.spawn_actor(blueprint, transform, attach_to=vehicle)
数据回调:
def on_gnss_data(gnss_data):
print(f"纬度: {gnss_data.latitude:.6f}")
print(f"经度: {gnss_data.longitude:.6f}")
print(f"海拔: {gnss_data.altitude:.2f}m")
gnss.listen(on_gnss_data)
注意,仿真里的 GNSS 默认是理想情况。实际中,城市峡谷、隧道都会导致信号丢失。我建议你故意把噪声调大一点,模拟真实场景。不然算法在仿真里跑得飞起,一上路就懵了。
4.3 IMU —— 车身的「平衡感」
IMU 包含加速度计和陀螺仪。它告诉你车在怎么加速、怎么转弯。说实话,IMU 的数据单独看没啥意义,但和 GNSS 一融合,就能得到高精度的定位。
配置:
blueprint = world.get_blueprint_library().find('sensor.other.imu')
blueprint.set_attribute('noise_accel_stddev_x', '0.01')
blueprint.set_attribute('noise_accel_stddev_y', '0.01')
blueprint.set_attribute('noise_gyro_stddev_x', '0.001')
blueprint.set_attribute('noise_gyro_stddev_y', '0.001')
blueprint.set_attribute('noise_gyro_stddev_z', '0.001')
imu = world.spawn_actor(blueprint, transform, attach_to=vehicle)
数据回调:
def on_imu_data(imu_data):
# 加速度(m/s²)
accel = imu_data.accelerometer
# 角速度(rad/s)
gyro = imu_data.gyroscope
# 朝向(四元数)
compass = imu_data.compass
print(f"加速度: x={accel.x:.2f}, y={accel.y:.2f}, z={accel.z:.2f}")
imu.listen(on_imu_data)
4.4 碰撞检测传感器 —— 安全底线
这个传感器不用于感知环境,它就是个「事件触发器」。一旦车辆发生碰撞,它就发出信号。
配置:
blueprint = world.get_blueprint_library().find('sensor.other.collision')
collision_sensor = world.spawn_actor(blueprint, transform, attach_to=vehicle)
回调:
def on_collision(event):
# event.actor —— 撞到的东西
# event.other_actor —— 被撞的东西
# event.normal_impulse —— 碰撞冲量
impulse = event.normal_impulse
print(f"碰撞!冲量: x={impulse.x:.2f}, y={impulse.y:.2f}, z={impulse.z:.2f}")
collision_sensor.listen(on_collision)
这个传感器我一般在测试自动驾驶策略时必挂。一旦碰撞发生,立即终止当前场景并记录日志。我曾经有一次调试泊车算法,碰撞传感器响了十几次我才发现是标定参数写反了……嗯,都是泪。
4.5 车道入侵检测传感器 —— 越线报警
这个传感器专门检测车辆是否压线或侵入对向车道。它返回一个布尔值,告诉你当前是否「越界」。
配置:
blueprint = world.get_blueprint_library().find('sensor.other.lane_invasion')
lane_sensor = world.spawn_actor(blueprint, transform, attach_to=vehicle)
回调:
def on_lane_invasion(event):
# event.crossed_lane_markings —— 被压过的车道线列表
for marking in event.crossed_lane_markings:
print(f"压线了!车道类型: {marking.type}")
lane_sensor.listen(on_lane_invasion)
这个传感器在评估「车道保持」功能时特别有用。你可以统计整个测试过程中压线的次数和时长,作为评价指标。
4.6 知识体系总览
我把这五个传感器的核心信息整理成了一张图,方便你对照记忆:
4.7 综合配置示例
最后,我给你一个一次性挂载所有传感器的示例代码。这是我个人常用的模板:
def setup_all_sensors(vehicle):
sensors = []
world = vehicle.get_world()
bp_lib = world.get_blueprint_library()
# 雷达
radar_bp = bp_lib.find('sensor.other.radar')
radar_bp.set_attribute('range', '50')
radar_bp.set_attribute('points_per_second', '1500')
radar = world.spawn_actor(radar_bp, transform, attach_to=vehicle)
radar.listen(lambda data: process_radar(data))
sensors.append(radar)
# GNSS
gnss_bp = bp_lib.find('sensor.other.gnss')
gnss_bp.set_attribute('noise_lat_stddev', '0.001')
gnss = world.spawn_actor(gnss_bp, transform, attach_to=vehicle)
gnss.listen(lambda data: process_gnss(data))
sensors.append(gnss)
# IMU
imu_bp = bp_lib.find('sensor.other.imu')
imu = world.spawn_actor(imu_bp, transform, attach_to=vehicle)
imu.listen(lambda data: process_imu(data))
sensors.append(imu)
# 碰撞检测
col_bp = bp_lib.find('sensor.other.collision')
col = world.spawn_actor(col_bp, transform, attach_to=vehicle)
col.listen(lambda event: on_collision(event))
sensors.append(col)
# 车道入侵
lane_bp = bp_lib.find('sensor.other.lane_invasion')
lane = world.spawn_actor(lane_bp, transform, attach_to=vehicle)
lane.listen(lambda event: on_lane_invasion(event))
sensors.append(lane)
return sensors
好了,这一章的内容就到这。雷达、GNSS、IMU、碰撞检测、车道入侵,每个传感器都有自己的脾气。你多跑几次仿真,自然就摸透了。
可可精品资料库