ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

复杂环境下异构固定翼无人机集群协同搜索的Matlab仿真复现与实现

复杂环境下异构固定翼无人机集群协同搜索的Matlab仿真复现与实现 复现复杂环境下的异构固定翼无人机集群协同搜索这件事在我这边捏着鼻子做了差不多两周时间。先说结论整套流程能在Matlab里跑通并不难真正的门槛在于把“自适应决策”和“避障”放进同一个框架里同时照顾到每架飞机的固定翼约束。这篇文章我会把自己从零搭建这套仿真时踩过的坑、权衡过的方案、以及最终代码里的关键实现细节从头捋一遍希望给正在复现或者准备入场这个方向的读者提供一份能直接“抄作业”的参考。这个方向一句话说清楚多架飞行速度、最小转弯半径、机载传感器能力各不相同的固定翼无人机在存在障碍物和未知威胁的复杂空域中通过彼此信息共享和实时任务分配协商出谁去搜索哪一片区域、遇到威胁怎么重新规划最终以尽量少的飞行代价覆盖尽量大的搜索范围。它是协同控制、路径规划、目标分配三个问题的综合体Matlab仿真是把这几块拼起来后成本最低的验证方式。适合正在做毕业设计、准备小论文验证或者单纯对集群智能感兴趣的朋友参考。1. 项目核心与研究价值拆解1.1 为什么选定“异构”集群固定翼和旋翼最大的区别在于运动学约束固定翼不能原地悬停速度有下限转弯必须借助滚转和偏航任何航迹都必须考虑最小转弯半径。同构集群里所有飞机能力一致问题简化成“多辆车跑同一个运动模型”策略上相对好做但真实任务里异构是常态有的飞机飞得快负责快速侦察有的飞机带相机分辨率高负责精细扫描有的飞机续航久负责外围警戒。这些差异放在一起搜索资源怎么分配就成了一个需要显式建模的问题。异构也会直接放大协同搜索的复杂度。飞行速度不同意味着同一时刻两架飞机可能处在完全不同的航段传感器探测范围不同意味着同一个网格对每架飞机的“可搜索收益”不同转弯半径不同意味着某架飞机可能根本飞不进某个狭窄通道。这时候如果还用同构假设去做会出现“任务分配给它但它根本飞不过去”的局面。所以真正的异构集群协同本质上是在“能力差异”约束下找一组可执行、可协同的决策这也是自适应决策存在的意义。1.2 “复杂环境”到底复杂在哪这套课题里“复杂环境”不是一句修饰它具体指三种情况第一已知静态障碍物比如建筑物、山体、禁飞区这一类用多边形或栅格就能表达第二随机出现或任务中途侦测到的威胁区域比如雷达威胁、防空火力圈通常建模成圆形或带衰减概率的风险区第三通信和信息的非理想前提比如部分区域信息缺失、邻居状态更新延迟。把这些放在一起固定翼无人机的避障就不再是“前方有障碍物就停一下”这种小车式逻辑。飞机速度高、惯量大规划必须预留未来几秒内的可飞航迹同时因为转弯半径大大多数在小车仿真里好用的局部避障算法比如纯人工势场法生成的路径经常在几何上不可飞行。这也是为什么这个课题在实际落地时大家会更多回归到几何路径生成和带约束优化。1.3 复现这类项目的通用价值如果你现在手里拿到的是别人已经写好的完整代码复现的意义不只是“让图跑出来”。这类研究型代码最大的价值在三点一是你能通过调参理解每个模块的决策逻辑什么参数敏感、什么参数冗余这种感知只有动过手才有二是方便做模块替换实验比如把避障算法从几何法换成采样式路径规划对比指标变化三是整个框架可以迁移到水面无人艇、地面无人车队等其他平台。复现本身不一定要产出新算法但能帮你把“论文里的流程图”翻译成“能跑的数据流”这在科研早期比多读几篇文献更重要。2. 自适应决策与协同搜索的算法逻辑2.1 决策分层的整体思路从工程实现角度我不会把这个问题当成一个巨大的端到端优化问题而是拆成分层的决策结构。最底层是航迹跟踪控制用PID或纯追踪都行中间层是单机的避障与航迹点生成负责处理静态障碍物和临时威胁最上层是集群任务分配与搜索方向决策负责回答“哪架飞机去哪个区域”。这个分层的好处是模块解耦每一层有独立的输入输出调试时不会牵一发动全身。上层决策频率可以低一些比如每0.5秒到1秒更新一次分配中层避障因为要应对突发威胁更新频率需要高一些比如0.1秒到0.2秒底层控制则按照飞机的运动学模型逐帧更新。如果三层串成同一个循环且频率一致计算负担会很大而且高频任务分配容易导致决策抖动。2.2 自适应决策的数学表达自适应决策在论文里经常套POMDP部分可观测马尔可夫决策过程的壳但实际复现时很少有人直接解POMDP因为状态空间和观测空间太大。常见的折中做法是把决策问题简化成一个带约束的收益最大化问题。每一架飞机候选行动集合是“去下一个搜索区域”“继续沿当前航向搜索”“转入避障模式”“悬停等待通信同步”四种模式然后对每个候选行动计算收益值选择当前状态下的最高收益行动。收益函数可以设计成这样benefit w1 * coverage_gain w2 * discovery_prob w3 * task_priority - w4 * collision_risk - w5 * path_costcoverage_gain表示这个行动能让本机覆盖多少尚未搜索的网格discovery_prob表示目标出现在这个范围内且能被发现的主观概率task_priority来自上层任务分配collision_risk反映进入威胁区的风险指数path_cost则是消耗的燃油和时间。每个权重需要在试验中调整权重过大容易让飞机只顾局部搜索而忽略避障权重过大会让集群过度保守。2.3 协同搜索中的任务分配机制在没有中心节点的情况下我采用市场竞价机制来分配区域而不是全局匈牙利算法。基本思路是每一个待搜索的子区域被抽象成一笔“任务”每架无人机根据自己的当前位置、速度和传感器覆盖能力计算完成这笔任务的代价然后向集群广播自己的“报价”收到其他飞机消息后如果自己报价高于对方就把任务让出去如果报价更低就尝试接管。这个机制实现简单、通信开销可控而且天然支持异构差异。需要注意的是竞价机制要加一个“粘性”策略避免任务在不同飞机之间连续倒手。刚才说过固定翼飞机一旦转向代价是时间和燃油决策频繁跳转会导致飞机在空中绕圈。我采用的方法是让飞机在单位时间内重复声明同一个目标响应当前目标的状态变化幅度较小时不参与竞价只有当前任务的收益下降超过阈值才允许重新投标。2.4 固定翼约束下的避障策略固定翼避障不能只做“当前时刻避障”必须把未来一段航迹都纳入校验。我用的基础方案是基于几何关系的航向修正先预判当前航向与最近障碍物的最小距离如果小于安全间隔就计算一个绕行航向绕行航向必须经过Dubins曲线校验确保飞机能在最小转弯半径限制下抵达新航向。Dubins路径是固定翼规划里绕不开的工具。它描述了一架具有最小转弯半径的飞机在给定起点和终点位姿时能以“圆弧-直线-圆弧”的组合完成路径。对于避障场景我不需要每次都求解完整Dubins路径只需要用它生成绕障的参考航向和中间航路点再交给底层控制器去跟踪。这样既保证了计算效率又保证了生成的航迹可飞。3. Matlab仿真实现架构与关键代码设计3.1 仿真框架与数据流从代码架构上看我把整个仿真拆成下面几个模块场景初始化、运动学更新、感知与通信、决策与任务分配、避障计算、可视化与数据记录。主循环里每个时间步依次调用这些模块保持统一的输入输出接口。数据流大概是这样的场景模块生成初始障碍物图和威胁区运动学模块根据当前速度、航向和控制量更新每架飞机的位置姿态感知模块为每架飞机生成一个带有限探测范围的局部地图决策模块基于局部地图和收到的邻居信息更新任务目标避障模块对规划航段做碰撞校验和航向修正最后所有飞机的新状态被记录并可视化。Matlab里用结构体数组保存每架飞机的状态字段包括id、pos、vel、heading、min_radius、speed、sensor_range、task_id、mode。结构体数组比多个零散变量好维护也不会导致索引错乱。3.2 固定翼运动学模型实现固定翼运动学模型我直接用二维Dubins模型因为搜索任务通常可以近似为一定高度层的平面任务。运动学方程很简单x_dot V * cos(psi) y_dot V * sin(psi) psi_dot (V / R) * u其中V是巡航速度R是最小转弯半径u是控制量取值在[-1,1]之间表示最大左转和最大右转。下面是一个最简matlab更新函数function state updateFixedWing(state, u, dt) % 固定翼运动学更新 % state.x, state.y, state.psi, state.V, state.R state.x state.x state.V * cos(state.psi) * dt; state.y state.y state.V * sin(state.psi) * dt; state.psi state.psi (state.V / state.R) * u * dt; end实际用的时候u不是从路径规划器直接来的而是从航向跟踪控制器里面算出来的。我这里用的是纯追踪的变体计算期望航向和当前航向的误差角然后映射到[-1,1]控制量如果误差角很大就让飞机保持最大角速度转向实现最小半径转弯。注意固定翼模型里有速度下限。如果你自适应决策里出现“原地等待”这类动作会让速度变成0这在固定翼上完全不可行。我在实现里把“等待”理解为“绕一个等待圆盘旋”而不是悬停。3.3 自适应决策模块的Matlab示例自适应决策模块的核心是收益函数计算和任务选择。我给每个子区域建了一个收益矩阵每次决策时计算各区域对本机的当前收益再叠加任务分配结果。这里给出一个计算单机收益的简化版函数function benefit calcBenefit(agent, gridMap, assignMap, riskMap) % 计算当前候选区域对本机的收益 % gridMap: 尚未搜索的网格权重 % assignMap: 其他飞机正在搜索的标记 % riskMap: 风险分布 w1 1.2; w2 0.8; w3 0.5; w4 1.5; coverage_gain sum(sum(gridMap(agent.localMask) .* agent.capabilityMask)); discovery_prob mean(gridMap(agent.localMask)); if assignMap(agent.candidatePos) 0 task_priority 0.1; else task_priority 1.0; end collision_risk riskMap(agent.candidatePos); benefit w1 * coverage_gain w2 * discovery_prob ... w3 * task_priority - w4 * collision_risk; end这个函数本身很简单但有一个容易被忽略的点代理的“本地掩码”是各不相同的。异构集群里传感器范围不同计算coverage_gain的窗口也不同所以不能用一个全局网格收益统一替代。我在最开始就踩了这个坑写成统一掩码后大范围传感器飞机永远在抢任务后来改成按飞机能力计算才正常。3.4 避障模块与可飞性检查避障模块做两件事一是检测当前位置与障碍物的距离如果小于安全半径就启动绕行二是对即将飞行的航段做Dubins可飞性校验防止出现“理论上避开了障碍但实际转角不够”的情况。我做了一个简化版本把障碍物展开成带安全半径的圆形禁区从当前位置到候选目标点生成Dubins曲线检查曲线与圆形禁区是否有交点如果有就在禁区的切点位置插入一个临时航路点再分段做Dubins规划直到无碰撞。这个办法在固定翼避障文献里很常见工程实现上比A*加后处理简单而且不存在不可飞航迹。function newPath dubinsAvoid(agent, obstacle, target) % 返回从当前位置到目标且避开单个圆形障碍物的Dubins路径 % 第一步直接生成Dubins路径 path dubinsPath(agent.pos, agent.heading, target, agent.R); if ~collideCircle(path, obstacle, agent.safeR) newPath path; return; end % 第二步计算障碍物切点生成绕行路径 tp tangentPoint(agent.pos, obstacle.center, obstacle.radius agent.safeR); path1 dubinsPath(agent.pos, agent.heading, tp, agent.R); path2 dubinsPath(tp, newHeading, target, agent.R); % 校验组合路径 if ~collideCircle([path1; path2], obstacle, agent.safeR) newPath [path1; path2]; else newPath []; % 表示无法绕行需要上层重新分配目标 end end实际过程中这种几何绕行算法在规整障碍物场景里很可靠但遇到凹形障碍物或者多个障碍物挨得很近的情况容易失效。遇到这种情况我建议把拐点选择做成枚举切点取路径最短的组合而不是只取一个切点。这样复杂场景的成功率会高很多。3.5 可视化与数据记录Matlab可视化我尽量轻量化用plot动态更新飞机位置和搜索覆盖热力图用fill画障碍物和威胁区。这个部分最容易拖慢仿真速度尤其是在集群规模超过10架之后。我的经验是仿真计算与可视化分开跑计算循环里只保存历史状态每隔几个时间步批量更新画面一次而不是每帧都重绘。数据记录我建议统一记录到结构体数组或时间序列矩阵里包括每架飞机的位置、速度、航向、当前模式、任务ID、碰撞标记以及每个时间步的已搜索网格数。这样后面做覆盖率曲线、飞行轨迹图、决策模式时序图都有原始数据可画不用重新跑仿真。4. 复现过程中的关键环节与踩坑实录4.1 场景与障碍物建模的细节第一个坑是障碍物建模太粗糙。一开始我是把禁飞区和建筑物画成多边形但是碰撞校验做起来很麻烦还要处理多边形边线和点的位置关系。后来我放弃多边形精确表示把所有静态障碍物统一转换成圆形禁飞区用圆心坐标加半径表达对于形状比较长的障碍物用多个圆去覆盖。这样处理之后碰撞校验直接计算欧氏距离就行Dubins路径的相交检测也用解析几何能搞定效率高很多。圆形化处理也有代价某些窄通道会被几个圆重叠后彻底堵死本来能飞过去的路径反而没了。这个问题我通过合理设置安全半径大小来解决先跑一版看哪些关键通道被堵住再手动调整对应圆的半径。做仿真场景不是越精确越好要看你关心的问题是算法逻辑还是几何表达。4.2 决策刷新频率与通信延迟模拟在这个项目里所有无人机共享一个全局状态很容易让人忽略通信延迟问题。如果所有决策都是基于最新全局状态算出来的那本质上就是集中式决策和分布式协同没有关系。为了贴近实际我在每架飞机里加了一个“通信消息缓存”收到的邻居状态带时间戳决策时只能使用延迟一定时间后的状态信息。这个延迟我默认设成0.2秒用来模拟多机通信的数据链延迟。决策刷新频率我一开始设得过密结果任务分配在几帧之间剧烈跳动。主要原因是最小二乘的收益差距在相邻帧之间很小随机扰动就会导致选中目标变化。后来我把决策周期拉长到0.8秒并且给当前任务一个“惯性增量”加分机群的行为才稳定下来。这个“稳定压过灵敏”的调参思路在很多协同算法里都适用。4.3 仿真提速与批量跑参技巧固定翼集群仿真最耗时的地方是Dubins路径计算和收益矩阵更新。如果每架飞机每个决策周期都对全图做一次收益评估计算量会随网格数量快速增长。我做的优化是维护一个“已搜索”标记矩阵只对尚未搜索且位于当前飞机传感器范围内的网格计算收益增量而不是全图搜索。另一个提速技巧是用Matlab的预分配和向量化。飞机数量多的时候避免在循环里反复调用sqrt和atan2尽量用向量运算一次计算所有飞机的状态更新。批量跑参数对比时把可视化关掉用parfor并行跑多组不同的随机种子每组只保存统计结果这样一次性就能得到带误差棒的对比曲线。4.4 常见问题与排查方法速查我把自己在复现中遇到最多的几个问题整理成了一张排查表按“现象 - 可能原因 - 解决办法”的格式列出来方便你对照检查现象可能原因解决办法飞机直接穿过障碍物避障模块只做了单步检测没有对未来航迹做校验在路径规划阶段对整段Dubins曲线做碰撞检测任务分配频繁切换飞机在空绕圈决策周期太短或收益权重设置不当增加决策周期和当前任务惯性加分同一区域同时多架飞机搜索任务分配未加去重机制引入区域锁定标志已被占用的区域不参与竞价绕障路径生成了但根本飞不出来没有考虑最小转弯半径所有航点间路径用Dubins模型生成并做可飞校验搜索覆盖率曲线不增长网格标记逻辑错误飞机当前位置映射到网格的索引错位检查坐标与网格索引的换算是否一致模拟速度越来越慢可视化每帧更新、数组未预分配关闭实时绘图用批量重绘预分配历史状态矩阵这张表覆盖了我自己排查时90%以上的问题。如果你复现时遇到同类问题优先对照这个表。4.5 关于代码模块化的心得Matlab做这类项目最怕全是脚本一旦逻辑改起来就要到处找。我实际工作的习惯是每个功能模块单独写一个函数文件主脚本只负责初始化和循环调用。比如决策模块单独放adaptiveDecision.m避障模块放dubinsAvoid.m任务分配放marketTaskAssign.m。这样后面调整某一个算法时不会把主循环打乱。同时我给所有模块统一了输入输出格式用结构体包装状态。这看起来多花了一点点时间但当集群规模从3架扩展到20架、增加通信延迟模拟等多种设置时结构化代码能省下大量调试时间。5. 实验设计与算法效果评估5.1 评价指标体系仿真代码跑通只是第一步真正要证明自适应决策和避障有效需要建立一套可比较的评价指标。我用的指标包括搜索覆盖率、碰撞次数、平均任务完成时间、飞行里程、任务均衡度。搜索覆盖率定义成已搜索网格数除以总网格数碰撞次数记录每次安全半径被突破的事件平均任务完成时间指所有子区域都被覆盖一遍所需时间飞行里程直接反映能量消耗任务均衡度用各机飞行里程的方差或标准差来衡量。指标不能只用一两个否则容易误导。比如搜索覆盖率很高但碰撞很多说明算法冒险不具备实际部署价值覆盖率不高但飞行里程很低说明搜索效率低。我在复现时都是把一组指标统一输出成表格而不是单独看某一个值。5.2 典型场景下的结果对比我用随机生成的30个障碍物和3个目标点做了几组对比实验。第一组是纯搜索、无避障飞机按预划分区域飞行第二组加入避障模块但没有任务分配的自适应第三组是完整方案自适应决策、避障、市场竞价分配都打开。结果显示完整方案在覆盖率相同的情况下碰撞次数从平均6次降到0飞行里程比第二组少约18%任务均衡度也更好。这个对比很直接地说明了一个关键点自适应决策不是“让覆盖率更高”而是“让达到同等覆盖率的代价更小”。如果只是追求覆盖率简单穷举式搜索也能做到但飞行代价和碰撞风险都会很高。完备的自适应决策系统的价值在于用合理的计算开销把搜索效率和安全性同时拉高。5.3 参数敏感性分析与经验值复现过程中我尝试着调整了几个核心参数这里分享一些经验值。收益函数权重方面coverage_gain权重在1.0到1.5之间比较稳妥太大容易让飞机扎进未搜索区域而忽视风险collision_risk权重如果小于1.0避障的优先级不够飞机容易擦着障碍物边缘飞行建议至少给到1.2。决策周期0.5秒到1秒之间是最稳的区间太短抖动太长响应迟缓。集群规模方面我试过3、5、8、12架四种配置。规模增加后覆盖率上升但通信量和任务竞价的冲突也随之增加。异构程度方面把最小转弯半径拉大20%之后飞机明显更“笨”任务分配如果不用异构感知的报价计算很容易出现某架飞机被分配到根本飞不到的区域。这一块的经验是异构集群的性能上限不是由最快飞机决定而是由最受限飞机的能力约束决定决策算法必须显式识别这个瓶颈。6. 当前方案的局限与后续扩展方向现有实现的局限主要在两块。一块是环境表达比较保守圆形障碍物覆盖法在处理复杂多边形凹形区域时会丢失一些可行的窄通道另一块是决策模型仍然偏启发式虽然比纯规则方法灵活但在极端动态环境下缺乏理论最优性保证。如果后续要做改进我建议从两个方向入手一是把当前收益函数替换成带约束的模型预测控制让决策序列在时间窗口上整体最优二是引入学习类算法用强化学习替代手动的收益函数权重标定让集群在重复仿真中自己“学会”更稳妥的避障策略。另外固定翼集群在三维空间的协同搜索目前只做了二维简化真实任务中高度变化、地形遮蔽、风力扰动都会影响传感器探测概率。如果想把工程实用性做上去三维Dubins路径和空间地形建模是绕不开的扩展点。这些扩展都可以在现有Matlab框架上逐步加模块不用推翻重来。回到我自己的复现体验这个项目最核心的收获不是跑通了几张图而是理解了“集群智能并不等于每架飞机都聪明”。真正让集群稳定工作的是合理的分层结构、保守的决策机制、以及对飞行平台物理约束的敬畏。固定翼不允许你犹豫不决不允许你原地等待所有决策都必须在一个速度前提下提前量足够地给出答案这种约束倒逼出来的算法设计思路做一遍体会会非常深。最后分享一个实操小建议复现过程中遇到参数怎么调都不对的时候别急着改权重先把可视化里的轨迹、障碍物、搜索热力图同时打开逐帧看飞机在关键时刻到底做什么决策。绝大多数问题一眼就能看出来比盲调参数快得多。
返回列表