☰
PX4仿真环境搭建:PX4、Gazebo、XRCE-DDS与QGC四组件关系详解
2026/11/4 11:00:30 网站建设 项目流程

1. 从零搭建 PX4 仿真链路前,先把四个组件的关系理清楚

很多人第一次接触 PX4 仿真,看到 PX4、Gazebo、XRCE-DDS、QGC 这四个名词就懵了,不知道谁依赖谁、谁先启动谁后启动。我刚开始搭这套环境的时候也走过弯路,把 QGC 先打开等着连飞机,结果 PX4 那边 SITL 还没跑起来,地面站一直显示"等待飞控连接",白白耗了一下午。所以这篇内容我不打算一上来就甩命令,而是先把这四个东西各自扮演什么角色讲透,后面操作起来你才知道每一步在干什么。

PX4 是飞控固件本身,也就是真正跑飞行控制算法的那套代码。在真机上它烧录在飞控硬件里,在仿真里它以一个叫 SITL(Software In The Loop,软件在环)的进程形式跑在你的电脑上。你可以把它理解成"虚拟飞控",它照样输出姿态、位置、电机指令,只不过这些指令没有真的驱动电机,而是发给了仿真器。

Gazebo 是仿真器,负责物理世界那一半:重力、空气阻力、碰撞、传感器噪声、摄像头图像、激光雷达点云,全都由它算。PX4 把控制指令发给 Gazebo,Gazebo 把仿真出来的传感器数据回传给 PX4,形成一个闭环。没有 Gazebo,PX4 就是"闭着眼睛"算控制,没有任何意义。

XRCE-DDS 是通信中间件,全称 eXtremely Resource Constrained Environments DDS。它解决的是 PX4 和外部程序(比如你的 ROS 2 节点、自定义 Offboard 控制程序)之间怎么对话的问题。PX4 内部用的是 uORB 消息机制,外部程序想读写这些消息,就得靠 XRCE-DDS 做桥接。它相当于一个翻译官,把 PX4 的 uORB 话题翻译成 DDS 话题,让 ROS 2 那边能订阅和发布。

QGC 是 QGroundControl 地面站,负责参数配置、航线规划、飞行监控、固件烧录这些地面操作。仿真里它连的是 SITL 暴露出来的 UDP 端口,看起来跟连真机一模一样。你可以用它解锁、切换飞行模式、看姿态仪表、改参数,是验证仿真是否正常的最直观工具。

把这四者的数据流串起来是这样的:QGC 通过 UDP 给 PX4 发指令,PX4 通过 Gazebo 的桥接插件收发仿真数据,同时 PX4 通过 XRCE-DDS 和 ROS 2 交换消息。四条链路各司其职,缺一个都跑不通完整的 Offboard 开发流程。

提示:如果你只是想跑个仿真看看飞机能不能飞,其实 PX4 + Gazebo + QGC 三件套就够了,XRCE-DDS 是给需要写外部控制程序的人准备的。但既然标题里带了 XRCE-DDS,说明目标是做 Offboard 开发,那四个都得配齐。

理解了这层关系,后面环境搭建的顺序就顺理成章了:先装基础依赖,再编译 PX4,然后配 Gazebo 模型,接着装 QGC,最后打通 XRCE-DDS 和 ROS 2。下面按这个顺序一步步来。

2. 环境准备阶段最容易翻车的几个细节

2.1 系统版本和 Ubuntu 22.04 的取舍

这套工具链对系统版本相当敏感。目前最省心的组合是 Ubuntu 22.04 + ROS 2 Humble,因为 PX4 官方对 22.04 的支持最完整,ROS 2 Humble 也是长期支持版本,和 Gazebo 的兼容性经过大量验证。如果你还在用 Ubuntu 20.04,装 ROS 2 Foxy 也能跑,但部分新版本的 PX4 和 Gazebo 插件会出现依赖冲突,排查起来很费时间。

