0 专栏介绍
本专栏以贝尔曼最优方程等数学原理为根基,结合PyTorch框架逐层拆解DRL的核心算法(如DQN、PPO、SAC)逻辑。针对机器人运动规划场景,深入探讨如何将DRL与路径规划、动态避障等任务结合,包含仿真环境搭建、状态空间设计、奖励函数工程化调优等技术细节,旨在帮助读者掌握深度强化学习技术在机器人运动规划中的实战应用
1 Double DQN算法回顾
无论Q-Learning还是DQN都存在过估计(overestimation)现象,过估计会导致智能体倾向于选择被高估的动作,可能陷入局部最优策略,降低学习效率和最终性能。例如,在复杂环境中,智能体可能反复选择某个次优动作,而忽略真正的高回报动作。
缓解最大化偏差的方法之一是互监督机制,典型算法是双深度Q网络(Double DQN, DDQN),该方法令
y i = { r i , s ′ 是最后一个状态 r i + γ Q ^ ( s ′ , max a ( Q ( s ′ , a ; θ ) ) ; θ ^ ) , s ′ 不是最后一个状态 y_i=\begin{cases} r_i\,\, , s'\text{是最后一个状态}\\ r_i+\gamma \hat{Q}\left( \boldsymbol{s}',\max _{\boldsymbol{a}}\left( Q\left( \boldsymbol{s}',\boldsymbol{a};\boldsymbol{\theta } \right) \right) ;\boldsymbol{\hat{\theta}} \right) , s'\text{不是最后一个状态}\\\end{cases} yi={ri,s′是最后一个状态ri+γQ^(s′,maxa(Q(s′,a;θ));θ^),s′不是最后一个状态
理论上DDQN实现了对 Q Q Q的无偏估计,如下图所示是DDQN和DQN在一些常见强化学习任务上的过估计现象对比,可以看到DDQN算法很好地缓解了过估计现象,具体算法原理请参考深度强化学习 | 详解过估计现象与Double DQN算法(附Pytorch实现)
2 基于DDQN的路径跟踪
2.1 DDQN网络设计
双深度Q网络(Deep Q-Network, DQN)的核心原理是通过
- 经验回放池(Experience Replay):考虑到强化学习采样的是连续非静态样本,样本间的相关性导致网络参数并非独立同分布,使训练过程难以收敛,因此设置经验池存储样本,再通过随机采样去除相关性;
- 目标网络(Target Network):考虑到若目标价值 与当前价值 是同一个网络时会导致优化目标不断变化,产生模型振荡与发散,因此构建与 结构相同但慢于 更新的独立目标网络来评估目标价值,使模型更稳定;
- 互监督机制
y i = { r i , s ′ 是最后一个状态 r i + γ Q ^ ( s ′ , max a ( Q ( s ′ , a ; θ ) ) ; θ ^ ) , s ′ 不是最后一个状态 y_i=\begin{cases} r_i\,\, , s'\text{是最后一个状态}\\ r_i+\gamma \hat{Q}\left( \boldsymbol{s}',\max _{\boldsymbol{a}}\left( Q\left( \boldsymbol{s}',\boldsymbol{a};\boldsymbol{\theta } \right) \right) ;\boldsymbol{\hat{\theta}} \right) , s'\text{不是最后一个状态}\\\end{cases} yi={ri,s′是最后一个状态ri+γQ^(s′,maxa(Q(s′,a;θ));θ^),s′不是最后一个状态
实现对DQN网络的增强,网络设计可以参考DQN
2.2 动作空间设计
在基于DDQN的差速驱动机器人路径跟踪算法中,动作空间的设计是决定算法性能的关键因素。DDQN要求算法具有离散动作空间,考虑到差速驱动机器人的运动学模型可用以下方程描述:
p ˙ = [ x ˙ y ˙ θ ˙ ] = [ cos θ 0 sin θ 0 0 1 ] [ v ω ] = S ( q ) u \boldsymbol{\dot{p}}=\left[ \begin{array}{c} \dot{x}\\ \dot{y}\\ \dot{\theta}\\\end{array} \right] =\left[ \begin{matrix} \cos \theta& 0\\ \sin \theta& 0\\ 0& 1\\\end{matrix} \right] \left[ \begin{array}{c} v\\ \omega\\\end{array} \right] =S\left( \boldsymbol{q} \right) \boldsymbol{u} p˙= x˙y˙θ˙ = cosθsinθ0001 [vω]=S(q)u
其中 ( x , y ) (x, y) (x,y) 表示机器人位置, θ \theta θ 为航向角, v v v 为线速度, ω \omega ω 为角速度。因此,动作空间的设计围绕控制变量 ( v , ω ) (v, \omega) (v,ω)展开。
具体而言,动作空间包含三个速度级别:
- 高速( v = v max v = v_{\text{max}} v=vmax)
- 中低速( v = 0.2 × v max v = 0.2 \times v_{\text{max}} v=0.2×vmax)
- 极低速( v = 0.1 × v max v = 0.1 \times v_{\text{max}} v=0.1×vmax)
转向方面也需要完整覆盖差速机器人的基本运动模式:
运动模式 | 数学描述 | 适用场景 |
---|---|---|
直线前进 | ω = 0 \omega = 0 ω=0 | 路径直线段跟踪 |
弧线运动 | ω ≠ 0 , v ≠ 0 \omega \neq 0, v \neq 0 ω=0,v=0 | 路径曲线段跟踪 |
原地旋转 | v = 0 , ω ≠ 0 v = 0, \omega \neq 0 v=0,ω=0 | 未包含但可通过动作组合实现 |
本文设计的动作空间为
self.action_space = [
DiffCmd(v=0.2 * self.params["max_v"], w=self.params["max_w"]),
DiffCmd(v=self.params["max_v"], w=self.params["max_w"]),
DiffCmd(v=self.params["max_v"], w=0.0),
DiffCmd(v=self.params["max_v"], w=-self.params["max_w"]),
DiffCmd(v=0.2 * self.params["max_v"], w=-self.params["max_w"]),
DiffCmd(v=0.1 * self.params["max_v"], w=0.0),
]
2.3 奖励函数设计
奖励函数设计采用多目标联合优化的混合奖励机制,通过时间惩罚、距离引导、目标达成奖励与碰撞惩罚的线性组合,构建了兼具探索激励与安全约束的强化学习回报,核心公式为:
R = r t i m e + α ( d t − 1 − d t ) + r r e a c h I w i n + r c o l l i s i o n I d e a d R=r_{\mathrm{time}}+\alpha \left( d_{t-1}-d_t \right) +r_{\mathrm{reach}}\mathbb{I} _{\mathrm{win}}+r_{\mathrm{collision}}\mathbb{I} _{\mathrm{dead}} R=rtime+α(dt−1−dt)+rreachIwin+rcollisionIdead
其中 d t d_t dt表示时刻 t t t智能体与目标的欧氏距离, I \mathbb{I} I为事件指示函数。时间惩罚项 r t i m e r_{\mathrm{time}} rtime作为基底奖励,通过固定负值施加步长成本压力,抑制智能体在环境中无效徘徊,驱动策略向高效路径收敛。距离引导项 α ( d t − 1 − d t ) \alpha \left( d_{t-1}-d_t \right) α(dt−1−dt)引入相对运动奖励机制,其中 α \alpha α为距离奖励系数,当智能体向目标靠近时 d t − 1 > d t d_{t-1}>d_t dt−1>dt产生正向激励,远离时 d t − 1 < d t d_{t-1}<d_t dt−1<dt施加负向惩罚,形成连续梯度信号引导策略优化方向。该设计相比绝对距离奖励更能话应动态环境,避免目标移动导致的奖励稀疏问题。目标达成奖励 r r e a c h r_{\mathrm{reach}} rreach作为稀疏奖励信号,仅在智能体进入目标区域时触发,通过显著的正向激励建立策略优化的全局目标导向。碰撞惩罚项 r c o l l i s i o n r_{\mathrm{collision}} rcollision则作为安全约束机制,当检测到与环境障碍物发生碰撞时施加高额负奖励,迫使策略学习规避高风险区域。
3 算法仿真
核心算法如下所示:
def plan(self, path: list):
"""
DDQN motion plan function.
Parameters:
path (list): planner path from path planning module
Returns:
flag (bool): planning successful if true else failed
real_path (list): real tracking path
cost (float): real path cost
pose_list (list): history poses of robot
"""
lookahead_pts, lidar_frames_vis = [], []
self.start, self.goal = path[0], path[-1]
self.robot = DiffRobot(self.start.x(), self.start.y(), self.start.theta(), 0, 0)
dt = self.params["time_step"]
for _ in range(self.params["max_iteration"]):
# break until goal reached
robot_pose = Point3d(self.robot.px, self.robot.py, self.robot.theta)
if self.shouldRotateToGoal(robot_pose, self.goal):
real_path = np.array(self.robot.history_pose)[:, 0:2]
cost = np.sum(np.sqrt(np.sum(np.diff(real_path, axis=0)**2, axis=1, keepdims=True)))
LOG.INFO(f"{str(self)} Controller Controlling Successfully!")
return
# get the particular point on the path at the lookahead distance
lookahead_pt, _ = self.getLookaheadPoint(path)
lookahead_pts.append(lookahead_pt)
# update simulated lidar
states = np.array([[self.robot.px, self.robot.py, self.robot.theta]])
self.lidar.updateScans(states, self.obstacle_indices, self.map2index_func)
# calculate velocity command
u = self.DDQNControl(robot_pose, lookahead_pt)
# feed into robotic kinematic
self.robot.kinematic(u, dt)
LOG.WARN(f"{str(self)} Controller Controlling Failed!")
return
完整工程代码请联系下方博主名片获取
🔥 更多精彩专栏: