PX4 v1.16.0仿真环境搭建实战:解决编译卡死与网络超时问题

本文详细记录了在WSL2 Ubuntu 22.04环境中搭建PX4 v1.16.0无人机仿真环境的完整过程,重点解决了编译过程中遇到的网络超时、子模块下载失败、模块编译卡死等实际问题,最终成功实现Gazebo Classic仿真环境并让无人机在仿真中起飞。

1. 环境准备与依赖安装

1.1 系统环境

  • 操作系统: WSL2 Ubuntu 22.04.5 LTS
  • 内存: 16GB (WSL2配置8GB)
  • 存储: 50GB以上可用空间
  • 网络: 国内网络环境(存在GitHub访问限制)

1.2 基础依赖安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 更新系统包
sudo apt-get update

# 安装基本开发工具
sudo apt-get install python3-pip python3-dev python3-wheel python3-setuptools -y
sudo apt-get install git zip qtcreator cmake build-essential genromfs ninja-build exiftool -y

# 安装Gazebo Classic (PX4 v1.16.0推荐使用Gazebo Classic 11)
sudo apt-get install gazebo11 libgazebo11-dev -y

# 安装PX4专用依赖
sudo apt-get install libxml2-dev libxslt1-dev perl python3-pip python3-tk python3-lxml python3-dev python3-numpy python3-matplotlib python3-yaml python3-serial python3-requests -y
sudo apt-get install libopencv-dev libeigen3-dev libgstreamer-plugins-base1.0-dev gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly -y

# 地理空间库
sudo apt-get install libgeographic-dev geographiclib-tools -y
sudo geographiclib-get-geoids egm96-5

2. PX4 v1.16.0源码获取与子模块问题解决

2.1 克隆主仓库

1
2
3
4
5
6
7
8
9
10
# 创建工作目录
mkdir -p ~/drone-simulation
cd ~/drone-simulation

# 克隆PX4-Autopilot仓库
git clone https://github.com/PX4/PX4-Autopilot.git
cd PX4-Autopilot

# 切换到v1.16.0版本
git checkout v1.16.0

2.2 解决子模块网络超时问题(关键步骤)

在默认HTTPS协议下,Git子模块下载经常因网络超时失败。我们采用SSH协议解决此问题:

2.2.1 配置Git全局使用SSH协议

1
2
3
4
5
6
# 检查SSH密钥是否已配置
ssh -T git@github.com
# 如果显示"Hi username! You've successfully authenticated..."则表示SSH配置正确

# 配置Git全局使用SSH替代HTTPS
git config --global url."git@github.com:".insteadOf "https://github.com/"

2.2.2 修改所有.gitmodules文件中的URL

1
2
3
4
5
6
7
8
9
10
11
# 主仓库的.gitmodules
sed -i 's|https://github.com/|git@github.com:|g' .gitmodules

# sitl_gazebo-classic子模块的.gitmodules
sed -i 's|https://github.com/|git@github.com:|g' Tools/simulation/gazebo-classic/sitl_gazebo-classic/.gitmodules

# mavlink子模块的.gitmodules
sed -i 's|https://github.com/|git@github.com:|g' src/modules/mavlink/mavlink/.gitmodules

# 同步子模块配置
git submodule sync

2.2.3 递归初始化子模块

1
2
3
# 清理并重新初始化子模块
git submodule deinit -f --all
git submodule update --init --recursive

注意: 如果递归初始化仍然超时,可以分步初始化关键子模块:

1
2
3
4
5
6
7
8
# 优先初始化核心子模块
for module in "Tools/simulation/gazebo-classic/sitl_gazebo-classic" \
"platforms/nuttx/NuttX/nuttx" \
"platforms/nuttx/NuttX/apps" \
"src/modules/mavlink/mavlink"; do
echo "正在初始化 $module"
git submodule update --init --recursive "$module" || echo "初始化失败: $module"
done

3. 编译问题诊断与解决方案

3.1 首次编译尝试

1
2
3
4
5
6
7
8
# 创建构建目录
mkdir -p build && cd build

# 配置CMake
cmake ..

# 尝试编译
make px4 -j4

3.2 问题一:px_update_git_header.py脚本错误

错误信息:

