坐标系与姿态表示:地心地固坐标系、导航坐标系、欧拉角、四元数、旋转矩阵的转换关系

做定位系统漂移补偿,绕不开坐标系和姿态表示。说白了,你得先知道“我在哪”,才能谈“我偏了多少”。

我个人习惯把坐标系比作“参考框架”。你站在地球上,和站在月球上,看到的“东”和“北”完全不一样。所以,搞定位补偿,第一步就是把这些坐标系理清楚。

1. 地心地固坐标系(ECEF)

这个坐标系,我刚开始接触时觉得挺抽象。它把地球中心作为原点,Z轴指向北极,X轴指向本初子午线与赤道的交点,Y轴按右手定则确定。

嗯,说白了,它是一个随着地球自转一起转的坐标系。你站在北京,你的ECEF坐标是固定的,不会因为你走路而变。但如果你坐飞机飞到上海,ECEF坐标就变了。

为什么用它?

  • GPS卫星直接输出的是ECEF坐标
  • 全球统一,没有投影变形
  • 适合做长距离、大范围的定位计算

避坑指南:我曾经在项目中直接用ECEF坐标做短距离的平面计算,结果发现距离误差很大。因为ECEF是三维球面坐标,短距离时曲率影响不可忽略。后来我改用局部切平面坐标系(ENU)才解决问题。

2. 导航坐标系(NED / ENU)

导航坐标系,说白了就是“你站在地面上,感觉到的方向”。

常用的有两种:

  • NED(北-东-地):X轴指北,Y轴指东,Z轴指向地心。航空、无人机常用。
  • ENU(东-北-天):X轴指东,Y轴指北,Z轴指天。机器人、自动驾驶常用。

我个人习惯用ENU,因为Z轴向上,和大多数传感器的安装方向一致。你想想看,IMU的加速度计,静止时Z轴输出是重力加速度,向上为正,多直观。

ECEF转ENU的步骤:

  1. 选定一个参考点(比如基站位置)
  2. 计算参考点的ECEF坐标
  3. 构建旋转矩阵,将ECEF坐标旋转到ENU
// 伪代码:ECEF 转 ENU
// 参考点经纬度:lat0, lon0, alt0
// 目标点ECEF坐标:x, y, z

// 1. 计算参考点的ECEF坐标
xe0, ye0, ze0 = geodetic_to_ecef(lat0, lon0, alt0)

// 2. 计算差值
dx = x - xe0
dy = y - ye0
dz = z - ze0

// 3. 构建旋转矩阵
// 这里用到了经纬度
sin_lat = sin(lat0)
cos_lat = cos(lat0)
sin_lon = sin(lon0)
cos_lon = cos(lon0)

// ENU 坐标
east = -sin_lon * dx + cos_lon * dy
north = -sin_lat * cos_lon * dx - sin_lat * sin_lon * dy + cos_lat * dz
up = cos_lat * cos_lon * dx + cos_lat * sin_lon * dy + sin_lat * dz

我的经验:做漂移补偿时,我建议把IMU数据统一到ENU坐标系下处理。因为IMU的原始数据是载体坐标系,而漂移补偿需要知道“相对于地面的姿态变化”。统一到ENU后,计算会清晰很多。

3. 姿态表示:欧拉角、四元数、旋转矩阵

姿态表示,说白了就是“你的手机现在朝哪个方向”。

有三种主流表示方法,我挨个说。

3.1 欧拉角

欧拉角用三个角度表示姿态:横滚(Roll)、俯仰(Pitch)、偏航(Yaw)。

嗯,直观,好理解。你想想看,飞机转弯时,飞行员看的就是偏航角。

但是,欧拉角有个致命问题——万向锁。

当俯仰角接近±90°时,横滚和偏航会耦合,丢失一个自由度。我在做无人机飞控时遇到过这个问题,飞机垂直爬升时,姿态解算突然跳变,差点炸机。

警告:如果你做的是全姿态系统(比如无人机、机器人),不要只用欧拉角做内部姿态更新。万向锁会让你在特定角度下完全失控。

3.2 四元数

四元数,说白了就是一个复数在三维空间的推广。它用四个数表示姿态:q = [w, x, y, z]。

我刚开始学四元数时觉得很难理解,但用多了就发现它真香。

四元数的优点:

  • 没有万向锁
  • 插值平滑(做姿态平滑补偿时特别有用)
  • 计算效率高(比旋转矩阵少乘法)
// 四元数乘法(组合两个旋转)
// q1 和 q2 是两个四元数
// 结果 q = q1 * q2

q.w = q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z
q.x = q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y
q.y = q1.w * q2.y - q1.x * q2.z + q1.y * q2.w + q1.z * q2.x
q.z = q1.w * q2.z + q1.x * q2.y - q1.y * q2.x + q1.z * q2.w

我的习惯:在IMU数据融合(比如卡尔曼滤波)中,我全部用四元数做状态量。只在最后输出给用户时,才转成欧拉角。这样既避免了万向锁,又方便用户理解。

3.3 旋转矩阵

旋转矩阵是一个3×3的正交矩阵,用于将一个向量从一个坐标系旋转到另一个坐标系。

比如,把载体坐标系的加速度计读数,旋转到导航坐标系:

// 旋转矩阵 R 将向量 v 从载体坐标系转到导航坐标系
v_nav = R * v_body

旋转矩阵的优点是直观,可以连续旋转。但缺点是参数多(9个数),而且必须保持正交性,否则会引入误差。

4. 三者之间的转换关系

这三者可以互相转换,我画了一张图帮你理解:

欧拉角 (Roll, Pitch, Yaw) 四元数 (w, x, y, z) 旋转矩阵 (3×3 矩阵) 公式转换 公式转换 Rodrigues公式 矩阵迹法 三次旋转组合 反正切求解 图:姿态表示方法及其转换关系

这张图展示了三种姿态表示方法之间的转换路径。我个人建议,在代码实现中,以四元数作为“中间格式”。

为什么?因为四元数转欧拉角和旋转矩阵都有现成的公式,而且数值稳定性好。

5. 实战中的选择建议

场景 推荐表示方法 原因
IMU姿态解算(内部) 四元数 无万向锁,适合滤波
用户界面显示 欧拉角 直观,容易理解
坐标变换(连续旋转) 旋转矩阵 方便链式乘法
姿态平滑插值 四元数 Slerp插值平滑
漂移补偿(卡尔曼滤波) 四元数 状态量少,线性化方便

我的经验:做漂移补偿时,我建议把姿态表示统一成四元数。因为漂移补偿的核心是“估计姿态误差”,而四元数的误差模型比欧拉角简单得多。我曾经在项目中用欧拉角做误差状态卡尔曼滤波,结果在俯仰角接近90°时滤波器直接发散。换成四元数后,问题迎刃而解。

6. 避坑总结

  • 不要混用坐标系:我曾经见过有人把ECEF坐标直接当ENU用,结果定位误差几十米。一定要明确当前数据在哪个坐标系下。
  • 注意四元数的归一化:四元数必须保持单位长度,否则旋转会变形。每次更新后记得归一化。
  • 欧拉角的旋转顺序:不同的应用可能用不同的旋转顺序(ZYX、XYZ等),转换时一定要确认顺序。
  • 旋转矩阵的正交性:数值计算会导致旋转矩阵失去正交性,定期做正交化处理。

嗯,坐标系和姿态表示就讲到这里。这些是定位系统漂移补偿的“地基”,地基打不牢,后面再好的算法也白搭。

可可精品资料库