尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

粒子群算法求解多无人机任务分配:Python源码深度剖析

粒子群算法求解多无人机任务分配:Python源码深度剖析 简介一套基于 Python 的粒子群算法多无人机任务分配源码主要面向毕业设计、课程设计与项目开发场景适合中高级本科生或研究生作为智能优化与无人机调度方向的起点。代码以航迹代价作为适应值核心完整覆盖 PSO 主程序、无人机间距离计算、适应度评估、约束条件处理、时间统计与结果可视化等模块模块划分清晰便于逐段调试和二次开发。压缩包共 16 个文件包含 9 个 Python 脚本、4 张结果示意图、README 使用说明、配置文件与文本文档整体仅 1.42MB轻量易部署。已有 657 人浏览学习源码经过严格测试可直接运行验证算法效果在此基础上可扩展多约束任务模型、改进粒子群策略或接入真实地图环境对理解群智能优化和任务分配实现具有较高参考价值。基于Python实现的粒子群算法多无人机任务分配源码剖析1. 这个项目的核心价值人人都能做“多机协同”的算法设计前段时间陆续有好几个读者私信问我毕业设计想选“无人机任务分配”方向但网上能找到的资料不是太理论就是没有完整代码到底怎么落地说实话这个题目确实很适合拿来做毕设或课程设计——粒子群算法PSO实现简单、收敛效果直观多无人机任务分配又自带非常漂亮的二维/三维可视化结果两样叠加在一起不需要太多硬件成本就能产出一个“能跑、能看、能讲清楚原理”的完整项目。先把这个项目的本质说白了假设现在有一个任务区域里面有若干个目标点需要被巡检、打击或投递物资而我们手上有多架无人机怎么给每一架无人机分派任务让整体的飞行总航程最短、完成时间最省、负载最均衡这类问题形式化之后是一个组合优化问题目标函数是非线性的约束条件多用传统穷举法在“无人机数量任务点数量”稍微大一点的时候就直接爆炸了。粒子群算法的思路很朴素——模拟鸟群觅食过程中个体经验和群体信息共享的机制通过不断更新每个粒子的速度和位置来逼近最优解。这个项目适合谁来参考如果你是准备毕设的本科生这个源码可以帮你把“问题建模、算法实现、结果分析”一整条链路完整打通如果你是在准备课程设计的同学代码里的注释和模块划分能让你快速读懂并做二次修改哪怕你只是对智能优化算法感兴趣的自学者把PSO用在无人机任务分配上也是一个非常好的“算法应用”练手项目。整个工程基于Python实现依赖库只用了numpy、matplotlib这些最常用的包不涉及复杂的无人机仿真平台学习成本非常低。接下来这篇博客我会把这套源码从问题建模、算法设计到代码实现的关键细节完整拆开来讲并且会分享一些在开发过程中踩过的坑希望能帮你节省调整参数和排错的时间。2. 先从数学建模说起无人机任务分配到底在优化什么2.1 任务分配问题的目标函数与约束条件很多人拿到这个问题第一反应是“直接用PSO跑就行”但实际上没有把问题建模清楚之前任何算法都是跑不起来的。我们要先定义清楚无人机集合 U {U1, U2, ..., Un}任务点集合 T {T1, T2, ..., Tm}。每一次任务分配的结果就是要确定一个方案矩阵 Xn行m列其中 x_ij 1 表示无人机 i 执行任务点 jx_ij 0 表示不执行。这个矩阵就是PSO要优化的“答案”。目标是什么最常用、也最好解释的目标是最小化所有无人机的总航程或总完成时间。假设已知每个无人机所在位置、每个任务点的坐标、飞行速度相同那么总航程就是每架无人机从起点出发经过分配给它的任务点再返回起点的路径长度之和。当然不同的应用场景可以调整目标函数——例如希望任务完成时间尽可能短那目标函数就变成“各无人机中完成时间最大的那个值取最小”也就是最小化最大完工时间makespan再比如希望各无人机工作量均衡可以引入负载方差项。约束条件通常有几条每个任务点只能被一架无人机执行这是硬约束每架无人机可执行的任务数量不能超过它的挂载能力或续航上限所有无人机的任务分配要满足“起点终点一致”的回路约束。在源码实现里我以“总航程最小 惩罚项处理约束”为标准形式来做因为这种方式对PSO来说最好处理不需要专门设计复杂的编码来硬性满足约束。2.2 适应度函数设计的隐藏学问PSO每次迭代都要调用适应度函数来评价一个粒子的好坏程度所以适应度函数的设计直接决定算法最终效果的走向。源码中设计的适应度函数分两部分基础代价 cost_base 和 惩罚代价 cost_penalty。基础代价的计算流程是这样的根据任务分配矩阵对每一架无人机把它负责的任务点按编号顺序连接成一条路径计算这条路径从出发点出发、经过所有任务点、回到出发点的总欧氏距离。这里有个细节需要注意——如果任务点在分配时没有指定“执行顺序”路径长度其实还跟访问顺序有关所以更严谨的做法是先对每架无人机负责的任务点做一次局部排序优化比如用贪心最近邻策略排一版顺序再计算总距离。源码里实际上是在适应度函数内部加入了最小化路径长度的贪心排序逻辑这样一方面保持PSO搜索的是“分配方案”另一方面路径顺序也被优化到了。惩罚代价则用来处理“约束被违反”的情况。例如有的粒子可能把多个任务点分配到了同一架无人机上导致这架无人机航程超出续航上限或者某些任务点没有被任何无人机执行这通常发生在编码映射不好处理时。对这些违反约束的粒子我在适应度公式里加上一个较大的惩罚系数乘以违反量比如fitness total_distance 1000 * violation_degree惩罚系数不能太小太小了被惩罚的粒子依然可能胜出导致最终解是“违规解”也不能太大太大了会破坏适应度函数曲面的平滑性让算法难以搜索。我实测在无人机数和任务点数在十几到几十这个量级时惩罚系数取 500~2000 之间效果稳妥。个人经验如果你的场景允许无人机任务数不均等那么“每个任务点恰好被覆盖一次”这个约束请在初始化粒子时就尽量保证不要全依赖惩罚函数去纠偏。把约束前移能大幅减少PSO的无效搜索。3. 粒子群算法代码实现编码方式和更新规则是灵魂3.1 粒子编码怎么把任务分配方案映射成粒子位置向量PSO本身是处理连续优化问题的而任务分配是离散的组合优化问题所以如何编码是写代码时最核心的一个决策。源码中采用了非常经典的“基于任务编号的实数编码法”每个粒子是一个 m 维向量m是任务点数量向量中第 j 个位置的值 v_j 表示任务点 T_j 被分配给哪架无人机v_j 的取值范围是 [1, n1)n是无人机数量对 v_j 向下取整就得到无人机编号。举个例子一共3架无人机、5个任务点某一个粒子的位置向量是 [1.4, 2.8, 3.2, 1.1, 2.0]那么任务点 T1 分给无人机1任务点 T2 分给无人机22.8取整为2任务点 T3 分给无人机33.2取整T4分给无人机1T5分给无人机2。这种编码方式最大的好处是PSO的速度和位置更新公式可以直接套用不需要额外的映射操作一个取整符号就完成了从连续解空间到离散分配方案的转换理解起来也特别直观非常适合用来做毕业设计讲解。但这种编码也带来一个问题——每个任务点都“必然”被分配给某架无人机天然满足“任务分配完整性”约束但无法直接保证“每架无人机的负载均衡”。这其实不算什么大问题因为我们可以在适应度函数里加上负载均衡项来引导搜索。还有一个更隐蔽的问题是如果某个维度取整后总是指向同一架无人机粒子在该维度上的搜索效率会下降这个后续我会说一个优化技巧。3.2 速度和位置更新公式的实现细节粒子群算法的核心迭代公式大家都熟悉这里我直接给出源码中对应的Python代码# 速度更新 new_velocity w * velocity \ c1 * random.random() * (pbest_position - current_position) \ c2 * random.random() * (gbest_position - current_position) # 位置更新 new_position current_position new_velocity # 边界处理限制速度范围 new_velocity np.clip(new_velocity, -v_max, v_max) # 位置范围处理 new_position np.clip(new_position, 1, num_drones 1)这里有三个关键参数惯性权重 w、个体学习因子 c1、社会学习因子 c2。我在这套源码里设置的是 w 从 0.9 线性衰减到 0.4这样迭代初期粒子的全局搜索能力强不容易被某个局部最优过早吸引迭代后期w变小群体收敛到精细搜索阶段更容易逼近全局最优。c1 和 c2 都设为 1.5 左右当然你也可以尝试 c1 大一点加强个体探索或 c2 大一点加快收敛但有早熟风险。速度边界 v_max 是一个非常容易被忽略的参数。它直接决定了粒子每一步在解空间里能“跳”多远。如果 v_max 设置过大粒子会像无头苍蝇一样在搜索空间里乱飞算法很难收敛设置过小粒子又容易被困在局部最优区。按照经验位置向量取值范围是 [1, n1)那么 v_max 设为这个区间宽度的 0.5 ~ 1倍比较合理比如 n8 时 v_max 取 3~5 即可。注意这里的边界处理用的是“截断”把超过速度上限的值拉回上限而不是“反射”或“随机重置”。截断实现最简单而且在这个连续取整的编码方式下效果已经够用。如果你想进一步提升性能可以尝试“边界反弹”策略把 v 改成 -v 的一部分有利于粒子在边界附近多探索。4. 源码工程的完整拆解从配置到可视化逐模块精读4.1 工程目录结构与模块职责先贴一下整套源码的文件组织结构我特意按“解耦”的原则把不同功能拆到了不同文件里方便你在做毕设写论文时引用和修改pso_uav_allocation/ ├── main.py # 主入口参数装配、调用算法、输出结果 ├── config.py # 全局配置参数 ├── env_model.py # 问题建模环境、任务点、无人机、距离矩阵、适应度函数 ├── pso_optimizer.py # PSO核心算法粒子类、种群迭代、速度/位置更新 ├── visualization.py # 结果可视化分配方案图、收敛曲线图 └── README.md # 使用说明与依赖安装main.py 是整个工程的入口做的事情比较纯粹读取config.py中的配置生成随机的任务点坐标也可以改成从文本读取外部数据创建环境模型实例然后调用pso_optimizer里的PSO求解器迭代优化最后调用visualization把结果画出来。这种“入口-配置-环境-算法-绘图”的分层结构非常像工业项目中的标准开发模式很多老师看到这种代码组织方式会认为你具备工程思维。config.py 里放的是所有可以调的参数无人机数量 NUM_DRONES、任务点数量 NUM_TASKS、种群大小 POP_SIZE、最大迭代次数 MAX_ITER、惯性权重范围 w_start/w_end学习因子 c1/c2速度钳制 v_max惩罚系数 penalty_coeff随机种子 RANDOM_SEED 等等。每次跑实验之前只需要改这一个文件不需要动算法逻辑这是我在实际写代码时最舒服的迭代方式。4.2 环境模型距离矩阵、路径构建与完整适应度计算env_model.py 是问题建模的核心我们自己把它称为“环境模型”受强化学习术语影响但本质就是个计算器。它负责做的事情有第一生成任务点和无人机出发点的坐标。默认在100x100的平面内随机生成坐标点无人机1到n的出发点可以设成同一个“基地”坐标也可以设为不同位置。如果是多基地场景就直接随机生成n个出发点。为了实验结果可复现我特别在config里提供了固定随机种子的选项。这一点对毕设尤其重要因为如果每次跑出来的图不一样论文里就没法贴固定的结果图了。第二预计算距离矩阵。所有无人机和任务点、任务点和任务点之间的欧氏距离在环境初始化时一次性算好存成二维矩阵。这样适应度函数在计算路径长度时只需要查表累加不需要反复调用开根号函数在迭代几百上千次时能省下不少时间。第三计算完整适应度。前面说过单个粒子的位置向量要先取整得到分配方案然后逐架无人机构建路径并算总长。这里最关键的一个小技巧是在计算每一架无人机负责的任务点序列时使用最近邻贪心算法做一次最短路径排序。为什么这样做因为我之前用“按任务编号顺序排列”的方式计算过航程结果相当离谱——比如无人机要执行任务点13、5、8如果按顺序走到13再折返到5路径长度比按5→8→13走多出好几倍。而PSO本身并不善于优化每架无人机内部的路径顺序问题它主要解决的是“哪些任务点分给谁”。所以把内部路径顺序通过贪心策略固定下来再让PSO去优化分配组合两者解耦之后效果会显著提升。def compute_fitness(self, allocation_vector): # allocation_vector: 长度为m的实数向量取整后得到每个任务的无人机编号 drone_tasks {i: [] for i in range(self.num_drones)} for task_idx, drone_idx in enumerate(allocation_vector): drone_idx int(drone_idx) - 1 if drone_idx self.num_drones: drone_tasks[drone_idx].append(task_idx) total_distance 0.0 violation 0.0 for drone_idx, task_list in drone_tasks.items(): if len(task_list) 0: continue # 贪心最近邻对任务点排序 sorted_tasks self.greedy_order(self.drone_start[drone_idx], task_list) # 计算路径长度 current_pos self.drone_start[drone_idx] for t in sorted_tasks: total_distance self.distance_matrix[current_pos][t] current_pos t total_distance self.distance_matrix[current_pos][self.drone_start[drone_idx]] # 超容量/超续航约束检查示例 if len(task_list) self.max_capacity: violation (len(task_list) - self.max_capacity) * 10.0 return total_distance self.penalty_coeff * violation这个适应度函数写得非常紧凑本身也方便你在答辩时逐行讲清楚。顺带一提如果你想实现“同时最小化完工时间”或者“负载均衡”只需要在这个函数基础上加项就行——每架无人机的路径总时长算出来后求max就是完工时间求方差就是负载均衡度。4.3 PSO核心类的完整实现解读pso_optimizer.py 里定义了Particle类和PSO类。Particle类的主要属性是 position、velocity、fitness、pbest_position、pbest_fitness。每个粒子初始化时position 是在 [1, n1) 之间随机采样得到的 m 维向量velocity 初始化为较小的高斯随机数比如均值为0、标准差1然后立即计算一次初始适应度记录为个体最优。PSO类的核心方法是 optimize()里面就是标准的迭代循环for iteration in range(max_iter): w w_start - (w_start - w_end) * iteration / max_iter for particle in self.particles: # 速度更新、位置更新、边界处理 ... # 计算新适应度 particle.calculate_fitness() # 更新个体最优 if particle.fitness particle.pbest_fitness: particle.pbest_position particle.position.copy() particle.pbest_fitness particle.fitness # 更新全局最优 if particle.fitness self.gbest_fitness: self.gbest_position particle.position.copy() self.gbest_fitness particle.fitness # 记录本次迭代最优适应度用于绘制收敛曲线 self.history.append(self.gbest_fitness)这里有一个细节很值得注意每次迭代时w 是实时线性衰减的而不是一个固定常数。我调试的时候试过固定 w0.6 不衰减结果在多任务点场景下明显更容易陷入局部最优最终总航程比衰减策略高出约12%左右。所以如果你拿到代码后想改参数建议优先调整 w 的衰减范围和速度而不是直接改 c1、c2。4.4 初始化种群时加入一个“小聪明”这也是我在调试过程中加进去的优化种群初始化时除了完全随机生成的粒子可以额外放几个“先验方案”粒子进去。例如把“所有任务按顺序轮流均分给每架无人机”和“所有任务全部交给距离最近的那架无人机”这两种简单启发式方案直接作为初始粒子的绑定到速度初始化里。这样做的好处是即便随机粒子开局探索方向很差PSO从第一轮迭代就已经有一个相对不错的 pbest 和 gbest 做引导收敛速度和最终解质量都能提升。我一直觉得这种做法特别适合课程设计场景——你不用在答辩时说“我的算法初值怎么选的”含糊其辞可以理直气壮地说“我采用启发式初始化 随机扰动目的就是给种群一个高质量起点同时保留群体的多样性”。这一句话就能体现你对算法细节有真正理解。5. 仿真实验与结果分析如何判断分配方案“好”在哪里5.1 典型实验场景设置源码默认的场景是 8 架无人机、30 个任务点所有无人机统一从 (50, 50) 这个“基地”出发任务点在 100x100 的二维平面内随机分布。种群规模设为 60迭代次数 250。这个规模的设定是有讲究的任务点是无人机的近4倍分配难度适中250次迭代在普通办公电脑上跑一次只需几秒钟调试体验非常舒服。运行 main.py 之后程序会输出两个核心结果一是全局最优方案的总航程fitness值二是迭代收敛曲线。我把一组典型实验结果列在这里方便你对自己的运行结果有个心理预期指标数值无人机数量8任务点数量30随机初始化总航程平均2850.6粒子群优化后期总航程1173.4相对优化率约58.9%达到最终结果所需迭代次数约180代左右可以看到单纯靠随机分配和PSO优化后的分配总航程相差近三倍这说明搜索算法对这个问题的提升幅度相当可观。收敛曲线在前50代下降非常快从2600一路降到1300左右然后进入较缓的下降阶段大概到180代以后曲线基本水平。这个趋势非常典型——PSO在前期依靠群体信息快速找到好区域后期主要做局部精细优化。5.2 任务分配方案的可视化判读visualization.py 模块会输出两张图一张是任务分配结果图另一张是收敛曲线图。分配结果图里不同无人机负责的任务点用不同颜色标记同色点用线段连接成该无人机的路径每个无人机出发点用黑色五角星标出。拿到结果图后怎么判断方案是不是合理的第一看有没有无人机被分配了横跨地图两个角落的任务点——如果有说明粒子的分配方案里可能出现了负载不均或路由不合理的迹象。第二看每架无人机的路径是否平滑、是否存在大量交叉段——路径交叉通常存在优化的空间。第三看有没有无人机被分配了数量明显多于其他的任务——这可能说明惩罚系数太小负载均衡项没有起到作用。我在测试中就遇到过某架无人机被分配了10个任务其他无人机只有两三个的情况检查后发现是惩罚系数设得太低导致的调高后立刻恢复正常分布。收敛曲线图同样值得仔细分析。它横轴是迭代次数、纵轴是全局最优适应度值。如果你画的曲线是一条直线没有下降先检查是不是距离矩阵算错了如果曲线是“阶梯状”下降的——就是很长时间不动然后突然跳一下——通常说明粒子群在搜索空间的某个区域停滞了可能要靠调整 v_max 或加入变异来解决。5.3 多组对比实验权重参数和惩罚系数的敏感性为了让毕设论文更有内容我强烈建议你做一组对照组实验把不同参数下的实验数据整理成表格。例如固定其他参数不变把惯性权重衰减终点 w_end 分别设成 0.2、0.4、0.6 跑一遍记录最终总航程和收敛代数。我自己做的结果是w_end0.4 时效果最优w_end0.2 时收敛稍快但容易早熟w_end0.6 时收敛变慢且最终结果恶化约10%。同样地对惩罚系数也做一组消融实验。当 penalty_coeff 从500降到10时分配方案中会出现大量任务点失衡的现象总航程虽然数值下降了因为很多约束没被惩罚但实际方案完全不可用当 penalty_coeff 高达10000时算法会把大量精力集中在满足约束上搜索效率下降最终总航程也比正常值高。这些对比数据非常能说明问题放在论文实验部分会非常加分。6. 常见问题排查与避坑指南这些坑我替你踩过了6.1 迭代不收敛怎么办早熟陷阱与速度边界很多人第一次跑代码会发现一个让人头大的现象适应度曲线下降十几代之后就直接水平了不管怎么迭代都不动而且最终分配方案明显很差。这种情况十有八九是早熟收敛。早熟的本质是群体中的粒子在迭代初期就被某个局部最优“吸引”住了大家的位置和速度趋于一致丧失了继续探索多样性的能力。针对早熟我通常按顺序检查三件事首先看 v_max 是不是太大了把速度上限降到区间宽度的0.3~0.5倍试试其次看种群大小 POP_SIZE 是不是太小了30个任务点如果种群只有20搜索能力确实会不足建议至少保持任务点数量的2倍以上最后如果前两项调整效果不明显就在每次迭代时对gbest做“扰动”——给全局最优位置加上一个很小的随机噪声强迫粒子跳出当前的停滞区域。这里我选择的是第二种思路因为实现起来只有两行代码但效果立竿见影。6.2 中文图表乱码和随机种子问题matplotlib 默认字体对中文支持很差如果你的结果图上要标“无人机1”、“任务点”这些中文直接写 text 后会变成方块。源码中我在 visualization.py 里加了如下设置import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei, Microsoft YaHei, WenQuanYi Micro Hei] plt.rcParams[axes.unicode_minus] False如果你在 Linux 服务器上跑常见于实验室服务器上面几个中文字体可能都没装那就需要自己安装字体包或者干脆把图表里的中文改成英文标签。从做毕设的角度我建议图表直接统一用英文标签因为在论文里插图的说明文字是在图注里写的图片本身用英文反而更正式、更不容易出错。另外如果你发现两次跑出来的结果完全一样或完全不一样都先确认一下是否设置了 RANDOM_SEED。设置了固定种子同一套参数跑出来的结果理论上应该完全一致如果没有设置每次结果有细微差异是正常的不代表代码有bug。补充一句numpy 和 Python 内置的 random 都要同时设种子否则可能因为两套随机体系不同步导致意外行为。6.3 从8个任务点到80个任务点规模扩展时的性能陷阱如果你的课程设计要求做更大规模的场景比如50架无人机、200个任务点这套PSO基础版可能会明显变慢甚至效果变差。主要瓶颈在于每次迭代要调用 n 次适应度计算而每个适应度计算里又包含路径构建和贪心排序复杂度是 O(n * m^2) 量级的。我自己测试过30个任务点跑250代没问题200个任务点跑500代在普通电脑上可能要等几分钟这个时间虽然能忍受但迭代中间没有任何输出会让人觉得“卡死了”。解决方案大致有几种一是引入并行计算numpy的向量化在PSO里可以作为突破口尝试把所有粒子一次性矩阵化评估适应度二是把贪心最近邻排序换成一次动态规划预处理得到的固定查找表对特定问题有效三是降低有效迭代次数早停——比如连续20代gbest没有变化就提前终止。代码里目前保留了“提前终止”这个逻辑开关默认关闭你可以打开后对比一下效果。6.4 把“航程最优”扩展到“时间最优/能耗最优”最后说一个我认为特别有用的扩展方向把目标函数从“总航程最短”扩展到“能耗最低”或“时间最优”。现实中无人机的能耗不仅仅是航程的函数还包括转弯次数、载荷重量、悬停时间等。比如在城市巡检场景中无人机每到一个任务点还要执行“图像采集”动作消耗固定时间的悬停能耗那么总完成时间就可以建模为飞行总距离/速度 访问任务数*悬停时间。改造源码时只需要调整 env_model.py 的 compute_fitness 函数加入时间项即可整个PSO迭代逻辑一行都不用改。我见过不少同学的毕设就是在航程最优这个版本基础上加了一个“任务优先级权重”的参数高优先级任务点必须在低优先级之前完成本质上就是给目标函数加一个带权重的任务排序惩罚项。这种改动既有理论深度又不会把工程复杂度推高到无法完成的程度非常适合用来展示自己对问题的理解。做这个项目最大的收获是粒子群算法看起来简单真正跑起来、调起来、把结果解释清楚每一步都有值得深入思考的细节。希望这份源码拆解能帮你少走几个弯路把更多精力放在理解问题和展示成果上而不是被“环境装不上”“中文乱码”“曲线不收敛”这类杂事消磨掉热情。如果你在复现时遇到和上面不太一样的问题不妨按着“建模—编码—参数—可视化”这条链路逐层排查大概率能在十分钟内定位到根因。本文还有配套的精品资源点击获取
返回列表