1. 项目概述:CARLA-SUMO联合仿真下的强化学习换道决策系统
在自动驾驶技术快速发展的今天,如何让车辆在复杂交通场景中做出安全高效的换道决策一直是核心挑战。这个项目通过整合CARLA高保真驾驶模拟器和SUMO宏观交通仿真器的优势,构建了一个完整的强化学习换道决策系统。不同于单一仿真环境,这种联合方案既能获得精确的车辆动力学反馈(CARLA),又能模拟真实的大规模交通流(SUMO),为算法训练提供了接近现实的测试场。
我在实际开发中发现,这种双仿真器架构特别适合处理换道决策这类需要兼顾微观操作和宏观交通影响的场景。CARLA提供毫米级精度的传感器数据和车辆控制接口,而SUMO则能生成包含数百辆车的复杂交通状况。当两者通过TraCI接口实时同步时,强化学习智能体获得的观察空间和奖励函数设计维度会显著丰富。
2. 系统架构设计与关键技术选型
2.1 CARLA与SUMO的协同工作机制
联合仿真的核心在于建立两个仿真器间的双向通信管道。具体实现时,我们采用SUMO作为主时钟,通过TraCI的Python API控制仿真步进。每完成一个SUMO仿真步(通常设为0.1秒),通过自定义的桥梁模块将SUMO中的车辆位置映射到CARLA世界坐标系。这里需要特别注意坐标转换的精度问题——我建议使用UTM坐标系作为中间转换基准,避免直接使用经纬度导致的累计误差。
对于CARLA生成的ego车辆(即我们的学习主体),其控制指令会实时反馈给SUMO。这种设计使得SUMO中的其他车辆能对ego车辆的行为做出反应,形成动态交互。在实际编码中,我封装了一个SyncManager类来处理两个仿真器的时间同步,关键代码如下:
class SyncManager: def __init__(self, carla_world, sumo_net): self.carla = carla_world self.sumo = sumo_net self.step_count = 0 def sync_step(self): # SUMO先行步进 self.sumo.simulationStep() # 获取SUMO车辆状态并更新CARLA sumo_vehicles = self.sumo.vehicle.getIDList() for vid in sumo_vehicles: if vid != 'ego': # 排除学习主体 pos = self.sumo.vehicle.getPosition(vid) carla_transform = convert_to_carla(pos) self.carla.update_vehicle(vid, carla_transform) # ego车辆状态回传SUMO ego_state = self.carla.get_ego_state() self.sumo.vehicle.moveToXY('ego', ego_state.lane_id, ego_state.x, ego_state.y) self.step_count += 12.2 强化学习框架选型对比
经过对主流框架的实测比较,我们最终选择Ray RLlib作为基础框架,主要基于以下考量:
- 对多GPU训练的原生支持(相比stable-baselines3更高效)
- 内置的PPO算法在连续动作空间任务中表现稳定
- 易于扩展的Policy和Model接口
在算法选择上,PPO(Proximal Policy Optimization)因其样本效率和训练稳定性成为首选。针对换道决策的特性,我对标准PPO做了三点改进:
- 在价值函数中增加了邻车预测误差项
- 采用分段式的奖励函数设计
- 添加了动作平滑惩罚项
具体网络架构采用双流输入设计:一个分支处理CARLA的BEV(鸟瞰图)图像,使用轻量化的EfficientNet提取特征;另一个分支处理SUMO提供的结构化交通数据(车距、相对速度等),通过全连接层编码。两个特征向量在中间层融合后输入LSTM,以捕捉时序依赖。
3. 环境建模与状态空间设计
3.1 多源感知数据融合
状态空间的设计直接影响学习效率。我们整合了以下数据源:
CARLA侧:
- 前视相机RGB图像(256×256)
- LiDAR点云(降采样到2048个点)
- 车辆IMU数据(加速度、角速度)
SUMO侧:
- 车道级交通密度(前后50米范围内)
- 邻车相对运动状态(最多跟踪6辆车)
- 交通信号灯状态(如可见)
特别重要的是如何表示周围车辆的影响。经过多次实验,我发现采用极坐标系表示相对位置比笛卡尔坐标系训练收敛更快。具体来说,对于每辆邻车记录:
- 距离ρ ∈ [0,150]米
- 方位角φ ∈ [-π,π]
- 相对速度Δv ∈ [-20,20] m/s
这种表示方式对旋转和平移具有更好的不变性。在实际编码时,建议对连续值进行Min-Max归一化,离散值(如信号灯状态)使用one-hot编码。
3.2 奖励函数工程
奖励函数是引导智能体学习的关键。我们的设计包含五个核心组件:
R_t = w_1R_{safety} + w_2R_{efficiency} + w_3R_{comfort} + w_4R_{rule} + w_5R_{smooth}其中各分量的计算方式如下:
| 分量 | 计算公式 | 说明 |
|---|---|---|
| 安全奖励 | $R_{safe} = -e^{d_{min}/5}$ | d_min为与最近车辆距离 |
| 效率奖励 | $R_{eff} = v_x/30$ | 鼓励保持接近限速(30m/s) |
| 舒适惩罚 | $R_{comf} = - | a_y |
| 规则惩罚 | $R_{rule} = -10·I_{violate}$ | 交通违规指示函数 |
| 平滑惩罚 | $R_{smooth} = - |
权重系数通过网格搜索确定为:w1=0.5, w2=0.3, w3=0.1, w4=0.05, w5=0.05。注意安全奖励采用指数形式,会在危险距离时产生陡峭的惩罚梯度,这对避免碰撞非常有效。
4. 训练流程与核心实现细节
4.1 分布式训练架构
为提高数据采集效率,我们部署了多实例仿真环境。具体配置:
- 每个worker节点运行独立的CARLA-SUMO联合实例
- 使用Redis作为经验回放池的中间件
- 参数服务器采用Ring-AllReduce架构同步梯度
在Ubuntu 18.04上的启动命令示例:
ray start --head --port=6379 --redis-password='carla_sumo' python train.py --num-workers 8 --gpus-per-worker 0.25关键配置参数:
train_batch_size: 4000 sgd_minibatch_size: 512 num_sgd_iter: 10 gamma: 0.99 lambda: 0.95 clip_param: 0.2 lr: 3e-44.2 课程学习策略
为应对复杂交通场景,我们设计了分阶段训练方案:
空场景基础控制(10k steps)
- 仅ego车辆,学习基本车道保持
- 奖励函数仅含效率和舒适项
简单交互场景(50k steps)
- 添加5-10辆背景车
- 引入安全奖励和规则惩罚
密集车流挑战(100k+ steps)
- 车流密度达到40辆/km
- 添加突发cut-in事件
- 启用完整奖励函数
这种渐进式训练可避免早期探索时的灾难性失败。实测表明,相比直接训练,课程学习能提升约35%的最终成功率。
5. 验证与性能分析
5.1 测试场景设计
我们构建了三种典型测试场景:
- 高速公路合流:入口匝道处决策
- 拥堵跟车:前车频繁加减速
- 紧急避障:静态障碍物突然出现
每个场景运行100次episode,统计以下指标:
- 成功率(无碰撞完成目标)
- 平均行程时间
- 最大横向加速度
- 违规次数(压线、逆行等)
5.2 基准对比结果
与规则基方法和模仿学习的对比如下:
| 方法 | 成功率 | 舒适度 | 效率 |
|---|---|---|---|
| 规则基 | 72% | 2.1m/s² | 85% |
| 模仿学习 | 81% | 1.8m/s² | 92% |
| 我们的RL | 94% | 1.5m/s² | 96% |
特别值得注意的是,在cut-in场景中,我们的方法表现出更好的预见性。通过分析价值函数的热力图,可以发现智能体提前2-3秒就开始对潜在危险区域产生警惕。
6. 部署优化与实车迁移
6.1 模型轻量化
为满足实时性要求(<100ms推理延迟),我们进行了以下优化:
- 将EfficientNet替换为MobileNetV3
- 量化模型权重至FP16
- 使用TensorRT加速
优化前后对比:
| 版本 | 参数量 | 推理时延 | 成功率 |
|---|---|---|---|
| 原始 | 12.3M | 78ms | 94% |
| 优化 | 4.7M | 32ms | 93% |
6.2 域适应技巧
仿真到实车的gap主要来自感知差异。我们采用以下应对措施:
- 在CARLA中添加相机噪声(高斯+运动模糊)
- 使用CycleGAN转换图像风格
- 在奖励函数中增加感知不确定性惩罚
实际测试表明,经过域适应训练的模型在实车测试中碰撞率可降低40%以上。
7. 常见问题与调试心得
Q1:SUMO车辆出现位置跳变
- 原因:坐标转换时未考虑高程变化
- 解决:在convert_to_carla()函数中加入DEM查询
Q2:训练初期策略过于保守
- 现象:车辆始终低速行驶
- 调试:调整奖励函数中效率项的权重曲线
- 改为:$R_{eff} = tanh(v_x/25)$
Q3:多车场景内存泄漏
- 诊断:CARLA PythonAPI的actor未及时销毁
- 修复:在每个episode后显式调用destroy()
经验总结:
- 始终监控SUMO的fcd输出,确保时间同步正常
- 定期可视化价值函数,理解策略决策依据
- 使用tensorboard记录原始奖励分量,便于调参
- 对连续动作空间,输出分布比确定值更稳定
这个项目的完整代码已结构化组织为以下模块:
/src /configs # 参数配置文件 /envs # 仿真环境封装 /models # 网络结构定义 /utils # 工具函数 train.py # 主训练脚本 eval.py # 性能评估