[BF学院_卷1] -- 第25讲:mixTable() 总览 —— Mixer 在控制循环中的位置

第25讲:mixTable() 总览 —— Mixer 在控制循环中的位置


本讲知识点

  • mixTable() 在 Betaflight 控制循环中的位置;
  • Mixer 在控制链中的职责;
  • mixTable() 的输入与输出;
  • Throttle、Roll、Pitch、Yaw 如何进入 Mixer;
  • mixTable() 内部执行流程;
  • 从 PID Output 到 Motor Output 的整体路径。

本讲对应 Betaflight 源码

文件:

src/main/flight/mixer.c

核心函数:

mixTable(timeUs_t currentTimeUs)

本讲覆盖范围:

  • mixTable() 整体结构;
  • 输入输出关系;
  • 内部几个主要阶段。

不展开:

  • calculateThrottleAndCurrentMotorEndpoints()
  • applyMixerAdjustment()
  • applyMixToMotors()

这些函数将在后续章节单独分析。


本讲学习目标

理解 mixTable() 为什么存在。

建立:

PID Controller -> Mixer -> Motor Output

这一控制链关系。

学习完成后,需要知道:Mixer 不是控制飞机姿态的模块。

它负责把已经计算好的控制需求,转换为每个电机应该执行的输出。


回顾上一阶段控制链

在前面的课程中,我们已经建立了:

RC输入

↓

飞行模式

↓

姿态控制

↓

PID Controller

↓

PID Output

到了这里,飞控已经知道: 飞机需要:

  • 增大 Roll 控制;
  • 增大 Pitch 控制;
  • 修正 Yaw;
  • 提供当前油门。

但是, PID Output 仍然不是电机信号。

例如, PID Controller 输出:

Roll = +100

Pitch = -50

Yaw = +30

这个结果表达的是:飞机需要产生这些方向的控制力。

但是飞控仍然不知道:哪个电机增加?哪个电机减少?增加多少?减少多少?

这个问题,就是 Mixer 需要解决的问题。


为什么需要 Mixer?

四旋翼飞机有一个基本特点:单个电机无法直接产生 Roll, Pitch, Yaw 控制。

飞机姿态变化来自不同电机之间的推力差。

例如, 想让飞机向右 Roll, 需要左侧电机增加推力, 右侧电机减少推力。

形成:

左侧推力 ↑, 右侧推力 ↓

↓

产生 Roll 力矩

↓

飞机向右倾斜

因此, PID 输出描述:"飞机需要向右滚转多少"

而 Mixer 需要回答:"具体哪些电机应该变化多少"

这就是:

控制需求 -> 电机分配

mixTable() 在控制链中的位置

mixTable() 位于PID 计算之后,电机输出之前。

完整控制链:

飞手输入

↓

RC Command

↓

姿态 / 角速度控制

↓

PID Controller

↓

PID Output

↓

mixTable()

↓

Motor Output

↓

ESC

↓

电机

因此,mixTable() 是控制链中的最后一个"控制分配层"。

它不负责:产生 PID。

它也不负责:读取陀螺仪。

它负责:把已有的控制需求转换为电机输出。


mixTable() 的输入是什么?

观察函数定义:

FAST_CODE_NOINLINE void mixTable(timeUs_t currentTimeUs)

函数输入 "currentTimeUs", 表示: 当前系统时间。

它主要用于时间相关功能, 例如动态功能。

但是 Mixer 真正使用的控制输入,并不是函数参数,而是函数内部读取的控制状态。

主要包括:

Throttle : 油门需求。

来源:RC 输入经过前处理后的 throttle。

物理意义:飞手希望飞机产生多少基础升力。


Roll / Pitch / Yaw PID Output

来源:

pidData[FD_ROLL].Sum

pidData[FD_PITCH].Sum

pidData[FD_YAW].Sum

它们表示:PID Controller 为了修正飞机状态,需要施加多少控制量。

例如:

Roll PID Output = +50

表示:飞机需要产生一个正方向 Roll 控制力。

