CarSim强化学习入门实战:从零搭建自动驾驶决策模型

1次阅读
没有评论

共计 2982 个字符,预计需要花费 8 分钟才能阅读完成。

image.webp

背景痛点

传统 CarSim 控制方法(如 PID 控制)需要手动调参,难以应对复杂驾驶场景。而强化学习(Reinforcement Learning)与 CarSim 结合时,新手常遇到三大难题:

  • 物理引擎接口复杂:CarSim 的动力学模型包含数百个参数,直接调用底层 API 需要掌握 C ++ 和 Simulink 知识
  • 训练效率低下:连续控制任务中,智能体(Agent)探索效率低导致收敛缓慢
  • 仿真 - 现实鸿沟:在仿真中训练的策略(Policy)往往难以直接迁移到真实车辆

技术选型

连续控制任务中,主流算法对比:

  1. DQN:适用于离散动作空间(如游戏按键),无法直接处理油门 / 转向的连续值
  2. PPO:策略梯度方法,对超参数敏感,训练波动较大
  3. DDPG:Actor-Critic 架构,适合连续控制,本文选择它的原因:
  4. 直接输出方向盘转角 / 油门等连续动作
  5. 通过经验回放池(Replay Buffer)提升样本利用率
  6. 双网络结构(Actor+Critic)稳定训练过程

实现细节

1. CarSim-Python 接口搭建

推荐通过 Simulink 生成 DLL 动态链接库:

% Simulink 模型配置步骤
1. 在 CarSim 界面导出 VS Vehicle Model
2. 添加 S -Function 模块连接控制输入 / 输出
3. 使用 Simulink Coder 生成 car_sim_interface.dll

Python 端调用示例:

import ctypes
car_sim = ctypes.CDLL('./car_sim_interface.dll')

# 关键参数说明
sim_step = 0.01  # 仿真步长 10ms
def run_step(action):
    steer, accel = action  # 输入转向角 [-1,1] 和加速度[0,1]
    car_sim.set_input(ctypes.c_float(steer), ctypes.c_float(accel))
    car_sim.step()
    state = get_state()  # 获取下一状态
    return state

2. 状态空间设计

选取 12 维特征向量:

  • 车辆状态:车速(m/s)、横向偏差(m)、航向角误差(rad)
  • 道路信息:曲率(1/m)、前方 10m/20m/30m 处的预瞄点偏差
  • 历史动作:上一时刻的转向角、加速度
# 状态归一化处理示例
def normalize_state(raw_state):
    # raw_state: [vx, vy, yaw_rate, e1, e2,...]
    return np.array([raw_state[0]/30.0,          # 车速归一化到 0~1
        raw_state[3]/3.0,           # 横向偏差限制在±3m
        raw_state[4]/np.pi          # 角度归一化到[-1,1]
        # ... 其他特征
    ])

3. 奖励函数设计

多目标加权组合:

R = w_1(1-|e|) + w_2\cos(Δψ) + w_3a_{smooth} - w_4|δ| 
  • 轨迹跟踪:横向偏差 e 越小越好
  • 行驶舒适性:转向角变化率 a_smooth=‖δ_t – δ_{t-1}‖
  • 控制效率:避免过大转向 δ

实际调参建议:

# 奖励计算示例
def calc_reward(state, action, last_action):
    e = abs(state[3])  # 横向偏差
    delta_steer = abs(action[0] - last_action[0])
    reward = 2.0*(1 - e/3.0) - 0.1*delta_steer - 0.05*abs(action[0])
    return np.clip(reward, -1, 1)  # 限制奖励范围

核心代码实现

DDPG 网络结构

import torch
import torch.nn as nn

class Actor(nn.Module):
    def __init__(self, state_dim, action_dim):
        super().__init__()
        self.net = nn.Sequential(nn.Linear(state_dim, 256),
            nn.LayerNorm(256),  # 稳定训练
            nn.ReLU(),
            nn.Linear(256, action_dim),
            nn.Tanh()  # 输出[-1,1]
        )

    def forward(self, state):
        return self.net(state)

class Critic(nn.Module):
    def __init__(self, state_dim, action_dim):
        super().__init__()
        self.state_net = nn.Sequential(nn.Linear(state_dim, 128),
            nn.LayerNorm(128),
            nn.ReLU())
        self.q_net = nn.Sequential(nn.Linear(128 + action_dim, 128),
            nn.ReLU(),
            nn.Linear(128, 1)
        )

    def forward(self, state, action):
        s_feat = self.state_net(state)
        return self.q_net(torch.cat([s_feat, action], dim=1))

经验回放池

from collections import deque
import random

class ReplayBuffer:
    def __init__(self, capacity):
        self.buffer = deque(maxlen=capacity)  # 循环队列

    def add(self, state, action, reward, next_state, done):
        self.buffer.append((state, action, reward, next_state, done))

    def sample(self, batch_size):
        batch = random.sample(self.buffer, batch_size)
        states, actions, rewards, next_states, dones = zip(*batch)
        return np.array(states), np.array(actions), \
               np.array(rewards), np.array(next_states), np.array(dones)

避坑指南

1. CarSim 实时同步

  • 设置仿真步长 = 训练步长(建议 10ms)
  • 在 Python 端添加循环等待,直到收到 CarSim 的完成信号
while not car_sim.is_step_done():  
    time.sleep(0.001)  # 避免 CPU 跑满

2. 奖励稀疏问题

  • 增量奖励:给每个步骤的小改进分配微小奖励
  • 课程学习:先训练简单直线场景,再逐步增加弯道复杂度

3. 训练不稳定

  • 优先检查梯度爆炸:添加梯度裁剪(torch.nn.utils.clip_grad_norm_
  • 降低学习率(Actor 建议 3e-4,Critic 建议 1e-3)
  • 增加 Batch Size(至少 128)

效果验证

CarSim 强化学习入门实战:从零搭建自动驾驶决策模型
蓝色轨迹:PID 控制,在急弯处偏离车道
红色轨迹:DDPG 策略,始终保持居中行驶

延伸思考

如何将模型部署到真实车辆 ECU?

  1. 量化压缩:将 PyTorch 模型转换为 TensorRT 引擎
  2. 硬件适配:使用 NVIDIA Drive 系列芯片满足实时性要求
  3. 安全冗余:添加看门狗机制(Watchdog)监控决策异常

完整代码已开源:GitHub 链接

正文完
 0
评论(没有评论)