飞控固件基础:PX4与ArduPilot两大开源体系
做飞控系统这么多年,我经常被问到同一个问题:「新手该学PX4还是ArduPilot?」
说实话,这问题没有标准答案。但如果你理解了它们的底层逻辑,选择就变得简单了。今天我就把这两大固件体系掰开揉碎,讲讲它们的架构差异、核心机制,以及怎么把编译环境搭起来。
两大固件体系的核心差异
先看一张对比图,心里有个整体印象。
PX4 的 uORB 消息总线机制
PX4 最让我欣赏的设计,就是 uORB。说白了,它是一个轻量级的发布-订阅消息总线。
每个飞控模块都是一个独立进程。传感器数据、姿态估计、控制指令……全都通过 uORB 传递。模块之间不直接调用,只通过消息耦合。
uORB 的核心概念:
- 主题(Topic):消息的唯一标识,比如
sensor_accel、vehicle_attitude - 发布者(Publisher):产生数据的模块,比如 IMU 驱动发布加速度数据
- 订阅者(Subscriber):消费数据的模块,比如 EKF 订阅加速度数据
- 多对多:一个主题可以有多个发布者和多个订阅者
我在一个项目中遇到过这样的坑:两个传感器驱动同时往同一个 uORB 主题写数据,结果数据打架,姿态估计直接飘了。后来加了互斥锁才解决。嗯,uORB 本身不保证线程安全,这点要记住。
ArduPilot 的调度器与库架构
ArduPilot 走的是另一条路。它把所有模块编译成一个单进程,通过调度器(Scheduler)来管理任务执行顺序。
你想想看,这样做的好处是什么?
- 低延迟:函数直接调用,没有进程间通信开销
- 内存紧凑:共享全局变量,适合资源受限的 MCU
- 调试方便:单进程,gdb 一把梭
但代价也很明显:一个模块崩了,整个飞控就挂了。PX4 的进程隔离在这里就体现出优势了。
| 对比维度 | PX4 | ArduPilot |
|---|---|---|
| 进程模型 | 多进程,独立地址空间 | 单进程,共享地址空间 |
| 模块通信 | uORB 消息总线 | 函数调用 + 共享变量 |
| 实时性 | 依赖 NuttX 调度 | 自定义调度器,确定性高 |
| 模块隔离 | 强(进程级) | 弱(模块间可互相影响) |
| 扩展性 | 高(新增模块不影响其他模块) | 中(需注意调度时序) |
| 学习曲线 | 陡峭(理解 uORB 和进程模型) | 平缓(单进程,逻辑直观) |
固件编译环境搭建:Ubuntu + PX4 Toolchain
好,理论说完了,咱们动手。我建议你直接用 Ubuntu 20.04 或 22.04 LTS,别折腾虚拟机里的 Windows 了——我在 Windows 上踩过太多坑,WSL 虽然能用,但 USB 透传经常出问题。
第一步:安装依赖
# 更新系统
sudo apt update && sudo apt upgrade -y
# 安装基础工具
sudo apt install -y \
git zip cmake build-essential \
ninja-build colordiff \
python3 python3-pip python3-dev \
python3-venv python3-empy \
python3-jinja2 python3-yaml \
python3-numpy python3-matplotlib \
python3-serial python3-toml \
python3-requests python3-pygments
# 安装交叉编译工具链
sudo apt install -y \
gcc-arm-none-eabi \
gdb-multiarch \
openocd
我的习惯:每次装完依赖,我都会跑一遍 arm-none-eabi-gcc --version 确认版本。如果低于 10.3,建议手动装新版。PX4 对编译器版本有要求,太老的版本编译会报错。
第二步:克隆 PX4 源码
# 创建工作目录
mkdir -p ~/px4_workspace
cd ~/px4_workspace
# 克隆稳定版(别用 main 分支,那是开发版)
git clone https://github.com/PX4/PX4-Autopilot.git --branch v1.14.3
cd PX4-Autopilot
# 初始化子模块
git submodule update --init --recursive
这里有个坑:子模块下载特别慢,尤其是某些被墙的仓库。我曾经等了一个小时还没下完……后来换了国内镜像才搞定。
避坑指南:如果子模块下载失败,可以手动修改 .gitmodules 文件,把 url 换成国内镜像地址。比如 https://github.com 换成 https://gitclone.com/github.com。
第三步:安装 PX4 专用工具链
# 运行自动安装脚本
bash ./Tools/setup/ubuntu.sh
# 安装完成后,重启终端或重新加载环境
source ~/.bashrc
这个脚本会自动安装所有 PX4 需要的工具,包括 px4_uploader、genromfs 等。我个人习惯在跑完脚本后,手动检查一下 python3 -m pip list | grep px4,确保 px4tools 装上了。
第四步:编译测试
# 以 Pixhawk 4 为例
make px4_fmu-v5_default
# 如果只想编译特定模块,可以加目标
# make px4_fmu-v5_default upload # 编译并上传
第一次编译大概要 15-30 分钟,取决于你的电脑性能。编译完成后,你会看到类似这样的输出:
-- Build files have been written to: /home/user/px4_workspace/PX4-Autopilot/build/px4_fmu-v5_default
[100%] Built target px4_fmu-v5_default
常见编译错误及解决:
- 找不到
arm-none-eabi-gcc:检查 PATH,或者重新安装 gcc-arm-none-eabi - Python 模块缺失:
pip3 install --user -r requirements.txt - 内存不足:编译时加
-j2限制并行任务数 - 子模块未更新:重新跑
git submodule update --init --recursive
ArduPilot 编译环境(快速对比)
虽然本章重点讲 PX4,但 ArduPilot 的环境搭建我也提一嘴,方便你对比。
# 克隆 ArduPilot
git clone https://github.com/ArduPilot/ardupilot.git
cd ardupilot
git submodule update --init --recursive
# 安装依赖
Tools/environment_install/install-prereqs-ubuntu.sh -y
# 编译(以 CubeOrange 为例)
./waf configure --board CubeOrange
./waf copter
ArduPilot 用 waf 构建系统,和 PX4 的 cmake + make 风格完全不同。我个人觉得 waf 的配置更简洁,但调试信息不如 cmake 直观。
模块化设计:为什么它如此重要?
不管是 PX4 还是 ArduPilot,都强调模块化设计。为什么?
- 可维护性:改一个模块不影响其他模块
- 可测试性:每个模块可以单独单元测试
- 可复用性:同一个模块可以在不同机型上复用
- 可扩展性:加新功能就像插积木
我记得有一次,客户要求在现有飞控上加一个自定义的避障算法。在 PX4 上,我只需要写一个新的 obstacle_avoidance 模块,发布 vehicle_obstacle 主题,然后让位置控制器订阅它就行。整个过程没动一行原有代码。这就是模块化的威力。
小建议:刚开始学飞控开发时,别急着改核心模块。先从写一个简单的 uORB 订阅者开始,打印传感器数据到控制台。等你熟悉了消息流,再慢慢深入。