详解互补滤波四元数中向量叉积与陀螺仪角速度补偿问题(Mahony算法)

本文深入探讨了四旋翼飞行器姿态解算中,利用互补滤波和四元数进行姿态估计的过程。通过归一化处理和坐标转换,解释了为何向量叉积能够有效补偿陀螺仪角速度的误差。文中还阐述了叉积运算在误差分析和PI滤波中的物理意义,以及如何利用加速度计数据修正陀螺仪的精度问题。
摘要由CSDN通过智能技术生成

作者:Leyvi
时间:2017.1.10

一、归一化与坐标转换

很多做四轴的网友对互补滤波四元数姿态解算代码中的向量叉积和陀螺仪积分补偿问题有疑问,我也查了很多资料,写下这篇博文与大家共同学习。
先放一段互补滤波和四元数姿态解算的代码:

/**
 * 6DOF 互补滤波姿态估计(via Mahony)
 * @param[in] halfT:状态估计周期的一半
 */
const float Kp = 3.5, Ki = 0.05;
float exInt, eyInt, ezInt;
float q0 = 1.0f, q1 = 0.0f, q2 = 0.0f, q3 = 0.0f; // roll,pitch,yaw 都为 0 时对应的四元数值。
void IMUupdate(float gx, float gy, float gz, float ax,float ay, float az)
{
    float norm;
    float vx, vy, vz;
    float ex, ey, ez;

    float q0q0 = q0*q0;
    float q0q1 = q0*q1;
    float q0q2 = q0*q2;
    float q1q1 = q1*q1;
    float q1q3 = q1*q3;
    float q2q2 = q2*q2;
    float q2q3 = q2*q3;
    float q3q3 = q3*q3;

    if(ax*ay*az==0)
        return;

    // 第一步:对加速度数据进行归一化
    norm = sqrt(ax*ax + ay*ay + az*az); 
    ax = ax / norm; 
    ay = ay / norm; 
    az = az / norm; 

    // 第二步:DCM矩阵旋转
    vx = 2*(q1q3 - q0q2); 
    vy = 2*(q0q1 + q2q3); 
    vz = q0q0 - q1q1 - q2q2 + q3q3 ;

    // 第三步:在机体坐标系下做向量叉积得到补偿数据
    ex = ay*vz - az*vy ;
    ey = az*vx - ax*vz ;
    ez = ax*vy - ay*vx ;

    // 第四步:对误差进行PI计算,补偿角速度
    exInt = exInt + ex * Ki;
    eyInt = eyInt + ey * Ki;
    ezInt = ezInt + ez * Ki;

    gx = gx + Kp*ex + exInt;
    gy = gy + Kp*ey + eyInt;
    gz = gz + Kp*ez + ezInt;

    // 第五步:按照四元数微分公式进行四元数更新
    q0 = q0 + (-q1*gx - q2*gy - q3*gz)*halfT;
    q1 = q1 + (q0*gx + q2*gz - q3*gy)*halfT;
    q2 = q2 + (q0*gy - q1*gz + q3*gx)*halfT;
    q3 = q3 + (q0*gz + q1*gy - q2*gx)*halfT;

    norm = sqrt(q0*q0 + q1*q1 + q2*q2 + q3*q3);
    q0 = q0/norm;
    q1 = q1/norm;
    q2 = q2/norm;
    q3 = q3/norm;

    roll =  atan2f(2*q2*q3 + 2*q0*q1, -2*q1*q1 - 2*q2*q2 + 1)*57.3;     
    pitch =  asinf(2*q1*q3 - 2*q0*q2)*57.3;                                                          
    yaw  =  -atan2f(2*q1*q2 + 2*q0*q3, -2*q2*q2 -2*q3*q3 + 1)*57.3; 
}

