2. 世界与客户端:理解CARLA世界、客户端-服务器架构、连接与断开连接

好,咱们正式开始动手了。这一章,我带你搞清楚CARLA最核心的两个东西——世界(World)和客户端(Client)。

说白了,CARLA就是一个典型的客户端-服务器(C/S)架构。你电脑上跑的那个带画面的程序是服务器,你写的Python脚本是客户端。客户端发指令,服务器执行并返回结果。嗯,就是这么简单。

2.1 客户端-服务器架构:谁在干活?

我第一次接触CARLA时,也纳闷过:为什么非要搞成C/S架构?直接在脚本里控制一切不香吗?

后来我明白了。你想想看,仿真场景里可能有几十辆车、几百个行人、复杂的传感器数据。如果所有计算都在一个进程里,CPU和内存根本扛不住。C/S架构的好处是:服务器负责渲染和物理计算,客户端负责逻辑控制。各干各的,互不干扰。

核心关系图:

CARLA 服务器 渲染引擎 物理引擎 世界状态管理 Python 客户端 发送指令 接收数据 控制逻辑 指令(控制) 数据(状态) 客户端发送指令 → 服务器执行并返回结果 通常运行在同一台机器上,通过 localhost:2000 通信

我个人习惯把服务器看作一个「黑盒」。你不需要知道它内部怎么渲染画面、怎么计算碰撞,你只需要通过客户端给它发消息就行。

2.2 连接与断开:你的第一个脚本

好,咱们直接写代码。这是你接触CARLA的第一个脚本,我建议你亲手敲一遍。

import carla

# 创建客户端,连接到本地服务器
# 默认端口是2000,超时时间设为10秒
client = carla.Client('localhost', 2000)
client.set_timeout(10.0)

print("客户端已创建,正在连接服务器...")

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

print("连接成功!当前世界名称:", world.get_map().name)

# 断开连接(其实Python脚本结束时会自动断开)
# 但养成好习惯,显式断开
client.disconnect()
print("已断开连接。")

这段代码干了三件事:创建客户端、获取世界、断开连接。就这么简单。

💡 小技巧: 如果你不确定服务器是否在运行,可以在创建客户端后调用 client.ping() 来测试连通性。返回 True 说明服务器活着。

2.3 世界对象:一切仿真的起点

获取到 world 对象后,你就能操控整个仿真环境了。世界对象是CARLA里最顶层的对象,它包含了:

  • 地图(Map):当前加载的地图信息,比如道路、交叉口、车道线
  • 参与者(Actors):所有车辆、行人、传感器等动态物体
  • 天气(Weather):晴天、雨天、雾天等环境参数
  • 设置(Settings):仿真步长、同步模式等

我在项目中遇到过一个问题:获取世界后直接操作,结果发现地图还没加载完。后来我加了个等待循环,确保世界状态稳定后再操作。

# 等待世界稳定(地图加载完成)
world.wait_for_tick()
print("世界已就绪,可以开始操作。")

2.4 常用客户端方法速查

下面这个表格,是我平时用得最多的客户端方法。你记不住没关系,用到时回来查就行。

方法 说明 示例
carla.Client(host, port) 创建客户端对象 client = carla.Client('localhost', 2000)
set_timeout(seconds) 设置超时时间(秒) client.set_timeout(10.0)
get_world() 获取当前世界对象 world = client.get_world()
load_world(map_name) 加载指定地图 client.load_world('Town01')
reload_world() 重新加载当前地图 client.reload_world()
get_available_maps() 获取所有可用地图列表 maps = client.get_available_maps()
ping() 测试服务器是否在线 client.ping()
disconnect() 断开与服务器的连接 client.disconnect()

2.5 避坑指南:连接失败的常见原因

我曾经花了一下午排查一个问题:脚本运行后一直报连接超时。后来发现,我忘了启动CARLA服务器。嗯,这种低级错误,谁没犯过呢?

⚠️ 常见坑点:

  • 服务器没启动:先双击运行 CarlaUE4.exe(Windows)或 ./CarlaUE4.sh(Linux),再运行脚本
  • 端口被占用:默认端口2000,如果被其他程序占用,换个端口(比如2001)
  • 超时时间太短:第一次连接时,服务器可能需要加载资源,建议设置10秒以上
  • 防火墙拦截:确保防火墙允许本地回环地址(127.0.0.1)的通信

2.6 多客户端连接:一个服务器,多个脚本

CARLA支持多个客户端同时连接同一个服务器。这意味着你可以:

  • 一个脚本控制车辆
  • 另一个脚本控制行人
  • 第三个脚本采集传感器数据

它们互不干扰,共享同一个世界状态。我在做多车协同仿真时,就用到了这个特性——每个车一个客户端脚本,各自独立控制。

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

# 客户端2:控制行人
client2 = carla.Client('localhost', 2000)
client2.set_timeout(10.0)
world2 = client2.get_world()

# 注意:world1 和 world2 指向同一个世界
# 修改 world1 中的天气,world2 也会同步变化

📌 关键点: 多个客户端获取的 world 对象是同一个底层世界的不同引用。你对世界做的任何修改,所有客户端都能看到。

2.7 断开连接的正确姿势

虽然Python脚本结束时会自动释放资源,但我建议你养成显式断开连接的习惯。特别是在长时间运行的仿真中,不主动断开可能导致服务器端资源泄漏。

try:
    # 你的仿真逻辑
    world = client.get_world()
    # ... 各种操作 ...
finally:
    # 确保无论如何都会断开
    client.disconnect()
    print("客户端已安全断开。")

嗯,用 try...finally 包裹起来,是最稳妥的做法。我在写自动化测试脚本时,一定会加这个结构。

好了,这一章的内容就这些。你掌握了客户端和服务器的关系,学会了连接和断开,也知道了世界对象是什么。下一章,我们会在世界里放点东西——没错,就是车辆和行人。

💡 课后小练习: 写一个脚本,连接服务器后,打印出当前地图的所有可用地图名称(提示:用 get_available_maps())。然后加载一个你没用过的新地图,比如 Town03。

可可精品资料库