[BF学院_卷1] -- 第22讲:Betaflight 如何描述 Mixer —— mixer.h 数据结构

第22讲:Betaflight 如何描述 Mixer —— mixer.h 数据结构


本讲知识点

  • Betaflight 为什么需要使用数据结构描述 Mixer(混控器)
  • mixerMode_e 如何描述不同飞行器结构
  • mixerType_e 如何描述不同 Mixer 计算方式
  • motorMixer_t 如何描述单个电机参与控制的方式
  • throttle、roll、pitch、yaw 四个参数分别代表什么
  • mixer_t 如何组合一个完整 Mixer
  • mixerConfig_t 如何保存用户配置和运行参数
  • customMotorMixer 如何支持自定义混控
  • motorCount 如何确定当前飞行器拥有多少电机

本讲对应 Betaflight 源码

文件:

src/main/flight/mixer.h

本讲主要分析:

typedef enum mixerMode
{
    ...
} mixerMode_e;


typedef enum mixerType
{
    ...
} mixerType_e;


typedef struct motorMixer_s {
    float throttle;
    float roll;
    float pitch;
    float yaw;
} motorMixer_t;


typedef struct mixer_s {
    uint8_t motorCount;
    uint8_t useServo;
    const motorMixer_t *motor;
} mixer_t;


typedef struct mixerConfig_s {
    uint8_t mixerMode;
    bool yaw_motors_reversed;
    uint8_t crashflip_motor_percent;
    uint8_t crashflip_expo;
    uint8_t mixer_type;
    ...
} mixerConfig_t;

回顾上一讲

上一讲,我们完成了 Mixer(混控器)的物理基础建立。

我们知道:PID Controller(PID控制器)输出的不是电机转速。

它输出的是:飞机需要产生什么运动。

例如:Roll(横滚), Pitch(俯仰), Yaw(偏航), Throttle(油门)。

但是电机只能理解:提高转速, 降低转速。

因此需要:

飞机运动需求

↓

电机输出分配

↓

Motor Command(电机指令)

这个转换过程,就是 Mixer。


但是,现在出现新的问题:如果在程序中实现 Mixer,飞控需要知道:

有几个电机?

每个电机应该受到哪些控制影响?

Roll 对这个电机影响多少?

Pitch 对这个电机影响多少?

Yaw 对这个电机影响多少?

因此,Betaflight 需要一种方式描述 Mixer。

这一讲,就是进入源码,理解:

Betaflight 如何描述 Mixer

Mixer 在源码中不是一个算法,而是一组数据

在上一讲中,我们从功能角度理解 Mixer:

Throttle + Roll + Pitch + Yaw

↓

Motor 1

Motor 2

Motor 3

Motor 4

但是,在代码中,Mixer 并不是简单写死:

如果是四轴:

Motor1 = ...

Motor2 = ...

Motor3 = ...

Motor4 = ...

因为 Betaflight 支持很多不同飞行器:

例如:

四旋翼,六旋翼,八旋翼,三旋翼,固定翼

不同结构:

  • 电机数量不同;
  • 电机位置不同;
  • 电机旋转方向不同;
  • Roll/Pitch/Yaw 对电机影响不同。

因此,Betaflight 将 Mixer 抽象成:

飞行器结构描述 + 电机控制权重描述 + 运行配置

mixerMode_e:描述飞行器类型

首先看:

typedef enum mixerMode
{
    MIXER_TRI = 1,
    MIXER_QUADP = 2,
    MIXER_QUADX = 3,
    ...
} mixerMode_e;

这个枚举描述:当前飞行器是什么结构。

例如,MIXER_QUADX 表示:X 型四旋翼,

也就是我们上一讲一直讨论的 Motor 1 ~ Motor 4 组成的四轴结构。


为什么 Betaflight 需要知道飞行器类型?

因为不同结构,电机分布不同。

例如,四旋翼:

     M1        M2


     M4        M3

六旋翼:

    M1      M2


 M6             M3


    M5      M4

