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


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

    (博客园 : 梦工厂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 与  互补滤波 四元数算法对比

     

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

  • 相关阅读:
    String类
    try catch异常捕获
    while循环语句
    编程中穷举法的运用
    for循环例题
    编程中的 if ()else() 语句
    代位符
    运算符_及_运算符优先级
    C#中的类型转换
    Asp.net基础知识
  • 原文地址:https://www.cnblogs.com/dreamfactory/p/3043025.html
Copyright © 2020-2023  润新知