我实测下来,Ubuntu 22.04 上装 Gazebo 有两个选择:一是 Gazebo Classic(就是 gazebo11 那一代),二是新版 Ignition Gazebo(现在改名叫 Gazebo Sim,比如 Fortress、Garden 这些版本)。PX4 目前对两者的支持都在,但 Classic 的教程和现成模型更多,新手建议先用 Classic 把流程跑通,等熟悉了再迁移到新版。

如果你是在 VMware 虚拟机里跑,这里有个高频坑:Gazebo 界面会疯狂闪烁甚至黑屏。根本原因是虚拟机的 3D 加速没开或者显存不够。解决办法是进虚拟机设置,把"加速 3D 图形"勾上,显存拉到 2GB 以上,然后在 Ubuntu 里确认显卡驱动走的是软件渲染还是硬件加速。实在不行就装 VMware Tools 并开启 3D 支持,或者干脆用双系统,仿真流畅度会好很多。

2.2 依赖安装:别跳过官方脚本

PX4 官方提供了一个ubuntu.sh脚本,一键装齐编译工具链、Gazebo、Python 依赖等等。很多人喜欢手动一个个 apt install,结果漏了某个包,编译到一半报错,回头找问题更麻烦。我的建议是老老实实用官方脚本:

git clone https://github.com/PX4/PX4-Autopilot.git --recursive bash ./PX4-Autopilot/Tools/setup/ubuntu.sh

注意--recursive这个参数不能省,PX4 仓库带了很多子模块(比如 mavlink、uORB 消息定义),不递归拉取的话编译时会出现找不到头文件的错误。脚本跑完后重启一次系统,让用户组和路径变更生效。

装完基础依赖后,Gazebo 的模型库还需要单独下载。Gazebo 启动时会去网上拉模型,国内网络环境下经常卡住或者超时,导致场景里只有地面没有建筑和飞机。解决办法是提前把模型缓存下来:

git clone https://github.com/osrf/gazebo_models.git ~/.gazebo/models

或者设置 Gazebo 的模型路径指向本地目录。这一步做完,后面启动仿真才不会出现"世界是空的"这种尴尬情况。

2.3 编译 PX4:第一次编译要有点耐心

依赖装好后进入 PX4-Autopilot 目录编译 SITL 目标:

cd PX4-Autopilot make px4_sitl gazebo-classic

第一次编译会花比较久,十几分钟到半小时都正常,取决于机器性能。编译过程中如果报错,八成是依赖没装全或者子模块没拉全。这时候别急着重装系统,先看报错信息里缺的是哪个包,针对性补上就行。

编译成功后会自动启动 Gazebo 和 PX4 SITL,你会看到 Gazebo 窗口里出现一架飞机(默认是 iris 四旋翼),同时终端里 PX4 开始打印启动日志。如果 Gazebo 起来了但飞机没出现,多半是模型路径问题;如果 PX4 日志里一直报 "Waiting for simulator",说明 Gazebo 和 PX4 之间的桥接没建立,检查一下是不是 Gazebo 版本和 PX4 期望的不一致。

注意:make px4_sitl gazebo-classic和make px4_sitl gazebo在不同 PX4 版本里指向的仿真器不一样。新版本里gazebo可能指向新版 Gazebo Sim,gazebo-classic才指向 Classic。跑之前先确认你的 PX4 版本对应哪个目标,别跑错了还以为是环境坏了。

3. Gazebo 仿真环境里那些影响体验的配置项

3.1 世界文件与机型的对应关系

PX4 启动 SITL 时,默认加载的世界文件是Tools/sitl_gazebo/worlds/empty.world或者类似的空场景。如果你想换成带建筑、带障碍物的场景,可以通过环境变量指定:

export PX4_SITL_WORLD=warehouse.world make px4_sitl gazebo-classic

