2. 坐标系与向量基础:导航坐标系(NED)与机体坐标系定义,旋转矩阵与四元数基础回顾
各位同学,欢迎来到《姿态解算进阶》的第一章实战内容。
说实话,做惯导这么多年,我见过太多人在磁力计融合上栽跟头。追根溯源,十有八九是坐标系没搞明白。你想想看,连飞机头朝哪、地磁场方向在哪都没定义清楚,后面算出来的偏航角能准吗?
所以这一章,咱们先把地基打牢。我会带着你重新梳理NED坐标系和机体坐标系,再把旋转矩阵和四元数这两个老朋友请出来,做个扎实的回顾。
2.1 导航坐标系(NED)—— 我们到底在哪个世界里算姿态?
导航坐标系,也叫参考坐标系。说白了,就是给飞行器定一个“绝对”的参考系。
我个人习惯用NED(北-东-地)坐标系。为什么选它?因为大部分无人机、无人车的导航算法都基于这个约定。你去看PX4、ArduPilot的源码,里面全是NED。
NED的定义很简单:
- X轴(N轴):指向地理北(真北,不是磁北)。
- Y轴(E轴):指向地理东。
- Z轴(D轴):指向地心,也就是“向下”。
这里有个容易混淆的点:Z轴向下。很多初学者会问:“为什么不是向上?” 嗯,我刚开始也纳闷。后来做了一次飞行器坠落数据分析才明白——Z轴向下,重力加速度就是正的(g ≈ 9.8 m/s²),计算高度时直接积分加速度的Z分量,符号逻辑非常顺。
核心记忆点: NED坐标系是右手系。拇指指向北,食指指向东,中指指向下。你比划一下,就记住了。
2.2 机体坐标系(Body Frame)—— 飞行器自己的小世界
机体坐标系是固定在飞行器上的。它跟着飞行器一起转。
机体坐标系的定义:
- X轴(Roll轴):指向机头方向。
- Y轴(Pitch轴):指向飞行器右侧(右翼方向)。
- Z轴(Yaw轴):指向飞行器下方(符合右手定则)。
我在项目中遇到过一个问题:有个同事把Y轴定义成了指向左侧。结果算出来的横滚角符号全是反的,飞控一上电就翻。所以,务必统一约定:前-右-下,这是行业标准。
我的小技巧: 在代码里,我习惯用枚举把坐标系定义写死,比如 typedef enum {BODY_X_FRONT, BODY_Y_RIGHT, BODY_Z_DOWN} BodyAxis_t;。这样团队里谁都不会搞错。
2.3 从机体到导航:旋转矩阵来搭桥
有了两个坐标系,怎么把机体上的测量值(比如加速度计读到的重力分量)转换到导航坐标系下?
答案就是旋转矩阵。它本质上是一个3x3的正交矩阵,描述了从一个坐标系到另一个坐标系的线性变换。
旋转矩阵的表示:
R = [r11 r12 r13
r21 r22 r23
r31 r32 r33]
其中每一列代表机体坐标轴在导航坐标系下的投影。举个例子,第一列就是机头方向在NED中的分量。
我记得有一次调试磁力计,发现偏航角总是跳变。查了半天,原来是旋转矩阵的转置用错了。这里提醒大家:从机体到导航的旋转矩阵,和从导航到机体的旋转矩阵互为转置。千万别搞反。
避坑指南: 我曾经在代码里直接用了旋转矩阵的逆,忘了正交矩阵的逆就是转置。结果算出来的姿态角全乱套了。记住:R_inv = R^T,别去求逆矩阵,浪费算力还容易出错。
2.4 四元数:旋转的优雅解法
旋转矩阵虽然直观,但有个致命问题:万向锁。当俯仰角接近±90°时,横滚和偏航会耦合,姿态解算直接崩掉。
所以,工业界普遍用四元数。它用四个参数表示旋转,没有奇点,而且插值平滑。
四元数的定义:
q = w + xi + yj + zk
其中w是实部,x、y、z是虚部。满足 w² + x² + y² + z² = 1(单位四元数)。
四元数与旋转矩阵的转换:
给定单位四元数 q = [w, x, y, z],对应的旋转矩阵为:
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²)]
这个公式你不需要背,但要知道怎么来的。我一般在代码里写成函数,用的时候直接调。
实战建议: 在嵌入式平台上,四元数更新用毕卡逼近法或者龙格-库塔法。我习惯用一阶毕卡,算力开销小,对于IMU更新率1kHz的场景,精度完全够。
2.5 本章知识体系总览
下面这张图,是我自己梳理的本章核心逻辑。你看一遍,心里就有谱了。
你看,从坐标系定义到旋转表示,是一条清晰的链路。后面讲磁力计融合时,我们就在这个框架下工作。
2.6 本章小结
好了,这一章的内容就是这些。我帮你把重点再拎一下:
- NED坐标系:北-东-地,右手系,Z轴向下。
- 机体坐标系:前-右-下,跟着飞行器转。
- 旋转矩阵:3x3正交矩阵,从机体到导航的桥梁。注意转置关系。
- 四元数:四个参数,无奇点,是工程首选。记得归一化。
这些基础打牢了,后面讲磁力计融合、防偏航漂移的时候,你才能跟得上节奏。嗯,咱们下一章见。
课后动手: 打开你的MCU开发板,写一个函数:输入机体坐标系下的加速度计读数(ax, ay, az),用四元数旋转到NED坐标系下。然后打印出来,看看重力分量是不是主要在Z轴(向下)。如果是,恭喜你,坐标系搞对了。