它们产生 Roll、Pitch、Yaw 的方式不同。

因此:飞行器结构决定 Mixer 方式。


需要注意,mixerMode_e 描述的是硬件结构,不是具体计算过程。

它回答:

这是什么飞机?

而不是:

Mixer 怎么计算?


mixerType_e:描述 Mixer 计算类型

接下来:

typedef enum mixerType
{
    MIXER_LEGACY = 0,
    MIXER_LINEAR = 1,
    MIXER_DYNAMIC = 2,
    MIXER_EZLANDING = 3,
} mixerType_e;

描述的是:Mixer 输出计算方式,

也就是当 Mixer 已经知道:

Throttle,Roll,Pitch,Yaw

以后,应该采用什么策略生成 Motor Output。


MIXER_LEGACY

传统 Mixer 计算方式,也就是最基础的:

Motor Output = Throttle + Roll 权重 + Pitch 权重 + Yaw 权重

例如:

Motor1 = Throttle + Roll + Pitch + Yaw

这是最经典的 Mixer 思想。


MIXER_LINEAR

Linear Mixer(线性混控)。

核心思想:保持控制输入与电机输出之间的线性关系。

例如,Roll 增加 10%,那么对应电机影响:

增加固定比例

不会根据其它状态进行复杂调整。


MIXER_DYNAMIC

Dynamic Mixer(动态混控)。

它允许 Mixer 根据当前状态动态调整输出。

例如,不同油门区域:

低油门,保持姿态控制能力

高油门,限制输出变化

它主要用于改善不同飞行状态下的控制效果。


MIXER_EZLANDING

用于辅助降落相关逻辑。

它不是改变 Mixer 的基本职责,仍然是:

控制需求 -> 电机输出

只是增加特殊情况下的输出处理。


因此:

mixerMode_e 和 mixerType_e 的区别:

类型 作用
mixerMode_e 描述什么飞机
mixerType_e 描述如何计算 Mixer 输出

motorMixer_t:描述单个电机如何参与控制

接下来进入 Mixer 最核心的数据结构:

typedef struct motorMixer_s {
    float throttle;
    float roll;
    float pitch;
    float yaw;
} motorMixer_t;

这个结构描述 "一个电机" 在 Mixer 中承担什么作用。

上一讲我们知道, Mixer 本质:

Throttle + Roll + Pitch + Yaw -> Motor Output

那么程序需要知道,每个电机:

Throttle 占多少?

Roll 影响多少?

Pitch 影响多少?

Yaw 影响多少?

这就是 motorMixer_t。


throttle 成员:油门权重

代码:

float throttle;

表示: Throttle 对这个电机输出的影响比例.

例如, 四旋翼悬停, 所有电机都需要提供升力。

因此通常:

Motor1 throttle = 1

Motor2 throttle = 1

Motor3 throttle = 1

Motor4 throttle = 1

意思:油门输入会平均作用到所有电机


roll 成员:横滚控制权重

代码:

float roll;

表示:Roll 控制量对这个电机的影响方向和大小。

例如,飞机需要向右 Roll。

Mixer 需要:一侧电机增加推力,另一侧电机减少推力。

因此不同电机 roll 权重不同。

例如:

左侧电机:roll = +1

右侧电机:roll = -1

表示:Roll 输入会让两侧产生相反变化。


pitch 成员:俯仰控制权重

代码:

float pitch;

作用类似:“roll”,但是控制方向不同。

它描述:Pitch 控制量如何影响这个电机。

例如,飞机需要向前 Pitch,需要后方电机增加推力,前方电机减少推力,

因此,前后电机:pitch 权重相反。


yaw 成员:偏航控制权重

代码:

float yaw;

表示:Yaw 控制量如何影响这个电机。

Yaw 与 Roll、Pitch 不同。

Roll/Pitch 主要利用 “升力差” 产生力矩。

Yaw 利用:“旋翼旋转反作用力” 产生力矩。

