4. PX4源码结构与编译系统
PX4 的源码并不是一堆散乱的 C++ 文件,而是一套“目录即架构”的工程组织方式。理解目录结构、模块划分、uORB 消息机制、启动脚本和编译烧录流程,是后续修改固定翼与 VTOL 控制逻辑、添加自定义模块、调试飞行行为的基础。本章从工程视角梳理 PX4 的代码骨架,并给出可落地的编译与烧录方法。
一、代码目录:从顶层看模块边界
PX4 固件仓库(PX4-Autopilot)顶层目录大致可分为“平台层、驱动层、模块层、库层、板级配置层”五类。常见目录及其职责如下:
| 目录 | 职责 | 典型内容 |
|---|---|---|
| src/modules | 飞行功能模块 | commander、navigator、mc_pos_control、fw_pos_control、vtol_att_control |
| src/drivers | 传感器与执行器驱动 | imu、barometer、gps、pwm_out、uavcan |
| src/lib | 通用算法与工具库 | mathlib、ecl、geo、mixer、parameters |
| src/platforms | OS 与硬件抽象 | posix、nuttx、common |
| boards | 板级配置与链接脚本 | px4_fmu-v5、px4_fmu-v6x、default.px4board |
| ROMFS | 启动脚本与混控文件 | init.d/rcS、mixers、airframes |
| msg | uORB 消息定义 | vehicle_attitude.msg、sensor_combined.msg |
其中 src/modules 是开发者最常改动的区域。固定翼相关模块包括 fw_att_control、fw_pos_control、fw_rate_control;VTOL 则额外涉及 vtol_att_control 与 vtol_control,它们负责在多旋翼与固定翼模式之间切换控制律。
二、模块划分与 uORB 消息机制
PX4 采用“模块 + 消息”的解耦设计。每个模块通常是一个独立任务或工作队列,通过 uORB(micro Object Request Broker)发布和订阅消息,而不是直接函数调用。这样做的核心好处是:模块之间无编译依赖,可独立启停,便于在资源受限的飞控上按需加载。
uORB 的基本使用模式是:发布者调用 orb_advertise() 获得句柄,再用 orb_publish() 发送数据;订阅者用 orb_subscribe() 订阅,用 orb_copy() 读取最新数据。消息定义放在 msg/ 目录下,编译时自动生成 C++ 头文件。
// 发布 vehicle_attitude 示例
orb_advert_t att_pub = orb_advertise(ORB_ID(vehicle_attitude), &att);
orb_publish(ORB_ID(vehicle_attitude), att_pub, &att);
// 订阅 sensor_combined 示例
int sub = orb_subscribe(ORB_ID(sensor_combined));
struct sensor_combined_s raw;
orb_copy(ORB_ID(sensor_combined), sub, &raw);
在终端中可用 uorb top 查看各消息的发布频率,用 listener vehicle_attitude 查看具体字段。调试固定翼姿态异常时,先确认 vehicle_attitude 与 vehicle_local_position 是否正常更新,往往比直接读代码更快定位问题。
三、启动脚本:ROMFS 中的 rcS 与 airframe
PX4 上电后由 NuttX 启动,随后执行 ROMFS/px4fmu_common/init.d/rcS。rcS 负责挂载 SD 卡、加载参数、启动传感器驱动、启动 estimator 与控制模块。不同机型的差异通过 rc.interface 和 airframe 配置脚本实现。
# 典型启动片段
if param compare SYS_AUTOSTART 4001
then
set AIRFRAME px4_fmu-v5_default
sh /etc/init.d/rc.fw_default
fi
# 启动固定翼姿态控制
fw_att_control start
fw_pos_control start
navigator start
对于 VTOL,启动脚本会同时加载多旋翼与固定翼控制模块,并由 vtol_att_control 根据 VTOL_TYPE 参数决定倾转或尾座式切换逻辑。修改 airframe 后必须重新编译并烧录,否则 ROMFS 中的脚本不会更新。
四、编译流程与固件烧录
PX4 使用 CMake + Ninja 构建系统。标准流程如下:
- 安装工具链:
./Tools/setup/ubuntu.sh或使用官方 Docker 镜像。 - 进入源码目录,执行
make px4_fmu-v5_default编译目标板固件。 - 编译产物位于
build/px4_fmu-v5_default/,生成.px4固件文件。 - 使用 QGroundControl 或
make px4_fmu-v5_default upload烧录。
# 常用编译命令
make px4_fmu-v5_default # 编译 FMUv5 固件
make px4_fmu-v6x_default # 编译 FMUv6X 固件
make px4_fmu-v5_default upload # 编译并上传
make clean # 清理构建目录
make distclean # 彻底清理
提示:首次编译建议使用 make px4_fmu-v5_default 验证工具链。若出现 Python 依赖错误,优先检查 pip3 install -r Tools/setup/requirements.txt 是否执行成功。
五、案例与常见误区
假设要为固定翼增加一个自定义日志模块。正确做法是:在 src/modules/ 下新建目录,编写 CMakeLists.txt 与模块源文件,在 boards/px4/fmu-v5/default.px4board 中启用该模块,然后重新编译。若只在源码中写模块却未加入板级配置,编译不会报错,但固件中不会包含该模块,运行时执行 my_module start 会提示命令不存在。
误区:直接修改 build/ 下的生成文件。这些文件由 CMake 自动生成,下次编译会被覆盖。所有修改必须落在 src/、msg/、ROMFS/ 或 boards/ 中。
另一个高频问题是 uORB 消息未更新。若 listener vehicle_attitude 显示频率为 0,通常不是控制模块的问题,而是上游 estimator 未启动或传感器驱动未加载。此时应检查 rcS 启动顺序与 uorb top 输出,而不是直接修改控制律参数。
掌握目录结构、uORB 机制、启动脚本与编译烧录流程后,后续修改固定翼与 VTOL 控制模块时,就能快速定位代码位置、验证消息流、完成固件部署,形成“改代码—编译—烧录—验证”的完整闭环。