别只当模拟器用!在Win11上玩转CARLA:手把手教你运行第一个自动驾驶脚本(Python API实战)

CARLA作为开源的自动驾驶仿真平台,其价值远不止于提供一个3D虚拟环境。许多用户在Windows11上完成安装后,面对虚幻引擎的界面却不知如何发挥其真正的潜力。本文将带你跳过基础操作,直接进入Python API的实战开发,从交互式控制到编写首个自动驾驶脚本,快速体验CARLA作为研究开发平台的核心功能。

1. 从手动控制到理解API架构

启动 manual_control.py 脚本后,你看到的不仅是一个可驾驶的虚拟世界,更是CARLA Python API的完整演示。这个位于 PythonAPI/examples 目录下的示例脚本,包含了传感器配置、车辆控制和数据采集等关键要素。

1.1 解剖manual_control.py的核心结构

打开脚本文件,你会发现几个关键组成部分:

# 世界和客户端设置
client = carla.Client('localhost', 2000)
world = client.get_world()

# 蓝图库和车辆生成
blueprint_library = world.get_blueprint_library()
vehicle_bp = blueprint_library.filter('model3')[0]
spawn_point = world.get_map().get_spawn_points()[0]
vehicle = world.spawn_actor(vehicle_bp, spawn_point)

这段代码展示了CARLA最基本的三个层次:

  1. Client层 :负责与服务器通信
  2. World层 :管理当前仿真环境状态
  3. Actor层 :控制具体的车辆、传感器等对象

提示:修改 filter('model3') 中的车型名称可以更换不同车辆,可用车型列表可通过 blueprint_library.filter('vehicle.*') 获取。

1.2 实时修改环境参数

在脚本运行过程中,你可以通过按键直接修改环境条件:

按键 功能 API对应方法
T 切换天气 world.set_weather()
G 切换地图图层 world.load_map_layer()
B 切换蓝图属性 actor.set_attribute()

尝试在脚本中找到这些按键处理逻辑,理解它们如何通过API改变仿真环境。例如天气切换的实现:

weather_presets = [
    carla.WeatherParameters.ClearNoon,
    carla.WeatherParameters.CloudyNoon,
    carla.WeatherParameters.WetNoon
]
current_weather = 0

def toggle_weather():
    global current_weather
    current_weather = (current_weather + 1) % len(weather_presets)
    world.set_weather(weather_presets[current_weather])

2. 传感器配置与数据采集实战

CARLA的强大之处在于其丰富的传感器模拟能力。让我们为车辆添加一个摄像头传感器,并保存采集到的图像数据。

2.1 创建RGB摄像头

manual_control.py 中找到传感器设置部分,添加以下代码:

# 摄像头蓝图配置
camera_bp = blueprint_library.find('sensor.camera.rgb')
camera_bp.set_attribute('image_size_x', '800')
camera_bp.set_attribute('image_size_y', '600')
camera_bp.set_attribute('fov', '90')

# 设置摄像头相对位置
camera_transform = carla.Transform(carla.Location(x=1.5, z=2.4))

# 生成并绑定到车辆
camera = world.spawn_actor(camera_bp, camera_transform, attach_to=vehicle)

# 数据回调函数
def camera_callback(image):
    image.save_to_disk('output/%06d.png' % image.frame)

camera.listen(camera_callback)

2.2 理解传感器数据流

CARLA的传感器工作遵循异步回调机制:

  1. 传感器按固定频率采集数据
  2. 每次采集触发注册的回调函数
  3. 回调函数接收处理后的传感器数据

对于摄像头数据,主要包含以下信息:

  • 原始图像数据 :可通过 image.raw_data 获取
  • 时间戳 image.timestamp
  • 帧编号 image.frame
  • 转换矩阵 image.transform

注意:高频率的传感器数据可能成为性能瓶颈,建议根据需求调整传感器的 sensor_tick 参数控制更新频率。

3. 从手动控制到自动巡航

现在我们将修改手动控制脚本,实现一个简单的自动巡航功能。

3.1 基础自动控制逻辑

创建一个新的Python文件 autopilot.py ,包含以下核心功能:

import carla
import random

client = carla.Client('localhost', 2000)
world = client.get_world()

# 获取地图的推荐生成点
spawn_points = world.get_map().get_spawn_points()

# 生成车辆
vehicle_bp = world.get_blueprint_library().filter('vehicle.*')[0]
vehicle = world.spawn_actor(vehicle_bp, random.choice(spawn_points))

# 基础自动控制逻辑
def auto_control():
    control = carla.VehicleControl()
    control.throttle = 0.5
    control.steer = random.uniform(-0.1, 0.1)
    vehicle.apply_control(control)

# 每0.1秒执行一次控制
world.on_tick(lambda _: auto_control())

这个简单的脚本实现了:

  • 随机选择生成点放置车辆
  • 持续施加油门和随机小幅转向
  • 利用 world.on_tick 回调实现持续控制

