第二章 飞控系统架构:PID调参的“藏身之处”
好,咱们直接进入正题。上一章聊了PID的基本概念,这一章咱们得把目光放到真正的飞控系统里。你想想看,PID控制器到底藏在代码的哪个角落?传感器数据是怎么流进控制环路的?
我个人习惯,在动手调参之前,先把架构摸清楚。不然你调了半天,可能连自己调的是哪个环都不知道。嗯,这很常见。
2.1 PX4与ArduPilot的PID实现位置
先说PX4。它的PID实现主要藏在 src/modules/control 目录下。具体来说:
- 位置控制器:在
mc_pos_control模块里。这里处理的是外环,也就是位置环和速度环。 - 姿态控制器:在
mc_att_control模块里。这里处理的是内环,也就是角速度环和姿态角环。
ArduPilot呢?它的PID实现更分散一些,但核心都在 libraries/AC_AttitudeControl 和 libraries/AC_PID 里。我个人觉得ArduPilot的代码结构更“接地气”,但PX4的模块化设计更清晰。
核心区别:PX4用的是级联PID,ArduPilot也是级联PID,但ArduPilot在角速度环里加了前馈项。这个前馈项,说白了就是提前预测控制量,减少滞后。我在项目中遇到过,不加前馈,大机动时飞机会明显“跟不上”。
2.2 传感器数据流:从物理量到控制量
传感器数据流,是飞控系统的“血液”。咱们一步步拆解:
- IMU(惯性测量单元):输出加速度和角速度。这是最原始的数据,频率通常在1kHz左右。
- 磁力计:输出磁场强度,用于航向修正。但注意,这东西容易受干扰。我曾经在电机大电流时,磁力计数据直接漂了10度。
- GPS/光流:输出位置和速度。频率低,通常5-10Hz,所以需要和IMU做数据融合。
数据流大致是这样的:
传感器 → 数据预处理(滤波、校准) → 状态估计(EKF/互补滤波) → 控制器(PID) → 混控器 → 电机
你想想看,如果传感器数据有延迟或者噪声,PID控制器会怎么反应?嗯,轻则抖动,重则炸机。所以,调参之前,先确认传感器数据是干净的。
2.3 控制环路:内环与外环的“相爱相杀”
飞控的控制环路,通常分为内环和外环。内环是角速度环,外环是姿态角环或位置环。它们的关系是这样的:
| 环路 | 控制对象 | 典型频率 | PID参数影响 |
|---|---|---|---|
| 内环(角速度环) | 角速度(gyro) | 200-400 Hz | P:响应速度,D:阻尼,I:稳态误差 |
| 外环(姿态角环) | 姿态角(roll/pitch/yaw) | 50-100 Hz | P:角度跟踪,I:消除静差 |
| 外外环(位置环) | 位置/速度 | 10-50 Hz | P:位置保持,D:速度阻尼 |
这里有个避坑指南:调参一定要从内环开始。我曾经见过一个新手,上来就调位置环,结果飞机在天上像“抽风”一样。为什么?因为内环没调好,外环再怎么调也没用。
我的个人经验:调内环时,先把外环的P值设小一点,甚至设成0。这样内环的响应就不会被外环干扰。等内环调稳了,再慢慢打开外环。
2.4 代码示例:PX4中的PID实现片段
咱们看看PX4里角速度环的PID代码(简化版):
// 来自 mc_att_control 模块
// 角速度环的PID计算
float rate_p = _params.rate_p; // 比例系数
float rate_i = _params.rate_i; // 积分系数
float rate_d = _params.rate_d; // 微分系数
// 误差计算
float error = desired_rate - current_rate;
// P项
float p_term = rate_p * error;
// I项(带积分限幅)
_integral += error * dt;
_integral = math::constrain(_integral, -_params.integral_limit, _params.integral_limit);
float i_term = rate_i * _integral;
// D项(对测量值微分,避免微分爆炸)
float d_term = rate_d * (current_rate - last_rate) / dt;
// 输出
float output = p_term + i_term + d_term;
注意看,这里的D项是对测量值微分,而不是对误差微分。为什么?因为对误差微分会放大噪声,尤其是当期望值突变时。嗯,这个细节很多新手会忽略。
2.5 实战中的架构思考
好了,理论说完了,咱们聊聊实战。我在搭建自整定系统时,最头疼的不是PID算法本身,而是数据流的时序。比如:
- 传感器数据什么时候更新?
- 控制环路什么时候运行?
- 如果传感器数据延迟了,控制器该怎么处理?
这些问题,说白了就是“实时性”问题。飞控系统里,每个任务都有固定的优先级和运行频率。比如,IMU数据读取是最高优先级,而日志记录是最低优先级。如果你在调参时发现飞机响应慢,别急着调PID,先看看是不是传感器数据被其他任务阻塞了。
警告:不要在飞行中随意修改PID参数!尤其是积分项。我曾经在一次测试中,边飞边调I值,结果积分饱和导致飞机直接翻转。嗯,那次之后,我养成了“落地调参”的习惯。
最后,总结一下这一章的核心:
- PX4和ArduPilot的PID实现位置不同,但核心思想一致。
- 传感器数据流是PID控制的基础,数据质量决定控制效果。
- 内环和外环的调参顺序不能乱,先内后外。
- 代码实现中,注意D项的处理方式,避免噪声放大。
下一章,咱们会深入PID参数的物理意义,以及如何通过“试凑法”快速找到合适的参数。嗯,到时候我会分享一些我自己的“土办法”,保证实用。
课后思考:如果你发现飞机在悬停时频繁抖动,但GPS信号良好,你会先检查哪个环节?是PID参数,还是传感器数据?或者控制环路的频率?