[BF学院_卷1] -- 第十讲:Angle Error(姿态角误差)如何变成 Desired Angular Rate(目标角速度)
第十讲:Angle Error(姿态角误差)如何变成 Desired Angular Rate(目标角速度)
- 为什么 Angle Error(姿态角误差)不能直接控制飞机
- Desired Angular Rate(目标角速度)到底是什么
- Outer Loop(外环)为什么要把角度变成角速度
angleRate = errorAngle * angleGain + angleFeedforward这一行代码在做什么- Angle Mode(自稳模式)的 Outer Loop(外环)正式开始工作
学习目标
阅读完本讲以后,你应该能够回答:
□ 为什么 Angle Error(姿态角误差)不能直接控制飞机?
□ 什么是 Desired Angular Rate(目标角速度)?
□ Outer Loop(外环)为什么要把角度变成角速度?
□ angleRate = errorAngle * angleGain + angleFeedforward 这一行代码在做什么?
□ Angle Mode(自稳模式)的 Outer Loop(外环)正式开始工作
本讲源码位置
src/main/flight/pid.c
Angle Mode(自稳模式)外环控制:
float angleRate =
errorAngle * pidRuntime.angleGain
+ angleFeedforward;
本讲只讨论:
errorAngleangleGainangleRate
暂不讨论:
angleFeedforward
回顾上一讲
上一讲我们已经得到:
Target Angle(目标姿态角)
它表示飞手希望飞机最终达到的姿态。
例如:
Pitch = 30°
但飞控仍然无法控制飞机,因为它还不知道:
飞机现在在哪里?
Current Angle(当前姿态角)的来源
在 Betaflight 中:
const float currentAngle =
(attitude.raw[axis] - angleTrim->raw[axis]) / 10.0f;
attitude.raw[] 是什么?
表示飞机当前姿态估计值,由姿态解算系统(陀螺仪 + 加速度计)计算得到。
在本课程中可以理解为:
attitude.raw[] = 当前飞机姿态
angleTrim->raw[] 是什么?
用于补偿机架安装误差,例如:
- 飞控安装倾斜
- 机架轻微不水平
作用:
消除静态安装偏差
/10.0f 是什么?
attitude.raw 的单位是:
0.1°
因此需要转换为:
°
得到 Current Angle
最终:
Current Angle(当前姿态角)
= 去除安装误差 + 单位转换
Angle Error(姿态角误差)
计算公式:
Angle Error = Target Angle - Current Angle
示例
Target Angle = 30°
Current Angle = 18°
则:
Angle Error = 12°
表示:
飞机距离目标还差 12°
为什么 Angle Error 不能直接控制飞机?
因为电机无法执行:
角度(Angle)
电机只能执行:
角速度(Angular Rate)
本质区别
| 类型 | 飞控理解 | 电机能力 |
|---|---|---|
| Angle | 位置 | ❌不能执行 |
| Angular Rate | 速度 | ✅可以执行 |
Angle Mode 外环的作用
告诉飞机应该以多快速度旋转
核心代码解析
到这里,飞控已经完成了前面的全部工作,控制链已经推进到:
Target Angle(目标姿态角)
↓
Current Angle(当前姿态角)
↓
Angle Error(姿态角误差)
上一讲最后,我们已经计算出了:
const float errorAngle =
angleTarget
-
currentAngle;
很多初学者看到这里,都会产生一个疑问:
Angle Error(姿态角误差)
已经计算出来了,
飞机是不是马上就可以开始旋转了?
答案仍然是否定的。
原因就在于:
Angle Error(姿态角误差)仍然只是一个"位置误差",它还不是电机能够执行的控制命令。
真正让飞机开始运动的,是下面这一行源码:
float angleRate =
errorAngle * pidRuntime.angleGain
+ angleFeedforward;
这一行代码,就是 Betaflight Angle Mode(自稳模式)Outer Loop(外环)真正开始工作的地方。
如果把这一行源码翻译成一句中文,它实际上表达的是:
根据飞机距离目标姿态还有多少角度,
计算:
飞机现在应该以多快的速度开始旋转。
因此,这一行代码完成了一件非常重要的事情:
Angle(角度)
↓
Angular Rate(角速度)
Outer Loop(外环)的全部任务,就是完成这一次转换。
Angle Error 已经计算出来了,为什么还不能控制飞机?
上一节,飞控已经完成了这一行计算:
errorAngle = Target Angle - Current Angle;
也就是说,飞控已经知道:
飞机距离目标姿态,还差多少角度。
例如:
Target Angle = 30°
Current Angle = 18°
Angle Error = 12°
这里的:
12°
只是表示:
当前位置距离目标位置,还有 12° 没有完成。
注意,
它仍然只是:
位置误差(Angle Error)。
它还不是:
电机能够执行的控制命令。
真正的问题来了:
既然已经知道:
飞机还差 12°,为什么飞控还不能马上控制飞机开始旋转?
答案就在下一节。
为什么电机不能直接执行 Angle Error?
很多初学者第一次学习飞控时,都会下意识认为:
飞机还差 12°
↓
那就继续转 12° 不就可以了吗?
听起来似乎很合理,但实际上,对于电机来说,这样的命令根本无法执行。
原因是:电机能够控制的,从来不是角度(Angle),而是角速度(Angular Rate)。
例如,下面两个命令对于电机来说是完全不同的:
命令一:
转到 30°
(Angle)
命令二:
以 60°/s 持续旋转
(Angular Rate)
第一种命令描述的是最终停留的位置。
第二种命令描述的是:
每一秒,应该旋转多少度。
真正能够直接驱动电机工作的,是第二种。
因此,当飞控计算出:
Angle Error = 12°
它得到的信息只是:
飞机距离目标姿态,还差 12°。
但是,这里面仍然缺少一个最关键的信息:
应该以多快的速度,去完成这 12°?
所以,飞控还必须继续完成一次新的计算。
angleGain(角度增益)是什么?
继续来看源码中的第二个变量:
pidRuntime.angleGain
很多资料都会直接说:
angleGain,是一个 Gain(增益)。
但是,对于第一次学习 PID 的人来说,这种解释几乎没有帮助。
真正容易理解的方法是:
把它看成一种:
转换比例。
它规定了一件事情:
每差 1°,应该输出多少角速度。
例如,假设:
angleGain = 5
那么:
误差:
1°
↓
输出:
5°/s
如果误差变成:
2°
那么输出就会变成:
10°/s
继续扩大:
误差:
10°
输出:
50°/s
如果:
误差:
20°
输出:
100°/s
可以发现:
误差扩大多少倍,
输出速度也扩大多少倍。
因此:
angleGain 的真正作用,就是把"角度误差"翻译成"目标角速度"。
第一项:errorAngle × angleGain 到底得到了什么?
现在,
Outer Loop(外环)已经拥有了两个条件:
当前还差多少角度
(Angle Error)
以及:
每差 1°,应该输出多少角速度(angleGain)
接下来,
飞控真正开始进行第一次控制计算:
errorAngle * angleGain
也就是说:
把:
姿态误差,转换成,目标角速度。
那么,把它们相乘以后:
errorAngle * angleGain
到底表示什么?
答案就是:
根据当前姿态误差,计算得到:
飞机此刻应该达到的目标角速度。
也就是说:
Angle Error(角度误差)
↓
Desired Angular Rate(目标角速度)
真正发生转换的位置,就是这里。
举一个完整例子
假设:
Target Angle = 30°
Current Angle = 18°
因此:
Angle Error = 12°
再假设:
angleGain = 5
那么:
angleRate
= 12 × 5
= 60°/s
飞控得到的新目标就变成了:
飞机现在应该以:
60°/s,继续旋转。
注意,
这里已经不是:
还差多少角度。
而是:
应该以什么速度旋转。
这就是 Outer Loop(外环)最重要的一次翻译。
为什么 Outer Loop 一定要把 Angle(角度)变成 Angular Rate(角速度)?
上一节,我们已经知道:
电机不能直接执行:
Angle(角度)。
因此,
Outer Loop(外环)必须先把:
Angle Error
↓
Desired Angular Rate
完成转换。
那么问题来了:
为什么电机不能直接控制角度,
却能够控制角速度?
答案来自飞机本身的物理运动过程。
飞机真正能够控制的对象,是:
四个电机的转速。
电机转速发生变化以后,
首先产生的是:
力矩(Torque)
然后:
力矩
↓
角加速度
角加速度继续作用以后,
才会产生:
角速度(Angular Rate)
最后,
角速度不断积累,飞机的位置(姿态角)才会发生变化。
因此,
整个物理过程实际上是:
电机
↓
力矩
↓
角加速度
↓
角速度
↓
姿态角
可以发现:
电机距离:
姿态角(Angle)
中间隔着很多层。
但是距离:
角速度(Angular Rate)
却只有一步。
所以,
飞控不会直接控制:
Angle(角度)。
而是先控制:
Angular Rate(角速度)。
这样,整个控制链才符合飞机真实的物理运动过程。
P 控制为什么会产生"误差越大,转得越快"?
很多资料都会写一句话:
P 控制:
误差越大,输出越大。
第一次看到的人,往往会觉得:
这只是一个结论。
其实,
它完全可以从刚才的公式直接看出来。
回到源码:
angleRate = errorAngle * angleGain
如果:
Angle Error = 2°
输出就是:
10°/s
如果:
Angle Error = 10°
输出就是:
50°/s
如果:
Angle Error = 20°
输出就是:
100°/s
可以发现:
误差越大,目标角速度也越大。
这就是:
P(Proportional),比例控制
名字的真正来源。
因为:
输出始终保持:
输出
∝
误差
它们始终保持固定比例。
因此,
飞控会自然表现出一种直觉:
离目标越远,转得越快;
离目标越近,转得越慢。
飞机最终就会越来越平滑地停在目标姿态附近。
angleFeedforward 是什么?
继续看源码:
float angleRate =
errorAngle * pidRuntime.angleGain
+ angleFeedforward;
除了:
errorAngle × angleGain
后面还有:
angleFeedforward
本讲暂时不会展开它的具体算法。
但是,
至少需要知道:
它并不是:
PID 的一部分。
它的作用更接近:
提前补偿。
也就是说,除了根据:
当前误差
计算目标角速度以外,
飞控还会根据飞手打杆的动作,
提前增加一部分角速度,
让飞机感觉:
响应更直接,更跟手。
因此,
这一行代码实际上由两部分组成:
第一部分:
errorAngle × angleGain
↓
根据姿态误差,计算应该旋转多快。
以及:
第二部分:
angleFeedforward
↓
提前增加一点目标角速度,提高操纵响应速度。
后面课程,我们会单独进入:
Feedforward(前馈控制)
专题,
详细讨论它为什么能够让飞机感觉"更丝滑"。
因此,
现在只需要知道:
它负责:
提前补偿,而不是修正误差。
整行代码最终完成了什么?
现在,
再回来看整行源码:
float angleRate =
errorAngle * pidRuntime.angleGain
+ angleFeedforward;
终于可以把它完整翻译成一句中文:
根据飞机距离目标姿态还有多少角度,
计算:
飞机现在应该以多快速度开始旋转,
同时加入前馈补偿,提高操纵响应。
经过这一行代码,
Outer Loop(外环)的工作已经结束。
它最终输出给下一层的是:
Desired Angular Rate(目标角速度)
也就是说,
飞控已经完成了:
Angle(角度)
↓
Angular Rate(角速度)
这一整次翻译。
接下来,
这个目标角速度将交给下一层:
Rate PID(角速度内环)
继续处理。
因此,
控制链继续推进:
Target Angle
↓
Current Angle
↓
Angle Error
↓
Desired Angular Rate
但是,
飞控仍然不知道:
飞机现在,真正的角速度,是多少?
只有知道:
Current Angular Rate(当前角速度)
才能计算:
Rate Error(角速度误差)
真正进入:
Rate PID(角速度内环)
Angle Mode 外环总结
经过本讲,
Outer Loop(外环)已经全部完成。
控制链现在变成:
RC Stick(遥控器摇杆)
↓
Target Angle(目标姿态角)
↓
Current Angle(当前姿态角)
↓
Angle Error(姿态角误差)
↓
Desired Angular Rate(目标角速度)
可以发现,
Outer Loop(外环)始终没有控制电机。
它只完成了一件事情:
把:
飞手希望飞机停在哪个姿态,
翻译成:
飞机现在应该以什么角速度开始旋转。
真正负责驱动飞机的,其实还在下一层。
下一讲预告
现在,
飞控已经得到:
Desired Angular Rate(目标角速度)
但是,
它仍然不知道:
飞机现在,真正的角速度,是多少?
下一讲,
我们正式进入:
Current Angular Rate(当前角速度)
并开始进入 Betaflight 真正的核心控制器:
errorRate = desiredRate - gyroRate;
从这里开始,
Rate PID(角速度内环)将正式接管飞机的控制。
浙公网安备 33010602011771号