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

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
T
Tailwind CSS Blog
有赞技术团队
有赞技术团队
爱范儿
爱范儿
Engineering at Meta
Engineering at Meta
J
Java Code Geeks
雷峰网
雷峰网
WordPress大学
WordPress大学
L
LangChain Blog
D
DataBreaches.Net
The GitHub Blog
The GitHub Blog
博客园 - 三生石上(FineUI控件)
Microsoft Security Blog
Microsoft Security Blog
P
Proofpoint News Feed
腾讯CDC
GbyAI
GbyAI
罗磊的独立博客
Blog — PlanetScale
Blog — PlanetScale
月光博客
月光博客
F
Fortinet All Blogs
Y
Y Combinator Blog
V
V2EX
A
About on SuperTechFans

博客园 - longyue

[BF学院_卷1] -- 第30讲:mixTable() 总结 —— Mixer 完整控制模型 [BF学院_卷1] -- 第29讲:applyMixToMotors() —— 最终 Motor Output 生成 [BF学院_卷1] -- 第28讲:applyMixerAdjustment() —— 为什么 Mixer 需要重新分配控制权限 [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] -- 第十一讲: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] -- 第27讲:PID Output 如何进入 Mixer —— 从控...
longyue · 2026-08-03 · via 博客园 - longyue

第27讲:PID Output 如何进入 Mixer —— 从控制需求到 motorMix


本讲知识点

  • PID Output 在控制链中的位置;
  • pidData[].Sum 代表什么控制需求;
  • Roll / Pitch / Yaw PID Output 为什么需要限制;
  • PID Mixer Scaling 的作用;
  • scaledAxisPidRoll / Pitch / Yaw 的形成过程;
  • PID 输出如何通过 motorMixer_t 转换为 motorMix;
  • Mixer 如何完成控制需求到电机修正量的转换。

本讲对应 Betaflight 源码

主要函数:

mixTable(timeUs_t currentTimeUs)

核心代码:

const float scaledAxisPidRoll =
    constrainf(pidData[FD_ROLL].Sum,
               -currentPidProfile->pidSumLimit,
               currentPidProfile->pidSumLimit)
    / PID_MIXER_SCALING;

const float scaledAxisPidPitch =
    constrainf(pidData[FD_PITCH].Sum,
               -currentPidProfile->pidSumLimit,
               currentPidProfile->pidSumLimit)
    / PID_MIXER_SCALING;

float scaledAxisPidYaw =
    constrainf(pidData[FD_YAW].Sum,
               -yawPidSumLimit,
               yawPidSumLimit)
    / PID_MIXER_SCALING;

以及:

float mix =
    scaledAxisPidRoll  * activeMixer[i].roll +
    scaledAxisPidPitch * activeMixer[i].pitch +
    scaledAxisPidYaw   * activeMixer[i].yaw;

本讲学习目标

理解 Mixer 接收到的不是"某个电机应该转多少",

而是"飞机需要多少 Roll、Pitch、Yaw 控制力"。

Mixer 的职责是:将飞机级控制需求,通过每个电机不同的权重,转换为每个电机需要增加或者减少多少输出。


回顾上一讲

上一讲分析了 calculateThrottleAndCurrentMotorEndpoints(), 它负责建立 Mixer 使用的油门输出空间。

也就是说, Mixer 在计算电机输出之前,需要先知道当前油门应该映射到哪个电机输出范围。


为什么 PID Output 不能直接给电机?

PID Controller 输出的是:飞机需要的控制量。

例如:飞机发生向右倾斜,PID Controller 计算以后得到:

Roll PID Output = +50

这个 50 表示:飞机需要一个 Roll 修正力。

但是它没有说明:

  • 哪个电机增加?
  • 哪个电机减少?
  • 增加多少?
  • 减少多少?

控制链:

姿态误差

↓

PID Controller

↓

Roll / Pitch / Yaw 控制需求

↓

Mixer

↓

Motor Output

所以,PID Output 是: "飞机需要什么",

而 Mixer 输出的是:"每个电机应该做什么"


pidData[].Sum —— PID 输出来源

mixTable() 中:

pidData[FD_ROLL].Sum
pidData[FD_PITCH].Sum
pidData[FD_YAW].Sum

分别代表:

Roll PID 总输出

Pitch PID 总输出

Yaw PID 总输出

这里的 "Sum" 表示 PID Controller 最终合成后的输出。

它已经包含 P项 + I项 + D项 的计算结果。


