
第一次启动Carla敲下那条熟悉的启动命令地图在UE引擎里慢慢加载出来街道上的车辆和行人开始流动那一瞬间很难不把它当游戏看。实际上Carla是当前自动驾驶研发里使用频率最高的开源模拟器之一它的定位就是Self-Driving Car Simulation一个提供城市级道路环境、多类传感器模拟、可编程交通流和车辆动力学接口的仿真平台。这篇7-1的Carla Overview聊的不是某个具体算法怎么实现而是把Carla整体框架讲清楚包括它解决什么问题、架构怎么分层、传感器有哪些、怎么快速跑通一个最小自动驾驶闭环以及在真实项目里最值得注意的坑。如果你正准备做感知、规划控制或数据生成这篇内容可以把头开起来。1. 为什么选Carla做自动驾驶仿真先算清安全和成本这两笔账1.1 一个模拟器解决的真实需求安全、成本、复现性自动驾驶算法做得再漂亮也不能直接扔到开放道路上试验。一条真实的研发测试路线上跑一次可能涉及安全员、测试申请、车辆损耗遇到一个危险场景甚至只能紧急接管。换句话说实车测试的成本不是“油钱”而是风险和时间。在项目早期团队关心的往往不是“能不能跑”而是“敢不敢让它跑”。让一辆配备激光雷达、多路相机和高性能计算单元的测试车在雨天十字路口做出激进变道绝大多数人都没这个胆量。但Carla里随时可以这么干把车开到极限、让它撞上路沿、让行人突然横穿重置场景之后再来一次。撞坏一辆虚拟车只需要点一下重置。成本方面算一笔账更好理解。一台带线控底盘、毫米波雷达、多相机和计算平台的研发测试车加起来几十万起步而Carla是开源的不需要授权费只要能带得动UE渲染的GPU就能跑。对个人开发者和小团队来说这是很长一段时间里唯一能负担得起的“城市级路测环境”。还有一点容易被忽略复现性。真实道路上出事往往靠运气同一个恶劣天气下的鬼探头想用实车复现基本看缘分。但在Carla里场景是一组参数地图、天气、交通密度、行人路径都可以固定同一个bug可以在同一条街道上反复复现修完再跑同样的测试用例做回归。这种“确定性”对调试感知模型和控制逻辑至关重要。1.2 Carla在自动驾驶技术栈里的卡位连接感知、规划、控制的闭环验证一个完整的自动驾驶系统通常分成感知、预测、规划、控制四层。Carla不替你做这些算法它提供的是让整套算法“动起来”的城市环境以及能产生传感器数据的接口。比如你的感知模型要从相机图上输出目标框Carla会按照你设定的相机参数和环境光照生成带深度信息的RGB图像你的规划模块要在道路网上找一条可行驶轨迹Carla的地图会给你车道、交叉路口、信号灯和路缘数据控制模块要输出油门、刹车、转向Carla的车辆模型会真的把这辆车在虚拟物理世界里推出去。整条链路在仿真环境里是闭环的这是很多单点仿真工具做不到的。用一句话概括Carla是算法和世界之间的“公共接口”。它把真实世界中需要用昂贵硬件和复杂传感系统才能得到的东西抽象成一组可以写进Python代码里的对象和API。1.3 和AirSim、SUMO这些仿真器比Carla的取舍在哪里很多人会问市面上的仿真器那么多为什么偏偏先学Carla这不是没有道理的选择题。AirSim同样基于UE引擎在飞行器和单机感知研究里做得很好但它的城市级场景、道路网规则和自动驾驶相关的交通流支持明显没有Carla那么成体系。SUMO则完全是另一条路线擅长路网交通流和路口信号协调能模拟上万辆车但它没有像素级传感器也没有车辆动力学意义上的“驾驶”你要验证摄像头感知算法在SUMO里无从下手。PreScan和CarSim是成熟的商业工具精度高、和行业工具链集成好但价格和授权方式对个人用户很不友好。Carla的取舍在于它同时照顾了“环境真实性”和“接口便利性”。有UE引擎提供的渲染质量有OpenDRIVE标准道路网有丰富传感器模型还有Python API可以直接操控。它不追求单一维度的极致精度但作为通用自动驾驶仿真底座综合成本最低。当然代价也有——体量大、启动重、对GPU要求高这些后面会聊。2. Carla整体架构与核心概念服务端、客户端、蓝图和地图2.1 服务端-客户端模型一个负责渲染世界一个负责写控制逻辑Carla的架构很容易理解但也是很多新手绕不过去的第一个坎。它分两个独立进程服务端是CarlaUE4负责渲染城市、跑物理引擎、计算传感器数据、维护交通流客户端是Python进程通过CARLA PythonAPI连接服务端创建角色、挂载传感器、下发控制命令。端口默认2000客户端通过carla.Client(localhost, 2000)连接。开一个服务端可以同时被多个客户端连接这个设计对并行训练很有用一台带强GPU的机器跑服务端另外几台机器各自跑客户端算法任务。我平时做数据生成时会在一台机器上开三四个Carla实例端口分别设为2000、3000、4000每个实例负责不同地图天气组合。客户端和服务端是一对多的关系版本必须严格匹配。0.9.15的客户端去连0.9.14的服务端大概率会直接报版本错误即使不报错某些API行为和传感器数据格式也可能有差异。每下载一个Carla压缩包解压后PythonAPI/carla/dist目录下会有一个egg文件文件名里带了Python版本信息这个文件的路径一定要加进PYTHONPATH否则import carla直接失败。2.2 蓝图、Actor、Spawn这些概念到底在说什么Carla把世界里的所有可操作对象都抽象成Actor车辆、行人、传感器、交通灯、路面标记都是Actor。创建Actor不是直接实例化而是从BlueprintLibrary里挑一个蓝图Blueprint再生成。蓝图相当于“物种库”vehicle.audi.etron是奥迪e-tronsensor.camera.rgb是RGB相机walker.pedestrian.0001是某一种行人外观。我在最开始接触Carla时总把蓝图当成普通对象模板其实它更像生物分类同一个车型蓝图可以生成多辆车每辆车又是独立的Actor。修改蓝图属性会影响以后生成的所有Actor已生成的Actor不受影响。生成Actor的动作叫spawn_actor。车辆和行人一般需要给定一个Transform位置和朝向传感器则通常不直接独立存在而是用attach_to挂到车辆或行人身上跟随宿主移动。一个典型操作是给车挂相机world.spawn_actor(camera_bp, camera_transform, attach_tovehicle)挂在车顶的相机就随着车辆一起动作传感器坐标相对宿主不变。2.3 地图、道路网与OpenDRIVE场景不是贴图而是一套可查询的数据Carla官方地图从Town01一直到Town15每张地图都有自己的性格。Town01是最简单的直线路网Town02带环形交叉口Town03混合城区场景Town04是小镇布局Town05专门设计了复杂的十字路口和车道变化。做算法初测时我最常用Town03道路丰富又不至于太难做终点测试或者比赛类场景再切换到更复杂的地图。地图底层的道路描述是OpenDRIVE格式.xodr文件这是一种公开的道路网描述标准。它定义了每条车道的几何形状、车道数量、宽度、速度限制、路口连接关系和信号灯位置。Carla把道路网当成结构化数据提供这意味着你的规划算法可以直接查询world.get_map().get_spawn_points()拿到合法生成点也可以用map.get_waypoint_xodr()拿到指定坐标最近的车道点。理解这点很重要Carla里的“场景”不是一个图片文件夹而是一套可以被算法的坐标系、查询、路线规划使用的路网数据库。地图的可编辑性也很强可以用RoadRunner导入自建的高精地图或OpenDRIVE文件也可以直接对地图做局部修改。不过做自定义地图时要注意坐标对齐、车道连接逻辑这些细节这是另一个大坑建议从官方自带Town地图上手。3. 传感器模拟的硬核细节把虚拟数据当成真实数据用3.1 相机传感器RGB、深度、语义分割、光流各有什么思路Carla里最常用的传感器就是相机。从蓝图库里可以找到sensor.camera.rgb、sensor.camera.depth、sensor.camera.semantic_segmentation和sensor.camera.optical_flow四类。RGB相机和普通相机一致核心参数是分辨率image_size_x和image_size_y、视场角fov还有一个sensor_tick控制采集频率。新手最容易犯的错是调整相机高度和位置随意导致后续感知模型的标定关系对不上。我常用的默认配置是1280x720、fov 90挂在车顶前方2.4米高度看起来高度很随意但后续做相机-车辆坐标变换时方便。深度相机和语义分割相机有个关键点直接从回调里拿到的图像不能直接用先要调用image.convert(carla.ColorConverter.Depth)或carla.ColorConverter.CityScapesPalette转成可视化形式。特别是语义分割转换后的像素值对应Cityscapes的19类语义标签这是很多语义分割训练数据的标准格式。从Carla生成数据集核心流程就是把原始图像和转换后的语义图成对保存后面训练网络时直接用。光流相机输出的是每个像素的运动向量场这在做运动预测和视觉里程计任务时会用到。它返回的不是普通图像而是带浮点分量的向量场需要自己解析水平垂直光流分量。使用前最好先跑官方文档里的光流示例确认数据结构别急着直接接到自己的光流模型里。3.2 LiDAR与毫米波雷达点云和稀疏检测数据的典型特征激光雷达是自动驾驶感知里最“实在”的传感器Carla的LiDAR模拟也会给出一帧帧点云数据。关键参数有四个channels通道数64线、128线常见、range最远量程默认50米可以拉到100米甚至更多、points_per_second每秒点数以及rotation_frequency扫描频率。我一般把64线、100米量程、每秒100万点和10Hz扫描作为标准配置因为这是一套接近真实中距离雷达的组合。点云数据中每个点包含x,y,z,intensity坐标系原点是传感器挂载点x指向车头。做目标检测算法时要把点云转到车辆坐标系再考虑去地面、聚类、目标框回归这些常规操作和真实雷达数据是一套处理逻辑。毫米波雷达在Carla里是sensor.other.radar返回的每个测量点带azimuth、altitude、depth距离和velocity相对速度。它的特点是稀疏、噪声比较明显和真实雷达输出一致。做雷达的目标列表或者融合时别期望它像LiDAR一样密雷达本身的价值在于直接给速度信息。Carla的雷达设定频率一般是20Hz比相机更高在做时序融合时要注意帧率对齐。3.3 GNSS/IMU与传感器坐标系做融合前必须整明白的尺子Carla里汽车的坐标系定义很特别x轴向前y轴向左z轴向上。这一点和很多车辆工程里的坐标系习惯一致但和某些设备坐标系不一样。做传感器外参标定时多花五分钟确认坐标系方向能省下半天调bug的时间。GNSS和IMU解决的是“车在哪”和“车姿态怎么变”的问题。GNSS输出经纬高还可以设置噪声标准差模拟真实信号抖动IMU输出加速度、角速度和指南针方向。这两类传感器通常不需要挂到具体车辆上直接以自身位置生成但要注意IMU的输出频率通常高于GNSS数据融合时要先统一时间戳。最容易被坑的是“同步问题”。如果你在异步模式下同时采集相机图像和LiDAR点云两者时间戳对不上会直接影响融合效果。后面我会专门讲同步模式这是做数据生成和评估时最重要的配置项没有之一。4. 新手必看的实操全流程从空地图跑到一个自动驾驶闭环4.1 环境准备与版本安装Linux下最省心的组合Carla的安装没有想象中复杂但也不能太随意。官方通常提供压缩包解压到任意目录就能启动。我的建议是直接在Linux下跑Ubuntu 20.04或者22.04都可以显卡驱动和CUDA先确认好。Windows也能跑但在多实例、Python环境兼容和底层调试上会多出不少额外麻烦。安装依赖有两个重点一是把PythonAPI里的egg文件路径加入环境变量二是装好必要的Python库。以0.9.15为例解压后目录里会有PythonAPI/carla/dist/carla-0.9.15-py3.10-linux-x86_64.egg如果你的Python是3.10执行export CARLA_ROOT~/carla export PYTHONPATH$CARLA_ROOT/PythonAPI/carla/dist/carla-0.9.15-py3.10-linux-x86_64.egg:$CARLA_ROOT/PythonAPI/carla:$PYTHONPATH pip install numpy pygame opencv-python启动服务端时如果机器显存比较紧张建议加上低质量参数./CarlaUE4.sh -quality-levelLow这一条指令可以让渲染分辨率降下来对跑算法逻辑影响不大但显存占用明显变小。我第一次用老显卡跑Town03卡到几乎没法操作加上-quality-levelLow之后整个画面立刻流畅了实测下来对传感器数据的内容影响很小。如果GPU性能足够不开也行画面质量和真实感会更好。4.2 最小可用脚本生成车辆、挂载相机、下发第一脚油门跑一个能动的Carla程序其实只要几个核心步骤创建客户端、加载地图、选蓝图、生成车辆、挂相机、循环控制。我写个最小示例你可以直接复制去跑import carla import random import time # 1. 连接服务端 client carla.Client(localhost, 2000) client.set_timeout(20.0) # 2. 加载地图 world client.load_world(Town03) time.sleep(5) # 等地图加载完成简单粗暴但有效 # 3. 获取蓝图库选一辆车 bp_lib world.get_blueprint_library() vehicle_bp random.choice(bp_lib.filter(vehicle.*)) # 4. 选一个生成点生成车辆 spawn_points world.get_map().get_spawn_points() spawn_point random.choice(spawn_points) vehicle world.try_spawn_actor(vehicle_bp, spawn_point) if vehicle is None: spawn_point spawn_points[0] vehicle world.spawn_actor(vehicle_bp, spawn_point) # 5. 挂载一个RGB相机 camera_bp bp_lib.find(sensor.camera.rgb) camera_bp.set_attribute(image_size_x, 1280) camera_bp.set_attribute(image_size_y, 720) camera_bp.set_attribute(fov, 90) camera_transform carla.Transform(carla.Location(x1.5, z2.4)) camera world.spawn_actor(camera_bp, camera_transform, attach_tovehicle) # 6. 回调里保存图像 camera.listen(lambda image: image.save_to_disk(fout/{image.frame:06d}.png)) # 7. 给一脚油门看看车动不动 for _ in range(100): vehicle.apply_control(carla.VehicleControl(throttle0.5, steer0.0, brake0.0)) time.sleep(0.1)这个脚本每一步都有它的意义。load_world后面加延时是为了避免地图还没加载完就去查询生成点try_spawn_actor则是因为部分生成点被占用时会返回None相机挂载到车上位置相对车辆不变这样图像会随着车辆移动而移动才像“从车上拍的”。你可能注意到我这里没有做感知没有做规划只是让车自己往前开。但这就是一个基础闭环后面所有复杂的东西都是往这里面填模块。建议第一次接触Carla的新手先把这个脚本跑通再考虑加其他传感器和上层算法。4.3 Traffic Manager让NPC车流和行人有“意识”单独一辆车往前开是很无聊的真实的自动驾驶测试需要周围有“会犯错的车和行人”。Carla里让NPC车辆自动驾驶的核心是Traffic Manager它是一套内置的交通流管理模块会控制NPC车辆以合理的速度跟车、变道、等红绿灯。使用方法也不复杂tm_port 8000 tm client.get_trafficmanager(tm_port) # 让一批车自动行驶 for npc in npc_list: npc.set_autopilot(True, tm_port) # 调整交通流参数 tm.set_global_distance_to_leading_vehicle(2.0) # 前车距离 tm.set_desired_speed(npc, 8.0) # 固定某辆车速度 tm.ignore_lights_percentage(npc, 10) # 10%概率闯红灯制造危险场景set_autopilot(True, tm_port)里的端口必须和创建Traffic Manager时一致这一点特别容易写错。写错后的表现是没有报错但NPC车完全不动或者只在原地打转。行人Autopilot和车辆略有不同。行者需要用一个AI控制器来控制先生成行人的Actor再绑定controller.ai.walker控制器然后调用控制器启动。我做行人横穿场景时会先生成目标行人再用控制器设置目标点和速度让它在指定时刻动起来这样能精确复现“鬼探头”场景。这里细节较多建议参考官方教程里的行人示例代码。4.4 同步模式与数据采集为什么生成训练数据必须开同步这是我认为Carla里最影响数据质量的一个开关。默认的异步模式服务端按自己的节奏实时渲染客户端发一条控制指令后图像和点云到达的时间会有差异。做可视化无所谓但做训练数据集比如相机和LiDAR要融合时间对不上就是灾难。解决方案是同步模式settings world.get_settings() settings.synchronous_mode True settings.fixed_delta_seconds 0.05 # 物理步长50ms即20Hz world.apply_settings(settings) for i in range(1000): world.tick() # 手动触发一帧所有传感器在同一时刻采集fixed_delta_seconds设成0.05表示每次tick固定推进50毫秒这样帧率是稳定的传感器数据的时间戳也是确定性的。代价是如果你忘了调用world.tick()程序会卡住不动这是新手最常见的同步模式事故现场。我在这个模式下采集过一段时间的数据做物体检测效果明显比异步好。不光因为时间戳对齐还因为你可以精确控制车辆每一步的油门刹车方便生成连续的控制标签。做完记得恢复异步模式否则退出程序时Carla可能一直停在卡死状态。5. 常见问题与排查技巧实录5.1 高频故障速查表我把做Carla项目和帮别人排查时遇到的高频问题整理成一张表照着排查能省很多时间问题现象可能原因解决思路import carla报错或找不到模块egg路径没加进PYTHONPATH确认egg文件名中的Python版本export到当前终端客户端连接失败服务端没启动/端口占用检查端口2000换端口启动或杀旧进程加载地图很久没反应编译着色器或显存不足第一次运行有编译过程等几分钟加-quality-levelLow车辆生成失败返回None生成点被占用换其他SpawnPoint或用try_spawn_actor循环尝试画面正常但NPC车不动Traffic Manager端口不匹配确认set_autopilot里的端口和get_trafficmanager端口一致同步模式下程序卡住忘记调world.tick()进入同步模式后每帧必须手动tick语义分割图颜色不对没转换调色板调用convert(carla.ColorConverter.CityScapesPalette)LiDAR点数太少points_per_second太低提高到50万或100万点/秒5.2 新手最容易忽略的三个隐性雷区第一个雷区Python版本和服务端版本不匹配。Carla的egg文件名会带Python版本号比如carla-0.9.15-py3.10如果你的Python解释器是3.8直接import会失败。遇到这个问题最简单的做法不是硬凑环境而是查看官方对版本的支持矩阵换对Python版本。第二个雷区多实例并行时的资源配置。Carla多开对显存特别敏感我遇到过开两个实例后其中一个直接黑屏。解决办法是每个实例都用低质量启动参数尽量减少车辆和行人总数同时给不同实例分配不同的GPU。在服务器上跑时用CUDA_VISIBLE_DEVICES隔离开比一个显卡满载然后崩溃要踏实得多。第三个雷区传感器数据里的“无效帧”。Carla里传感器在刚挂载的前几帧可能返回空数据尤其是LiDAR和Radar。我在做数据采集脚本时加一个跳过前20帧的逻辑避免把空点云写进数据集里。有人会忽略这个小细节结果训练时出现大量空白特征模型性能莫名其妙下降。6. 仿真和实车结合的个人经验与新手指南6.1 先跑虚拟回归测试再上公开数据集最后才是实车我刚做自动驾驶时有一个习惯现在看是很危险的模型在公开数据集上表现不错就直接想往实车上搬。后来一个在行业里做了多年的朋友告诉我一个流程先让模型在Carla里跑固定路线回归测试每次改完网络都跑一遍相同的虚拟路线记录mAP、平均碰撞次数、违规次数这些指标曲线有异常就说明什么地方退化了。这个习惯我一直保持到现在。Carla的价值不在于替代真实道路测试而是把“回归测试”的成本降到零。真实路测一次都要耗费大量资源但模拟器里你可以准备固定10条路线每次改代码后几分钟跑完快速看指标变化。一个小技巧把所有固定路线和天气写成一个JSON配置文件跑回归测试时读取配置循环执行。这样每次测试的随机性很小对比结果才有意义。6.2 用Carla做强化学习环境的一套粗浅经验Carla也经常被用来做强化学习训练。开源社区里已经有把Carla封装成Gym环境的项目方便接入Stable-Baselines3这类库。奖励函数怎么设是个大学问我的粗浅经验是不要只奖励“前进距离”要同时惩罚“偏离车道”“碰撞”“时间延迟”否则训练出来的车学会原地转圈赚奖励看起来像很聪明实际就是个“刷分机”。仿真环境训练出来的策略直接搬到实车几乎不可能存在典型的sim-to-real gap。光照、路面摩擦、传感器噪声都有差异。比较务实的做法是在Carla里用强化学习做策略预训练让模型先学会基本驾驶行为再用真实数据做微调或行为约束而不是指望一个纯仿真模型直接上实车。6.3 从模拟器到实车怎么判断“仿真过”到底有没有意义很多人把“仿真测试通过了”视为“实车一定能过”这是对模拟器最大的误解。反过来仿真测试都过不了实车大概率更惨因为真实世界的不确定性只会更多。所以仿真测试的定位应该是“过滤低级错误”。我用Carla判断模型质量时会关注两个指标一是极端天气下的表现比如把雨天、雾天、夜晚综合起来跑看传感器数据里的目标是否还能保持稳定二是先验知识能不能结合比如地图先验信息是否被正确注入到模型里而不是简单堆更多网络层。7. 最后分享几点实际操作的体会装好Carla很容易但把Carla用好需要有一些项目级的思维。我自己在跑仿真数据时一定会在脚本里加入随机的种子控制这样既能让同一场景重复复现又能通过修改种子生成大量相似但不完全相同的训练样本。一个固定的随机种子往往对应一个完全确定的场景序列做数据增强和测试回归都很方便。很多同学问我“上手Carla多久能跑通”我的答案是如果只是跑通最小闭环一个下午都够了但如果你要做传感器融合、规划控制或强化学习至少需要一周把API和官方案例过一遍。刚开始不要追求把所有地图、所有传感器都试一遍先用一张地图、一个相机、一个LiDAR跑通整个“采集-处理-训练-评估”流程再慢慢扩展。还有一点是我踩过几次坑之后总结出来的Carla的官方示例代码一定要动手敲一遍不要只是看。很多细节只有在实际运行出错时才会意识到比如时间同步的顺序、坐标系的转换、地图加载的等待时长。写在这里的每一条经验几乎都对应过一次真实的踩坑过程。工具本身是免费的真正值钱的是自己试错之后沉淀下来的流程和方法。