深入解析
简介
本页旨在介绍 BetaFlight 固件的内部工作机制。内容收集自以下来源:
- BetaFlight RC Groups 论坛(尽可能注明原作者)。
- 提供相关内容的 YouTube 频道。
准备点零食,找个舒服的位置阅读吧!
目录
- 开源软件开发的运作方式
- 基于陀螺仪的控制循环实现
delta_from_gyro设置与 PID 控制器 D 值- 滤波、混叠与陀螺仪同步
- Rates / rc rate 与 deg/sec 对照表
- 电机更新
开源软件开发的运作方式
以下视频介绍了同一爱好领域为何会存在多个软件分支(CleanFlight、BetaFlight、RaceFlight 等),以及开发者如何在项目间交流想法、推动代码演进:
http://www.youtube.com/watch?v=kZvoei1dzNQ
基于陀螺仪的控制循环实现
陀螺仪更新驱动整个控制循环。每当新的陀螺仪样本触发中断,循环便会开始;PID 控制器因此始终使用最新的陀螺仪值计算。若陀螺仪采样率为 1 kHz,会依据配置和目标硬件能力自动以 1000 us 或 500 us 的循环时间运行,因而不再需要手动设置 looptime。陀螺仪与控制循环之间不会漂移,PID 调校结果也更一致;理论上不会发生混叠。这也有助于滤波器更有效地输出干净的陀螺仪轨迹。