机型也是同理,默认是 iris,你可以换成固定翼、VTOL、 rover 等等。机型定义文件在Tools/sitl_gazebo/models或者ROMFS/px4fmu_common/init.d-posix下面,每个机型对应一套传感器配置和初始参数。换机型的时候要注意,不同机型的电机数量、传感器类型不一样,Offboard 控制程序里的消息字段也得跟着改,不然会出现控制指令发出去了但飞机没反应的情况。

3.2 传感器噪声与仿真真实性

Gazebo 默认给传感器加的噪声比较理想化,GPS 几乎不漂、IMU 几乎没噪声。这在调试基础控制逻辑时是好事,但如果你要测试滤波算法或者做鲁棒性验证,就得把噪声调得更接近真实。方法是在机型对应的 sdf 文件里修改传感器插件的噪声参数,比如给 GPS 加上水平/垂直位置噪声,给 IMU 加上高斯噪声。

这里有个经验:调噪声不要一次调太猛,否则 PX4 的 EKF(扩展卡尔曼滤波)可能直接发散,飞机在仿真里就"炸"了。建议从小幅噪声开始,逐步加大,观察 EKF 的状态估计是否还能收敛。这个过程本身也是理解滤波器鲁棒性的好机会。

3.3 摄像头与视觉仿真的坑

做视觉相关开发(比如目标检测、视觉定位)时,需要在 Gazebo 里给飞机挂摄像头。PX4 的 iris 机型默认可能没带摄像头,你得在模型文件里加一个 camera 传感器插件,并配置好图像话题的发布。Gazebo 会把图像通过一个叫gazebo_ros_camera的插件发布成 ROS 话题,ROS 2 那边订阅就能拿到图像流。

实测中常见的问题是图像话题发布了但收不到数据,或者帧率极低。前者多半是插件没加载或者话题名对不上,用ros2 topic list确认一下;后者通常是 Gazebo 的渲染设置问题,把 Gazebo 的实时更新率调低一点,或者关掉不必要的阴影和特效,帧率会明显改善。

4. QGC 地面站连接与飞行模式调试

4.1 连接 SITL 的正确姿势

QGC 装好后(官网下载 AppImage 或者用 apt 装都行),启动它会自动扫描 UDP 端口。PX4 SITL 默认在 14550 端口广播 MAVLink 消息,QGC 一般能自动识别并连接。如果没自动连上,手动添加一个 UDP 连接,地址填127.0.0.1:14550即可。

连接成功后,QGC 左上角会显示飞机图标和"Ready To Fly"之类的状态。这时候你可以进"参数"页面看 PX4 的参数树,进"飞行"页面看姿态仪表。如果 QGC 一直显示"等待飞控",先确认 PX4 SITL 进程还在跑,再确认端口没被占用。

4.2 飞行模式没反应的排查思路

"QGC 飞行模式没反应"是个高频问题。表现是你在地面站上点了某个飞行模式(比如 Position、Offboard),但飞机状态栏没变化。原因通常有这么几类:

第一类是遥控器没校准或者没连接。PX4 默认要求有 RC 输入才能切换某些模式,仿真里虽然可以用虚拟摇杆,但如果没配置好,模式切换请求会被拒绝。解决办法是在 QGC 里做一次遥控器校准,或者修改参数允许无 RC 切换。

第二类是模式切换的条件不满足。比如 Offboard 模式要求外部程序先持续发送设定点消息,PX4 收到一定数量后才会真正进入 Offboard。如果你只是在地面站上点了一下,没有外部程序在发消息,它自然不会切过去。

第三类是解锁状态不对。飞机没解锁的时候,很多模式是切不了的。先在 QGC 里点解锁,或者用 MAVLink 命令解锁,再试模式切换。

排查的时候建议打开 QGC 的 MAVLink 控制台,看模式切换请求发出去后 PX4 回了什么。如果回了拒绝原因,顺着原因查就快多了。

4.3 参数配置的持久化

