☰
PX4仿真环境搭建全攻略:从Gazebo到MAVROS的完整实践指南
2026/10/5 1:15:23 网站建设 项目流程

1. 这次为什么又折腾了一遍PX4仿真环境

先说结论:这不是我第一次搭PX4仿真环境,但确实是踩坑踩得最值的一次。第一次搭建的时候,我照着网上的教程一步步来,结果卡在编译环节整整两天,最后勉强跑起来一个不带相机、不带里程计的裸机仿真,连offboard模式都没测利索。这次重新搭,一方面是换了新电脑想从零走一遍完整流程,另一方面也是因为之前对PX4仿真的理解太浅——只会敲make px4_sitl gazebo这种命令,根本不知道背后发生了什么,更不知道怎么改参数、怎么加传感器模型。第二次搭建最大的不同在于,我不再满足于“能跑起来”,而是想真正搞懂这套仿真链路是怎么串起来的。

如果你正准备接触PX4仿真,或者已经装了半截发现跑不通,这篇记录应该能帮你省下大量试错时间。文章会按照实际搭建顺序展开,从环境准备、源码编译、固件构建,到Gazebo仿真启动、QGroundControl地面站连接,再到MAVROS与ROS2的桥接,整个过程全部记录下来。里面会涉及一些命令行操作和配置文件修改,但不会堆砌术语,每一步我都会解释清楚为什么这么做、不这么做会有什么后果。

先说一个重要判断:PX4仿真环境的搭建难度,80%集中在环境依赖的处理上,而不是PX4代码本身。PX4的源码编译本身并不复杂,真正折磨人的是Ubuntu版本、Gazebo版本、ROS版本、显卡驱动、CMake缓存这几样东西之间的隐性冲突。如果你之前在任何教程里看到过“我按照这篇文章一步步做就成功了”,那大概率是运气好——因为不同机器上预装的库版本差异,会导致完全不同的报错内容。所以这篇记录会特别强调“排查思路”而不是“标准答案”,你要学的不是某一条命令,而是当命令报错时,知道去哪里看日志、改什么参数、查什么依赖。

2. 搭建前的思路梳理与整体规划

2.1 先明确PX4仿真的完整链路

很多人第一次搭PX4仿真时,会直接搜索“PX4仿真环境搭建”,然后照着教程复制粘贴命令,跑起来一个窗口就觉得自己完成了。但如果你不知道这个窗口里运行的到底是什么,后面改需求时会寸步难行。

完整的PX4 SITL(Software In The Loop,软件在环)仿真链路是这样的:PX4飞控程序本身,也就是固件,是在你电脑上以进程方式运行的,它并不知道自己是在真实硬件上还是在模拟环境里。飞控的传感器数据(IMU、气压计、GPS、磁力计等)来自Gazebo仿真器里模拟出来的世界。Gazebo负责物理引擎计算和渲染,把虚拟世界里的无人机状态反馈给PX4。两者之间通过MAVLink协议通信,通常是UDP端口。地面站(QGroundControl)也通过MAVLink连接PX4进程,用于显示状态、发送指令。

这条链路里有三个独立的大件:PX4固件、Gazebo仿真器、QGroundControl地面站。它们各自有各自的依赖和启动方式,但只要理清了“谁给谁发数据、谁依赖谁启动”这个关系,后续的故障排查就变得非常简单。

2.2 版本选型是成败的关键

第二次搭建时,我在版本选择上比第一次谨慎得多。原因很直接:PX4的master分支一直在更新,Gazebo的版本也从老版的Gazebo 9/11过渡到了Gazebo Classic和新的Gazebo(Ignition),ROS这边还有ROS1 Noetic和ROS2 Humble/Iron等版本。如果你不刻意锁定版本,直接git clone最新代码,很可能碰到今天能编译、下周就被某个依赖更新搞挂的情况。

我的建议是:不要追求最新版本。PX4官方文档会告诉你不同Ubuntu版本对应哪些Gazebo版本,但你真正要关注的是“你打算用哪个版本长期开发”。如果你只是练习仿真,建议选择LTS(长期支持)组合:Ubuntu 20.04 + ROS Noetic + Gazebo 11 + PX4 v1.13或v1.14。如果你需要ROS2,那就选Ubuntu 22.04 + ROS2 Humble + Gazebo Classic(默认随PX4附带)+ PX4 v1.14或以上。

