惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

The GitHub Blog
The GitHub Blog
有赞技术团队
有赞技术团队
Apple Machine Learning Research
Apple Machine Learning Research
V
V2EX
Engineering at Meta
Engineering at Meta
美团技术团队
H
Hackread – Cybersecurity News, Data Breaches, AI and More
博客园 - 司徒正美
I
InfoQ
S
SegmentFault 最新的问题
博客园 - 叶小钗
N
Netflix TechBlog - Medium
Y
Y Combinator Blog
IT之家
IT之家
博客园 - Franky
大猫的无限游戏
大猫的无限游戏
人人都是产品经理
人人都是产品经理
T
The Blog of Author Tim Ferriss
月光博客
月光博客
The Cloudflare Blog
U
Unit 42
GbyAI
GbyAI
L
LangChain Blog
Microsoft Azure Blog
Microsoft Azure Blog

博客园 - longyue

[BF学院_卷1] -- 第30讲:mixTable() 总结 —— Mixer 完整控制模型 [BF学院_卷1] -- 第29讲:applyMixToMotors() —— 最终 Motor Output 生成 [BF学院_卷1] -- 第28讲:applyMixerAdjustment() —— 为什么 Mixer 需要重新分配控制权限 [BF学院_卷1] -- 第27讲:PID Output 如何进入 Mixer —— 从控制需求到 motorMix [BF学院_卷1] -- 第26讲:calculateThrottleAndCurrentMotorEndpoints() —— Mixer 如何确定油门基础范围 [BF学院_卷1] -- 第25讲:mixTable() 总览 —— Mixer 在控制循环中的位置 [BF学院_卷1] -- 第24讲:mixer_init.c —— 飞控启动时如何准备 Mixer [BF学院_卷1] -- 第23讲:Mixer 数学模型 —— motorMixer_t 如何形成 Motor Output [BF学院_卷1] -- 第22讲:Betaflight 如何描述 Mixer —— mixer.h 数据结构 [BF学院_卷1] -- 第21讲:四旋翼为什么可以通过电机控制姿态 —— Mixer 背后的物理基础 [BF学院_卷1] -- 第20讲:从 PID Output 到 Motor Command(电机指令)——为什么飞控需要 Mixer [BF学院_卷1] -- 第19讲:PID Controller(PID控制器)——飞控到底如何理解误差并控制飞机? [BF学院_卷1] -- 第18讲:PID Controller 的最后一环——为什么飞控还需要 Feedforward(前馈控制)? [BF学院_卷1] -- 第17讲:D Term(微分控制项)——飞控如何提前感知运动变化? [BF学院_卷1] -- 第16讲:I Term(积分控制项)——飞机为什么总是差一点? [BF学院_卷1] -- 第15讲:P Term(比例控制项)——飞控是如何利用误差开始控制飞机的? [BF学院_卷1] -- 第13讲:Outer Loop 的终点——为什么还要读取 Current Angular Rate(当前角速度)? [BF学院_卷1] -- 第十二讲:Yaw Compensation(偏航补偿) [BF学院_卷1] -- 第12讲脚本 [BF学院_卷1] -- 第十一讲:Current Angular Rate(当前角速度)——飞控怎样知道飞机现在转得有多快? [BF学院_卷1] -- 第十讲:Angle Error(姿态角误差)如何变成 Desired Angular Rate(目标角速度) [BF学院_卷1] -- 第九讲:Current Angle(当前姿态角)遇见 Target Angle(目标姿态角) [BF学院_卷1] -- 第八讲:飞手打杆以后,飞控首先得到什么? [BF学院_卷1] -- 第七讲:为什么 Pitch Flip 只在 180° 看起来正确 [BF学院_卷1] -- 第7讲脚本 [BF学院_卷1] -- 第6讲:为什么 Pitch Flip 会骗人 [BF学院_卷1] -- 第6讲脚本 [BF学院_卷1] -- 第五讲:第一次修正——Pitch Flip 为什么看起来有效 [BF学院_卷1] -- 第5讲脚本 - longyue [BF学院_卷1] -- 第4讲:为什么"绕飞机自己转"不等于"朝世界转" - longyue
[BF学院_卷1] -- 第14讲:Rate Error(角速度误差)——PID 真...
longyue · 2026-08-03 · via 博客园 - longyue

第14讲:Rate Error(角速度误差)——PID 真正控制的到底是什么?


本讲知识点

  • 为什么 PID Controller(PID控制器)不能直接控制 Target(目标值)?
  • 为什么 PID Controller(PID控制器)不能直接控制 Current(实际值)?
  • Rate Error(角速度误差)为什么会成为 PID 的输入?
  • PID Controller(PID控制器)真正控制的永远是什么?
  • Rate Error(角速度误差)在控制链中的控制职责
  • Desired Angular Rate(目标角速度)与 Current Angular Rate(当前角速度)如何形成控制误差
  • PID Controller(PID控制器)为什么必须先得到 Error(误差)才能开始工作

本讲对应 Betaflight 源码

文件:

src/main/flight/pid.c

函数:

pidController()

本讲涉及源码:

const float gyroRate = gyro.gyroADCf[axis];

float errorRate = currentPidSetpoint - gyroRate;

上一讲,我们已经完成了:

const float gyroRate = gyro.gyroADCf[axis];

本讲将正式进入:

float errorRate = currentPidSetpoint - gyroRate;

并建立:

Rate Error(角速度误差)

为什么会成为整个 PID Controller(PID控制器)的输入。


本讲学习目标

上一讲结束以后,Inner Loop(内环)已经得到了:

Desired Angular Rate(目标角速度)

↓

Current Angular Rate(当前角速度)

