4、场景构建基础:静态场景搭建、动态场景搭建、场景参数化、场景随机化
好,咱们进入正题。场景构建,说白了就是给自动驾驶的车子搭一个「考场」。这个考场要能模拟真实世界的各种情况。我做了这么多年仿真,最深的体会就是:场景建得好不好,直接决定了你的算法是「真牛」还是「假牛」。
今天咱们就聊聊场景构建的四个核心维度。嗯,这也是我平时工作中最常用的套路。
4.1 静态场景搭建:打好地基
静态场景,就是那些不会动的东西。比如道路、建筑、交通标志、路灯、树木。这些是场景的「骨架」。
核心思路: 用 CARLA 的 Python API 把地图元素加载出来,然后固定住。
我个人习惯先把地图加载好,再往上面「贴」道具。举个例子:
import carla
# 连接客户端
client = carla.Client('localhost', 2000)
world = client.get_world()
# 获取蓝图库
blueprint_library = world.get_blueprint_library()
# 放置一个路灯(静态物体)
light_bp = blueprint_library.find('static.prop.streetlight')
light_transform = carla.Transform(carla.Location(x=100, y=50, z=0.5))
world.spawn_actor(light_bp, light_transform)
这里要注意一点:静态物体一旦放置,就不会自己动。但你可以通过 set_transform() 来调整它的位置。我在项目中遇到过一个问题——路灯放歪了,结果激光雷达点云一直报错。排查了半天才发现是路灯杆的位置偏了 5 厘米。
set_simulate_physics(False)。结果车子一撞,路灯直接飞了。静态场景一定要关闭物理模拟,否则会出幺蛾子。
4.2 动态场景搭建:让世界活起来
静态场景只是背景。真正考验算法的,是那些会动的东西——车辆、行人、自行车。动态场景的核心是「行为控制」。
CARLA 提供了两种方式:
- Autopilot 模式: 让车辆自己跑,适合做随机交通流。
- 手动控制模式: 你写代码控制每一帧的速度和转向,适合做精确的切入、切出场景。
我建议新手先用 Autopilot。代码很简单:
# 生成一辆车并开启自动驾驶
vehicle_bp = blueprint_library.filter('vehicle.*')[0]
spawn_point = random.choice(world.get_map().get_spawn_points())
vehicle = world.spawn_actor(vehicle_bp, spawn_point)
vehicle.set_autopilot(True)
但 Autopilot 有个问题——它太「规矩」了。真实世界里,有人会突然变道、有人会急刹车。这时候就需要手动控制。说白了,就是你在每一帧里告诉车子:「往左打 10 度,油门踩 30%」。
举个例子,让一辆车在 3 秒内完成变道:
import time
start_time = time.time()
while time.time() - start_time < 3.0:
# 计算横向偏移量
lateral_offset = (time.time() - start_time) / 3.0 * 3.5 # 3.5米变道距离
control = carla.VehicleControl()
control.steer = lateral_offset * 0.1 # 简单映射
control.throttle = 0.5
vehicle.apply_control(control)
world.tick()
嗯,这里要注意:手动控制时一定要用 world.tick() 推进仿真。不然你的控制指令发不出去。
4.3 场景参数化:让场景可配置
你想想看,如果每次改场景都要改代码,那得多累?参数化就是把这些「可变的东西」抽出来,变成配置文件。
我一般用 YAML 文件来管理参数。比如:
# scene_config.yaml
static_objects:
- type: streetlight
count: 10
distribution: uniform
- type: traffic_sign
count: 5
types: [stop, yield, speed_limit]
dynamic_objects:
- type: vehicle
count: 20
speed_range: [5, 15] # m/s
behavior: random
- type: pedestrian
count: 10
speed_range: [1, 2]
jaywalking_probability: 0.3
然后在 Python 里读取:
import yaml
with open('scene_config.yaml', 'r') as f:
config = yaml.safe_load(f)
# 根据配置生成场景
for obj in config['static_objects']:
for _ in range(obj['count']):
# 生成物体...
pass
这样做的好处是:测试人员不需要懂代码,改个 YAML 文件就能换场景。我在项目里就是这么干的,测试团队反馈特别好。
4.4 场景随机化:对抗过拟合
为什么要随机化?说白了,就是防止你的算法「背题」。如果每次测试都是同一个场景,算法很容易过拟合。真实世界里,没有两个完全一样的场景。
随机化可以从这几个维度入手:
- 位置随机: 车辆、行人的初始位置随机分布。
- 速度随机: 每辆车的速度在一定范围内随机。
- 行为随机: 有的车直行,有的车变道,有的车刹车。
- 天气随机: 晴天、雨天、雾天、夜晚,随机切换。
代码实现其实不复杂:
import random
# 随机生成车辆位置
spawn_points = world.get_map().get_spawn_points()
random.shuffle(spawn_points)
# 随机生成速度
for vehicle in vehicles:
target_speed = random.uniform(5.0, 15.0) # 5-15 m/s
# 设置车辆的目标速度...
pass
# 随机切换天气
weather_presets = [
carla.WeatherParameters.ClearNoon,
carla.WeatherParameters.RainNoon,
carla.WeatherParameters.FoggyNoon,
carla.WeatherParameters.Night,
]
world.set_weather(random.choice(weather_presets))
这里有个坑:随机化不是「瞎随机」。我曾经犯过一个错误——把车辆随机生成在路肩上,结果车子直接卡住了。后来我加了一个校验:生成位置必须在可行驶区域内。
4.5 实战组合拳:把四个维度串起来
好了,咱们把静态、动态、参数化、随机化串起来,做一个完整的场景生成流程:
- 加载地图: 选择 Town03 或 Town05。
- 放置静态物体: 根据 YAML 配置,放置路灯、标志牌。
- 生成动态物体: 随机生成 20 辆车、10 个行人。
- 设置行为: 80% 车辆用 Autopilot,20% 车辆手动控制做切入。
- 随机化: 随机切换天气,随机调整车辆速度。
- 开始测试: 让被测车辆进入场景,记录数据。
这个流程我用了好几年,效果很稳定。你想想看,一个场景模板就能生成几百种不同的测试用例,效率提升不是一点半点。
最后说一句:场景构建没有「完美」一说。关键是找到你算法最薄弱的环节,然后针对性地构建场景。别想着一次覆盖所有情况,那不现实。