delta_from_gyro 设置与 PID 控制器 D 值
Boris B 写道:
开启 = delta from measurement / gyro
关闭 = delta from error
如果不先深入了解 PID 控制器的工作方式,这个概念很难解释。
下面尝试用相对易懂的方式说明。
在解释之前,先说明 PIDsum 中 Dterm 的决定因素:它是导数,也就是变化率,本质上表示某个量变化的速度。
假设你以恒定的 50 km/h 行驶,速度导数为 0;若踩下油门并持续加速,速度每秒增加 5 km/h,则速度导数为 5。开始减速时,速度导数会变为负值。
Delta from error:
这是经典的导数计算方法,反映误差的变化速度。误差来自摇杆输入;移动摇杆会引入误差,PID 控制器必须修正它。误差增长越快,导数越大。它有助于 PID 循环更快达到目标,会进一步加速响应,从而产生阻尼效果。
Delta from measurement/gyro:
这是将误差视作 0 后,对“从误差求导”进行数学简化的公式。
由于误差为 0,公式中去除误差后只剩下 -(measurement delta),即陀螺仪测量值的变化速度。陀螺仪在正方向增长越快,反方向的 Dterm 分量越大。
它会直接对 P 产生阻尼作用。
主要区别在于:Delta from error 会在一定程度上加速摇杆输入,但因跟随刷新率较低的摇杆数据而产生导数突变(derivative kick);delta from gyro 不会加速摇杆输入,也不会产生导数突变。
ctzsnooze 写道:
实际上,在 gyro 模式下,Dterm 与陀螺仪信号的变化率成反比。它总是抵消陀螺仪信号的变化。机架惯性会延迟陀螺仪对 P 变化的响应;但由于 Dterm 始终抵抗陀螺仪变化,它通常与 Pterm 符号相反(当然也与 Dterm 自身相反)。
正向摇杆输入使 Pterm 增大时,四轴飞行器的惯性最初会形成很大的 Pterm 误差信号。由于惯性质量,机体一开始并未运动;此时 Dterm 为零,而 Pterm 相当大。很快,电机升速并开始带动机体旋转;当旋转速率接近目标、误差下降时,Pterm 也会降低。Dterm 会减缓旋转开始的过程,使旋转起始和横滚结束都更平顺。但 Pterm 始终更强,因此飞行器最终会达到所需的旋转速率。旋转速率稳定后,Pterm 和 Dterm 都趋近于零。动量可能使机架在应当停止后仍继续旋转一小段;由于动量误差的实际偏差通常较小,P 只会较弱地抵抗它,而 Dterm 对 Pterm 的高速过冲非常敏感,能比 Pterm 更快地将其阻尼掉。
没有摇杆动作时,Pterm 抵抗作用于机架的外力。Pterm 响应幅度始终与目标旋转速率和实际测得旋转速率之间的误差成正比,例如飞入阵风产生的非预期旋转。
发生正向摇杆动作时,正的 rcCommand 会因机架无法立即达到新的目标旋转速率而突然产生负误差。因此每次正向 rcCommand 阶跃时,均可观察到小幅 Pterm 峰值。这就是 Pterm 基于误差的含义:随着摇杆输入,PTerm 会与 rcCommand 同方向变化。机架以所需速率旋转后,Pterm 误差下降;达到目标速度时变为零。
Dterm 以陀螺仪为基础时,其值与陀螺仪信号的变化率成正比,符号相反。非误差型 Dterm 不关注摇杆输入,只抵抗陀螺仪速率的变化,无论这种变化如何产生。因此,尽管在数学上它是导数,实际表现为振荡的阻尼机制,类似汽车悬架中的减振器。
由于机架惯性,基于陀螺仪的 Dterm 会略微滞后于 Pterm;但在摇杆输入期间,它通常与 Pterm 符号相反。
ctzsnooze 写道:
Dterm 可以只根据陀螺仪信号变化率计算,也可以根据从 rcCommand 到陀螺仪之间的误差计算。
前一种方法最早用于 Lux;MultiWii 和 Rewrite Dterm 在历史上采用基于误差的方式。
直到最近,BetaFlight 仍使用基于误差的 Dterm 计算;但自 2.3.4 起,Boris 回归了最初的 Lux 方法,仅根据陀螺仪信号的变化率推导 Dterm。
Dterm 的基本作用是抵抗陀螺仪变化,对快速变化的抵抗强于缓慢变化。若在 Acro 模式下手持四轴飞行器、无摇杆输入且突然极快地轻微倾斜它,最初抵抗这种突然微小变化的力量几乎完全来自 Dterm。
没有摇杆输入时,两种方法表现完全相同;但当控制输入使当前横滚速率与新的目标横滚速率之间突然产生“误差”时,二者差异明显。
当 D 基于误差时,rcCommand 突然改变误差值会产生强烈的“Dterm kick”。这个突变通常与期望动作同相,通过覆盖 Dterm 原本抵抗运动的响应来加快摇杆输入的响应。但是,它会在 Dterm 曲线上产生尖峰,SBus 较小、PPM 较大。实现 RC 平滑的主要原因就是处理这些尖峰:它能消除尖峰,同时保留“kick”效应。
突然输入摇杆时,如果 Dterm 寻求误差,四轴飞行器的响应会略快,因为 D 不会抵抗由摇杆输入引发的运动。这一差异是否明显尚不确定,但理论上应该更灵敏一些。
但也有潜在缺点:Dterm 不寻求误差时,突然摇杆输入后的摆动,例如横滚结束时的晃动,可能更小。此外,若未平滑这些“kick”,它们会在摇杆输入期间给电机带来噪声、降低效率;而为消除它们所用的 RC 平滑又可能引入延迟或其他问题。因此,Boris 希望重新评估哪种方式更好。
纯为测试目的,若能通过开关或 CLI 参数选择 Dterm 的计算模式,就可以在飞行中切换,以直观判断差异;否则必须刷写自定义版本,难以直接比较。
总之,在大幅摇杆输入时,新的 Dterm 方法会让 Blackbox 中的输入过程更平顺,并始终与陀螺仪反相,可能使摇杆输入时相对 Pterm 的响应略有延迟。少量提高 P 也许能抵消 Dterm kick 的损失;若确实如此,就不再需要误差寻求型 Dterm 计算。
补充资料
D 项对 P/D 控制器的影响:http://www.youtube.com/watch?v=xMygUvegC80
D 项的一般说明:http://en.wikipedia.org/wiki/Derivative
滤波、混叠与陀螺仪同步
以下视频以 BetaFlight 为背景制作,是深入学习这些复杂主题的优质资料:
滤波基础:http://www.youtube.com/watch?v=CpW8_fOJ7_M
使用 Nuhertz Spectra 分析多旋翼陀螺仪数据:http://www.youtube.com/watch?v=fZm9N-WFkQk
分析多旋翼调校的 FFT 图:http://www.youtube.com/watch?v=nxHK-V7GCYY
混叠与陀螺仪同步:http://www.youtube.com/watch?v=-lmoKal_e4s
BetaFlight V2.3.x 中的新双二阶滤波器:http://www.youtube.com/watch?v=Q2tSWU1MsVk
Rates / rc rate 与 deg/sec 对照表
Boris 在以下位置发布了对照表:
固定 rc rate 为 100 时,rate 的作用(rc rate 不影响偏航),满摇杆输入:
http://www.rcgroups.com/forums/showpost.php?p=34028934&postcount=18514
固定 rate 为 0 时,rc rate 的作用,满摇杆输入:
http://www.rcgroups.com/forums/showpost.php?p=34028937&postcount=18515
以及仅偏航 rate 的作用: http://www.rcgroups.com/forums/showpost.php?p=34028986&postcount=18516
电机更新
我来自与控制律完全不同的 VOIP 领域;不过实时音视频处理中的抖动问题甚至更突出,也有多种应对方式。另一种选择是在电机输出信号来得过早、前一个信号尚未结束时丢弃该输出。
举例来说:新方法的 cycletime 为 125 us,PID 循环为 375 us。电机更新发生在新 cycletime 的开始,而不是新的 PID looptime 开始时。
启动 GYRO/PID 循环------>+125us GYRO/MOTOR----->+125us GYRO----> +125 PID/GYRO------->+125 GYRO/MOTOR (375us)
电机更新率高于循环率毫无意义,因为数值仍会被覆盖并导致抖动。这正是我目前正在重构任务调度的原因。
理想的电机处理方式是:仅在有新的混控计算结果时写入电机;且两次电机更新的间隔绝不能小于期望周期。更长的更新间隔并无问题,只要下一次电机更新不与前一次重叠。
假设 PID 控制器 / 混控器请求 OneShot125 的全电机功率,其 PWM 周期约为 250 us。若以 2 kHz 更新电机,合计有 250 us 的空闲区间,在这一区间内的具体更新时间并不重要,因此允许的抖动时间略小于 250 us。
在 4 kHz 速度下,电机更新周期完全不允许出现抖动,否则无法达到全油门。
电机更新过晚无关紧要,但绝不能过早更新。
如今循环时间很低,电机更新已接近 cycletime 末尾,因此不存在所谓延迟问题;无论在末尾还是开头完成操作都没有区别。可以把它想象成绕圈跑步,无法区分哪里是开始、哪里是结束,顺序不再重要。
cycletime 末尾的抖动最大,时间变化在 0 至 100 us 之间。尤其在低循环时间下,为获得最大效率而采用调度任务机制时,循环周期末尾的抖动非常明显。
因此,将电机更新移到循环开始位置可以获得恒定时序。原先在循环末尾写入电机产生的可变延迟,现在变为固定延迟。
抖动对 OneShot 信号很关键,因为 60 us 的周期几乎相当于半个 OneShot 信号。