注意:这里不是某个电机输出 +50。而是整个飞机需要产生 +50 的 Roll 力矩。


mixTable() 的输出是什么?

最终输出:

motor[]

这个数组保存每个电机最终输出值。

例如, 四旋翼:

motor[0] ~ motor[3]

分别对应四个电机的控制输出。

最终:

motor[] -> ESC -> 电机转速

mixTable() 内部整体流程

虽然 mixTable() 有大量代码,但是从控制思想来看,可以分成几个阶段:


第一阶段:准备油门输出空间

代码:

calculateThrottleAndCurrentMotorEndpoints(currentTimeUs);

作用:确定当前电机输出范围。

例如,

普通模式:最低输出 -> 最高输出。

3D模式:反转区域 -> 死区 -> 正转区域

这个阶段解决的问题:"当前油门应该映射到哪个电机输出范围?"

下一讲详细分析。


第二阶段:选择当前 Mixer 数据

代码:

motorMixer_t * activeMixer = &mixerRuntime.currentMixer[0];

这里选择:当前使用的 Mixer 参数。

这些参数来自前面第22讲、第23讲学习的:

motorMixer_t

它描述每个电机如何响应:Throttle, Roll, Pitch, Yaw。


第三阶段:处理 PID 输出

代码:

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

Pitch 和 Yaw 同理, 这里完成两个动作:


限制 PID 输出

如果 PID 输出过大, Mixer 会要求电机产生超过能力范围的变化。

例如:电机最大输出 100%, 但是 Mixer 计算 120%, 最终只能限制。

因此需要提前限制 PID 权限。


缩放 PID 输出

因为 PID 输出单位 和 Mixer 内部计算单位 不同。

所以需要转换到 Mixer 使用的范围。


第四阶段:计算每个电机的控制需求

核心代码:

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

这一部分是 Mixer 最核心的数学关系。

它表示:某个电机的控制修正量等于:

  Roll控制需求  × 该电机Roll权重
+ Pitch控制需求 × 该电机Pitch权重
+ Yaw控制需求   × 该电机Yaw权重

注意, 这里还没有加入 Throttle。

因为这里计算的是 "姿态修正量", 而不是最终电机输出。


为什么 Throttle 没有立即加入?

这是初学者容易疑惑的问题。

直觉上, 电机输出应该:

Throttle + Roll + Pitch + Yaw

但是代码不是立即这样做。

因为 Roll/Pitch/Yaw 是控制修正, Throttle 是基础推力。

如果直接相加, 可能出现:

某个电机超过最大输出 -> 控制量被截断 -> 飞机失去控制能力

所以 Betaflight 会先计算姿态控制需求, 再根据整体范围调整, 最后才加入 Throttle。

这个过程就是后续章节重点分析的:Mixer Adjustment。


7. 本讲源码流程总结

本讲只建立 mixTable() 的整体框架:

mixTable()

↓

准备油门范围

↓

读取 Mixer 参数

↓

读取 PID Output

↓

计算每个电机的姿态修正量

↓

调整混控范围

↓

加入 Throttle

↓

生成 motor[]

当前阶段需要记住 mixTable() 的核心任务:不是产生控制, 而是把控制需求翻译成电机动作。


本讲小结

本讲建立了 mixTable() 在整个控制链中的位置。

从控制系统角度看,PID Controller 输出的是飞机需要的控制力,而 Mixer 负责把这些控制力转换成多个电机之间的推力变化。

源码层面,本讲分析了 mixTable() 的整体结构,明确了它接收 Throttle、Roll、Pitch、Yaw 控制需求,并最终生成 motor[] 输出。

其中,calculateThrottleAndCurrentMotorEndpoints()、混控调整函数以及最终电机输出映射过程,只进行了功能定位,没有展开细节。


下一讲预告

下一讲继续进入 mixTable() 内部。

重点分析:calculateThrottleAndCurrentMotorEndpoints()

学习:飞控如何把 RC Throttle 转换成 Mixer 可以使用的电机输出空间。

posted on 2026-08-03 15:41  longyue  阅读(9)  评论(0)    收藏  举报

导航