4. CARLA世界构建:地图加载与切换、天气系统控制、静态与动态物体生成、蓝图库(BLUEPRINT)使用

好,我们进入第四章。这一章,咱们要真正动手搭建CARLA世界了。

说实话,我刚开始接触CARLA时,最兴奋的就是这部分。你想想看,一个空荡荡的虚拟城市,通过几行代码就能变得车水马龙、阴晴雨雪。这种掌控感,很爽。

但别急,爽归爽,坑也不少。我一个个说。

4.1 地图加载与切换

CARLA自带的地图不少,比如Town01到Town10。每个地图的布局、复杂度都不一样。

我个人习惯,测试简单场景用Town01,做复杂交通流用Town03或Town05。Town07是赛道,适合测极限工况。

加载地图的代码很简单:

import carla

client = carla.Client('localhost', 2000)
client.set_timeout(10.0)

# 加载Town03
world = client.load_world('Town03')
print(f"当前地图: {world.get_map().name}")

嗯,这里要注意。 load_world() 会重新加载整个世界,所有之前的对象都会被清空。如果你在仿真运行中切换地图,记得先保存必要数据。

⚠️ 我曾经踩过的坑: 在仿真进行到一半时直接切换地图,导致车辆传感器数据全部丢失。后来我养成了习惯——切换前先暂停仿真,保存状态。

如果你只想重置当前地图,可以用 reload_world()

# 重置当前世界
world = client.reload_world()

它不会改变地图,但会清空所有动态物体,恢复到初始状态。适合做场景重置。

4.2 天气系统控制

天气系统是CARLA的一大亮点。你可以控制阳光、云层、雨雪、风速,甚至路灯亮度。

说白了,就是一套参数化的环境调节器。

先看一个基础例子:

weather = carla.WeatherParameters(
    cloudiness=80.0,        # 云量 0-100
    precipitation=30.0,     # 降水量 0-100
    sun_altitude_angle=45.0 # 太阳高度角 0-90
)
world.set_weather(weather)

为什么太阳高度角这么重要? 我建议你试试设成10度和80度,看看摄像头图像的区别。低角度时,阴影拉得很长,对视觉感知算法是个考验。

CARLA还内置了几种预设天气:

预设名称 适用场景
ClearNoon 晴天正午,标准测试
CloudyNoon 阴天,光照均匀
WetNoon 雨后路面,反光明显
HardRainNoon 暴雨,能见度低
ClearSunset 黄昏,逆光场景

用法很简单:

world.set_weather(carla.WeatherParameters.HardRainNoon)
💡 我的小技巧: 做传感器鲁棒性测试时,我会写一个循环,每30秒切换一种天气。这样能快速暴露算法在恶劣天气下的短板。

4.3 蓝图库(BLUEPRINT)使用

蓝图库,说白了就是CARLA的“造物清单”。里面存着所有可以生成的东西——车辆、行人、传感器、交通标志等等。

获取蓝图库:

blueprint_library = world.get_blueprint_library()

然后你可以筛选:

# 获取所有车辆蓝图
vehicle_blueprints = blueprint_library.filter('vehicle.*')

# 获取所有行人蓝图
walker_blueprints = blueprint_library.filter('walker.pedestrian.*')

# 获取特定车型
audi_blueprint = blueprint_library.find('vehicle.audi.a2')

我记得第一次用蓝图库时,我直接 filter('*') 打印了所有蓝图,好家伙,几百个。后来我学会了按类别筛选,效率高多了。

蓝图还可以设置属性:

blueprint = blueprint_library.find('vehicle.audi.a2')
blueprint.set_attribute('color', '255,0,0')  # 红色
blueprint.set_attribute('role_name', 'hero') # 角色名
🔑 关键点: role_name 属性很重要。自动驾驶车通常设为 'hero',其他车辆设为 'autopilot' 或 'scenario'。这样在日志分析时能快速区分。

4.4 静态与动态物体生成

有了蓝图,生成物体就水到渠成了。

4.4.1 生成车辆

# 选择一个生成点
spawn_points = world.get_map().get_spawn_points()
spawn_point = spawn_points[0]

# 生成车辆
vehicle = world.spawn_actor(blueprint, spawn_point)

你想想看,如果生成点被占了怎么办? spawn_actor() 会直接报错。所以 我建议try_spawn_actor()

vehicle = world.try_spawn_actor(blueprint, spawn_point)
if vehicle is None:
    print("生成失败,换个位置试试")

4.4.2 生成行人

walker_bp = blueprint_library.find('walker.pedestrian.0001')
walker = world.spawn_actor(walker_bp, carla.Transform(location))

行人需要控制器才能动起来:

walker_controller_bp = blueprint_library.find('controller.ai.walker')
walker_controller = world.spawn_actor(walker_controller_bp, carla.Transform(), walker)
walker_controller.start()
walker_controller.go_to_location(target_location)

4.4.3 生成静态物体

静态物体包括路灯、垃圾桶、路障等。它们属于 static.prop 类别:

prop_bp = blueprint_library.find('static.prop.streettrash')
prop = world.spawn_actor(prop_bp, carla.Transform(location))
⚠️ 注意: 静态物体没有碰撞检测?不,它们有。我曾经在路中间放了个垃圾桶,结果自动驾驶车直接撞上去了。嗯,这其实是个很好的测试用例——检测静态障碍物。

4.5 综合示例:构建一个测试场景

最后,我给你们看一个完整的例子。这是我做传感器融合测试时常用的场景:

import carla
import random

client = carla.Client('localhost', 2000)
client.set_timeout(10.0)
world = client.load_world('Town03')

# 设置天气
world.set_weather(carla.WeatherParameters.CloudyNoon)

# 获取蓝图
bp_lib = world.get_blueprint_library()
vehicle_bp = bp_lib.find('vehicle.audi.a2')
vehicle_bp.set_attribute('role_name', 'hero')

# 生成主车
spawn_points = world.get_map().get_spawn_points()
hero = world.spawn_actor(vehicle_bp, spawn_points[0])

# 生成10辆随机车辆
for i in range(10):
    bp = random.choice(bp_lib.filter('vehicle.*'))
    point = random.choice(spawn_points)
    vehicle = world.try_spawn_actor(bp, point)
    if vehicle:
        vehicle.set_autopilot(True)

# 生成5个行人
for i in range(5):
    bp = random.choice(bp_lib.filter('walker.pedestrian.*'))
    location = carla.Location(x=100+random.uniform(-10,10), 
                              y=100+random.uniform(-10,10), 
                              z=0.5)
    walker = world.try_spawn_actor(bp, carla.Transform(location))

print("场景构建完成!")
print(f"主车: {hero.type_id}")
print(f"车辆数: {len(world.get_actors().filter('vehicle.*'))}")
print(f"行人: {len(world.get_actors().filter('walker.*'))}")

这个例子涵盖了地图加载、天气设置、蓝图筛选、车辆和行人生成。你跑一遍,就能看到一个活生生的虚拟世界。

💡 最后说一句: 构建世界时,别贪多。先从小场景开始,逐步增加复杂度。我见过太多人一上来就生成100辆车,结果仿真卡成PPT。循序渐进,才是正道。

好,这一章就到这儿。下一章我们聊聊传感器——摄像头、激光雷达、毫米波雷达,怎么配、怎么用、怎么采数据。到时候见。