CARLA-SUMO 协同仿真强化学习框架:让自动驾驶汽车学会主动换道

基于 CARLA 与 SUMO 协同仿真架构,使用 PPO 算法训练自动驾驶车辆在混合交通流中自主决策换道。详解双仿真器同步机制、奖励函数设计与万步训练实验结果。

CARLA-SUMO 协同仿真强化学习框架:让自动驾驶汽车学会主动换道

1. 引言:为什么需要协同仿真?

训练自动驾驶换道策略,面临一个根本矛盾:

单独用任何一个,都不够。

如果只用 CARLA,背景交通稀疏,换道决策缺乏挑战性。如果只用 SUMO,车辆行为太”规矩”,无法学到真实的动力学响应。

于是,协同仿真成了最优解——CARLA 管主车的动力学,SUMO 管背景交通流,通过 TraCI 协议实时同步状态。这正是本项目的核心设计。

系统架构图

2. 系统架构:双仿真器是如何协同的?

2.1 并行架构

CARLA 和 SUMO 作为两个独立进程运行,通过 Python 接口(CARLA Python API + TraCI)进行通信。整个系统的数据流如下:

┌─────────────┐      TraCI      ┌─────────────┐
│   SUMO     │ ←────────────→  │   CARLA     │
│ (交通流)    │   状态同步       │ (动力学)     │
└─────────────┘                 └─────────────┘
      ↑                               ↑
      │                               │
      └─────── 主车状态双向同步 ───────┘
              (BridgeHelper)

2.2 时间同步机制

协同仿真的核心是一个严格的顺序同步函数 _sync_world

def _sync_world(self):
    # 1. 推进 SUMO,获取所有交通参与者状态
    sumo_sim.tick()
    
    # 2. SUMO → CARLA:同步背景车辆位置
    self._sync_sumo_to_carla()
    
    # 3. 推进 CARLA,应用主车控制指令
    carla_sim.tick()
    
    # 4. CARLA → SUMO:同步主车位置回 SUMO(幽灵车)
    self._sync_carla_to_sumo()

每步仿真长度为 0.1 秒(STEP_LENGTH = 0.1),在精度和效率之间取得平衡。

2.3 主车控制机制

主车通过 CARLA 的 Traffic Manager (TM) 接管。TM 配置了几个关键参数:

当策略输出换道动作时,通过 force_lane_change 发送强制换道指令,同时设置 40 步(约 4 秒)的换道冷却时间。

3. 强化学习算法:PPO

3.1 为什么选 PPO?

本项目采用 Proximal Policy Optimization (PPO) 算法,由 Stable-Baselines3 库实现。选择 PPO 的核心理由:

PPO 的目标函数为:

其中 是新旧策略的概率比, 是优势函数估计, 通常取 0.1 或 0.2。

3.2 网络结构

策略网络采用 MlpPolicy(多层感知机):

训练超参数:

参数
学习率3e-4
GAE λ0.95
折扣因子 γ0.99
每轮步数 n_steps2048
批次大小64
熵系数 ent_coef0.01

4. 动作空间与观测空间

4.1 动作空间(3 维离散)

动作行为
保持车道0当前车道匀速行驶
向左换道1向左侧车道发起换道
向右换道2向右侧车道发起换道

4.2 观测空间(14 维连续向量)

观测向量包含三类信息:

主车状态(3维)

周围车辆感知(10维) 采用 5 通道传感器配置,每个通道返回「最近车辆距离」+ 「相对速度」:

      [左后]  [左前]

[后] ←—— [主车] ——→ [前]

      [右后]  [右前]

道路信息(1维)

5. 奖励函数设计

奖励函数是策略学习的核心驱动力。本项目采用稠密奖励 + 稀疏激励的混合设计:

5.1 各分量奖励

速度奖励(r_speed)

达到目标速度 50 km/h 时,奖励为 1.0;速度越低,奖励越少。

堵车惩罚

这是驱动智能体主动换道的核心动力——被困在慢车后面会持续扣分。

换道成功奖励

当且仅当:换道冷却结束后 35 步内检测到车道变化,才算成功换道。高额奖励建立了”换道→成功”的强关联。

安全惩罚

碰撞是高压线,任何情况下都不可接受。

5.2 奖励信号解析

为什么这样设计?

堵车惩罚设得不太重(-0.5),是因为如果太重,智能体会”宁可撞车也要换道”;而碰撞惩罚设得极重(-50),是因为安全性必须压倒一切。通过多分量加权组合,策略最终学会:在安全的前提下,积极换道以避免拥堵。

6. 训练结果与分析

6.1 训练配置

6.2 训练曲线

经过 27 万步的训练(对应约 7.5 小时),智能体已经展现出清晰的换道能力:

奖励曲线

图:每回合平均奖励(episode reward mean)随训练步数的变化。早期(050k 步)奖励波动剧烈,智能体处于随机探索阶段;中期(50k150k 步)奖励快速上升,策略逐渐学会换道以获得更高速度奖励;后期(150k+ 步)趋于收敛,策略接近次优解。

6.3 价值损失与策略损失

价值损失

图:价值网络损失(value loss)随训练步数的变化。初期损失较高,价值网络还在学习估计状态价值;中后期损失稳定在较低水平,说明价值估计趋于准确,为优势函数提供了可靠的基线。

