第二章:坐标系与姿态表示

做飞控这些年,我最大的体会就是——坐标系搞不清楚,后面全是坑。你想想看,飞机在天上飞,你说它“往左转”,这个“左”是相对于谁说的?是相对于地面,还是相对于机头?这就是坐标系要解决的根本问题。

2.1 常用坐标系

飞控里常用的坐标系就那么几个。我刚开始学的时候,总觉得它们长得差不多,后来踩了坑才明白,每个坐标系都有自己的脾气。

2.1.1 地心坐标系(ECEF)

地心坐标系,说白了就是把地球中心当成原点。X轴指向本初子午线与赤道的交点,Z轴指向北极,Y轴按右手定则补齐。这个坐标系在GPS定位里用得最多。

我记得有一次做长航时无人机,GPS数据直接拿来用,结果发现飞机位置飘得厉害。后来一查,原来是ECEF坐标系和当地水平坐标系没转换对。嗯,这里要注意:ECEF是随地球自转的,不是惯性系。

2.1.2 地理坐标系(NED)

地理坐标系也叫北东地坐标系。原点在飞机质心,X轴指向北,Y轴指向东,Z轴指向地心。这个坐标系最符合人的直觉——你说“往北飞”,就是沿着NED的X轴方向。

我个人习惯在导航解算时用NED坐标系,因为它的物理意义很清晰。但要注意,NED坐标系的原点会随着飞机移动,所以它是个动坐标系。

2.1.3 机体坐标系(Body Frame)

机体坐标系是固定在飞机上的。X轴沿机头方向,Y轴指向右翼,Z轴指向下(符合右手定则)。这个坐标系是飞控最常用的——所有的IMU传感器数据,说白了都是相对于机体坐标系的。

我曾经遇到过一个问题:IMU安装时歪了1度,结果姿态解算出来一直有偏差。后来花了整整两天才找到原因。所以我现在做项目,第一件事就是标定IMU的安装误差。

核心要点:坐标系转换是飞控的基础。地心→地理→机体,这三层转换必须搞明白。我见过太多新手,代码写得很漂亮,但坐标系搞反了,飞机直接翻跟头。

2.2 欧拉角

欧拉角是描述姿态最直观的方式。三个角度:横滚角(Roll)、俯仰角(Pitch)、偏航角(Yaw)。

角度 符号 范围 说明
横滚角 φ -180° ~ 180° 绕X轴旋转,右滚为正
俯仰角 θ -90° ~ 90° 绕Y轴旋转,抬头为正
偏航角 ψ -180° ~ 180° 绕Z轴旋转,右转为正

避坑指南:我曾经在项目中遇到过万向锁问题。当俯仰角接近±90°时,横滚和偏航会耦合在一起,姿态解算直接崩掉。所以,如果你做的是全姿态飞行(比如特技无人机),千万别只用欧拉角。

2.3 四元数

四元数是个好东西。它用四个数表示旋转:q = [q0, q1, q2, q3]。其中q0是标量部分,q1、q2、q3是矢量部分。

为什么用四元数?说白了就两个原因:没有万向锁,计算效率高。我刚开始做飞控时,姿态解算用的就是欧拉角,结果一做大机动就出问题。后来换成四元数,世界清净了。

// 四元数初始化(单位四元数)
float q0 = 1.0f, q1 = 0.0f, q2 = 0.0f, q3 = 0.0f;

// 四元数乘法(旋转合成)
void quaternion_multiply(float *q_out, float *q_a, float *q_b) {
    q_out[0] = q_a[0]*q_b[0] - q_a[1]*q_b[1] - q_a[2]*q_b[2] - q_a[3]*q_b[3];
    q_out[1] = q_a[0]*q_b[1] + q_a[1]*q_b[0] + q_a[2]*q_b[3] - q_a[3]*q_b[2];
    q_out[2] = q_a[0]*q_b[2] - q_a[1]*q_b[3] + q_a[2]*q_b[0] + q_a[3]*q_b[1];
    q_out[3] = q_a[0]*q_b[3] + q_a[1]*q_b[2] - q_a[2]*q_b[1] + q_a[3]*q_b[0];
}

个人经验:四元数虽然好,但要注意归一化。每次更新后都要做一次归一化,否则误差会累积。我习惯在每次姿态更新后都调用归一化函数,哪怕多花几个时钟周期也值得。

2.4 方向余弦矩阵(DCM)

方向余弦矩阵,说白了就是一个3×3的旋转矩阵。它可以把一个向量从一个坐标系转换到另一个坐标系。

比如,从机体坐标系到地理坐标系的转换矩阵C_b^n,它的每一列就是机体坐标轴在地理坐标系中的方向余弦。

// 从欧拉角构建DCM
void euler_to_dcm(float roll, float pitch, float yaw, float dcm[3][3]) {
    float cr = cos(roll), sr = sin(roll);
    float cp = cos(pitch), sp = sin(pitch);
    float cy = cos(yaw), sy = sin(yaw);
    
    dcm[0][0] = cp*cy;
    dcm[0][1] = sp*sr*cy - cr*sy;
    dcm[0][2] = cr*sp*cy + sr*sy;
    dcm[1][0] = cp*sy;
    dcm[1][1] = sp*sr*sy + cr*cy;
    dcm[1][2] = cr*sp*sy - sr*cy;
    dcm[2][0] = -sp;
    dcm[2][1] = sr*cp;
    dcm[2][2] = cr*cp;
}

我记得有一次做姿态融合,用DCM做旋转矩阵更新,结果发现矩阵的正交性慢慢丢失了。后来才意识到,DCM需要定期做正交化处理。嗯,这里要注意:DCM的更新比四元数复杂,但物理意义更直观。

2.5 知识体系总览

下面这张图是我自己整理的坐标系与姿态表示的知识结构。你把它看懂了,飞控的姿态部分就通了八成。

坐标系与姿态表示知识体系 常用坐标系 地心坐标系 (ECEF) 地理坐标系 (NED) 机体坐标系 (Body) 三者之间需要转换 姿态表示方法 欧拉角 (Roll/Pitch/Yaw) 四元数 (q0,q1,q2,q3) 方向余弦矩阵 (DCM) 三种方法可互相转换 飞控应用场景 姿态解算 (AHRS) 导航与定位 控制律设计 传感器融合 核心原则 坐标系转换要明确 → 姿态表示要统一 → 数值稳定性要保证 坐标系是飞控的“语言”,姿态是飞控的“灵魂” ⚠ 常见坑:坐标系搞反、万向锁、四元数未归一化、DCM未正交化

这张图里,左边是坐标系,中间是姿态表示方法,右边是应用场景。你从左边走到右边,就是飞控姿态部分的完整链路。我个人建议,新手先从欧拉角入手理解物理意义,然后尽快切换到四元数做工程实现。

总结一下:坐标系是飞控的“语言”,姿态是飞控的“灵魂”。搞不清楚坐标系,你写的控制律再漂亮也是白搭。我见过太多人,代码写得飞起,结果坐标系搞反了,飞机一上天就翻。所以,花时间把这一章吃透,后面你会感谢自己的。


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