PX4 Autopilot · Mixer Deep Dive

MixerControl Allocation

用一个四旋翼 X 构型的完整数值例子,手把手拆解两代混控架构的计算逻辑差异。

≤ v1.12 · 旧版 Mixer ≥ v1.13 · 新版 Control Allocation
00 / Scenario

统一场景设定

以下所有例子都基于同一个飞行场景,方便直接对比两套系统在同一输入下的行为差异。

✦ 场景

四旋翼 X 构型 · 悬停中右倾修正

一架标准 X 型四旋翼正在悬停,姿态控制器检测到需要向右滚转修正,同时保持俯仰、偏航稳定。控制器输出如下归一化指令:

Roll
0.30
向右滚转
Pitch
0.00
不俯仰
Yaw
0.05
微量偏航
Thrust
0.60
悬停油门
X M1 CCW ↺ 右前 M2 CCW ↺ 左后 M3 CW ↻ 左前 M4 CW ↻ 右后 ▲ 机头方向
01 / Legacy Mixer

旧版混控器的计算过程 ≤ v1.12

旧版的核心逻辑极其简洁:读取一张写死的权重表,然后做矩阵乘法。

Step 1

读取 .mix 文件中的权重表

系统启动时,读取 quad_x.main.mix 文件。对于四旋翼 X 构型,R: 4x 语法会被展开为以下固定权重表:

quad_x.main.mix
# 多旋翼混控器 —— 四旋翼 X 构型 R: 4x # roll_scale pitch_scale yaw_scale deadband 10000 10000 10000 0 # 解析后内部展开为 4×4 权重矩阵 W: # Roll Pitch Yaw Thrust # M1(右前) -1.0 +1.0 -1.0 +1.0 # M2(左后) +1.0 -1.0 -1.0 +1.0 # M3(左前) +1.0 +1.0 +1.0 +1.0 # M4(右后) -1.0 -1.0 +1.0 +1.0
注意:这张权重表在编译/启动后就固定在内存中,运行期间无法修改。每种机架对应一个唯一的 .mix 文件(quad_x、hex_x、octa_+……)。想换构型?换文件、重启。
Step 2

线性加权求和 —— 直接矩阵乘法

把控制器输出 [roll, pitch, yaw, thrust] 和权重矩阵相乘,就得到各电机输出:

motor[i] = W[i][0]×roll + W[i][1]×pitch + W[i][2]×yaw + W[i][3]×thrust

代入具体数值 roll=0.30, pitch=0.00, yaw=0.05, thrust=0.60

逐电机计算
M1

右前 (CCW):(-1.0)×0.30 + (+1.0)×0.00 + (-1.0)×0.05 + (+1.0)×0.60

= -0.30 + 0 - 0.05 + 0.60 = 0.25

M2

左后 (CCW):(+1.0)×0.30 + (-1.0)×0.00 + (-1.0)×0.05 + (+1.0)×0.60

= +0.30 + 0 - 0.05 + 0.60 = 0.85

M3

左前 (CW):(+1.0)×0.30 + (+1.0)×0.00 + (+1.0)×0.05 + (+1.0)×0.60

= +0.30 + 0 + 0.05 + 0.60 = 0.95

M4

右后 (CW):(-1.0)×0.30 + (-1.0)×0.00 + (+1.0)×0.05 + (+1.0)×0.60

= -0.30 + 0 + 0.05 + 0.60 = 0.35

初始输出结果(范围 0~1):

M1 右前
0.25
M2 左后
0.85
M3 左前
0.95
M4 右后
0.35

✅ 本例中所有电机都在 [0, 1] 范围内,无需饱和处理。左侧电机(M2、M3)转速更高以产生向右滚转的力矩——符合物理直觉。

Step 3

当电机饱和时 —— 启发式推力缩放

如果控制指令更大(比如 roll=0.50, thrust=0.75),某些电机就会超限:

!
饱和场景计算

先正常计算:

M1

(-1.0)×0.50 + 0 + (-1.0)×0.05 + (+1.0)×0.75 = 0.20

M2

(+1.0)×0.50 + 0 + (-1.0)×0.05 + (+1.0)×0.75 = 1.20 ⚠

M3

(+1.0)×0.50 + 0 + (+1.0)×0.05 + (+1.0)×0.75 = 1.30 ⚠

M4

(-1.0)×0.50 + 0 + (+1.0)×0.05 + (+1.0)×0.75 = 0.30

M1
0.20
M2
1.20
M3
1.30
M4
0.30
↓ 旧版处理策略 ↓
1

等比缩小 roll/pitch/yaw 分量:最大超限量 0.30(M3 超了 1.0),将所有电机的姿态控制分量等比缩小,使最大值恰好 = 1.0。

缩放因子 ≈ 0.77 → roll 实际效果被削弱为 0.38

2

如果有电机低于下限:所有电机整体上移,保证 min(output) ≥ 0。

