第一章 捷联惯导系统概述

各位同学好,我是你们这门课的主讲。今天咱们聊聊捷联惯导系统最基础的东西——基本原理、坐标系定义,还有姿态表示方法。这些东西看着简单,但我在项目里吃过不少亏,所以想从一开始就把这些坑给你们指出来。

1.1 捷联惯导的基本原理

捷联惯导,说白了就是把惯性传感器(陀螺仪和加速度计)直接“绑”在载体上。跟平台式惯导不一样,它没有物理上的稳定平台。那怎么导航呢?靠数学!

陀螺仪测角速度,加速度计测比力。然后通过计算机实时解算,算出姿态、速度和位置。我刚开始接触这个的时候,总觉得“这不就是积分嘛,有什么难的?”后来发现,积分误差积累起来,能把你的导航结果带到沟里去。

核心思想:捷联惯导用“数学平台”代替了物理平台。这个数学平台就是姿态更新算法。姿态算不准,后面速度、位置全是错的。

嗯,这里要注意:捷联惯导没有活动部件,可靠性高,成本低。但代价是计算量大,对算法要求高。咱们这门课,就是专门讲怎么在嵌入式平台上把这些算法跑得又快又准。

1.2 坐标系定义

搞惯导,坐标系是绕不开的。我见过不少新手,坐标系搞混了,结果整个程序推倒重来。所以咱们先把坐标系理清楚。

常用的坐标系有这么几个:

  • 地心惯性坐标系(i系):原点在地心,轴指向恒星。这是牛顿定律成立的坐标系。说白了,就是绝对空间的一个参考。
  • 地球坐标系(e系):原点在地心,z轴指向北极,x轴指向本初子午线。跟着地球转的。
  • 导航坐标系(n系):通常选“东北天”或“北东地”。我习惯用东北天,因为直观。原点在载体所在位置。
  • 载体坐标系(b系):原点在载体质心,x轴朝前,y轴朝右,z轴朝下(右前上也有,看具体定义)。
坐标系 原点 特点
i系 地心 不旋转,惯性定律适用
e系 地心 随地球自转
n系 载体位置 东北天,导航计算用
b系 载体质心 传感器直接测量

我的经验:在代码里,坐标系一定要用注释写清楚。我曾经在一个项目里,因为b系定义跟传感器手册不一致,整整调了两天bug。后来我养成了习惯,每个变量都标注坐标系。

1.3 姿态表示方法

姿态表示,是捷联惯导的核心。说白了,就是描述b系相对于n系怎么转的。常用的有三种:欧拉角、四元数、方向余弦矩阵。咱们一个一个说。

1.3.1 欧拉角

欧拉角最直观。就是三个角度:航向角(ψ)、俯仰角(θ)、横滚角(φ)。你想想看,飞机怎么转的?先转航向,再抬头,最后侧倾。这就是欧拉角的物理意义。

但是!欧拉角有个致命问题——万向锁。当俯仰角接近±90°时,航向和横滚就分不清了。我在做无人机项目时,有一次飞机垂直爬升,姿态解算直接炸了。后来查原因,就是万向锁。

避坑指南:如果你做的是全姿态运动(比如无人机、机器人),千万别只用欧拉角。我建议用四元数做内部计算,欧拉角只做显示用。

1.3.2 方向余弦矩阵(DCM)

DCM是一个3×3的矩阵,表示两个坐标系之间的旋转关系。它没有万向锁问题,但计算量大。每次更新要算9个元素,而且还要做正交化处理。

我记得有一次做嵌入式移植,CPU资源紧张,用DCM做姿态更新,一次迭代要好几毫秒。后来换成四元数,时间降了一个数量级。

