第二章 飞控系统架构:PID调参的“藏身之处”

好,咱们直接进入正题。上一章聊了PID的基本概念,这一章咱们得把目光放到真正的飞控系统里。你想想看,PID控制器到底藏在代码的哪个角落?传感器数据是怎么流进控制环路的?

我个人习惯,在动手调参之前,先把架构摸清楚。不然你调了半天,可能连自己调的是哪个环都不知道。嗯,这很常见。

2.1 PX4与ArduPilot的PID实现位置

先说PX4。它的PID实现主要藏在 src/modules/control 目录下。具体来说:

  • 位置控制器:在 mc_pos_control 模块里。这里处理的是外环,也就是位置环和速度环。
  • 姿态控制器:在 mc_att_control 模块里。这里处理的是内环,也就是角速度环和姿态角环。

ArduPilot呢?它的PID实现更分散一些,但核心都在 libraries/AC_AttitudeControllibraries/AC_PID 里。我个人觉得ArduPilot的代码结构更“接地气”,但PX4的模块化设计更清晰。

核心区别:PX4用的是级联PID,ArduPilot也是级联PID,但ArduPilot在角速度环里加了前馈项。这个前馈项,说白了就是提前预测控制量,减少滞后。我在项目中遇到过,不加前馈,大机动时飞机会明显“跟不上”。

2.2 传感器数据流:从物理量到控制量

传感器数据流,是飞控系统的“血液”。咱们一步步拆解:

  1. IMU(惯性测量单元):输出加速度和角速度。这是最原始的数据,频率通常在1kHz左右。
  2. 磁力计:输出磁场强度,用于航向修正。但注意,这东西容易受干扰。我曾经在电机大电流时,磁力计数据直接漂了10度。
  3. 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参数,还是传感器数据?或者控制环路的频率?