3、Python API入门:Client与World、Actor生命周期、传感器数据获取、车辆控制
好,咱们进入正题。这一章是实操的基础,说白了就是让你学会怎么用Python跟Carla这个仿真世界对话。我刚开始接触Carla时,也对着文档发懵,后来发现核心就四个东西:Client、World、Actor、传感器。把这几个玩明白了,后面的场景复现就是搭积木的事。
3.1 Client与World:连接仿真世界
先说说Client。你可以把它理解成一把钥匙,用来打开Carla服务器的大门。我个人习惯在脚本开头就建立连接,像这样:
import carla
# 连接Carla服务器,默认端口是2000
client = carla.Client('localhost', 2000)
client.set_timeout(10.0) # 设置超时,我一般给10秒
嗯,这里要注意。如果你连不上,八成是Carla没启动,或者端口被占了。我曾经在项目里遇到过,开了好几个Carla实例,端口冲突,折腾了半天才发现。
连上之后,就能拿到World对象了。World就是整个仿真世界的句柄,地图、天气、车辆、行人,全归它管。
world = client.get_world()
你想想看,有了world,你就能干很多事。比如获取当前地图:
print(world.get_map().name) # 比如输出 "Town03"
或者改变天气:
weather = carla.WeatherParameters(
cloudiness=80.0,
precipitation=30.0,
sun_altitude_angle=45.0
)
world.set_weather(weather)
为什么我要提天气?因为场景复现时,光照和雨雾对传感器数据影响很大。我建议你每次复现前,都显式设置一下天气,避免环境不一致。
world.get_weather() 先打印出来看看。
3.2 Actor生命周期:创建、控制、销毁
Actor是Carla里所有动态物体的统称——车辆、行人、传感器,都是Actor。它的生命周期很简单:创建 -> 控制 -> 销毁。但很多新手会漏掉最后一步,导致内存泄漏。
先看怎么创建一辆车:
# 获取蓝图库
blueprint_library = world.get_blueprint_library()
# 选一辆车,比如奥迪
vehicle_bp = blueprint_library.find('vehicle.audi.a2')
# 找个生成点
spawn_point = world.get_map().get_spawn_points()[0]
# 生成车辆
vehicle = world.spawn_actor(vehicle_bp, spawn_point)
这里有个坑。我曾经在复现一个多车场景时,发现车辆生成后位置不对。后来排查发现,get_spawn_points() 返回的点是固定的,但有些点可能被占用了。所以生成前最好检查一下:
if spawn_point is None:
print("生成点无效,换个点试试")
车辆生成后,怎么控制它?两种方式:
- 自动驾驶模式: 用
vehicle.set_autopilot(True),Carla内置的交通管理器会接管。 - 手动控制: 通过
vehicle.apply_control()发送油门、刹车、转向指令。
手动控制的代码长这样:
control = carla.VehicleControl()
control.throttle = 0.5 # 油门 50%
control.steer = -0.3 # 左转 30%
control.brake = 0.0 # 不刹车
vehicle.apply_control(control)
你想想看,场景复现时,我们通常需要精确控制车辆的轨迹,所以手动控制更常用。我会把控制指令写到一个列表里,按时间步逐帧发送。
最后,别忘了销毁。用完的Actor一定要清理:
vehicle.destroy()
3.3 传感器数据获取:让车“看见”世界
传感器是Carla的灵魂。没有传感器,你的车就是个瞎子。常用的传感器有相机、激光雷达、GPS、IMU等。获取数据的方式都是类似的:先创建传感器,再绑定回调函数。
拿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')
# 安装到车上,位置在车顶
transform = carla.Transform(carla.Location(x=1.5, z=2.4))
camera = world.spawn_actor(camera_bp, transform, attach_to=vehicle)
# 定义回调函数,处理图像数据
def process_image(image):
# image是carla.Image对象
# 可以保存为文件,或者转成numpy数组
image.save_to_disk(f'output/{image.frame}.png')
# 开始监听
camera.listen(process_image)
这里有个关键点:listen() 是异步的。也就是说,传感器数据是源源不断流进来的,你的主循环可以继续做其他事。我个人习惯在回调函数里把数据存到队列里,主循环再从队列里取,这样不会阻塞。
激光雷达的用法类似,只是数据类型不同:
lidar_bp = blueprint_library.find('sensor.lidar.ray_cast')
lidar_bp.set_attribute('channels', '32')
lidar_bp.set_attribute('range', '50')
lidar = world.spawn_actor(lidar_bp, transform, attach_to=vehicle)
def process_lidar(data):
# data是carla.LidarMeasurement对象
# 可以转成numpy数组做点云处理
points = np.frombuffer(data.raw_data, dtype=np.dtype('f4'))
points = np.reshape(points, (int(points.shape[0] / 4), 4))
lidar.listen(process_lidar)
3.4 车辆控制:让车动起来
车辆控制这块,刚才已经提了一点。这里再深入说说。Carla的车辆控制模型挺真实的,不是简单的“给油门就走”。它考虑了转向延迟、轮胎摩擦、空气阻力等因素。
常用的控制参数:
| 参数 | 范围 | 说明 |
|---|---|---|
| throttle | 0.0 ~ 1.0 | 油门,0是松油,1是地板油 |
| steer | -1.0 ~ 1.0 | 转向,负值左转,正值右转 |
| brake | 0.0 ~ 1.0 | 刹车,0是不刹,1是急刹 |
| hand_brake | True / False | 手刹,一般用于停车 |
| reverse | True / False | 倒车,需要配合油门使用 |
举个例子,让车匀速直线行驶:
control = carla.VehicleControl()
control.throttle = 0.4
control.steer = 0.0
control.brake = 0.0
# 在仿真循环里持续发送
while True:
vehicle.apply_control(control)
world.tick() # 推进仿真时间
你可能会问,为什么不用 set_autopilot(True)?因为场景复现需要精确控制。自动驾驶模式会自己决定路线,你没法保证每次跑的轨迹都一样。所以,手动控制才是复现的王道。
好了,这一章的内容就这些。Client连接、World管理、Actor生命周期、传感器数据、车辆控制,这五个点你掌握了,Carla的Python API就算入门了。下一章我们会把这些东西串起来,做一个完整的场景复现案例。