// DCM更新示例(简化版)
// C_b^n 是方向余弦矩阵
// omega 是角速度向量
void dcm_update(float C[3][3], float omega[3], float dt) {
    // 构造反对称矩阵
    float Omega[3][3] = {
        {0, -omega[2], omega[1]},
        {omega[2], 0, -omega[0]},
        {-omega[1], omega[0], 0}
    };
    // 一阶近似更新
    for(int i=0; i<3; i++)
        for(int j=0; j<3; j++)
            C[i][j] += dt * (C[i][0]*Omega[0][j] + 
                             C[i][1]*Omega[1][j] + 
                             C[i][2]*Omega[2][j]);
    // 别忘了正交化!
    orthogonalize(C);
}

1.3.3 四元数

四元数是我个人最喜欢的姿态表示方法。它用四个数表示旋转:q = [q0, q1, q2, q3]。没有万向锁,计算量小,而且容易做插值。

四元数跟欧拉角、DCM之间可以互相转换。我一般用四元数做姿态更新,只在需要输出时转成欧拉角。

// 四元数更新(毕卡算法)
// q 是四元数,omega 是角速度,dt 是时间步长
void quaternion_update(float q[4], float omega[3], float dt) {
    float wx = omega[0], wy = omega[1], wz = omega[2];
    float norm = sqrt(wx*wx + wy*wy + wz*wz);
    float half_theta = 0.5f * norm * dt;
    
    if(norm > 1e-10f) {
        float sin_half = sinf(half_theta) / norm;
        float cos_half = cosf(half_theta);
        
        float dq[4] = {
            cos_half,
            wx * sin_half,
            wy * sin_half,
            wz * sin_half
        };
        // 四元数乘法
        float q_new[4];
        q_new[0] = q[0]*dq[0] - q[1]*dq[1] - q[2]*dq[2] - q[3]*dq[3];
        q_new[1] = q[0]*dq[1] + q[1]*dq[0] + q[2]*dq[3] - q[3]*dq[2];
        q_new[2] = q[0]*dq[2] - q[1]*dq[3] + q[2]*dq[0] + q[3]*dq[1];
        q_new[3] = q[0]*dq[3] + q[1]*dq[2] - q[2]*dq[1] + q[3]*dq[0];
        
        for(int i=0; i<4; i++) q[i] = q_new[i];
        // 归一化
        float norm_q = sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]);
        for(int i=0; i<4; i++) q[i] /= norm_q;
    }
}

我的建议:在嵌入式平台上,四元数更新用毕卡算法就够了。如果陀螺仪采样率够高(>100Hz),一阶近似也能用。别搞太复杂的算法,算力宝贵。

1.4 三种方法的对比

方法 优点 缺点 适用场景
欧拉角 直观,物理意义明确 万向锁,计算有奇点 显示、小角度运动
DCM 无奇点,线性 计算量大,需正交化 全姿态,但算力充足时
四元数 无奇点,计算量小 不够直观 嵌入式实时系统首选

我个人在嵌入式项目里,90%的情况都用四元数。只有在需要跟用户交互时,才转成欧拉角。DCM我基本不用,除非是教学演示。

1.5 本章知识体系

下面这张图,是我画的本章知识结构。你看一眼,就能明白各个概念之间的关系。

捷联惯导系统知识体系 捷联惯导系统 基本原理 陀螺仪测角速度 加速度计测比力 数学平台代替物理平台 坐标系定义 i系(惯性坐标系) e系(地球坐标系) n系(导航坐标系) b系(载体坐标系) 姿态表示方法 欧拉角(直观,有万向锁) DCM(无奇点,计算量大) 四元数(推荐,计算量小) 核心:姿态更新是数学平台的基础 姿态不准 → 速度不准 → 位置不准

这张图把本章内容串起来了。你记住:捷联惯导的核心就是用数学平台替代物理平台,而数学平台的基础就是姿态更新。姿态表示方法里,四元数是嵌入式平台的首选。

好了,第一章就讲这么多。内容不多,但都是基础。坐标系搞不清,后面全白搭。姿态表示选不对,代码写再多也没用。希望你们能把这些概念吃透。


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