2. 坐标系与姿态表示:地球坐标系、机体坐标系、欧拉角、旋转矩阵、四元数基础
做垂直起降控制,第一件事是什么?
不是调PID,也不是写代码。而是先把「我在哪」和「飞机朝哪」说清楚。
说白了,坐标系和姿态表示,是整个飞控的「语言」。语言不通,后面全是扯淡。我见过不少新手,上来就调参数,结果飞机原地打转,查了半天发现是坐标系定义反了。嗯,这种坑我踩过不止一次。
2.1 两个核心坐标系
垂直起降阶段,我们主要跟两个坐标系打交道:
- 地球坐标系(NED):北东地。原点在地面某点,X轴指北,Y轴指东,Z轴指向地心。说白了,就是地面上的「绝对参考系」。
- 机体坐标系(Body):原点在飞机重心,X轴指机头,Y轴指右翼,Z轴指向机腹。这是飞机自己的「身体坐标系」。
为什么需要两个?
因为传感器数据(比如加速度计、陀螺仪)是在机体坐标系下测量的,而导航指令(比如「飞到北边10米」)是在地球坐标系下给出的。你得在两者之间来回翻译。
关键点:垂直起降阶段,我们通常用NED坐标系作为导航参考。但控制输出(比如电机推力)必须转换到机体坐标系下执行。
我个人习惯,在代码里用 ned_frame 和 body_frame 两个结构体来区分。别偷懒混在一起,否则调试时你会哭的。
2.2 欧拉角:最直观的姿态表示
欧拉角是什么?就是三个角度:滚转(Roll)、俯仰(Pitch)、偏航(Yaw)。
你想想看,飞机在空中,无非就是绕三个轴转:
- 绕X轴转 → 滚转(左右倾斜)
- 绕Y轴转 → 俯仰(抬头低头)
- 绕Z轴转 → 偏航(机头左右转)
欧拉角的好处是直观。你一看「滚转30度」,脑子里就能想象出飞机是什么姿态。
但欧拉角有个致命问题——万向锁(Gimbal Lock)。
我记得有一次做半实物仿真,飞机在俯仰接近90度时突然失控。查了半天,发现是欧拉角在俯仰±90度附近出现了奇点,导致姿态解算炸了。从那以后,我对欧拉角就多了一份敬畏。
避坑指南:我曾经在垂直起降的过渡阶段(飞机从悬停转平飞),俯仰角变化剧烈,差点触发万向锁。后来我强制在俯仰角超过80度时切换成四元数解算,才稳住。
所以,欧拉角适合小角度姿态描述。大角度机动,请用四元数。
2.3 旋转矩阵:坐标系之间的桥梁
旋转矩阵,说白了就是一张「翻译表」。它能把机体坐标系下的向量,翻译到地球坐标系下,或者反过来。
从机体到地球的旋转矩阵,通常记作 R_body_to_ned。它的形式是3x3的矩阵,由三个欧拉角的正余弦值组合而成。
// 从欧拉角构建旋转矩阵(ZYX顺序)
float roll = 0.3f; // 滚转 17度
float pitch = 0.1f; // 俯仰 5.7度
float yaw = 0.5f; // 偏航 28.6度
float cr = cosf(roll);
float sr = sinf(roll);
float cp = cosf(pitch);
float sp = sinf(pitch);
float cy = cosf(yaw);
float sy = sinf(yaw);
// 旋转矩阵 R_body_to_ned
float R[3][3] = {
{cp*cy, sr*sp*cy - cr*sy, cr*sp*cy + sr*sy},
{cp*sy, sr*sp*sy + cr*cy, cr*sp*sy - sr*cy},
{-sp, sr*cp, cr*cp}
};
有了这个矩阵,你就可以把机体坐标系下的加速度、角速度、磁场等数据,转换到地球坐标系下使用。
个人经验:我建议把旋转矩阵的计算封装成一个函数,输入欧拉角,输出3x3矩阵。这样代码干净,也方便单元测试。
另外,注意旋转顺序。飞控里常用的是ZYX顺序(先偏航,再俯仰,最后滚转)。别搞混了。
2.4 四元数:飞控的「真香」选择
四元数是什么?
它是一个四维复数,形式是 q = w + xi + yj + zk,其中 w 是实部,x, y, z 是虚部。在飞控里,它用来表示旋转。
为什么用四元数?三个理由:
- 无万向锁:随便你怎么转,不会出现奇点。
- 计算效率高:比旋转矩阵少几个乘法和加法。
- 插值平滑:做姿态插值时,四元数的球面线性插值(SLERP)非常平滑。
我记得第一次在STM32上跑四元数解算,发现比欧拉角快了将近30%。对于实时性要求高的飞控来说,这很关键。
四元数和旋转矩阵可以互相转换:
// 四元数转旋转矩阵
float qw = 0.98f, qx = 0.02f, qy = 0.01f, qz = 0.15f;
float R_q[3][3] = {
{1 - 2*(qy*qy + qz*qz), 2*(qx*qy - qw*qz), 2*(qx*qz + qw*qy)},
{2*(qx*qy + qw*qz), 1 - 2*(qx*qx + qz*qz), 2*(qy*qz - qw*qx)},
{2*(qx*qz - qw*qy), 2*(qy*qz + qw*qx), 1 - 2*(qx*qx + qy*qy)}
};
核心建议:在飞控内部,姿态解算和更新全部用四元数。只在需要输出给用户或做可视化时,才转成欧拉角。
这样既避免了万向锁,又保持了直观性。
2.5 知识体系总览
下面这张图,是我自己梳理的坐标系与姿态表示的知识结构。你把它理解了,后面控制算法的推导就顺了。
2.6 实战中的选择建议
| 场景 | 推荐表示 | 原因 |
|---|---|---|
| 姿态初始化 | 欧拉角 | 直观,方便设置初始姿态 |
| 姿态解算(IMU融合) | 四元数 | 无万向锁,计算快,适合实时更新 |
| 坐标系转换 | 旋转矩阵 | 直接做向量旋转,物理意义清晰 |
| 垂直起降过渡段 | 四元数 + 旋转矩阵 | 大角度机动,必须避开欧拉角奇点 |
| 地面站可视化 | 欧拉角 | 人眼看得懂,调试方便 |
我的习惯:在飞控代码里,姿态核心变量用四元数存储。每次传感器数据进来,用四元数更新姿态。需要输出控制量时,转成旋转矩阵做向量旋转。只有发给地面站时,才转成欧拉角。
这样既保证了精度和效率,又兼顾了可读性。
好了,坐标系和姿态表示就聊到这。这些东西看起来基础,但真的是飞控的「地基」。地基不稳,楼盖得再高也得塌。你把这些概念吃透了,后面讲姿态控制算法时,就会觉得顺理成章。
公众号:蓝海资料掘金营,微信deep3321