3

最终输出:

M1
0.36
M2
0.95
M3
1.00
M4
0.41
问题在哪?roll、pitch、yaw 被同比例缩小——即使 pitch=0 不需要保护,yaw 分量也被无差别削弱。系统无法说"我更在意推力而不是偏航"。对于标准四轴悬停还勉强能用,但对不对称构型(Y6、Tilt-rotor)或多轴冗余场景表现很差。
02 / Control Allocation

新版控制分配的计算过程 ≥ v1.13

新版把同一个问题建模成矩阵方程,用优化方法求解。同样的输入,思路完全不同。

Step 1

从几何参数构建效能矩阵 B

不再读 .mix 文件,而是读取每个电机的物理参数(位置 x/y、推力系数、偏航系数),在运行时计算 B 矩阵。

参数系统(CA_ROTOR*)
# 电机 0 (M1 右前): CA_ROTOR0_PX = 0.707 # x 位置(前为正) CA_ROTOR0_PY = 0.707 # y 位置(右为正) CA_ROTOR0_KM = -0.05 # 偏航力矩系数(CCW 为负) # 电机 1 (M2 左后): CA_ROTOR1_PX = -0.707 CA_ROTOR1_PY = -0.707 CA_ROTOR1_KM = -0.05 # 电机 2 (M3 左前): CA_ROTOR2_PX = 0.707 CA_ROTOR2_PY = -0.707 CA_ROTOR2_KM = 0.05 # 电机 3 (M4 右后): CA_ROTOR3_PX = -0.707 CA_ROTOR3_PY = 0.707 CA_ROTOR3_KM = 0.05

代码根据这些物理参数,实时计算效能矩阵 B

ActuatorEffectivenessRotors.cpp
// 对每个电机 i,根据几何参数填 B 矩阵的第 i 列 B(0, i) = PY[i]; // roll 力臂 = y 位置 B(1, i) = -PX[i]; // pitch 力臂 = -x 位置 B(2, i) = KM[i]; // yaw = 偏航力矩系数 B(3, i) = 1.0; // thrust = 每个电机都贡献推力
B
效能矩阵(代入数值后)
M1 右前 M2 左后 M3 左前 M4 右后
Roll+0.707−0.707−0.707+0.707
Pitch−0.707+0.707−0.707+0.707
Yaw−0.05−0.05+0.05+0.05
Thrust1.01.01.01.0

每列 = 一个电机对四个控制轴的贡献能力。例如 M1 的 Roll 行为 +0.707,表示 M1 转速提高时会产生正 roll(右倾)力矩。

与旧版的根本区别:旧版 W 矩阵的值是人为写在 .mix 文件中的 ±1.0,新版 B 矩阵的值从电机物理位置自动计算。新增/移除一个电机只需改参数,B 矩阵下一拍自动更新。
Step 2

伪逆法求解最优执行器输出

已知期望控制量 v 和效能矩阵 B,求电机输出 u 使得 B · u = v

u = B⁺ · v    其中 B⁺ = Bᵀ(BBᵀ)⁻¹

代入 v = [0.30, 0.00, 0.05, 0.60]ᵀ 求解:

正常工况求解结果
M1 右前
0.26
M2 左后
0.84
M3 左前
0.94
M4 右后
0.36

标准对称四轴在正常工况下,两套系统输出非常接近。真正的差距在饱和处理和非标构型。

Step 3

当电机饱和时 —— 顺序去饱和 + 优先级

同样的极端场景 roll=0.50, thrust=0.75,新版的处理完全不同:

!
Sequential Desaturation 算法
1

初始伪逆求解:

M1
0.18
M2
1.22
M3
1.32
M4
0.28

⚠ M2、M3 超限

2

固定饱和执行器:将 M2 钳位到 1.0,M3 钳位到 1.0。计算残差控制量:

v_残差 = v_期望 − B · u_已钳位

"M2、M3 被限制了,有一部分控制量没实现,这部分残差交给 M1、M4 补偿。"

3

按优先级重新分配(这是核心差异!):

优先级从高到低:Thrust → Roll/Pitch → Yaw
如果推力和姿态不可兼得,先保推力(安全第一),再尽量保姿态。偏航最低优先级——可以暂时偏一点。

用 M1、M4 的效能子矩阵,对残差控制量再次伪逆求解,迭代直到所有输出合法。

4

最终输出:

M1
0.30
M2
1.00
M3
1.00
M4
0.40

推力得到了更好的保持,roll 被适度削减,yaw 被优先牺牲——这正是我们想要的。

核心差异总结:旧版对所有姿态轴"一刀切"等比缩放;新版则——① 精确计算残差 ② 用数学最优方法重新分配 ③ 按优先级决定谁先被牺牲。激烈机动、阵风扰动、电机失效等场景下差距非常显著。
03 / Real-World Scenarios

