3、坐标系与姿态表示:地球坐标系、机体坐标系、欧拉角、四元数、旋转矩阵

做无人机仿真,第一个绕不开的坎就是坐标系和姿态表示。我见过不少新手,代码写得飞起,结果一跑仿真,飞机直接翻跟头——十有八九是坐标系搞反了,或者姿态更新算错了。

说白了,坐标系就是给无人机一个「参考系」。你在地面上说「往东飞」,飞机得知道东在哪。你在机身上说「往前飞」,飞机得知道自己的鼻子朝哪。这两者之间的转换,就是我们今天要聊的核心。

3.1 地球坐标系:我们站在哪里看飞机?

地球坐标系,也叫惯性坐标系或导航坐标系。我习惯用 NED(北东地) 坐标系,也就是 X 轴指向北,Y 轴指向东,Z 轴指向地心。

为什么选 NED?因为无人机飞控里,加速度计测的是重力方向,而重力正好指向地心。用 NED 坐标系,重力加速度就是 [0, 0, 9.81],计算起来非常直观。

关键点:地球坐标系是固定不动的。无论飞机怎么翻滚,NED 的方向始终不变。它是我们所有导航计算的基准。

我在项目中遇到过一个问题:有人把经纬度直接当成平面坐标用。这在几公里范围内误差不大,但一旦飞远,地球曲率的影响就出来了。所以,真正做长航时仿真时,我建议用 ECEF(地心地固坐标系) 或者 UTM(通用横轴墨卡托投影) 来做位置解算。

3.2 机体坐标系:飞机自己怎么看?

机体坐标系是固定在飞机上的。我常用的定义是:X 轴指向机头,Y 轴指向右翼,Z 轴指向机腹(也就是向下)。

你想想看,飞机上的传感器——IMU(惯性测量单元)——测量的角速度和加速度,都是相对于机体坐标系的。陀螺仪告诉你「绕 X 轴转了多少」,它可不知道这个 X 轴是朝北还是朝东。

我的习惯:在 Simulink 建模时,我会在机体坐标系下做所有的动力学计算,比如气动力、推力、力矩。然后通过姿态矩阵,把这些量转换到地球坐标系下,再做位置和速度的积分。

嗯,这里要注意:机体坐标系的原点通常选在飞机的重心。如果重心偏移了,力矩计算就会出错。我曾经因为没注意这个细节,仿真出来的飞机总是自己偏航,查了两天才发现是重心没对齐。

3.3 欧拉角:最直观的姿态表示

欧拉角就是大家常说的 俯仰角(Pitch)、滚转角(Roll)、偏航角(Yaw)。它用三个角度来描述飞机从地球坐标系到机体坐标系的旋转。

我习惯的旋转顺序是 Z-Y-X(也就是先偏航,再俯仰,最后滚转)。这个顺序在航空领域是标准做法。

角度 符号 范围 说明
偏航角 ψ (Yaw) -180° ~ 180° 绕 Z 轴旋转,机头指向
俯仰角 θ (Pitch) -90° ~ 90° 绕 Y 轴旋转,抬头低头
滚转角 φ (Roll) -180° ~ 180° 绕 X 轴旋转,左右倾斜

欧拉角的致命问题:万向锁(Gimbal Lock)。当俯仰角接近 ±90° 时,偏航和滚转的旋转轴会重合,导致丢失一个自由度。我在做特技飞行仿真时就踩过这个坑——飞机倒飞时,姿态解算直接炸了。

所以,如果你只是做常规的平飞仿真,欧拉角完全够用。但一旦涉及大角度机动,我强烈建议你换用四元数。

3.4 四元数:没有死区的姿态表示

四元数是一个超复数,形式为 q = w + xi + yj + zk。它用四个数来表示旋转,没有万向锁问题。

我个人觉得,四元数最大的好处是 插值平滑。在 Simulink 里做姿态控制时,用四元数做球面线性插值(SLERP),可以让飞机的姿态过渡非常自然。

四元数的基本运算规则:

// 四元数乘法(用于组合旋转)
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

// 四元数共轭(用于求逆旋转)
q_conj = (w, -x, -y, -z)

// 用四元数旋转向量
v_rotated = q * v * q_conj

避坑指南:四元数必须归一化!也就是 w² + x² + y² + z² = 1。我刚开始用四元数时,经常忘记归一化,结果旋转后的向量长度变了,飞机越飞越飘。后来我在 Simulink 模型里加了一个归一化模块,才彻底解决这个问题。

3.5 旋转矩阵:连接两个世界的桥梁

旋转矩阵是一个 3x3 的正交矩阵,它能把机体坐标系下的向量转换到地球坐标系下(或者反过来)。

从欧拉角到旋转矩阵的转换公式(Z-Y-X 顺序):

R = Rz(ψ) * Ry(θ) * Rx(φ)

其中:
Rz(ψ) = [cosψ  -sinψ  0;  sinψ  cosψ  0;  0  0  1]
Ry(θ) = [cosθ   0      sinθ;  0    1    0;  -sinθ  0  cosθ]
Rx(φ) = [1      0      0;  0    cosφ  -sinφ;  0  sinφ  cosφ]

从四元数到旋转矩阵的转换:

R = [1-2(y²+z²)   2(xy-wz)     2(xz+wy);
     2(xy+wz)     1-2(x²+z²)   2(yz-wx);
     2(xz-wy)     2(yz+wx)     1-2(x²+y²)]

我在 Simulink 里通常用 MATLAB Function 模块 来实现这些转换。写一个函数,输入欧拉角或四元数,输出旋转矩阵。这样模型看起来干净,调试也方便。

3.6 知识体系总览

下面这张图是我自己总结的坐标系与姿态表示的核心逻辑。你可以把它当作一个快速参考。

坐标系与姿态表示知识体系 地球坐标系 NED / ECEF / UTM 固定不动,导航基准 机体坐标系 X机头 Y右翼 Z机腹 传感器测量基准 姿态表示方法 欧拉角(直观,有万向锁) 四元数(无死区,需归一化) 旋转矩阵(计算桥梁) 定义参考方向 描述自身朝向 坐标转换 机体 → 地球:R * v_body 地球 → 机体:R⁻¹ * v_earth

这张图的核心逻辑很简单:地球坐标系和机体坐标系是两个不同的参考系,姿态表示(欧拉角、四元数、旋转矩阵)就是连接它们的数学工具。 你选哪种表示方法,取决于你的应用场景——常规飞行用欧拉角,大机动用四元数,计算转换用旋转矩阵。

3.7 Simulink 建模实战建议

在 Simulink 里搭建坐标系转换模块时,我有几个经验分享:

  1. 用子系统封装:把欧拉角转四元数、四元数转旋转矩阵这些功能,封装成独立的子系统。这样主模型看起来清爽,也方便复用。
  2. 加一个「姿态监视器」:在模型里加一个 Scope,实时观察欧拉角、四元数的变化。调试时特别有用,一眼就能看出姿态更新是否正常。
  3. 注意数值稳定性:四元数归一化一定要做,而且最好放在每个计算周期里。我习惯用 u / sqrt(u(1)^2 + u(2)^2 + u(3)^2 + u(4)^2) 这个公式。
  4. 初始化要小心:仿真开始时,确保姿态的初始值是正确的。比如飞机停在地面上,俯仰角和滚转角应该是 0,偏航角根据机头指向设定。

一句话总结:坐标系是仿真的地基,姿态表示是沟通的桥梁。地基没打牢,楼盖得再高也得塌。我建议你在开始写控制算法之前,先把坐标系和姿态转换这部分跑通、跑稳。


公众号:蓝海资料掘金营,微信deep3321