4、生成车辆:使用蓝图生成车辆、设置生成点、处理生成失败

好,咱们进入正题。上一章我们把地图和天气搞定了,这一章该让车跑起来了。

生成车辆这件事,说白了就是三步:选车 → 选位置 → 把车变出来。听起来简单,但我在项目里踩过的坑可不少。比如车卡在地底下、车飞到天上、或者干脆生成不出来——嗯,这些我都遇到过。

4.1 蓝图是什么?

在CARLA里,每辆车都有一个“设计图纸”,这就是蓝图(Blueprint)。蓝图里存了车的型号、颜色、物理属性、传感器配置等等。

你可以把蓝图想象成汽车的“出生证明”。有了它,CARLA才知道你要造一辆什么样的车。

核心概念:蓝图库(Blueprint Library)里存了所有可用的车辆模型。你需要先从库里挑一个,再用它来生成实体车。

我个人习惯先把蓝图库遍历一遍,看看有哪些车可以用。代码很简单:

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

# 打印前5个看看
for bp in vehicle_blueprints[:5]:
    print(bp.id)

输出大概长这样:

vehicle.audi.a2
vehicle.bmw.grandtourer
vehicle.chevrolet.impala
vehicle.dodge.charger_police
vehicle.ford.mustang

你看,命名规则是 vehicle.品牌.型号。想选哪辆,直接写名字就行。

4.2 设置生成点

车选好了,接下来得找个地方放它。CARLA地图里预置了很多生成点(Spawn Points),每个点包含位置和朝向。

获取生成点的方法:

spawn_points = world.get_map().get_spawn_points()
print(f"地图共有 {len(spawn_points)} 个生成点")

我建议你第一次跑的时候,先打印一下生成点的数量。不同地图差别很大——Town01可能只有几十个,Town05能有上百个。

小技巧:生成点是有编号的。你可以用 spawn_points[0] 取第一个,或者随机选一个。我个人习惯用随机,这样每次跑仿真都不一样。

import random

# 随机选一个生成点
spawn_point = random.choice(spawn_points)

4.3 生成车辆

蓝图和位置都准备好了,接下来就是见证奇迹的时刻:

# 选一辆车
bp = blueprint_library.find('vehicle.audi.a2')

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

print(f"车辆已生成: {vehicle.type_id}")

就这么简单?嗯,大部分情况是的。但我要提醒你——生成失败是家常便饭。

4.4 处理生成失败

为什么会失败?我总结了几种常见情况:

失败原因 表现 解决办法
生成点被占用 抛异常 换个生成点,或先清空该位置
生成点不合理 车卡在建筑物里 检查生成点是否在路面上
蓝图无效 找不到指定蓝图 确认蓝图ID拼写正确
超出最大车辆数 生成被拒绝 减少车辆数量或销毁旧车

我曾经在项目里遇到过一个问题:连续生成20辆车,到第15辆就报错了。查了半天才发现是地图的生成点不够用,有些点被前面的车占了。

解决方案很简单——用 try-except 包起来,失败了就换下一个点:

def spawn_vehicle_safely(world, blueprint, spawn_points):
    """安全生成车辆,失败自动重试"""
    for spawn_point in spawn_points:
        try:
            vehicle = world.spawn_actor(blueprint, spawn_point)
            return vehicle
        except:
            continue
    print("所有生成点都试过了,还是失败")
    return None

注意: spawn_actor 如果失败会抛出 RuntimeError。别问我怎么知道的——我第一次写的时候没加异常处理,程序直接崩了。

4.5 批量生成车辆

实际仿真中,我们经常要生成多辆车。比如模拟十字路口的车流,至少得有个七八辆吧。

批量生成的套路是这样的:

# 选5辆不同的车
blueprints = blueprint_library.filter('vehicle.*')
selected_bps = random.choices(blueprints, k=5)

# 选5个不同的生成点
selected_points = random.sample(spawn_points, k=5)

# 批量生成
vehicles = []
for bp, point in zip(selected_bps, selected_points):
    try:
        v = world.spawn_actor(bp, point)
        vehicles.append(v)
        print(f"生成成功: {v.type_id}")
    except Exception as e:
        print(f"生成失败: {e}")

print(f"成功生成 {len(vehicles)} 辆车")

你想想看,如果每辆车都手动指定位置,那得多累。用随机选择,省时省力。

4.6 车辆生成后的设置

车生成了,不代表就完事了。我一般会做几件事:

  • 设置自动驾驶模式:让车自己跑起来
  • 调整颜色:方便区分不同车辆
  • 设置物理参数:比如最大速度、碰撞检测等

设置自动驾驶最简单:

vehicle.set_autopilot(True)

改颜色也不难:

# 获取可用的颜色列表
colors = bp.get_attribute('color').recommended_values
# 选一个随机颜色
random_color = random.choice(colors)
bp.set_attribute('color', random_color)

小提示:颜色属性是在生成之前设置的。生成之后改颜色?嗯,我试过,不行。所以记得在 spawn_actor 之前把颜色调好。

4.7 知识体系总览

这一章的内容,我用一张图帮你理清楚:

生成车辆核心流程 1. 获取蓝图 get_blueprint_library() 2. 选择生成点 get_spawn_points() 3. 生成车辆 spawn_actor() ⚠ 失败处理:try-except 捕获异常 → 换生成点 → 重试 生成成功 → 设置自动驾驶 / 调整颜色 / 配置物理参数 常见坑点 生成点被占用 | 蓝图ID拼写错误 | 超出最大车辆数限制

4.8 完整示例代码

最后,给你一个可以直接跑的完整示例。我平时写仿真脚本,基本就是这个结构:

import carla
import random

def main():
    # 连接CARLA
    client = carla.Client('localhost', 2000)
    client.set_timeout(10.0)
    world = client.get_world()
    
    # 获取蓝图和生成点
    blueprint_library = world.get_blueprint_library()
    spawn_points = world.get_map().get_spawn_points()
    
    # 选一辆车,设置颜色
    bp = blueprint_library.find('vehicle.audi.a2')
    color = random.choice(bp.get_attribute('color').recommended_values)
    bp.set_attribute('color', color)
    
    # 安全生成
    vehicle = None
    for point in spawn_points:
        try:
            vehicle = world.spawn_actor(bp, point)
            break
        except:
            continue
    
    if vehicle is None:
        print("生成失败,所有生成点都试过了")
        return
    
    # 开启自动驾驶
    vehicle.set_autopilot(True)
    print(f"车辆 {vehicle.type_id} 已上路,颜色: {color}")
    
    # 让仿真跑一会儿
    import time
    time.sleep(10)
    
    # 清理
    vehicle.destroy()
    print("仿真结束")

if __name__ == '__main__':
    main()

这段代码我反复用过很多次,基本没出过问题。你拿去改改就能用。

核心要点回顾:

  • 蓝图是车的“设计图纸”,从蓝图库里选
  • 生成点决定了车的位置和朝向
  • 生成失败很正常,用 try-except 兜底
  • 颜色等属性要在生成前设置好

好了,这一章就到这里。车已经能跑起来了,下一章我们聊聊怎么控制它——嗯,到时候见。

可可精品资料库