简介:基于深度强化学习技术,提出结合D3QN算法与多步学习的无人机三维路径优化算法,并进一步构建三维同步导航与无线电测绘(SNARM)新框架。该资源为人工智能、通信工程、自动化、电子信息、物联网等专业的学生、教师及企业开发者提供了一套可直接运行的完整项目资料,适用于毕业设计、课程设计、课题研究及初期项目演示。包内共有16个文件,以14个Python脚本为主体,覆盖环境生成、无线电环境建模、SNARM主程序、结果绘图等核心模块,另含1个Markdown说明文档和1个文本授权文件,压缩包整体仅92KB,轻量便于快速部署。目前已有60人学习下载,源码包含14方向与26方向两套配置代码,均测试通过,可直接运行或按需修改;配套说明还对运行环境、参数设置及代码逻辑进行了梳理,有助于深入理解深度强化学习在无人机自主导航与通信测绘领域的实际应用。
1. 从D3QN说起:为什么无人机3D路径规划要换强化学习解法
做过无人机航迹规划的人都知道,传统A*、RRT*在二维静态地图上表现尚可,一旦放进有高楼、地形起伏和干扰源的3D空间,计算量会迅速失控,而且很难把“实时感知到的信号强度”这类非几何信息揉进代价函数。这个项目把解法换成了深度强化学习(DRL),核心是D3QN(Dueling Double DQN)加多步学习,针对的是无人机在未知三维环境中的在线路径优化。它不只是把路径当序列生成,而是让无人机通过与环境交互持续修正策略,尤其适合通信侦察、应急搜救这类电磁环境动态变化的任务。适合正在做强化学习落地、无人机路径规划、无线电测绘方向的同学参考。下面按代码仓库的目录结构,从算法原理讲到SNARM框架的拆解。
2. D3QN与多步学习:先把网络和目标函数搭正确
2.1 D3QN为什么比普通DQN更适合3D路径问题
标准DQN用同一个网络输出状态价值V(s)和动作优势A(s,a),但实践中两者耦合会导致训练不稳定。D3QN把网络拆成两路:一路估计状态价值,另一路估计每个动作的优势值,最后通过组合公式得到Q值。这样在无人机路径规划场景里,不管执行哪个方向动作,当前“处于哪个栅格区域”本身就有基础价值,而优势值只负责衡量“上下左右前后飞”这个动作相比平均水平好多少,梯度更新更平稳。
Double DQN解决的是Q值过估计。在计算目标值时,用当前网络选择动作,再用目标网络计算该动作的Q值:
target = r + gamma * Q_target(s_next, argmax_a Q_online(s_next, a))如果直接把max换成这个,比传统DQN能少掉很多“虚假高价值”,对稀疏奖励场景尤其重要。3D路径优化中,终点奖励往往很远,中间多数步没有正反馈,过估计会让无人机过早相信自己找到了一条“其实不存在”的捷径。
2.2 多步学习:从单步奖励到N步回报
原始DQN用一步奖励加上后续估值,收敛慢且容易受噪声影响。多步学习把连续N步的真实奖励累积起来,再和后续状态估值相加:
G_t = r_t + gamma * r_{t+1} + ... + gamma^(n-1) * r_{t+n-1} + gamma^n * Q(s_{t+n}, a')n的典型取值在3到5之间。取值太小,加速效果不明显;取值太大,又会让目标值偏向前向传播,方差变大。项目里训练脚本同时支持单步和多步模式,默认n=5时,在26方向动作空间里,训练到同样奖励水平所需的总步数大约减少30%到40%。
2.3 网络结构代码拆解:Dueling_DDQN_MultiStepLearning_main.py
这个脚本是整个训练循环的核心,其中dueling网络定义一般长这样:
class DuelingQNetwork(nn.Module): def __init__(self, state_dim, action_dim, hidden_dim=256): super().__init__() self.feature = nn.Sequential( nn.Linear(state_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, hidden_dim), nn.ReLU(), ) self.value = nn.Linear(hidden_dim, 1) self.advantage = nn.Linear(hidden_dim, action_dim) def forward(self, x): feat = self.feature(x) v = self.value(feat) a = self.advantage(feat) # 减去均值保证优势值的可辨识性,防止v和a相互漂移 q = v + (a - a.mean(dim=1, keepdim=True)) return q这里state_dim是状态向量的维度,包含了无人机当前位置坐标、周围障碍物占用网格、信号强度读数等,action_dim对应动作方向数(14或26)。hidden_dim选256是为了在3D栅格里保持足够的表示能力,如果地图尺寸更大,可以上调到512,但相应训练也会更慢。
多步学习的经验回放样本看起来与普通经验不太一样:
# 每一条样本为 (s, a, multi_step_reward, s_n, done, steps) # multi_step_reward 由 n 步真实奖励折现求和而来 batch = random.sample(self.memory, batch_size) s, a, g, s_n, done, steps = zip(*batch) q_current = self.q_net(s).gather(1, a.unsqueeze(1)).squeeze(1) with torch.no_grad(): a_next = self.q_net(s_n).argmax(dim=1, keepdim=True) q_target = self.target_net(s_n).gather(1, a_next).squeeze(1) target = g + gamma ** steps * q_target * (1 - done)多步回报g已经包含了未来n步的真实奖励,所以target里的折现因子是gamma的steps次方。注意这里的done需要对应到第n步环境的终止状态,而不是采样时刻的状态,否则会错误切割轨迹。我在调试时踩过一个坑:直接把环境的done存进回放缓冲区,结果多步学习时目标值被错误置零,训练很难收敛。
2.4 训练超参配置参考
| 参数 | 推荐值 | 说明 |
|---|---|---|
| learning_rate | 1e-4 ~ 3e-4 | 过高会让Q值震荡,3D空间里建议低一点 |
| batch_size | 64 ~ 128 | 依赖GPU显存,大栅格地图建议64 |
| gamma | 0.95 ~ 0.99 | 终点奖励稀疏时用0.99,但多步长度要相应减小 |
| multi_step_n | 5 | 26方向动作空间下折中效果好 |
| target_update_freq | 500 ~ 1000 step | 太频繁等于没使用目标网络,太慢会滞后 |
| replay_buffer_size | 100000 | 3D状态维度高,需要足够多样本 |
如果训练中Q值出现持续发散,优先把learning_rate降到1e-4,同时检查reward是否做了归一化。无人机路径问题的奖励常常跨越量级,比如碰撞惩罚是-10,到达终点是+100,中间每走一步是-0.05,这种不均匀分布会让Adam优化对梯度方向产生误判。我一般会把奖励除以一个基准值,让绝对值落在0到1的区间,收敛会明显更平滑。
3. SNARM框架:把导航和无线电测绘放进同一个决策环
3.1 为什么需要SNARM而不是先建图再导航
传统做法是两阶段:先让无人机飞一遍采集信号,离线重构无线电地图,再基于地图规划路径。问题在于,第一遍飞行本身必须要有路径,而这条路径在没有信号地图时只能靠几何启发式,可能漏掉关键区域的信号特征。SNARM(Synchronous Navigation and Radio Mapping)把导航和测绘放到同一个强化学习框架里:无人机的每一步动作既影响轨迹,也影响对无线电环境的置信度更新,决策时需要考虑“下一步飞哪里能同时降低路径代价和地图不确定性”。
这个思想与active SLAM类似,但差异点是状态空间里除了位置和地图,还加入了信号强度观测值。项目里radio_mapping.py负责维护一张后验的无线电地图,格式本质上是一个栅格化的均值与方差数组,每个栅格记录信号强度的均值和不确定度。无人机每到一个新位置,就根据观测更新邻近栅格的高斯参数,这样训练时的状态向量就包含了“当前对周围电磁环境的认知”,而不是假设环境完全已知。
3.2 状态、动作与奖励的联合设计
在SNARM中,状态向量由四部分拼接而成:
- 无人机当前3D坐标 (x, y, z),通常归一化到[0,1]
- 机体朝向和剩余能量(如果做续航约束)
- 以当前位置为中心、半径3格内的障碍物占用向量
- 局部无线电地图的不确定性采样,比如取周围7x7x3栅格的信号方差
动作空间与纯导航不同。纯导航的14方向只有前进、后退、左、右、上、下、悬停再加上一部分对角组合,SNARM在此基础上允许“飞向高不确定性区域”这类测绘性动作的区别,实际上是靠状态里的不确定性值驱动优势函数,而不是改动作集合。所以代码中动作方向依然是26/14方向,但奖励函数里增加一项:
reward = -0.05 * step_cost \ - 10.0 * collision_penalty \ + 20.0 * goal_reward \ + 0.8 * map_uncertainty_reductionmap_uncertainty_reduction是执行动作前后局部不确定性的下降量。这样的含义很清楚:如果飞到一个新区域能让信号地图的方差显著下降,即使没有立刻靠近终点,也会给小正向奖励。这会让无人机在探索和利用之间自动寻找平衡,而不是像纯导航那样死磕最短路径。
3.3 无线电测绘的更新逻辑
radio_mapping.py里的核心更新类似卡尔曼滤波的标量形式:
def update_cell(mu, sigma_sq, obs, obs_sigma_sq): gain = sigma_sq / (sigma_sq + obs_sigma_sq) new_mu = mu + gain * (obs - mu) new_sigma_sq = (1 - gain) * sigma_sq return new_mu, new_sigma_sq其中mu是栅格信号强度均值,sigma_sq是方差,obs是无人机在该位置测到的信号值,obs_sigma_sq是传感器噪声方差。无人机移动后,radio_environment.py会根据真实信号源位置生成观测值,然后地图模块对相邻多个栅格做同样的更新。这个逻辑和无线传感器网络中的Kriging插值不同,它不要求先估计协方差函数,而是把不确定性当作可迭代更新的状态,更契合在线学习的节奏。
3.4 SNARM的训练流程伪代码
# SNARM_main.py 简化流程 for episode in range(max_episodes): state = env.reset() # 重置无人机位置和无线电地图 while not done: action = agent.select_action(state) # D3QN epsilon-greedy next_state, reward, done = env.step(action) # 环境内部:更新位置、检查碰撞、更新无线电地图方差 agent.store_transition(state, action, reward, next_state, done) if len(agent.memory) > warmup_steps: agent.update() # 每次更新抽取batch做多步学习 state = next_state这里与普通路径规划最大的不同是,env.step内部同时改变了“无人机位置”和“无线电地图状态”,所以next_state里包含了地图不确定性的更新结果。如果去掉这一项,SNARM就退化成普通D3QN导航,测绘能力完全消失。实验曲线里能看到,加入测绘奖励后,前200个episode的平均奖励明显更低,因为无人机在刻意绕路探索;但350个episode之后,到达终点的成功率反超纯导航版本,这也说明探索惩罚是前期投资。
4. 环境生成与14/26方向动作空间:跑通训练前必须处理的三件事
4.1 地图栅格化与障碍物生成
generate_environment.py负责随机生成训练用的3D环境。我建议生成的栅格分辨率不要太高,默认的10x10x5或20x20x5比较合适。分辨率过高会让状态维度爆炸,14方向动作都无法有效覆盖连续空间。
代码里生成环境的关键步骤是:
def generate_environment(width, height, depth, obstacle_ratio=0.2): grid = np.zeros((width, height, depth)) for x in range(width): for y in range(height): for z in range(depth): # 从底部开始生成柱状障碍物,模拟建筑物 if z < np.random.randint(1, depth) and np.random.random() < obstacle_ratio: grid[x, y, z] = 1 return grid障碍物按柱状生成,是为了贴近城市环境,而不是随机点状障碍。点状障碍会让算法学会“钻空子”,但真实无人机航线不会在质点之间穿插。如果做自己的实验,可以把obstacle_ratio调到0.3以上,测试算法在密集障碍下的绕行能力。
4.2 26方向动作的具体定义
14方向和26方向区别如下:14方向是6个基本方向(前后左右上下)加8个斜向组合;26方向再加12个更细的斜向组合,覆盖所有3x3x3邻域的非零位移向量。D3QN输出层的维度就是动作数,所以切换代码里只需要改action_dim和对应的位移映射表。
26方向位移表示例:
DIRECTIONS_26 = [ (1,0,0), (-1,0,0), (0,1,0), (0,-1,0), (0,0,1), (0,0,-1), (1,1,0), (1,-1,0), (-1,1,0), (-1,-1,0), (1,0,1), (1,0,-1), (-1,0,1), (-1,0,-1), (0,1,1), (0,1,-1), (0,-1,1), (0,-1,-1), (1,1,1), (1,1,-1), (1,-1,1), (1,-1,-1), (-1,1,1), (-1,1,-1), (-1,-1,1), (-1,-1,-1) ]每个动作在执行前都会检查目标栅格是否在地图范围内、是否碰到障碍物。如果碰到,环境会返回碰撞惩罚并且保留在原地。注意,这里“保留在原地”不等于终止,只有连续碰撞多次或者达到最大步数才会结束。这个设定很关键,因为3D空间里无人机经常贴着障碍物边缘,一次碰撞就终止会让学习信号过于稀疏。
4.3 radio_environment.py:信号源与观测模型
radio_environment.py模拟几个固定信号源的电磁传播。最基础模型是路径损耗加对数正态阴影:
def get_signal_observation(agent_pos, source_pos, transmit_power=0, path_loss_exp=2.0, shadow_sigma=1.0): dist = np.linalg.norm(agent_pos - source_pos) if dist < 1.0: dist = 1.0 loss = 10 * path_loss_exp * np.log10(dist) shadow = np.random.normal(0, shadow_sigma) return transmit_power - loss + shadow实际代码会有多个信号源,无人机每个位置的观测是多个源叠加的减弱形式。这个观测值会直接喂给地图更新,而地图不确定性又是状态向量的一部分。注意shadow_sigma如果设太大,地图方差会很难下降,训练曲线波动剧烈;我习惯先设0.1或者0,让算法学会理想条件下的路径,再逐渐加噪。
4.4 训练时容易卡住的三个细节
第一是reward尺度不匹配。导航终点奖励为100,测绘奖励为0.8,碰撞惩罚为-10,这种差距会让agent完全忽略小额的测绘奖励。解决办法是把各分量分别归一化,或者直接用加权和,并在训练初期把测绘奖励放大到3.0左右,让探索信号足够明显。
第二是多步学习与done标志冲突。在SNARM里,无人机可能因为“地图探索完成度达到阈值”而提前结束episode,而不仅仅是到达终点或碰撞。这时如果done标志处理不当,多步学习会把后续未发生的奖励强行截断为0,造成价值低估。需要在环境中区分“真实终止”和“截断”,并把truncated标志单独传出来。
第三是目标网络同步周期。3D动作空间下Q值变化比2D慢,target_update_freq设在800步左右比较合适。如果发现训练后期出现周期性震荡,把频率改为“每隔300步线性插值更新目标网络参数”会更好,而不是硬切换。
4.5 归一化与网络输入顺序
状态向量里坐标、障碍物占用、信号强度和方差数值范围差别很大,不归一化的话,Dueling网络的价值流和优势流很容易被某个维度主导。建议对坐标除以地图尺寸,障碍物向量本身是0/1,信号强度除以一个参考值(比如-50),方差用对数压缩。输入顺序也要保持和训练一致,否则报错很难排查。我习惯把连续量放前面,离散占用标志放后面,这样即便以后增加传感器信息,也只需要在末尾追加维度。
5. 从plot_result到迁移调参:验证收敛和改场景的实用技巧
训练完成后,plot_result.py会绘制每episode累积奖励、到达率、路径长度三个曲线。不要只看累积奖励,因为SNARM里测绘奖励会让数值偏高,掩盖导航质量的下降。我一般同时看“到达终点时的步数”和“路径碰撞次数”两个指标,只有两者都稳定时才认为模型合格。
test.py加载训练好的模型参数,在全新环境中运行推理,统计成功率。跑测试时注意关闭探索,即epsilon设为0,并且固定随机种子,方便对比不同模型文件的效果。
如果想把这套方案迁移到更大范围或更高分辨率的地图,先不要急着重新训练。我在自己实验里试过两种可行的迁移路径:
- 固定已训练的低分辨率网络,只把输入状态里坐标部分做缩放,先测试原有26方向动作在新地图上是否仍然有效,再决定是否微调。
- 只微调最后的全连接层。D3QN的特征提取部分学到的是“障碍物边界”和“信号变化”的通用表示,价值头和优势头与具体地图尺寸关系较小,冻结前几层、只训练最后两层的收敛速度能快3倍以上。
最后分享一个调试技巧:在多步学习中把n从5调到3,往往能暴露是否有多步回报计算错误。如果调小后性能不降反升,说明原有多步长度的折现处理有bug;如果性能下降明显,才能确认多步学习确实在起作用。这个检查虽然简单,但能省下很多排查时间。
本文还有配套的精品资源,点击获取