[BF学院_卷1] -- 第16讲:I Term(积分控制项)——飞机为什么总是差一点?

第16讲:I Term(积分控制项)——飞机为什么总是差一点?


本讲知识点

  • P Term(比例控制项)为什么无法解决所有误差?
  • 什么是长期存在的控制误差?
  • I Term(积分控制项)为什么会出现?
  • I Term(积分控制项)到底在积累什么?
  • I Term(积分控制项)在控制链中的职责是什么?
  • 为什么飞机总会存在“总是差一点”的现象?
  • I Term(积分控制项)为什么能够消除长期误差?

本讲对应 Betaflight 源码

文件:

src/main/flight/pid.c

函数:

pidController()

本讲涉及源码:

pidData[axis].I += pidRuntime.pidCoefficient[axis].Ki
    * pidRuntime.dT
    * errorRate;

本讲重点讲解:

errorRate

为什么需要被长期积累,以及:

pidData[axis].I

为什么能够消除长期存在的控制误差。


回顾上一讲

上一讲中,我们已经得到Rate Error(角速度误差),

并且知道 P Term(比例控制项)负责解决的问题是:现在差多少?

控制链已经推进到了:

Rate Error

↓

P Term

但是,飞机并不会因为拥有了 P Term(比例控制项),就一定能够完全达到目标值。

现实世界中的控制误差,往往比我们想象得更加复杂。


本讲学习目标

现实中的飞机经常会出现:

总是差一点;

总是慢一点;

总是推不够;

总是需要长期补偿。

因此,本讲将正式进入:

I Term(积分控制项)

去理解它为什么会成为 PID Controller(PID控制器)中负责长期补偿的控制器。


P Term(比例控制项)已经很好了,为什么还需要 I Term?

假设:

目标:300°/s

现实:250°/s

于是:

Rate Error = 50°/s

P Term(比例控制项)开始工作:

差了 50 -> 开始增加控制量 -> 飞机开始加速

经过一段时间以后:

300°/s -> 290°/s -> 295°/s -> 297°/s -> 298°/s

这时候看起来已经非常接近目标值了, 但是问题来了:

为什么它永远都是:298°/s?而不是:300°/s?


飞机总会存在长期控制误差

现实中的飞机永远不是一个理想模型。

例如:

  • 空气阻力;
  • 电机效率变化;
  • 电池电压下降;
  • 机架振动;
  • 重心变化;
  • 螺旋桨效率变化。

这些因素都会导致:飞机总是差一点。

例如:目标 300°/s, 现实 298°/s

又或者:目标 300°/s, 现实 295°/s

甚至:目标 300°/s, 现实一直都是 290°/s

此时会出现一种非常有意思的现象:飞机没有完全控制失败;但它也没有完全控制成功。

它会长期停留在总是差一点。

这就是:

长期控制误差(Steady-state Error)。

P Term(比例控制项)为什么无法解决这个问题?

因为P看到的永远只有:现在差多少。

例如:300 -> 298 只差 2°/s

于是, P:差的不多,我只需要补一点。

但是, 这一点补偿,很可能永远不够。

于是:

298 -> 298 -> 298 -> 298 -> 298

飞机就会长期停留在差一点。

所以:

P看到的是:现在。

I看到的是:长期。

这就是两者最大的区别。


I Term(积分控制项)到底在看什么?

例如:

第1次循环:差 2°/s

↓

第100次循环:还是差 2°/s

↓

第500次循环:还是差 2°/s

这时候, I发现: 这已经不是偶然误差, 而是长期存在的控制偏差。

于是, I开始不断积累这个误差。

可以简单理解为:

差一点, 记下来

↓

还差一点, 继续记下来

↓

还是差一点, 继续记下来

↓

长期都在差一点, 开始增加长期补偿。

因此, I看到的并不是现在差多少, 而是长期到底差了多少。


I Term(积分控制项)的职责是什么?

如果用最简单的话去描述:

P负责立即修正,I负责长期补偿。

或者说:

P:现在差多少?

I:为什么一直都在差?

所以:

P负责解决立即误差。

I负责解决长期误差。

直到现在,我们第一次发现:PID中的三个字母,其实负责的是三种完全不同的控制职责。

其中,

P:现在。
I:长期。
D:变化速度。

它们看到的根本不是同一个世界。


控制链再次推进

现在:

Rate Error

↓

P Term

↓

I Term

已经开始共同参与控制。

这也是 PID Controller(PID控制器)开始变得有趣的地方:

