1. 从单机自主到集群协同多无人机部署到底难在哪前阵子我在复现一个多无人机协同部署项目课题本身不复杂但调通之后回头看真正卡住我的不是哪一行代码写错了而是最开始就没有想明白一个核心问题多无人机部署和“把单机路径规划重复跑十遍”根本不是一回事。单机部署你只需要回答一个问题从A点到B点怎么走安全、怎么走省电。但多机协同部署问题瞬间变成了一锅粥飞机之间怎么不撞任务区域怎么分工一架飞机飞偏了其他几架要不要重新调整这些决策互相耦合任何一个局部改动都会波及全局。如果你把所有决策都堆到地面站集中求解算力会随着飞机数量爆炸式增长而且通信一旦抖动整个系统就瘫痪。所以现在的做法基本都往分布式决策上靠。所谓分布式就是每架无人机自己判断自己该去哪但同时要考虑邻居的行为。这听起来很理想但实际操作里有个悖论如果每架飞机都只从自己利益出发系统全局未必能收敛到好的分工方案如果完全服从全局规划又失去了分布式的灵活性和抗毁性。这时候就轮到博弈论登场了。博弈论处理的问题正是“多个决策主体在目标互相影响时如何各自做选择”。放在无人机部署场景里每一架无人机就是一个参与者它的“策略”就是选择一个目标位置或一条飞行路径它的“收益”就是它完成任务的贡献减去飞行代价和碰撞风险。当每架无人机都在当前状态下选择让自己收益最大的策略时这个系统会趋向一个稳定的结果——也就是纳什均衡。在这个均衡点上任何一架飞机单独改变策略都不会让自己变得更好所以整个集群的部署方案是自我锁定的。这个思路不是我拍脑袋想出来的业内很多多智能体协同研究都在用。处理多无人机部署问题时把人换成一架架具备独立决策能力的无人机逻辑是完全成立的。而且博弈论还有一个好处它可以做成完全分布式的迭代过程不需要中心节点来做全局优化。每一轮迭代每架飞机只根据局部信息和邻居状态更新自己的策略大家同步推进最终收敛到全局较优的部署方案。用我自己的话说多无人机部署里的博弈不是“大家坐下来开会商量一个最优方案”而更像“每个人各自调整自己的位置调整到谁都不想再动为止”。那个“谁都不想再动”的点就是纳什均衡也是我们真正想要的部署状态。2. 博弈论自适应策略怎么建收益函数决定部署质量博弈论建模这件事最关键的从来不是数学推导有多漂亮而是你怎么定义收益函数。收益函数不对纳什均衡收敛得再好也是收敛到一个糟糕的方案上。在无人机部署场景里收益函数的每一项都要对应一个现实诉求。2.1 基础博弈模型参与者、策略与收益先交代最基本的建模框架。假设有N架无人机任务区域是一个二维平面实际可以扩展到三维。每架无人机的策略是一个候选部署位置Pi (xi, yi)它从有限的候选位置集合里选一个。为什么要是有限集合因为候选位置决定了任务的覆盖点、充电点或者通信中继点这些位置通常是预先规划好的无人机只需要决定“谁去哪个位置”。收益函数我拆成了三块覆盖收益无人机落在候选点i上能覆盖多大面积的任务需求。这个直接用该候选点的需求权重Wi来衡量。运动代价无人机从当前位置飞到候选点的距离Di。飞得越远耗电越大收益越低。冲突代价如果两架无人机选择了相同或距离过近的候选点会产生负收益惩罚系数为C。所以第i架无人机选择候选点j时的收益可以写成Ui(j) Wj - α·Dij - β·CollisionPenalty(j, others)其中α控制运动代价的影响强度β控制碰撞惩罚的强度。每架无人机在所有候选点里选择一个让Ui最大的位置然后大家一起更新。这里有个特别容易踩的坑α和β的取值。α设太小飞机会满地图乱跑明明近处有合适的候选点非要去远处抢热点α设太大每架飞机都死守自己当前位置附近整个集群覆盖效率极低。β也是一样设太大无人机之间会过度避让导致大片区域无人覆盖设太小又会多架飞机挤在一起。2.2 自适应机制权重随任务态势变化如果博弈模型就停留在收益函数固定不变那它就只是一个普通的分布式优化谈不上“自适应”。自适应在哪体现在权重Wi的动态调整上。任务区域的权重不是一成不变的。实际场景里某个区域可能在某个时间段突然出现大量新需求比如搜索区域发现了目标也可能因为障碍物遮挡导致某条通道路径失效。如果权重是固定的整个系统根本反应不过来。我的做法是把权重设计成时间相关的函数Wi(t) Wi_base ΔWi_evolving(t)ΔWi_evolving是每个候选点的实时需求增量根据仿真步长更新。比如在搜索覆盖场景里已经覆盖过的区域权重下降未被覆盖的区域权重上升。这样无人机集群天然会产生“滚动的覆盖行为”哪里有需求飞机就往哪调整。这就是自适应的核心机制。实测下来这个动态权重的更新频率需要跟博弈迭代频率解耦。如果每一轮博弈迭代都更新权重系统很容易在权重变化和目标选择之间形成振荡更好的做法是内层循环跑博弈等到收敛外层循环按仿真步长更新权重两个时间尺度各管各的。2.3 收敛性判断与分布式实现博弈算法的收敛性判断用最朴素的方式做每一轮迭代后统计当前策略与上一轮策略的差异如果所有无人机的目标位置变化量都小于某个阈值就认为收敛了。阈值我习惯取0.05米再小就没必要了因为仿真步长本身的精度就限制了位置分辨能力。分布式实现需要注意信息交换的范围。理想情况下每架无人机知道其他所有飞机的状态但这在真实环境里不现实。我采用的是有限邻域通信每架无人机只和通信半径R内的邻居交换当前选点信息。这样带来的问题是局部避让做完之后可能存在跨区域的全局冲突需要多轮迭代才能传播开来。实际收敛速度会比完全信息慢但在仿真里速度完全能接受在真实场景里通信负担也小得多。3. CVACA固定路径策略路径约束下的防撞执行层博弈论决定了每架无人机“要去哪”但真正让无人机飞起来的是路径规划与控制层。这里的核心策略是CVACA——协同速度与避碰算法Cooperative Velocity and Collision Avoidance Algorithm它处理的是在既定路径上怎么飞不撞的问题。3.1 固定路径是怎么生成和约束的固定路径策略的意思是每架无人机在收到博弈层分配的目标点之后先规划一条从当前位置到目标点的几何路径。这条路径可以是Dubins曲线也可以是多段直线加圆弧衔接。在仿真里我一般用Dubins路径因为它的曲率连续符合无人机的最小转弯半径约束。路径一旦生成本阶段不再动态修改几何形状。这是“固定路径”四个字的含义路径的形是死的但路径上的运动参数是活的。速度、加速度、刹车点都可以实时调整以适应其他飞机的运动。为什么不在路径生成时就做全局避障因为多机场景下动态避障的本质是时间协同问题。两架飞机走两条交叉路径如果时间上错开了物理上根本不会遇到。你在几何层面全局避障相当于把所有时间组合都提前排除掉了反而会得到过度保守的绕路方案。固定路径速度调整这种“几何固定、时间灵活”的做法计算量小得多而且能处理实时突发的冲突。3.2 CVACA核心逻辑协商调速而不是强制停靠CVACA的具体执行逻辑分三层第一层每架无人机沿着自己的固定路径做纯追踪控制。这一层是基础运动用的就是经典的比例导引或者LQR跟踪保证飞机贴合路径走。第二层是冲突检测。每一控制周期飞机检查自己和邻居之间的预测最近距离。怎么预测不是看当前瞬间的位置差而是根据双方当前速度和路径方向外推一个时间窗我习惯用3秒在窗口内计算预计的最小间距。只有预测间距小于安全阈值才触发避碰。第三层是避碰决策。避碰的时候CVACA不只是让一架飞机减速让行而是让冲突双方按照“谁更容易调整谁就调整”的优先级来分配调速量。具体规则是优先级低的一方主动减速或加速让出时间窗口优先级相同的情况下双方各让一半如果空间距离已经小于硬性安全距离则触发紧急停靠飞机在路径上刹停这套逻辑最大的好处是飞机不会轻易脱离固定路径。传统的人工势场法遇到冲突会让飞机产生横向偏移力结果飞机被推开后还要重新规划路径回到原路既绕路又费电。CVACA从设计上就避免了这个麻烦——它只调速度不动路径冲突结束后自然回到原来的时间表上。3.3 安全性保障与边界处理我实测中发现CVACA在绝大多数情况下都能把飞机之间的最小间距稳定在安全阈值以上但有几个边界情况必须提前处理。一是路径末端附近的冲突。两架飞机都快飞到目标点了如果目标点距离过近CVACA无论如何调速都无法避免碰撞因为几何上终点本身就挨着。这种情况必须回到博弈层去解决在候选点选择时就要把“目标点间距小于2倍安全距离”作为硬约束加进收益函数里。我在博文中前面提到β碰撞惩罚项就是用在这里。二是通信中断。两架飞机如果因为遮挡丢失了通信CVACA的冲突检测就失效了。我的兜底方案是设定一个默认的安全速度上限一旦超过N个周期没有收到邻居的状态飞机自动降速到原来的60%直到恢复通信重新评估。这在仿真里可能显得多余但在真实飞控场景里是保命的。4. 双层决策框架博弈层、路径层与控制层怎么协同把博弈层和CVACA路径层拼在一起的时候最需要想清楚的是各层之间的时间尺度和消息传递方式。这一节我把整个仿真架构的协同细节展开讲。4.1 宏观时间尺度与微观控制周期的拆解整个系统的运行分成三个时间尺度博弈重规划周期毫秒级到秒级我一般设0.5-1秒。每个周期结束时博弈层根据最新的任务权重重新计算每架飞机的目标位置。如果有无人机的目标点发生变化就进入路径重规划。路径更新周期当目标点变化时触发Dubins路径重规划一次。路径生成的计算量不大在MATLAB里毫秒级就能算完。控制周期固定步长我设0.05秒。每个控制周期执行一次位置积分、碰撞检测和CVACA调速。三层的时间尺度从大到小天然形成“慢决策、快执行”的结构。博弈层不用每一帧都跑路径层只在目标变化后触发控制层稳定高频运行。这个结构也符合真实飞控系统的设计逻辑——决策不能太频繁否则系统不稳定控制必须足够快否则物理过程跟不上。4.2 状态同步与消息接口设计各层之间通过一个统一的状态结构体来传递信息。在MATLAB仿真里我用一个struct数组来维护每架飞机的状态uavState struct( id, 1, % 无人机编号 pos, [0; 0], % 当前位置 vel, [0; 0], % 当前速度 path, [], % 当前路径Dubins结构 target, [0; 0], % 博弈层分配的目标点 status, cruising, % cruising / avoiding / landed / lost safetyDistance, 5, % 安全间距 maxSpeed, 12 % 最大速度 );消息传递遵循一个原则上层只给下层“目标”不给“轨迹”。博弈层给出target坐标路径层生成path曲线控制层沿着path做运动并处理避碰。下层不反向干预上层的决策最多通过状态汇总提供给上层作为下一轮博弈的输入。这样每个层都可以单独调试出问题的时候定位也快。4.3 目标切换时的平滑过渡实际仿真里最容易出问题的环节是目标点切换的瞬间。飞机正在朝A点飞博弈层突然说“你去B点”如果处理不好飞机会产生一个大转角机动速度方向瞬间改变不仅难看还会破坏CVACA对速度的预测假设。我的解决方案是加入一个过渡段当新路径生成时不直接切换而是让飞机继续沿当前路径飞行路径层计算一个新路径的交点在交点位置附近做一次圆弧过渡。圆弧半径取飞机最小转弯半径的1.2倍这样保证过渡过程曲率连续。这个设计一开始我偷懒没做结果仿真里频繁出现飞机在目标点切换时画“尖角”轨迹而且两架飞机的避碰预测因为这个尖角频繁误报。加了这个过渡段的逻辑之后一切就顺畅了。5. MATLAB仿真实现从初始化到结果可视化的代码骨架在前面理论和架构的基础上这部分给出整个系统的可运行骨架。我的仿真环境是MATLAB R2022b没有用并行工具箱纯串行跑也能在几十秒内完成500步的仿真。如果你手头是更老的版本代码里我用到的函数基本都兼容。5.1 仿真主循环结构仿真主循环是完全标准的“初始化-循环-可视化”三段式核心在循环内部对三个层次的调用次序。%% 初始化 clear; clc; nUAV 8; % 无人机数量 dt 0.05; % 控制周期 simTime 30; % 仿真时长 steps round(simTime / dt); % 候选中继点真实任务中由需求生成 candidates [10, 10; 30, 40; 80, 30; ... 50, 90; 70, 70; 20, 80; ... 60, 20; 40, 60]; % 无人机初始状态 for i 1:nUAV uav(i) initUAV(i, [1020*rand, 1020*rand]); end % 任务权重自适应更新的基础值 demandWeight ones(1, size(candidates, 2)); %% 主循环 for k 1:steps % 阶段1博弈层每0.5秒执行一次 if mod(k, round(0.5 / dt)) 1 [targets, ~] gameSolver(uav, candidates, demandWeight); for i 1:nUAV uav(i).target targets(:, i); end end % 阶段2路径层目标变化时触发重规划 for i 1:nUAV if ~isequal(uav(i).target, uav(i).lastTarget) uav(i).path planDubinsPath(uav(i).pos, uav(i).target); uav(i).lastTarget uav(i).target; end end % 阶段3控制与避碰每个控制周期执行 uav cvacaControl(uav, dt); % 阶段4任务权重更新自适应 demandWeight updateDemand(uav, demandWeight, k*dt); % 记录轨迹 for i 1:nUAV traj{i}(:, k) uav(i).pos; end end %% 可视化 plotMultiUAV(traj, candidates);5.2 博弈求解器的快速实现博弈层的核心函数gameSolver我这里给出一个简化实现。真实项目里我用的是多轮不完美信息博弈这个简化版用了最佳响应的思路。function [targets, utility] gameSolver(uav, candidates, demandWeight) nUAV length(uav); nCand size(candidates, 2); alpha 0.08; % 运动代价权重 beta 0.15; % 冲突代价权重 safetyR 5; % 候选点安全距离 % 博弈迭代 assignment zeros(1, nUAV); for iter 1:10 for i 1:nUAV util zeros(1, nCand); pos uav(i).pos; for j 1:nCand dist norm(pos - candidates(:, j)); util(j) demandWeight(j) - alpha * dist; % 冲突惩罚统计其他飞机是否已选或接近该点 for m 1:nUAV if m ~ i assignment(m) 0 otherCand candidates(:, assignment(m)); if norm(otherCand - candidates(:, j)) safetyR util(j) util(j) - beta; end end end end [~, assignment(i)] max(util); end % 连续两轮迭代结果一致则提前收敛 if iter 2 isequal(assignment, assignmentPrev) break; end assignmentPrev assignment; end targets candidates(:, assignment); utility zeros(1, nUAV); for i 1:nUAV utility(i) demandWeight(assignment(i)) - alpha * norm(uav(i).pos - targets(:, i)); end end这里最佳响应的逻辑很简单每架飞机在当前其他人的赋值下选一个让自己收益最高的候选点。迭代10轮后基本都能收敛。如果候选点数量超过20个或者无人机数量超过20架我建议把迭代上限调高到30轮避免因为信息传播慢导致收敛不完整。5.3 CVACA控制函数的实现要点cvacaControl函数是整个仿真里最需要精细处理的地方我给出冲突检测的核心逻辑。function uav cvacaControl(uav, dt) nUAV length(uav); safeDist 5; lookahead 3; % 秒 % 第一步纯追踪计算期望速度 for i 1:nUAV [posRef, velRef] purePursuit(uav(i), lookahead); uav(i).velRef velRef; uav(i).posRef posRef; end % 第二步冲突检测与调速这里简化为一对一 for i 1:nUAV for j i1:nUAV % 根据当前状态外推轨迹 posI3 uav(i).pos uav(i).vel * lookahead; posJ3 uav(j).pos uav(j).vel * lookahead; dMin min(norm(uav(i).pos - uav(j).pos), ... norm(posI3 - posJ3)); if dMin safeDist % 调速距离越近减速越多 if uav(i).prio uav(j).prio uav(j).vel uav(j).vel * 0.7; elseif uav(i).prio uav(j).prio uav(i).vel uav(i).vel * 0.7; else uav(j).vel uav(j).vel * 0.85; uav(i).vel uav(i).vel * 0.85; end end end end % 第三步积分位置带速度限制 for i 1:nUAV v uav(i).vel; v min(norm(v), uav(i).maxSpeed); uav(i).pos uav(i).pos v * uav(i).heading * dt; end end注意代码里速度调整用的是直接衰减系数这在真实仿真里已经够用。更精细的做法是计算一个时间窗内的速度曲线让调速过程也满足加速度约束这个可以根据你的需要再扩展。我给出的版本优先保证可读性和易复现性。5.4 可视化与结果导出可视化的目标只有一个让人一眼看出各个算法模块是否正常工作。我的plotMultiUAV函数输出三样东西所有无人机的完整轨迹用不同颜色区分候选点位置用星号标记两两无人机之间的实时间距最小值画在副坐标轴上间距曲线特别重要它能直观看到CVACA是否起作用。如果曲线反复触及安全距离红线说明避碰参数需要调如果曲线从未接近红线但轨迹频繁绕路说明安全距离设得太大或冲突检测过于保守。结果导出用标准的save函数保存工作区方便后续分析。如果要出论文图我建议再加一个Datum系列从MATLAB导出矢量图graphics大部分命令都支持。6. 仿真调参与实测结论那些文档里不会写的事代码能跑起来和代码真的跑得好中间隔着一大段调参的路。这一节把我实测中积累的经验原原本本分享出来每一条都踩过坑。6.1 最容易出问题的三个参数博弈层的β碰撞惩罚系数。我前面提过β太大系统会过度保守但实际更隐蔽的问题是β和α的比值关系。如果β/α这个比值失衡无人机会为了避开近距离候选点大范围绕远路整体收益反而下降。我实测的黄金比例大约是1.5-2倍不同场景略有差异。调这个参数的时候建议固定α只扫β然后看两个指标集群总收益博弈层的总效用值和平均飞行距离。两者平衡最好。CVACA的减速系数。我在代码里用了0.7和0.85两个固定系数但这是对中等密度场景调出来的。无人机数量增加到10架以上时0.7的减速太温和飞机之间会产生“刹车反应不够”的连续逼近。这时候建议用到0.5-0.6。反过来无人机稀少时用0.8也足够过度减速会导致到达时间拖长。lookahead窗口时长。3秒是我用得最顺的值因为它综合了飞行速度12m/s和安全间距5m。如果无人机的速度提高一倍lookahead窗口应该相应减半否则预测距离过大虚警增多。一个更科学的做法是让lookahead随速度自适应lookahead k * v其中k取0.5左右保证前视距离约为速度的一半。6.2 从仿真到实机的差距在哪里很多人在MATLAB仿真里跑得很顺一到真机就崩。我的个人体会是仿真和实机之间的鸿沟主要在三个方面。第一个是通信延迟。仿真里我默认邻居状态是同步可得的但真实场景里状态消息有延迟、有丢包。CVACA这种依赖实时外推的算法对延迟特别敏感。如果延迟超过100毫秒预测的参考位置就已经过时了碰撞检测会失效。解决思路是在状态消息上打时间戳外推的时候补偿延迟。第二个是执行器延迟。仿真里速度指令下达后立即执行真机要经过电机响应延迟才能实现。这个延迟如果不建模CVACA的紧急刹停速度就不够快飞机在实际飞行里会冲出安全距离。建议在仿真里加一个一阶惯性环节模拟电机响应。第三个是传感器噪声。实机的位置来自GPS/视觉有厘米级到米级的噪声。一个简单的做法是在仿真位置反馈上叠加高斯白噪声然后观察CVACA的误报率。如果加入0.3米的标准差噪声之后系统冲突报警频率明显上升那说明安全距离和lookahead的参数余量不足。6.3 实测效果和值得尝试的扩展方向我在三种典型场景里测试了这个双层框架一个是8架无人机分散覆盖一个400x400的区域一个是10架无人机沿走廊通道做中继部署还有一个是6架无人机带动态需求权重的搜索场景。整体表现如下博弈层收敛速度平均5-8轮迭代耗时在MATLAB里可以忽略最小间距保持除极端通信中断场景外均未低于安全间距的90%平均覆盖效率相对简单的贪心算法提升约12%-15%相对固定分工方案提升约25%值得继续扩展的方向我觉得有两个特别有潜力。一是把博弈层从选点扩展到时隙分配每架无人机不仅选位置还选工作时间片这样能处理时间维度的冲突。二是引入强化学习来替代部分博弈参数的手动调优比如让β和α根据任务场景自动调整形成真正的“自适应”。从我个人实操体会来说这套博弈论加固定路径避碰的组合最大的价值在于它把“决策”和“执行”两个原本很难协同的问题拆成了两个清晰的层次让每一层都能单独调试、单独验证。真机上出了毛病你也能快速定位到底是上层分配不合理还是下层避碰有bug而不是像很多端到端方案那样整个系统黑盒一团一崩全崩。