坐标系基础:地理坐标系(NED/ENU)、机体坐标系、坐标系之间的转换关系

各位同学,欢迎来到姿态解算的第一课。

说实话,很多新手一上来就盯着四元数、卡尔曼滤波猛啃,结果代码跑起来天旋地转。为什么?因为坐标系没搞明白。你想想看,连“北”在哪儿都没定义清楚,算出来的姿态能准吗?

我个人习惯,做飞控第一件事就是先把坐标系钉死。今天我们就来聊聊这三个最基础的东西:地理坐标系、机体坐标系,以及它们怎么互相转换。

1. 地理坐标系:你的绝对参考系

地理坐标系,说白了就是“大地给你的参考”。我们飞无人机,总得知道哪边是北、哪边是地吧?

业内主流有两种定义方式:NEDENU

坐标系 X轴 Y轴 Z轴 常见场景
NED 北 (North) 东 (East) 地 (Down) PX4、ArduPilot、航模
ENU 东 (East) 北 (North) 天 (Up) ROS、GPS、机器人

我在项目中遇到过最坑的事:团队里有人用NED,有人用ENU,结果融合出来的航向角差了90度。飞机一解锁直接原地打转……嗯,从那以后我规定:所有代码注释里必须写明坐标系定义

核心记忆点:

  • NED:Z轴朝下,符合“重力向下”的直觉,飞控常用。
  • ENU:Z轴朝上,符合“右手系”数学习惯,ROS常用。

2. 机体坐标系:跟着飞机转的参考系

机体坐标系是固定在飞机上的。不管飞机怎么翻,这个坐标系都跟着它一起动。

标准定义是这样的:

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

你想想看,机载的IMU(惯性测量单元)测量到的加速度和角速度,其实都是相对于机体坐标系的。但我们要控制飞机,必须知道它在“大地”里是什么姿态。这就引出了下一个问题——怎么转?

一个小技巧: 我习惯在飞控板上贴一个标签,标出X/Y/Z的正方向。调试时看一眼就知道传感器安装有没有歪。曾经有一次,就是因为IMU焊偏了0.5度,导致悬停时一直往右飘,排查了整整两天。

3. 坐标系转换:从机体到地理

转换的核心就是旋转矩阵。说白了,就是把机体坐标系下的向量,投影到地理坐标系下。

假设我们有一个向量在机体坐标系下表示为 [x_b, y_b, z_b]^T,想转到NED坐标系下:

// 伪代码:机体到NED的旋转
// 已知欧拉角:roll(φ), pitch(θ), yaw(ψ)
// 旋转顺序:Z-Y-X (yaw -> pitch -> roll)

R = R_z(ψ) * R_y(θ) * R_x(φ)

// 其中:
// R_x(φ) = [1,    0,      0;
//           0,  cosφ,  -sinφ;
//           0,  sinφ,   cosφ]

// R_y(θ) = [ cosθ,  0,  sinθ;
//             0,    1,    0;
//           -sinθ,  0,  cosθ]

// R_z(ψ) = [cosψ, -sinψ,  0;
//           sinψ,  cosψ,  0;
//            0,     0,    1]

// 最终转换:
v_ned = R * v_body

这里有个坑:旋转顺序不能乱。我见过有人把yaw和pitch的顺序搞反了,结果飞机低头时航向也跟着变。嗯,这其实是数学上的“非交换性”——旋转不满足交换律。

避坑指南: 我曾经在移植PX4代码时,发现它的旋转顺序是Z-Y-X,而另一套库用的是X-Y-Z。两者差了十万八千里。所以移植时一定要确认:

  1. 旋转顺序是什么?
  2. 用的是NED还是ENU?
  3. 欧拉角定义是“绕固定轴”还是“绕动轴”?

4. 知识体系总览

下面这张图是我自己整理的坐标系知识脉络。每次带新人时,我都会先让他们看这个图,再动手写代码。

坐标系基础:知识体系 地理坐标系 绝对参考系 NED:北-东-地 ENU:东-北-天 飞控常用NED,ROS常用ENU 机体坐标系 随飞机运动 X:机头方向 Y:右侧机翼 Z:机身下方 坐标系转换 旋转矩阵 R = R_z(ψ) · R_y(θ) · R_x(φ) v_ned = R · v_body 注意:旋转顺序不可交换! 核心:先定坐标系,再谈姿态解算

5. 实战中的坐标系选择建议

说了这么多理论,到底怎么选?我个人的经验是这样的:

  • 做飞控固件:用NED。PX4、ArduPilot都是这么干的,生态统一。
  • 做地面站或ROS节点:用ENU。ROS的tf树默认就是ENU,别跟它对着干。
  • 做仿真:看你的工具链。Gazebo用ENU,FlightGear用NED,别搞混。

我的习惯: 在代码里定义一个全局宏,比如 #define COORDINATE_SYSTEM NED。所有转换函数都依赖这个宏。这样换平台时,只需要改一个地方。嗯,这招帮我省了不少事。

好了,坐标系基础就讲到这里。记住一句话:坐标系是飞控的“语言”,语言不通,飞机就乱飞。下一节我们会基于这个基础,开始讲姿态的数学表示——欧拉角、旋转矩阵、四元数。到时候你会发现,坐标系搞明白了,后面全是水到渠成的事。


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