简介这份资源面向无人艇USV控制、深度强化学习方向的研究生与工程技术人员提供一套基于DQN的避障控制完整MATLAB实现。内容涵盖无人艇运动学建模、巡逻艇目标建模以及DQN智能体的训练与仿真主流程可用于复现论文实验、课程设计或算法二次开发。压缩包共12个文件以11个.m脚本和1个.mat数据文件为主脚本分别承担环境初始化、奖励计算、Q目标值计算、ε-greedy策略、模糊集处理与仿真主循环等职责数据文件保存训练过程或场景参数整体约24.47MB。目前已有6280人学习下载说明该方案在同类课题中具有较高参考价值。读者可据此获得从建模到训练再到避障仿真的完整代码链路理解状态设计、奖励函数与Q网络更新之间的配合方式并在此基础上调整参数、替换场景或迁移到其他智能体控制任务中。1. 从一次仿真翻船说起DQN 到底在无人艇避障里干什么很多人第一次把 DQN 往无人艇上套是在 MATLAB 里搭好一个二维水面场景艇体按固定步长前进障碍物随机撒点然后发现训练几百回合后艇要么原地打转要么直直撞上去。问题往往不在 DQN 本身而在于把「避障」当成了「分类」——以为网络输出左转右转就完事忽略了无人艇是欠驱动、有惯性、动作连续被离散化之后会产生抖动的对象。基于深度强化学习 DQN 的无人艇避障控制本质是让智能体在每一个仿真步里根据当前感知到的相对位置、航向、速度从有限个离散动作比如左满舵、左小舵、直行、右小舵、右满舵里选一个通过累积奖励学会一套避障策略。它解决的是传统人工势场法容易陷入局部极小、A* 只适合静态全局规划、而规则法难以覆盖多障碍动态场景的问题。适合已经会 MATLAB 基础编程、想用 DQN 做路径规划或避障验证的读者也适合做移动机器人室内自主导航、无人艇编队等方向、需要一套可复现仿真框架的人。2. DQN 避障建模状态、动作、奖励怎么定才不翻船2.1 无人艇运动学模型与离散动作空间设计无人艇常用三自由度模型surge、sway、yaw仿真里为了控制复杂度多数做法是固定前向速度只控制艏摇角速度或舵角。状态向量一般取艇体位置 (x, y)、航向角 ψ、前向速度 u、以及若干条测距射线得到的障碍物距离。动作空间离散成 5 个或 7 个舵角档位档位太密会导致 Q 值区分度下降太疏则避障动作粗糙。% 无人艇三自由度简化运动学更新固定前向速度 function state usv_step(state, action, dt, env) % state [x, y, psi, u] % action: 1~5 对应舵角 [-30 -15 0 15 30] 度 rudder_set [-30, -15, 0, 15, 30] * pi/180; delta rudder_set(action); u state(4); psi state(3); % 简化航向角速度与舵角成正比与速度相关 r env.K_r * u * delta; psi_next psi r * dt; x_next state(1) u * cos(psi_next) * dt; y_next state(2) u * sin(psi_next) * dt; state [x_next, y_next, psi_next, u]; end这段代码把连续舵角离散成 5 档K_r是回转性系数dt是仿真步长。逻辑上先由动作查表得到舵角再算角速度、更新航向和位置。参数说明dt一般取 0.1~0.2 秒太大导致碰撞检测漏判K_r需要根据艇长和速度标定取值过大会让艇转向过猛DQN 很难学到稳定策略。2.2 奖励函数稀疏奖励为什么训不出来奖励设计是 DQN 避障成败的关键。常见错误是只给终点正奖励、碰撞负奖励其余为 0这种稀疏奖励在几百步的回合里几乎无法传播到早期动作。我一般会拆成三部分靠近目标给连续小奖励距离障碍物过近给连续惩罚碰撞给大负奖励并终止回合。奖励项触发条件建议取值作用目标接近奖励每步距离减少1.0引导向目标障碍惩罚最近障碍距离 安全半径-2.0提前避让碰撞终止距离 艇体半径-50强约束步数惩罚每步固定-0.05抑制绕圈function [reward, done] compute_reward(state, goal, obs, env) dist_goal norm(state(1:2) - goal); min_obs min(vecnorm(obs - state(1:2), 2, 2)); reward -0.05; % 步数惩罚 reward reward 1.0 * (env.prev_goal_dist - dist_goal); if min_obs env.safe_radius reward reward - 2.0; end done false; if min_obs env.boat_radius reward -50; done true; elseif dist_goal env.goal_radius reward reward 100; done true; end env.prev_goal_dist dist_goal; end逻辑说明每步先扣固定步数惩罚再按目标距离变化给增量奖励障碍距离小于安全半径时叠加惩罚碰撞或到达目标则终止。参数说明safe_radius建议取 2~3 倍艇体半径太小来不及避让goal_radius取 1~2 米即可太大会让艇提前停止。2.3 用 MATLAB 搭 DQN 网络状态输入与 Q 值输出MATLAB 的 Reinforcement Learning Toolbox 提供rlDQNAgent网络可以用rlVectorQNetwork或自定义dlnetwork。输入维度等于状态向量长度输出维度等于动作数。隐藏层用两个全连接层每层 128 个神经元ReLU 激活足够应付二维避障。obsInfo rlNumericSpec([stateDim 1]); actInfo rlFiniteSetSpec({1,2,3,4,5}); net [ featureInputLayer(stateDim, Normalization,none) fullyConnectedLayer(128) reluLayer fullyConnectedLayer(128) reluLayer fullyConnectedLayer(actInfo.NumElements) ]; agent rlDQNAgent(obsInfo, actInfo, rlVectorQNetwork(net)); agent.AgentOptions.DiscountFactor 0.95; agent.AgentOptions.TargetUpdateFrequency 100; agent.AgentOptions.ExperienceBufferLength 1e5;逻辑说明featureInputLayer接收状态两个隐藏层提取特征最后一层输出每个动作的 Q 值。参数说明DiscountFactor取 0.95~0.99越大越看重长期回报TargetUpdateFrequency控制目标网络同步频率太小训练不稳太大收敛慢ExperienceBufferLength建议 1e5 量级太小样本相关性高。3. 训练循环与超参数让 DQN 在 MATLAB 里真正收敛3.1 训练主循环与经验回放的最小实现MATLAB 的train函数封装了训练循环但要做避障仿真通常需要自定义环境类继承rl.env.MATLABEnvironment在step方法里调用前面的运动学和奖励函数。下面是一个最小训练脚本骨架。env USVEnv(); % 自定义环境 agent createDQNAgent(env); % 前面定义的 agent trainOpts rlTrainingOptions( ... MaxEpisodes, 2000, ... MaxStepsPerEpisode, 500, ... ScoreAveragingWindowLength, 50, ... StopTrainingCriteria, AverageReward, ... StopTrainingValue, 200, ... Verbose, false, ... Plots, training-progress); trainingStats train(agent, env, trainOpts);逻辑说明MaxEpisodes是总回合数MaxStepsPerEpisode限制单回合步数防止死循环ScoreAveragingWindowLength做滑动平均平滑曲线。参数说明StopTrainingValue要根据奖励量级调整如果奖励里碰撞是 -50、到达是 100平均奖励到 200 可能过高建议先跑 200 回合看曲线再定。3.2 学习率、批大小与探索率衰减的调参顺序调参不要一上来就网格搜索按影响从大到小排先定奖励函数再调探索率衰减最后调学习率和批大小。探索率Epsilon从 1.0 线性衰减到 0.05衰减回合数占总回合的 60%~70% 比较合适。参数建议范围调大后果调小后果学习率1e-4 ~ 1e-3震荡不收敛收敛慢批大小32 ~ 128显存/内存高梯度噪声大Epsilon 终值0.05 ~ 0.1探索过多早熟收敛目标网络更新100 ~ 500 步收敛慢训练不稳agent.AgentOptions.EpsilonGreedyExploration.Epsilon 1.0; agent.AgentOptions.EpsilonGreedyExploration.EpsilonMin 0.05; agent.AgentOptions.EpsilonGreedyExploration.EpsilonDecay 1e-4; agent.AgentOptions.LearnRate 5e-4; agent.AgentOptions.MiniBatchSize 64;逻辑说明EpsilonDecay是每步衰减量按总步数估算衰减到EpsilonMin的时机。参数说明如果训练曲线前期奖励上升后突然崩塌多半是学习率偏大或目标网络更新太频繁先把学习率降到 1e-4 试。3.3 训练不收敛时先查这四处第一查奖励量级如果碰撞惩罚 -50 而每步奖励只有 0.1Q 值会被大负值主导网络输出饱和。第二查状态归一化位置和距离量纲差一个数量级时输入层不做归一化会让训练极慢。第三查经验回放是否真的在采样ExperienceBufferLength设得比单回合步数还小等于没有回放。第四查动作空间是否合理5 档舵角如果每档间隔 30 度艇在高速下会直接冲出安全区。提示MATLAB 里用rlTrainingOptions的Plots打开训练进度窗口重点看 Episode Reward 和 Average Reward 两条线前者波动大是正常的后者持续不升才是问题。4. 仿真验证与避障效果评估别只看奖励曲线4.1 用测试回合统计碰撞率和到达率训练完不能只看平均奖励要跑固定测试集随机生成 100 个障碍物场景每个场景跑一次贪心策略Epsilon0统计碰撞次数、到达次数、平均路径长度。numTest 100; collision 0; success 0; pathLen zeros(numTest,1); for i 1:numTest env.reset(rand_seed(i)); state env.getState(); done false; steps 0; while ~done steps 500 action getGreedyAction(agent, state); [state, ~, done] env.step(action); steps steps 1; end if env.isCollision, collision collision 1; end if env.isGoal, success success 1; end pathLen(i) env.traveledDistance; end fprintf(碰撞率 %.2f%%, 到达率 %.2f%%, 平均路径 %.2f m\n, ... collision/numTest*100, success/numTest*100, mean(pathLen));逻辑说明每个测试场景重置环境用贪心动作跑完回合记录结果。参数说明rand_seed要固定保证每次评估可比steps上限和训练时一致否则统计不公平。4.2 避障轨迹可视化与失败案例回放把成功和失败的轨迹画在同一张图上能直观看出策略边界。MATLAB 里用plot画障碍物圆、起点终点、艇体轨迹失败案例单独标红。figure; hold on; axis equal; for k 1:size(obs,1) viscircles(obs(k,:), safe_radius, Color, [0.6 0.6 0.6]); end plot(traj_success(:,1), traj_success(:,2), b-, LineWidth, 1.5); plot(traj_fail(:,1), traj_fail(:,2), r--, LineWidth, 1.5); plot(goal(1), goal(2), gp, MarkerSize, 12); legend(障碍安全区,成功轨迹,失败轨迹,目标);逻辑说明viscircles画障碍安全半径成功轨迹用实线失败用虚线。参数说明safe_radius要和奖励函数里一致否则可视化会误导判断。4.3 和人工势场法、A* 的对比口径对比时不要只比成功率要比同等感知条件下的路径平滑度和计算耗时。DQN 的优势在动态障碍和未知环境A* 在静态全局规划上仍然更快更稳。常见做法是静态场景用 A* 做基线动态场景用 DQN人工势场法作为中间对照。方法静态场景动态障碍路径平滑度单步耗时A*优差中低人工势场中中差低DQN中优中高注意DQN 单步推理在 MATLAB 里如果每次调用getAction都重建网络耗时会高一个数量级测试时要把 agent 对象常驻内存。5. 从仿真到工程Double DQN 与状态编码的几个实用技巧5.1 用 Double DQN 抑制 Q 值高估普通 DQN 用同一个网络选动作和估 Q 值容易高估表现为训练后期奖励虚高但实际避障变差。MATLAB 里把 agent 换成rlDQNAgent并设置agent.AgentOptions.UseDoubleDQN true即可底层会解耦动作选择和 Q 值评估。agent rlDQNAgent(obsInfo, actInfo, rlVectorQNetwork(net)); agent.AgentOptions.UseDoubleDQN true; agent.AgentOptions.DiscountFactor 0.98;逻辑说明开启后目标 Q 值用在线网络选动作、目标网络估价值。参数说明DiscountFactor可以比普通 DQN 略大因为高估被抑制后长期回报更可信。5.2 状态编码极坐标比直角坐标更省网络把障碍物相对位置从 (dx, dy) 改成 (距离, 相对方位角)输入维度不变但物理意义更清晰网络更容易学到「前方近就转」这种规则。相对方位角用atan2(dy, dx) - psi归一化到 [-pi, pi]。function s encode_state(boat, obs, goal) rel_goal goal - boat(1:2); dg norm(rel_goal); ag wrapToPi(atan2(rel_goal(2), rel_goal(1)) - boat(3)); s [boat(4)/max_speed, dg/max_dist, ag/pi]; for k 1:size(obs,1) rel obs(k,:) - boat(1:2); d norm(rel); a wrapToPi(atan2(rel(2), rel(1)) - boat(3)); s [s, d/max_dist, a/pi]; end end逻辑说明速度和距离都除以量程做归一化角度除以 pi。参数说明max_dist取感知半径max_speed取艇体最大前向速度这样所有输入都在 [-1, 1] 附近训练更稳。5.3 训练中断后接着跑保存与加载 agent长训练容易中断MATLAB 里用save存 agent下次load后继续train。注意保存时要连环境参数一起存否则奖励函数变了 Q 值会对不上。save(usv_dqn_checkpoint.mat, agent, envParams); % 下次加载 load(usv_dqn_checkpoint.mat); trainingStats train(agent, env, trainOpts);逻辑说明checkpoint 里同时存 agent 和环境参数保证奖励口径一致。参数说明建议每 200 回合存一次文件名带回合数方便回滚到崩溃前的版本。5.4 一个容易被忽略的细节MATLAB 版本与中文注释编码MATLAB 2023 之后默认编码在某些系统上仍是 GBK脚本里中文注释在另一台机器打开会乱码进而导致train报解析错误。稳妥做法是把含中文注释的.m文件统一存成 UTF-8并在脚本开头确认编码设置。如果团队里有人用 Linux 跑训练这一步不做协作时必踩。提示训练日志里如果出现Invalid use of a reserved word但代码看着没问题先查注释编码再查是否有中文全角符号混进代码行。本文还有配套的精品资源点击获取