【无人机编队】基于改进三维人工势场法 (APF) 实现 20 架无人机从地面起飞、集结围成正方形环形编队全过程Matlab仿真,包含起飞阶段、编队收敛、机间自主避碰、3D 高清可视化、轨迹渐变发光
2026/8/1 4:33:23 网站建设 项目流程

✅作者简介:热爱科研的Matlab仿真开发者,擅长毕业设计辅导、数学建模、数据处理、算法改进、程序设计科研仿真。

🍎完整代码获取 定制创新 论文复现私信

🍊个人信条:做科研,博学之、审问之、慎思之、明辨之、笃行之,是为:博学慎思,明辨笃行。

1. 相关介绍

一、研究背景与意义

20架规模的无人机集群从地面自主起飞、快速集结并形成稳定正方形环形编队,是当前无人机集群表演、协同巡检、应急照明等场景的核心技术需求。传统人工势场法(APF)凭借逻辑简单、实时性强、分布式计算的天然优势,非常适配多无人机的实时轨迹规划场景,但在三维空间多机密集编队场景下,存在局部最优陷阱、目标不可达、机间震荡避碰等固有缺陷,无法直接支撑20架无人机的全流程自主编队任务。

本研究提出改进型三维人工势场法,针对性优化引力斥力函数与势场调节逻辑,完整覆盖地面垂直起飞、空间编队收敛、机间自主避碰全流程,同时实现3D高清可视化与轨迹渐变发光效果,在无全局集中控制的前提下,实现20架无人机从地面到空中正方形环形编队的零碰撞、高平滑度自主集结,为中小规模无人机集群的全自主编队落地提供高可靠工程方案。

二、传统三维人工势场法的固有缺陷

传统三维人工势场法的核心逻辑是在三维空间中构建引力场与斥力场,引力场引导无人机向目标位置运动,斥力场在障碍物或邻近无人机周围生成排斥力,避免碰撞。但在20架无人机的密集编队场景下,该算法暴露出四大无法忽视的缺陷:
第一,局部最优陷阱问题。当多架无人机的引力合力与斥力合力大小相等、方向相反时,无人机会在空间中陷入停滞,无法向预设编队位置移动,直接导致编队收敛失败;
第二,目标不可达问题。当无人机的预设编队目标点附近存在其他无人机时,目标点周围的斥力会抵消引力,导致无人机始终无法抵达目标位置,只能在目标点附近持续震荡;
第三,起飞阶段势场逻辑不兼容。传统APF的势场函数没有针对地面起飞场景做特殊适配,无人机在地面初始位置会受到邻近无人机的斥力干扰,出现起飞前侧滑、地面碰撞的风险;
第四,密集编队下避碰震荡问题。20架无人机在向环形编队收敛的过程中,多机之间的斥力会出现连锁叠加效应,导致无人机之间出现反复靠近又推开的震荡运动,轨迹平滑度极差,甚至引发机间碰撞。

这些缺陷直接导致传统APF完全无法支撑20架无人机的全流程自主编队任务,必须对势场函数进行针对性的三维场景改进优化。

三、改进三维人工势场法核心原理与全流程实现逻辑

本研究针对20架无人机的正方形环形编队任务,对传统三维人工势场法完成四大核心改进,完整覆盖起飞、收敛、避碰全场景:
第一,优化三维引力函数。引入距离自适应引力增益,在无人机距离目标点较远的起飞阶段,采用大引力增益提升运动速度,在距离目标点小于1m的编队收敛末期,自动降低引力增益,避免无人机冲过目标点,引力函数的三维空间表达式为:

