资讯动态

空地协同路径规划实践:从任务分配到时间同步

发布时间:2026/10/20 8:21:08 来源:尧图企业网站定制
1. 项目整体拆解空地协同不是“会飞”加“会跑”拿到“空地多无人平台协同路径规划”这个课题很多人的第一反应是无人机管天上、无人车管地上各跑各的最后把路径拼在一起不就行了真这么想就错了。我当初复现完这篇论文的最大感触是——空地协同难的不是单平台路径规划而是怎么让两种动力学特性完全不同的平台在同一个任务里做到时间上对齐、空间上解耦、冲突上可控。先说这个项目解决的核心问题。在典型的多区域侦察、物资转运或搜救场景里空中平台速度快、视角广、不受地面障碍限制但续航短、载荷小地面平台载重大、续航长但速度慢、受地形约束严重。把这两类平台放在同一个任务里天然存在三个矛盾速度差异无人机巡航速度可能是无人车的3到5倍同样的任务区域无人机几分钟能到的地方无人车要跑几十分钟约束差异无人车必须严格跟随路网或可通行地形无人机除了禁飞区和高层障碍几乎到处能走任务耦合很多任务必须是空地平台在同一时刻到达同一区域才能完成比如无人机先抵近侦察无人车再进场作业——先后关系一旦颠倒任务就失败论文的核心贡献是把这个问题形式化成了一个“先分配、后规划”的两层优化结构。上层用任务分配算法决定哪架无人机、哪辆无人车去执行哪个目标点下层用路径规划算法在满足各自运动学约束的前提下算出从当前位置到目标点的可行路径。两层之间通过时间协同变量耦合——这个“时间协同”四个字是整个项目的灵魂也是我在复现过程中花时间最多的地方。为什么这种分层结构是合理的选择因为路径规划和任务分配耦合在一起本质上是一个混合整数优化问题直接求解在计算上是不可行的。比如5个平台对8个目标点任务分配组合数量就已经是天文数字还要叠加路径规划的空间约束全局求解器的计算时间会让人怀疑人生。拆成两层上层只负责“谁去”下层只负责“怎么走”中间通过代价矩阵和时间窗做迭代虽然未必是全局最优但工程上收敛快、可解释性强、调试起来不会“一崩全崩”。我在复现时直接用Matlab而不是Python有一个很实际的原因Matlab的绘图和可视化调试能力在这个场景下太顺手了。路径规划算法调试的本质是反复看“路径为什么弯了”“为什么穿墙了”“为什么两辆车在同一个栅格里打架”Python用matplotlib也能做但交互性和实时更新的流畅度确实差了一截。加上Matlab的Global Optimization Toolbox里面现成的ga、particleswarm可以直接用来做任务分配层的求解能省掉不少造轮子的时间。再提醒一下这个课题的代码实现有两条截然不同的路线一种是完全按照论文的伪代码逐步实现把每个公式都落地另一种是调用现成的路径规划工具箱混搭比如用自动驾驶工具箱里的规划模块再套一层自己的协同逻辑。我这次选择的是前者因为论文复现的第一目标是“理解”而不是“跑通”——用现成工具箱搭出来可能一天就能出结果但论文里那些关键公式你依然看不懂出了问题也不知道去哪里排查。做科研复现慢就是快这个学费值得交。2. 核心算法解析任务分配和路径规划两条腿缺一不可2.1 任务分配层不是简单的目标点“抢单”任务分配层要回答的问题很朴素这么多目标点哪一个平台去哪个最划算但如果真把这个问题展开里面全是细节。论文里的任务分配建模方式我建议按“收益最大化”的思路去理解而不是“路程最短”。很多复现者的直觉是把所有平台到所有目标的距离算出来然后做一个指派问题求解让总距离最小。这在单平台场景成立但在多平台协同场景里会翻车——因为不同平台的代价度量根本不统一。无人机飞1公里和无人车开1公里消耗的资源不同任务收益也不同简单加总没有意义。我复现时采用的建模方式是目标函数任务覆盖率时间惩罚项约束包括平台性能约束、目标点访问次数约束、时间窗约束时间惩罚项用于惩罚“到达过早”和“到达过晚”——协同任务里到太早和到太晚一样糟糕甚至更糟因为早到的平台可能暴露位置这里有一个看起来不起眼但影响很大的细节距离矩阵的计算要不要考虑地形差异我一开始用的是欧氏距离结果任务分配结果经常“看起来很美跑起来就废”——分配器觉得某辆车去某个目标点最近但实际路径上有一片沼泽或建筑群真实路径长度是分配器预估的两倍时间协同直接崩掉。后来我改成用下一层路径规划器的首轮输出作为代价矩阵的输入做一个循环迭代效果立刻好了很多。这个“分配-规划-再分配”的交替优化结构我觉得是论文里没有明说、但实际效果最关键的工程决策之一。对于求解算法论文给的框架是遗传算法。Matlab的ga函数我用了但说实话直接套用的效果不好——标准遗传算法在平台数量多、约束复杂的时候收敛很慢而且容易陷入局部最优。我的做法是做了两点改进编码方式改成双层编码上层是目标点序列下层是平台分配掩码交叉和变异操作分别处理两层避免产生大量非法子代引入精英保留策略每代保留前几个最优个体直接进入下一代防止优秀解被变异掉这个改进不需要动ga的底层逻辑只用ga的MutationFcn和CrossoverFcn回调函数接口就行。2.2 路径规划层A*框架下的三种形态路径规划层是论文最核心的算法部分也是我复现时调试时间最长的地方。论文在这一层用了A*框架并根据平台类型分化出了三种形态无人机路径规划固定翼无人机有最小转弯半径约束A的直接栅格移动方式不适用。论文的做法是在A的节点扩展阶段加入运动学约束——每次扩展的不是四周邻居栅格而是根据当前航向角和最小转弯半径生成一组可行的航向扇区节点。这种思路本质上是把A*从几何空间搜索变成了状态空间搜索。我复现时用了一个比较取巧的等价实现先在几何空间用标准A搜出一条折线路径再做路径平滑的后处理用Dubins曲线把折线转角替换成满足最小转弯半径的圆弧过渡。结果在算法层面可能和论文的“带约束A”不完全等价但在最终路径形态和代价上基本一致。而且这样写的代码要简单很多——标准A加一个平滑后处理模块比在A内部做状态空间扩展要容易调试得多。无人车路径规划无人车用标准A*栅格搜索即可但有一个非常关键的细节代价函数的权重要和车的实际通过能力匹配。复现时我用的是G代价累计路径长度H代价当前节点到目标的欧氏距离附加代价经过不同类型地形时的惩罚系数地形惩罚系数这个设计来源于户外场景的实际需求。同一片区域的路径草地、土路、沥青路对无人车的通行成本完全不一样如果不加这个惩罚A*出来的路径经常会让你气笑——沿着河堤走最短的线路实际上那是一条车根本开不上去的人行栈道。空地协同的速度协调这就是论文标题里“协同”二字的实际落点。无人机路径短、速度快如果按照各自的默认速度跑无人机早早就到目标点悬停等待不仅费电还暴露轨迹。论文用速度协调层来对齐到达时间先算出所有平台路径的实际长度再根据最长耗时路径反推统一的任务完成时间最后给每个平台算出一个参考巡航速度。这个逻辑看起来简单实际执行时会遇到一个非常容易被忽略的问题速度调整幅度不能太大。无人机把速度降到原本的60%以下或者无人车把速度提到120%以上都会偏离各自的经济巡航区间实际耗能反而上升。我复现时给速度协调层加了一个安全域判断如果平台的最优速度偏离度超过阈值就通知任务分配层重新做时间窗调整而不是硬性推一个物理上不合理的速度。注意速度协调层不是简单的代数计算它必须在路径生成之后运行并且要把输出反馈回任务分配层做第二轮验证。很多初写者只做单向流程分配-规划-出图等真实验发现协同时间对不上又开始怀疑是算法问题。实际上缺的就是这个反馈回路。2.3 三种算法的适用边界对比模块算法优点局限适用场景任务分配双层遗传算法全局搜索能力强约束扩展容易收敛慢参数敏感单次静态任务规模5-15个目标无人机路径标准A*Dubins平滑实现简单路径形态满足运动学约束非最优转弯段较多空旷区域障碍密度适中的城区无人车路径加权栅格A*易于融合地形代价实现直观栅格分辨率影响大地面道路网清晰、地形差异明显的场景协同层速度同步迭代逻辑清晰容易验证只在单任务周期内有效一次性协同任务不适用于实时重规划3. 工程实现从论文公式到可运行代码的完整链路3.1 框架结构设计怎么分模块最容易调试这一节说说代码层面的工程实现。我的实践是把整个项目拆成五个独立模块模块之间通过接口交互用主脚本串联Config模块集中管理地图参数、平台参数、算法参数的配置文件Map模块地图加载、栅格化、障碍标记、可通行区域提取TaskAssign模块任务分配层的遗传算法实现PathPlan模块A*路径规划及路径平滑实现TimeSync模块速度协调和时间对齐计算这样的分层有几个实际好处。第一模块间拆开后每个模块可以单独调试和验证。PathPlan模块可以脱离任务分配单独测试路径效果TaskAssign模块可以用预设代价矩阵验证分配逻辑定位问题不需要每次都跑全流程。第二后续做算法改进时可以只替换单个模块比如把A换成RRT改PathPlan模块就够了其他模块不动。配置管理模块的信号我建议都用统一的struct来组织不要在各模块里散写参数。实际复现时我吃过这个亏改了参数以后算法行为变了但找半天不知道哪里的参数改了回滚都没有方向。把所有参数全部集中到Config模块之后这个问题的排查效率一下提升了好几倍。3.2 代价地图构建所有上层算法的地基代价地图是整个系统的地基这个模块的准确性直接决定上层算法会不会做出蠢事。我构造地图的步骤如下第一步读取二值地图图源作为原始数据白色可通行黑色障碍第二步对地图做膨胀处理。膨胀半径根据无人机和无人车的物理尺寸分别设置——无人机膨胀5格对应物理空间的飞行安全距离无人车膨胀8格车身宽两侧安全余量第三步根据图源中的灰度值或者区域标签设置通行代价系数形成代价值地图第四步在代价值地图上叠加禁飞区、禁行区等逻辑约束区域膨胀处理是必须做的不然A*规划的路径会贴着障碍物边缘走实际物理平台上根本执行不了。但膨胀半径不是越大越好——膨胀过大窄通道会被封死原本可以通行的路径直接变成断头路膨胀过小路径安全距离不足。调试经验是先用小膨胀半径跑一遍路径观察实际平台上最窄的通过距离再逐步加大直到路径形态稳定。这一层我强烈建议把可视化做顺——把膨胀前后的地图对比、代价热力图、最终路径叠加这三层图画出来放在一个figure窗口里。做路径规划的调试快速看清地图和路径的关系比什么都重要Matlab的交互式缩放在这种场景下真的比Python好用太多。3.3 A*路径规划模块的核心实现这里给出A*模块的关键代码结构代码按“可运行骨架”的标准来写方便直接复现function path AstarPlan(map, start, goal, options) % map: 代价地图矩阵 % start, goal: [x, y] 下标坐标 % options: 结构体包含启发函数权重、搜索邻域类型等 % 初始化 nRows size(map, 1); nCols size(map, 2); gScore inf(nRows, nCols); gScore(start(1), start(2)) 0; fScore inf(nRows, nCols); fScore(start(1), start(2)) hFunc(start, goal, options); cameFrom cell(nRows, nCols); directions [1,0; -1,0; 0,1; 0,-1; 1,1; 1,-1; -1,1; -1,-1]; % 使用优先队列priority queue可以用最小堆实现 openQueue InfPriorityQueue(); push(openQueue, [start, fScore(start(1), start(2))]); visitedSet zeros(nRows, nCols); while ~isEmpty(openQueue) current pop(openQueue); if isequal(current(1:2), goal) path reconstructPath(cameFrom, start, goal); return; end visitedSet(current(1), current(2)) 1; for i 1:size(directions, 1) neighbor current(1:2) directions(i, :); % 越界检查 障碍检查默认map中0为可通行 if neighbor(1) 1 || neighbor(1) nRows || ... neighbor(2) 1 || neighbor(2) nCols continue; end if map(neighbor(1), neighbor(2)) 1 continue; end if visitedSet(neighbor(1), neighbor(2)) 1 continue; end % 计算g代价考虑方向不同的路劲长度差异 if abs(directions(i,1)) abs(directions(i,2)) 2 stepCost sqrt(2) * map(neighbor(1), neighbor(2)); else stepCost 1 * map(neighbor(1), neighbor(2)); end tentativeG gScore(current(1), current(2)) stepCost; if tentativeG gScore(neighbor(1), neighbor(2)) cameFrom{neighbor(1), neighbor(2)} current(1:2); gScore(neighbor(1), neighbor(2)) tentativeG; fScore(neighbor(1), neighbor(2)) tentativeG hFunc(neighbor, goal, options); push(openQueue, [neighbor, fScore(neighbor(1), neighbor(2))]); end end end path []; % 无路径返回空 end这段代码有几个值得注意的细节对角线移动的代价是√2而不是1这个看起来是常识但很多初写的代码里会忘记导致路径倾向走斜线形态不对优先队列的效率至关重要。我前几个版本用的是普通数组加排序A*在500×500的地图上跑一次要600ms换成堆实现以后降到80ms左右。在Matlab里用java.util.PriorityQueue或自写最小堆都可以千万别用排序数组硬扛hFunc的选择直接影响搜索效率。无人机场景用欧氏距离因为可以任意方向飞行无人车场景用切比雪夫距离更贴近栅格实际移动代价3.4 路径平滑与速度分配的衔接A*出来的路径是折线段无人机飞这种路径转弯角是苛刻的无人车也受不了这种原地打折的转向。这一步做Dubins平滑function smoothPath dubinsSmooth(path, turningRadius) smoothPath []; for i 1:length(path)-2 p1 path(i, :); p2 path(i1, :); p3 path(i2, :); % 计算向量夹角如果转弯过大插入Dubins过渡弧 v1 p2 - p1; v2 p3 - p2; angle atan2(abs(v1(1)*v2(2) - v1(2)*v2(1)), dot(v1, v2)); if angle deg2rad(30) % 插入圆弧过渡 [arcPoints, ~] dubinsArc(p1, p2, p3, turningRadius); smoothPath [smoothPath; arcPoints]; else smoothPath [smoothPath; p2]; end end end速度协调的实现在平滑之后、任务执行模拟之前。流程是先根据平滑后的路径逐段累加长度除以每个平台的经济巡航速度得到各自的自然完成时间取最大完成时间作为协同参考时间最后反算每个平台的参考速度并做物理可行性校验。注意路径长度和轮速执行都是在仿真层面做的真实硬件平台上还有电机响应延迟和里程计漂移的问题。仿真里速度同步做得再精确硬件上跑起来都会有偏差。所以代码里要留一个时间缓冲接口在目标点附近设置等待区既有的平台可以提前到但不能早到目标正上方暴露位置而是停在等待区内等所有平台就绪后再统一进场。4. 实操过程从零搭建到场景复现的完整步骤4.1 场景定义与仿真参数设置我复现时用的测试场景定义如下地图尺寸400×400像素对应物理区域400×400米无人机参数巡航速度15m/s最小转弯半径30m最大航程3000m无人车参数巡航速度3m/s最小转弯半径5m最大续驶里程2000m任务目标覆盖10个目标点每个目标点都需要至少一个空中平台和一个地面平台在时间窗±10秒内到达配置参数里的一个关键细节是协同时间窗的宽窄设定。时间窗±10秒在物理世界已经是很严苛的要求了——无人机和无人车的速度差异摆在那里能对齐到这个精度说明协同算法刷得很正常。初学时可以把时间窗放宽到±30秒先把逻辑跑通再逐步收紧看算法的边界能力。4.2 需要逐步执行的四个阶段阶段一地图预处理与可视化验证把地图读进来以后第一件事不是跑算法而是验证膨胀处理后的地图是否正确。把原始地图和膨胀地图画在一起对比看哪些窄通道被合理保留了哪些不该切断的通道被切断了。这一步每次都值得做15分钟能防止后续所有问题。阶段二单平台路径规划验证在膨胀地图上分别跑无人机和无人车的单平台路径规划先不启用协同逻辑确认每一条单路径本身是合理可行的。这一步如果看到路径穿障碍、过大折线、绕远路的问题直接在这一层解决不要带着问题进协同层。阶段三开启任务分配验证目标分配结果把10个目标点加进去分配器计算结果以后人工审视分配结果是否合理。我在这一步发现过一个很有意思的现象分配器倾向于把所有目标都分配给无人机因为它的速度快、欧氏距离近。人工一眼就能看出这不行——无人机续航根本不够跑完10个点。原因就是代价矩阵缺少续航约束的惩罚项。在代价矩阵里加上平台最大航程的软约束之后分配结果就明显合理了。阶段四协同时间对齐与迭代验证在最终分配结果和路径都确定后跑速度同步算法。把10个目标点的到达时间差画成柱状图应该能看到所有目标点的时间误差都在容限范围内。如果有个别点超限要么是路径长度估算误差太大要么是速度调整超了安全域需要回到分配-规划回路重新迭代。4.3 全流程效果的可视化呈现调试的时候把协同过程可视化我做了四个主视图左上方视图全局任务态势图地图与所有平台路径左下方视图各平台随时间变化的位置轨迹带拖影右上方视图时间对齐误差图各平台到达每个目标点的时间偏差右下方视图速度曲线图这四个视图在联调的时候帮了我大忙。时间对齐误差图尤其好用——哪个环节有问题从误差柱状图上能一眼定位是分配问题还是路径问题还是速度同步问题。5. 常见问题与排查技巧实录5.1 八个高频问题速查表编号问题现象可能原因解决策略1无人车路径穿障碍地图膨胀不足或障碍标记坐标和路径坐标不一致检查坐标系原点是左上还是左下检查膨胀半径2无人机路径连续大角度转弯A*生成的折线路径未做平滑切换Dubins平滑后处理算法3目标点总分配给无人机代价矩阵缺少续航约束在目标函数中加入平台剩余航程惩罚项4到达时间差很大速度同步层没有启用或安全域太小检查速度同步是否在路径规划之后执行5遗传算法收敛特别慢种群太小或交叉率不合适种群设为目标点数的5-10倍交叉率0.8-0.96路径在窄通道处反复绕行膨胀半径过大导致通道被判定为不可通行减小膨胀半径或对地图做形态学开运算7仿真运行时平台在同一栅格碰撞缺少平台间的动态防撞检查在速度同步后加入动态避让时间窗8多次运行结果不一致遗传算法有随机性未固定随机种子设置 rng(固定数值) 做可复现实验5.2 问题3的深入讲解为什么分配结果经常“偏心”目标点总分配给无人机这个问题值得展开讲讲。根本原因是遗传算法的目标函数是总收益最大化而无人机的“单位时间收益”天然高于无人车。在平台数量和任务量都不大的时候求解器会本能地把任务往高效平台身上堆。这在单目标优化视角下没有错但它违背了“多平台协同”这个前提——协同的意义就是让不同类型平台各展所长而不是让一类平台包圆所有任务。我的解决方案是显式加入平台利用率均衡项。目标函数从总收益 Σ(各平台任务收益)改成总收益 Σ(各平台任务收益) - λ ×(平台间任务量方差)λ是一个手调的惩罚权重。加入这一项以后分配结果在协同性上明显改善无人机和无人车各司其职从最终路径形态上看也更合理像是团队作战而不是单兵逞英雄。5.3 问题7的动态防撞处理栅格A*规划的都是静态路径但在多平台同时执行时即使静态路径不重叠时间上也可能出现两个平台同时占用同一个栅格的情况。离散事件仿真里这表现为平台在同一栅格的轨迹穿插。最简单的解决方式是在速度同步层做时间窗避让——对于每对可能占用的公共节点调整一个平台在该段的通过时间。代价是可能破坏全局时间同步精度所以要做迭代平衡。更复杂的方案是引入优先级机制比如无人机在空中和无人车不冲突但如果两辆无人车争用同一个节点让先到达占位的车先通行另一个在节点附近等待。实操心得动态防撞的代码量不大但调试时最花时间的不是算法逻辑而是让仿真事件队列里的时间戳和数据结构的行列索引保持一致。出错几乎都是因为这些细节两边对不上用断点单步追查又慢又烦。我的做法是写一个专门的时间戳快照打印函数每个平台每运行一个时间步就记录一次位置和时间把数据导入表格排序后人工检查是否有时空碰撞。一个测试下来几千行数据但定位问题的速度比手动查快几十倍。5.4 复现过程中的三条核心避坑经验第一条先跑通再调优。论文里的算法是理论最优的表述但真实复现时第一次跑通的时候大概率是次优结果。不要急着在第一次跑通时就调参调到完美先把全流程跑起来、数据记录下来、可视化做出来再回头逐项优化。这个过程会让调试效率和心情都好很多。第二条代码里所有坐标单位统一。地图像素坐标、物理坐标、路径坐标、时间戳索引这几个之间要保持清晰、可追溯的换算关系。我原代码里有一版混用了像素坐标和物理坐标排查了好久才发现简直欲哭无泪。从一开始就在地图模块里写坐标转换函数后面所有模块一律调用转换函数这个问题就再也不存在了。第三条订阅参数日志。每跑完一次实验把能记录的都记录下来——地图版本、膨胀半径、遗传代数、每轮的目标函数值、每条的路径长度、速度同步后的到达时间误差。后期做对比分析时这些日志是判断改进是有利还是有害的唯一依据。没有日志的算法实验基本等于白跑。6. 根据我的实际经验说几个总结性的体会做这类论文复现项目真正的收获往往不在“把论文的代码抄通”而在于复现过程中逼着自己把论文里一笔带过的“废话”重新思考一遍。比如论文可能用一句话说“设置协同时间窗口”你实现的时候才会发现这句话背后藏着一堆问题时间窗宽窄怎么定、哪个平台先到怎么办、时间同步不满足时是让快的等还是让慢的赶。这些细节论文通常不会逐字写清楚但恰恰是这些细节决定了算法能不能在真实任务里落地。从投入产出比看多远平台协同路径规划这个方向的技术栈极其通用。A*、遗传算法、Dubins曲线、时间同步这些组件拆开来看都是非常成熟的技术寒假里练手也好、组会汇报做demo也好这套项目做完之后的代码积累在后续做多智能体仿真、编队控制、分布式决策这些课题时都能直接复用。Matlab代码在算法迭代和可视化验证这个环节的开发效率也确实让它成为这类复现项目的合理第一选择。最后讲一个小经验这个项目做完以后可以往两个方向继续扩展。一个方向是加动态障碍物把静态地图换成有移动物体的仿真环境让平台在路径规划中引入滚动时域重新规划逻辑另一个方向是加通信约束模拟真实通信环境下平台之间信息交换受限时的协同策略。两个方向的工程量都在可控范围内但对这块知识的理解深度会有质的提升。如果你复现完这个项目以后觉得还不过瘾优先挑其中一个方向继续往下做就对了。

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

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

免费获取报价 →
↑