2、Carla核心概念:世界(World)、蓝图(Blueprint)、参与者(Actor)、传感器(Sensor)

好,咱们正式开始动手之前,得先把Carla里的几个「老熟人」认识清楚。

我第一次接触Carla的时候,看着文档里一堆英文术语,说实话有点懵。什么World、Blueprint、Actor……感觉像在学一门新语言。但后来我发现,搞懂这四个概念,你就掌握了Carla的「骨架」。

说白了,Carla就是一个虚拟的游乐场。你作为工程师,就是那个搭场景、放道具、装摄像头的人。而World、Blueprint、Actor、Sensor,就是你手里的四样核心工具。

2.1 世界(World)—— 你的虚拟沙盘

World是什么?就是整个仿真环境本身。它包含了地图、天气、交通流、时间等等一切。

我个人习惯,每次启动仿真后第一件事就是拿到World对象。没有它,你什么都干不了。

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

拿到World之后,你能做什么?我列几个最常用的操作:

  • 切换地图:比如从Town01换到Town05,跑不同场景。
  • 控制天气:晴天、雨天、大雾,甚至沙尘暴。
  • 获取参与者列表:看看当前场景里都有哪些车、哪些人。
  • 设置仿真步长:控制仿真跑得快还是慢。
小技巧: 我建议你每次拿到World后,先调用一下 world.get_settings() 看看当前配置。有时候默认设置会跟你预期不一样,比如同步模式没开,导致你发指令后车不动。

2.2 蓝图(Blueprint)—— 造物的「模具」

Blueprint,翻译过来是蓝图,但我觉得叫「模具」更贴切。它定义了你要创建的物体长什么样、有什么属性。

举个例子,你想在场景里放一辆车。你不能凭空变出来,得先找一个车的Blueprint。这个Blueprint里规定了:

  • 车型(奥迪A2、特斯拉Model 3、还是卡车)
  • 颜色
  • 最大速度
  • 是否有碰撞检测
  • 等等

我曾经踩过一个坑:想放一辆自行车,结果找了半天没找到。后来才发现,Carla的Blueprint库里,自行车属于「Vehicle」分类下的「Bicycle」子类。嗯,分类逻辑有时候挺反直觉的。

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

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

# 选一个具体的车型,比如奥迪
audi_blueprint = blueprint_library.find('vehicle.audi.a2')
重点: Blueprint只是一个模板,不是实物。你得用它「生成」出Actor,才能放到场景里。

2.3 参与者(Actor)—— 场景里的「活物」

Actor,就是Blueprint造出来的实物。车、行人、交通标志、路灯……只要能在场景里动或者被感知的,都是Actor。

你想想看,你拿到Blueprint之后,得指定一个位置,然后调用 spawn_actor(),才能把车「生」出来。

# 指定生成位置
spawn_point = random.choice(world.get_map().get_spawn_points())

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

这里有个坑,我当年栽过:生成位置不能重叠。如果你在一个点上连续生成两辆车,第二辆会直接报错。所以一定要用 get_spawn_points() 拿到的合法位置。

Actor有几个重要方法,你必须记住:

  • destroy():销毁Actor,释放资源。不用的车一定要销毁,不然内存会炸。
  • set_location():瞬移。调试时很好用。
  • set_transform():设置位置+朝向。
  • get_velocity():获取当前速度。
注意: 仿真结束后,记得遍历所有Actor并调用 destroy()。我曾经有一次忘了销毁,结果Carla进程占了我8G内存,卡得鼠标都动不了。

2.4 传感器(Sensor)—— 自动驾驶的「眼睛」

传感器是特殊的Actor。它不移动,但能「感知」环境,然后把数据传回来。

Carla支持的传感器很多,我挑几个最常用的:

传感器类型 作用 常用场景
RGB相机 输出彩色图像 视觉感知、目标检测
深度相机 输出深度图 距离估计、3D重建
LIDAR 输出点云数据 激光雷达感知、SLAM
GNSS 输出经纬度 定位、导航
IMU 输出加速度、角速度 惯性导航、车辆状态估计

传感器的使用套路很固定:先找Blueprint,然后绑定到某个Actor上(通常是你的主车),再注册一个回调函数来处理数据。

# 创建一个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, transform, attach_to=vehicle)

# 注册回调函数,处理图像数据
def process_image(image):
    # 这里你可以保存图像、做推理、或者显示
    image.save_to_disk('output/%06d.png' % image.frame)

camera.listen(process_image)
个人经验: 传感器回调函数里不要做耗时操作,比如写数据库或者跑深度学习模型。否则会拖慢仿真速度。我一般只把数据存到队列里,另开线程处理。

2.5 它们之间的关系

最后,我用一句话总结这四个概念的关系:

World是舞台,Blueprint是剧本,Actor是演员,Sensor是演员身上的麦克风。

你通过World拿到Blueprint,用Blueprint生成Actor,再给Actor挂上Sensor。Sensor采集数据,你拿到数据做算法验证。

嗯,就是这么简单。但简单归简单,实际项目中容易出问题的往往是细节。比如:

  • 生成Actor时位置没选好,车卡在地底下。
  • 传感器回调没处理好,导致内存泄漏。
  • World设置没同步,导致控制指令延迟。

这些坑,后面章节我会一个一个带你踩一遍。别怕,踩过了就记住了。