[BF学院_卷1] -- 第十一讲:Current Angular Rate(当前角速度)——飞控怎样知道飞机现在转得有多快?
第十一讲: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(角速度内环)
浙公网安备 33010602011771号