跳到主要内容

SwarmCore 集群控制框架(swarm_api)使用说明与教程

适用对象:需要在 SwarmCore 上开发单机/集群算法的用户 前置条件:已完成 SwarmCore 快速入门教程,能跑通单机 demo 对应版本:swarm_api 0.1.0(2026-07-27) 配套文档:swarm_api API 接口说明(快速查阅用,本文是理解与教学用)


目录

  1. 框架是什么、解决什么问题
  2. 架构与设计原理
  3. 坐标系与航向约定
  4. 编译与环境
  5. 快速上手
  6. 阻塞语义、超时与并行模型
  7. 错误处理完整体系
  8. 进阶用法
  9. 安全机制与失效行为
  10. 性能特征与调参建议
  11. 基于框架开发自己的算法包
  12. 从仿真迁移到真机
  13. 当前限制与边界
  14. 常见问题 FAQ

1. 框架是什么、解决什么问题

1.1 没有框架时要面对什么

直接操作 PX4 的 ROS 2 Offboard 接口写控制程序,需要处理一大堆与算法无关的工程细节:

工程细节不处理的后果
fmu/in 话题必须 reliable QoS,fmu/out 是 best_effort指令被静默丢弃,飞机毫无反应且无任何报错
PX4 内部用 NED 坐标系,ROS 习惯用 ENU飞机往错误方向飞、高度正负写反
Offboard 模式要求 ≥2Hz 持续发送设定点断流 0.5 秒飞控触发失联保护,动作中断
切 Offboard 前必须先有一段设定点流模式切换被拒绝,飞机不起飞
切模式/解锁命令可能被丢掉需要循环重发直到状态确认
EKF 高度原点有偏差(尤其室内/仿真)写死绝对高度导致起飞高度不对

一个单机 demo 里这些样板代码近 200 行。要控制 N 架飞机,还得处理多机并行:每架飞机的状态订阅、指令发送、超时监控都要同时进行——复制 N 份单机代码既无法维护,也无法做到"同时起飞"这种基本集群动作。

1.2 框架给出的答案

swarm_api 把以上全部封装成库。你写算法时只看到动作,看不到通信

from swarm_api import Swarm

swarm = Swarm(num_drones=3) # 自动发现在线飞机
swarm.takeoff(1.5) # 三机同时起飞
swarm.goto_all([(0,2,1.5), (2,2,1.5), (4,2,1.5)]) # 各机飞各自目标,同时到达
swarm.land() # 三机同时降落
swarm.shutdown()

控制 1 架、3 架还是 10 架,代码量基本不变——这就是框架存在的意义:让算法开发者把时间花在算法上

1.3 框架不做什么

明确边界,避免误用:

  • 不做底层控制:姿态环、位置环都在 PX4 飞控里,框架只发设定点。这也意味着框架的输出频率(20Hz)不决定飞行品质。
  • 不做轨迹规划/避障goto 是"直线飞过去",路径上有障碍物它不管。规划算法是你(或后续规划包)的事。
  • 不做全局坐标管理:仿真中每架飞机有自己的本地坐标系原点(见第 3 节),跨机全局规划需要真机 UWB 环境或自行做坐标对齐。

2. 架构与设计原理

2.1 分层结构

┌─────────────────────────────────────────────────┐
│ 你的算法 / 策略插件(Strategy 子类) │
├─────────────────────────────────────────────────┤
│ Swarm 多机并行层 │
│ · 自动发现在线飞机(扫描 ROS 话题) │
│ · 每机一个任务线程,动作真正并行 │
│ · 单机异常隔离 + SwarmError 汇总 │
│ · 编队辅助(line/column/triangle/grid) │
├─────────────────────────────────────────────────┤
│ Drone 单机原语层 │
│ · takeoff / goto / set_velocity / hover / land │
│ · 阻塞式语义 + 超时保护 │
│ · 实时状态属性(pos/yaw/armed/offboard) │
├─────────────────────────────────────────────────┤
│ 通信层(Drone 内部) │
│ · QoS 配置、ENU↔NED 转换 │
│ · 后台 20Hz 设定点流线程 │
│ · 切模式/解锁命令自动重发 │
├─────────────────────────────────────────────────┤
│ PX4 飞控(Offboard 接口)——仿真与真机完全同一套 │
└─────────────────────────────────────────────────┘

2.2 线程模型

理解线程模型对写出正确的算法很重要:

每架 Drone 有 2 个常驻后台线程Drone() 构造时启动,shutdown() 时停止):

  1. 订阅线程:ROS executor 线程,持续接收飞控上报的位置与状态,更新 pos / yaw / armed / offboard 属性。你读这些属性永远是最新值,不需要自己 spin。
  2. 设定点流线程:20Hz 循环。takeoff() 之后开始工作,把"当前目标"(位置点或速度)持续发给飞控。这是 Offboard 模式的生命线——你调用 goto 只是改了一个变量,真正维持飞行的是这个线程

Swarm 的并行:调用 swarm.takeoff() 这类多机动作时,Swarm 为每架飞机临时创建一个任务线程,同时执行对应的单机阻塞原语,全部结束后才返回。因此:

  • swarm.takeoff(1.5) 的总耗时 ≈ 最慢那架飞机的起飞耗时,而不是三架相加;
  • 多机动作是"同发同收"的屏障(barrier)语义:全部到位才继续往下走。

线程安全性:框架内部的共享状态(当前目标、模式标志)都是简单标量/列表的原子读写,你的算法线程直接调动作函数是安全的。但不要从多个线程同时调用同一架飞机的 goto——后调用会覆盖先调用的目标点,行为符合直觉但不保证你想要的时序。

2.3 Offboard 状态机与框架动作的关系

PX4 侧的关键状态转换,以及框架如何驱动它:

takeoff() land()
[待机/上锁] ──────────────────────→ [Offboard 飞行中] ──────────→ [自动降落] → [上锁]
↑ │ │ │
│ │ 1. 预发设定点流 1s │ │ goto():改目标点
│ │ 2. 循环发切模式+解锁 │ │ set_velocity():改速度目标
│ │ 命令直到生效 │ │ hover():目标点=当前位置
│ │ │ │
│ └──── 任意环节失败 ──────┴───┴──→ 抛 DroneError

└──── 飞控 failsafe(失联/姿态异常/围栏越界)随时可强制接管,
框架检测到 Offboard 丢失后立即报错(不等超时)

要点:

  • 解锁≠起飞takeoff() 内部完成了"预发流 → 切 Offboard → 解锁 → 爬升到目标高度"四步,对用户是一步。
  • 降落由 PX4 执行land() 先发 NAV_LAND 命令并停止设定点流(不停流飞控会拒绝降落命令),之后飞控自动降落、触地自动上锁,框架等到上锁才返回。
  • failsafe 优先级高于一切。飞控触发失联/姿态/围栏保护时会强制退出 Offboard,此时框架的指令不再被听从——这是设计如此,安全永远优先于任务。

2.4 关键实现机制(使用框架不必读,改框架前必读)

机制实现为什么
设定点流独立线程 20Hz 发布 OffboardControlMode + TrajectorySetpoint,未用字段填 NaNPX4 要求 ≥2Hz 且未用通道必须 NaN,否则行为未定义
坐标转换只有 enu_to_ned / yaw_enu_to_ned 两个函数,只在发布/订阅两处调用转换散在代码各处是坐标系 bug 的万恶之源
高度基准takeoff(alt) 的目标高度 = 起飞前实测高度 + altEKF 高度原点有偏差,写死绝对海拔会出错
命令重发切模式/解锁命令每 0.5s 重发,直到状态话题确认生效单条命令可能丢失,"发了等确认"才是可靠做法
Offboard 丢失检测goto 循环里监控 offboard 属性,丢失超过 2s 立即抛错飞控 failsafe 接管后再等下去毫无意义
降落前断流land() 第一步停止设定点流持续的位置设定点会让 PX4 保持 Offboard 并拒绝 NAV_LAND(实测踩过的坑)
异常隔离Swarm 任务线程捕获单机异常 → 该机 hover → 汇总抛 SwarmError一架飞机出问题不该拖垮整个集群

3. 坐标系与航向约定

3.1 框架层:统一 ENU

框架所有输入输出(位置、速度、航向)都是 ENU(REP-103,ROS 标准):

北 y

│ x = 东(East)
│ y = 北(North)
└──────→ 东 x z = 上(Up),海拔越高值越大
  • 位置 (x, y, z):单位米。z 向上为正,起飞 1.5m 就是 z=1.5
  • 速度 (vx, vy, vz):单位 m/s。vy=0.5 表示以 0.5 m/s 向北飞。
  • 航向 yaw:单位弧度,0 = 朝东,逆时针为正。朝北 = π/2,朝西 = π,朝南 = -π/2。
  • 航向角速度 yaw_rate:rad/s,逆时针为正。

3.2 底层:PX4 是 NED

PX4 飞控内部使用 NED(x=北,y=东,z=),航向 0=北、顺时针为正。框架只在 drone.py 顶部的两个函数里做转换,一处转换、全局生效:

def enu_to_ned(x, y, z): return y, x, -z # 换轴即可
def yaw_enu_to_ned(yaw): return math.pi/2 - yaw # 两个约定相差 90° 且方向相反

如果你需要直接读 PX4 原始话题(绕过框架),务必记得这个差异。

3.3 本地坐标系 vs 全局坐标系(重要)

仿真环境:每架 PX4 实例有自己的本地坐标系,原点在各自出生点,互不相同。所以 swarm.goto_all((0, 2, 1.5)) 让三架飞机各自向"自己的北"飞 2m,互不冲突——demo 正是利用这一点。

真机 UWB 环境:所有飞机接入同一套 UWB 定位后,本地坐标系对齐到统一的全局坐标系(uwb_map)。此时 goto_all 传同一个点意味着真的飞向同一个物理点——会撞机!编排航线时各机目标点必须分开。

写算法时建议养成习惯:集群动作的目标点永远按机分别给出goto_all([(x1,y1,z1), (x2,y2,z2), ...])),这样代码在两种环境下行为一致、都安全。

4. 编译与环境

框架位于 swarm_ws/src/swarm_api/,一键安装脚本 install.sh 已会自动编译。手动编译:

cd ~/0c00_ws/swarm_ws
source /opt/ros/humble/setup.bash
colcon build --packages-select swarm_api

每次使用前加载环境(每个新终端都要):

source /opt/ros/humble/setup.bash
source ~/0c00_ws/swarm_ws/install/setup.bash

依赖只有 rclpypx4_msgs,纯 Python 实现,无 C++ 编译、无第三方 pip 包。

5. 快速上手

5.1 单机(Drone)

# 终端 1:单机仿真
~/0c00_ws/swarm_ws/src/bringup/scripts/start_swarm_sim.sh 1 1

# 终端 2
source /opt/ros/humble/setup.bash && source ~/0c00_ws/swarm_ws/install/setup.bash
python3 ~/0c00_ws/swarm_ws/src/bringup/scripts/demo_single_drone.py

demo_single_drone.py 核心逻辑(起飞 → 顺时针画 2m 正方形 → 回原点 → 降落):

from swarm_api import Drone

drone = Drone("uav_1") # 连接一架飞机
drone.takeoff(1.5) # 起飞到 1.5m
drone.goto(0, 2, 1.5) # 向北 2m(阻塞:飞到才返回)
drone.goto(2, 2, 1.5) # 向东 2m
drone.goto(2, 0, 1.5) # 向南 2m
drone.goto(0, 0, 1.5) # 向西 2m 回原点
drone.land() # 降落,自动上锁后返回
drone.shutdown() # 释放资源

5.2 集群(Swarm)

# 终端 1:三机仿真
~/0c00_ws/swarm_ws/src/bringup/scripts/start_swarm_sim.sh 3 1

# 终端 2
python3 ~/0c00_ws/swarm_ws/src/bringup/scripts/demo_swarm_square.py

demo_swarm_square.py 核心逻辑(三机同时画正方形):

from swarm_api import Swarm

swarm = Swarm(num_drones=3) # 自动发现 uav_1..uav_3
swarm.takeoff(1.5) # 全群同时起飞
for x, y in [(0,2), (2,2), (2,0), (0,0)]:
swarm.goto_all((x, y, 1.5)) # 全群同时飞向下一个角点
swarm.land()
swarm.shutdown()

注意两个 demo 的结构几乎一样——从单机到集群的学习成本只有一次思维转换Drone 的单数动作换成 Swarm 的复数动作。

6. 阻塞语义、超时与并行模型

6.1 哪些动作阻塞、哪些不阻塞

动作阻塞?返回时机
takeoff阻塞飞机到达目标高度并悬停
goto / goto_all / goto_formation阻塞到达判定满足(见下)
land阻塞触地并自动上锁
set_velocity / set_velocity_all不阻塞立即返回,飞机持续按该速度飞
hover / emergency_stop不阻塞立即返回(目标点已设为当前位置)

6.2 到达判定与 tol

goto 的到达判定:水平误差与垂直误差同时小于 tol(默认 0.3m):

d_xy = math.hypot(pos_x - target_x, pos_y - target_y) < tol
d_z = abs(pos_z - target_z) < tol
  • 室内/UWB 精度好:可以用 tol=0.15 飞得更精确;
  • GPS 仿真/定位噪声大:tol 太小会导致飞机在目标附近反复微调、很久才判定到达,建议保持默认或放宽到 0.5;
  • 状态轮询周期 0.1s,不要把 tol 设得比定位噪声还小。

6.3 timeout 语义

所有阻塞动作都有 timeout(默认 60s),超时抛 DroneError。注意:

  • 超时不等于失败坠机——飞机仍在原目标点悬停(设定点流还在工作),你可以捕获异常后继续下达新指令;
  • 长距离飞行要自己估算时间:goto 的飞行速度由 PX4 参数(默认约 1~2 m/s)决定,飞 20m 至少给 30s;
  • takeoff 的 timeout 覆盖"切模式+解锁+爬升"全过程,仿真刚启动 EKF 未收敛时可能需要更长。

6.4 Swarm 的屏障语义与部分失败

Swarm 的多机动作是屏障(barrier):所有飞机的任务线程都结束(成功或失败)后才返回。

  • 全部成功 → 正常返回;
  • 部分失败 → 失败机自动悬停,其余机已完成动作,最后抛 SwarmError(携带每机的错误明细)。

这意味着"三机编队变换"中若有一架超时,另外两架已经飞到新位置了——你的异常处理代码要意识到这一点,必要时在 except SwarmError 里让全群 hover() 再决定下一步。

7. 错误处理完整体系

7.1 异常类型

from swarm_api import DroneError, SwarmError
  • DroneError:单机操作失败。消息格式 "uav_1: 具体原因"
  • SwarmError:多机并行执行的汇总错误。e.errors{命名空间: 异常} 字典,可逐机检查。

7.2 失败场景与框架行为对照表

场景框架行为飞机实际状态
启动时无飞控数据takeoff 10s 后抛 DroneError(等待超时)地面待机
EKF 未收敛 / preflight 不过takeoff 循环重发命令直到 timeout 抛错地面待机
goto 未在 timeout 内到达DroneError仍在目标点悬停,可继续下达指令
飞行中飞控 failsafe 接管goto 2s 内检测 Offboard 丢失,抛错飞控按 failsafe 逻辑行动(悬停/返航/降落)
takeoffgoto/set_velocity立即抛 DroneError地面待机
land 超时未上锁DroneError可能仍在降落中,检查飞控状态
多机动作中某机失败该机自动 hover,其余继续,最后抛 SwarmError失败机悬停,其余机正常
程序崩溃 / Ctrl+C设定点流停止 → 飞控 Offboard 失联保护接管自动降落(PX4 默认行为)

7.3 推荐的错误处理写法

from swarm_api import Swarm, SwarmError

swarm = Swarm(num_drones=3)
try:
swarm.takeoff(1.5)
swarm.goto_all([(0,2,1.5), (2,2,1.5), (4,2,1.5)])
except SwarmError as e:
for ns, err in e.errors.items():
print(f"{ns} 失败: {err}")
swarm.hover() # 先稳住全群
# ... 决策:重试 / 放弃任务 ...
finally:
swarm.land() # 无论如何安全降落
swarm.shutdown()

如果不想自己写 try/finally,直接用 Strategy 基类(见 8.3),异常处理已托管。

8. 进阶用法

8.1 速度控制(非阻塞,适合连续轨迹)

set_velocity 设定速度后立即返回,飞机持续按该速度飞,直到下一个指令。适合圆轨迹、跟踪、人工摇杆这类连续控制场景:

import math, time
from swarm_api import Swarm

swarm = Swarm(num_drones=3)
swarm.takeoff(1.5)

t0 = time.time()
while time.time() - t0 < 10: # 飞 10 秒圆
t = time.time() - t0
swarm.set_velocity_all((-math.sin(t), math.cos(t), 0.0)) # 切向速度
time.sleep(0.1)

swarm.hover() # 切回位置模式悬停
swarm.land()
swarm.shutdown()

要点:

  • 速度指令周期建议 10~20Hz(sleep(0.05~0.1)),框架流线程会按最新值持续发出;
  • 从速度模式切回位置模式只需调 hover()goto(),框架自动处理 OffboardControlMode 标志位切换;
  • yaw_rate 参数可以让飞机边飞边转头(如搜索时扫描)。

8.2 集群动作 + 单机微调混用

Swarm 提供三种单机访问方式,可随时对个别飞机单独下指令:

swarm = Swarm(num_drones=3)
swarm.takeoff(1.5)

swarm["uav_2"].goto(1, 1, 2.5) # 按命名空间取:只让 uav_2 爬升
swarm[0].set_velocity(0, 0.3, 0) # 按下标取:uav_1 低速向北
swarm.drones[2].hover() # 按列表取

swarm.goto_all((0, 3, 1.5)) # 全群再一起动(注意此时各机高度不同)
swarm.land()
swarm.shutdown()

8.3 用 Strategy 编写可复用的集群算法(推荐)

把算法写成策略插件,起飞、异常处理、降落、收尾全部托管——这也是平台内置基线算法(编队、覆盖、搜索、任务分配)的组织方式,便于你的算法与基线在相同环境、相同指标下公平对比:

from swarm_api import Strategy

class TriangleDemo(Strategy):
name = "triangle_demo"

def setup(self, swarm):
# 可选:算法前的准备(订阅传感器、加载地图、打印参数)
print(f"将对 {len(swarm)} 架飞机执行三角编队")

def run(self, swarm):
# 必须实现:算法主体
swarm.takeoff(1.5)
swarm.goto_formation("triangle", spacing=2.0, z=1.5)

def teardown(self, swarm):
# 可选:降落后的清理(保存数据、生成报告)
print("数据已保存")

if __name__ == "__main__":
TriangleDemo().main(num_drones=3)

main() 托管的完整生命周期:

发现飞机 → setup() → run() →(异常则全群悬停)→ 自动降落 → teardown() → 释放资源
  • 运行中 Ctrl+C 会安全触发降落;
  • run() 里抛任何异常都会被捕获、打印堆栈、全群悬停后降落——写算法时不用为安全收尾分心。

8.4 长任务与监控循环

阻塞动作之间可以随时读状态做监控或决策:

swarm.takeoff(1.5)
for d in swarm.drones:
print(f"{d.ns}: 高度 {d.pos[2]:.2f} m, 航向 {d.yaw:.2f} rad, "
f"armed={d.armed}, offboard={d.offboard}")

9. 安全机制与失效行为

框架内置五道防线(全部自动生效,无需配置):

#机制保护对象
1后台 20Hz 设定点流杜绝"断流导致 Offboard 退出"这类低级事故
2Offboard 丢失 2s 快速报错飞控 failsafe 接管后,算法立即知情而不是傻等
3单机异常隔离 + 自动悬停故障机不拖垮全群
4PX4 失联保护程序崩溃/Ctrl+C 后飞控自动接管降落(最后防线)
5PX4 电子围栏仿真默认 10m×6m 围栏(启动脚本 GF_ACT 环境变量可配),越界自动返航

以及两条使用纪律(框架管不了,靠流程):

  1. 真机之前必须先过仿真回归——这是平台的强制流程,没有例外;
  2. 真机实验时人手握遥控器待命——框架再可靠也只是软件,PX4 的遥控器接管优先级最高,用它。

10. 性能特征与调参建议

项目数值说明
设定点流频率20Hz / 机PX4 要求 ≥2Hz,20Hz 是经验舒适值
状态轮询周期0.1sgoto 到达判定的检查间隔
命令重发间隔0.5s切模式/解锁/降落命令
控制链路延迟典型 20~50ms指令到飞控生效(与产品指标一致)
每机线程开销2 常驻 + 1 临时(动作期间)10 机约 30 线程,CPython 无压力
实测规模3 机(仿真)产品承诺 3~4 机,6 机演示

调参建议:

  • 机数 > 6:先测通信链路的并发上限(WiFi 验证链路有实测报告),框架本身不是瓶颈;
  • tol 不要小于定位噪声:仿真 GPS 约 0.10.3m,UWB 典型 0.10.3m(以实测报告为准);
  • 不要追求过快的 goto 接力:每个 goto 到达后飞控需要时间稳定,密集小步点不如用 set_velocity 走连续轨迹。

11. 基于框架开发自己的算法包

推荐的工程结构(以 ROS 2 Python 包形式,与 swarm_api 并列):

swarm_ws/src/
├── swarm_api/ # 框架(不要改,改了全平台受影响)
└── my_algorithm/ # 你的算法包
├── package.xml # exec_depend: swarm_api, rclpy
├── setup.py
└── my_algorithm/
├── __init__.py
├── my_strategy.py # Strategy 子类:算法主体
└── my_planner.py # 纯计算逻辑(不碰 ROS,方便单元测试)

开发规范:

  1. 算法逻辑与框架调用分离my_planner.py 只算目标点(输入状态、输出坐标),不 import rclpy——这样可以脱离仿真做单元测试;
  2. 不要继承/修改 Drone 的内部:需要新原语时,在你的包里组合现有原语(如"飞矩形扫描"= 循环 goto);确实需要框架级新能力,提需求给平台维护者;
  3. 坐标一律 ENU:你的包对外接口也用 ENU,全平台统一;
  4. 版本绑定:算法包、参数文件、固件版本三者绑定归档,真机实验可追溯到精确版本组合。

12. 从仿真迁移到真机

框架层零代码改动。迁移检查清单:

项目仿真真机要做的
命名空间uav_N,自动发现自动发现(同一规则)
坐标系每机各自本地系UWB 统一全局系检查 goto_all 目标点是否会撞机
高度基准GPS(已降噪)光流/UWB无(takeoff 用相对高度,天然免疫)
起飞高度1.5m 任意受场地净高限制确认围栏与净高
通信本地回环ESP32 WiFi 透传测并发延迟与丢包
失效行为围栏 10m×6m按 SOP 配置布场后核对 GF 参数
安全无所谓防护网+遥控器待命完成安全培训(验收前置条件)

13. 当前限制与边界

使用前先了解这些,避免踩坑:

  1. 无避障goto 走直线,不管路径上有什么;
  2. 无轨迹插值:目标是阶跃的,飞控自身的位置环会平滑它,但不要指望精确的时间同步轨迹(多机"同时转弯"是近似的同时);
  3. 无全局坐标变换层:仿真中跨机的全局规划需要自己处理各机原点偏移(真机 UWB 无此问题);
  4. 速度模式无位置保护set_velocity 期间框架不做位置监控,飞出围栏由 PX4 围栏兜底;
  5. Python GIL:每机状态回调与流线程共享 GIL,20 机以上规模未验证(产品也不承诺这个规模);
  6. 不订阅的话题拿不到:框架目前只订阅位置和状态。电量、GPS 质量等需要时请在你的算法包里自行订阅(/uav_N/fmu/out/battery_status 等)。

14. 常见问题 FAQ

Q1:Swarm(num_drones=3) 报"只发现 0 架飞机"? 仿真没启动或没启动完。先运行 start_swarm_sim.sh 3 1,等 30~40 秒再运行脚本。用 ros2 topic list | grep vehicle_local_position 确认飞机在线。

Q2:takeoff 超时,报"进入 Offboard/解锁超时"? 飞控 preflight 检查未通过。仿真刚启动时 EKF 需要 10~20 秒收敛,等一会再跑;真机检查定位源、罗盘与起飞前检查项(QGC 里能看到具体哪项不过)。

Q3:飞机往反方向飞 / 高度反了? 确认传的是 ENU(x=东,y=北,z=)。框架不接受 NED。想复习转换看 swarm_api/drone.py 顶部的两个函数,全部转换只在那里发生。

Q4:goto 总在目标附近晃很久才判定到达? tol 相对定位噪声太小了。放宽 tol(如 0.5),或接受它——飞机到位精度没变,只是判定晚了。

Q5:多机动作抛 SwarmError,剩下的飞机怎么办? 它们已完成该动作并在原地悬停,处于安全状态。捕获异常后调 swarm.hover() 稳住,再决定重试或降落(见 7.3 的写法)。

Q6:能在 set_velocity 期间读位置做闭环吗? 可以,这正是设计用法:while 循环里读 drone.pos、算速度、调 set_velocity,周期 0.05~0.1s。注意做位置保护(框架不管,见第 13 节第 4 条)。

Q7:最大能控几架? 框架本身无硬上限,瓶颈在 WiFi 链路和地面站性能。仿真实测 3 机;产品承诺 3~4 机、6 机演示。

Q8:和 PX4 官方 uXRCE-DDS 例程什么关系? 框架底层就是官方 Offboard 接口(trajectory_setpoint + offboard_control_mode + vehicle_command),把工程细节产品化了。想深入底层,swarm_api/drone.py 全文约 250 行,注释完整,是最好的学习材料。

Q9:为什么 land() 要先停设定点流? PX4 在 Offboard 模式下持续收到位置设定点时,会认为外部计算机仍在主动控制,从而拒绝 NAV_LAND。这是实测发现的飞控行为,框架已在内部处理,了解即可。

Q10:真机上 takeoff(1.5) 和仿真行为完全一致吗? 一致。高度基准都是"当前实测高度 + 1.5m",不依赖绝对海拔,对 GPS/光流/UWB 任何高度源都成立。


文档版本:v2.0(2026-07-27),对应 swarm_api 0.1.0。框架 API 变更时本文档同步更新。