我在这次搭建中选择的是Ubuntu 22.04 + ROS2 Humble + PX4 v1.14.3稳定分支,Gazebo用的是PX4自带工具链安装的Gazebo Classic 11。为什么要选稳定分支而不是main?因为main分支的开发进度快,但偶尔会引入需要额外安装的依赖,对新手不友好。稳定分支可能在某些特性上落后几个月,但胜在“社区验证过的人多,坑基本都被踩平了”。

2.3 磁盘空间与硬件配置的提前规划

这是很多人忽略但影响巨大的点。PX4源码加上Gazebo模型库、编译中间文件、ROS2环境,全部加起来至少需要30GB左右的磁盘空间。而且编译过程中会生成大量小文件,机械硬盘的编译速度会比固态硬盘慢好几倍。如果你是用虚拟机装的Ubuntu,还要注意给虚拟机分配的内存不能太少——PX4编译时建议至少4GB内存,Gazebo运行时又需要额外的内存,总共8GB是底线,16GB才够宽敞。

我在这次搭建前,先检查了磁盘剩余空间、CPU核数和内存大小。编译时可以开多线程加速,用make -j$(nproc),但如果你内存不够,开太多线程会导致内存溢出直接编译失败。我的机器是8核16线程、32GB内存,编译时用make -j12,整个过程大约15分钟完成。如果你只有4核8GB内存,建议用make -j4,编译时间会长一些,但至少不会崩。

3. 核心依赖与前置知识准备

3.1 Ubuntu系统的初始配置与换源

拿到一台新装的Ubuntu 22.04,第一件事不是装PX4,而是先把系统的基础环境配置好。这里我强烈建议先更换apt软件源,因为默认源在国内的下载速度实在感人,尤其是安装一些基础依赖包时,动辄几百MB的下载量,慢的话能等半小时。

换源的操作很简单:编辑/etc/apt/sources.list,把archive.ubuntu.com替换为国内镜像源地址,比如清华源或阿里源。然后执行sudo apt update和sudo apt upgrade把系统更新到最新状态。这一步之所以放在最前面,是因为后面安装的所有依赖都依赖apt源,如果源本身有问题,后面每装一个包都会卡壳。

基础工具链也需要提前装好:build-essential(编译工具)、git、cmake、python3-pip、ninja-build等。这些是PX4编译的必要条件,但不同版本的PX4对cmake版本有要求——PX4 v1.14要求cmake 3.10.2以上,Ubuntu 22.04自带的cmake版本是3.22,满足要求。如果你用的是Ubuntu 20.04,自带cmake是3.16,也满足要求。这里不用特意升级cmake,系统自带版本就能用。

3.2 自动脚本与手动安装的选择

PX4官方文档提供了一个自动安装脚本ubuntu_sim_common_deps.sh,可以帮你装好Gazebo、ROS、MAVROS等一系列依赖。第一次搭建时,我就直接跑了这个脚本,结果出了不少问题——脚本里有些依赖包的版本和我系统里已有的包冲突,而且脚本运行完之后,你根本不知道它装了哪些东西、改了什么配置。出了问题时很难排查。

第二次搭建时,我改用“半自动”方式:官方脚本照跑,但每执行一步,都记录下这一步装了什么、输出了什么警告。如果脚本中途报错,就去查对应包的安装方法,而不是盲目重跑。这样做的好处是,如果最终编译失败,我能清楚地知道是哪一步引入的问题,而不是对着一个黑洞一样的“一键安装”脚本束手无策。

如果你是新手,我建议这样操作:先跑官方脚本,如果成功,恭喜你可以直接跳到编译环节;如果失败,再回到我这篇文章的排查部分,按图索骥。不要死磕脚本——脚本失败不等于环境有问题,很多时候只是某个包的下载源临时不可达。

3.3 认识目录结构:PX4源码在电脑上是怎么组织的

PX4源码克隆下来后,你会看到一个名为PX4-Autopilot的目录,这个目录就是整个飞控固件的家。里面有几个子目录特别重要:src/存放着飞控的核心代码,包括模块、驱动等;Tools/存放仿真相关工具,比如sitl_gazebo子模块就是Gazebo仿真器的桥接插件;build/目录是编译输出目录,编译产生的所有二进制文件都在这里;ROMFS/存放文件系统镜像,里面包含参数定义、启动脚本等。

