3、CARLA入门:CARLA架构解析、安装与启动、Python API基础、客户端与服务器模型

好,咱们正式开始啃CARLA这块硬骨头。说实话,我第一次接触CARLA的时候,也被它的架构搞得有点懵。但别担心,我带你捋一遍,你会发现它其实挺清晰的。

3.1 CARLA架构解析:到底谁在干活?

CARLA本质上是一个客户端-服务器架构。你想想看,这就像打网络游戏——服务器负责渲染画面、计算物理、管理世界;客户端负责发指令、收数据。嗯,就是这么回事。

具体来说:

  • 服务器(Server):运行虚幻引擎4,负责仿真世界的运行。包括车辆动力学、传感器模拟、交通流、天气变化等等。服务器是核心,它不关心谁来连它。
  • 客户端(Client):通过Python API与服务器通信。你写的脚本就是客户端。客户端可以控制车辆、配置环境、读取传感器数据。

核心要点:一个服务器可以同时服务多个客户端。我在项目中就试过,一个客户端控制主车,另一个客户端跑路测场景,互不干扰。但要注意,多个客户端操作同一个对象时,可能会打架。

为什么会设计成这种架构?说白了,就是为了解耦。服务器专心做仿真,客户端专心做算法。你可以在本地跑服务器,在远程跑客户端,完全没问题。

3.2 安装与启动:别踩我踩过的坑

安装CARLA其实不复杂,但有几个细节我吃过亏,你注意一下。

3.2.1 系统要求

组件 最低要求 推荐配置
操作系统 Windows 10 / Ubuntu 18.04 Ubuntu 20.04
GPU NVIDIA GTX 1060 NVIDIA RTX 2070 以上
内存 8 GB 16 GB
硬盘 20 GB 空闲 SSD 50 GB

3.2.2 安装步骤(以Ubuntu为例)

我个人习惯用预编译包,省事。你如果喜欢从源码编译,也行,但第一次建议别折腾。

# 1. 下载CARLA包
wget https://carla-releases.s3.eu-west-3.amazonaws.com/Linux/CARLA_0.9.13.tar.gz

# 2. 解压
tar -xzf CARLA_0.9.13.tar.gz

# 3. 进入目录
cd CARLA_0.9.13

# 4. 安装Python依赖
pip install -r PythonAPI/examples/requirements.txt

# 5. 启动服务器
./CarlaUE4.sh

警告:我曾经在Windows上遇到过路径中文导致启动失败的问题。所以,安装路径千万别带中文,也别带空格。血的教训。

3.2.3 启动服务器

启动服务器后,你会看到一个虚幻引擎的窗口。别急着关,这就是仿真世界。你可以用鼠标拖拽视角,看看这个虚拟城市长什么样。

如果你想在无头模式下运行(没有图形界面),可以加参数:

./CarlaUE4.sh -RenderOffScreen

嗯,这个在服务器上跑特别有用。我经常在远程服务器上这样搞,省显卡资源。

3.3 Python API基础:你的遥控器

Python API是CARLA的灵魂。说白了,你通过它跟仿真世界对话。

3.3.1 连接服务器

第一步永远是建立连接:

import carla

# 创建客户端,连接到本地服务器的2000端口
client = carla.Client('localhost', 2000)

# 设置超时时间,我习惯设10秒
client.set_timeout(10.0)

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

print("连接成功!")

你想想看,如果连不上,后面什么都干不了。所以超时时间别设太短,网络波动很正常。

3.3.2 世界与蓝图

世界对象代表整个仿真环境。蓝图(Blueprint)则是物体的模板,比如车辆、行人、传感器。

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

# 找一个特定的车辆蓝图
vehicle_bp = blueprint_library.find('vehicle.tesla.model3')

# 或者随机选一个
spawn_point = world.get_map().get_spawn_points()[0]

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

print(f"生成了车辆:{vehicle.type_id}")

小技巧:我建议你先把蓝图库打印出来看看,熟悉一下有哪些车型和传感器。用 print(blueprint_library.filter('vehicle.*')) 就能过滤出所有车辆。

3.3.3 控制车辆

