3、PX4 SITL仿真:SITL原理、启动PX4 SITL、连接QGroundControl、基础飞行指令测试

说实话,做飞控开发最怕什么?怕炸机。我早期在实验室调参数,一个不小心,四轴直接翻了个跟头砸在地上,桨叶碎了一地。从那以后,我养成了一个习惯——所有代码改动,必须先过SITL仿真

这一章,我们就来聊聊PX4的SITL仿真。说白了,就是在你的电脑上跑一个虚拟的飞控,模拟真实的硬件环境。你想想看,不用焊板子、不用接电机、不用担心炸机,多爽。

SITL原理:到底在模拟什么?

SITL,全称Software In The Loop。它的核心思路很简单:把飞控的硬件层替换成软件模拟层

具体来说,PX4的SITL做了三件事:

  • 模拟传感器:IMU、GPS、磁力计、气压计的数据,都由一个数学模型生成。比如你给飞机发一个“向前飞”的指令,模拟器会计算出对应的加速度和角速度,然后喂给飞控算法。
  • 模拟执行器:电机、舵机的响应,也被模型化了。你给一个PWM值,模拟器算出转速和推力。
  • 模拟物理环境:重力、空气阻力、地面效应……这些物理量,由Gazebo或jMAVSim这样的仿真引擎负责计算。

核心要点:SITL跑的是和真机完全一样的二进制代码。你编译出来的px4固件,在仿真里跑的和在真机上跑的,是同一份代码。这就是SITL最大的价值——代码零改动,环境全仿真

我在项目中遇到过一个问题:有个同事在真机上测试时,飞机总是莫名其妙地偏航。后来用SITL复现,发现是磁力计校准的代码里有个边界条件没处理好。如果在真机上排查,得飞多少次才能找到这个bug?

启动PX4 SITL:三步走

嗯,这里要注意,启动SITL之前,你得先把环境搭好。假设你已经装好了PX4工具链和Gazebo。我个人习惯用make px4_sitl gazebo这个命令,简单直接。

第一步:打开终端,进入PX4源码目录

cd ~/PX4-Autopilot

第二步:启动SITL仿真

make px4_sitl gazebo

这条命令会做几件事:编译PX4固件(如果代码有改动)、启动Gazebo仿真环境、加载一个默认的四旋翼模型(通常是iris)。

第三步:等待启动完成

你会看到终端里刷出一堆日志。别慌,等看到类似这样的输出,就说明启动成功了:

INFO  [simulator] Waiting for simulator to accept connection on TCP port 4560
INFO  [simulator] Simulator connected on TCP port 4560
INFO  [mavlink] MAVLink only on localhost (127.0.0.1), port 14556
INFO  [mavlink] MAVLink only on localhost (127.0.0.1), port 14557

小技巧:如果你只想快速测试,不想看Gazebo的3D画面,可以用make px4_sitl gazebo-classic。Gazebo-classic启动更快,资源占用也更少。

我曾经踩过一个坑:第一次启动时,Gazebo卡在加载界面不动了。后来发现是显卡驱动的问题。如果你也遇到类似情况,试试在终端里加一个--headless参数:

HEADLESS=1 make px4_sitl gazebo

连接QGroundControl:地面站配置

SITL启动后,飞控默认在本地开了两个MAVLink端口:14556和14557。QGroundControl(简称QGC)会自动检测到本地的SITL实例。

连接步骤:

  1. 打开QGC(确保版本在4.0以上)。
  2. 在QGC的“Comm Links”设置里,添加一个UDP连接:
    • 监听端口:14550(QGC默认监听这个端口)
    • 目标主机:127.0.0.1
    • 目标端口:14556
  3. 点击“Connect”,几秒钟后,QGC的左上角会显示“Connected”。

连接成功后,你会在QGC上看到飞机的姿态、位置、电池电压等信息。注意,这里的电池电压是模拟的,别当真。

注意事项:如果你同时开了多个SITL实例(比如想测试多机协同),每个实例的MAVLink端口必须不同。否则端口冲突,谁也连不上。

基础飞行指令测试:让飞机动起来

连接上QGC后,我们就可以给飞机发指令了。我个人习惯用QGC的“Stick”模式手动控制,或者用MAVSDK写脚本自动测试。

方式一:通过QGC手动控制

  1. 在QGC的“Vehicle Setup”页面,找到“Safety”选项卡,把“Arming Check”设为“Disabled”。
  2. 回到主界面,点击右上角的“Arm”按钮。你会看到电机开始旋转(在Gazebo里能看到桨叶转动)。
  3. 切换到“Position”模式,推动摇杆,飞机就会起飞。

方式二:通过MAVSDK脚本自动测试

写一个简单的Python脚本,让飞机起飞、悬停、降落:

import asyncio
from mavsdk import System

async def run():
    drone = System()
    await drone.connect(system_address="udp://:14540")

    print("Waiting for drone to connect...")
    async for state in drone.core.connection_state():
        if state.is_connected:
            print("Connected!")
            break

    print("Arming...")
    await drone.action.arm()

    print("Taking off...")
    await drone.action.takeoff()

    await asyncio.sleep(5)

    print("Landing...")
    await drone.action.land()

if __name__ == "__main__":
    asyncio.run(run())

运行这个脚本,你会看到Gazebo里的飞机缓缓起飞,悬停5秒,然后降落。整个过程和真机一模一样。

避坑指南:我曾经在测试时,飞机起飞后直接往一边偏。排查了半天,发现是Gazebo的模型参数里,重心位置设置错了。所以,如果你发现仿真里的飞机姿态异常,先检查模型文件,别急着改飞控参数。

本章知识体系

下面这张图,帮你理清SITL仿真的核心逻辑:

PX4 SITL仿真核心流程 用户指令 (QGC / MAVSDK) PX4飞控 (真实固件代码) 传感器模拟 (IMU/GPS/磁力计) Gazebo 物理状态反馈 核心逻辑:用户指令 → PX4飞控(真实代码) → 传感器模拟 → 物理引擎(Gazebo) 物理引擎将状态反馈给传感器模拟,形成闭环 关键MAVLink端口 14556 (飞控→地面站) | 14557 (飞控→SDK) | 14550 (QGC默认监听)

这张图展示了SITL的完整数据流。你从QGC发一个指令,经过PX4飞控处理,然后传感器模拟层生成对应的数据,最后Gazebo更新物理状态。这个状态又反馈给传感器模拟层,形成闭环。说白了,就是用软件模拟了一个完整的飞控硬件环境

个人建议:刚开始接触SITL时,别急着跑复杂的任务。先手动控制飞机飞一圈,看看姿态响应是否正常。我每次搭建新环境,都会先做一次“起飞-悬停-降落”的测试,确保整个链路是通的。

好了,这一章的内容就到这里。SITL仿真是一个强大的工具,但也要记住——仿真永远无法完全替代真机测试。不过,它能帮你过滤掉90%的低级错误,这就足够了。


公众号:蓝海资料掘金营,微信deep3321