新建终端进入PX4源码目录后,你需要先运行一条命令来加载环境变量:source Tools/setup_gazebo.bash $(pwd) $(pwd)/build/px4_sitl_default。这条命令会把Gazebo插件路径、模型路径等环境变量注入当前终端,这样Gazebo启动时才能找到PX4提供的传感器模型和世界文件。

这也是新手最容易忽略的一步:如果你没有source这个脚本,Gazebo也能启动,但你会发现无人机模型加载不出来,或者加载出来了但没有传感器数据。因为Gazebo不知道去哪里找那些模型插件。每次新开终端都需要重新source一次,这个问题我会在后面反复强调。

4. 实操全过程:从源码拉取到仿真跑通

4.1 第一步:拉取PX4源码并切换到稳定分支

打开终端,进入你准备存放源码的目录(我建议放在主目录下,路径中不要有中文和空格),执行:

git clone https://github.com/PX4/PX4-Autopilot.git --recursive

这个--recursive参数非常重要,它会把PX4依赖的子模块一并拉取下来。如果你忘了加这个参数,后续编译时会提示缺少子模块,此时需要进入目录执行git submodule update --init --recursive来补拉。但这里有个坑:PX4的子模块数量非常多,而且有些子模块在国外的服务器上,下载速度极慢,甚至经常失败。如果你网络状况不好,建议直接使用国内镜像源加速:

git clone https://ghproxy.com/https://github.com/PX4/PX4-Autopilot.git --recursive

或者先用git clone拉取主仓库,再手动配置子模块的URL为镜像地址。但这个操作比较复杂,不太适合新手。我的建议是直接用官方源拉取,如果子模块下载失败,就反复执行git submodule update --init --recursive,不要因为一次失败就放弃——多试几次,失败的子模块会被逐个补齐。

源码拉取完成后,立即切换分支。执行git branch -a查看所有分支,找到v1.14.3或你选择的其他稳定版本标签,执行:

git checkout v1.14.3 git submodule update --init --recursive

切换到稳定分支后也要再更新一次子模块,因为不同分支对应的子模块版本可能不同。这一步完成后,你的源码就处于一个“固定版本”的状态,后续不会因为远端更新而变动。

4.2 第二步:安装系统依赖与Gazebo

PX4官方提供了一个安装脚本PX4-Autopilot/Tools/setup/ubuntu.sh,直接执行:

bash ./PX4-Autopilot/Tools/setup/ubuntu.sh

这个脚本会安装PX4编译所需的所有依赖,包括Gazebo、ROS(如果你选择ROS版本)、MAVROS、Python包等。但脚本运行时间很长,而且中途大概率会卡在某一步。我的经验是分步骤执行,先安装基础依赖:

sudo apt-get install -y \ build-essential \ cmake \ git \ curl \ wget \ python3-pip \ python3-venv \ ninja-build \ autoconf \ automake \ libtool \ pkg-config

然后再单独安装Gazebo。Ubuntu 22.04上PX4默认使用Gazebo Classic,安装命令是:

sudo apt-get install -y gazebo libgazebo11-dev

Gazebo安装完成后,执行gazebo --version,如果能看到版本号,说明安装成功。这里注意:Ubuntu 22.04的默认Gazebo版本是11,如果你在终端输入gazebo启动的却是新版的Gazebo(Ignition),说明你的环境里同时装了新旧两个版本,输入gazebo命令会启动旧版,输入ign gazebo才会启动新版。PX4的仿真脚本默认调用的是gazebo命令,所以旧版的存在是必要的。

接下来,不要急着跑PX4编译,先测试一下Gazebo本身能不能正常启动。在终端输入gazebo,等待几秒,如果出现一个3D模拟窗口,说明Gazebo没问题。如果启动失败,大概率是显卡驱动问题——我在下面问题排查部分会专门讲。

4.3 第三步:编译PX4固件

进入源码目录,执行:

cd PX4-Autopilot make px4_sitl gazebo-classic

