验证网络上四元数的正确性

  这里的四元数算法来自这里,我没有直接使用这个算法而是自己写了个程序验证其正确性.下面是代码:

(博客园 : 梦工厂2012)

// Quaternion_test.cpp : Defines the entry point for the console application.
//


/*所有方法体者经过了验证*/
#include "stdafx.h"
#include "math.h"
#define pi 3.1415926
/*四元数的元素,代表估计方向  */
float q0 = 1, q1 = 0, q2 = 0, q3 = 0;
float q0_inc,q1_inc,q2_inc,q3_inc;     
/*用于对四元进行更新,角增量,不是真实的欧拉角*/
float Roll_inc,Pitch_inc,Yaw_inc;
float Roll,Pitch,Yaw;                /*真实欧拉角*/

void FromEulerAngle(float Roll_add,float Pitch_add,float Yaw_add) ;
void ToEulerAngle();
void Quaternion_nor();
void Multiply(float q0_n,float q1_n,float q2_n,float q3_n);


int main(int argc, char* argv[])
{
    Roll_inc=00.0/180*pi;
    Pitch_inc=0.0/180*pi;
    Yaw_inc=10.0/180*pi;

    printf("第一次旋转\n");
    printf("yaw_inc=%f\n",Yaw_inc*57.3);
    printf("pitch_inc=%f\n",Pitch_inc*57.3);
    printf("roll_inc=%f\n",Roll_inc*57.3);

    FromEulerAngle(Roll_inc,Pitch_inc,Yaw_inc) ;
    /*更新四元  */
    Multiply(q0_inc,q1_inc,q2_inc,q3_inc);

    printf("q0=%f\n",q0);
    printf("q1=%f\n",q1);
    printf("q2=%f\n",q2);
    printf("q3=%f\n",q3);
    
    ToEulerAngle();

    printf("yaw=%f\n",Yaw*57.3);
    printf("pitch=%f\n",Pitch*57.3);
    printf("roll=%f\n",Roll*57.3);

    printf("第二次旋转\n");
    Roll_inc=0.0/180*pi;
    Pitch_inc=10.0/180*pi;
    Yaw_inc=0.0/180*pi;

/*角度增量*/
    printf("yaw_inc=%f\n",Yaw_inc*57.3);
    printf("pitch_inc=%f\n",Pitch_inc*57.3);
    printf("roll_inc=%f\n",Roll_inc*57.3);

    /*欧拉角转四元数, 增量四元数*/
    FromEulerAngle(Roll_inc,Pitch_inc,Yaw_inc) ;

    /*更新四元数*/
    Multiply(q0_inc,q1_inc,q2_inc,q3_inc);
    printf("第二次旋转的四元数\n");
    printf("q0=%f\n",q0);
    printf("q1=%f\n",q1);
    printf("q2=%f\n",q2);
    printf("q3=%f\n",q3);
    /*转成载体欧拉角*/
    ToEulerAngle();
    printf("yaw=%f\n",Yaw*57.3);
    printf("pitch=%f\n",Pitch*57.3);
    printf("roll=%f\n",Roll*57.3);
/*第三次旋转*/


    printf("第三次旋转\n");
    Roll_inc=10.0/180*pi;
    Pitch_inc=0.0/180*pi;
    Yaw_inc=0.0/180*pi;

/*角度增量*/
    printf("yaw_inc=%f\n",Yaw_inc*57.3);
    printf("pitch_inc=%f\n",Pitch_inc*57.3);
    printf("roll_inc=%f\n",Roll_inc*57.3);

    /*欧拉角转四元数, 增量四元数*/
    FromEulerAngle(Roll_inc,Pitch_inc,Yaw_inc) ;

    /*更新四元数*/
    Multiply(q0_inc,q1_inc,q2_inc,q3_inc);
    printf("第三次旋转的四元数\n");
    printf("q0=%f\n",q0);
    printf("q1=%f\n",q1);
    printf("q2=%f\n",q2);
    printf("q3=%f\n",q3);
    /*转成载体欧拉角*/
    ToEulerAngle();
    printf("yaw=%f\n",Yaw*57.3);
    printf("pitch=%f\n",Pitch*57.3);
    printf("roll=%f\n",Roll*57.3);





    return 0;
}