三个实际场景对比

不同拓扑和工况下,两套系统的具体行为差异。

场景 A · 电机失效

Motor 3 突然停转

旧版

混控器完全不知道 M3 已经停了——权重表里 M3 的系数还在。系统继续给 M3 分配一个非零输出值,但实际产生不了推力。

姿态控制器只能通过反馈环路慢慢"追"偏差,响应滞后严重,飞行器剧烈抖动甚至翻转坠机。

// 权重表不变,系统浑然不知 M3_output = 0.95 // 算出来发给 M3,但 M3 已死 // 只能等反馈发现高度下降 → 姿态偏差 → 慢慢补

❌ 无前馈适应,依赖反馈纠错(通常来不及)

新版

检测到 M3 失效后,将 B 矩阵中 M3 对应的列全部清零,用剩余 3 个电机的子矩阵重新计算伪逆。

系统在同一控制周期内就切换到 3 电机模式——自动放弃 yaw 控制(欠驱动),但保住推力和 roll/pitch。

// B 矩阵实时修改 B[:, 2] = [0, 0, 0, 0] // M3 列清零 u = B_reduced⁺ · v // 用 3 电机重新求解 // 同一拍完成,无需等待反馈

✅ 前馈级适应,亚毫秒响应

场景 B · VTOL 过渡

多旋翼模式 → 固定翼模式

旧版

需要两套独立 mixer:mc_group 控制电机,fw_group 控制舵面。过渡期通过权重线性混合:

out = w × mixer_mc(ctrl) + (1-w) × mixer_fw(ctrl) // 两个 mixer 各自独立,互不知道对方的饱和状态 // 容易出现两边同时饱和互相抢资源

❌ 两套独立系统线性混合,易冲突

新版

统一的 B 矩阵同时包含电机列和舵面列,过渡期间效能系数连续变化:

B = [ Motor1..4 | Aileron Elevator Rudder ] // 效能×w 渐减 效能×(1-w) 渐增 // 所有执行器在同一个优化问题内统一求解

✅ 统一优化,过渡平滑无冲突

场景 C · 自定义构型

非标准三角形布局三轴无人机

旧版

没有现成的 R: 语法,需要手动计算权重,用 S: 逐行写 .mix 文件,刷固件,试飞,发现不对再改……

# 必须自己算每个系数 S: 1 3 0 0 8000 8000 0 -10000 10000 0 1 8000 8000 0 -10000 10000 0 3 10000 10000 0 -10000 10000 # 手算 → 写文件 → 刷固件 → 试飞 → 重来

❌ 需手算权重、刷固件、反复迭代

新版

在 QGC 参数界面中填写每个电机的物理坐标和旋转方向,系统自动生成 B 矩阵:

CA_ROTOR_COUNT = 3 CA_ROTOR0_PX = 1.0 # 前方电机 CA_ROTOR0_PY = 0.0 CA_ROTOR1_PX = -0.5 # 左后电机 CA_ROTOR1_PY = -0.87 CA_ROTOR2_PX = -0.5 # 右后电机 CA_ROTOR2_PY = 0.87 # 保存参数即可,无需刷固件

✅ 描述几何 → 自动算 → 实时生效

04 / Comparison Table

完整对比表

维度旧版 Mixer ≤ v1.12新版 Control Allocation ≥ v1.13
配置方式.mix 文本文件,每种机架一个CA_* 参数族(QGC 可视化配置)
核心数据结构权重表 W(人工定义 ±1.0)效能矩阵 B(从几何坐标自动计算)
求解方法线性加权求和(矩阵乘法)伪逆 / 顺序去饱和 / 加权最小二乘
饱和处理等比缩放所有姿态轴(启发式)固定饱和器 → 残差重分配(迭代最优)
优先级不支持(一视同仁缩放)Thrust > Roll/Pitch > Yaw(可配置)
构型扩展每种构型一个 .mix,需刷固件重启改参数即生效,支持任意几何布局
电机失效无感知,完全依赖反馈可清零 B 列,同周期内切换分配
VTOL 过渡两套 mixer 线性混合,互不通信统一 B 矩阵,效能系数连续变化
uORB 消息actuator_controls → actuator_outputstorque/thrust_setpoint → actuator_motors/servos
代码位置src/lib/mixer/src/modules/control_allocator/
版本状态v1.9~v1.12(v1.14 起完全移除)v1.13 引入,v1.14+ 为唯一方案
05 / Summary

一句话总结

旧版是 "查表得答案"——告诉每个电机该加多少
新版是 "描述问题让系统求最优解"——告诉系统我要什么效果
迁移建议:v1.14+ 已完全移除旧版 Mixer,新项目请直接使用新架构。标准构型在 QGC 中选择 Airframe 即可自动完成参数设置;自定义构型需要把 .mix 文件中的权重反推回几何参数填入 CA_ROTOR* 参数族。