这条命令做了三件事:编译PX4飞控固件(SITL版本)、编译Gazebo的PX4插件、启动Gazebo仿真。第一次编译时,系统会先下载一些模型文件,然后开始漫长的编译过程。

编译时你会看到大量的[ xx%]进度提示,这个过程可能持续10-30分钟,具体取决于你机器性能。编译过程中,屏幕上可能会出现一些warning(警告),不用慌张,只要不是error(错误),就不会影响最终结果。

有一个常见问题是编译过程中内存耗尽。如果你发现编译中途进程被系统杀掉,或者报出internal compiler error,多半是内存不够。解决办法是在make时限制并行编译线程数:

make px4_sitl gazebo-classic -j4

-j后面的数字就是你希望使用的线程数,4表示同时编译4个文件。线程数少一些,编译慢一些,但不容易崩。

编译完成后,如果一切顺利,终端会停留在PX4 shell提示符下(类似pxh>),同时Gazebo窗口会打开,里面有一架多旋翼无人机。这说明你的仿真环境已经跑起来了。在PX4 shell里输入commander takeoff,无人机就会起飞——当然,前提是所有传感器都正常工作。

4.4 第四步:启动QGroundControl地面站

单独的PX4仿真窗口只能看到无人机在Gazebo里飞行,但无法直观地看到飞控状态、参数、日志等信息。这时候需要启动QGroundControl地面站。

去QGroundControl官网下载对应Ubuntu版本的AppImage文件。下载完成后,赋予执行权限:

chmod +x QGroundControl.AppImage ./QGroundControl.AppImage

启动地面站后,它会自动通过UDP端口14550连接PX4仿真进程。如果连接成功,你会看到地面站界面右上角出现一个绿色的连接指示灯,同时能看到无人机当前的姿态、高度、GPS状态等信息。这里注意:QGroundControl连接的是PX4 SITL进程,而不是Gazebo——PX4进程和Gazebo插件之间通过另一个UDP端口(14557)通信,地面站和PX4通过14550端口通信。

有时候地面站启动后无法连接仿真,最常见的原因是Gazebo还没启动完成,PX4进程还没进入等待连接的状态。解决办法是等Gazebo完全启动、PX4 shell出现后,再打开QGroundControl。

4.5 第五步:验证offboard模式与MAVROS桥接

纯PX4仿真的关键验证点是能否通过外部指令控制无人机——也就是offboard模式。在PX4仿真中,最常见的控制方式是通过MAVROS包将ROS消息发送给PX4。

安装MAVROS的方法在PX4官方文档里有详细教程,核心是添加ROS源后用apt安装。安装完成后,需要配置PX4飞控的仿真参数,在QGroundControl的连接页面中,确保MAVLink参数里的MAV_PROTO_VER设置为2.0(默认就是2.0)。然后在终端启动MAVROS:

roslaunch mavros px4.launch fcu_url:="udp://:14540@127.0.0.1:14557"

这条命令会让MAVROS作为MAVLink客户端,连接本机的14557端口,也就是PX4 SITL监听的端口。连接成功后,你可以用rostopic echo /mavros/state查看飞控状态,其中connected字段应该为true。

然后,就可以写一个简单的offboard控制脚本了。这里我提供一个最简单的Python示例,先切换offboard模式,再发送位置指令:

#!/usr/bin/env python3 import rospy from geometry_msgs.msg import PoseStamped from mavros_msgs.msg import State from mavros_msgs.srv import CommandBool, SetMode rospy.init_node('offboard_test') state = State() def state_cb(msg): global state state = msg rospy.Subscriber('/mavros/state', State, state_cb) pose_pub = rospy.Publisher('/mavros/setpoint_position/local', PoseStamped, queue_size=10) arming_client = rospy.ServiceProxy('/mavros/cmd/arming', CommandBool) set_mode_client = rospy.ServiceProxy('/mavros/set_mode', SetMode) # 先发送一些期望位置,让飞控有初步的设定点 pose = PoseStamped() pose.pose.position.x = 1.0 pose.pose.position.y = 1.0 pose.pose.position.z = 2.0 rate = rospy.Rate(10) # 10Hz for _ in range(100): pose_pub.publish(pose) rate.sleep() while not rospy.is_shutdown(): if not state.armed: arming_client(True) if state.mode != "OFFBOARD": set_mode_client(0, "OFFBOARD") pose_pub.publish(pose) rate.sleep()