这段代码中[ax,ay,az]是加速度计测量得到的重力向量,然后对其归一化,但是为什么要对它归一化处理呢?不是画蛇添足,而是后面大有用途!
[vx,vy,vz]是世界坐标系重力分向量[0,0,1]经过DCM旋转矩阵计算得到的机体坐标系中的重力向量,即
这里写图片描述(该图摘自网络)
这个旋转矩阵在秦永元的惯性导航书中有详细解释,这里就看出来了,旋转得到的正是机体坐标系归一化后的重力向量。
有人可能纳闷为什么要进行旋转?这就涉及到世界坐标系和机体坐标系的概念了,我从网上摘了几张图进行简单讲解。
这里写图片描述
这里写图片描述
这里写图片描述

图1中盒子模型中的小球处于失重状态,坐标系与世界坐标系重合。
图2中盒子坐标系仍与世界坐标系重合,描述为[x,y,z],不同的是小球收到重力作用,盒子模型坐标系中重力向量为[0,0,1],世界坐标系中也是[0,0,1].
图3中盒子在世界坐标系中与地面夹角为45度,但是盒子坐标系仍是[x,y,z],重力向量变为了[-0.71,0,-0.71],注意这个向量是盒子模型坐标系的向量值,转换到世界坐标系仍是[0,0,1].
所以无论盒子怎么旋转重力向量在世界坐标系中都是[0,0,1],但是我们有加速度计读到的值是基于盒子模型坐标系的,也就是我们所说的机体坐标系。现在就明白了,刚才为什么要用四元数将[0,0,1]乘一个旋转矩阵,我们之后关于加速度计和陀螺仪的计算都是基于机体坐标系的。

二、叉乘运算

重点来了,我们得到了加速度计测得的[ax,ay,az],还有机体坐标系标准的重力向量,下面我们就要对它们做叉积运算:
首先我们先来一点向量叉积的预备知识

在Arduino实现二阶互补滤波,通常涉及到模拟信号处理,用于平滑、滤除噪声或提高传感器读数的质量。二阶滤波器由两个并联的电容器组成,这称为LC电路,可以提供比低通滤波更多的频率响应控制。在软件层面,可以使用IIR(无限 impulse response)滤波算法实现。 以下是一个简单的二阶互补滤波器的Arduino代码示例,这里假设你有一个带噪声的ADC输入(例如来自ADXL345加速度计),我们使用Atmel库的`analogRead()`函数: ```cpp #include <Wire.h> #include "Adafruit_ADXL345.h" // 如果你用的是ADXL345 // 定义滤波器常量 const int sampleRate = 10; // 每秒采样次数 const float c1 = 0.9; // 电容系数 (C1) const float c2 = 0.1; // 电容系数 (C2) const float beta = sqrt(c1 * c2); // β = √(C1*C2) ADXL345 accel; // 假设你已初始化了ADXL345实例 void setup() { Serial.begin(9600); } void loop() { int rawValue = analogRead(A0); // 读取传感器值或其他通道 float filteredValue = filter(rawValue); // 过滤值 Serial.print("Filtered Value: "); Serial.println(filteredValue); // 这里只是一个简单的线性滤波示例,实际应用可能需要调整参数 float filteredValueComplementary = complementaryFilter(filteredValue, prevRawValue); Serial.print("Complementary Filtered Value: "); Serial.println(filteredValueComplementary); // 更新上一周期的数据 prevRawValue = rawValue; delay(1000 / sampleRate); // 等待下一帧采样 } float filter(int input) { float output = input - beta * (input - prevInput); prevInput = input; return output; } float complementaryFilter(float filtered, int unfiltered) { return (unfiltered + filtered) / 2.0; } // 假设prevRawValue在这里用于存储上一次循环的rawValue值 int prevRawValue = 0; ``` 这个例子,`filter()`函数实现了IIR低通滤波,而`complementaryFilter()`则组合了滤波后的结果和原始值,提供了一种互补滤波策略。注意,具体的硬件连接和库依赖会根据实际设备有所不同。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值