QGC 里改的参数默认存在飞控里,仿真重启后会丢失(因为 SITL 每次启动都是全新状态)。如果你有一批常用参数想每次自动加载,可以写一个启动脚本,在 PX4 启动后通过 MAVLink 批量下发参数,或者直接把参数写进 PX4 的机型配置文件里。后者更彻底,但改错了会影响所有用这个机型的人,建议只在个人分支上这么干。

5. XRCE-DDS 打通 PX4 与 ROS 2 的关键步骤

5.1 为什么需要 XRCE-DDS 而不是 MAVROS

早期做 PX4 和 ROS 的桥接,大家用的是 MAVROS,它基于 MAVLink 协议。MAVROS 能用,但消息类型受限,很多 PX4 内部的 uORB 话题它映射不过来,而且延迟相对高。XRCE-DDS 是 PX4 官方现在主推的方案,它直接把 uORB 话题映射成 DDS 话题,ROS 2 原生就能订阅,消息类型完整,实时性也更好。

简单说,MAVROS 像是"翻译二手消息",XRCE-DDS 像是"直接接内部总线"。做 Offboard 高频控制或者需要访问冷门 uORB 话题时,XRCE-DDS 优势明显。

5.2 编译并启动 XRCE-DDS Agent

XRCE-DDS 分两部分:跑在 PX4 里的客户端(Client)和跑在电脑上的代理(Agent)。PX4 固件里已经内置了客户端,你只需要编译并启动 Agent:

git clone https://github.com/eProsima/Micro-XRCE-DDS-Agent.git cd Micro-XRCE-DDS-Agent mkdir build && cd build cmake .. make sudo make install sudo ldconfig /usr/local/lib/

装好后启动 Agent,指定 UDP 端口(PX4 默认用 8888):

MicroXRCEAgent udp4 -p 8888

Agent 启动后,再启动 PX4 SITL。PX4 启动时会自动去连这个端口,连上后终端会打印 "XRCE client connected" 之类的日志。这时候你在 ROS 2 里ros2 topic list,就能看到一堆/fmu/开头的话题,比如/fmu/out/vehicle_attitude、/fmu/in/offboard_control_mode等等。

5.3 ROS 2 工作空间与消息包

要在 ROS 2 里读写这些话题,需要对应的消息定义包。PX4 提供了px4_msgs包,把它 clone 到你的 ROS 2 工作空间里编译:

cd ~/ros2_ws/src git clone https://github.com/PX4/px4_msgs.git cd ~/ros2_ws colcon build source install/setup.bash

编译完px4_msgs,你就能在自定义节点里#include <px4_msgs/msg/vehicle_attitude.hpp>之类的头文件,发布和订阅 PX4 话题了。注意px4_msgs的版本要和你的 PX4 固件版本匹配,版本差太多会出现消息字段对不上的问题。

5.4 Offboard 控制的最小闭环

Offboard 控制的核心逻辑是:外部程序持续以一定频率(通常大于 2Hz)向/fmu/in/offboard_control_mode发送心跳,告诉 PX4 "我还在控制";同时向/fmu/in/trajectory_setpoint或/fmu/in/vehicle_attitude_setpoint发送设定点。PX4 收到足够数量的设定点后,才会允许切换到 Offboard 模式。

一个最小可用的 Offboard 节点大概长这样(伪代码逻辑):

// 定时器 10Hz void timer_callback() { // 1. 发心跳 offboard_control_mode_msg.timestamp = now(); offboard_control_mode_pub->publish(msg); // 2. 发设定点 trajectory_setpoint_msg.timestamp = now(); trajectory_setpoint_msg.position = {0, 0, -5}; // 悬停 5 米 trajectory_setpoint_pub->publish(msg); }

启动节点后,在 QGC 里切 Offboard 模式,飞机应该会起飞到 5 米高度悬停。如果切不过去,检查心跳频率够不够、设定点有没有发出去、飞机有没有解锁。