1
IndexError: list index out of range

原因分析: NuttX子模块缺少版本标签,导致正则表达式匹配失败。

解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 修改文件:src/lib/version/px_update_git_header.py
# 备份原文件
cp src/lib/version/px_update_git_header.py src/lib/version/px_update_git_header.py.backup

# 应用补丁
cat > px_update_git_header.patch << 'EOF'
--- a/src/lib/version/px_update_git_header.py
+++ b/src/lib/version/px_update_git_header.py
@@ -129,8 +129,12 @@
if (os.path.exists("platforms/nuttx/NuttX/nuttx/.git")):
nuttx_git_tags = subprocess.check_output("git -c versionsort.suffix=- tag --sort=v:refname".split(),
cwd="platforms/nuttx/NuttX/nuttx", stderr=subprocess.STDOUT).decode("utf-8").strip()
- nuttx_git_tag = re.findall(r"nuttx-[0-9]+\.[0-9]+\.[0-9]+", nuttx_git_tags)[-1].replace("nuttx-", "v")
- nuttx_git_tag = re.sub("-.*", ".0", nuttx_git_tag)
+ nuttx_matches = re.findall(r"nuttx-[0-9]+\.[0-9]+\.[0-9]+", nuttx_git_tags)
+ if nuttx_matches:
+ nuttx_git_tag = nuttx_matches[-1].replace("nuttx-", "v")
+ nuttx_git_tag = re.sub("-.*", ".0", nuttx_git_tag)
+ else:
+ nuttx_git_tag = "v0.0.0"
nuttx_git_version = subprocess.check_output("git rev-parse --verify HEAD".split(),
cwd="platforms/nuttx/NuttX/nuttx", stderr=subprocess.STDOUT).decode("utf-8").strip()
nuttx_git_version_short = nuttx_git_version[0:16]
EOF

patch -p1 < px_update_git_header.patch

3.3 问题二:uxrce_dds_client模块编译卡死(核心问题)

现象:

  • 编译在modules__uxrce_dds_client目标上无限期挂起
  • 外部依赖Micro-XRCE-DDS-Client下载超时
  • 错误提示缺少dds_topics.h头文件

深度分析:
uxrce_dds_client模块是PX4 v1.16.0新增的DDS通信模块,依赖外部库Micro-XRCE-DDS-Client。在国内网络环境下,该依赖下载极易失败,导致整个编译流程卡死。

解决方案:

方案A:跳过uxrce_dds_client模块(推荐)

1
2
3
4
5
6
7
8
9
10
# 修改模块的CMakeLists.txt文件
vi src/modules/uxrce_dds_client/CMakeLists.txt

# 找到第34行附近的代码:
# if(${CMAKE_VERSION} VERSION_LESS_EQUAL "3.15")
# 修改为:
# if(TRUE)

# 应用修改
sed -i 's/if(${CMAKE_VERSION} VERSION_LESS_EQUAL "3.15")/if(TRUE)/' src/modules/uxrce_dds_client/CMakeLists.txt

方案B:手动生成缺失的头文件

1
2
3
4
5
6
7
8
9
10
11
12
13
# 如果选择编译该模块,需要手动生成dds_topics.h
cd ~/drone-simulation/PX4-Autopilot
python3 src/modules/uxrce_dds_client/generate_dds_topics.py \
--client-outdir build/src/modules/uxrce_dds_client \
--dds-topics-file src/modules/uxrce_dds_client/dds_topics.yaml \
--template_file src/modules/uxrce_dds_client/dds_topics.h.em

# 验证文件生成
ls -la build/src/modules/uxrce_dds_client/dds_topics.h

# 编译events_json目标(依赖dds_topics.h)
cd build
make events_json -j2

3.4 问题三:OpticalFlow子模块的子模块缺失

现象:

1
2
3
4
CMake Error at CMakeLists.txt:XXX (add_subdirectory):
The source directory
[...]/external/OpticalFlow/external/klt_feature_tracker
does not contain a CMakeLists.txt file.

解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 进入OpticalFlow目录
cd Tools/simulation/gazebo-classic/sitl_gazebo-classic/external/OpticalFlow