第二,重构三维斥力函数。将无人机与目标点的距离项引入斥力函数,当无人机接近预设编队目标点时,斥力会自动趋近于0,彻底解决目标不可达问题,同时设置分层斥力阈值,当两架无人机间距大于3m时斥力为0,间距在1.5~3m区间时生成弱斥力用于预避碰,间距小于1.5m时生成强斥力用于紧急避碰,从根源上避免多机避碰的连锁震荡。
第三,新增起飞阶段专属势场约束。在无人机距离地面高度小于0.5m的起飞阶段,临时屏蔽水平方向的斥力作用,仅保留竖直向上的恒定起飞引力,保证所有无人机先垂直上升到1m的安全高度,再解除水平方向的势场限制,彻底避免地面阶段的侧滑与碰撞风险。
第四,引入局部最优逃逸机制。当检测到无人机的速度持续2s小于0.05m/s时,判定其陷入局部最优陷阱,自动给无人机叠加一个随机方向的微小扰动力,帮助其快速跳出局部最优区域,继续向目标位置运动。

20架无人机的正方形环形编队全流程分为三个阶段:

  1. 地面垂直起飞阶段‌:20架无人机在地面按5×4的网格分散摆放,间距不小于2m,所有无人机同时解锁起飞,在专属起飞势场的约束下,全部垂直上升到1m的安全高度,全程无水平方向运动,完全避免地面碰撞;

  2. 编队收敛阶段‌:所有无人机解除起飞势场约束,每架无人机分配正方形环形上的唯一预设目标点,正方形环的边长设置为12m,20架无人机均匀分布在环形轨迹上,每架无人机在改进三维APF的引力引导下向目标点运动,同时通过分层斥力与邻近无人机保持安全距离;

  3. 稳定编队维持阶段‌:当所有无人机都抵达预设目标点后,势场自动切换为弱维持模式,仅在无人机偏离目标点超过0.3m时生成微小引力修正位置,同时机间斥力持续生效,保证环形编队在外部风扰下依然维持稳定。

四、3D高清可视化与轨迹渐变发光实现

本研究基于Unity3D引擎搭建全三维高清可视化系统,完整还原20架无人机的运动过程与轨迹效果:为每架无人机的飞行轨迹设置渐变发光材质,轨迹的发光强度随无人机的运动速度动态变化,速度越快轨迹发光亮度越高,无人机抵达编队目标点进入稳态后,轨迹发光逐渐衰减为柔和的常亮状态,直观展示整个编队的运动过程。可视化系统支持自由视角拖拽缩放,可从任意角度观察无人机的起飞、集结、编队全过程,同时实时显示每架无人机的位置、速度、机间间距数据,全程记录所有无人机的飞行轨迹用于后续回放分析。

2. 运行效果展示

3. 部分代码呈现

