第三章 PX4源码结构:顶层目录、modules与drivers

好,咱们今天来聊聊PX4的源码结构。说实话,我第一次打开PX4源码仓库的时候,也有点懵——文件夹太多了。但别怕,这东西有规律可循。我个人的习惯是,先看顶层,再钻modules,最后摸drivers。按这个顺序走一遍,你心里就有谱了。

3.1 顶层目录结构

先说说根目录下那些文件夹是干嘛的。你 git clone 完PX4之后,ls 一下,会看到大概这么几个关键目录:

目录名 作用 我常用的场景
src/ 核心源码,所有逻辑都在这里 90%的时间泡在这里
boards/ 板级支持包,各种硬件配置 移植新飞控板时必改
cmake/ 编译配置脚本 加模块、改编译选项
ROMFS/ 文件系统镜像,启动脚本 改默认参数、加启动项
Tools/ 辅助工具链 刷固件、日志分析
test/ 单元测试和集成测试 提PR前跑一遍

嗯,这里要注意:src/ 才是咱们的主战场。其他目录虽然也重要,但平时改得少。我记得有一次为了调一个新传感器,在 boards/ 里折腾了一整天,最后发现是 ROMFS/ 里的启动脚本没配好——这种坑踩过一次就记住了。

核心原则: 顶层目录里,src/ 是大脑,boards/ 是骨架,ROMFS/ 是血液。改代码先找 src/,改硬件先找 boards/,改启动流程先找 ROMFS/。

3.2 src/modules 目录:飞控的大脑

好,咱们钻进 src/modules。这里才是真正干活的地方。说白了,PX4的每个功能模块就是一个独立的文件夹,各自跑各自的uORB消息循环。

我列几个最常用的模块,你感受一下:

  • commander:飞行模式切换、状态机。说白了就是飞控的「大脑皮层」。
  • navigator:航线规划、任务执行。飞自主航线全靠它。
  • mc_pos_control:多旋翼位置控制。悬停稳不稳,看这里。
  • mc_att_control:多旋翼姿态控制。翻跟头、抗风靠它。
  • ekf2:扩展卡尔曼滤波器。位置、速度、姿态的融合核心。
  • sensors:传感器数据预处理。IMU校准、温度补偿都在这里。

每个模块内部结构其实挺统一的。我随便打开一个,比如 mc_pos_control,你会看到:

src/modules/mc_pos_control/
├── CMakeLists.txt      # 编译规则
├── mc_pos_control_main.cpp  # 主循环
├── mc_pos_control_params.c  # 参数定义
└── PositionControl.cpp      # 核心算法

我个人习惯是,先看 _main.cpp 里的 Run() 函数,那是模块的入口。然后看 _params.c 了解有哪些可调参数。最后才看算法实现。你想想看,如果一上来就啃算法,很容易迷失在数学公式里。

小技巧: 想快速了解一个模块在干什么?直接搜它订阅和发布了哪些uORB话题。比如 uORB::Subscription 和 uORB::Publication。这比读100行代码都管用。

3.3 src/drivers 目录:飞控的感官

接下来是 src/drivers。这里管的是所有硬件驱动——传感器、执行器、通信接口。说白了,飞控能不能「看见」和「动起来」,全看这里。

我按设备类型给你分个类:

设备类型 典型驱动 避坑点
IMU icm20602, bmi088 SPI速率别设太高,容易丢数据
磁力计 hmc5883, ist8310 注意安装位置,远离大电流线
气压计 ms5611, bmp280 避风、避光,否则高度跳变
GPS gps (通用) ublox协议兼容性最好
PWM输出 pwm_out 注意电机映射顺序
RC输入 rc_input SBUS信号需要反相器

我曾经在一个项目里,IMU数据老是跳变,查了三天。最后发现是驱动里SPI时钟极性配错了。嗯,这种硬件底层的坑,光看代码是看不出来的,得拿逻辑分析仪抓波形。

警告: 别随便改 drivers 里的代码!尤其是那些带 #ifdef 的条件编译。改之前先确认你的硬件版本和芯片型号。我见过有人把BMI088的驱动改成了ICM20602的配置,结果飞控直接「原地爆炸」。

3.4 一张图看懂整体结构

说了这么多,不如画张图。下面这张SVG图,把顶层、modules、drivers的关系串起来了。你盯着看30秒,比读我1000字都管用。

PX4源码结构关系图 PX4 源码三层架构 顶层目录 (src/ boards/ cmake/ ROMFS/ Tools/ test/) src/modules (飞控逻辑) commander mc_pos_control mc_att_control ekf2 navigator sensors src/drivers (硬件驱动) IMU (icm20602) 磁力计 (ist8310) 气压计 (ms5611) GPS (ublox) PWM输出 RC输入 核心关系:drivers 采集原始数据 → uORB 消息总线 → modules 处理逻辑 → 输出控制指令 每个模块独立运行,通过 uORB 话题通信,互不阻塞

3.5 我的实战建议

最后,给几个实在的建议。这些是我在项目里摔出来的经验:

  1. 别一上来就改modules。先改drivers,让传感器数据能正确读上来。数据不对,后面全是白搭。
  2. 加新功能先找现有模块。比如你想加个自定义控制律,看看 mc_att_control 的结构,照着抄一份改。别自己从头造轮子。
  3. 编译报错先看CMakeLists.txt。90%的编译问题都是模块没加进编译列表,或者依赖没写对。
  4. 学会用 git log --oneline。看提交历史能帮你理解某个模块为什么这么写。我经常这么干,比读文档快。

一句话总结: 顶层目录是地图,modules是大脑,drivers是手脚。先看懂地图,再研究大脑怎么思考,最后才看手脚怎么动。顺序别搞反了。