3.2 添加基本的碰撞避免

增强自动巡航的安全性,添加激光雷达传感器和简单避障逻辑:

# 添加激光雷达
lidar_bp = blueprint_library.find('sensor.lidar.ray_cast')
lidar_bp.set_attribute('range', '20')
lidar = world.spawn_actor(lidar_bp, carla.Transform(), attach_to=vehicle)

obstacle_detected = False

def lidar_callback(point_cloud):
    global obstacle_detected
    # 转换点云数据为numpy数组
    points = np.frombuffer(point_cloud.raw_data, dtype=np.dtype('f4'))
    points = np.reshape(points, (int(points.shape[0]/4), 4))
    
    # 检查前方5米内是否有障碍物
    front_points = points[(points[:,0]>0) & (points[:,0]<5) & (abs(points[:,1])<2)]
    obstacle_detected = len(front_points) > 50

lidar.listen(lidar_callback)

def auto_control():
    control = carla.VehicleControl()
    
    if obstacle_detected:
        control.throttle = 0
        control.brake = 1.0
        control.steer = random.uniform(-0.5, 0.5)
    else:
        control.throttle = 0.5
        control.steer = random.uniform(-0.1, 0.1)
    
    vehicle.apply_control(control)

4. 构建完整的自动驾驶实验流程

现在我们将整合前面所学,创建一个完整的自动驾驶实验脚本,包含传感器套件、数据记录和简单决策逻辑。

4.1 多传感器配置方案

一个典型的自动驾驶研究需要以下传感器组合:

传感器类型 作用 推荐配置参数
RGB摄像头 场景识别 分辨率1920x1080,FOV 90°
语义分割摄像头 场景理解 与RGB摄像头同位置
激光雷达 3D环境感知 32线,范围50米
雷达 障碍物检测 水平角30°,垂直角15°
IMU 位姿估计 默认参数

配置代码示例:

def setup_sensors(vehicle):
    sensors = {}
    
    # 摄像头配置
    camera_bp = blueprint_library.find('sensor.camera.rgb')
    camera_bp.set_attribute('image_size_x', '1920')
    camera_bp.set_attribute('image_size_y', '1080')
    camera_transform = carla.Transform(carla.Location(x=1.5, z=2.4))
    sensors['rgb'] = world.spawn_actor(camera_bp, camera_transform, attach_to=vehicle)
    
    # 激光雷达配置
    lidar_bp = blueprint_library.find('sensor.lidar.ray_cast')
    lidar_bp.set_attribute('channels', '32')
    lidar_bp.set_attribute('range', '5000')
    lidar_transform = carla.Transform(carla.Location(z=2.5))
    sensors['lidar'] = world.spawn_actor(lidar_bp, lidar_transform, attach_to=vehicle)
    
    return sensors

4.2 数据同步与记录

多传感器数据同步是自动驾驶系统的关键挑战。CARLA提供了 SensorData 对象中的时间戳和帧编号来实现数据对齐:

from collections import defaultdict

sensor_data = defaultdict(dict)

def sensor_callback(sensor_type, sensor_data):
    def callback(data):
        sensor_data[data.frame][sensor_type] = data
    return callback

# 为每个传感器注册回调
sensors['rgb'].listen(sensor_callback('rgb', sensor_data))
sensors['lidar'].listen(sensor_callback('lidar', sensor_data))

# 同步检查线程
def check_synchronization():
    for frame in list(sensor_data.keys()):
        if 'rgb' in sensor_data[frame] and 'lidar' in sensor_data[frame]:
            # 处理同步数据
            process_frame_data(sensor_data[frame])
            del sensor_data[frame]

world.on_tick(lambda _: check_synchronization())

4.3 构建决策控制循环

基于感知数据的简单决策控制示例:

def decision_cycle(vehicle, sensor_readings):
    # 获取当前速度
    velocity = vehicle.get_velocity()
    speed = 3.6 * math.sqrt(velocity.x**2 + velocity.y**2 + velocity.z**2)  # km/h
    
    control = carla.VehicleControl()
    
    # 简单跟车逻辑
    if sensor_readings['front_vehicle_distance'] < 20:
        target_speed = min(speed, sensor_readings['front_vehicle_speed'])
        control.throttle = 0 if speed > target_speed else 0.5
        control.brake = 0.3 if speed > target_speed else 0
    else:
        control.throttle = 0.7
        control.brake = 0
    
    # 车道保持
    if sensor_readings['lane_offset'] > 0.5:
        control.steer = -0.3
    elif sensor_readings['lane_offset'] < -0.5:
        control.steer = 0.3
    else:
        control.steer = 0
    
    vehicle.apply_control(control)

在实际项目中,这个决策循环可以替换为更复杂的自动驾驶算法,如基于规则的决策树、机器学习模型或端到端的深度学习系统。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