但是,仅仅知道:

  • 应该转多快;
  • 现在转多快;

控制器仍然无法开始工作。

因为,PID Controller(PID控制器)真正需要的并不是:

Target(目标值)或者 Current(实际值)

而是:

Error(误差)。

因此,本讲将建立:

Rate Error(角速度误差)

并理解为什么:

PID Controller(PID控制器)控制的永远不是目标值,而是目标值与现实之间的误差。


回顾上一讲

上一讲结束时,我们已经进入了 Inner Loop(内环),并得到了:

Desired Angular Rate(目标角速度)

↓

Current Angular Rate(当前角速度)

控制链已经推进到:

RC Stick

↓

Target Angle

↓

Current Angle

↓

Angle Error

↓

Desired Angular Rate

↓

Current Angular Rate

现在,飞控终于同时知道了:

  • 飞机应该转多快;
  • 飞机现在转多快。

但是,一个新的问题出现了:

PID Controller(PID控制器)到底应该控制什么?

Target 和 Current 并不会直接产生控制

假设,现在外环希望飞机完成一次快速滚转:

Desired Angular Rate = 300°/s

与此同时,陀螺仪返回:

Current Angular Rate = 225°/s

于是,控制系统现在知道:

应该转:300°/s

现实却只有:225°/s

但是,此时 PID Controller(PID控制器)仍然无法开始工作。

因为对于 PID 来说, 300 和 225 其实都没有意义。

PID 并不关心目标是多少?也不关心现实是多少?

它真正关心的问题只有一个:现实距离目标还差多少?

因为:

控制系统真正需要控制的,永远都是误差。

PID Controller 真正需要的是什么?

继续观察刚才的例子:

Desired Angular Rate = 300°/s

Current Angular Rate = 225°/s

对于控制器来说,它真正关心的是:

300 - 225 = 75

也就是说, 飞机还少转了:75°/s。

于是, 75°/s 才是真正需要被控制的数据。

同样,如果现在变成:

Desired Angular Rate = 300°/s

Current Angular Rate = 330°/s

控制器得到的则是:

300 - 330 = -30°/s

它立刻知道:飞机已经转得太快了。

请注意这里发生的变化, 控制器看到的已经不再是 300 和 225, 而是:+75°/s 或者 -30°/s。

因此,对于 PID 来说,它真正需要控制的永远都是 Error(误差)。


Rate Error(角速度误差)的建立

直到这里,我们终于可以建立:

Rate Error(角速度误差)

它表示:

目标角速度 减去 当前角速度。

即:

Rate Error = Desired Angular Rate - Current Angular Rate

它的现实意义就是:

飞机距离我们希望达到的旋转速度,还差多少。

因此:

Desired Angular Rate

↓

Current Angular Rate

↓

Rate Error

实际上描述的是:

应该转多少

↓

现在转多少

↓

还差多少

控制器真正需要知道的永远都是最后一句:还差多少?


第二行源码终于出现了

现在,我们终于可以回到 pidController() 的第二行核心源码:

float errorRate = currentPidSetpoint - gyroRate;

请注意:

currentPidSetpoint 表示:Desired Angular Rate(目标角速度)

gyroRate 表示:Current Angular Rate(当前角速度)

因此:

float errorRate = currentPidSetpoint - gyroRate;

翻译成控制链语言就是:

Rate Error = Desired Angular Rate - Current Angular Rate

源码完成的事情其实非常简单:

它第一次告诉 PID Controller(PID控制器),飞机距离目标状态还差多少。

直到这一刻:

PID Controller(PID控制器)才终于获得了自己的输入。

为什么 PID 控制的永远都是 Error?

现在我们终于能够回答这个问题:

PID为什么不控制Target(目标值)?

因为:

Target(目标值)并不知道控制是否已经成功。

同样:

PID为什么不控制Current(实际值)?

因为:

Current(实际值)并不知道应该达到什么目标。

只有Target 和 Current 共同产生的Error(误差),才能同时告诉控制器:

  • 应该去哪里;
  • 现在在哪里;
  • 两者之间还差多少。

因此:

PID Controller(PID控制器)控制的永远不是目标值,也不是实际值,而是目标值与现实之间的误差。

这也是整个 PID 控制理论最核心的思想之一。


控制链继续推进

至此,控制链正式推进到:

RC Stick

↓

Target Angle

↓

Current Angle

↓

Angle Error

↓

Desired Angular Rate

↓

Current Angular Rate

↓

Rate Error

↓

???

现在,一个新的问题出现了:

PID Controller(PID控制器)已经拿到了 Rate Error(角速度误差)。

但是,它准备如何利用这个误差去控制飞机?

例如:

误差是:+75°/s, 应该增加多少控制量?

误差是:-30°/s,又应该减少多少控制量?

控制器仍然不知道答案。

于是,我们终于来到了 PID Controller(PID控制器)的第一部分。


本讲小结

本讲正式建立了 Rate Error(角速度误差)的控制职责。PID Controller(PID控制器)真正控制的并不是 Target(目标值)或者 Current(实际值),而是两者之间的 Error(误差)。只有当控制器同时知道目标值、现实值以及两者之间的差距时,它才能开始决定应该增加多少控制量或者减少多少控制量。

至此,Inner Loop(内环)已经完成了 PID Controller(PID控制器)的输入建立工作。


下一讲预告

现在,PID Controller(PID控制器)终于拿到了:

Rate Error(角速度误差)。

但是,它仍然不知道应该如何利用这个误差去控制飞机。

下一讲,我们将正式进入 PID Controller(PID控制器)的第一部分:

P Term(比例控制项)。

去看看飞控究竟是如何利用误差开始控制飞机的。