0 专栏介绍
本专栏以贝尔曼最优方程等数学原理为根基,结合PyTorch框架逐层拆解DRL的核心算法(如DQN、PPO、SAC)逻辑。针对机器人运动规划场景,深入探讨如何将DRL与路径规划、动态避障等任务结合,包含仿真环境搭建、状态空间设计、奖励函数工程化调优等技术细节,旨在帮助读者掌握深度强化学习技术在机器人运动规划中的实战应用
1 软性演员-评论家SAC算法
软性演员-评论家(Soft Actor-Critic, SAC)算法是基于最大熵原理的离线策略方法,具有高效的采样效率和泛化能力。SAC的核心原理在于三个参数化公式:
参数化动作-价值函数
J ( w ) = 1 2 E [ ( Q ( s , a ; w ) − ( r s → s ′ + γ max a ′ ( Q ^ ( s ′ , a ′ ; w ^ ) − α log π ( s ′ , a ′ ; θ ) ) ) ) ] J\left( \boldsymbol{w} \right) =\frac{1}{2}\mathbb{E} \left[ \left( Q\left( \boldsymbol{s},\boldsymbol{a};\boldsymbol{w} \right) -\left( r_{\boldsymbol{s}\rightarrow \boldsymbol{s}'}+\gamma \max _{\boldsymbol{a}'}\left( \hat{Q}\left( \boldsymbol{s}',\boldsymbol{a}';\boldsymbol{\hat{w}} \right) -\alpha \log \pi \left( \boldsymbol{s}',\boldsymbol{a}';\boldsymbol{\theta } \right) \right) \right) \right) \right] J(w)=21E[(Q(s,a;w)−(rs→s′+γa′max(Q^(s′,a′;w^)−αlogπ(s′,a′;θ))))]参数化策略
J ( θ ) = E ( s , a ) π ( α log π ( s , a ; θ ) − Q ( s , a ; w ) ) J\left( \boldsymbol{\theta } \right) =\mathbb{E} _{\left( \boldsymbol{s},\boldsymbol{a} \right) ~\pi}\left( \alpha \log \pi \left( \boldsymbol{s},\boldsymbol{a};\boldsymbol{\theta } \right) -Q\left( \boldsymbol{s},\boldsymbol{a};\boldsymbol{w} \right) \right) J(θ)=E(s,a) π(αlogπ(s,a;θ)−Q(s,a;w))参数化温度
J ( α ) = E [ − α log π ( s , a ; θ ) − α H 0 ] J\left( \alpha \right) =\mathbb{E} \left[ -\alpha \log \pi \left( \boldsymbol{s},\boldsymbol{a};\boldsymbol{\theta } \right) -\alpha H_0 \right] J(α)=E[−αlogπ(s,a;θ)−αH0]
SAC算法完整的流程如下所示,更多算法原理推导细节清看深度强化学习 | 图文详细推导软性演员-评论家SAC算法原理
本节将基于深度强化学习中的SAC算法实现移动机器人的路径跟踪
2 基于SAC算法的路径跟踪
2.1 SAC网络设计
策略网络(Actor)采用浅层MLP结构,其核心特征提取器由两层全连接网络构成(128→256单元),最终输出128维特征向量作为策略决策的潜在空间表示;价值评估采用双Q网络(Critic)架构,每个Critic网络均配备独立的三层MLP结构(128→64单元),与Actor共享观测输入但使用专属的特征提取器。Critic网络的特征提取器采用与Actor相同深度的双隐藏层结构(128→256单元),但输出维度保持128维特征向量,随后通过两层全连接网络完成状态-动作对的联合编码,最终输出标量Q值。双Q网络通过最小化两个独立估计值的方式有效缓解价值高估问题,既能避免策略与价值函数在特征表达上的相互干扰,又可通过差异化特征处理增强Q值估计的多样性。
2.2 动作空间设计
针对连续动作空间的特性设计了基于高斯分布采样的策略优化框架,以线速度 v v v和角速度 ω \omega ω为控制维度,构建了对称的二维连续动作空间 [ v , ω ] ∈ [ − v max , v max ] × [ − ω max , ω max ] \left[ v,\omega \right] \in \left[ -v_{\max},v_{\max} \right] \times \left[ -\omega _{\max},\omega _{\max} \right] [v,ω]∈[−vmax,vmax]×[−ωmax,ωmax]该设计通过上下界约束限定了动作输出的物理可行域,既避免因动作幅值过大导致运动失稳,又为策略网络的探索提供了明确的边界条件。进一步,通过高斯分布 N ( μ , σ ) \mathcal{N} \left( \mu ,\sigma \right) N(μ,σ)采样生成随机动作,再经tanh函数压缩至[-1,1]后线性映射到实际动作范围,既保证梯度可导性又满足动作边界约束
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):
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)
lidar_angles = self.lidar.lidar_angles + self.robot.theta
lidar_end_x = (self.robot.px + self.lidar.lidar_scans_grouped * np.cos(lidar_angles)).squeeze()
lidar_end_y = (self.robot.py + self.lidar.lidar_scans_grouped * np.sin(lidar_angles)).squeeze()
# calculate velocity command
e_theta = self.regularizeAngle(self.robot.theta - self.goal[2]) / 10
if self.shouldRotateToGoal(robot_pose, self.goal):
if not self.shouldRotateToPath(abs(e_theta)):
u = DiffCmd(0, 0)
else:
u = DiffCmd(0, self.angularRegularization(e_theta / dt))
else:
e_theta = self.regularizeAngle(self.angle(robot_pose, lookahead_pt) - self.robot.theta)
if self.shouldRotateToPath(abs(e_theta), np.pi / 4):
u = DiffCmd(0, self.angularRegularization(e_theta / dt / 10))
else:
u = self.SACControl(robot_pose, lookahead_pt)
# feed into robotic kinematic
self.robot.kinematic(u, dt)
LOG.WARN(f"{str(self)} Controller Controlling Failed!")
return ...
完整工程代码请联系下方博主名片获取
🔥 更多精彩专栏: