拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

无人机开发必备:SITL+MAVProxy+QGC模拟飞行环境搭建指南

无人机开发必备:SITL+MAVProxy+QGC模拟飞行环境搭建指南

搞无人机开发这些年,我最大的教训就是:千万别在没验证逻辑的情况下直接上真机。一次炸机,轻则损失几千块,重则把周围人都搭进去。所以现在我的工作习惯很固定——任何新的飞行任务、航点脚本、应急返航策略,先在一套纯软件模拟环境里反复跑几十遍,确认没问题再谈实飞。今天要聊的这套组合,就是我用了很久、也踩过不少坑之后沉淀下来的模拟飞行方案:DRONEKIT-SITL 负责在电脑上假装是一台完整的飞控,MAVProxy 作为命令行链路调试工具,QGroundControl 提供可视化地面站面板。三者配合,能在一台普通电脑上完整走完起飞、巡航、航点任务、异常返航这一整套飞行流程。

这套环境能帮你解决什么问题?一句话概括:不花钱、不冒险、不占场地,就能把飞控上要跑的逻辑先彻底跑熟。它特别适合三类人:正在学 MAVLink 协议和 ArduPilot 架构的入门玩家、需要为测绘或巡检任务编写自动飞行脚本的开发者、以及想测试地面站航线和参数调优功能的工程人员。下面我就把这套环境的搭建过程、链路原理、真实踩坑记录全部写下来,跟着操作,你也能在半小时内拥有一套属于自己的“空中模拟场”。

1. 模拟飞行环境搭建前,先看懂这条数据链路

很多人一上来就急着装软件,结果 SITL 起来了、QGC 也装了,但就是连不上,最后卡在“为什么没反应”上。根源在于没搞清楚这三个组件到底怎么协同工作。我先花点篇幅把架构讲透,后面你排查问题会省很多力气。

1.1 不飞真机,为什么还要这么认真地搭环境

先聊聊 SITL 到底是什么。SITL 全称 Software In The Loop,软件在环仿真。它不是一个普通的三维飞行游戏,也不是简单的“模拟器”,而是把 ArduPilot 或 PX4 这类真实飞控固件,编译成能在普通操作系统里直接运行的二进制程序。你通过 MAVLink 协议跟它通信时,它输出的心跳包、姿态数据、GPS 坐标、电机转速,全部是真实飞控代码处理出来的结果——只是传感器数据被虚拟模型代替了。

这意味着什么?你在真实飞机上跑的同一个 ArduCopter 固件,在电脑上跑的是同一条代码路径。你今天在 SITL 里验证过的模式切换、RC 覆盖、地理围栏逻辑,上真机后行为基本一致。差别只在于:真实世界有风、有磁场干扰、有 GPS 漂移,而 SITL 里这些都可以建模和注入。所以,用 SITL 做逻辑验证是可靠的,它是从“代码写完”到“真机起飞”之间最重要的一道关卡。

那 MAVProxy 和 QGroundControl 又是什么角色?MAVProxy 是一个基于命令行的 MAVLink 地面站,轻量、灵活,适合调试协议和链路。QGroundControl(习惯叫 QGC)是更完善的可视化地面站,负责航线规划、参数调参、仪表显示。它们不参与仿真计算,只负责跟 SITL 通信、监控和控制。简单说,SITL 是“被仿真的飞机”,MAVProxy 和 QGC 是“地面端”。这两者可以同时存在、同时连接,也可以只选其一。实际使用时,我通常让 MAVProxy 常驻,因为它诊断链路和注入故障指令非常方便。

1.2 三个组件如何串成一条完整的仿真链路

搞懂数据流,是这套环境最核心的部分。ArduPilot SITL 启动后,默认会在本机打开两个通信入口:一个是 TCP 端口 5760,专门给 MAVProxy 或 DroneKit 这类需要主动发起连接的客户端使用;另一个是 UDP 端口 14550,用于向地面站广播遥测数据。MAVProxy 连接 SITL 之后,又可以作为一个“数据转卖商”,把自己收到的 MAVLink 数据包再转发给其他端口,这样 QGC 就能通过 MAVProxy 间接拿到数据。

我常用的链路是这样的:

  • SITL 监听tcp:127.0.0.1:5760
  • MAVProxy 用--master tcp:127.0.0.1:5760连接 SITL
  • MAVProxy 通过--out 127.0.0.1:14550将数据转发到 UDP 14550
  • QGC 新建一个 UDP 连接,监听127.0.0.1:14550,就能看到飞机了

还有一种更粗暴的方式:SITL 启动时直接加--out 127.0.0.1:14551,QGC 监听 14551,绕开 MAVProxy。这种方式适合只测地面站功能、不需要命令行干预的场景。但我个人建议不要省掉 MAVProxy,因为它在排查“心跳断了”“数据没转发”“消息类型不对”这些问题时,简直是神器。后面我在故障排查部分会详细举例子。

端口和数据流心里有数之后,安装和启动就变成了一件顺理成章的事。

2. 环境部署:从零跑通 SITL + MAVProxy + QGC

搭建这套环境,依赖的工具并不多:Python 3、pip、DroneKit-SITL、MAVProxy,以及一个 QGroundControl 桌面端。整个过程我按“安装依赖 → 启动 SITL → 连接 MAVProxy → 检查健康状态”四步来走。

2.1 依赖安装与版本选择

先说大前提:强烈建议在 Linux 环境下跑这套东西,尤其是 SITL。Windows 虽然也能跑,但经常会遇到路径含中文、防火墙拦截、超时连接这类莫名其妙的怪问题。如果手头只有 Windows 电脑,优先开启 WSL(Windows Subsystem for Linux),在 Ubuntu 环境里操作。我这边的操作全部基于 Ubuntu 22.04。

Python 环境推荐用虚拟环境,避免把系统搞乱。命令如下:

sudo apt update sudo apt install -y python3 python3-pip python3-venv mkdir ~/drone-sim && cd ~/drone-sim python3 -m venv venv source venv/bin/activate

接着安装核心工具:

pip install dronekit dronekit-sitl mavproxy pymavlink

这里有个版本选择的关键点:dronekit-sitl会自动下载并缓存对应版本的 ArduPilot 固件,默认机型是 ArduCopter。下载完成后,它会提示你 SITL 二进制放在哪个目录。如果你之前装过旧版,建议先pip uninstall dronekit-sitl再重装,否则可能启动旧固件。

MAVProxy 本身依赖 pymavlink,在某些新架构机器上可能出现编译失败。如果遇到这种情况,先装好编译工具链再重试:

sudo apt install -y build-essential python3-dev libxml2-dev libxslt1-dev

QGroundControl 的安装就简单多了,去官方仓库下载对应系统的 AppImage 或安装包。Linux 下给 AppImage 加上执行权限即可:

chmod +x QGroundControl.AppImage ./QGroundControl.AppImage

2.2 启动 SITL 模拟器与 home 点设置

依赖装好后,第一步就是启动 SITL。我喜欢在启动时指定好 home 点坐标,因为 SITL 默认的 home 点固定在一个海外坐标,如果你的任务脚本里写死了相对位置,默认坐标会导致数据看起来很奇怪。

我常用的启动命令是:

dronekit-sitl copter-3.3 --home=31.2304,121.4737,10,0 --out=127.0.0.1:14550

拆开解释一下:

  • copter-3.3:指定 ArduPilot 机型与版本。copter 表示多旋翼,3.3 是 ArduPilot 的经典稳定版本;也可以换成plane-3.3模拟固定翼,或rover-3.3模拟小车。
  • --home:后跟四个参数,依次是纬度、经度、海拔高度、朝向角。我这里是上海某地的坐标,海拔 10 米,朝向 0 度。设置成你本地的位置,写任务脚本时更直观。
  • --out:额外输出一个 UDP 遥测端口。SITL 默认已经有 5760 和 14550 了,这里再加一个 14551,留给 QGC 备用。

启动成功后,终端会滚动打印模拟飞控的启动日志,包括传感器校准、GPS 锁定、EKF 初始化等。等到日志稳定出现EKF2 IMU0 is using GPS之类的内容,说明飞控已经进入待命状态。此时再开一个终端窗口,进入虚拟环境,准备连接 MAVProxy。

2.3 MAVProxy 连接与链路健康检查

MAVProxy 连接 SITL,最核心的命令就这一条:

mavproxy.py --master=tcp:127.0.0.1:5760 --out=127.0.0.1:14550

--master指定数据源,--out指定转发目标。如果你想同时把数据转发给 QGC 和另一个调试脚本,可以再加一个--out。MAVProxy 启动后,下方会有一个STABILIZE>之类的命令行提示符。此时在里面输入status,你会看到类似这样的输出:

APM: ArduCopter V3.3 GPS: GPS OK, fix 3 Vcc: 4.97 Rel: 0.00

字段含义可以直接看字面:GPS 锁定状态、供电电压、相对高度。如果GPS显示fix 3而没有报错,说明 SITL 和 MAVProxy 之间的链路已经通了。

再用module list查看当前加载的模块,help查看可用命令。我习惯在 MAVProxy 里先执行几个基础命令验证控制能力:

STABILIZE> mode GUIDED STABILIZE> arm throttle STABILIZE> takeoff 10

如果一切正常,飞控会从 STABILIZE 切到 GUIDED,电机解锁,并自动起飞到 10 米高度。我用这种方式确认 MAVProxy 已经拥有完整的“地面站权限”。注意,arm throttle后会看到Throttle armed的提示,直接起飞之前建议先取消:

STABILIZE> mode LAND

等飞机落地后再进行下一步。这一步走通,就说明整个命令行链路已经 OK,剩下的就是让 QGC 进来看可视化界面了。

3. 让 QGroundControl 接管模拟飞行的可视化监控

命令行能干活,但对大多数人来说,千里之外看不见飞机,心里还是不踏实。QGC 的价值就是把整个仿真环境变成一个可视化的操控台:你能看到飞机在地图上的位置、姿态仪、空速地速、电池电压,还能在地图上画航线、传任务、切换飞行模式。下面讲 QGC 的连接、界面验证和航线规划。

3.1 添加连接:UDP 还是 TCP

QGC 连接 SITL 有两条路:直接连 SITL 的 UDP 14550,或者连 MAVProxy 转发出来的端口。两种方式我都在用,场景不同而已。

如果你只开了 SITL,没有启动 MAVProxy,可以在 QGC 右上角点开“应用设置”,进入“通信连接”,添加一个连接:

  • 类型:UDP
  • 监听端口:14550

保存并连接后,QGC 应该能在几秒内识别到 SITL 飞控,顶部状态灯变绿,并显示 ArduCopter V3.3 的固件版本。

如果你和我一样常驻 MAVProxy,则更简单。MAVProxy 已经通过--out=127.0.0.1:14550把数据转发出来了,QGC 同样监听 14550 就行。这里有个容易踩的坑:如果 MAVProxy 和 QGC 都在同一台电脑上,QGC 用 UDP 监听,MAVProxy 也是 UDP 转发,一般来说没问题;但 Windows 防火墙会把 UDP 广播拦截,导致 QGC 端怎么都收不到心跳。解决方法是给防火墙放行那几个 UDP 端口,或者干脆在 MAVProxy 里转发到一个 TCP 端口,QGC 用 TCP 客户端方式连接。我一般测试时直接放行 UDP,固定开发环境后就改成 TCP,稳定很多。

3.2 在 QGC 里验证传感器数据与姿态同步

连接成功后,先不要急着规划航线。观察一下界面右侧的仪表盘:

  • 高度:SITL 默认会模拟气压计,起飞前应该显示 0 米或接近于 0。
  • GPS 坐标:应该对应你通过--home设置的坐标点,地图上的飞机图标稳稳停在那里。
  • 姿态角:roll、pitch、yaw 在静止状态下应该全部归零或接近零。
  • 电池电量:SITL 默认模拟一个满电电池,电压 12V 以上,不会变化。

这些看起来不起眼的数据,其实是检验链路是否完整最直接的指标。有一次我在新电脑上搭环境,QGC 看到飞机却怎么都不动,高度一直是 0,后来一查是 SITL 的 EKF 没有收敛,日志里提示磁力计异常,重启 SITL 重新校准就好了。

验证数据正常后,我通常会在 MAVProxy 里发送一条控制指令,看看 QGC 仪表是否实时变化:

STABILIZE> mode GUIDED STABILIZE> arm throttle STABILIZE> takeoff 5

QGC 的仪表盘上,高度开始上升,姿态也随着模拟电机的动力输出发生变化。到这一步,可视化链路就算完全打通了。

3.3 任务规划与自动飞行验证

QGC 最大的价值之一就是航点任务规划。在 SITL 模拟环境里规划航线,跟在真机里操作流程一模一样。

点击左侧工具栏的“飞行计划”,在地图上飞机现在的位置附近点几个航点,设置每个航点的高度(比如 30 米),保存并上传任务。此时注意看 MAVProxy 终端的输出,会滚动显示Got MAVLink msg: MISSION_COUNT、MISSION_ITEM_INT之类的内容,说明任务已经通过 MAVLink 协议上传到了 SITL 飞控。

上传完成后,切到 QGC 的“飞行界面”,在模式选择里选择“自动”(AUTO),飞机就会依次飞向每个航点。地图上会实时绘制出飞机的飞行轨迹,你能看到它起飞、转弯、平飞、降落的全过程。这个过程中 QGC 就相当于一个实时的空管雷达,SITL 则相当于完整执行飞控逻辑的“虚拟真机”。

这里我特别建议新手在模拟环境里多试几次航线规划,因为很多真实飞行的操作习惯——比如起飞前检查 home 点、确认任务上传完整、保证航点高度合理——就是在这种反复演练里培养出来的。

4. 实战:完整跑一遍模拟自主航线与应急返回

环境通了,功能也看过了,接下来的实战部分是整套方法最有价值的地方。我会用一个真实场景来描述:编写一个 DroneKit 飞行脚本,自动起飞、按航点飞行、最后返回起飞点并降落;然后再人为注入 GPS 故障,验证应急返航逻辑。

4.1 起飞前检查清单

虽然只是模拟环境,但我还是习惯走一遍检查流程,目的是养成肌肉记忆,真机上才不会慌。我通常在启动任何飞行任务之前,在 MAVProxy 里执行这些检查:

STABILIZE> status STABILIZE> gps STABILIZE> battery STABILIZE> ekf
  • status:确认飞控版本和心跳正常。
  • gps:确认 GPS fix 正常,星数模拟值通常为 10 以上,HDOP 小于 1。
  • battery:确认电压、电流检查无异常。
  • ekf:确认姿态估计没有出现严重漂移。

同时确认 QGC 地图上的 home 点位置正确。这个 home 点很重要,因为自动返航(RTL)的降落点就是它,如果设错了,应急返航就会落错地方。

4.2 编写并执行 DroneKit 自动飞行脚本

DroneKit 是 MAVLink 的 Python SDK,可以让你用几行代码控制一整个飞行流程。下面是我用来测试 SITL 环境的一套最小脚本:

from dronekit import connect, VehicleMode import time connection_string = "tcp:127.0.0.1:5760" print("Connecting to vehicle on %s" % connection_string) vehicle = connect(connection_string, wait_ready=True) print("Global Location: %s" % vehicle.location.global_frame) # 设置 GUIDED 模式并解锁 vehicle.mode = VehicleMode("GUIDED") vehicle.armed = True while not vehicle.armed: print("Waiting for arming...") time.sleep(1) print("Armed!") # 起飞到 20 米 vehicle.simple_takeoff(20) while True: alt = vehicle.location.global_relative_frame.alt print("Altitude: %.1f" % alt) if alt >= 20 * 0.95: print("Reached target altitude") break time.sleep(1) # 向前飞行 10 秒 vehicle.airframe = None # 占位,保持脚本结构完整 vehicle.simple_goto(vehicle.location.global_frame, groundspeed=5) time.sleep(10) # 返航并降落 print("Returning to launch") vehicle.mode = VehicleMode("RTL") while True: if vehicle.location.global_relative_frame.alt <= 1: print("Landed") break time.sleep(1) vehicle.close() print("Test completed")

注意,simple_goto的参数是一个LocationGlobalRelative对象,我这里为了保持示例简短,只用了当前点让飞机悬停,实际任务中可以构造一个偏移航点,比如:

from dronekit import LocationGlobalRelative point = LocationGlobalRelative(lat, lon, 30)

跑这个脚本之前,确认你已经启动了 SITL 和 MAVProxy。然后执行:

python test_flight.py

你会看到脚本逐行打印坐标和高度,同时 MAVProxy 和 QGC 同步显示飞机状态。如果脚本运行中出现Command Failed或超时,多半是 SITL 还在初始化 EKF,等几秒再重试即可。

4.3 注入故障:GPS 丢失与应急返航验证

模拟环境里最能锻炼人的地方,就是可以肆无忌惮地制造故障。我常用 MAVProxy 来禁掉 GPS,看看飞控和脚本会怎么反应。

过程是这样的:飞机先正常起飞到 20 米悬停,稳定后我在 MAVProxy 里执行:

STABILIZE> param set GPS_TYPE 0 STABILIZE> reboot

GPS_TYPE 0表示禁用 GPS 模块,重启飞控后相当于模拟器完全没了 GPS 信号。这个时候观察 QGC 上的现象:GPS 图标变灰,位置不再更新,速度读数变为 0。此时如果依赖 GPS 的自动模式(比如 AUTO、RTL)还在运行,飞控通常会给出警告或切换到自稳,具体行为取决于参数配置。

那怎么应急处理?我在实际测试中,通常会先在脚本里监听 GPS 丢失事件,然后让飞机直接切换回 GUIDED 模式并执行原地降落:

def gps_callback(self, attr_name, value): if vehicle.gps_0.fix_type < 2: print("GPS lost!") vehicle.mode = VehicleMode("GUIDED") vehicle.mode = VehicleMode("LAND") vehicle.add_attribute_listener('gps_0', gps_callback)

这样一套流程跑下来,你就会深刻理解 GPS 在飞控里有多重要,以及“失去定位后立刻原地降落”为什么是多数场景下最安全的兜底策略。这套验证在真机上代价极高,但在 SITL 里也就几十秒的事。

5. 常见故障排查:连接失败、数据异常、兼容性的处理办法

最后这块内容,我整理了自己在这套组合上踩过的大多数坑。按问题类型分了三类,每一类都直接给处理方法,遇到问题时可以当成速查表用。

5.1 连接失败类问题

QGC 一直显示“等待心跳”。优先检查 SITL 是否启动成功,日志是否有异常;再检查 MAVProxy 的status是否正常。如果 MAVProxy 正常但 QGC 还是看不到,就检查 UDP 端口。在 Linux 下可以用:

ss -ulpn | grep 14550

确认 14550 端口有没有进程在监听。如果什么都没有,多半是 MAVProxy 的--out参数没生效,重启 MAVProxy 时加上--out=127.0.0.1:14550即可。

DroneKit 脚本 connect 直接卡死。大概率是 SITL 还没就绪。DroneKit 的wait_ready=True会等待 MAVLink 心跳和关键消息,如果 SITL 的 EKF 还没收敛,就会一直等下去。解决方法是稍等几秒再跑脚本,或者在connect()前加一个sleep(5)。

Windows 下 UPD 连接不稳定。这个我前面提到过,多办是防火墙拦截。除了放行端口,更稳妥的方式是让 MAVProxy 额外输出一个 TCP 端口:

STABILIZE> output add 127.0.0.1:14560

然后在 QGC 里添加 TCP 连接,地址127.0.0.1、端口14560,立刻稳定。

5.2 数据异常类问题

高度一直跳、GPS 坐标乱飞。通常是因为 SITL 的传感器模型没有正确初始化。请确认启动 SITL 时没有--no-rc之类的限制参数,并且等待日志出现EKF2 IMU0 is using GPS之后再开始飞。

起飞后姿态乱摆甚至自翻。先检查电机方向是否一致。在 SITL 里没有物理电机,方向问题多半来自 SITL 的参数配置。可以重置参数:

STABILIZE> param set ARMING_CHECK 0 STABILIZE> reboot

这只是模拟环境下的排查手段,真机千万别这样做。

位置数据静止但高度在变。这个是 GPS 和气压计数据不一致导致的。做一次完整的传感器校准:

STABILIZE> module load compass STABILIZE> compass cal

5.3 版本兼容与性能问题

DroneKit 脚本提示某些属性不存在。不同 ArduPilot 版本号的 MavLink 消息类型略有差异。SITL 的copter-3.3和 DroneKit 的新版 SDK 配合时,有时候vehicle.ekf_ok这类属性会不兼容。优先把 dronekit 和 pymavlink 升级到最新,或者固定使用官方示例里兼容的版本组合。

电脑跑 SITL 很卡,QGC 操作有延迟。SITL 和 QGC 同机运行,对 CPU 有一定压力。推荐在启动 QGC 前先调低操作系统性能模式,并且在 SITL 启动时限制仿真频率:

dronekit-sitl copter-3.3 --speedup=5

--speedup表示仿真速度倍数,默认是 1 倍速,改成 5 倍后任务执行速度会加快,但 QGC 显示会感觉比较“快进”。调试逻辑时用 1 倍,跑长航线验证用 5 倍,效率高很多。

多次启动 SITL 后端口被占用。这个我会直接杀掉残留进程再重启:

lsof -i :5760 kill -9 <PID>

如果是在 Windows 上,换成netstat -ano | findstr 5760,然后taskkill /F /PID。

我个人在实际操作中的体会是:这套模拟环境最大的价值,不是让你“学会用 QGC”,而是让你在零成本、零风险的前提下,把飞行逻辑、应急策略、通信机制全部验证一遍。你可以在一个下午内反复飞一百次、拉掉十次 GPS、切换二十次模式,这在真机上几乎是不可想象的。搭建这个环境装的软件不多,真正的门槛在于理解 MAVLink 数据流和飞控的行为逻辑——而一旦你把 SITL + MAVProxy + QGC 这条链路吃透,再上手真机,心里会踏实很多。

最后再分享一个小技巧:把常用的 SITL 启动命令和 MAVProxy 连接命令写成一个 shell 脚本,一键启动整套环境,省去每次敲命令的时间。我自己的脚本里还会加一个gnome-terminal同时拉起 QGC,真正做到了“一条命令,模拟飞行”。这套流程用熟了之后,你会发现写无人机代码的迭代速度,能比之前快出一个量级。

返回列表