3、PX4系统架构:uORB消息机制、模块与任务、启动脚本、参数系统、飞行模式概览
好,我们进入第三章。这一章是PX4的骨架,理解了它,你才算真正入了门。很多新手一上来就急着调参、改代码,结果遇到问题根本不知道从哪查起。说白了,就是没搞懂系统是怎么跑起来的。
我个人习惯,拿到一个新飞控,第一件事不是飞,而是先看它的架构。就像你开一辆新车,总得先知道方向盘、油门、刹车在哪吧?PX4也一样,它的核心就这几块:消息怎么传、任务怎么调度、启动时干了什么、参数存在哪、以及飞行模式怎么切换。
3.1 uORB:飞控的“神经网络”
uORB是PX4内部的消息总线。你可以把它想象成飞控的神经网络——所有模块之间不直接通信,而是通过uORB发布和订阅消息。
举个例子,传感器模块读取了陀螺仪数据,它不会直接扔给姿态估计模块。而是把数据打包成一个sensor_gyro消息,发布到uORB总线上。姿态估计模块如果订阅了这个消息,就能收到。这样做的好处是模块之间解耦,你想换一个姿态估计算法,完全不用动传感器驱动。
核心概念:
- 发布(Publish): 模块把数据扔到总线上。
- 订阅(Subscribe): 模块从总线上拿数据。
- 主题(Topic): 消息的唯一标识,比如
sensor_gyro、vehicle_attitude。
我曾经在一个项目中,发现日志里姿态数据偶尔会跳变。排查了很久,最后发现是某个第三方模块在发布vehicle_attitude时,频率没对齐,导致数据覆盖。嗯,从那以后,我每次加新模块都会先检查它发布的消息频率和优先级。
uORB的消息定义在msg/目录下,以.msg文件存在。比如sensor_gyro.msg里定义了陀螺仪数据的字段:
# sensor_gyro.msg
uint64 timestamp # 时间戳
uint32 device_id # 设备ID
float[3] x # X轴角速度
float[3] y # Y轴角速度
float[3] z # Z轴角速度
uint16 samples # 采样数
你想想看,如果每个模块都自己定义数据结构,那整个系统就乱套了。uORB强制了数据格式的统一,这也是PX4能保持稳定迭代的原因之一。
3.2 模块与任务:飞控的“器官”
PX4的每个功能模块,本质上都是一个独立的任务(Task)。这些任务由系统调度器管理,按优先级和时间片轮流运行。
模块分为几类:
- 驱动模块: 负责跟硬件打交道,比如读取传感器、控制电机。
- 估计模块: 处理传感器数据,算出姿态、位置、速度。比如
ekf2。 - 控制模块: 根据期望值和估计值,算出控制量。比如
mc_att_control(多旋翼姿态控制)。 - 通信模块: 处理遥控器、地面站、机载计算机的数据。比如
mavlink。
每个模块在启动时,都会注册一个任务名。你可以用top命令在NuttX终端里看到所有运行中的任务:
nsh> top
PID PRIORITY STATE CPU NAME
0 0 READY 0.0% Idle Task
1 100 WAIT_SIG 0.0% hpwork
3 100 READY 0.0% lpwork
10 150 READY 0.0% px4_sdhc
15 100 READY 0.0% uavcan
20 100 READY 0.0% sensor_combined
25 100 READY 0.0% ekf2
30 100 READY 0.0% mc_att_control
我建议你养成习惯,每次刷完固件,先跑一下top,看看该启动的模块是不是都起来了。如果某个模块没启动,飞控肯定不正常。
小技巧: 如果某个模块崩溃了,系统会自动重启它。但如果你发现某个模块反复崩溃,那多半是硬件问题或者配置冲突。别硬扛,先查硬件连接。
3.3 启动脚本:飞控的“开机自检”
PX4上电后,第一件事就是执行启动脚本。这些脚本在ROMFS/px4fmu_common/init.d/目录下。
启动脚本是Shell脚本,但运行在NuttX的NSH环境下。它决定了:
- 加载哪些驱动
- 启动哪些模块
- 设置哪些参数默认值
- 配置混控器(Mixer)
比如,一个典型的四旋翼启动脚本rcS会做这些事:
# 加载传感器驱动
ms5611 start
mpu9250 start
# 启动姿态估计
ekf2 start
# 启动姿态控制
mc_att_control start
# 启动位置控制
mc_pos_control start
# 加载混控器
mixer load /dev/pwm_output0 /etc/mixers/quad_x.main.mix
我记得有一次,客户说他们的飞控上电后电机不转。我远程一看,发现启动脚本里混控器加载路径写错了。你想想看,混控器没加载,电机怎么可能转?所以,改启动脚本时一定要小心,路径和文件名都不能错。
避坑指南: 我曾经在调试一个新机架时,直接复制了别人的启动脚本,结果电机顺序全乱了。后来我养成了一个习惯:每次改启动脚本,都会在注释里写上修改日期和原因。别偷懒,这能救你命。
3.4 参数系统:飞控的“记忆”
参数系统是PX4的持久化存储。所有可调参数都保存在/fs/microsd/parameters文件里(如果有SD卡),或者/fs/mtd_params(内部Flash)。
参数分为几类:
| 参数类型 | 说明 | 示例 |
|---|---|---|
| 整数 | 32位有符号整数 | MC_ROLL_P(滚转P增益) |
| 浮点 | 32位浮点数 | MPC_XY_VEL_MAX(最大水平速度) |
| 布尔 | 0或1 | COM_ARM_EKF_AB(EKF异常时是否允许解锁) |
| 枚举 | 整数,但映射到特定选项 | RC_MAP_MODE_SW(遥控器模式开关通道) |
每个参数都有默认值、最小值和最大值。你可以在QGroundControl里修改,也可以通过param set命令在终端里改:
nsh> param set MC_ROLL_P 0.15
我个人习惯,在调参前先param save一下,把当前参数备份到SD卡。万一调乱了,直接param load恢复。别问我为什么有这个习惯——你经历过一次参数全丢就知道痛了。
3.5 飞行模式概览:飞控的“驾驶模式”
飞行模式决定了飞控在多大程度上接管控制权。PX4的飞行模式很多,但核心就几类:
- 手动模式: 飞控只做姿态稳定,位置和速度完全由遥控器控制。比如Stabilized(自稳模式)。
- 辅助模式: 飞控帮你稳住一部分,比如Altitude(定高模式)会锁定高度,但水平方向还是手动。
- 自动模式: 飞控全权控制,比如Mission(任务模式)按预设航点飞行,Land(降落模式)自动降落。
- 特殊模式: 比如Offboard(外部控制模式),由机载计算机发送控制指令。
模式切换通常通过遥控器上的三段开关实现。你需要在QGC里把开关通道映射到RC_MAP_MODE_SW参数。
我的建议: 新手第一次试飞,一定要把手动模式和降落模式设到最顺手的位置。万一失控,能第一时间切回手动或者触发降落。别问我怎么知道的——我见过太多人飞丢了才想起来切模式。
下面这张图,是我自己总结的PX5系统架构核心流程,你一看就明白各模块怎么配合了:
从这张图你能看到,传感器数据先通过uORB总线,分发给估计模块。估计模块算出姿态和位置后,再通过uORB发给控制模块。控制模块算出控制量,交给混控器,最终输出到电机。整个链路清晰明了,任何一个环节出问题,飞控都会异常。