尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

基于合同网协议的多无人机任务分配算法:Matlab实现与时间窗口优先级约束优化

基于合同网协议的多无人机任务分配算法:Matlab实现与时间窗口优先级约束优化 1. 项目概述当无人机集群遇上“拍卖会”最近在做一个挺有意思的项目核心是解决多架无人机怎么“聪明地”去分活儿。想象一下你手头有十架无人机要派它们去二十个不同的地点执行任务比如巡检、拍照或者投递。这些任务可不是随到随做的有的必须在上午10点到11点之间完成时间窗口有的任务优先级高必须优先处理。更复杂的是无人机之间还得协调避免撞车或者资源浪费。这听起来是不是像个调度难题没错这就是典型的多智能体任务分配问题。我这次采用的解决方案核心是一种叫做“合同网协议”的分布式算法。你可以把它理解成一场在无人机集群内部举行的“微型拍卖会”。每架无人机都是一个独立的“投标人”而待分配的任务就是“拍卖品”。当一个新的任务出现或者有无人机完成了当前任务它就会向集群广播一个“招标公告”。其他无人机根据自己当前的位置、电量、任务队列计算出一个“投标价”通常是完成这个任务的预估成本比如飞行距离、时间消耗然后回复给招标方。招标的无人机就像拍卖师它会评估所有投标选择那个“出价”最合适的无人机和它“签订合同”把这个任务正式分配给它。这种方法最大的好处是分布式和自适应。不需要一个高高在上的中央大脑来指挥一切每架无人机自己就能做决策。当有无人机故障或者突然插入紧急任务时整个系统能快速响应重新协商分配非常灵活。我用Matlab来实现这个逻辑主要是因为它的矩阵运算和仿真环境特别适合做这种算法验证和快速原型开发。整个项目不仅实现了基本的合同网协议还重点攻克了“时间窗口”和“优先级”这两个在实际应用中绕不开的硬约束最后还能对分配结果进行动态跟踪和可视化。下面我就把这个从理论到代码实现的完整过程以及踩过的坑和心得详细拆解一遍。2. 核心问题拆解与建模思路在动手写代码之前必须把问题定义清楚。我们这个“多无人机具有时间窗口和优先级约束任务分配及跟踪问题”可以拆解成以下几个核心部分2.1 约束条件到底是什么时间窗口约束这不是说任务必须在某个时间点完成而是它有一个允许执行的“时间段”。例如任务A必须在[t_start_A, t_end_A]这个区间内开始执行。如果无人机到达任务点的时间早于t_start_A它需要等待如果到达时间晚于t_end_A则任务失败。这模拟了现实中的很多场景比如光照条件最佳的巡检时段、客户指定的送货时间范围等。优先级约束任务有高低之分。高优先级任务必须优先于低优先级任务被分配和执行。在算法中这不能简单理解为“先分配高优先级任务”因为还要考虑无人机的位置、时间窗口等因素。我们需要一个机制在投标和评标时让优先级因素能够压倒性地影响决策。无人机能力约束每架无人机有最大航程、最大负载、续航时间。它不能同时执行两个任务单任务机假设必须完成一个才能开始下一个。冲突避免虽然本项目主要聚焦任务分配但跟踪问题隐含着对路径的考虑需要确保无人机在执行任务的路径上不会发生时空冲突。2.2 为什么选择合同网协议面对多智能体任务分配主流方法有集中式和分布式。集中式比如整数规划把所有无人机和任务信息汇总到一个中心服务器求解优点是能获得全局最优解但计算量大通信负担重且中心节点是单点故障。分布式方法如合同网协议、拍卖算法每个智能体只处理局部信息通过通信协商达成一致。选择CNP的理由很充分鲁棒性强没有单点故障任何一架无人机失效其余无人机可以接管其任务或重新协商。可扩展性好增加无人机或任务不需要改变核心算法架构只需加入新的通信节点。适应动态环境新任务随时发布无人机状态如电量实时变化CNP能通过持续的招标-投标-中标流程快速响应。天然契合问题招标、投标、中标的过程非常方便融入对时间窗口和优先级的考量。投标价的计算函数就是融入这些约束的核心载体。2.3 数学模型与关键参数我们需要用数学语言描述问题。假设有N_u架无人机和N_t个任务。无人机i的状态可以用一个向量表示U_i [x_i, y_i, v_i, E_remain_i, status_i] 分别代表位置坐标、巡航速度、剩余电量、状态空闲、 traveling、 executing。任务j的属性T_j [x_j, y_j, d_j, p_j, [t_start_j, t_end_j]] 分别代表任务位置、执行耗时例如拍照需要稳定悬停10秒、优先级p_j数值越高越优先、时间窗口。决策变量本质上是一个分配矩阵XX_{ij}1表示任务j分配给无人机i否则为0。目标函数通常是最小化总成本比如所有无人机完成所分配任务的总飞行距离或总时间。在CNP中这个总成本最小化是通过每架无人机在投标时局部优化自己的任务序列来实现的。投标价计算这是CNP算法的灵魂。当无人机i收到任务j的招标时它需要计算一个投标价bid_{ij}。这个价格不是随便报的它必须反映无人机i去执行任务j的“代价”。一个典型的计算方式如下bid_{ij} C_travel(i, j) C_wait(i, j) C_priority(j)其中C_travel从无人机当前位置或当前任务结束位置飞到任务j位置的代价与距离成正比。C_wait如果无人机到达任务点的时间早于t_start_j产生的等待代价。等待可能浪费时间和电量。C_priority基于任务优先级的惩罚项。对于低优先级任务可以增加一个基础惩罚使得高优先级任务在价格上更具竞争力。一个技巧是使用-alpha * p_j其中alpha是一个大的正系数这样优先级p_j越高投标价反而越低更容易中标。招标方通常是任务发布者或空闲无人机会收集所有投标选择bid最小的无人机作为中标者。这就实现了在考虑距离、时间、优先级后的“最优”分配。3. 基于Matlab的CNP算法实现详解理论清晰后我们进入实操环节。用Matlab实现CNP关键在于设计好智能体无人机的类、通信机制和仿真循环。3.1 系统架构与类设计我采用面向对象的思想来构建系统这样结构清晰也便于调试。classdef Task properties id location % [x, y] duration % 执行所需时间 priority % 优先级 数值越大越高 timeWindow % [startTime, endTime] status % unassigned, assigned, completed assignedUAVId startTime endTime end methods function obj Task(id, loc, dur, prio, tw) % 构造函数 obj.id id; obj.location loc; obj.duration dur; obj.priority prio; obj.timeWindow tw; obj.status unassigned; obj.assignedUAVId []; obj.startTime inf; obj.endTime inf; end end end classdef UAV properties id location % 当前位置 velocity % 巡航速度 battery % 剩余电量简化模型可代表续航时间 status % idle, moving_to_task, executing, returning currentTaskId % 当前正在执行或前往的任务ID taskList % 已分配的任务队列按计划执行顺序 estimatedTime % 预计完成当前任务列表的时间 end methods function obj UAV(id, initLoc, vel, bat) obj.id id; obj.location initLoc; obj.velocity vel; obj.battery bat; obj.status idle; obj.currentTaskId []; obj.taskList []; obj.estimatedTime 0; % 从当前时刻开始算 end function bid calculateBid(obj, task, currentTime) % 核心函数计算对某个任务的投标价 % 1. 计算到达时间 distance norm(obj.location - task.location); travelTime distance / obj.velocity; arrivalTime currentTime travelTime; % 2. 计算等待时间如果早于时间窗口 waitTime max(0, task.timeWindow(1) - arrivalTime); actualStartTime max(arrivalTime, task.timeWindow(1)); % 3. 检查是否能在时间窗口内完成 if actualStartTime task.timeWindow(2) bid inf; % 无法在窗口内开始投标无效无穷大代价 return; end % 4. 计算代价 travelCost travelTime; % 代价1飞行时间 waitCost waitTime * 0.5; % 代价2等待时间系数可调等待通常比飞行代价小 priorityCost -10 * task.priority; % 代价3优先级高优先级产生负代价降低总价 % 注意这里优先级是数值越大越高所以用负号使其降低总bid bid travelCost waitCost priorityCost; % 5. 可选考虑电量约束 if obj.battery (distance * 0.1) % 假设一个简单的能耗模型 bid bid * 1.5; % 电量低时提高投标价降低中标概率 end end function obj addTask(obj, taskId) % 将任务加入本机队列 obj.taskList [obj.taskList, taskId]; % 这里需要重新规划队列顺序和估算时间简化处理可假设按添加顺序执行 % 更复杂的实现可以在此处调用一个内部调度优化 end end end注意calculateBid函数中的权重系数如等待代价系数0.5优先级系数-10是调参的关键。它们直接决定了算法是更看重距离、时间还是优先级。需要根据具体的仿真场景反复调试。一个经验是优先级的系数绝对值要足够大以确保高优先级任务能压倒性地胜出。3.2 主仿真循环与协议流程主程序是一个时间步进的仿真循环在每个时间步里模拟无人机状态更新和CNP协议的运行。% 初始化 numUAVs 5; numTasks 20; UAVs cell(1, numUAVs); Tasks cell(1, numTasks); % ... 创建UAV和Task对象的代码 ... % 仿真参数 maxTime 200; % 最大仿真时间 dt 1; % 时间步长 currentTime 0; % 主循环 while currentTime maxTime 还有未完成的任务 % --- 阶段1 检查并发布招标 --- for t 1:length(Tasks) task Tasks{t}; if strcmp(task.status, unassigned) % 该任务需要招标 % 在实际CNP中可能由任务本身或一个协调者发布招标 % 这里简化由第一个发现它的空闲无人机来发起招标或定时全局招标 callForBids(task, currentTime); end end % --- 阶段2 投标与中标 --- % 假设有一个全局的“招标板”存储了正在招标的任务 % 每架空闲或即将空闲的UAV检查招标板对感兴趣的任务投标 for u 1:length(UAVs) uav UAVs{u}; if strcmp(uav.status, idle) || uav.estimatedTime currentTime 5 % 即将空闲 for each task in biddingBoard bid uav.calculateBid(task, currentTime); submitBid(uav.id, task.id, bid); end end end % 招标方模拟收集所有投标选择bid最小的UAV中标 % 更新Task和UAV的状态task.statusassigned, task.assignedUAVIdwinnerId; uav.addTask(task.id); % --- 阶段3 无人机状态更新与任务执行 --- for u 1:length(UAVs) uav UAVs{u}; switch uav.status case idle % 检查任务队列如果有任务则开始前往第一个任务 if ~isempty(uav.taskList) nextTaskId uav.taskList(1); uav.status moving_to_task; uav.currentTaskId nextTaskId; % 计算路径点等... end case moving_to_task % 向任务点移动 uav.location moveTowards(uav.location, taskLocation, uav.velocity, dt); if 到达任务点 uav.status executing; taskStartTime max(currentTime, task.timeWindow(1)); % 考虑时间窗口 Tasks{nextTaskId}.startTime taskStartTime; end case executing if currentTime Tasks{uav.currentTaskId}.startTime Tasks{uav.currentTaskId}.duration % 任务完成 Tasks{uav.currentTaskId}.status completed; Tasks{uav.currentTaskId}.endTime currentTime; uav.taskList(1) []; % 从队列移除 uav.currentTaskId []; uav.status idle; end end % 更新电量等... UAVs{u} uav; end % --- 阶段4 可视化与数据记录 --- plotSimulationState(UAVs, Tasks, currentTime); recordMetrics(completionRate, totalTravelDistance, etc.); currentTime currentTime dt; endcallForBids,submitBid,moveTowards等函数需要具体实现。通信过程在仿真中可以用全局变量或消息队列来模拟。3.3 时间窗口与优先级约束的融合实现这是算法的难点和亮点。关键在于calculateBid函数和任务执行逻辑。时间窗口在投标阶段的处理如代码所示在计算投标价时如果计算出的到达时间晚于任务时间窗口的结束时间直接返回inf无穷大表示无法接受此任务。如果到达时间早于开始时间则加入等待代价。这确保了只有能满足时间窗口的无人机才会参与有效投标。时间窗口在执行阶段的处理当无人机抵达任务点时状态变为executing但实际开始执行的时间是max(当前时间, task.timeWindow(1))。这模拟了提前到达后的等待行为。优先级约束的处理在投标价中我使用了priorityCost -10 * task.priority。这是一个非常巧妙的设计。因为招标方是选择最低投标价中标。对于高优先级任务priority值大这个项是一个很大的负数会显著拉低总bid从而极大地增加其中标的概率。系数-10的绝对值大小决定了优先级因素相对于飞行距离和等待时间的权重。你可以通过调整这个系数来平衡“效率”和“紧急程度”。实操心得优先级系数的设定需要大量实验。如果设得太小可能无法保证高优先级任务绝对优先如果设得太大又可能导致无人机为了一个高优先级但非常远的任务牺牲了整个系统的效率。一个稳妥的做法是进行归一化处理。例如将所有任务的优先级映射到[0,1]区间飞行时间和等待时间也估算一个最大范围进行归一化然后给优先级分配一个固定的、较大的权重如0.7这样约束的平衡性更好。4. 任务分配跟踪与可视化分配算法跑起来之后我们更需要直观地看到结果和过程。跟踪不仅仅指无人机飞行的动画更重要的是对分配决策、任务完成序列、系统性能指标的记录和分析。4.1 动态可视化实现我用Matlab的plot和scatter函数结合循环实现了一个简单的动态看板。function plotSimulationState(UAVs, Tasks, currentTime) clf; % 清空当前图形 hold on; % 1. 绘制任务点 for t 1:length(Tasks) task Tasks{t}; pos task.location; switch task.status case unassigned plot(pos(1), pos(2), ko, MarkerSize, 10, LineWidth, 2); text(pos(1), pos(2)0.2, [T, num2str(task.id)], FontSize, 8); % 用虚线圆表示时间窗口可选较复杂 case assigned plot(pos(1), pos(2), bs, MarkerSize, 12, LineWidth, 2); text(pos(1), pos(2)0.2, [T, num2str(task.id), (U, num2str(task.assignedUAVId), )], FontSize, 8); case completed plot(pos(1), pos(2), g^, MarkerSize, 10, LineWidth, 2); end % 在任务点旁边显示优先级 text(pos(1)-0.3, pos(2)-0.3, [P:, num2str(task.priority)], FontSize, 7, Color, red); end % 2. 绘制无人机及其轨迹 colors lines(length(UAVs)); % 为每架无人机分配不同颜色 for u 1:length(UAVs) uav UAVs{u}; pos uav.location; % 绘制无人机当前位置 plot(pos(1), pos(2), o, Color, colors(u,:), MarkerFaceColor, colors(u,:), MarkerSize, 15); text(pos(1), pos(2)-0.4, [U, num2str(uav.id)], FontSize, 10, FontWeight, bold, Color, colors(u,:)); % 绘制无人机的任务队列连线从当前位置到下一个任务点 if ~isempty(uav.taskList) ~isempty(Tasks{uav.taskList(1)}) nextTaskPos Tasks{uav.taskList(1)}.location; plot([pos(1), nextTaskPos(1)], [pos(2), nextTaskPos(2)], --, Color, colors(u,:), LineWidth, 1.5); end % 绘制历史轨迹存储位置历史 if isfield(uav, pathHistory) plot(uav.pathHistory(:,1), uav.pathHistory(:,2), -, Color, colors(u,:), LineWidth, 0.5); end end % 3. 绘制图例和信息面板 title(sprintf(多无人机任务分配仿真 - 时间: %.1f s, currentTime)); xlabel(X坐标); ylabel(Y坐标); axis equal; grid on; legend({未分配任务, 已分配任务, 已完成任务}, Location, bestoutside); % 4. 实时显示关键指标 completedTasks sum(arrayfun((t) strcmp(t{1}.status, completed), Tasks)); text(0.02, 0.98, sprintf(任务完成率: %d/%d\n当前时间: %.1f, completedTasks, length(Tasks), currentTime), ... Units, normalized, VerticalAlignment, top, BackgroundColor, w, EdgeColor, k); drawnow; hold off; end这个可视化能清晰展示哪些任务未分配黑圈、已分配蓝方块给哪架无人机、已完成绿三角每架无人机的位置、颜色编码的轨迹和任务连线以及实时的完成率。4.2 性能指标跟踪与分析光有动画不够我们需要数据来评估算法好坏。在仿真循环中我记录了以下核心指标任务完成率随时间变化的曲线。可以看算法是否能快速完成所有任务。总飞行距离/时间所有无人机飞行距离之和。衡量系统能耗和效率。优先级任务平均完成时间比较不同优先级任务从发布到完成的平均时间验证优先级约束是否生效。时间窗口违反次数任务实际开始时间晚于其时间窗口结束时间的次数越少越好。通信开销模拟的招标-投标消息数量。分布式算法需要关注通信负担。在仿真结束后可以绘制这些指标的图表并与集中式调度如全局整数规划求解器的结果进行对比分析CNP在效率、最优性差距和鲁棒性上的优劣。注意事项Matlab动态绘图尤其是频繁clf和drawnow在任务数量多、仿真时间长时会非常卡顿。对于长期运行或参数寻优建议将可视化开关设置为可选或者只每隔N个时间步绘制一次。核心是把数据记录下来事后分析。5. 参数调优、常见问题与调试技巧实现基本功能后项目进入了最耗时的阶段调参和调试。CNP算法的表现非常依赖于投标价计算函数中的权重系数、招标触发机制等参数。5.1 关键参数调优指南优先级权重系数 (alpha)如前所述priorityCost -alpha * p_j。alpha太小高优先级任务可能竞争不过距离近的低优先级任务alpha太大无人机可能会“不惜一切代价”奔向高优先级任务导致总体路径规划极差。调试方法固定其他参数逐渐增大alpha观察高优先级任务的平均完成时间是否显著下降同时监控总飞行距离的增长是否在可接受范围内。可以画一个折衷曲线Pareto前沿来帮助选择。等待代价系数等待时间乘以的系数。这个系数通常小于飞行代价系数设为1因为等待消耗的能源通常少于飞行。但如果设得太小无人机可能会倾向于提前很久到达并等待浪费了执行其他任务的时间窗口。可以将其设置为一个与无人机续航成本相关的值。招标触发机制是任务一发布就招标还是定期批量招标或者是当有无人机空闲时才触发全局招标不同的机制影响系统的响应速度和通信量。简单有效的策略每个时间步检查所有unassigned任务如果其发布时间超过一个阈值比如5秒就发起一次招标。同时每当有无人机变为空闲状态也检查一次未分配任务列表并招标。投标有效期在真实通信中投标可能有过期时间。在仿真中可以为投标设置一个有效期例如投标基于当前状态计算2秒后失效以避免无人机状态已变但仍基于旧信息中标。5.2 常见问题与排查实录在开发过程中我遇到了几个典型问题这里分享排查思路问题1仿真陷入停滞很多任务无人投标。现象大量任务状态一直是unassigned无人机在 idle 状态也不去投标。排查检查投标价计算函数calculateBid。最常见的原因是时间窗口约束过严。打印几个典型任务和无人机的arrivalTime和timeWindow看看是否所有无人机计算出的bid都是inf。如果是说明在当前无人机部署和速度下没有无人机能在时间窗口内赶到这些任务点。需要放宽时间窗口或增加无人机数量/速度。检查招标触发逻辑。确认未分配任务列表能被正确遍历并且招标消息能被无人机接收到在仿真中就是相应的函数被调用。检查无人机状态机。确保idle状态的无人机会去检查招标板并计算投标价。问题2高优先级任务没有被优先执行。现象从可视化上看无人机还是就近选择任务高优先级任务被晾在一边。排查确认优先级数值定义是数字越大优先级越高吗在投标价计算中priorityCost -alpha * p_j如果p_j越大优先级越高那么-alpha * p_j就是一个很大的负数会降低总bid这没错。检查alpha的值是否足够大。可以临时将alpha设为一个极大值如10000然后观察高优先级任务是否立刻被分配。检查投标价范围打印出不同任务对不同无人机的bid值。比较一个距离近的低优先级任务和一个距离远的高优先级任务的bid。如果高优先级任务的bid仍然比低优先级的高说明飞行代价部分仍然占主导需要继续调大alpha或者对飞行距离进行归一化处理使其与优先级项处于同一数量级。问题3无人机路径出现明显不合理的绕远或交叉。现象从轨迹上看无人机A穿过无人机B的路径去执行一个任务而另一个更近的任务却由无人机C执行。排查这是分布式算法的固有缺点——局部最优不等于全局最优。CNP是贪婪的每次招标只考虑单个任务的最优分配没有考虑多个任务之间的协同。例如无人机A和B可能各自独立地投标了两个距离自己最近但方向相反的任务导致总路径交叉。改进策略可以引入任务包招标。不是一次只招标一个任务而是将空间或时间上接近的多个任务打包成一个“合同”进行招标。无人机计算的是执行整个任务包的总代价。这能在一定程度上改善协同性。在Matlab中实现需要修改Task对象和招标逻辑将多个任务ID绑定在一起。另一种思路是引入重协商机制。当无人机获得一个新任务后评估如果将此任务与集群中其他无人机的某个任务交换是否能降低系统总成本。如果可以则发起一次任务交换的协商。这增加了通信和计算复杂度但能提升全局性能。问题4仿真后期剩余的几个任务迟迟无法完成。现象大部分任务已完成少数几个分散的、时间窗口紧迫或优先级低的任务一直没人接。原因与解决这可能是因为所有无人机都已排满任务队列或者剩余任务对任何无人机来说投标价都太高如距离太远且时间窗口将过。引入“全局重规划”触发当系统检测到超过一定时间如30秒没有新任务被分配且存在未分配任务时强制所有无人机清空当前任务队列已完成的任务除外重新对所有未分配任务进行一次集中式的招标分配。这相当于在分布式中加入了集中式的“重置”按钮能有效解决死锁。设置“最后期限”惩罚在投标价计算中为任务加入一个随时间增长的“紧急度”惩罚。任务发布越久其投标价基础值就越高或减去一个值从而促使无人机最终去处理它。5.3 Matlab编程与调试技巧使用tic和toc进行性能分析在仿真的关键步骤如所有无人机的投标计算循环前后加上tic/toc找出计算瓶颈。如果任务和无人机数量很多50投标计算O(N*M)可能成为瓶颈需要考虑优化距离计算使用预计算的距离矩阵或采用近似算法。结构化日志输出不要只用disp打印零散信息。定义一个全局的日志结构体或写入文件记录每个时间步的关键事件如“时间10.5 任务T5由UAV3招标 收到投标[UAV1:15.2, UAV2:inf, UAV3:12.7] 中标者UAV3”。这比看图形更容易追溯算法逻辑错误。利用Matlab Debugger和条件断点当算法出现异常行为时在怀疑的函数如calculateBid里设置条件断点。例如断点条件设为task.id 5 uav.id 2这样就可以专门观察特定任务和无人机的交互过程查看中间变量计算是否正确。参数扫描与批量仿真为了调优权重系数可以写一个脚本循环不同的参数组合自动运行多次仿真并记录每次的性能指标总距离、完成率等。最后用surf或plot3函数可视化参数与性能的关系科学地找到较优参数区。这个项目从问题定义到算法实现再到调试验证是一个完整的闭环。合同网协议为多无人机任务分配提供了一个优雅的分布式解决方案而时间窗口和优先级的引入使其更贴近实际应用。Matlab强大的数值计算和可视化能力使得这类算法的原型验证和性能分析变得非常高效。尽管最终的实现可能为了清晰做了一些简化但核心框架和问题解决思路是完整且可扩展的。在实际工程化时需要考虑更复杂的通信模型、不确定性处理以及真正的并行计算但这份Matlab代码无疑是一个坚实可靠的起点。
返回列表