2. Carla基础架构与核心概念

好,咱们正式开始啃Carla的核心概念了。说实话,我第一次接触Carla时,也被它那一堆术语搞得有点懵——世界、蓝图、参与者、传感器……这些到底都是啥?它们之间又是怎么配合的?

别急,我带你捋一遍。搞懂了这些,后面的脚本控制你就顺手了。

2.1 世界(World)——一切发生的舞台

世界,说白了就是Carla仿真环境的根对象。它管理着整个仿真场景的生命周期。

你可以把世界想象成一个巨大的容器,里面装着地图、天气、所有的车辆行人、传感器等等。没有世界,其他东西都无处安放。

核心要点:世界是Carla仿真中最高层级的对象,所有操作都从获取世界实例开始。

获取世界实例的代码很简单:

import carla

# 连接客户端
client = carla.Client('localhost', 2000)
client.set_timeout(10.0)

# 获取世界
world = client.get_world()

我个人习惯在脚本开头就拿到世界对象,后面所有操作都基于它。嗯,这里要注意:每次重新加载地图时,世界对象会变化,需要重新获取。

2.2 蓝图(Blueprint)——参与者的“出生证明”

蓝图是什么?它定义了参与者的类型、属性和默认配置。你可以把它理解成汽车的出厂配置单——什么车型、什么颜色、带不带传感器,都在蓝图上写着。

Carla内置了丰富的蓝图库,包括各种车辆、行人、交通标志、传感器等。我在项目中遇到过最头疼的事,就是找合适的车辆模型——蓝图库里有上百种,你得知道怎么筛选。

# 获取所有可用的蓝图
blueprint_library = world.get_blueprint_library()

# 筛选出所有车辆蓝图
vehicle_blueprints = blueprint_library.filter('vehicle.*')

# 挑选一个具体的车型
bp = blueprint_library.find('vehicle.tesla.model3')

小技巧:使用filter方法配合通配符,可以快速筛选出你需要的蓝图类型。比如'vehicle.*'匹配所有车辆,'sensor.*'匹配所有传感器。

2.3 参与者(Actor)——仿真世界里的“活物”

参与者是蓝图的实例化结果。蓝图只是模板,参与者才是真正出现在仿真场景中的实体。

你想想看,蓝图就像一张建筑设计图,而参与者就是按照这张图盖起来的房子。蓝图可以反复使用,但每个参与者都是独一无二的——它有自己独立的ID、位置、状态。

创建参与者的流程:

# 1. 获取蓝图
bp = blueprint_library.find('vehicle.tesla.model3')

# 2. 设置初始位置
spawn_point = random.choice(world.get_map().get_spawn_points())

# 3. 生成参与者
vehicle = world.spawn_actor(bp, spawn_point)

# 4. 使用完毕后销毁
vehicle.destroy()

注意:参与者如果不手动销毁,会一直存在于仿真世界中。我曾经在调试时忘了销毁,结果场景里堆了上百辆车,卡得不行。记得养成好习惯——用完就销毁,或者用with语句管理生命周期。

2.4 传感器(Sensor)——Carla的“眼睛”和“耳朵”

传感器是特殊的参与者。它们不占据物理空间,但能感知环境并返回数据。

Carla支持的传感器类型很丰富:

传感器类型 功能 常见用途
RGB相机 返回彩色图像 视觉感知、目标检测
深度相机 返回深度信息 3D重建、距离估计
激光雷达 返回点云数据 环境建模、障碍物检测
GNSS 返回GPS坐标 定位、导航
IMU 返回加速度、角速度 惯性导航、状态估计

传感器的使用套路很固定:先获取蓝图,再设置参数,最后绑定到某个参与者上。

# 创建RGB相机传感器
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 = world.spawn_actor(
    camera_bp,
    carla.Transform(carla.Location(x=1.5, z=2.4)),
    attach_to=vehicle
)

# 监听传感器数据
camera.listen(lambda image: image.save_to_disk('output/%06d.png' % image.frame))

避坑指南:我曾经把传感器位置设得太低,结果拍到的全是地面。传感器的附着位置很重要,建议先打印几个位置试试效果。

2.5 地图(Map)——仿真世界的“地基”

地图定义了仿真场景的物理结构——道路、车道线、交通标志、建筑物等等。Carla自带了几张官方地图,比如Town01到Town07,各有特色。

地图和世界的关系很紧密:每个世界都关联着一张地图。切换地图时,世界会重新加载。

# 获取当前地图
current_map = world.get_map()
print(f"当前地图: {current_map.name}")

# 切换地图
client.load_world('Town03')

# 获取地图中的生成点
spawn_points = current_map.get_spawn_points()
print(f"共有 {len(spawn_points)} 个生成点")

我个人觉得Town03最适合做交通场景测试——它有环岛、十字路口、弯道,场景丰富。Town05则更适合高速公路场景。

2.6 天气系统(Weather)——仿真世界的“情绪”

天气系统控制着环境的光照、降水、雾气等参数。别小看它,天气对传感器数据的影响非常大——雨天激光雷达会打折扣,雾天相机基本废掉。

Carla提供了预设的天气模式,也支持自定义:

# 使用预设天气
weather = carla.WeatherParameters.ClearNoon
world.set_weather(weather)

# 自定义天气
custom_weather = carla.WeatherParameters(
    cloudiness=80.0,      # 云量 0-100
    precipitation=60.0,   # 降水量 0-100
    precipitation_deposits=50.0,  # 积水程度
    wind_intensity=30.0,  # 风速
    sun_altitude_angle=45.0,  # 太阳高度角
    fog_density=20.0,     # 雾浓度
    fog_distance=50.0     # 雾的可见距离
)
world.set_weather(custom_weather)

经验之谈:做自动驾驶算法测试时,一定要覆盖多种天气条件。我见过太多算法在晴天跑得飞起,一到雨天就翻车。建议至少测试晴天、阴天、雨天、雾天四种场景。

2.7 它们之间的关系——一张图说清楚

好,现在我们把所有概念串起来。它们的关系其实很简单:

  • 客户端连接服务器,获取世界
  • 世界包含地图天气
  • 蓝图库从世界获取,用于创建参与者
  • 传感器是特殊的参与者,附着在其他参与者上
  • 所有参与者都在世界中活动,受地图天气影响

说白了,整个Carla仿真就是:在世界这个舞台上,按照地图的规则,在特定的天气下,让各种参与者(包括传感器)动起来。

搞懂了这些,后面的章节你就知道我们在操作什么了。下一章,我们开始动手搭建第一个交通场景——到时候这些概念都会用上。