[BF学院_卷1] -- 第18讲:PID Controller 的最后一环——为什么飞控还需要 Feedforward(前馈控制)?
第18讲:PID Controller 的最后一环——为什么飞控还需要 Feedforward(前馈控制)?
本讲知识点
- PID Controller(PID控制器)中的三个反馈控制项已经完成后,为什么仍然需要 Feedforward(前馈控制)
- Feedback Control(反馈控制)与 Feedforward(前馈控制)的区别
- Feedforward 为什么直接观察飞手输入变化
- pidSetpointDelta(目标变化量)的作用
- Kf(前馈系数)如何影响 Feedforward 输出
- Betaflight 中 pidData[axis].F 的计算过程
- PID Sum(最终控制输出)的形成
本讲对应 Betaflight 源码
文件:src/main/flight/pid.c
函数:pidController()
本讲涉及源码:
#ifdef USE_ABSOLUTE_CONTROL
pidSetpointDelta += setpointCorrection - pidRuntime.oldSetpointCorrection[axis];
pidRuntime.oldSetpointCorrection[axis] = setpointCorrection;
#endif
const float feedforwardGain = launchControlActive ? 0.0f : pidRuntime.pidCoefficient[axis].Kf;
pidData[axis].F = feedforwardGain * pidSetpointDelta;
以及:
const float pidSum = pidData[axis].P + pidData[axis].I + pidData[axis].D + pidData[axis].F;
回顾上一讲
上一讲中,我们已经完成 D Term(微分控制项)的建立。
至此,Rate Controller(角速度控制器)已经具备:
P Term(比例控制项)
I Term(积分控制项)
D Term(微分控制项)
三个基础反馈控制项。
控制链继续推进到:
P Term
↓
I Term
↓
D Term
↓
Feedforward
本讲学习目标
虽然 PID Controller(PID控制器)已经能够根据误差修正飞机状态,
但是, 反馈控制存在一个天然限制:它必须先等误差产生,然后才能开始修正。
当飞手快速打杆时,飞机需要快速产生响应,而不是等待:
目标变化
↓
产生误差
↓
PID修正
这个过程完成以后才开始动作。
因此,本讲进入:
Feedforward(前馈控制)
理解飞控如何直接观察目标变化,在误差出现之前,提前产生控制响应。
PID 三个反馈项已经足够了吗?
到目前为止,控制链已经进入:Rate Controller(角速度控制器)。
飞控拥有:Rate Error(角速度误差)。
然后通过:P Term -> I Term -> D Term 产生控制输出。
看起来,PID 已经完整了。
但是现实中仍然存在一个问题:飞手输入是主动产生的。
例如:
飞手快速向右打杆,控制目标瞬间变化:
当前目标角速度:0°/s -> 300°/s
这时候, 飞机实际角速度仍然可能接近 0°/s, 因此, Rate Error 会突然增大。
反馈控制需要经历:
目标变化
↓
产生误差
↓
P/I/D计算
↓
电机响应
这个过程需要时间。
而飞手希望看到的是:打杆以后,飞机立即开始响应。
因此,飞控需要一种不等待误差出现,提前响应目标变化的方法。
这就是:Feedforward(前馈控制)。
Feedback Control 与 Feedforward 的区别
理解 Feedforward 前,需要先区分两种控制思想。
Feedback Control(反馈控制)
反馈控制关注:飞机现在做得对不对。
它观察:
目标值
↓
当前状态
↓
计算误差。
例如:
目标角速度:300°/s
当前角速度:200°/s
产生:Rate Error 100°/s
然后 PID 根据误差修正。
所以, 反馈控制解决的是:飞机已经偏离目标以后,如何修回来。
Feedforward(前馈控制)
Feedforward 关注:目标正在如何变化。
例如:
飞手突然快速打杆:目标角速度 0°/s --> 300°/s
虽然飞机还没有产生误差,但是飞控已经知道:未来需要快速增加控制输出。
因此,Feedforward 不等待 Current Angular Rate(当前角速度)变化。
而是直接观察 Setpoint(目标值)的变化。
pidSetpointDelta:目标变化量
源码中:
pidSetpointDelta 表示:当前目标角速度,相比上一周期变化了多少。
简单理解:
如果上一周期目标:0°/s
当前目标:300°/s
那么,目标变化量 300°/s
这个变化量代表:飞手希望飞机快速改变运动状态。
因此,Feedforward 使用“目标变化速度”作为提前控制依据。
第一行核心源码
首先观察:
const float feedforwardGain = launchControlActive ? 0.0f : pidRuntime.pidCoefficient[axis].Kf;
这一行负责获取:Kf(Feedforward Gain,前馈增益)。
Kf 的作用:控制 Feedforward 对最终输出的影响大小。
如果Kf 较大, 目标变化时,提前产生更强响应。
如果Kf 较小, 提前响应较弱。
因此, Kf 决定飞控对飞手输入变化的敏感程度。
Feedforward 输出计算
核心代码:
pidData[axis].F = feedforwardGain * pidSetpointDelta;
翻译成控制思想:
目标变化量 × 前馈增益 --> Feedforward 输出
也就是说, 飞手动作变化越快,Feedforward 输出越大。
例如:
飞手轻微移动摇杆, 目标变化小。
↓
Feedforward 小。
飞手快速打杆, 目标变化大。
↓
Feedforward 大。
为什么 Feedforward 不替代 PID?
这里需要注意:Feedforward 不是替代 PID。
因为, 它只知道:飞手希望怎么变化, 但是它不知道:飞机实际有没有做到。
例如:
飞手快速打杆, Feedforward 提供提前推力。
但是, 如果电池电压下降;电机性能不足;受到风阻;飞机仍然可能达不到目标。
这时候, Rate Error 仍然存在。
于是, PID Feedback Control(反馈控制)继续负责修正实际误差。
所以完整控制逻辑是:
Feedforward 提前推动飞机。
PID:根据实际误差修正飞机。
两者共同作用:快速响应 + 准确控制。
PID Sum:最终控制输出
当:
P Term
I Term
D Term
Feedforward
全部计算完成以后, 源码进入:
const float pidSum = pidData[axis].P
+ pidData[axis].I
+ pidData[axis].D
+ pidData[axis].F;
这里表示所有控制作用最终合并。
也就是, 反馈控制 P + I + D + F 共同形成PID Controller(PID控制器)的最终输出。
控制链推进到:
Rate Error
↓
P Term
↓
I Term
↓
D Term
↓
Feedforward
↓
PID Sum
至此, Rate Controller 内部的主要控制组成已经建立完成。
本讲小结
本讲完成了 Feedforward(前馈控制)的建立。
Feedforward 与 P Term、I Term、D Term 不同,它不是根据已经产生的误差进行修正,而是直接观察目标变化趋势,提前产生控制响应。
Betaflight 通过 pidSetpointDelta 获得目标角速度变化量,
再结合 Kf 计算 pidData[axis].F。
至此,Rate Controller 内部主要控制组成已经全部建立:
P Term:解决当前误差。
I Term:解决长期累计误差。
D Term:观察变化趋势。
Feedforward:提前响应目标变化。
下一讲预告
下一讲,我们将离开 PID Controller 内部计算,
进入:
Motor Mixer(电机混控)。
理解飞控如何把单个轴的控制输出,转换为四个电机的具体控制量。
浙公网安备 33010602011771号