2. 坐标系与姿态表示:地理坐标系、机体坐标系、欧拉角与四元数

飞控算法里,坐标系和姿态表示是地基中的地基。说白了,你连无人机“朝哪飞”、“怎么转”都描述不清楚,后面什么控制、导航全是空中楼阁。

我个人习惯,每次带新人入门,第一件事就是让他们把这三个概念刻在脑子里:地理坐标系机体坐标系,以及姿态的数学表达。今天我们就来把这层窗户纸捅破。

2.1 地理坐标系:无人机眼中的“世界”

地理坐标系,也叫导航坐标系。你可以把它想象成一个固定在起飞点的三维空间直角坐标系。

  • X轴:指向正北(或正东,看具体定义)
  • Y轴:指向正东(或正北)
  • Z轴:指向地心(也就是“向下”)

嗯,这里要注意:Z轴向下是航空界的惯例。为什么?因为这样定义,高度越高,Z值越小(负得越多)。虽然反直觉,但行业标准就是这样,别问为什么,记住就行。

核心作用:地理坐标系是无人机的“绝对参考系”。GPS给出的经纬高、航线规划的目标点、返航点,全部基于这个坐标系。

我在项目中遇到过一个问题:有次试飞,无人机返航时总是偏左几米。查了半天,发现是GPS模块的安装方向偏了1度,导致地理坐标系下的航向角有偏差。你看,坐标系不准,飞控再牛也白搭。

2.2 机体坐标系:无人机“自己”的视角

机体坐标系是固定在无人机机身上的坐标系。它跟着飞机一起转。

  • X轴:指向机头方向(前进方向)
  • Y轴:指向机身右侧(右翼方向)
  • Z轴:指向机身下方(符合右手定则)

你想想看,无人机上的传感器——IMU(惯性测量单元)、磁力计、气压计——它们测量的原始数据,都是基于机体坐标系的。比如加速度计测的是“机体坐标系下的加速度”,陀螺仪测的是“机体坐标系下的角速度”。

我的习惯:在代码里,我会用 body_frameBODY 作为变量前缀,提醒自己这是机体坐标系下的量。比如 body_accelbody_gyro

但问题来了:飞控要控制无人机“往北飞”,而传感器只知道“机头方向有加速度”。这两个坐标系之间怎么转换?这就引出了姿态表示。

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

欧拉角用三个角度来描述机体坐标系相对于地理坐标系的旋转:偏航角(Yaw)俯仰角(Pitch)横滚角(Roll)

角度 旋转轴 范围 物理意义
偏航角 (Yaw, ψ) Z轴 -180° ~ 180° 机头指向(北偏东为正)
俯仰角 (Pitch, θ) Y轴 -90° ~ 90° 机头抬起/低下(抬头为正)
横滚角 (Roll, φ) X轴 -180° ~ 180° 机身左右倾斜(右倾为正)

欧拉角的好处是直观。你一看“偏航30度,俯仰10度,横滚5度”,脑子里就能大概想象出飞机的姿态。

我曾经踩过一个坑:欧拉角有“万向锁”问题。当俯仰角接近±90度时,偏航和横滚会失去一个自由度,导致姿态解算出现奇异。所以,在飞控内部做姿态解算和插值时,我几乎不用欧拉角,而是用四元数。

2.4 四元数:飞控工程师的“瑞士军刀”

四元数是一个超复数,形式为 q = w + xi + yj + zk,其中 w 是实部,x, y, z 是虚部。它用四个数来表示三维空间中的旋转。

为什么飞控里非要用四元数?三个原因:

  1. 无万向锁:随便你怎么转,四元数都能平滑表示。
  2. 计算效率高:旋转组合只需要四元数乘法,比欧拉角转矩阵快得多。
  3. 插值平滑:用球面线性插值(SLERP)可以在两个姿态之间做平滑过渡。

我个人习惯,在飞控代码里,姿态的“内部存储”和“运算”全部用四元数。只在需要给地面站显示、或者做简单逻辑判断时,才转成欧拉角。

下面是一个简单的四元数转欧拉角的代码片段,我经常在调试时用:

// 四元数转欧拉角(弧度)
void quaternion_to_euler(float q[4], float *roll, float *pitch, float *yaw) {
    // 计算俯仰角(注意asin的范围限制)
    float sinr_cosp = 2.0f * (q[0]*q[1] + q[2]*q[3]);
    float cosr_cosp = 1.0f - 2.0f * (q[1]*q[1] + q[2]*q[2]);
    *roll = atan2f(sinr_cosp, cosr_cosp);

    float sinp = 2.0f * (q[0]*q[2] - q[3]*q[1]);
    if (fabsf(sinp) >= 1.0f)
        *pitch = copysignf(M_PI/2.0f, sinp); // 处理万向锁
    else
        *pitch = asinf(sinp);

    float siny_cosp = 2.0f * (q[0]*q[3] + q[1]*q[2]);
    float cosy_cosp = 1.0f - 2.0f * (q[2]*q[2] + q[3]*q[3]);
    *yaw = atan2f(siny_cosp, cosy_cosp);
}

避坑指南:四元数一定要归一化!我见过太多新手因为忘记归一化,导致姿态越算越飘。每次更新完四元数,记得做 q = q / norm(q)

2.5 知识体系总览

为了让你更直观地理解这三者之间的关系,我画了一张图:

地理坐标系 NED (北东地) 绝对参考系 GPS、航线、返航点 机体坐标系 FRD (前右下) 随体参考系 IMU、角速度、加速度 姿态表示 欧拉角 / 四元数 旋转矩阵 坐标变换的桥梁 定义 描述 坐标变换(旋转矩阵) 核心逻辑 传感器数据(机体坐标系)→ 姿态解算(四元数)→ 坐标变换 → 导航控制(地理坐标系) 欧拉角主要用于人机交互和显示,四元数用于内部运算

这张图把整个逻辑串起来了。你从传感器拿到的是机体坐标系下的数据,经过姿态解算(四元数),转换成地理坐标系下的量,才能做导航和控制。

2.6 实战中的选择建议

说了这么多,到底什么时候用欧拉角,什么时候用四元数?我总结一下:

  • 显示和日志:用欧拉角。人看得懂,调试方便。
  • 姿态解算(AHRS/INS):用四元数。稳定、无奇异。
  • 控制律计算:用四元数或旋转矩阵。避免欧拉角的非线性问题。
  • 航点规划:用地理坐标系下的位置和欧拉角。直观。

一句话总结:地理坐标系是“世界”,机体坐标系是“自我”,欧拉角是“人话”,四元数是“机器语言”。飞控工程师的工作,就是在这四者之间自由切换。

好了,坐标系和姿态表示就讲到这里。这些东西看似基础,但每次我遇到飞控bug,十有八九都能追溯到坐标系搞混或者姿态转换出错。希望你能把这些概念刻在脑子里,后面讲悬停控制和航线规划时,我们还会反复用到它们。


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