因此,CW 电机和 CCW 电机Yaw 权重方向相反。

例如:

CW 电机:yaw = +1

CCW 电机:yaw = -1

这样,增加某些电机输出,就可以改变顺时针反作用力与逆时针反作用力之间的平衡,最终产生 Yaw。


一个完整 motorMixer_t 的直觉

前面我们已经知道,Mixer 的任务是:

Throttle + Roll + Pitch + Yaw -> Motor Output

但是,不同电机在飞机上的位置不同,因此它们承担的控制职责也不同。

例如:左前电机, 右前电机, 左后电机, 右后电机, 它们距离飞机中心的位置不同,旋转方向也不同。

所以,当飞机需要 Roll(横滚), Pitch(俯仰), Yaw(偏航)时,每个电机需要增加或者减少的量并不相同。

Betaflight 使用 motorMixer_t 描述这种关系。


例如,一个电机的 Mixer 参数:

{
    throttle = 1.0,
    roll = 0.5,
    pitch = -0.5,
    yaw = 1.0
}

他表示这个电机最终输出,需要按照这些比例参与四种控制需求。

具体来看:


throttle = 1.0

表示:这个电机完整参与基础油门控制。

假设当前:Throttle = 50,那么这个电机获得:

50 × 1.0 = 50

也就是说:油门增加,这个电机增加同样比例的推力。

四旋翼悬停时,所有电机通常都会有类似的:throttle = 1.0,因为所有电机都需要共同提供升力。


roll = 0.5

表示:这个电机参与 Roll 控制,并且贡献方向为正。

假设飞机需要:Roll = 20,那么这个电机产生:

20 × 0.5 = 10

的 Roll 修正量。

也就是说:Roll 控制需求,这个电机增加 10 的输出。

如果另一个电机:

roll = -0.5

那么同样的 Roll 命令,会让它减少 10 的输出。

因此,通过正负不同的 Roll 权重:一部分电机增加推力,另一部分电机减少推力。

飞机两侧产生推力差,最终形成 Roll 力矩。


pitch = -0.5

表示:这个电机参与 Pitch 控制,但是方向相反。

假设:Pitch = 20,那么:

20 × (-0.5) = -10

表示:这个电机需要减少输出。

为什么需要负号?

因为这个电机的位置决定了:

增加推力 -> 产生某方向 Pitch 力矩

还是:

减少推力 -> 产生该方向 Pitch 力矩

不同位置的电机方向不同。

所以 Mixer 必须通过正负号描述:哪个电机增加,哪个电机减少。


yaw = 1.0

表示:这个电机参与 Yaw 控制,并且方向为正。

假设:Yaw = 10,那么:

10 × 1.0 = 10

这个电机增加输出。

但是,Yaw 与 Roll、Pitch 不同,Roll 和 Pitch 主要利用:

推力差 -> 产生倾斜力矩

而 Yaw 利用:

旋翼旋转方向产生的反作用力 -> 产生旋转力矩

因此,不同旋转方向的电机,需要拥有不同符号的 Yaw 权重。

例如:

CW 电机,yaw = +1

CCW 电机,yaw = -1

这样当 Yaw 命令产生时:

部分电机增加,部分电机减少

↓

顺逆时针反作用力失去平衡

↓

飞机产生 Yaw

因此,一个 motorMixer_t

{
    throttle = 1.0,
    roll = 0.5,
    pitch = -0.5,
    yaw = 1.0
}

真正表达的是:

这个电机:100%参与基础升力,

Roll 控制时,按照 +0.5 的比例响应,

Pitch 控制时,按照 -0.5 的比例响应,

Yaw 控制时,按照 +1.0 的比例响应

最终 Mixer 会根据:

Throttle,Roll,Pitch,Yaw

四个控制需求,与这个电机自己的:

throttle,roll,pitch,yaw

权重相乘,再相加:

Motor Output = Throttle × throttle权重
            + Roll × roll权重
            + Pitch × pitch权重
            + Yaw × yaw权重

