第三章 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字都管用。
3.5 我的实战建议
最后,给几个实在的建议。这些是我在项目里摔出来的经验:
- 别一上来就改modules。先改drivers,让传感器数据能正确读上来。数据不对,后面全是白搭。
- 加新功能先找现有模块。比如你想加个自定义控制律,看看
mc_att_control的结构,照着抄一份改。别自己从头造轮子。 - 编译报错先看CMakeLists.txt。90%的编译问题都是模块没加进编译列表,或者依赖没写对。
- 学会用
git log --oneline。看提交历史能帮你理解某个模块为什么这么写。我经常这么干,比读文档快。
一句话总结: 顶层目录是地图,modules是大脑,drivers是手脚。先看懂地图,再研究大脑怎么思考,最后才看手脚怎么动。顺序别搞反了。