PID Output 为什么需要限制?

观察源码:

constrainf(pidData[FD_ROLL].Sum, -currentPidProfile->pidSumLimit, currentPidProfile->pidSumLimit)

这里进行了限制。

原因是:PID 输出理论上可以无限增大, 比如:飞机受到强烈扰动。

PID Controller 可能认为:需要非常大的修正力量。

但是电机存在物理限制:最大输出有限。

如果 PID 输出过大,进入 Mixer 后,可能导致:

  • 某些电机超过最大输出;
  • 某些电机被压到最低输出;
  • 三轴控制互相抢夺电机能力。

因此,Mixer 输入之前,需要限制 PID 输出范围。

控制思想:

无限控制需求 -> 限制到飞控允许范围 -> 进入 Mixer

PID Mixer Scaling —— 为什么需要缩放?

限制以后,源码继续:

/ PID_MIXER_SCALING

例如:

scaledAxisPidRoll = pidData[FD_ROLL].Sum / PID_MIXER_SCALING;

作用是:将 PID Controller 输出单位,转换为 Mixer 使用的控制空间。

因为PID Controller 内部使用的是PID 计算尺度,而 Mixer 使用的是电机输出混合尺度,二者不是同一个范围。

因此需要:

PID Output -> 缩放 -> Mixer 输入

最终得到:

scaledAxisPidRoll

scaledAxisPidPitch

scaledAxisPidYaw

scaledAxisPidRoll / Pitch / Yaw

经过限制和缩放以后,Mixer 得到三个核心输入:

scaledAxisPidRoll

表示:飞机需要多少 Roll 修正,

例如,正值:需要向正方向 Roll;负值:需要向反方向 Roll


scaledAxisPidPitch

表示:飞机需要多少 Pitch 修正


scaledAxisPidYaw

表示:飞机需要多少 Yaw 修正

注意:这里仍然不是电机输出,而是飞机级控制需求。


motorMix —— 控制需求转换为电机修正量

现在进入 Mixer 核心:

float mix =
    scaledAxisPidRoll  * activeMixer[i].roll +
    scaledAxisPidPitch * activeMixer[i].pitch +
    scaledAxisPidYaw   * activeMixer[i].yaw;

这就是 Mixer 数学模型。

对于第 i 个电机:

Motor Mix = Roll需求 × Roll权重
          + Pitch需求 × Pitch权重
          + Yaw需求 × Yaw权重

例如:某个电机,

roll = 0.5
pitch = -0.5
yaw = 1.0

那么:

motorMix = Roll × 0.5 + Pitch × (-0.5) + Yaw × 1.0

这个结果表示:该电机需要因为姿态控制,增加多少,或者减少多少输出。


为什么每个电机需要不同权重?

因为电机的位置不同。

例如,

Roll 控制:左侧电机增加,右侧电机减少 -> 产生滚转力矩;

Pitch 控制:前后电机产生推力差 -> 产生俯仰力矩;

Yaw 控制:不同旋向电机改变输出 -> 改变反作用力矩。

所以,每个电机对应一个:

Roll 权重

Pitch 权重

Yaw 权重

Mixer 并不是创造控制需求。

它只是按照飞机结构,重新分配控制需求。


控制链推进

到这里,Mixer 已经完成:

PID Output -> motorMix

转换。

此时, motorMix[]里面保存的是:每个电机由于姿态控制产生的 "修正量"。

但是,它还没有加入 "Throttle", 也没有转换成最终 ESC 输出值。

下一步的问题, 如何把:

Throttle + motorMix

合成为真正的:

Motor Output

本讲小结

本讲完成了 Mixer 输入控制量的建立。

源码中的 pidData[].Sum 是 PID Controller 输出的三轴控制需求,它描述飞机需要多少 Roll、Pitch、Yaw 修正,而不是直接描述电机输出。

Mixer 首先对 PID 输出进行限制和缩放,形成 scaledAxisPidRollscaledAxisPidPitchscaledAxisPidYaw,然后通过 motorMixer_t 中保存的权重,将三轴控制需求转换为每个电机对应的 motorMix 修正量。

至此,控制链完成了:

PID Controller

↓

Roll / Pitch / Yaw 控制需求

↓

Mixer 分配

↓

motorMix

下一讲预告

下一讲继续分析 mixTable()

重点:

motorMix + Throttle -> Motor Output

也就是:Mixer 如何把姿态修正量和油门基础输出合成为最终电机输出。