飞控固件基础:PX4与ArduPilot两大开源体系

做飞控系统这么多年,我经常被问到同一个问题:「新手该学PX4还是ArduPilot?」

说实话,这问题没有标准答案。但如果你理解了它们的底层逻辑,选择就变得简单了。今天我就把这两大固件体系掰开揉碎,讲讲它们的架构差异、核心机制,以及怎么把编译环境搭起来。

两大固件体系的核心差异

先看一张对比图,心里有个整体印象。

PX4 vs ArduPilot 核心差异 PX4 架构:微内核 + uORB 消息总线 模块:独立进程,通过 uORB 通信 语言:C++,NuttX RTOS 适合:学术、工业、深度定制 ArduPilot 架构:单进程 + 调度器 + 库 模块:共享内存,函数调用 语言:C++,ChibiOS / Linux 适合:航模、商业、快速部署 共同点:都支持多旋翼/固定翼/直升机/车/船,都支持 MAVLink 协议 选择建议:想深入底层学 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 订阅者开始,打印传感器数据到控制台。等你熟悉了消息流,再慢慢深入。