3. PX4软硬件架构

好,咱们今天来拆解PX4的源码结构。说实话,我第一次接触PX4源码时,也被它的目录层级吓了一跳——东西太多了。但别慌,核心就几个目录:src/modules、src/drivers、src/lib、boards,再加上构建相关的Makefile和Kconfig。搞懂这些,你就抓住了PX4的骨架。

3.1 四大核心目录:各司其职

先看一张整体结构图,我习惯把它叫做“PX4的四层蛋糕”。

PX4 源码核心目录结构 src/modules — 应用模块层 mc_pos_control | navigator | commander | uORB | logger src/drivers — 设备驱动层 gps | imu | baro | magnetometer | pwm_out | rc_input src/lib — 公共库层 mathlib | geo | mixer | parameters | cdev | perf boards — 板级支持包 px4_fmu-v5 | px4_fmu-v6x | sitl | crazyflie 调用关系 模块 → 驱动 → 库 → 板级

这张图我画了好几次才满意。它清晰地展示了调用关系:上层模块调用下层驱动和库,最底层是板级支持。咱们一层层来看。

3.1.1 src/modules — 应用模块

这是PX4的大脑。所有飞控逻辑、导航算法、通信协议都在这里。我挑几个重点说说:

  • mc_pos_control:多旋翼位置控制。我调试过这个模块,里面PID参数调不好,飞机就会像喝醉了一样晃。
  • navigator:任务导航。负责航线跟踪、返航、降落等逻辑。
  • commander:模式切换与状态机。说白了就是控制飞机在“手动/定高/悬停/返航”之间切换。
  • uORB:内部消息总线。所有模块之间通信都靠它,这是PX4的“血管”。
  • logger:数据记录。出问题后分析日志全靠它。

我的习惯:刚接触一个新模块时,先看它的module.yaml文件。这个文件定义了模块的依赖、启动参数和描述,比直接读代码快得多。

3.1.2 src/drivers — 设备驱动

驱动层负责跟硬件打交道。每个传感器、执行器都有对应的驱动。我记得有一次GPS模块死活搜不到星,最后发现是驱动里波特率配置错了——这种坑踩过一次就记住了。

驱动目录的典型结构:

src/drivers/
├── gps/           # GPS驱动
├── imu/           # IMU(加速度计+陀螺仪)
├── baro/          # 气压计
├── magnetometer/  # 磁力计
├── pwm_out/       # PWM输出(控制电机/舵机)
├── rc_input/      # 遥控器输入
└── ...

每个驱动内部通常包含:

  • CMakeLists.txt:编译配置
  • *.cpp:驱动实现
  • *.hpp:头文件
  • params.c:参数定义(如果有)

3.1.3 src/lib — 公共库

库层是“工具箱”。所有模块都能调用它,但库本身不依赖任何模块。我特别喜欢mathlib里的四元数运算,写姿态控制时省了不少事。

库名 功能 我常用的场景
mathlib 向量、矩阵、四元数运算 姿态解算、坐标变换
geo 地理坐标计算 GPS经纬度转局部坐标
mixer 混控器(控制量→电机PWM) 自定义机架混控
parameters 参数系统 读取/写入飞控参数
cdev 字符设备抽象 驱动与用户态通信
perf 性能计数器 分析模块CPU占用

3.1.4 boards — 板级支持包

这是PX4的“硬件适配层”。每块飞控板在这里都有对应的目录。我刚开始移植PX4到一块新板子时,就是从这里入手的。

典型的板级目录结构:

boards/
├── px4/
│   ├── fmu-v5/        # Pixhawk FMUv5
│   ├── fmu-v6x/       # Pixhawk FMUv6X
│   └── sitl/          # 软件在环仿真
├── holybro/
│   ├── durandal-v1/   # Holybro Durandal
│   └── ...
└── ...

每个板级目录包含:

  • board_config.h:硬件引脚定义、时钟配置
  • CMakeLists.txt:板级编译配置
  • default.px4board:默认构建配置
  • nuttx-config/:NuttX RTOS配置

避坑指南:我曾经在移植时忘记修改board_config.h里的SPI引脚映射,结果IMU数据全是乱码。检查硬件配置时,一定要对照原理图逐行核对。

3.2 关键构建文件:Makefile与CMakeLists.txt

PX4的构建系统用的是CMake + Make。说实话,刚开始看这些文件时我也头疼,但摸清规律后就好办了。

3.2.1 顶层CMakeLists.txt

根目录下的CMakeLists.txt是总入口。它做了三件事:

  1. 设置CMake最低版本和项目名称
  2. 包含cmake/目录下的通用配置
  3. 根据目标板加载对应的板级配置

核心代码片段:

cmake_minimum_required(VERSION 3.10)
project(PX4-Autopilot)

# 包含通用CMake模块
include(cmake/common.cmake)

# 根据目标板加载配置
if(DEFINED PX4_BOARD)
  include(${PX4_BOARD_DIR}/board.cmake)
endif()

3.2.2 模块级CMakeLists.txt

每个模块都有自己的CMakeLists.txt。以src/modules/commander为例:

px4_add_module(
  MODULE modules__commander
  MAIN commander
  STACK_MAIN 2500
  SRCS
    commander.cpp
    state_machine.cpp
    ...
  DEPENDS
    modules__uORB
    lib__parameters
)

这里px4_add_module是PX4自定义的CMake函数。参数含义:

  • MODULE:模块唯一标识,用双下划线表示层级
  • MAIN:主入口函数名
  • STACK_MAIN:主线程栈大小(字节)
  • SRCS:源文件列表
  • DEPENDS:依赖的其他模块或库

我的经验:如果你要添加一个新模块,直接复制一个现有模块的CMakeLists.txt改改就行。别从头写,容易漏掉STACK_MAIN这种细节——栈给太小,模块跑起来会莫名其妙崩溃。

3.3 Kconfig配置系统

Kconfig是Linux内核引入的配置系统,PX4把它拿过来用了。说白了,它让你在编译前就能开关功能、调整参数。

配置入口在Kconfig文件(根目录和各个子目录都有)。举个例子:

menu "GPS Configuration"
  config GPS_ENABLED
    bool "Enable GPS support"
    default y
    help
      Enable GPS module for position estimation.

  config GPS_PROTOCOL
    string "GPS protocol"
    default "u-blox"
    help
      Select GPS protocol: u-blox, NMEA, etc.
endmenu

配置方法:

  1. 运行make px4_fmu-v5_default config进入图形化配置界面
  2. 用方向键导航,空格键开关选项
  3. 保存后生成.config文件
  4. 编译时自动读取.config中的配置
配置类型 语法 说明
bool bool "描述" 开关选项,y/n
int int "描述" 整数参数
string string "描述" 字符串参数
hex hex "描述" 十六进制参数

我曾经踩过的坑:有次为了省Flash空间,我把GPS_ENABLED关了,结果编译出来的固件死活搜不到星。折腾了半天才想起来——哦,GPS驱动根本没编译进去。所以改配置后一定要make clean再重新编译,避免缓存干扰。

3.4 构建流程速览

最后,我画个流程图帮你理解整个构建过程:

PX4 构建流程 make px4_fmu-v5 CMake配置生成 编译+链接 Kconfig配置 板级配置 px4_fmu-v5_default.px4

流程很简单:你敲make命令,CMake读取Kconfig和板级配置生成构建系统,然后编译器把源码编译成固件。嗯,就是这么回事。