3、CARLA基础操作:生成车辆与行人、控制车辆运动(手动/自动)、获取车辆状态信息
好,咱们进入第三章。这一章可以说是CARLA实操的「第一脚油门」。你想想看,仿真平台搭好了,环境也加载了,接下来最直观的事是什么?——往场景里塞车、塞人,然后让它们动起来。
我个人习惯把这一章叫做「让世界活过来」。因为只有当你亲手在代码里生成一辆车,看着它从无到有出现在屏幕上,你才会真正理解仿真和游戏的区别在哪。
3.1 生成车辆与行人——从蓝图到实体
CARLA里所有能生成的东西,都叫蓝图(Blueprint)。你可以把它理解成「模具」——模具里定义了车型、颜色、物理属性等等。我们要做的,就是从蓝图库里挑一个,然后告诉服务器:「嘿,在这个位置给我造一辆。」
核心流程:
- 获取蓝图库(world.get_blueprint_library())
- 筛选特定蓝图(比如找一辆奥迪)
- 设置生成点(Spawn Point)
- 调用 spawn_actor() 方法
代码写起来其实很直白。我贴一段我项目里常用的写法:
import carla
# 连接客户端
client = carla.Client('localhost', 2000)
client.set_timeout(10.0)
world = client.get_world()
# 获取蓝图库
blueprint_library = world.get_blueprint_library()
# 筛选车辆蓝图——我习惯先过滤出所有车,再随机挑一辆
vehicle_bp = blueprint_library.filter('vehicle.*')
spawn_point = random.choice(world.get_map().get_spawn_points())
# 生成车辆
vehicle = world.spawn_actor(vehicle_bp, spawn_point)
print(f"车辆已生成,ID: {vehicle.id}")
嗯,这里要注意:spawn_point 不能乱选。CARLA地图上预定义了很多合法的生成点,用 get_spawn_points() 拿到的才是安全的。我曾经在项目里图省事,自己随便编了个坐标,结果车直接卡到地底下去了……
生成行人也是类似的逻辑,只不过蓝图要换成 walker.pedestrian.*。不过行人有个坑——它需要额外的控制器才能走路,这个咱们后面讲。
我的小技巧:生成行人时,建议先设置好它的颜色和行走速度。蓝图里有个 set_attribute('color', '255,0,0') 的方法,可以让你在生成前就定制外观。我在做行人避让测试时,就靠不同颜色区分「正常行走」和「突然横穿」的行人。
3.2 控制车辆运动——手动挡 vs 自动驾驶
车生出来了,怎么让它跑?CARLA给了你两条路:手动控制和自动驾驶。说白了,一个是你自己拧方向盘踩油门,另一个是让内置的AI代劳。
3.2.1 手动控制——精细到每个踏板
手动控制就是直接给车辆发指令:油门、刹车、转向、档位。每个值都是0到1之间的浮点数。举个例子:
# 创建一个车辆控制对象
control = carla.VehicleControl()
# 设置油门和转向
control.throttle = 0.5 # 50%油门
control.steer = -0.3 # 左转30%
control.brake = 0.0 # 不刹车
# 应用控制
vehicle.apply_control(control)
你想想看,这就像你在玩赛车游戏,只不过手柄换成了代码。我刚开始做的时候,为了模拟一个「平稳起步」,得一点点把油门从0.1加到0.5,不然车会猛地窜出去——这在仿真里无所谓,但如果你在做ADAS测试,这种突兀的加速会干扰传感器数据。
避坑指南:我曾经在项目里连续调用 apply_control() 时忘了设置 brake 为0,结果车一直带着刹车跑。排查了半天才发现是上一帧的刹车值没清零。建议每次创建新的 VehicleControl 对象,或者显式把所有值都设一遍。
3.2.2 自动驾驶——让CARLA自己开
手动控制适合做精确测试,但大多数时候我们想让车自己跑起来,模拟真实的交通流。CARLA内置了自动驾驶模式,一行代码搞定:
vehicle.set_autopilot(True)
就这么简单。开启后,CARLA会接管车辆,它会遵守红绿灯、避让行人、沿着车道行驶。你想想看,这背后其实是一套完整的交通规则引擎在运作。
不过要注意,自动驾驶模式依赖CARLA的交通管理器(Traffic Manager)。你可以通过它调整驾驶风格,比如:
# 获取交通管理器
traffic_manager = client.get_trafficmanager()
# 设置全局速度限制(km/h)
traffic_manager.global_percentage_speed_difference(10.0)
# 让某辆车更激进一点
traffic_manager.ignore_lights_percentage(vehicle, 20)
我个人习惯在测试时,把自动驾驶的车流速度调低10%-20%,这样场景更接近真实城市路况。太整齐划一的车流反而容易掩盖问题。
3.3 获取车辆状态信息——速度、位置、碰撞
车在跑,我们得知道它跑得怎么样。CARLA提供了非常丰富的状态查询接口。我挑三个最常用的讲:速度、位置、碰撞。
3.3.1 速度与位置
这两个是最基础的。获取方式也很直接:
# 获取车辆变换(位置+朝向)
transform = vehicle.get_transform()
location = transform.location # 包含 x, y, z
rotation = transform.rotation # 包含 pitch, yaw, roll
# 获取速度(km/h)
velocity = vehicle.get_velocity()
speed = 3.6 * (velocity.x**2 + velocity.y**2 + velocity.z**2)**0.5
print(f"位置: ({location.x:.2f}, {location.y:.2f})")
print(f"速度: {speed:.2f} km/h")
这里有个细节:get_velocity() 返回的是 m/s,但咱们看车速习惯用 km/h,所以要乘以3.6。我刚开始做的时候忘了换算,日志里显示速度只有2点多,我还纳闷这车怎么跟乌龟似的……
我的经验:如果你在做路径规划测试,建议每帧都记录位置和速度。我一般会写一个简单的数据记录器,把每帧的 frame_number、location、speed 存到CSV里。后期回放分析时特别有用。
3.3.2 碰撞检测——别等撞了才知道
碰撞检测是自动驾驶仿真里的核心需求。CARLA通过回调函数(Callback)来实现。你需要给车辆绑定一个碰撞传感器:
# 创建碰撞传感器蓝图
collision_bp = blueprint_library.find('sensor.other.collision')
# 将传感器附着在车辆上
collision_sensor = world.spawn_actor(collision_bp, carla.Transform(), attach_to=vehicle)
# 定义碰撞回调函数
def on_collision(event):
print(f"碰撞发生!冲击力: {event.normal_impulse}")
# 这里可以记录碰撞对象、位置等信息
# 注册回调
collision_sensor.listen(on_collision)
嗯,这里要注意:碰撞传感器本身也是一个Actor,生成后要记得在程序结束时销毁它,不然会一直占用资源。
我曾经在做一个多车交互测试时,发现日志里频繁出现碰撞事件,排查了半天才发现是传感器附着点没设好,导致车辆自己跟自己「碰撞」了。所以建议你在回调函数里加一个判断,过滤掉与自己车身的碰撞。
3.4 综合示例——让一辆车跑起来并记录数据
最后,我把上面讲的东西串起来,给你一个完整的示例。这个示例会生成一辆车,开启自动驾驶,然后实时打印它的速度和位置:
import carla
import random
import time
def main():
# 连接
client = carla.Client('localhost', 2000)
client.set_timeout(10.0)
world = client.get_world()
# 生成车辆
bp_lib = world.get_blueprint_library()
vehicle_bp = random.choice(bp_lib.filter('vehicle.*'))
spawn_point = random.choice(world.get_map().get_spawn_points())
vehicle = world.spawn_actor(vehicle_bp, spawn_point)
# 开启自动驾驶
vehicle.set_autopilot(True)
# 绑定碰撞传感器
collision_bp = bp_lib.find('sensor.other.collision')
collision_sensor = world.spawn_actor(collision_bp, carla.Transform(), attach_to=vehicle)
def on_collision(event):
print(f"[碰撞] 冲击力: {event.normal_impulse}")
collision_sensor.listen(on_collision)
# 主循环:每0.1秒打印一次状态
try:
for i in range(100):
# 获取状态
loc = vehicle.get_location()
vel = vehicle.get_velocity()
speed = 3.6 * (vel.x**2 + vel.y**2 + vel.z**2)**0.5
print(f"帧{i:3d} | 位置: ({loc.x:.1f}, {loc.y:.1f}) | 速度: {speed:.1f} km/h")
time.sleep(0.1)
finally:
# 清理
collision_sensor.destroy()
vehicle.destroy()
print("资源已释放")
if __name__ == '__main__':
main()
这个示例虽然简单,但已经覆盖了生成、控制、状态获取、碰撞检测这四个核心操作。你可以在它的基础上扩展,比如同时生成多辆车、记录轨迹数据、或者接入外部控制算法。
本章小结:
- 生成车辆和行人,核心是蓝图 + Spawn Point
- 手动控制精细但繁琐,自动驾驶省心但需要调参
- 速度记得从m/s换算到km/h,位置用get_transform()获取
- 碰撞检测靠传感器回调,别忘了销毁资源
好,这一章就到这里。下一章我们会深入CARLA的传感器系统——相机、激光雷达、毫米波雷达,这些东西才是自动驾驶的「眼睛」。到时候我会分享一些我在传感器标定上踩过的坑,保证让你少走弯路。