运行这个脚本后,如果一切正常,无人机会起飞飞到(1, 1, 2)的位置。这是PX4仿真环境搭建成功的最有力证明。

5. 常见问题与排查技巧实录

5.1 编译报错排查:从日志中找到关键信息

PX4编译失败时,终端会打印一大段错误信息,新手往往看得一头雾水。我的经验是:先找error:关键词,它会直接告诉你哪个文件哪一行出了问题。最常见的编译错误有几类:

  • 缺依赖:提示找不到某个头文件或库文件,比如fatal error: xxx.h: No such file or directory。这种问题最简单,去网上搜索这个头文件属于哪个包,然后apt install即可。比如rapidjson相关的头文件缺失,就执行sudo apt install rapidjson-dev。
  • CMake配置错误:提示CMake Error,说找不到某个包。这就需要检查你是否漏装了对应的开发包。例如提示找不到GStreamer,就安装libgstreamer1.0-dev和libgstreamer-plugins-base1.0-dev。
  • 编译缓存冲突:如果你之前用旧版本的PX4编译过,再次编译新版本时可能因为build目录下的缓存文件导致错误。解决办法是删除build/px4_sitl_default目录,重新编译。

我把这几个问题整理成一个速查表,方便你对照排查。

报错关键词可能的根因解决办法
No such file or directory缺少某个头文件使用apt-file search或搜索工具查找所属包并安装
Could not find a package configuration fileCMake无法找到依赖包检查该包的-dev版本是否安装
undefined reference库文件未链接检查CMakeLists.txt中是否有对应的target_link_libraries
internal compiler error内存不足或编译线程过多减少-j参数,或增加系统内存

还有一个很隐蔽的问题:如果你在编译过程中切换了PX4的git分支,但没有清理之前的编译缓存,偶尔会出现“修改不生效”的诡异问题。解决方法永远是那三板斧:删掉build目录、重新source环境变量、重新编译。

5.2 Gazebo启动失败与模型加载不出来的处理

Gazebo启动异常是仿真环境搭建中最常见的问题。正常情况下,PX4启动后Gazebo会自动打开,里面有一架无人机模型盘旋(也就是在地面上微微震动)。如果你看到Gazebo窗口打开了,但里面是空白世界,没有无人机模型,或者模型显示为灰色/半透明,这通常是模型加载路径有问题。

检查方法:单独开一个终端,手动执行模型加载命令:

source Tools/setup_gazebo.bash $(pwd) $(pwd)/build/px4_sitl_default echo $GAZEBO_MODEL_PATH

如果$GAZEBO_MODEL_PATH为空,说明环境变量没有生效。你需要确认启动PX4的那个终端是否执行过source命令。记住:每次新开终端,都要先source环境变量,再启动仿真,否则Gazebo不会加载模型。

还有一种情况是Gazebo启动后卡死,窗口不刷新,无人机模型没出现。如果是虚拟机,这个问题尤其常见——Gazebo依赖OpenGL渲染,虚拟机默认的显卡驱动性能极差。如果你用的是VMware或VirtualBox,建议在虚拟机设置里启用3D加速,或者安装VMware Tools/增强功能。如果还是卡死,可以在Gazebo启动前设置环境变量禁用GPU渲染:

export LIBGL_ALWAYS_SOFTWARE=1

这会强制使用软件渲染,画面会卡一些,但至少不会崩溃。

5.3 QGroundControl连接不上仿真的排查思路

QGroundControl无法连接仿真进程的表现是:地面站右上角一直显示“未连接”,没有无人机状态信息。这种情况通常有以下几个原因。

第一,PX4 SITL进程没启动成功。检查PX4源码目录的终端,看看是否有pxh>提示符。如果PX4进程根本没启动,QGroundControl自然连不上。第二,PX4进程和QGroundControl的通信端口被防火墙拦截。Ubuntu的ufw防火墙默认不拦截UDP广播,但如果你手动配置过防火墙规则,可能会屏蔽14550端口。执行sudo ufw disable暂时关闭防火墙试试。第三,QGroundControl版本太新,对MAVLink协议版本的要求与PX4固件不兼容。建议下载QGroundControl的稳定版,不要用最新的Daily版本。