% create_uav_gif.m - 将已保存的图片转换为GIF动画% 日期: 2025年3月15日function create_uav_gif()% 清空工作区和命令行窗口clc;% 参数设置delay_time = 0.1; % GIF帧之间的延迟时间(秒)compression = 256; % GIF颜色压缩级别(256色)% 选择包含图片的文件夹fprintf('请选择包含图片的文件夹(包含frames_YYYYMMDD_HHMMSS子文件夹的父目录):\n');parent_dir = uigetdir(pwd, '选择包含帧图像的父文件夹');if parent_dir == 0fprintf('未选择文件夹,操作取消。\n');return;end% 查找所有以frames_开头的子文件夹frame_dirs = dir(fullfile(parent_dir, 'frames_*'));if isempty(frame_dirs)fprintf('错误: 在选定文件夹中未找到任何frames_*子文件夹。\n');return;end% 列出找到的文件夹fprintf('找到以下帧文件夹:\n');for i = 1:length(frame_dirs)fprintf('%d) %s\n', i, frame_dirs(i).name);end% 询问用户选择哪个文件夹folder_idx = input('请输入要处理的文件夹编号: ');if isempty(folder_idx) || folder_idx < 1 || folder_idx > length(frame_dirs)fprintf('无效选择,操作取消。\n');return;end% 获取选定的文件夹selected_folder = fullfile(parent_dir, frame_dirs(folder_idx).name);fprintf('已选择: %s\n', selected_folder);% 询问是处理起飞阶段还是编队阶段,或者全部fprintf('\n请选择要处理的阶段:\n');fprintf('1) 仅起飞阶段 (takeoff_*.png)\n');fprintf('2) 仅编队阶段 (formation_*.png)\n');fprintf('3) 全部阶段 (先起飞后编队)\n');stage_option = input('请输入选项编号: ');% 获取输出GIF的文件名default_name = sprintf('uav_animation_%s.gif', datestr(now, 'yyyymmdd_HHMMSS'));fprintf('\n请输入输出GIF的文件名 (直接按Enter使用默认名称: %s): ', default_name);output_name = input('', 's');if isempty(output_name)output_name = default_name;end% 如果用户没有指定.gif扩展名,添加它if ~contains(output_name, '.gif')output_name = [output_name, '.gif'];end% 完整的输出路径output_path = fullfile(parent_dir, output_name);% 获取要处理的图片takeoff_files = sort_files(dir(fullfile(selected_folder, 'takeoff_*.png')));formation_files = sort_files(dir(fullfile(selected_folder, 'formation_*.png')));switch stage_optioncase 1files_to_process = takeoff_files;fprintf('仅处理起飞阶段: 找到 %d 张图片。\n', length(files_to_process));case 2files_to_process = formation_files;fprintf('仅处理编队阶段: 找到 %d 张图片。\n', length(files_to_process));case 3files_to_process = [takeoff_files; formation_files];fprintf('处理全部阶段: 找到 %d 张图片 (%d 起飞 + %d 编队)。\n', ...length(files_to_process), length(takeoff_files), length(formation_files));otherwisefprintf('无效选择,操作取消。\n');return;endif isempty(files_to_process)fprintf('错误: 未找到任何图片文件。\n');return;end% 询问是否自定义延迟时间fprintf('\n是否自定义GIF帧延迟时间? 当前: %.2f秒\n', delay_time);custom_delay = input('输入自定义延迟时间(秒),或按Enter使用默认值: ');if ~isempty(custom_delay) && isnumeric(custom_delay) && custom_delay > 0delay_time = custom_delay;fprintf('已设置延迟时间为: %.2f秒\n', delay_time);end% 创建GIFfprintf('\n开始创建GIF,总共处理 %d 张图片...\n', length(files_to_process));% 进度条初始化progress_bar_width = 50;fprintf('[%s]', repmat(' ', 1, progress_bar_width));fprintf('\b'); % 回到行首repmat('\b', 1, progress_bar_width);for i = 1:length(files_to_process)% 读取图像img_path = fullfile(selected_folder, files_to_process(i).name);img = imread(img_path);% 转换为索引图像[imind, cm] = rgb2ind(img, compression);% 写入GIF - 去掉了Quality参数if i == 1imwrite(imind, cm, output_path, 'gif', 'LoopCount', Inf, 'DelayTime', delay_time);elseimwrite(imind, cm, output_path, 'gif', 'WriteMode', 'append', 'DelayTime', delay_time);end% 更新进度条progress = floor(i/length(files_to_process) * progress_bar_width);fprintf('\b%s', repmat('=', 1, progress));fprintf('\b%s', repmat(' ', 1, progress_bar_width - progress));fprintf('\b'); % 回到行首repmat('\b', 1, progress_bar_width);endfprintf('\n处理完成! GIF已保存到:\n%s\n', output_path);end% 辅助函数:按编号排序文件(确保takeoff_0001.png在takeoff_0010.png之前)function sorted = sort_files(files)% 提取文件名中的编号nums = zeros(length(files), 1);for i = 1:length(files)% 从文件名中提取数字部分name = files(i).name;num_str = regexp(name, '\d+', 'match');if ~isempty(num_str)nums(i) = str2double(num_str{end}); % 使用最后一个数字序列endend% 按编号排序[~, idx] = sort(nums);sorted = files(idx);end

4. 参考文献

🍅更多免费数学建模和仿真教程关注领取

如果觉得内容不错,那就请分享和点个“在看”呗!

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询