姿态控制基础:四元数与欧拉角、旋转矩阵、姿态表示方法

姿态控制,说白了就是让飞行器知道自己「脑袋朝哪」。你想想看,如果连自己正着还是歪着都不知道,那还谈什么控制?

我刚开始做飞控时,觉得姿态表示就是个数学工具,随便选一种就行。直到有一次在SITL仿真里,一架四旋翼突然在天上翻起了跟头——后来查出来是欧拉角万向锁导致的。嗯,从那以后我再也不敢轻视这个基础了。

为什么需要多种姿态表示?

飞行器在三维空间中的旋转,其实只有三个自由度。但不同的表示方法,各有各的脾气。

表示方法 优点 缺点 我的使用场景
欧拉角 直观,人脑好理解 万向锁,插值不平滑 遥控器输入、地面站显示
旋转矩阵 无奇点,可叠加 9个参数,冗余大 坐标变换、刚体动力学
四元数 无奇点,计算快,可插值 不直观,需归一化 姿态解算、控制律核心
轴角 物理意义清晰 不可直接叠加 姿态误差计算

核心原则:飞控内部运算用四元数,人机交互用欧拉角,坐标变换用旋转矩阵。别混着用,容易出bug。

欧拉角:最直观,但最危险

欧拉角用三个角度描述旋转:横滚(Roll)、俯仰(Pitch)、偏航(Yaw)。我习惯用Z-Y-X顺序,也就是先转偏航,再转俯仰,最后转横滚。

但这里有个坑——万向锁。当俯仰角接近±90°时,横滚和偏航会变成同一个轴,丢失一个自由度。我在SITL里测试大机动动作时,就遇到过这个问题。飞行器突然失控,日志里显示欧拉角解算直接炸了。

避坑指南:千万不要在控制律内部直接用欧拉角做积分或插值。我曾经试过,结果就是姿态发散。欧拉角只适合给人看,不适合给机器算。

旋转矩阵:数学上的瑞士军刀

旋转矩阵是一个3×3的正交矩阵,行列式为+1。它可以把一个向量从一个坐标系变换到另一个坐标系。

比如,从机体坐标系到世界坐标系的变换:

// 绕Z轴旋转(偏航)
Rz = | cosψ  -sinψ  0 |
     | sinψ   cosψ  0 |
     | 0      0     1 |

// 绕Y轴旋转(俯仰)
Ry = | cosθ   0   sinθ |
     | 0      1   0    |
     | -sinθ  0   cosθ |

// 绕X轴旋转(横滚)
Rx = | 1   0      0    |
     | 0   cosφ  -sinφ |
     | 0   sinφ   cosφ |

// 完整旋转矩阵:R = Rz * Ry * Rx

我个人习惯在SITL仿真里用旋转矩阵做坐标变换,因为它每一步都很清晰。但注意,矩阵乘法有累积误差,长时间运行需要重新正交化。

四元数:飞控的幕后英雄

四元数是个超复数,形式是 q = w + xi + yj + zk,其中 w 是实部,x、y、z 是虚部。它用四个参数表示旋转,没有奇点。

为什么飞控都用四元数?三个原因:

  • 无万向锁——随便你怎么转,不会丢自由度
  • 计算快——乘法比矩阵快,适合嵌入式
  • 可插值——球面线性插值(SLERP)让姿态过渡平滑

但四元数有个硬性要求:必须归一化。模长必须为1,否则姿态会漂移。我在代码里每次更新四元数后都会加一行归一化,已经成了肌肉记忆。

// 四元数乘法(旋转叠加)
q1 * q2 = (w1*w2 - x1*x2 - y1*y2 - z1*z2) +
          (w1*x2 + x1*w2 + y1*z2 - z1*y2)i +
          (w1*y2 - x1*z2 + y1*w2 + z1*x2)j +
          (w1*z2 + x1*y2 - y1*x2 + z1*w2)k

// 归一化
norm = sqrt(w*w + x*x + y*y + z*z)
w /= norm; x /= norm; y /= norm; z /= norm

小技巧:在SITL里调试时,可以用四元数到欧拉角的转换函数,把内部数据打印出来看。这样既保留了四元数的计算优势,又能用人脑理解。

三种表示方法的转换

实际开发中,这三种表示方法经常需要互相转换。我整理了一份速查表:

转换方向 公式/方法 注意事项
欧拉角 → 四元数 分别计算各轴四元数,再相乘 注意旋转顺序
四元数 → 欧拉角 用atan2和asin提取角度 俯仰角接近±90°时精度下降
四元数 → 旋转矩阵 用四元数元素构造矩阵 确保四元数已归一化
旋转矩阵 → 四元数 从矩阵迹中提取 注意数值稳定性

知识体系总览

下面这张图,是我自己总结的姿态表示方法知识结构。每次带新人时,我都会先让他们看这张图。

姿态表示方法知识体系 姿态表示 欧拉角 旋转矩阵 四元数 轴角 直观 有万向锁 适合显示 无奇点 9个参数 适合变换 无奇点 4个参数 适合运算 物理意义清晰 不可叠加 适合误差计算 转换关系 欧拉角 ↔ 四元数 四元数 ↔ 旋转矩阵 旋转矩阵 ↔ 欧拉角 核心原则:运算用四元数,显示用欧拉角,变换用旋转矩阵 避免混用,注意数值稳定性

实战中的选择建议

在SITL仿真里调参时,我一般这样用:

  • IMU数据融合——用四元数做姿态解算,配合Mahony或Madgwick滤波
  • 控制律计算——用四元数算误差,转成轴角形式再算PID
  • 日志记录——转成欧拉角存下来,方便人看
  • 可视化——用旋转矩阵把机体坐标转成世界坐标,渲染3D模型

个人习惯:我在代码里统一用四元数做内部表示,只在接口处做转换。这样既避免了万向锁,又保持了代码的简洁性。你可以在SITL的AP_AHRS模块里看到这种设计模式。