如果以上都排除了,可以在终端里看一下PX4启动时是否有MAVLink相关的输出。正常情况下,启动仿真后终端会显示类似MAVLink: creating UDP server的日志,后面会带上端口号。如果你看到端口号不是14550,说明PX4配置不同,QGroundControl连接时也要调整端口。

5.4 MAVROS连不上飞控的检查清单

MAVROS连接不上时,先运行rostopic echo /mavros/state看看数据有没有进来。如果这个topic没有输出,说明MAVROS到PX4的链路不通。这时候按照这个顺序排查:

第一步,确认PX4仿真进程在运行。第二步,确认MAVROS启动命令中fcu_url的端口号和PX4监听的端口号一致。第三步,确认MAVROS的UDP端口没有被占用,netstat -ulnp | grep 14540能看到MAVROS进程监听在14540端口。第四步,检查ROS主节点是否启动——如果你是用roscore方式启动的MAVROS,要先执行roscore,再启动MAVROS节点。如果你是用roslaunch启动的,它会自动启动ROS Master,不用手动执行roscore。

这里有个容易忽略的坑:MAVROS启动时,对PX4的MAVLink协议版本有要求。PX4 v1.14默认使用MAVLink 2.0,而MAVROS也同时支持1.0和2.0,正常情况下两者能自动协商。但如果你在源码中手动改过MAV_PROTO_VER参数,可能会造成版本不匹配,导致MAVROS能连接到端口但收不到有效数据。检查QGroundControl中该参数的值,确保是2。

5.5 我踩过的一个隐蔽的坑:编译子模块版本不匹配

最后分享一个我在第二次搭建时踩过的坑,这个坑在网上的教程里几乎没人提到。PX4源码使用git子模块来管理Gazebo相关插件,但子模块的版本可能和主仓库存放的版本不一致。如果你直接克隆的是v1.14.3标签,然后执行子模块更新,此时子模块的版本会自动切换到与该标签匹配的版本,一般不会出问题。但如果你之前在main分支上更新过子模块,再切换回稳定分支,子模块并不会自动变回旧版本,仍然是main分支对应版本。

这时候编译期间可能出现莫名其妙的功能变化,比如某个传感器模型的参数不对,或者Gazebo启动时加载了一个新版本插件。解决办法很简单:切换分支后,强制更新子模块到分支对应的版本:

git submodule sync --recursive git submodule update --init --recursive --force

--force会强制覆盖本地子模块的修改,确保和远端版本完全一致。这个坑的排查方法也很简单:进入Tools/sitl_gazebo目录,执行git status,如果显示有修改或不在预期的分支,说明子模块版本有问题,强制更新即可。

6. 一点真实感受:第二次搭建带来的认知提升

第二次搭建PX4仿真环境,明显比第一次从容了很多。这不仅仅是技术熟练度的问题,更关键的是对整套系统有了更清晰的认识——我知道Gazebo挂了应该去哪里查模型路径,知道MAVROS连不上应该先看端口而不是重装系统,知道编译失败时最该做的是看日志关键词而不是满屏复制给搜索引擎。这种“知道去哪里找问题”的掌控感,才是搭建过程中最宝贵的收获。

如果让我给正准备入门的读者一个建议,我想说的是:不要害怕报错。PX4仿真环境的报错信息虽然多,但绝大多数错误都是可以追根溯源的。碰到问题时,先打开一个新的终端,敲几下echo $环境变量看看路径对不对,或者去PX4源码目录的build目录下找CMakeCache.txt看看有没有残留配置。这种“自己动手查一层”的习惯,比任何现成教程都能让你更快地成长。

最后分享一个小技巧:在你的Ubuntu主目录下创建一个别名文件,把常用的source和启动命令写成一条自定义命令,比如:

alias px4_sitl='cd ~/PX4-Autopilot && source Tools/setup_gazebo.bash $(pwd) $(pwd)/build/px4_sitl_default && make px4_sitl gazebo-classic'

这样每次打开新终端,只需输入px4_sitl就能一键启动仿真环境,不再需要忍受一长串命令和反复记忆路径。这个小改动,能让你把更多精力放在飞控逻辑本身,而不是环境搭建上。

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

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

立即咨询