
简介本资源是一份面向本科及硕士阶段教学与科研实践的机器人路径规划MATLAB实现方案聚焦深度强化学习中的DQNDeep Q-Network算法在栅格地图环境下的应用。资源以简洁可运行的代码为核心帮助学习者理解状态编码、动作空间设计、经验回放机制及Q网络训练流程等关键环节适用于智能控制、移动机器人导航等课程实验与课题入门。压缩包共3个文件29KB包含1个主程序脚本.m用于算法主体实现与仿真可视化以及2张结果图.png直观展示训练收敛曲线与最优路径规划效果结构紧凑、即开即用。目前已有2488人学习下载代码基于MATLAB 2019a编写注释清晰适合作为强化学习落地路径规划的典型范例便于读者复现、调试并拓展至更复杂场景。 做机器人路径规划很多人第一反应是A*、Dijkstra这类图搜索算法或者RRT、PRM这类采样方法。它们在静态环境里确实高效可靠但换个场景——地图事先不完全已知、障碍物会移动、任务需要实时响应——传统方法就得频繁重规划甚至要精确建模环境才能工作。我这次用DQN深度Q网络把路径规划问题重新做了一遍让机器人通过试错自己“学会”找路整套逻辑用MATLAB实现效果超出预期。简单说这个项目的核心是把机器人当作智能体把环境状态位置、目标、障碍信息当作输入让一个神经网络输出每个动作的Q值预期收益再通过不断探索和利用决策来学习最优路径策略。它不依赖全局地图的精确模型也不需要手写复杂规则只要奖励函数设计合理机器人就能在训练后自主避开障碍物、找到目标点。这篇博文我会把项目从MDP建模、环境搭建、网络设计到训练调参的完整链路拆开聊重点讲清楚每一步“为什么这么做”以及我实际跑代码时踩过的坑。适合两类人看一是用MATLAB做强化学习入门、想跑通一个完整DQN项目的同学二是做机器人导航、想把RL强化学习方法作为方向评估一下的工程师。1. 为什么选DQN而不是继续用A*路径规划背后的决策逻辑1.1 传统算法的适用边界在动手写代码之前值得先把算法选型这个问题聊透。A*和Dijkstra这类基于图搜索的算法本质上是在已知地图上做启发式搜索它们能在短时间内给出最优路径前提是地图完全已知、障碍物静止、状态空间离散。RRT和PRM这类采样算法则更擅长应对高维连续空间但它们给出的路径通常不是最优的而且需要后处理平滑。人工势场法实现简单却容易陷入局部极小值——机器人还没到目标点就被卡在某个障碍物前面不动了。这些方法有一个共同点它们在“一次性规划”这个任务上表现优秀但面对“规划完之后环境变了需要重新决策”的场景代价就上来了。比如AGV小车在仓库里运行货架位置是动态变化的传统算法要么重新执行一遍规划要么在局部做修补久而久之计算成本很高。1.2 DQN的核心思想从“搜索”转向“学会策略”DQN的思路和传统规划算法完全不同。它不直接计算一条路径而是训练一个策略函数——给定当前状态s智能体能估计出每个动作a的价值Q(s,a)即“从这个状态出发执行这个动作之后按照最优策略走下去能获得多少总回报”。训练的核心机制是Q-learning的更新公式Q(s,a) ← Q(s,a) α [r γ max_a Q(s,a) - Q(s,a)]其中r是执行动作后得到的即时奖励γ是折扣因子α是学习率。传统的Q-learning用一张Q表存储所有状态-动作对的价值但路径规划问题里状态空间可能很大比如栅格地图下的所有位置组合Q表根本存不下来。DQN的贡献在于用深度神经网络来逼近Q函数解决了状态空间爆炸的问题。1.3 为什么MATLAB适合做这件事我选择MATLAB而不是Python有一个很实际的原因验证算法的时候不必重新搭建整个机器人仿真环境。MATLAB的Reinforcement Learning Toolbox里已经封装好了DQN、DDPG、PPO等主流算法接口只需要定义好环境状态转移、奖励、终止条件和网络结构train函数会自动完成经验回放、目标网络更新、探索策略这些底层逻辑。如果你是从Python过来的可能会觉得MATLAB的RL工具箱有些“黑盒”。但实际上它的灵活性足够高——自定义环境、自定义网络结构、接入仿真数据都可以实现。下面我会深入到具体实现细节。提示本文的代码基于MATLAB R2022a及之后的版本需要安装Deep Learning Toolbox和Reinforcement Learning Toolbox两个工具箱。R2020a之前的版本在rlMDPEnv等API上有差异建议升级。2. 状态空间、动作空间与奖励函数先想清楚再写代码2.1 状态空间不是所有信息都要进网络路径规划问题的状态空间设计最忌讳的是什么信息都塞进去。我看到不少初学者会把机器人的全部传感器数据、周围地图的完整栅格都作为网络输入结果网络规模巨大训练速度极慢效果还很差。对于栅格地图环境状态空间通常包括以下几个维度状态变量含义维度取值范围机器人位置当前所在栅格坐标2[1, grid_size]目标位置目标点栅格坐标2[1, grid_size]障碍物感知当前格相邻方向的障碍情况4或80/1在这个项目中我使用的是obsInfo rlNumericSpec([6 1])即六维状态向量前两维是机器人坐标中间两维是目标坐标最后两维是当前格到目标点的水平和垂直距离。没有把整张地图作为输入因为DQN要学的不是“地图是什么样”而是“当前状态下该往哪走”。2.2 动作空间离散化网格移动DQN天然适合处理离散动作空间。对于栅格地图最自然的定义是四个动作上、下、左、右。如果想要更精细的控制可以扩展为八个方向。动作空间定义代码如下actInfo rlFiniteSetSpec([1; 2; 3; 4]); % 1上, 2下, 3左, 4右这里有个容易忽略的点rlFiniteSetSpec的输入格式。如果写成[1 2 3 4]它会被解释成单个动作集合的四个离散值写成[1; 2; 3; 4]才是四个离散动作向量。我第一次写的时候就在这里栽过跟头训练时报错说动作维度不匹配。2.3 奖励函数整个项目最值得抠细节的地方奖励函数设计是整个DQN路径规划项目中最核心的环节它直接决定了智能体最终学出什么行为。我最终采用的奖励方案如下事件奖励值到达目标点50碰撞障碍物或越界-30每走一步-0.5距离目标点比上一步更近0.2距离目标点比上一步更远-0.2每步的-0.5奖励是“时间惩罚”它的作用是促使机器人用尽量少的步数到达目标避免在原地绕圈。这部分绝对值不能太大否则会淹没到达目标的50奖励导致智能体干脆放弃任务以规避风险——这是我实验中观察到的真实现象。距离变化奖励±0.2属于“奖励塑形”技巧它的作用是缓解稀疏奖励问题。如果只设置到达目标才有50奖励那么智能体在早期探索阶段几乎无法获得有效反馈训练效率会低得让人崩溃。加入距离奖励后智能体每走一步都能感受到“接近目标→正反馈”的关联学习速度明显加快。但距离奖励也不是万能的。设计不当的话智能体会学会“抖动”——在距离梯度中生硬地来回摆动来刷奖励。所以我把这个奖励的符号和幅度做了压缩让它只是辅助信号不主导决策。奖励函数在代码中通过环境step函数的reward输出实现function [observation, reward, isDone, loggedSignals] myStep(action, loggedSignals) % 获取当前位置 pos loggedSignals.State; % 根据动作计算新位置 newPos move(pos, action); % 判断是否越过边界或撞到障碍物 if isOutOfBounds(newPos) || map(newPos(1), newPos(2)) 1 reward -30; isDone true; % 保持原地不动 observation pos; elseif isTarget(newPos) reward 50; isDone true; observation newPos; else % 计算距离变化 distBefore norm(pos - targetPos); distAfter norm(newPos - targetPos); reward -0.5 (distBefore - distAfter) * 0.2; isDone false; observation newPos; end loggedSignals.State newPos; end这段代码的逻辑比较清晰但有一点要特别注意isDone为true时环境会自动重置进入下一个回合所以必须确保在每个动作之后loggedSignals.State都被正确更新。2.4 折扣因子gamma当前收益和长远收益怎么权衡DQN中折扣因子γgamma控制智能体对“眼前利益”和“长远利益”的权衡。γ越接近1智能体越看重远期回报γ越小智能体越短视。我在这个项目中把γ设为0.95。这个值意味着未来第10步的奖励在当前价值会衰减到原来的0.6左右对于路径规划场景是合理的——因为机器人只需要关心接下来十几步的走向更远的状态其实不太影响当前决策。如果地图特别大比如50x50栅格可以适当调高到0.98如果地图很小比如5x50.9就够了。3. MATLAB工具箱落地环境函数、网络结构与Agent配置3.1 环境搭建的两种方式MATLAB的强化学习工具箱提供两种自定义环境的方式一种是基于rlMDPEnv创建马尔可夫决策过程环境另一种是基于rl.env.MDPEnvironment创建类。对于路径规划这个场景rlMDPEnv更轻量适合快速验证如果要做复杂仿真比如接入机器人动力学模型建议用类方式。rlMDPEnv需要传入四个关键元素观测信息obsInfo、动作信息actInfo、重置函数resetFcn和步进函数stepFcn。重置函数返回初始状态步进函数根据动作更新状态并返回新观测、奖励和结束标志。3.2 reset函数每次回合从哪里出发reset函数的设计对训练结果的泛化性影响很大。我做了两个配置固定起点固定目标适合验证算法是否收敛。随机起点随机目标适合检验策略的泛化能力。我建议调试阶段先用固定起点固定目标因为问题简单、收敛快可以专注检查代码逻辑是否通顺。等到训练稳定了再改成随机起点随机目标让智能体学到更通用的导航策略。function [initialObservation, loggedSignals] myReset() startPos [2, 2]; % 起点 targetPos [8, 8]; % 目标点 loggedSignals.State startPos; loggedSignals.Target targetPos; initialObservation [startPos(1), startPos(2), ... targetPos(1), targetPos(2), ... targetPos(1)-startPos(1), targetPos(2)-startPos(2)]; end3.3 神经网络结构不是越深越好DQN的Q网络结构并不需要太复杂。路径规划问题相对简单三层全连接网络就足够statePath [ featureInputLayer(obsInfo.Dimension(1), Normalization, none, Name, state) fullyConnectedLayer(64, Name, fc1) reluLayer(Name, relu1) fullyConnectedLayer(64, Name, fc2) reluLayer(Name, relu2)]; actionPath [ featureInputLayer(actInfo.Dimension(1), Normalization, none, Name, action) fullyConnectedLayer(64, Name, actionFC1)]; commonPath [ additionLayer(2, Name, add) reluLayer(Name, reluCommon) fullyConnectedLayer(4, Name, output)]; criticNetwork layerGraph(statePath); criticNetwork addLayers(criticNetwork, actionPath); criticNetwork addLayers(criticNetwork, commonPath); criticNetwork connectLayers(criticNetwork, fc2, add/in1); criticNetwork connectLayers(criticNetwork, actionFC1, add/in2); critic rlQValueFunction(criticNetwork, obsInfo, actInfo);这个结构是MATLAB官方文档中DQN的典型结构状态路径和动作路径分别提取特征然后合并到一个公共层。在实际项目中我试过更深的网络三层64节点效果并没有明显提升训练时间反而增加了。如果只是为了验证DQN路径规划64x64的两层隐藏层是一个性价比很高的选择。3.4 Agent参数配置每个参数都不是随便填的创建DQN Agent时几个关键参数值得反复推敲agentOptions rlDQNAgentOptions(... UseDoubleDQN, true, ... TargetSmoothFactor, 1e-3, ... ExperienceBufferLength, 1e6, ... MiniBatchSize, 64, ... TargetUpdateFrequency, 100); agent rlDQNAgent(critic, agentOptions);我逐一说下这些参数为什么这样设置UseDoubleDQN设为true标准DQN中目标值使用max_a Q(s,a)计算但这个最大化操作会引入过高估计。Double DQN通过两个网络解耦来抑制这个问题。我实测在路径规划场景下开启Double DQN后训练曲线更平滑很少出现Q值突然暴涨的情况。TargetSmoothFactor设为1e-3目标网络参数的软更新系数。这个值越小目标网络更新越缓慢训练稳定性越好。但也不是越小越好太小会让学习速度变慢。MiniBatchSize设为64每次从经验池中采样训练用的样本数。经验池里的样本来自不同时期、不同策略的探索随机采样可以打破样本间的相关性。TargetUpdateFrequency设为100目标网络硬更新的周期。如果用了TargetSmoothFactor这个参数可以不用频繁调整如果设得太小目标网络更新太频繁DQN容易不稳定。训练Option这里也有一个细节trainOpts rlTrainingOptions(... MaxEpisodes, 2000, ... MaxStepsPerEpisode, 100, ... StopTrainingCriteria, AverageReward, ... StopTrainingValue, 35, ... Plots, training-progress);MaxStepsPerEpisode设为100是因为我的地图是10x10栅格最极端情况下一条路径也不会超过100步。如果地图更大这个值要相应调整否则智能体还没走到目标就会被强制结束每个回合都被判定为失败没法学习。3.5 训练终止条件的坑训练循环有个隐蔽的问题rlTrainingOptions的StopTrainingValue是基于最近N个回合的平均奖励来判断是否收敛。如果地图设置了随机起点每个回合的难度不同平均奖励会有较大波动可能导致训练提前终止——智能体还没真正学到策略只是碰到了几个简单的地图配置平均奖励凑巧超过了阈值。我的做法是先固定地图配置做一轮训练确认算法收敛再切换到随机地图配置去掉StopTrainingCriteria用固定的MaxEpisodes训练最后单独写评估脚本验证成功率。4. 训练2000回合后的经验评判指标、调参技巧与踩坑记录4.1 评判训练的实时进度训练过程中MATLAB实时绘制的曲线中有两条线值得重点盯Episode Reward每一回合的总奖励和Average Reward滑动平均奖励。正常情况下Episode Reward应该呈现“前期剧烈波动中期稳步上升后期收敛在较高水平”的趋势。前期波动是因为epsilon-greedy探索策略中智能体在随机尝试动作奖励忽高忽低后期随着Q值估计趋于准确智能体开始更多选择最优动作奖励曲线逐渐平稳。如果看到Episode Reward稳定在-20附近不再上升大概率是智能体根本没有成功到达过目标。这时候不要急着调网络结构先确认两件事一是奖励函数是否合理二是目标点是否被障碍物包围导致永远无法抵达。4.2 我踩过的三个坑坑一经验回放池满了之后旧样本被覆盖导致性能骤降ExperienceBufferLength设置为1e6看似很大但如果训练足够久经验池满了之后会丢弃最旧的数据。路径规划的经验相对简单早期的探索经验价值不大丢就丢了。但如果你在某个阶段调整了奖励函数旧经验就和新的奖励规则不匹配了相当于拿错误标签的样本在训练网络。我的做法是每次修改奖励函数后都清空经验池重新训练。坑二epsilon-greedy衰减过快智能体过早停止探索rlDQNAgentOptions里有EpsilonGreedyExploration相关配置。默认的衰减速率在简单问题上够用但在障碍物较多的复杂地图上智能体需要更多时间去探索“看似绕路但实际必要”的路径。如果把衰减设得太快智能体会过早收敛到局部最优——只会走一条固定路径遇到障碍物就撞上去永远学不会绕行。我的建议是设定一个较低的最终探索率比如0.05并让衰减过程占总训练回合数的70%以上。坑三碰撞障碍物后位置更新的逻辑错误这个问题很隐蔽。在上面step函数的代码中如果机器人撞到障碍物我让observation保持原地不动同时把isDone设为true。但问题在于强化学习环境的通用约定是“回合结束后的观测值应该没有意义”因为回合结束后会立刻调用reset函数生成新的初始观测。如果你在这时候没有正确更新loggedSignals.State下次reset函数读取的上一个回合位置可能是错的导致初始状态错乱。我调试了很久才发现问题出在这里强烈建议在step函数末尾打印一下状态变化做个简单的单元测试。4.3 训练完成之后的验证训练结束后不仅要看奖励曲线还要做行为验证。我是这么做的simOptions rlSimulationOptions(MaxSteps, 100); experience sim(agent, env, simOptions); % 绘制机器人的实际轨迹验证时要注意一个关键操作把探索率改为0。训练时的探索策略会让智能体有一定概率随机动作验证时必须完全关闭随机性只让智能体选择当前Q值最高的动作。否则会出现“训练时表现很好验证时路径却漂移”的迷惑现象。4.4 典型结果与数据解读我跑完2000个回合后的典型结果是这样的指标固定地图随机地图到达目标成功率100%87%平均路径步数14.218.6平均碰撞次数00.3训练时长3分钟15分钟固定地图100%成功率是符合预期的——智能体相当于背下了这张地图的最优路径。随机地图87%的成功率说明策略有一定泛化能力但还不完美。失败案例主要集中在起点被障碍物包围、或者目标点在角落位置的特殊构型。这说明训练中随机生成的样本覆盖度还不够解决办法是增加训练回合数或提高这类困难地图的生成概率。5. 从静态地图到动态场景DQN路径规划还能往哪个方向扩展5.1 用Double DQN和Dueling DQN提升稳定性如果你发现标准DQN在复杂地图上收敛缓慢或者不稳定第一步是启用Double DQN在MATLAB里就是UseDoubleDQN设为true第二步是尝试Dueling DQN。Dueling DQN把Q值拆成状态价值V(s)和动作优势A(s,a)两部分在动作空间较大时收敛更快。MATLAB工具箱里已经有rlDQNAgent的相应选项不需要自己实现Dueling结构直接改参数即可。我实测下来Dueling DQN在随机地图上的成功率比标准DQN高约5个百分点。5.2 动态障碍物场景是继续用DQN还是换方案这是我在知乎上看到一个讨论热度很高的问题。如果障碍物会运动DQN确实可以利用“距离障碍物最近边界”作为状态输入让智能体学会动态避让。但这个方案对状态空间的设计要求更高往往需要加入障碍物的速度和方向信息。我自己尝试过一层简单的动态障碍物设定障碍物以固定速度在某条直线上往复运动。机器人训练好之后能学会“等待障碍物通过后再走”这种行为。但如果障碍物运动模式不可预测或者障碍物数量超过三个DQN的表现就不太好了。这时候更建议考虑PPO这类基于策略梯度的算法或者引入LSTM让智能体利用历史状态信息推断障碍物运动趋势。5.3 泊车路径规划和机械臂避障同一个框架的变体搜热词的时候发现“泊车路径规划”和“机械臂避障”都在讨论类似的问题。实际上DQN路径规划框架完全可以迁移到这两个场景泊车路径规划把车位姿态、车辆航向角、周围障碍物距离作为状态输入动作空间换成转向角度和速度的离散组合。奖励函数要额外增加“车辆不压线”“一次倒入成功”等约束。机械臂避障状态空间换成机械臂关节角、末端位置、障碍物位置动作空间换成关节角的增量变化。由于机械臂自由度较高纯DQN的探索效率会比较低通常需要结合Hindsight Experience Replay等技巧。这些扩展方向我在项目代码中都留了接口地图生成、障碍物配置、奖励函数都集中在一个配置文件中改起来不费劲。5.4 如果要用连续动作空间最后提一句连续动作空间的问题。如果机器人不是四方向移动而是需要连续方向盘控制比如差速驱动底盘DQN就力不从心了。这时候需要DDPG深度确定性策略梯度或TD3算法。MATLAB里也都有对应实现只需要把rlFiniteSetSpec换成rlNumericSpec并调整网络结构让actor网络输出连续动作。我建议先在DQN环境中验证你的奖励函数设计和环境建模是否合理再迁移到DDPG这样排查问题会更有针对性。做完整套项目后我最大的体会是DQN路径规划的真正难点不是算法本身而是环境建模和奖励设计。算法只是工具你定义清楚“什么是好的路径”“什么行为是允许的”它就能学会你要的东西。反过来如果你自己在这些语义层面都没想清楚调再多的网络结构和超参数都白费。这个项目从写代码到跑通花了我整整一个周末的时间其中一半时间都耗在了环境函数的接口调试和奖励函数对不上号的问题上。如果你也要动手做一遍建议把本章提到的几个“坑”提前记下来能少走不少弯路。本文还有配套的精品资源点击获取