策略损失

图:策略损失(policy loss)曲线。PPO 的策略损失直接反映策略更新的方向和幅度,可以看到策略在探索-利用之间动态调整。

6.4 速度对比分析

速度对比

图:主车速度(橙色)vs 道路平均速度(蓝色)对比。可以观察到主车速度整体高于交通流平均速度,说明策略学会了主动寻找高速车道或摆脱低速拥堵。

6.5 换道频率分析

换道次数

图:训练过程中累计换道次数的变化。前期换道频繁但低效(大量失败换道),中后期换道减少但成功率显著提升,策略学会了在必要时换道而非盲目换道。

6.6 已保存的检查点

项目在 checkpoints/ 目录下保存了 30 个检查点,覆盖从 10,000 步到 270,000 步的完整训练过程:

ppo_carla_autodrive_10006_steps.zip
ppo_carla_autodrive_20253_steps.zip
ppo_carla_autodrive_30253_steps.zip
...
ppo_carla_autodrive_270489_steps.zip

每一步 checkpoint 都可用于中断恢复策略对比实验

7. 关键代码实现细节

7.1 BridgeHelper:坐标转换

CARLA 使用左手坐标系(X 前,Y 右,Z 上),SUMO 使用右手坐标系,两者轴向相反。BridgeHelper 实现了这个转换:

# 位置转换:SUMO → CARLA
carla_location = carla.Location(
    x=sumo_x,
    y=-sumo_y,  # Y 轴取反
    z=0.5
)

# 朝向角转换
carla_rotation = carla.Rotation(
    pitch=0,
    yaw=math.degrees(-sumo_angle),  # 角度取反
    roll=0
)

7.2 死锁检测与清理

SUMO 中的背景车可能因红灯、拥堵等原因陷入死锁。本项目实现了智能死锁检测:

def _check_and_remove_deadlock(self, vehicle_id):
    speed = traci.vehicle.getSpeed(vehicle_id)
    wait_time = traci.vehicle.getAccumulatedWaitingTime(vehicle_id)
    
    if speed < 0.1:
        if self._is_at_red_light(vehicle_id) and wait_time > 120:
            traci.vehicle.remove(vehicle_id)  # 红灯等待超时,移除
        elif wait_time > 10:
            traci.vehicle.remove(vehicle_id)  # 非红灯死锁,快速清理

7.3 自定义回调:TrafficLoggerCallback

训练过程中自动记录交通数据到 CSV,用于后续分析:

class TrafficLoggerCallback(BaseCallback):
    def _on_step(self) -> bool:
        infos = self.locals["infos"][0]
        self.writer.writerow([
            self.num_timesteps,
            infos.get('ego_speed_kmh', 0.0),
            infos.get('average_speed', 0.0),
            infos.get('ego_road_avg_speed', 0.0),
            infos.get('current_lane_id', -1)
        ])
        return True

8. 项目结构一览

carlaSumoRL/
├── assets/                     # SUMO 地图配置、Town06 路网
│   ├── Town06.rou.xml         # 交通流生成配置
│   ├── Town06.net.xml         # SUMO 路网定义
│   ├── town06.sumocfg         # SUMO 仿真配置文件
│   └── *.png                   # 可视化结果图
├── core/                       # 核心仿真逻辑
│   ├── bridge_helper.py       # 坐标系转换(368行)
│   ├── carla_simulation.py    # CARLA 仿真控制(186行)
│   ├── sumo_simulation.py     # SUMO 仿真控制(517行)
│   └── constants.py           # 常量定义
├── envs/
│   └── carla_sumo_env.py      # Gym 环境定义(469行)
├── checkpoints/                # 30个训练检查点
├── ppo_carla_tensorboard/     # TensorBoard 日志
├── train_ppo.py                # 训练入口
├── test_ppo.py                 # 测试入口
├── plot_training_curve.py     # 训练曲线可视化
├── plot_metrics.py            # 交通数据分析
└── traffic_log.csv            # 实时交通数据日志

9. 局限性与未来工作

当前局限

  1. 观测空间有限:仅用 5 通道射线传感器,未利用视觉输入,高速场景下感知信息不足
  2. 单主车场景:尚不支持多智能体协同,多车同时换道的交互博弈未建模
  3. SUMO 车辆行为简单:背景车使用默认 IDM 跟驰模型,缺乏激进/保守驾驶风格的差异化
  4. 换道判定依赖冷却时间:真实驾驶中换道需要感知-决策-执行的多阶段协调,当前模型做了较大简化

未来方向

10. 总结

本项目完整实现了一个 CARLA-SUMO 协同仿真 + PPO 强化学习 的自动驾驶换道训练框架。通过双仿真器协同,既保证了主车动力学的真实性,又确保了背景交通流的多样性和挑战性。

项目代码量约 1540 行,结构清晰,覆盖训练-测试-可视化全流程,已保存 30 个检查点供复现和二次开发。如果你对自动驾驶决策规划、强化学习在交通场景中的应用感兴趣,这个框架是一个不错的起点。


项目地址:/home/tartlab/project/outwork/carlaSumoRL/

作者:Kagura Tart | 2026-04-15