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

推荐订阅源

奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
大猫的无限游戏
大猫的无限游戏
博客园 - 聂微东
Jina AI
Jina AI
The Cloudflare Blog
V
Visual Studio Blog
博客园_首页
量子位
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 【当耐特】
爱范儿
爱范儿
博客园 - 三生石上(FineUI控件)
小众软件
小众软件
博客园 - 司徒正美
阮一峰的网络日志
阮一峰的网络日志
Last Week in AI
Last Week in AI
V
V2EX
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 叶小钗
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
WordPress大学
WordPress大学
宝玉的分享
宝玉的分享
T
Tailwind CSS Blog
博客园 - Franky

博客园 - 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] -- 第14讲:Rate Error(角速度误差)——PID 真正控制的到底是什么? [BF学院_卷1] -- 第15讲:P Term(比例控制项)——飞控是如何利用误差开始控制飞机的? [BF学院_卷1] -- 第13讲:Outer Loop 的终点——为什么还要读取 Current Angular Rate(当前角速度)? [BF学院_卷1] -- 第十二讲:Yaw Compensation(偏航补偿) [BF学院_卷1] -- 第12讲脚本 [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] -- 第十一讲:Current Angular Rate(当前角速...
longyue · 2026-08-03 · via 博客园 - longyue

第十一讲:Current Angular Rate(当前角速度)——飞控怎样知道飞机现在转得有多快?

  • Desired Angular Rate(目标角速度)为什么还不能直接进入 PID
  • Current Angular Rate(当前角速度)是什么
  • Gyroscope(陀螺仪)为什么输出的是角速度
  • Current Angular Rate(当前角速度)的来源
  • 为什么 Current Angular Rate(当前角速度)是 Inner Loop(内环)的输入之一
  • 下一步为什么必须计算 Rate Error(角速度误差)

本讲对应 Betaflight 源码

源码文件

src/main/flight/pid.c

核心变量

gyro.gyroADCf[axis]

本讲对应控制流程

Desired Angular Rate(目标角速度)
        │
        ▼
Current Angular Rate(当前角速度)

本讲学习目标

阅读完本讲以后,你应该能够回答:

□ 为什么 Desired Angular Rate(目标角速度)还不能直接进入 PID?

□ Current Angular Rate(当前角速度)是什么?

□ 飞控怎样知道飞机现在真正转得有多快?

□ Gyroscope(陀螺仪)为什么输出的是角速度,而不是姿态角?

gyro.gyroADCf[axis] 表示什么?

□ Current Angular Rate(当前角速度)在整个控制链中的作用是什么?


回顾上一讲

上一讲,

Angle Mode(自稳模式)的 Outer Loop(外环)已经全部完成。

飞控已经把:

Angle Error(姿态角误差)

转换成了:

Desired Angular Rate(目标角速度)

对应源码就是:

float angleRate =
    errorAngle * pidRuntime.angleGain
    + angleFeedforward;

这一行代码完成以后,飞控已经知道:

飞机现在应该以:

多少角速度,开始继续旋转。

例如:

Desired Angular Rate = 60°/s

看到这里,很多初学者都会认为:

飞控已经知道:

应该以 60°/s 旋转。

那么,

是不是直接交给 PID,飞机就开始运动了?

答案仍然是否定的。

原因只有一句话:

飞控虽然知道:

应该转多快。

但是,它还不知道:

飞机现在,到底转得有多快。

这就是:

Inner Loop(内环)真正开始之前,必须解决的问题。


飞控真正缺少的信息是什么?

上一讲,飞控得到的是:

Desired Angular Rate(目标角速度)

它表示:

飞机现在,希望达到的旋转速度。

但是,这里仍然只有:

希望。

飞控仍然不知道现实情况。

例如:

飞控希望:

60°/s

但是飞机真正可能正在:

40°/s

也可能:

65°/s

甚至:

0°/s

如果飞控不知道:

飞机真实角速度。

那么,它就永远不知道:

控制命令,到底有没有真正执行出来。

因此,控制系统必须增加一个新的变量:

Current Angular Rate(当前角速度)

它表示:

飞机此刻,真正的旋转速度。

Current Angular Rate(当前角速度)是什么?

Current Angular Rate(当前角速度)

第一次看到这个名字,很多人容易把它理解成:

飞机当前角度。

其实,这是两个完全不同的物理量。

例如:

如果飞机保持:

Pitch = 30°

那么:

Current Angle(当前姿态角)

= 30°

这是:

飞机现在停留的位置。

但是,如果飞机正在继续向前翻滚,

例如:

每秒继续旋转:

80°

那么:

Current Angular Rate(当前角速度)

= 80°/s

它描述的是:

飞机旋转得有多快。

因此,这两个变量分别回答的是两个不同的问题:

Current Angle

↓

飞机现在,在哪里?

而:

Current Angular Rate

↓

飞机现在,转得有多快?

这是 Outer Loop(外环)

和 Inner Loop(内环)

最大的区别。

Outer Loop(外环)始终关心:

位置。

Inner Loop(内环)开始关心:

速度。

为什么一定要知道 Current Angular Rate?

可以想象一个现实生活中的例子。

例如:

你正在开汽车。

导航告诉你:

目标速度:60 km/h

但是,如果仪表盘坏了,你完全不知道:

现在到底是:

30 km/h

还是:

80 km/h。

那么,

你还能稳定保持:

60 km/h

吗?

当然不能。

因为:

你没有:

反馈。

飞控也是一样。

上一讲得到的:

Desired Angular Rate(目标角速度)

其实就相当于:

导航告诉你的:

目标速度。

而:

Current Angular Rate(当前角速度)

就是:

速度表。

只有:

目标速度 + 当前速度

同时存在,飞控才能开始判断:

到底还差多少。

但是,这个"还差多少",我们这一讲还不会计算。

这一讲,只负责建立:

Current Angular Rate(当前角速度)

这个新的变量。

下一讲,它才会第一次参与控制。


那么,飞控怎样知道飞机现在转得有多快?

到这里,新的问题自然出现了:

Current Angular Rate(当前角速度)

到底来自哪里?

Current Angle(当前姿态角)上一讲已经知道,来自:

姿态解算。

那么:

Current Angular Rate(当前角速度)

是不是也是姿态解算出来的?

答案:

不是。

它直接来自:

Gyroscope(陀螺仪)。

Gyroscope(陀螺仪)为什么测的是角速度?

现在,我们已经知道:

Current Angular Rate(当前角速度)

来自:

Gyroscope(陀螺仪)。

很多人第一次学习飞控时,又会产生新的疑问:

为什么陀螺仪测出来的是:

角速度?

而不是:

姿态角?

这个问题其实非常重要。

因为它决定了:

为什么飞控一定要分成:

Outer Loop(外环)

↓

Inner Loop(内环)

两层控制。


如果没有陀螺仪,会发生什么?

假设,

现在飞机已经开始旋转。

飞控希望它:

60°/s

继续旋转。

但是,如果没有陀螺仪,飞控能够知道什么?

它只能知道:

目标角速度:

60°/s

却不知道:

飞机真正有没有:

60°/s。

也就是说:

飞控失去了:

反馈。

没有反馈,控制系统就无法判断:

应该继续增加动力?

还是已经转得太快,需要减小动力?

因此,飞控必须实时知道:

飞机当前真正的旋转速度。

而这个信息,只有陀螺仪能够提供。


Gyroscope(陀螺仪)真正测量的是什么?

很多初学者容易认为:

陀螺仪负责告诉飞控:

飞机现在是多少度。

其实,

这是一种非常常见的误解。

Gyroscope(陀螺仪)根本不知道:

飞机现在朝向哪里。

它真正能够测量的是:

飞机此刻,正在旋转得有多快。

例如:

飞机完全静止时:

Pitch Angular Rate

= 0°/s

如果开始缓慢抬头:

Pitch Angular Rate

= 20°/s

如果快速翻滚:

Roll Angular Rate

= 300°/s

可以发现,

Gyroscope(陀螺仪)

始终描述的是:

速度。

而不是:

位置。

为什么 Gyroscope(陀螺仪)不能直接得到姿态角?

可以用一个生活中的例子来理解。

假设,

汽车仪表盘上只有:

速度表。

速度表能够告诉你:

现在:

60 km/h

但是,它不能告诉你:

汽车已经开到了:第几公里。

原因很简单:

速度 ≠ 位置。

同样,陀螺仪测量的是:

Angular Rate(角速度)

而不是:

Angle(角度)

因此,飞控不能直接从陀螺仪得到:

Current Angle(当前姿态角)。

姿态角,必须经过:

姿态解算(Attitude Estimation)

才能得到。

所以,飞控内部实际上同时存在两类完全不同的数据:

Current Angle(当前姿态角)

↓

姿态解算得到。

以及:

Current Angular Rate(当前角速度)

↓

Gyroscope(陀螺仪)直接测量。

两者不能混淆。


Gyroscope(陀螺仪)得到的是哪一个时刻的角速度?

到这里,很多初学者都会产生一个新的疑问:

飞机一直在运动。

角速度一直在变化。

那么:

gyro.gyroADCf[axis] 里面保存的,

到底是哪一个时刻的角速度?

很多人第一次学习飞控时,都会下意识想到一种解释:

飞控隔一段时间,读取一次陀螺仪。

↓

那么:

是不是软件两次读取之间,求出来的平均角速度?

实际上,

并不是。


它不是软件计算出来的平均值

先来看一种错误理解。

假设:

飞控:

每 250μs 读取一次陀螺仪。

很多人就会认为:

这 250μs 内,飞机不断旋转。

↓

软件把这段时间,平均一下。

↓

得到:

Current Angular Rate。

事实上,飞控并没有做这件事情。

CPU(中央处理器)只是:

读取。

它并不会先把:

250μs 里面所有角速度拿出来平均。

原因很简单:

飞控根本拿不到这段时间内的所有历史数据。


真正测量角速度的是 IMU(惯性测量单元)

真正一直在工作的,其实不是 CPU,

而是:

IMU(惯性测量单元)

IMU 内部,一直在不断完成:

角速度采样

↓

数字滤波

↓

更新输出寄存器

也就是说,IMU 自己一直在高速工作。

飞控只是:

周期性读取:

最新结果。

因此,真正发生的过程更接近:

IMU 一直测量

↓

不断更新寄存器

↓

CPU 过来读取一次。

可以发现:

CPU 并没有参与:

角速度计算。

它只是:

读取已经准备好的结果。

Current Angular Rate(当前角速度)中的"Current"是什么意思?

看到这里,很多人又会继续问:

既然不是平均值。

那么:

Current(当前)到底是什么意思?

这里,Current(当前)并不是:

软件读取这一刻,瞬间重新计算出来。

而是:

IMU 最近一次刷新出来的最新角速度。

因此,可以把它理解成:

Current Angular Rate

≈ IMU 最新一次输出的角速度。

注意,这里强调的是:

最新。

而不是:

平均。

因此,Current(当前)真正表达的是:

这是飞控目前能够拿到的,最新的一份角速度数据。

用时间轴理解整个过程

下面用一个简化的时间轴,来看整个过程。

假设:

IMU(惯性测量单元)输出频率为:

8kHz

意味着:

每:

125μs 更新一次角速度。

而飞控 PID Loop(控制循环)运行频率为:

4kHz

意味着:

每:

250μs 读取一次。

整个过程就变成:

时间 →

0μs

IMU 输出:

ω₁

↓

125μs

IMU 输出:

ω₂

↓

250μs

CPU 开始读取。

↓

CPU 读到:

ω₂

(最新值)

↓

375μs

IMU 输出:

ω₃

↓

500μs

CPU 再次读取。

↓

CPU 读到:

ω₄

(最新值)

可以发现:

CPU 每次读取的,都不是:

这一段时间的平均值。

而是:

寄存器里面,最新刷新出来的一份角速度。

注意:

这里只需要知道:

Current Angular Rate(当前角速度)来自 IMU 最新一次输出。

至于:

为什么长期积分不会越来越偏,飞控如何修正陀螺仪漂移,

属于后续姿态解算(Attitude Estimation)专题,

将在后面的课程中详细展开。


为什么要这样设计?

很多人会继续追问:

为什么不用平均值?

为什么一定要最新值?

原因就在于:

飞控控制的是:

实时控制。

例如,

飞机突然受到一阵风影响,角速度瞬间发生变化。

如果飞控使用:

过去一段时间的平均值。

那么:

得到的结果就会:

比真实状态慢半拍。

控制器会误以为:

飞机还没有开始旋转。

实际上,飞机可能已经:

快速滚转起来了。

因此,飞控更希望知道的是:

飞机此刻,最新的真实状态。

而不是:

过去一段时间的平均状态。

所以,IMU 每刷新一次,飞控都会尽快读取:

最新角速度。

这样,整个控制系统才能保持:

最快响应。

本小节总结

因此,

gyro.gyroADCf[axis]

真正表示的是:

Gyroscope(陀螺仪)

最近一次输出的:

最新角速度。

它:

不是:

软件计算出来的平均值;

不是:

软件积分得到的角度;

也不是:

历史一段时间的统计结果。

它只是:

飞控当前能够获得的,最新角速度测量值。

后面,Rate PID(角速度内环)正是利用这一份:

最新真实状态

去和:

Desired Angular Rate(目标角速度)

进行比较,计算真正的:

Rate Error(角速度误差)。

gyro.gyroADCf[axis] 是什么?

现在,终于回到源码。

在 Betaflight 中,

Current Angular Rate(当前角速度)

对应的重要变量就是:

gyro.gyroADCf[axis]

第一次看到这个变量,很多人都会被名字吓到。

其实,把它拆开以后,就容易理解了。

首先:

gyro

表示:

Gyroscope(陀螺仪)

说明:

这个变量来自:

陀螺仪。

然后:

ADC

表示:

最早的数据来源于:

ADC(模数转换)

虽然现代 IMU(惯性测量单元)内部已经完成数字化,

这个名字仍然保留了下来,作为历史命名。

最后:

f

表示:

float

说明:

当前保存的是:

浮点数形式的数据。

因此,整个变量可以理解成:

Gyroscope(陀螺仪)提供的:

当前角速度(浮点数)。

这里,

axis 表示三个不同轴:

Roll

Pitch

Yaw

因此,飞控能够同时知道:

Roll 当前角速度

Pitch 当前角速度

Yaw 当前角速度

Current Angular Rate(当前角速度)在控制链中的位置

到这里,我们已经认识了新的变量:

Current Angular Rate(当前角速度)

但是,它真正的重要性,并不在于它来自:

Gyroscope(陀螺仪)。

真正重要的是:

它终于让控制链具备了"比较"的条件。

上一讲结束时,飞控只有:

Desired Angular Rate(目标角速度)

它表示:

飞机应该转多快。

而这一讲,飞控又得到了:

Current Angular Rate(当前角速度)

它表示:

飞机实际上,正在转多快。

于是,控制链第一次同时拥有了:

目标值

↓

实际值

看到这里,很多人都会下意识想到:

既然:

目标有了,实际也有了。

是不是马上就可以开始比较?

答案是:

可以。

但是,

这一步,将留到下一讲。

因为:

本讲只负责建立:

Current Angular Rate(当前角速度)

这个变量。

真正的:

比较

将在下一讲正式发生。


为什么 Current Angular Rate(当前角速度)必须属于 Inner Loop(内环)?

现在,可以重新回顾:

Outer Loop(外环)

Inner Loop(内环)

最大的区别。

Outer Loop(外环)始终讨论的是:

姿态角(Angle)

它关心的是:

飞机应该停在哪里。

所以,

上一讲一直围绕:

Target Angle(目标姿态角)

↓

Current Angle(当前姿态角)

↓

Angle Error(姿态角误差)

展开。

而从这一讲开始,控制对象发生了变化。

Inner Loop(内环)开始讨论的是:

角速度(Angular Rate)

它关心的是:

飞机现在,到底转得有多快。

因此,控制链自然推进为:

Desired Angular Rate(目标角速度)

↓

Current Angular Rate(当前角速度)

可以发现,Outer Loop(外环)负责的是:

位置。

Inner Loop(内环)负责的是:

运动。

这也是飞控能够既稳定,又响应快速的重要原因。


为什么 Current Angular Rate(当前角速度)不能直接控制电机?

很多初学者看到这里,还会继续追问:

既然:

Current Angular Rate(当前角速度)

已经知道了。

是不是:

直接控制电机就可以?

答案依然是否定的。

原因其实很简单。

Current Angular Rate(当前角速度)

只是:

当前状态。

它描述的是:

飞机现在,正在发生什么。

但是,控制器真正需要知道的是:

距离目标,还差多少。

因此,飞控下一步,一定还需要完成一次新的计算。

它需要回答:

目标角速度:

60°/s

↓

当前角速度:

42°/s

↓

还差:

多少?

只有得到这个新的误差以后,

PID(比例–积分–微分控制器)

才真正知道:

应该继续增加动力,

还是减小动力。

所以,

Current Angular Rate(当前角速度)

依然不是:

最终控制量。

它只是:

下一步计算所需要的:

实际值(Actual Value)。

本讲总结

经过这一讲,

Inner Loop(内环)正式开始。

控制链继续推进了一步:

RC Stick(遥控器摇杆)

↓

Target Angle(目标姿态角)

↓

Current Angle(当前姿态角)

↓

Angle Error(姿态角误差)

↓

Desired Angular Rate(目标角速度)

↓

Current Angular Rate(当前角速度)

到这里,飞控已经同时知道:

飞机应该转多快。

以及:

飞机现在真正转多快。

这意味着:

控制系统终于具备了:

比较目标值

与

实际值

的全部条件。

但是,真正的比较,我们仍然没有开始。


下一讲预告

现在,

飞控已经拥有:

Desired Angular Rate(目标角速度)

Current Angular Rate(当前角速度)

下一讲,它们将第一次相遇。

飞控将计算:

errorRate = desiredRate - gyroRate;

也就是:

Rate Error(角速度误差)

从这里开始,Betaflight 真正的:

Rate PID(角速度内环)

将正式开始工作。

控制链也将继续推进为:

Desired Angular Rate(目标角速度)

↓

Current Angular Rate(当前角速度)

↓

Rate Error(角速度误差)

↓

Rate PID(角速度内环)