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)
注意: IMU 的零偏和温漂在仿真里默认是 0。这太理想了。实际项目中,IMU 的噪声模型非常复杂。如果你要做高精度定位,建议自己加一个随机游走噪声模型。

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 知识体系总览

我把这五个传感器的核心信息整理成了一张图,方便你对照记忆:

其他传感器知识体系 CARLA 其他传感器 雷达 (Radar) GNSS IMU 碰撞检测 车道入侵检测 测距测速,雨雾天稳定 经纬度+海拔定位 加速度+角速度 碰撞事件触发 检测是否压线 核心思路:各传感器互补,融合使用效果最佳 雷达+GNSS+IMU 构成定位铁三角,碰撞+车道入侵保障安全

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+碰撞检测,这是最低配置。

好了,这一章的内容就到这。雷达、GNSS、IMU、碰撞检测、车道入侵,每个传感器都有自己的脾气。你多跑几次仿真,自然就摸透了。

可可精品资料库