简介基于微软AirSim的无人机编队仿真工程包面向无人机算法学习者、机器人开发者以及需要快速验证编队控制策略的研究者。包内聚焦多智能体协同、路径规划、避障和编队控制提供Python算法脚本、实验视频、仿真进程说明及项目配置等内容既有单积分器/双积分器模型下的leader-follower方案也包含3D相对状态偏差跟踪与MTP/MTF等编队控制实现便于结合实际飞行仿真理解AirSim环境配置与无人机控制链路。压缩包共32个文件约216MB以py源码、mp4实验录屏、xml工程文件和pptx说明为主并附带README与项目标识文件结构清晰。已有284人学习下载适合正在开展无人机集群仿真或相关课程设计的开发者参考借助源码、演示视频和进度记录可快速复现、改造并扩展自己的编队控制实验。1. AirSim 编队仿真不是建模仿真这包代码的定位和能解决的问题先说结论这份「利用 AirSim 做无人机编队仿真」不是教你如何给无人机建气动模型也不是带你熟悉 Unreal Engine 场景搭建的教程。它是一套已经能跑的编队控制 Python 代码把常见的多智能体编队算法拆成了可以直接在 AirSim 里跑起来的脚本——你拿到手先跑通再逐步改参数最后替换成自己的控制逻辑。适合谁想快速看到三架以上无人机在仿真环境里维持队形飞行的学生、做多机控制课题的研究生、以及想评估「领导-跟随」编队策略在实际飞行前效果的从业者。这套包最大的价值在于把编队控制理论和仿真器之间的桥搭好了。下载包里没有大而全的框架而是十几个相互解耦的脚本每个脚本负责一个具体的控制场景这正是我拆完以后觉得最顺手的地方。2. 代码包全貌按「动力学模型 任务类型」拆解十几个 Python 脚本2.1 先看文件命名你能从脚本名里读出编队控制的设计意图打开压缩包第一眼看到的是十几个 Python 文件。文件名不是随便起的它们遵循一个固定规则「动力学模型 任务类型 维度 误差形式」。比如single_integrator__one_leader_2D_XZ.py拆开看就是single_integrator一阶积分器模型、one_leader单领导跟随、2D_XZ在 X-Z 平面做编队。再比如double_integrator(4.2)__one_leader_3D_relativeStateDeviation.py表示用的是二阶积分器模型即双积分器三维空间误差形式是相对状态偏差relative state deviation。这个命名习惯强烈建议保留。后面你自己加脚本时沿用这套命名几天之后再看文件列表一眼就知道每个脚本在干什么。编队控制里最常见的模型就两种一阶积分器和二阶积分器。一阶积分器把无人机当质点位置的变化率直接等于速度指令二阶积分器把加速度当控制量位置变化率等于速度、速度变化率等于加速度。两者在代码里的区别非常明显前者self.u k * error直接给速度后者self.u kp * error kd * d_error给的是加速度。这套包把两种模型分开写调试时互不干扰这点做得比很多混在一起的项目要好。2.2 按功能把脚本分成四组对应不同调试阶段我拆包后习惯先把文件分组再决定调试顺序。这个包可以分成四组基础指令组、单智能体控制组、多智能体编队组、辅助工具组。下面是文件清单及各自角色文件分组作用main.py/multi_agent_drone.py入口负责初始化 AirSim 客户端、注册无人机、设置控制模式speed_control.py辅助工具封装速度控制指令编队算法输出速度后统一走这个接口single_integrator__one_leader_1D.py单智能体一维编队演示适合验证指令通路是否打通single_integrator__one_leader_2D_XZ.py单智能体二维 XZ 平面跟随看高度和水平方向的配合single_integrator__one_leader_3D_relativeStateDeviation.py单智能体三维跟随误差用相对状态偏差表示double_integrator(4.2)__one_leader_3D_relativeStateDeviation.py单智能体双积分器三维跟随比单积分器多速度项更接近真实动力学single_integrator(3.11)_tracking_MTP_relativeStateDeviation.py编队MTP 任务朝目标队形点运动single_integrator_tracking_MTA_relativeStateDeviation_3D.py编队MTA 任务跟踪指定智能体single_integrator_tracking_MTF_relativeStateDeviation_3D.py编队MTF 任务整个队形迁移double_integrator(5.14)_tracking_MTP_relativeStateDeviation.py编队双积分器版本的 MTP 编队square.py辅助工具队形轨迹示例方形轨迹拆成航点multi_agent_speed.py辅助工具多智能体速度分配逻辑仿真记录 / 实验视频 / 仿真进程记录.pptx资料记录运行效果与算法演进过程README.md文档项目说明建议第一个打开分组以后调试顺序就清晰了先跑1D确认 AirSim 连接和电机指令正常再跑2D_XZ确认二维平面控制没问题最后进3D和编队脚本。不要一上来直接跑 3D 编队否则报错时你分不清是控制算法的问题还是 AirSim 连接的问题。2.3 README 和仿真记录这些非代码文件的用法压缩包里除了.py还有 PPTX、实验视频和仿真记录。很多人拿到下载包只看代码把视频和 PPTX 当摆设实际上这些是最省时间的资料。仿真进程记录.pptx记录的是作者每次更新的前后对比哪个版本从 2D 扩展到了 3D、哪个版本换上了双积分器模型、误差曲线变化趋势。先看这几个文件能直接避开作者踩过的大坑。视频则是运行时录屏看视频可以确认「编队飞行」到底达成了一个什么效果——尤其在你还没配好 AirSim 环境之前先看视频再跑代码心里有个预期避免跑出来以为是 bug 其实本来就是那个效果。3. 把 single_integrator 脚本跑起来AirSim 连接与 2D 编队的第一个示例3.1 运行前环境准备AirSim 装好、Python 解释器选对AirSim 本身是微软开源的高精度仿真器场景基于 Unreal Engine 构建。它和 PX4 这种飞控固件仿真器的区别在于AirSim 是仿真环境 API 控制接口你可以不碰飞控直接用 Python/C 给无人机下发速度、位置、姿态指令。这套包走的就是纯 Python API 路线所以不需要装 PX4 工具链但有两点必须提前确认AirSim 本体要装好并能启动默认的仿真环境比如 Blocks 场景能手动起飞。这一步装不好后续一切免谈。Python 侧需要airsim包。常见做法是把 AirSim 仓库里的PythonClient目录拿出来加到你的项目路径里或者直接用pip install airsim安装。检查连接是否正常用一段最简代码import airsim client airsim.MultirotorClient() client.confirmConnection() print(连接成功当前仿真时间, client.simGetTime()) # 查看当前无人机位置 pose client.simGetVehiclePose() print(位置, pose.position.x_val, pose.position.y_val, pose.position.z_val)MultirotorClient是 AirSim 的旋翼机客户端对象confirmConnection()会阻塞直到与仿真器握手成功如果 AirSim 没启动或者版本不匹配这一步会一直卡住simGetVehiclePose()返回的是 NED 坐标系下的位置注意 Z 轴向下为正这直接影响你后面写编队目标点。第一次跑这段代码时如果confirmConnection()卡住超过 30 秒大概率是 AirSim 的 Unreal 环境没启动而不是代码问题。3.2 跑通single_integrator__one_leader_2D_XZ.py环境通了以后直接跑 2D XZ 平面的跟随脚本。这个脚本的核心逻辑是定义一架领航机和一架跟随机领航机按固定轨迹或航点飞跟随机根据相对位置偏差计算速度指令。代码里有几个关键参数需要注意一般我会这样调整# 编队目标相对位置跟随机应该处在领航机的哪个方位 FORMATION_OFFSET_X 5.0 # 水平方向偏差米正数表示领航机前方 FORMATION_OFFSET_Z -2.0 # 高度偏差米NED 坐标下正数向下 # 控制器增益增益太大容易振荡太小收敛慢 K_POS 0.8 # 位置偏差比例增益 K_VEL 0.5 # 可选双积分器模型下速度偏差增益FORMATION_OFFSET_X和FORMATION_OFFSET_Z就是编队「相对状态偏差」的目标值——跟随机不是飞到领航机的位置而是飞到「领航机位置 这个偏移量」的位置。K_POS是最重要的参数单积分器模型下速度指令v K_POS * errorK_POS太大跟随机会来回震荡太小跟随机会拖得很远才追上。我的调试习惯是先从 0.5 开始看误差收敛趋势再每次加 0.1 往上调直到出现震荡再回退 0.1。跑起来以后打开 AirSim 场景视角你看到的应该是两架无人机一架沿着预设轨迹飞另一架始终保持在它侧后方或侧前方一个固定偏移位置。XZ 平面的含义是水平方向和高度方向构成的控制平面Y 轴方向不控制。这在真实场景里相当于两架无人机在一个垂直剖面内做编队很适合用来验证算法逻辑。3.3 脚本内部的控制循环一阶积分器是如何实现的如果你打开了脚本源码会发现核心控制循环很紧凑while True: # 读取领航机的当前位置实际项目中从 AirSim 获取 leader_pos get_leader_position(client) # 计算跟随机的目标位置 领航机位置 编队偏移 target_pos leader_pos FORMATION_OFFSET # 获取跟随机当前实际位置 follower_pos get_follower_position(client) # 计算相对状态偏差 error target_pos - follower_pos # 一阶积分器速度指令直接正比于位置偏差 velocity_cmd K_POS * error # 通过 AirSim 下发速度控制指令 client.moveByVelocityAsync( velocity_cmd.x_val, velocity_cmd.y_val, velocity_cmd.z_val, duration0.1 ).join() time.sleep(0.1) # 控制周期 0.1 秒这个循环值得细看target_pos leader_pos FORMATION_OFFSET那一行是编队控制的灵魂——领航机位置实时变化跟随机的目标点也跟着变化所以这是动态目标跟踪而不是静态航点飞行。moveByVelocityAsync的duration0.1表示这条速度指令只生效 0.1 秒所以循环里time.sleep(0.1)必须和它保持一致否则指令会断断续续。如果你想让编队更平滑可以缩短周期到 0.05 秒但 CPU 占用会上升AirSim 的渲染帧率也可能被拉低。4. 从 1D 到 3DMTP、MTA、MTF 任务切换与模型选择的完整路径4.1 MTP、MTA、MTF 三种编队任务到底差在哪这套包里出现了MTP、MTA、MTF三个缩写对应三种不同的编队任务描述我在实际跑的时候把它们的差异总结如下任务含义典型场景代码区别MTPMove to Point编队中的智能体向指定队形点运动从散乱状态聚拢成编队目标点是固定的队形坐标MTAMove to Agent智能体跟踪某个指定智能体领导-跟随编队目标点来自另一架无人机实时位置MTFMove to Formation整个队形在空间中迁移编队整体平移或变换队形目标点由队形参考点加上各机偏移举例来说single_integrator_tracking_MTA_relativeStateDeviation_3D.py里跟随机的目标位置每一帧都取领导机的实时位置而single_integrator(3.11)_tracking_MTP_relativeStateDeviation.py里目标点可能是预定义的一组坐标跟随机只要飞到那一点就算完成任务。调试时要注意MTP 类型跑起来直观、容易验证但看不出编队保持能力MTA 才是真正考验跟随性能的任务。如果你在验证编队控制算法建议先跑 MTP 确认控制器参数收敛再切到 MTA 看动态跟踪效果。4.2 从 single integrator 换成 double integrator 要改哪些东西很多初学者直接跑double_integrator(5.14)_tracking_MTP_relativeStateDeviation.py发现跟单积分器脚本长得差不多就以为只是把系数改大了。实际上两者在控制律上的区别是结构性的single integrator状态是位置控制量是速度控制律v K_pos * ee 是位置偏差。double integrator状态是位置 速度控制量是加速度控制律至少是 PD 形式a Kp * e Kd * e_dot其中 e_dot 是速度偏差。所以当你把一段单积分器代码改成双积分器至少要补三件事读取智能体的当前速度AirSim 里用client.getMultirotorState().kinematics_estimated.linear_velocity、计算目标速度与当前速度的偏差、把加速度指令通过速度增量或直接加速度接口下发给无人机。这套包里的双积分器脚本已经把这三件事做好了你要做的是调Kp和Kd的比例Kd太小时飞机会「冲过头」Kd太大时响应慢、编队显得很钝。4.3 1D → 2D → 3D 扩展时最容易忽略的维度细节压缩包里有 1D、2D_XZ、3D 三个维度的版本它们的核心逻辑逐级递进。我跑下来的经验是维度升级时最常犯的错在坐标系约定1D只有 X 轴方向的控制适合测试指令通路是否正常。2D_XZX Z 两个方向Z 在 AirSim NED 坐标系里是向下为正所以你写的高度目标如果是正数飞机会一直往下扎。正确写法是FORMATION_OFFSET_Z -3.0表示领航机上方 3 米。3DX Y Z 全控制此时要注意 AirSim 的 Y 轴对应右手坐标系中的侧向编队队形若用角度描述转热门问题是符号问题。我自己踩过最典型的一回把 2D 代码扩展成 3D 时Y 方向忘了初始化编队偏移量结果跟随机一直在领航机正下方看起来像没控制住其实是偏移量全为 0。所以 3D 调试时先给每个方向设一个明显的偏移比如 X5、Y3、Z-2确认队形成形后再调回正式目标值这一步能省大量排查时间。4.4 速度控制模块speed_control.py在多机编队里的衔接方式多机编队脚本最终都要调用速度控制模块下发指令。speed_control.py实际上就是对 AirSim 的moveByVelocityAsync做了一层封装把Vector3r速度向量拆分到三个坐标轴并统一处理了duration参数。多机时关键是区分 vehicle_nameAirSim 多机仿真里每架无人机有一个名字默认是、UAV1、UAV2等封装好的速度控制函数会多一个vehicle_name参数# speed_control.py 的典型封装 def send_velocity(client, vehicle_name, vx, vy, vz, duration0.1): 下发速度指令 vehicle_name: 多机仿真时用于指定哪一架无人机 vx, vy, vz: 三个方向的速度NED client.moveByVelocityAsync(vx, vy, vz, duration, vehicle_namevehicle_name).join()没有这个vehicle_name参数多机脚本里所有无人机收到的是同一条速度指令编队就变成「齐步走」而不是「跟随」。我在自己项目里用这个封装时习惯把duration改成和控制循环周期相同避免指令间隙无人机「自由滑翔」导致偏移。5. 避坑记录五个在 AirSim 编队里真实踩过的坑5.1 AirSim 版本不匹配confirmConnection()卡死无报错现象代码运行到confirmConnection()就一直停着不报错也不退出等三五分钟还是没反应。原因AirSim 的 Python API 包和仿真器本体版本对不上握手协议不兼容。最常见的是 PythonClient 目录是从旧版本仓库拷贝的而 Unreal 环境是新版本编译的。解决统一版本。先看 Unreal 环境里 AirSim 插件的版本号再去对应版本的 AirSim 仓库里取 PythonClient或者卸载后重跑pip install airsim --upgrade。如果还卡看 AirSim 终端窗口有没有打印Client connected之类的日志没有就说明握手根本没建立。5.2 多机仿真时enableApiControl只对第一架生效现象脚本里注册了三架无人机但只有第一架能响应指令第二第三架悬停原地。原因多机控制时每一架都要单独enableApiControl和armDisarm很多脚本只对默认这架做了使能。解决三架机就写三个初始化块逐一指定vehicle_namefor vname in [, UAV1, UAV2]: client.enableApiControl(True, vname) client.armDisarm(True, vname)5.3 2D_XZ 脚本里高度一直往下掉控制不住现象跟随机的位置在 X 方向正常跟随但 Z 方向不断升高或降低最后撞到场景边界。原因AirSim 默认 NED 坐标系 Z 轴向下为正把 Z 目标值写成正数时算法以为「向下是目标」其实是「向上飞」正反馈导致发散。解决所有高度目标统一用负数表示向上FORMATION_OFFSET_Z -3.0。落地后想回到地面高度 0就目标设 0 附近不要设正数。这个符号习惯要贯穿整个脚本否则 2D 能跑 3D 必翻车。5.4 控制周期不一致导致编队发散抖动现象两架无人机飞行轨迹像「画心电图」一会儿贴近一会儿拉开队形始终稳不住。原因不同智能体的控制循环里time.sleep的周期不一致比如领航机 0.1 秒更新一次、跟随机 0.05 秒更新一次导致误差信号来回跳。解决统一用一个主循环调度所有智能体的控制指令循环内固定dt 0.1秒用time.time()实测间隔计算真实 dt避免误差累积。5.5 PyCharm 里运行时ModuleNotFoundError: No module named airsim现象代码在终端里能跑放到 PyCharm 里就报airsim找不到。原因PyCharm 默认用的是项目虚拟环境的解释器而 AirSim Python 包装在了系统 Python 或其他环境里。解决在 PyCharm 的 Settings → Project → Python Interpreter 里手动添加airsim或者直接把 AirSim 仓库的PythonClient目录整个复制到项目根目录AirSim 本身就是「把包放在项目文件夹里就能 import」的设计路径到位即可。6. 验证编队效果的三个习惯从「看视频」到「看数据曲线」AirSim 编队仿真跑起来以后最大的问题是你以为它成功了但说不清成功在哪。肉眼看着两架飞机前后飞这不能证明编队算法收敛。我后来固定用三个步骤验证每一步都有对应的工具在包里的仿真记录和实验视频里能看到使用痕迹。第一跑对角线航点测试。给领航机设一条包含急转弯的轨迹比如square.py里的方形轨迹看跟随机在转弯处是否会切入内圈或者甩出外圈。方形轨迹是急性子测试如果你的控制器能顶住 90 度转弯才谈得上平滑轨迹。这一步不需要额外写代码跑square.py就行。第二画位置误差曲线。编队算法核心是relativeStateDeviation偏差数据每一帧都存在了只是没画出来。加一个采集和可视化import matplotlib.pyplot as plt # 记录每帧的相对状态偏差X 方向 deviation_x_history [] while running: error target_pos - follower_pos deviation_x_history.append(error.x_val) # ... 原有控制逻辑 # 仿真结束后绘制误差曲线 plt.plot(deviation_x_history, labelX 方向偏差) plt.xlabel(控制周期) plt.ylabel(偏差 (m)) plt.axhline(0, colorgray, linestyle--) plt.legend() plt.show()偏差曲线收敛到 0 附近说明编队保持成功如果曲线等幅振荡K 增益偏大如果曲线逐渐漂移但不确定K 增益偏小或者指令周期太慢。这是最能量化的验证手段比录屏靠谱得多。第三录像与仿真记录对齐。AirSim 自带录制功能录完的视频和仿真记录里的时间戳对不上是正常的——AirSim 录制帧率可能在 60fps而控制算法工作在 10Hz。我在实践里发现一个规律控制频率越低视频里越看不出问题因为两帧之间偏差早被下一帧指令拉回来了。所以验证编队能力时把控制周期故意调慢到 0.2 秒跑一次看还能不能稳住能稳住才是真稳。这套流程走完再来跑包里的实验视频对照你就知道作者当时录到那个效果大概用的是什么参数了。从那以后我拿到任何编队源码包第一件事都是先跑 1D 例子确认指令通路再跑方形轨迹看动态响应最后才上 3D 编队——跳过任何一步都可能把时间浪费在「以为算法错、其实是环境错」的排查上。希望这份拆解对你有用。本文还有配套的精品资源点击获取
