1. PX4飞控架构概览
各位同学,欢迎来到这门课的第一讲。今天咱们不聊虚的,直接切入PX4的核心——它的软件架构到底长什么样?模块之间怎么打招呼?说白了,就是搞清楚代码跑起来的时候,谁在干活,谁在等消息。
我个人习惯,学一个新系统,先看它的“骨架”。PX4的骨架,就是一套模块化、消息驱动的实时操作系统。你想想看,飞控要同时处理传感器数据、控制算法、遥控器信号、日志记录……如果所有代码揉成一锅粥,调试起来会疯掉的。PX4的做法很聪明:每个功能独立成一个模块,模块之间通过uORB这个“消息总线”来通信。
1.1 整体架构:三层结构
我把PX4的架构归纳为三层,这样好记:
- 底层(硬件抽象层):负责跟传感器、PWM输出、GPS等硬件打交道。这一层把硬件差异屏蔽掉,上层模块不用关心你用的是SPI还是I2C。
- 中间层(核心服务层):包括uORB消息总线、参数系统、日志系统、任务调度等。这是整个系统的“血管”和“神经”。
- 应用层(功能模块层):姿态估计、位置控制、导航、GPS处理、RC输入……所有你关心的飞行逻辑都在这里。
嗯,这里要注意:这三层不是物理隔离的,而是逻辑上的划分。实际代码里,一个模块可能既调用底层驱动,又发布uORB消息。
1.2 uORB消息机制:模块间的“快递员”
uORB是PX4里最核心的通信机制。我刚开始接触时觉得它有点绕,但用熟了会发现,它比全局变量优雅太多了。
uORB的工作原理:
- 发布/订阅模型:一个模块发布某个主题(topic),其他模块可以订阅这个主题。发布者不需要知道谁在订阅,订阅者也不需要知道谁在发布。解耦得干干净净。
- 主题(Topic):每个主题对应一个数据结构。比如
sensor_accel主题,里面就放着加速度计的x、y、z值和时间戳。 - 多实例支持:同一个主题可以有多个实例。比如你有两个IMU,就可以发布
sensor_accel的实例0和实例1。
核心要点:uORB不是网络协议,它只在同一片内存空间里传递数据。所以速度极快,延迟在微秒级。我在项目中遇到过有人想用TCP/IP在飞控内部传数据,那完全是杀鸡用牛刀。
1.3 模块间通信:一个完整的例子
咱们看一个实际场景:遥控器摇杆推一下,飞机要往前飞。这个过程中,消息是怎么流转的?
- RC输入模块读取遥控器PWM信号,发布
rc_channels主题。 - 姿态控制器订阅
rc_channels,解析出期望的俯仰角,结合当前姿态(来自vehicle_attitude主题),计算出期望的角速度。 - 角速度控制器订阅期望角速度,结合当前角速度(来自
vehicle_angular_velocity主题),计算出电机控制量。 - 混控器模块订阅电机控制量,输出PWM信号给电调。
你看,每个模块只关心自己那点事。如果以后要换一种遥控器协议,只需要改RC输入模块,其他模块完全不用动。
我的经验:调试uORB通信时,可以用uorb top命令查看当前所有主题的发布频率和大小。我曾经靠这个命令抓到一个模块因为死循环导致消息发布频率飙升的bug。
1.4 核心数据结构一览
下面列出几个你一定会打交道的uORB主题。记住它们,后面写代码会频繁用到。
| 主题名称 | 数据结构(简化) | 发布者 | 订阅者 |
|---|---|---|---|
sensor_accel |
x, y, z, timestamp | 传感器驱动 | 姿态估计、日志 |
vehicle_attitude |
q[4], roll, pitch, yaw | 姿态估计 | 控制器、导航 |
vehicle_local_position |
x, y, z, vx, vy, vz | 位置估计 | 位置控制器、导航 |
actuator_controls |
control[8] | 控制器 | 混控器 |
rc_channels |
channels[18] | RC输入 | 控制器、模式切换 |
1.5 架构图:一图胜千言
下面这张SVG图,把PX4的模块化架构和uORB通信关系画出来了。你盯着看两分钟,比读一千字管用。
避坑指南:我曾经犯过一个低级错误——在中断服务函数里直接发布uORB消息。结果导致系统死锁,飞机直接炸机。记住:uORB的发布和订阅必须在任务上下文中进行,不能在中断里搞。
1.6 小结:你该记住什么?
这一章的内容,说白了就三句话:
- PX4是模块化架构,每个模块独立干活。
- 模块之间通过uORB消息总线通信,发布/订阅模型。
- 理解uORB主题的数据结构,是写自定义模块的第一步。
嗯,下一章我们会动手写第一个自定义模块,到时候你会更深刻地理解uORB怎么用。今天就到这里,有问题随时在群里问我。
公众号:蓝海资料掘金营,微信deep3321