# 检查.gitmodules文件
cat .gitmodules
# 输出:[submodule "external/klt_feature_tracker"]
# path = external/klt_feature_tracker
# url = https://github.com/ethz-ait/klt_feature_tracker.git

# 修改URL为SSH格式
sed -i 's|https://github.com/ethz-ait/klt_feature_tracker.git|git@github.com:ethz-ait/klt_feature_tracker.git|' .gitmodules

# 同步并更新子模块
git submodule sync
git submodule update --init

4. 完整编译流程

4.1 清理并重新配置构建环境

1
2
3
4
5
6
7
8
9
10
11
# 确保在PX4-Autopilot目录下
cd ~/drone-simulation/PX4-Autopilot

# 清理旧的构建目录
rm -rf build && mkdir build && cd build

# 配置CMake(使用Ninja构建系统,速度更快)
cmake -G Ninja ..

# 或者使用Makefile系统
cmake ..

4.2 分步编译

1
2
3
4
5
6
7
8
9
10
11
12
13
# 1. 编译PX4主程序(跳过uxrce_dds_client模块)
ninja px4
# 或使用make
make px4 -j2

# 2. 编译Gazebo Classic插件
ninja sitl_gazebo-classic
# 或使用make
make sitl_gazebo-classic -j2

# 3. 验证编译结果
ls -la bin/px4
ls -la Tools/simulation/gazebo-classic/sitl_gazebo-classic/build/lib*.so

4.3 编译成功标志

1
2
[100%] Built target px4
[100%] Built target sitl_gazebo-classic

生成的关键文件:

  • build/bin/px4 - PX4 SITL可执行文件(约49MB)
  • build/Tools/simulation/gazebo-classic/sitl_gazebo-classic/build/libgazebo_*.so - Gazebo插件库

5. 启动Gazebo仿真

5.1 直接启动方法

1
2
3
# 在构建目录中运行
cd ~/drone-simulation/PX4-Autopilot/build
make gazebo-classic_iris

5.2 手动启动方法(了解底层原理)

1
2
3
4
5
6
7
8
9
10
# 设置环境变量
export GAZEBO_PLUGIN_PATH=$PWD/Tools/simulation/gazebo-classic/sitl_gazebo-classic/build:$GAZEBO_PLUGIN_PATH
export GAZEBO_MODEL_PATH=$PWD/Tools/simulation/gazebo-classic/sitl_gazebo-classic/models:$GAZEBO_MODEL_PATH
export LD_LIBRARY_PATH=$PWD/Tools/simulation/gazebo-classic/sitl_gazebo-classic/build:$LD_LIBRARY_PATH

# 启动PX4 SITL
./bin/px4 ./etc/init.d-posix/px4-rc.gzsim

# 在另一个终端中启动Gazebo服务器
gzserver Tools/simulation/gazebo-classic/sitl_gazebo-classic/worlds/empty.world

5.3 验证仿真运行状态

1
2
3
4
5
6
7
8
9
10
# 检查进程
ps aux | grep -E '(px4|gazebo|gzserver)' | grep -v grep

# 预期输出示例:
# dminist+ 267074 12.5 0.0 1454428 6400 ? Sl 09:07 0:00 /home/dministrator/drone-simulation/PX4-Autopilot/build/bin/px4 [...]
# dminist+ 266907 31.5 3.4 7227628 280048 ? SLl 09:07 0:00 gzserver [...]
# dminist+ 266911 12.5 1.7 2371192 143616 ? SLl 09:07 0:00 gz model --verbose --spawn-file=... --model-name=iris

# 检查网络连接(PX4默认监听UDP 14550端口)
ss -uln | grep 14550

6. 飞行控制测试

6.1 安装MAVLink工具

1
2
3
4
5
# 安装pymavlink
pip3 install --user pymavlink

# 安装mavproxy(可选)
pip3 install --user mavproxy

6.2 连接PX4 SITL

1
2
3
4
5
6
# 使用mavlink_shell.py连接
cd ~/drone-simulation/PX4-Autopilot
python3 Tools/mavlink_shell.py 0.0.0.0:14550

# 或使用mavproxy
mavproxy.py --master=udp:0.0.0.0:14550 --out=udp:127.0.0.1:14551

6.3 基本飞行命令