生成车辆后,怎么让它动起来?通过控制指令:

# 创建控制对象
control = carla.VehicleControl()

# 设置油门和转向
control.throttle = 0.5  # 50%油门
control.steer = -0.3    # 左转

# 应用控制
vehicle.apply_control(control)

# 让仿真跑几步
for _ in range(100):
    vehicle.apply_control(control)
    world.tick()  # 推进一帧

注意,world.tick() 是手动推进仿真。如果你不调用,世界是静止的。我记得刚开始做的时候,忘了加tick,车死活不动,查了半天才发现这个坑。

3.4 客户端与服务器模型:深入理解

咱们再深入聊聊这个模型。你可能会问:为什么非要搞成客户端-服务器?

原因有三:

  1. 并行开发:算法团队和仿真团队可以独立工作。服务器升级不影响客户端代码。
  2. 分布式部署:服务器跑在GPU服务器上,客户端跑在普通PC上,甚至可以在Jupyter Notebook里写代码。
  3. 多语言支持:虽然官方推荐Python,但理论上任何支持TCP/IP的语言都能写客户端。

3.4.1 同步模式 vs 异步模式

这是个大坑,我详细说说。

  • 同步模式:客户端调用 world.tick() 后,服务器才推进一帧。适合需要精确控制的场景,比如强化学习训练。
  • 异步模式:服务器自己按固定帧率跑,客户端只管收数据。适合数据采集,但控制精度差一些。
# 设置为同步模式
settings = world.get_settings()
settings.synchronous_mode = True
settings.fixed_delta_seconds = 0.05  # 20 FPS
world.apply_settings(settings)

# 之后必须手动tick
world.tick()

注意:我曾经在异步模式下做控制,结果发现车辆反应延迟了200ms。后来改成同步模式,问题就解决了。所以,如果你做精确控制,一定要用同步模式。

3.4.2 多客户端场景

一个服务器可以连多个客户端。比如:

# 客户端1:控制主车
client1 = carla.Client('localhost', 2000)
world1 = client1.get_world()

# 客户端2:监控传感器
client2 = carla.Client('localhost', 2000)
world2 = client2.get_world()

# 两个客户端操作同一个世界
# 但要注意,不要同时修改同一个actor

嗯,这个特性在测试V2X场景时特别有用。一个客户端模拟主车,另一个模拟路侧单元。

3.5 实战:跑通第一个仿真

光说不练假把式。咱们写个完整的例子,把上面讲的串起来。

import carla
import random
import time

def main():
    # 连接服务器
    client = carla.Client('localhost', 2000)
    client.set_timeout(10.0)
    world = client.get_world()
    
    # 设置同步模式
    settings = world.get_settings()
    settings.synchronous_mode = True
    settings.fixed_delta_seconds = 0.05
    world.apply_settings(settings)
    
    # 生成车辆
    blueprint_library = world.get_blueprint_library()
    vehicle_bp = random.choice(blueprint_library.filter('vehicle.*'))
    spawn_point = random.choice(world.get_map().get_spawn_points())
    vehicle = world.spawn_actor(vehicle_bp, spawn_point)
    
    print(f"生成了 {vehicle.type_id}")
    
    # 控制车辆前进
    control = carla.VehicleControl()
    control.throttle = 0.6
    
    # 跑100帧
    for i in range(100):
        vehicle.apply_control(control)
        world.tick()
        time.sleep(0.05)  # 模拟真实时间
        
        if i % 20 == 0:
            print(f"第 {i} 帧,车辆位置:{vehicle.get_location()}")
    
    # 清理
    vehicle.destroy()
    print("仿真结束")

if __name__ == "__main__":
    main()

这个例子虽然简单,但包含了连接、配置、生成、控制、清理的完整流程。你跑通了这个,后面学传感器、地图、交通流就顺了。

总结一下:CARLA的客户端-服务器模型,说白了就是「服务器管世界,客户端管逻辑」。你只要记住三步:连服务器、拿世界、操作Actor。剩下的,都是细节。

好,这一章就到这儿。下一章咱们开始玩传感器——摄像头、激光雷达、GPS,一个都不能少。