/*欧拉角转四元,其它坐标系 */
/*这里是否采用小角近似???*/
void FromEulerAngle(float Roll_add,float Pitch_add,float Yaw_add)  /*这里只是机体转角近似成欧拉角   */
{

    /*在俊的姿态解算中,用的是小角近似  q=[1,Ω*t/2,Ω*t/2,Ω*t/2]T*/

    float fCosHRoll = (float)cos(Roll_add * .5f);
    float fSinHRoll = (float)sin(Roll_add * .5f);
    float fCosHPitch = (float)cos(Pitch_add * .5f);
    float fSinHPitch = (float)sin(Pitch_add * .5f);
    float fCosHYaw = (float)cos(Yaw_add * .5f);
    float fSinHYaw = (float)sin(Yaw_add * .5f);                   /*回来看看这三角函数运算用了多长时间*/
                                                                                        /*下面这个运算要根据坐标第进行修改*/
    q0_inc = fCosHRoll * fCosHPitch * fCosHYaw + fSinHRoll * fSinHPitch * fSinHYaw;
    q1_inc = fSinHRoll * fCosHPitch * fCosHYaw - fCosHRoll * fSinHPitch * fSinHYaw;
    q2_inc = fCosHRoll * fSinHPitch * fCosHYaw + fSinHRoll * fCosHPitch * fSinHYaw;
    q3_inc = fCosHRoll * fCosHPitch * fSinHYaw - fSinHRoll * fSinHPitch * fCosHYaw;
    
}
/*四元数转欧拉角*/
void ToEulerAngle()
{
    Roll=atan2(2 * (q0 * q1 + q2 * q3) , 1 - 2 * (q1 * q1 + q2 * q2)); 
    Yaw = atan2(2 * (q0 * q3 + q1 * q2) , 1 - 2 * (q2 * q2 + q3 * q3));
    Pitch = asin(2*(q0*q2-q3*q1)) ;
}
    
/*更新四元数*/
/* q_n  这里代表新来的四元数,这里指的是增量   */
void Multiply(float q0_n,float q1_n,float q2_n,float q3_n)
{
    float q0_temp=q0*q0_n      -q1*q1_n      -q2*q2_n      -q3*q3_n;
    float q1_temp=q0*q1_n      +q1*q0_n      +q2*q3_n      -q3*q2_n;
    float q2_temp=q0*q2_n      -q1*q3_n      +q2*q0_n      +q3*q1_n;
    float q3_temp=q0*q3_n      +q1*q2_n      -q2*q1_n      +q3*q0_n;
    q0=q0_temp;
    q1=q1_temp;
    q2=q2_temp;
    q3=q3_temp;

float s=sqrt(q0*q0+q1*q1+q2*q2+q3*q3); //这里重新进行规范化,避免的累积误差
q0=q0/s;
q1=q1/s;
q2=q2/s;
q3=q3/s;



}

网页中给的欧拉角的转动顺序为  yaw  pitch  roll   ,代码不是最重要的而是其验证的思想 .这里我介绍一下代码的思想 ,首先我们假设转动的顺序为 yaw pitch  roll  ,

这样的话我们首先只进行 yaw角度的旋转,pitch角度的旋转,roll角度的旋转 ,如果假设成立的话应该出现下面这结果,也就是说最终的欧拉角不相互影响:

进一步验证其正确性,其共有6种可能性,逐一进行验证,最终确定其转动顺序为 yaw pitch roll  .和之前说的一致.

我利用这个算法 对陀螺仪数据 简单平均采样,限幅处理之后,直接积分的效果:

 下面这个视频是 与加计互补滤波,可以全姿态

imu.c 与  互补滤波 四元数算法对比

 

博文为本人所写转载请表明出处 :验证网络上四元数的正确性   

原文地址:https://www.cnblogs.com/dreamfactory/p/3043025.html