资讯动态

基于MASAC的多无人机协同路径规划实战:从原理到代码实现

发布时间:2026/8/28 20:21:31 来源:尧图企业网站定制
简介强化学习作为人工智能领域的关键技术在多智能体系统中展现出巨大潜力。多智能体强化学习面临环境非平稳、动作空间爆炸等挑战而最大熵算法SAC通过熵正则化提升探索稳定性其多智能体变体MASAC结合集中训练与分散执行框架有效解决协同决策问题。在无人机编队、自动驾驶、机器人协作等场景中多无人机协同路径规划是典型应用要求无人机在未知环境下保持队形并避免碰撞。本文基于PyTorch实现MASAC算法详细阐述环境建模、状态动作空间设计、奖励函数构建及训练调参经验为多智能体协同控制提供可复现的工程参考。 多无人机协同路径规划这几年是真火但真正能把训练代码跑通、把仿真结果调稳的人并不多。我去年接手了一个无人机编队协同的仿真验证需求目标很直接让3到5架无人机在未知障碍物环境下从各自起点出发保持编队队形避开碰撞最终全部到达目标点。一开始我走的是传统凸优化加一致性控制的路线发现障碍物一多、环境一变就非常被动航迹重规划次数多到根本没法看。后来切换到MASAC强化学习算法用Python重写了环境、训练和评估整套代码效果才真正立住了。这篇文章就把我基于MASAC做多无人机协同路径规划的一套完整思路、代码结构和踩坑记录分享出来。这套方案适合这三类人看一是刚开始接触多智能体强化学习想找一个能落地的协同规划项目做参考的学生二是已经从单智能体SAC切入但不太清楚怎么把它扩展到多无人机场景的工程师三是科研人员想快速搭一套可复现的仿真验证环境对比不同奖励函数和网络结构下的收敛表现。项目源码基于Python和PyTorch实现核心算法用MASACMulti-Agent Soft Actor-Critic环境是自研的多无人机二维/三维仿真环境后面我会把每个模块拆开讲。1. 多机协同问题的本质与算法选型逻辑1.1 单机路径规划与多机协同的差异单无人机路径规划里核心问题是一个智能体在环境约束下找到从起点到终点的可行路径经典方法有A*、RRT、人工势场法以及单智能体强化学习算法。只要环境建模准确、静态障碍物已知这些方法都能得到不错的效果。但多无人机协同路径规划不是单机规划的简单求和。举个最简单的例子两架无人机同时飞向同一个目标点单机各算各的路线结果大概率是双方在中途就发生了空间重合。多机协同关注的核心是“耦合”——无人机之间不仅要考虑环境障碍物还要相互避碰甚至要保持特定的编队构型。这意味着奖励函数里必须有“队友之间距离”的项而且动作选择会影响整个编队的下一步状态分布。这个“耦合”让问题的维度从单机的有限状态空间暴涨成联合状态空间。举个例子3架无人机每架机的状态向量是4维位置xyz加一个速度联合状态就是12维动作空间也一样如果每架机是4维连续动作联合动作就是12维。如果使用DQN这类基于离散动作和表格/值函数的方法动作空间规模没法看如果使用策略梯度又很难处理连续动作下的高方差更新。这也是我最终选用MASAC的核心原因。1.2 为什么选MASAC而不是DQN、DDPG或PPO我现在复现这个项目时并没有把市面上所有算法都做一遍但基于之前的经验我对比过DQN、DDPG、PPO和SAC/MASAC这几条路线。DQN虽然有各种改进版本但它天然面向离散动作空间不适合油门、偏航角这类连续变量DDPG虽然可以处理连续动作但训练稳定性差超参数敏感一不留神Q值就发散PPO在单智能体任务里稳定度不错但在多智能体场景下每个智能体都在同时更新策略环境的非平稳性会让每一个单机的PPO优化目标都在移动靶子上做梯度上升。MASAC的核心优势在于它把SAC的最大熵框架搬到了多智能体场景。最大熵的意思简单说就是智能体在累积奖励的同时策略还要尽量随机化避免过早收敛到某个次优的确定策略。多智能体环境下最大的问题就是环境非平稳性别的无人机也在实时改变策略你的经验池里的数据其实是在一个不断变化的动态环境中采样出来的。MASAC的熵正则化机制让策略保持一定的探索度在训练初期能更稳地探索整个状态空间不容易被队友的策略变化带偏。这句话实际用下来是非常明显的体验。我在同一个环境里换用DDPG和多智能体版本DDPG大概每跑3次训练就有1次结果崩掉而MASAC即便超参数差一点也能收敛到可用水平只是方差会大一点。这个差距在做科研和工程复现时非常致命稳定压倒一切。1.3 项目定位与技术边界这里的实现目标是二维平面内的多无人机协同路径规划障碍物是静态圆形或者矩形无人机被建模成固定高度下的质点。如果你需要做三维编队、动态障碍物、甚至复杂气象下的规划这套代码的算法骨架不需要推翻但环境模型和奖励函数得改不少。所以项目边界要讲清楚这是一套验证多智能体PPO/SAC类算法在协同路径规划上可行性的参考实现不是一套能达到军事标准或工业落地的完整飞行系统。仿真层面我的实现里使用自研的Python环境而不是直接上AirSim或Gazebo。这样做的原因很简单在算法验证阶段自研环境更轻量、容易控制变量、调试成本低。如果你要迁移到Gazebo需要做的是把环境类里的状态获取和动作下发替换成ROS topic这个在文章最后会专门讲。2. MASAC算法核心机制CTDE框架与最大熵的变体2.1 从单智能体SAC到多智能体MASACSAC的核心思想是在标准强化学习目标函数中引入熵项。如果用数学表达式描述SAC要最大化的是每个时刻的累积奖励加上一个策略熵项。熵稍微解释一下如果一个策略在一个状态下输出的动作概率分布非常“尖锐”比如90%概率选择动作A、10%概率选择B那么熵就低如果两个动作概率各50%熵就高。SAC希望策略在收益和随机性之间找到平衡点这就是最大熵强化学习的基本思路。MASAC是多智能体版本的SAC。它的做法是在每个智能体的状态信息里引入其他智能体的信息特别是在Critic网络里。比如无人机i的状态量不仅包括自己的位置速度和目标点信息还包括队友的位置和速度。训练时Critic用全局信息做价值评估Actor只用局部可观测信息做动作决策。这就是“集中训练、分散执行”的经典范式也是MASAC能够处理多智能体非平稳性的关键原因。2.2 集中训练与分散执行的关键直接看“CTDE”可能有点抽象我用编队飞行的逻辑解释一下。在训练阶段仿真器是上帝视角每架无人机的状态都可以直接读出来。此时我让每架无人机的Critic网络输入“所有无人机的联合状态和联合动作”这样它就能感知到队友策略的变化给出一条稳定的价值评估。但到了部署阶段不会有一台中央计算机能够实时获取所有无人机的完整状态再给每架机下发精确动作即便有通信延时也是大问题。所以每一架无人机实际执行策略的Actor网络输入只包含自己传感器范围内的信息包括自己的状态、目标点、可探测到的障碍物以及编队邻居的状态。这样做的好处是兼顾了训练稳定性和部署可行性。如果训练时Actor也用局部信息由于看不到队友变化策略很难学会协同如果部署时还要用全局信息那就不具备分布式执行的条件。MASAC的工程价值就在于它用训练阶段的高信息量换来了执行阶段的高适配性。2.3 自动温度系数与熵正则化的稳定作用SAC里有一个温度系数控制熵项在总目标函数中的权重。温度系数大策略更偏向探索温度系数小策略更偏向利用已有Q值。手动调这个系数非常痛苦因为不同训练阶段需要不同的探索水平。SAC作者提出了自动调节版本让智能体在训练过程中自己控制这个系数目标就是把熵维持在预设阈值附近。MASAC在原理上与SAC一致。我的理解是这个自动温度系数在多智能体环境里特别宝贵。因为多智能体环境比单智能体更不稳定手动固定温度系数常常会导致训练前中期探索不足。自动温度机制能让策略在队友策略还不稳定的时候自动保持随机性等到环境逐渐稳定了再慢慢降低熵平滑提高确定性。这个特性对收敛过程非常有帮助我在调参阶段几乎没动过温度相关的超参数它自己就能找到比较合理的平衡点。3. 训练环境搭建状态空间、动作空间和奖励函数设计3.1 简化但可扩展的无人机运动模型我没有一上来就用坐标系的完整六自由度模型。在强化学习算法验证阶段那样做只会让调参难度指数上升。我采用的是二维平面内的质点模型加一阶惯性约束。每架无人机的状态是 (x, y, vx, vy)其中x和y是坐标vx和vy是速度。控制输入是目标加速度的x分量和y分量动作值范围被限制在-1到1之间再乘上最大加速度系数。这个模型不是真实飞控里的轨迹控制器但对多智能体协同路径规划算法的验证完全够用。真实无人机有内环姿态控制你给它的是一组期望速度或者期望航向底层飞控会跟踪。所以这里用加速度控制其实是合理的抽象。如果你后续要迁移到AirSim或Gazebo也只需要把动作转换成期望速度或者期望姿态角即可上层决策逻辑不必大改。我在很多厂里的实际项目中算法层面都是用这种简化模型做预研再交给飞控工程师去做真机部署。3.2 状态空间、观测空间和动作空间怎么定义我设定的目标是5架无人机从不同起点出发飞到同一个目标点全程不能互相碰撞也不能撞障碍物。环境区域是一个200米×200米的二维平面随机生成5个圆形障碍物圆心和半径在每次reset时随机变化。目标点位于(150, 150)。每架无人机的观测空间包含以下内容自身位置和速度4维目标点相对位置2维距离最近的3个障碍物的相对位置6维其他4架无人机相对自身的位置8维总体观测维度是20维。全局状态空间在训练时会把所有无人机的观测都拼接起来形成一个100维左右的向量。动作空间是2维连续动作控制的是加速度在x和y方向的分量。为了让训练初期更容易探索出“向目标点移动”的动作我还加了一个动作加权系数。这个设计看起来简单但有一个非常关键的细节我故意没有把“其他无人机与自身是否可能碰撞”这种高度抽象的信息作为输入让网络自己从相对位置中学习碰撞关系。这样做的好处是环境换了障碍物布局甚至换了机群数量网络输入维度不变时可以直接泛化坏处是训练时间会变长网络需要自己归纳出“别人离我太近不是好事”这个隐性规则。3.3 奖励函数到达、避碰、编队三件套奖励函数是整个项目中最影响训练效果的模块我前后迭代了五个版本。最终版本由四部分组成到达奖励到目标点距离小于阈值时给予正向奖励并且本回合结束。为了让智能体学会接近目标我还加了一个“稀疏到达大奖励”但只有在最终判定成功时触发。碰撞惩罚每架无人机与障碍物或其他无人机的距离小于安全半径时给予大的负向惩罚并终止本回合。这里我分了两档如果距离小于碰撞半径会执行终止和惩罚如果距离小于预警半径但大于碰撞半径只给一个小的负向惩罚不终止目的是让智能体学习保持安全间距。编队保持奖励无人机的目标是到达同一个目标点但我希望它们在整个飞行过程中保持一定的队形。我定义了一个编队中心点也叫做“虚拟编队参考点”每架无人机离参考点的目标相对位置越近奖励越高。实际代码里我没有强制队形固定而是对偏离期望位置的偏差做了惩罚。进度奖励每步给一个小的即时奖励等于“当前到目标的距离”减“上一步到目标的距离”再乘一个系数。这可以避免纯粹稀疏奖励带来的收敛过慢问题。奖励系数我列一下方便大家参考奖励项系数触发条件到达目标点100距离阈值 3m碰撞/预警惩罚-50 / -1距离小于碰撞半径 / 预警半径编队偏差惩罚-0.02 × 偏差²每步持续触发距离减少奖励0.5 × Δ距离每步持续触发这套设计最终让算法能在训练12万步后实现稳定到达率。如果你复现时收敛速度太慢可以先试着调大距离减少奖励的系数这是最常用的加速手段。4. 核心代码实现与工程结构4.1 项目文件结构我最终的Python项目按下面这种方式组织结构清爽每个模块职责单一调试起来也方便multi_uav_masac/ ├── envs/ │ ├── multi_uav_env.py # 多无人机协同环境 │ └── obstacle_pool.py # 障碍物生成逻辑 ├── models/ │ ├── networks.py # Actor/Critic 网络结构 │ ├── masac_agent.py # MASAC智能体类 │ └── replay_buffer.py # 经验回放池 ├── train.py # 训练主入口 ├── evaluate.py # 评估主入口 ├── config.py # 超参数配置 └── utils/ └── logger.py # 训练日志记录config.py里放着所有超参数训练或评估时直接从config读取。我习惯把所有环境参数和算法参数都放一起一方面方便试验记录另一方面在多人协作时减少“参数到底写在哪个文件”的争论。4.2 环境类与核心算法类的编写思路环境类的核心方法是reset、step和render。reset时随机生成障碍物布局重置所有无人机的位置到预设起点并返回初始观测。step接收所有无人机的动作数组更新位置、速度计算奖励、终止标志和下一观测。代码量不大但每一步都可能成为性能瓶颈所以能用numpy向量化运算的地方尽量向量化而不是写for循环遍历每架无人机。MASAC智能体类的设计参考了SAC官方实现。每架无人机有一个Actor网络用来输出动作的均值和标准差一个目标Critic、一个当前Critic构成Double-Q结构。训练时每个智能体从经验池里采样一个batch用联合状态和联合动作来更新自己的Critic再用当前策略采样动作更新Actor。下面是一个简化版的网络定义代码片段不包含完整实现但你能从中看到结构import torch import torch.nn as nn import torch.nn.functional as F class Actor(nn.Module): def __init__(self, obs_dim, action_dim, hidden_dim256): super().__init__() self.fc1 nn.Linear(obs_dim, hidden_dim) self.fc2 nn.Linear(hidden_dim, hidden_dim) self.mean nn.Linear(hidden_dim, action_dim) self.log_std nn.Linear(hidden_dim, action_dim) def forward(self, obs): x F.relu(self.fc1(obs)) x F.relu(self.fc2(x)) mean self.mean(x) log_std torch.clamp(self.log_std(x), -20, 2) return mean, log_std def sample(self, obs): mean, log_std self.forward(obs) std log_std.exp() normal torch.distributions.Normal(mean, std) z normal.rsample() action torch.tanh(z) log_prob normal.log_prob(z) - torch.log(1 - action.pow(2) 1e-6) return action, log_prob.sum(dim-1, keepdimTrue)Critic的输入不再是本机单独的状态而是拼接了所有无人机状态和动作的联合向量。这里我用了独立Q网络的变体没有采用共享参数版本。实测下来独立Q网络参数多一点但训练更稳定。经验回放池里保存的数据包括联合观测、联合动作、联合奖励、联合下一观测、联合终止标志。这里必须强调“联合”两个字。在MASAC框架下训练Critic时需要完整的世界状况信息所以在经验池里存的是所有无人机的观测和动作拼成的全局向量。Actor执行时再进行切片取自己的局部观测部分。4.3 训练主循环与并行优化训练主循环的逻辑很直接初始化环境循环若干episode每步从每个Actor中采样动作调用环境step获得转移数据存入回放池当回放池容量足够后每步从池中采样train_batch_size条经验分别对每个智能体的Critic和Actor更新一次。代码结构上我做了两个优化第一如果状态重置次数很多可以用多进程并行跑多个环境增加数据采集效率第二目标网络更新采用软更新方式即每次把目标网络参数往当前网络参数方向移动很小一步。软更新能有效提高训练稳定性也是SAC默认的做法。有一个小坑值得单独说多智能体训练时的“联合奖励”怎么处理。理论上每个智能体的奖励可以不同但我在协同路径规划里给所有智能体使用了一个共享的团队奖励即每个智能体的奖励都是全局奖励的同一份数值。这样做的好处是智能体之间不存在奖励竞争更容易学会协作缺点是可能牺牲一些个体效率比如某架无人机会为了整体编队调整变得比其他无人机更慢。如果你更看重编队保持的严格性可以使用个体奖励加团队奖励的混合方案。5. 训练实战收敛过程中的坑与调参经验5.1 训练曲线怎么判断收敛我训练时记录了到达率、平均回合奖励、平均编队偏差、碰撞率这几项指标。其中到达率是最核心的指标。在训练初期5架无人机几乎全部碰墙或互撞到达率是0这很正常不用慌。大约到4万步后开始出现个别episode的零碰撞成功案例到8万步后到达率会突然上升然后总体保持一个波动上升趋势到12万到15万步基本能稳定在80%以上。这里有一个容易被忽略的判断标准看到达率是否“突变式上升”。如果环境设计得当MASAC的收敛过程往往不是线性上升而是前期长时间平台期之后某个阶段突然跳上去。这个跳变点意味着agent终于学会了“先往目标点飞同时躲开别人”这个组合策略。如果一直不出现跳变说明奖励信号有问题或熵系数自动调节失效。5.2 我踩过的三个影响收敛的坑第一个坑碰撞惩罚太重导致智能体完全不敢动。初始版本碰撞惩罚是-100结果无人机学会了待在起点不动因为这样虽然拿不到到达奖励但也不会被惩罚。这个问题在强化学习里叫“奖励悬崖”解决方法是把碰撞惩罚降到一个合理的水平同时给一个每步必需的最小探索激励。第二个坑编队保持项权重太高导致无人机为了队形宁愿偏离目标点。我一开始把编队偏差惩罚系数设成0.1结果训练出来的轨迹看起来特别“拧巴”无人机为了凑队形不停转圈到目标点的效率很低。最终我把系数降到了0.02同时引导智能体明白“编队保持是辅助目标到达目标才是主目标”。第三个坑经验回放池里旧策略数据占比过高。多智能体训练中随着策略更新旧经验里的“队友行为模式”已经过时直接使用会导致Q值评估失准。我用了两个手段解决一是回放池大小不要设得太大二是在训练后期逐步减少经验再利用次数。这个在很多SAC实现里都能通过调replay_buffer_size和batch_size来平衡。5.3 超参数参考表我把一套能稳定收敛的超参数贴在下面这个配置在5机编队200×200区域5个圆形障碍物环境下表现稳定参数名数值无人机数量5最大速度5 m/s最大加速度2 m/s²安全半径3 m预警半径6 m障碍物数量5回放池容量100000batch_size256Actor学习率3e-4Critic学习率3e-4温度学习率3e-4折扣因子0.99软更新系数0.005每回合最大步数300目标熵阈值-action_dim这个表格不是万能配置但如果你是从零开始复现建议先按这个跑通再逐步调参。我自己实验时把学习率从3e-4降到1e-4后训练时间大约翻倍把batch_size从256降到64后方差明显变大所以这两个参数尽量维持在上表附近。6. 从仿真到实机的扩展建议6.1 如何迁移到Gazebo或AirSim如果你要把这套训练好的策略搬到Gazebo或AirSim里核心工作不在算法而在环境接口。我的建议是写一个仿真适配器把MASAC环境类的reset和step接口分别转成Gazebo场景重置和里程计读取。具体说就是把无人机的位姿从Gazebo的ROS topic中读出来把MASAC网络生成的目标速度发送给PX4或ArduPilot的飞控栈。这个迁移过程中最需要关注的是动作映射频率。自研环境里step是20HzGazebo里如果你也是20Hz发布控制指令Model Predictive Control式的飞控响应基本能跟踪上。但如果在Gazebo里实际步长太大比如5Hz那么训练出来的加速度控制指令就失真了。解决办法是在自研环境里把step频率调低重新训练再迁移。6.2 部分可观测与通信约束仿真训练时我用的是全局观测但实际部署时同一时刻每架无人机无法获得所有其他无人机的精确位置。一是通信带宽受限二是远处无人机的数据对当前决策价值不大。所以我在工程化版本里把观测空间做了截断只观测通信距离内的队友通信距离设为30米超过这个距离的队友不进入观测。这个改动听起来不大但会导致模型输入的“队友数量”不再是固定5个可能是0到4个不等。我建议用“最大邻居数量”加“填充补零”的方式处理即固定分配最多4个队友的观测槽位实际邻居不足时用0填充。这种方式在强化学习里非常常见虽然会牺牲一点信息效率但能保持网络输入维度不变不需要改网络结构。6.3 奖励塑形与安全兜底实机部署时神经网络策略的输出不能直接无条件使用。我会在策略输出后面串一个安全过滤器如果计算出的目标加速度会让无人机在最近一个控制周期内进入禁飞区或碰撞锥就用安全过滤算法把它修正到安全方向。这个思路在工程上叫“安全屏障”和强化学习本身是互补关系。另一种做法是把安全约束嵌入到奖励函数里比如使用基于约束的强化学习框架。但那个实现复杂度会上升不少我的建议是先跑通“训练完成 部署时加安全过滤器”这条路线再考虑更复杂的CBF-RL方案。6.4 关于代码复现的几点提醒最后再说几句关于复现这套代码的建议。首先随机种子一定要固定不然多智能体训练的结果波动会让你怀疑人生。我在训练脚本里固定了Python、numpy、PyTorch和环境的随机种子这样才能保证每次训练的轨迹可追溯。其次训练过程中建议定期保存checkpoint不要等训练结束才保存因为分布式环境随时可能因为显存不足或终端断连导致前功尽弃。我自己用的显存是单张RTX 30905架无人机的MASAC训练网络规模不大显存占用不到4GB所以大部分消费级显卡都能跑得动。如果你用的是CPU训练时间会非常感人强烈建议至少使用一张入门级N卡。这个项目的完整Python代码我已经打好包里面包含自研环境、MASAC智能体、训练主程序、评估脚本和几组训练好的模型权重文件。拿到之后先运行train.py再运行evaluate.py应该能在20分钟左右看到到达率的上升曲线。训练时如果遇到收敛问题优先检查奖励函数的权重设置其次检查回放池大小最后还是不行再动网络结构这个排查顺序能帮你省下大量时间。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价