因此,motorMixer_t 本质上就是:

描述某一个电机,如何把飞机级控制需求转换为自身输出变化的参数表。

后续分析 mixTable() 时,Betaflight 正是利用这些权重,把:

PID Output

↓

Throttle / Roll / Pitch / Yaw

↓

每一个 Motor Output

完成真正的控制分配。


mixer_t:描述一个完整 Mixer

继续看:

typedef struct mixer_s {
    uint8_t motorCount;
    uint8_t useServo;
    const motorMixer_t *motor;
} mixer_t;

这个结构表示:一个完整 Mixer 配置。

包含:


motorCount

uint8_t motorCount;

表示:这个 Mixer 有多少个电机

例如,四旋翼:motorCount = 4,

六旋翼:motorCount = 6。


useServo

uint8_t useServo;

表示:当前 Mixer 是否需要 Servo(舵机)。

因为 Betaflight 不只支持多旋翼,也支持:

固定翼, 三角翼, 其它结构

这些可能包含舵机控制。


motor

const motorMixer_t *motor;

这是最关键的数据。

它指向:每个电机的 Mixer 权重表,

也就是:

Motor1 的 throttle/roll/pitch/yaw

Motor2 的 throttle/roll/pitch/yaw

Motor3 的 throttle/roll/pitch/yaw

...

mixerConfig_t:运行时配置

最后观察:

typedef struct mixerConfig_s {

    uint8_t mixerMode;

    bool yaw_motors_reversed;

    uint8_t crashflip_motor_percent;

    uint8_t crashflip_expo;

    uint8_t mixer_type;

} mixerConfig_t;

它保存:用户选择的 Mixer 配置。


mixerMode

决定:使用哪一种飞行器结构,例如:MIXER_QUADX。


yaw_motors_reversed

控制:Yaw 电机方向处理, 用于特殊硬件布局。


crashflip_motor_percent

与 "Flip Over After Crash" 功能相关,用于控制翻转时的电机输出比例。


mixer_type

决定:Mixer 使用哪一种计算方式, 对应:mixerType_e。


customMotorMixer:为什么需要自定义 Mixer?

源码:

PG_DECLARE_ARRAY(
    motorMixer_t,
    MAX_SUPPORTED_MOTORS,
    customMotorMixer
);

表示 Betaflight 支持用户提供:自己的 motorMixer_t 表,

因为,不同飞行器结构可能非常多。

例如,特殊布局:

非标准四轴,实验飞行器,特殊电机排列

如果只能使用固定 Mixer,程序无法支持。

因此,Betaflight 提供:“Custom Mixer(自定义混控)”,

让用户直接定义每个电机:throttle,roll, pitch, yaw 的权重。


本讲控制链回归

现在回到整个控制链:

上一讲:

PID Output(PID输出)

↓

Mixer

这一讲,我们回答:Mixer 在代码中是什么?

答案:它不是一个简单函数,而是一组描述数据:

飞行器类型

↓

Mixer 类型

↓

电机数量

↓

每个电机控制权重

↓

运行配置

最终形成:“Mixer 数据模型”。


本讲总结

本讲完成了 Mixer 源码进入前的第一步:理解 Betaflight 如何描述 Mixer。

核心认识:

第一:mixerMode_e 描述:什么飞机。

第二:mixerType_e 描述:Mixer 使用什么计算策略。

第三:motorMixer_t 描述:单个电机如何受到 Throttle、Roll、Pitch、Yaw 影响。

第四:mixer_t 描述:完整 Mixer 结构。

第五:mixerConfig_t 保存:用户配置和运行参数。


至此,控制链推进到:

Mixer 概念

↓

Mixer 数据结构

↓

下一讲:Mixer 数学模型

下一讲,我们将进一步回答:

Throttle、Roll、Pitch、Yaw 到底如何通过 motorMixer_t 中的权重,计算出每一个 Motor Output?

也就是:Mixer Matrix(混控矩阵)的数学原理。

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

导航