它不是一个控制器,而是多个控制思想共同工作的结果。


源码补充说明

为了帮助大家回到源码进行阅读,这里简单说明一下源码中出现,但本讲没有展开讲解的几个变量。

dynCi

const float iTermChange = (Ki + pidRuntime.itermAccelerator)
    * dynCi
    * pidRuntime.dT
    * itermErrorRate;

这里的 dynCi 表示 Dynamic Integral Coefficient(动态积分系数)。

它的作用是:动态调整 I Term 的积分速度, 因为飞机在不同的飞行状态下,对 I Term 的需求其实并不完全相同。

我们根据代码来进行讲述:

dynCi = constrainf((1.0f - getMotorMixRange()) * pidRuntime.itermWindupPointInv, 0.0f, 1.0f);

const float itermWindupPoint = pidProfile->itermWindupPointPercent / 100.0f;
pidRuntime.itermWindupPointInv = 1.0f / (1.0f - itermWindupPoint);

首先,机体的调整的姿态空间是有限的,而函数 getMotorMixRange() 就是获取飞机姿态调整空间已占用的百分比。

而 itermWindupPointPercent 就是机体调整空间的百分比阀值,该阀值之内,本次I Term增量完整增加;超过阀值,则按比例缩减,直至不增加。

(1.0f - getMotorMixRange()) / (1.0f - itermWindupPoint) 则表示用余量来计算百分比,如:

itermWindupPointPercent 为80,表示机体调整度从 80% 开始衰减,那么(1.0f - itermWindupPoint)的值为0.2

当机体调整余量充足时,mixRange() 返回 0.6, 计算就是 (1-0.6)/0.2 = 2, dynCi = constrainf(2, 0, 1) = 1。

当机体调整余量不足时, mixRange() 返回 0.9, 计算就是 (1-0.9)/0.2 = 0.5, dynCi = 0.5

需要注意的是:

dynCi 并不会改变 I Term 的控制职责,它只是帮助 I Term 更合理地完成自己的工作。

pidRuntime.itermAccelerator

它的作用是:为 I Term 提供额外的积分增益补偿。

飞机在一些特殊情况下,例如:

  • 大油门变化;
  • 快速动作变化;

I Term 的建立速度可能会偏慢。

为了让 I Term 能够更快建立起补偿能力,Betaflight 会临时提高积分速度,因此就引入了:

itermAccelerator(积分加速器)

需要注意的是:它并不是新的 I Term,它只是让原来的 I Term 积分得更快一些。


pidRuntime.dT

表示:PID Loop(PID控制循环)的时间间隔。

积分 = 时间 × 误差

如果不知道过去了多少时间,控制器就无法知道 这一帧应该积分多少误差。

因此:误差越大, 时间越长, 积分增加越多。

这也是 I Term 之所以被称为 “Integral(积分项)” 的原因。


小结

因此,这几项参数分别承担着不同的职责:

Ki : 决定 I Term 的基础积分速度

itermAccelerator : 决定是否需要临时提高积分速度

dynCi : 决定当前飞行状态下应该采用怎样的积分速度

dT : 决定这一帧应该积分多少时间

最终得到:iTermChange

虽然源码看起来出现了很多变量,但它们并没有改变 I Term 的控制职责。

本讲真正需要建立的核心思想仍然只有一句话:

I Term(积分项)的职责,就是记住那些长期存在的误差,并持续补偿它们。

其它变量,都只是帮助 I Term 更稳定、更合理地完成自己的工作。


本讲小结

本讲我们正式进入了 I Term(积分控制项)的控制职责。

P Term(比例控制项)负责解决“现在差多少”的问题,而 I Term(积分控制项)负责解决“为什么一直都在差”的问题。当飞机长期存在控制偏差时,I Term 会不断积累这些长期误差,并逐渐增加补偿量,从而帮助飞机最终达到目标状态。

至此,我们已经完成了 PID Controller(PID控制器)中的两个核心控制职责:

现在差多少?

↓

长期差多少?

下一讲预告

现在,PID Controller(PID控制器)已经拥有了:

P:现在差多少?

I:长期差多少?

但是,它仍然无法判断:飞机现在的变化是不是太快了?

下一讲,我们将正式进入:

D Term(微分控制项)。

去看看飞控究竟是如何观察变化速度,并让控制变得更加稳定的。

posted on 2026-08-03 14:43  longyue  阅读(14)  评论(0)    收藏  举报

导航