提示:Offboard 模式下如果外部程序停止发送设定点超过一定时间(默认 0.5 秒左右),PX4 会自动退出 Offboard 并执行失效保护。调试的时候如果程序崩了,飞机可能会直接掉下来,所以建议先在低空、有保护的情况下测试。

6. 整套链路联调时我踩过的坑和排查方法

6.1 时间戳不同步导致消息被丢弃

PX4 和 ROS 2 对消息时间戳的处理比较严格。如果 ROS 2 节点发出去的消息时间戳和 PX4 内部时钟差太多,PX4 会认为消息过期直接丢弃。仿真里 PX4 用的是仿真时间,ROS 2 默认用的是系统时间,两者不一致就会出问题。

解决办法是在 ROS 2 节点里用 PX4 发布的时间戳作为基准,或者配置 ROS 2 使用仿真时间。我一般是在节点里订阅/fmu/out/vehicle_attitude,拿它的 timestamp 作为当前时间,再填到要发的消息里,这样时间戳就对齐了。

6.2 话题名对不上

PX4 的 uORB 话题经过 XRCE-DDS 映射后,话题名会带上/fmu/out/或/fmu/in/前缀。out是 PX4 往外发的(ROS 2 订阅),in是 PX4 往里收的(ROS 2 发布)。新手容易搞反,把该订阅的写成发布,结果一直收不到数据。用ros2 topic list和ros2 topic info确认话题方向和类型,能省很多时间。

6.3 Gazebo 卡顿拖垮整个仿真

Gazebo 是吃 CPU 和 GPU 的大户。如果你的机器性能一般,仿真跑起来后 PX4 的控制频率会跟着掉,表现为飞机响应迟钝甚至失控。优化方向有几个:降低 Gazebo 的物理更新率、关掉不必要的光照和阴影、减少场景里的物体数量、用 headless 模式(不开 Gazebo 界面)跑纯算法验证。

headless 模式特别适合做批量测试,命令大概是:

make px4_sitl gazebo-classic HEADLESS=1

没有界面渲染,CPU 占用大幅下降,仿真速度能快不少。等算法调好了再开界面看效果。

6.4 虚拟机里的网络与端口问题

在虚拟机里跑这套环境,UDP 端口有时候会被宿主机的防火墙或者虚拟网络配置挡住。表现是 QGC 连不上、XRCE Agent 连不上。排查方法是先在虚拟机内部用netstat -anu看端口有没有在监听,再从宿主机 ping 一下虚拟机,确认网络通。如果用的是 NAT 模式,可能需要改成桥接模式,或者手动做端口转发。

7. 从跑通到用好:一些提升效率的实践建议

环境跑通只是第一步,真正做开发的时候,效率差异体现在细节上。我自己的习惯是写一个启动脚本,把 PX4、Gazebo、XRCE Agent、QGC、ROS 2 节点的启动顺序和参数都固化下来,一条命令拉起整套环境。这样每次调试不用重复敲命令,也避免了漏启动某个组件。

另外建议把常用的 Offboard 控制逻辑封装成 ROS 2 的 launch 文件,参数通过 yaml 配置,切换测试场景时只改配置不改代码。PX4 的参数也可以用脚本批量下发,避免每次重启仿真都手动在 QGC 里点一遍。

还有一点,仿真里验证过的控制逻辑,上真机前一定要重新检查安全逻辑,比如失效保护、地理围栏、失控返航这些。仿真环境太理想,很多边界情况不会暴露,真机上出问题代价就大了。我见过不少人在仿真里飞得很顺,一上真机就炸机,基本都是忽略了仿真和现实的差距。

最后,PX4 的日志系统很强大,仿真跑完后可以用 Flight Review 分析飞行数据,看姿态跟踪误差、电机输出、EKF 状态。养成看日志的习惯,很多隐藏的问题能在早期发现,比等到炸机再回头查要划算得多。

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

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

立即咨询