1
2
3
4
5
6
7
8
# 在mavlink shell中执行
commander takeoff
commander land
commander arm
commander disarm

# 查看系统状态
commander check

7. 环境优化与配置

7.1 WSL2专用配置

1
2
3
4
5
6
7
8
9
10
# 提高WSL2内存限制(编辑Windows中的.wslconfig文件)
# 文件路径:%USERPROFILE%\.wslconfig
[wsl2]
memory=8GB
swap=4GB
processors=4

# 设置X11转发用于Gazebo图形界面(Windows上安装VcXsrv)
export DISPLAY=$(grep -m 1 nameserver /etc/resolv.conf | awk '{print $2}'):0.0
echo "export DISPLAY=\$(grep -m 1 nameserver /etc/resolv.conf | awk '{print \$2}'):0.0" >> ~/.bashrc

7.2 性能优化

1
2
3
4
5
6
# 使用无头模式运行Gazebo(节省资源)
HEADLESS=1 make px4_sitl gazebo-classic_iris

# 降低Gazebo渲染质量
export GAZEBO_RENDERING_QUALITY=low
export GAZEBO_PHYSICS_UPDATE_RATE=60

8. 常见问题汇总

8.1 网络相关问题

问题 解决方案
Git子模块下载超时 使用SSH协议替代HTTPS,配置全局git替换
外部依赖下载失败 手动下载并放置到指定目录,或使用代理
Gazebo模型下载慢 设置本地模型缓存,或使用离线模型包

8.2 编译相关问题

问题 解决方案
uxrce_dds_client模块卡死 修改CMakeLists.txt跳过该模块
events_json目标失败 手动生成dds_topics.h头文件
内存不足导致编译失败 减少并行编译任务数(使用-j2)
CMake配置失败 清除build目录重新配置

8.3 运行时问题

问题 解决方案
Gazebo无法启动 检查DISPLAY变量设置,或使用无头模式
PX4进程崩溃 检查日志文件,降低仿真复杂度
无法连接QGroundControl 确认UDP端口14550监听正常

9. 项目结构说明

1
2
3
4
5
6
7
8
9
drone-simulation/
|------ PX4-Autopilot/ # PX4源码
| |------ build/ # 构建目录
| | |------ bin/px4 # PX4可执行文件
| | `------ ...
| |------ src/modules/uxrce_dds_client/CMakeLists.txt # 修改过的文件
| `------ Tools/simulation/gazebo-classic/sitl_gazebo-classic/ # Gazebo插件
|------ start_px4_gazebo.sh # 启动脚本
`------ px4-v1-16-0-simulation-guide.md # 本文档

10. 总结与经验分享

10.1 关键技术点

  1. 网络优化:SSH协议是解决Git子模块下载问题的关键
  2. 模块选择性编译:跳过问题模块不影响核心仿真功能
  3. 分步编译:优先编译核心组件,再处理依赖复杂的模块
  4. 环境隔离:WSL2提供与Windows隔离的Linux环境,避免系统污染

10.2 性能评估

  • 编译时间:完整编译约30-45分钟(依赖网络状况)
  • 内存占用:仿真运行时约2-3GB内存
  • CPU占用:Gazebo物理仿真约占用单核30-50%

10.3 适用场景

  • 无人机控制算法开发与测试
  • 视觉SLAM算法集成验证
  • 多机协同仿真实验
  • 教学与科研演示

10.4 后续扩展

  1. 视觉仿真增强:集成3D Gaussian Splatting高保真相机模拟
  2. 多机仿真:配置多个无人机协同飞行
  3. 硬件在环:连接真实飞控进行HIL测试
  4. 云仿真部署:将仿真环境部署到云端服务器

附录:常用命令速查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 编译相关
make px4 -j2 # 编译PX4主程序
make sitl_gazebo-classic # 编译Gazebo插件
make gazebo-classic_iris # 启动Iris无人机仿真

# 网络配置
git config --global url."git@github.com:".insteadOf "https://github.com/"

# 进程管理
ps aux | grep px4 # 查找PX4进程
killall px4 gzserver gzclient # 停止所有仿真进程

# 日志查看
tail -f ~/.px4/log/px4.log # 查看PX4日志
gz log -e -f # 查看Gazebo日志