3、坐标系与旋转:刚体旋转、欧拉角、四元数、旋转矩阵、坐标系对齐

各位同学好,我是你们的讲师。今天我们来聊聊OIS防抖算法里最基础、也最容易踩坑的一个话题——坐标系与旋转。

说实话,我刚开始做OIS的时候,觉得旋转不就是转个角度嘛,有什么难的?结果第一次联调,画面抖得比没开防抖还厉害。查了两天,最后发现是陀螺仪和镜头的坐标系没对齐。嗯,从那以后,我再也不敢小看坐标系了。

3.1 刚体旋转:物理世界的“转身”

先说说刚体旋转。什么叫刚体?就是不会变形的物体。手机、镜头模组、陀螺仪芯片,都可以近似看作刚体。

刚体旋转有一个核心性质:旋转前后,物体内部任意两点之间的距离保持不变。你想想看,手机转个角度,屏幕上的像素点之间的距离会变吗?不会。这就是刚体旋转。

在数学上,刚体旋转可以用一个3x3的矩阵来描述。这个矩阵叫旋转矩阵,它有三个特点:

  • 行列式为1(保证不缩放)
  • 是正交矩阵(转置等于逆)
  • 满足右手定则(我们一般用右手坐标系)

核心要点:刚体旋转只有3个自由度。无论你怎么转,最终都可以用3个独立参数来描述。

3.2 欧拉角:直观但危险的表达方式

欧拉角可能是大家最熟悉的旋转表达方式了。俯仰角(Pitch)、偏航角(Yaw)、翻滚角(Roll),听着就亲切。

但我要提醒你:欧拉角有坑

我在项目中遇到过一个问题:用欧拉角做插值,结果画面突然“翻了个跟头”。后来才发现,这是欧拉角的万向锁问题——当俯仰角接近90度时,偏航和翻滚会耦合,丢失一个自由度。

避坑指南:我曾经在陀螺仪数据融合时直接用欧拉角做卡尔曼滤波,结果状态协方差矩阵奇异了。后来改用四元数,问题迎刃而解。所以,OIS算法里尽量别用欧拉角做内部计算,只用来做可视化或人机交互。

欧拉角的另一个问题是:旋转顺序很重要。同样的三个角度,按XYZ顺序和ZYX顺序旋转,结果完全不同。我习惯用ZYX顺序(先偏航,再俯仰,最后翻滚),因为这样更符合手机的实际运动。

3.3 四元数:防抖算法的“瑞士军刀”

四元数,说白了就是一个有四个分量的超复数。形式是:

q = w + xi + yj + zk

其中w是实部,x、y、z是虚部。约束条件是:w² + x² + y² + z² = 1(单位四元数)。

为什么OIS算法里要用四元数?三个理由:

  1. 无万向锁——随便你怎么转,不会丢自由度
  2. 插值平滑——球面线性插值(SLERP)可以生成非常平滑的旋转过渡
  3. 计算高效——乘法只需要16次浮点运算,比旋转矩阵的27次少

我个人习惯用四元数来融合陀螺仪和加速度计的数据。具体做法是:

// 伪代码:四元数更新
// gyro_data: 角速度 (rad/s)
// dt: 采样间隔 (s)
// q: 当前姿态四元数

void update_quaternion(float gyro[3], float dt, float q[4]) {
    float wx = gyro[0] * dt / 2.0f;
    float wy = gyro[1] * dt / 2.0f;
    float wz = gyro[2] * dt / 2.0f;
    
    float dq[4] = {1.0f, wx, wy, wz};
    // 四元数乘法:q_new = q * dq
    quaternion_multiply(q, dq, q_new);
    // 归一化
    quaternion_normalize(q_new);
}

小技巧:四元数乘法不满足交换律。我刚开始写代码时搞反了顺序,结果姿态估计完全不对。记住:先旋转的放右边

3.4 旋转矩阵:数学上的“标准答案”

旋转矩阵是描述旋转最标准的方式。一个3x3的矩阵,每一列代表旋转后的坐标轴方向。

举个例子,绕Z轴旋转θ角的矩阵是:

Rz(θ) = [cosθ  -sinθ  0]
        [sinθ   cosθ  0]
        [0      0     1]

旋转矩阵的好处是:可以任意组合。多个旋转连在一起,就是矩阵乘法。而且,逆矩阵就是转置矩阵,求逆非常方便。

但缺点也很明显:9个参数,冗余了6个。而且,如果数值误差累积,矩阵会慢慢“退化”成非正交矩阵。所以,用旋转矩阵时,记得定期做正交化

3.5 坐标系对齐:OIS算法的“第一道坎”

好了,终于到了最关键的环节。坐标系对齐,说白了就是让陀螺仪和镜头“说同一种语言”。

手机里,陀螺仪芯片的坐标系和镜头模组的坐标系通常是不重合的。可能差了90度,也可能某个轴是反的。如果不做对齐,防抖算法就会“帮倒忙”。

我一般分三步走:

  1. 确定参考坐标系——通常以镜头的光轴方向为Z轴,水平方向为X轴,竖直方向为Y轴
  2. 测量偏移量——用标定板或已知运动,测出陀螺仪坐标系到镜头坐标系的旋转关系
  3. 应用变换——把陀螺仪数据乘以一个固定的旋转矩阵,转换到镜头坐标系

经验之谈:我曾经遇到一个项目,陀螺仪和镜头之间差了0.5度的安装误差。一开始没在意,结果防抖效果始终差一口气。后来用高精度标定补偿了这0.5度,效果立竿见影。所以,坐标系对齐的精度,直接决定了防抖效果的上限

下面这张图展示了整个坐标系与旋转的知识体系:

坐标系与旋转知识体系 刚体旋转 3自由度 欧拉角 Pitch/Yaw/Roll 四元数 w + xi + yj + zk 旋转矩阵 3x3正交矩阵 坐标系对齐 陀螺仪 → 镜头 确定参考坐标系 光轴为Z轴 测量偏移量 标定旋转关系 应用变换 旋转矩阵乘法 核心:四元数做内部计算,欧拉角做可视化,旋转矩阵做坐标系变换

3.6 实际工程中的坐标系对齐流程

最后,我分享一下实际项目中的坐标系对齐流程。这可不是纸上谈兵,是我踩过无数坑后总结出来的:

步骤 操作 注意事项
1 读取陀螺仪原始数据 注意数据格式,可能是16位整数,需要转成float
2 应用陀螺仪坐标系到镜头坐标系的旋转矩阵 这个矩阵是固定的,一次标定终身使用
3 将旋转后的数据转换为四元数 用角速度积分,注意积分顺序
4 用四元数计算镜头需要补偿的角度 这里要考虑延迟补偿,后面章节会讲
5 将补偿角度映射到OIS执行器 注意执行器的行程限制和非线性

我的习惯:在代码里,我会把坐标系对齐矩阵单独写成一个函数,并且加上单元测试。每次改硬件后,只需要更新这个矩阵,其他代码不用动。这样既安全又方便。

好了,这一章的内容就到这里。坐标系和旋转是OIS算法的地基,地基不稳,上面盖的房子再漂亮也没用。希望大家在实际项目中,能把这些概念用起来,少走弯路。


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