3. PX4软硬件架构
好,咱们今天来拆解PX4的源码结构。说实话,我第一次接触PX4源码时,也被它的目录层级吓了一跳——东西太多了。但别慌,核心就几个目录:src/modules、src/drivers、src/lib、boards,再加上构建相关的Makefile和Kconfig。搞懂这些,你就抓住了PX4的骨架。
3.1 四大核心目录:各司其职
先看一张整体结构图,我习惯把它叫做“PX4的四层蛋糕”。
这张图我画了好几次才满意。它清晰地展示了调用关系:上层模块调用下层驱动和库,最底层是板级支持。咱们一层层来看。
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是总入口。它做了三件事:
- 设置CMake最低版本和项目名称
- 包含
cmake/目录下的通用配置 - 根据目标板加载对应的板级配置
核心代码片段:
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
配置方法:
- 运行
make px4_fmu-v5_default config进入图形化配置界面 - 用方向键导航,空格键开关选项
- 保存后生成
.config文件 - 编译时自动读取
.config中的配置
| 配置类型 | 语法 | 说明 |
|---|---|---|
| bool | bool "描述" |
开关选项,y/n |
| int | int "描述" |
整数参数 |
| string | string "描述" |
字符串参数 |
| hex | hex "描述" |
十六进制参数 |
我曾经踩过的坑:有次为了省Flash空间,我把GPS_ENABLED关了,结果编译出来的固件死活搜不到星。折腾了半天才想起来——哦,GPS驱动根本没编译进去。所以改配置后一定要make clean再重新编译,避免缓存干扰。
3.4 构建流程速览
最后,我画个流程图帮你理解整个构建过程:
流程很简单:你敲make命令,CMake读取Kconfig和板级配置生成构建系统,然后编译器把源码编译成固件。嗯,就是这么回事。