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系统架构核心流程,你一看就明白各模块怎么配合了:

PX4 系统架构核心流程 传感器驱动 uORB 消息总线 姿态/位置估计 姿态/位置控制 混控器 PWM/电机输出 参数系统 启动脚本 飞行模式管理 说明 传感器数据通过uORB 传递给估计和控制模块

从这张图你能看到,传感器数据先通过uORB总线,分发给估计模块。估计模块算出姿态和位置后,再通过uORB发给控制模块。控制模块算出控制量,交给混控器,最终输出到电机。整个链路清晰明了,任何一个环节出问题,飞控都会异常。