3. 车辆与行人控制:让仿真世界动起来
好,我们继续往下走。上一章我们把地图和传感器搭好了,但一个空荡荡的仿真环境,说实话跟个鬼城似的。这一章,咱们就来给它注入灵魂——让车跑起来,让人走起来。
我个人习惯把车辆和行人控制分成两大块:生成和控制。生成是让对象出现在场景里,控制是让它们按照我们的意图动。这两步缺一不可。
3.1 生成车辆:从蓝图到实体
在Carla里,每一辆车都对应一个蓝图(Blueprint)。你可以把蓝图理解成汽车的「设计图纸」。我刚开始接触时,总以为直接给个车型名字就行,结果发现得先查蓝图库。
来看看怎么生成一辆车:
import carla
# 连接客户端
client = carla.Client('localhost', 2000)
world = client.get_world()
# 获取蓝图库
blueprint_library = world.get_blueprint_library()
# 挑选一辆车,比如奥迪A2
vehicle_bp = blueprint_library.find('vehicle.audi.a2')
# 找个生成点
spawn_points = world.get_map().get_spawn_points()
spawn_point = spawn_points[0]
# 生成车辆
vehicle = world.spawn_actor(vehicle_bp, spawn_point)
嗯,这里要注意:spawn_points 是地图预定义的停车位或起始位置。如果你随便给个坐标,车可能会卡在地底下。我曾经犯过这个错,调试了半天才发现是坐标没落在路面上。
random.choice(blueprint_library.filter('vehicle.*'))。但记得过滤掉自行车和摩托车,它们的行为逻辑跟汽车不太一样。
3.2 控制车辆运动:让车听你的话
车生成了,但它不会自己动。你需要给它指令。Carla提供了两种控制方式:手动控制和自动驾驶。
3.2.1 手动控制:油门、刹车、方向盘
说白了,就是模拟真实驾驶操作。通过 carla.VehicleControl 这个类,你可以设置油门、刹车、转向等参数。
# 创建一个控制指令
control = carla.VehicleControl()
control.throttle = 0.5 # 油门踩一半
control.steer = 0.3 # 方向盘右转30%
control.brake = 0.0 # 不刹车
# 应用到车辆
vehicle.apply_control(control)
你想想看,如果只给一次指令,车只会动一瞬间。所以通常我们会把它放在一个循环里,每帧更新一次控制参数。我在项目中遇到过一个问题:油门给太大,车直接漂移撞墙了。后来我加了个速度限制,超过30km/h就自动收油。
3.2.2 自动驾驶模式:交给Carla自己开
如果你不想手写控制逻辑,Carla内置了自动驾驶。用起来很简单:
vehicle.set_autopilot(True)
就这么一行。它会自动遵守红绿灯、避让行人、沿着车道走。但说实话,这个自动驾驶比较「死板」,有时候会在路口犹豫不决。我一般只在测试传感器时用它,真要验证算法,还是得自己写控制。
3.3 生成行人:让街道有人气
行人的生成逻辑跟车辆类似,但有个关键区别:行人没有预定义的生成点。你得自己指定坐标。
# 获取行人蓝图
walker_bp = blueprint_library.find('walker.pedestrian.0001')
# 指定生成位置(注意:要在人行道上)
walker_transform = carla.Transform(
carla.Location(x=100, y=50, z=0.5),
carla.Rotation(yaw=0)
)
# 生成行人
walker = world.spawn_actor(walker_bp, walker_transform)
为什么 z=0.5?因为行人的原点在脚底,如果不抬高一点,它会陷进地面。我记得第一次生成行人时,只看到一个脑袋在地面上飘,吓我一跳。
blueprint_library.filter('walker.*') 打印出所有行人蓝图,再挑选。
3.4 控制行人行走:让走路更自然
行人控制比车辆复杂一些。车辆只需要油门刹车转向,但行人需要控制走路方向、速度,甚至动画状态。
3.4.1 使用WalkerControl
Carla提供了 carla.WalkerControl 类,可以控制行人的移动方向和速度。
# 创建行人控制指令
walker_control = carla.WalkerControl()
walker_control.direction = carla.Vector3D(x=1, y=0, z=0) # 朝X轴正方向走
walker_control.speed = 1.5 # 速度1.5m/s,约等于正常步行速度
# 应用控制
walker.apply_control(walker_control)
这里有个坑:direction 必须是单位向量,否则速度会异常。我曾经传了个长度为2的向量,结果行人跑得跟博尔特一样快。
3.4.2 让行人自动行走
跟车辆一样,行人也可以开启自动模式。但行人的自动模式需要额外启动一个「行人控制器」:
# 开启行人自动驾驶
walker.set_autopilot(True)
不过说实话,Carla自带的行人自动驾驶效果一般。它们只会沿着人行道随机走,不会过马路,也不会避让车辆。如果你需要更真实的行人行为,我建议自己写路径规划。
3.5 批量生成:让场景更丰富
单个车辆或行人太孤单了。实际项目中,我们往往需要生成一个车队或一群人。来看看怎么批量操作:
import random
# 批量生成车辆
vehicle_list = []
for i in range(10):
bp = random.choice(blueprint_library.filter('vehicle.*'))
spawn_point = random.choice(spawn_points)
v = world.spawn_actor(bp, spawn_point)
v.set_autopilot(True)
vehicle_list.append(v)
# 批量生成行人
walker_list = []
for i in range(20):
bp = random.choice(blueprint_library.filter('walker.*'))
location = carla.Location(
x=random.uniform(50, 150),
y=random.uniform(30, 80),
z=0.5
)
transform = carla.Transform(location)
w = world.spawn_actor(bp, transform)
w.set_autopilot(True)
walker_list.append(w)
你想想看,如果每次生成都手动指定位置,那得累死。用随机生成配合自动驾驶,几行代码就能造出一个热闹的街道。
spawn_actor 的返回值。如果返回 None,说明生成失败(通常是位置冲突)。我曾经没做检查,结果列表里一堆空对象,后面调用控制方法时直接报错。
3.6 清理场景:别让仿真环境变垃圾场
仿真结束后,记得清理生成的车辆和行人。否则下次启动时,你会发现满大街都是上一轮留下的「幽灵车」。
# 销毁所有车辆
for v in vehicle_list:
v.destroy()
# 销毁所有行人
for w in walker_list:
w.destroy()
嗯,这个习惯一定要养成。我在早期开发时,经常忘记清理,结果仿真越来越卡,最后客户端直接崩溃。后来我写了个 cleanup() 函数,每次仿真结束自动调用。
3.7 本章小结
这一章我们覆盖了车辆和行人的生成与控制。说白了,核心就三件事:选蓝图、定位置、发指令。手动控制给你精细度,自动驾驶给你便利性。根据场景需求,灵活切换就好。
下一章,我们会把传感器数据和控制逻辑结合起来,做一个完整的感知-决策-控制闭环。到时候你会发现,前面这些基础操作,都是为那个闭环服务的。