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.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')
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():获取当前速度。
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设置没同步,导致控制指令延迟。
这些坑,后面章节我会一个一个带你踩一遍。别怕,踩过了就记住了。