5iMX宗旨:分享遥控模型兴趣爱好

5iMX.com 我爱模型 玩家论坛 ——专业遥控模型和无人机玩家论坛(玩模型就上我爱模型,创始于2003年)
查看: 6262|回复: 24
打印 上一主题 下一主题

参考h e u y c k与dongfang的姿态算法,我也弄了一个姿态解算出来玩。。

[复制链接]
跳转到指定楼层
楼主
发表于 2012-3-12 13:25 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
参考h e u y c k与dongfang的姿态算法,我也弄了一个姿态解算出来玩。。
///////////////////////////////////////
#define   PI 3.141592653589793
#define f 0.0216                //采样速度
#define  rad 57.29578//180/PI

int cons;
////////////////////////////////////
extern float  gx, gy, gz;
extern float  ax, ay, az;
///////////////////////////////////////       
float  w, x, y, z;
float  b_w, b_x, b_y, b_z;
float  c_w, c_x, c_y, c_z;
float  ea_fRoll, ea_fPitch, ea_fYaw;
float  Roll, Pitch, Yaw;

////////////////////////////////////////////////////

/////////////////////////////////////////////////////////

float   ea_EulerAngle[3];
float   new_EulerAngle[3];
float   ea_Quaternion[4];
float   new_Quaternion[4];

/////////////////////////////////////////////////////
//----------------------------------------------------------------------------------------------------
// Definitions

#define Kp 4.0f                        // proportional gain governs rate of convergence to accelerometer/magnetometer
#define Ki 0.005f                // integral gain governs rate of convergence of gyroscope biases
#define halfT 0.01f                // half the sample period

//---------------------------------------------------------------------------------------------------
// Variable definitions

float q0 = 1, q1 = 0, q2 = 0, q3 = 0;        // quaternion elements representing the estimated orientation
float exInt = 0, eyInt = 0, ezInt = 0;        // scaled integral error

//====================================================================================================
// Function
//====================================================================================================

void IMUupdate(float gx, float gy, float gz, float ax, float ay, float az) {
        float norm;
        float vx, vy, vz;
        float ex, ey, ez;         
       
        // normalise the measurements
        norm = sqrt(ax*ax + ay*ay + az*az);      
        ax = ax / norm;
        ay = ay / norm;
        az = az / norm;      
       
        // estimated direction of gravity
        vx = 2*(q1*q3 - q0*q2);
        vy = 2*(q0*q1 + q2*q3);
        vz = q0*q0 - q1*q1 - q2*q2 + q3*q3;
       
        // error is sum of cross product between reference direction of field and direction measured by sensor
        ex = (ay*vz - az*vy);
        ey = (az*vx - ax*vz);
        ez = (ax*vy - ay*vx);
       
        // integral error scaled integral gain
        exInt = exInt + ex*Ki;
        eyInt = eyInt + ey*Ki;
        ezInt = ezInt + ez*Ki;
       
        // adjusted gyroscope measurements
        gx = gx + Kp*ex + exInt;
        gy = gy + Kp*ey + eyInt;
        gz = gz + Kp*ez + ezInt;
       
        // integrate quaternion rate and normalise
        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;  
       
        // normalise quaternion
        norm = sqrt(q0*q0 + q1*q1 + q2*q2 + q3*q3);
        q0 = q0 / norm;
        q1 = q1 / norm;
        q2 = q2 / norm;
        q3 = q3 / norm;
}
//////////////////////////////////////////////////////////////////////////



void Quaternion_FromEulerAngle( float  ea_fRoll,float  ea_fPitch,float  ea_fYaw)         //欧拉转四元
{
        float  fCosHRoll = cos(ea_fRoll * 0.5f);
        float  fSinHRoll = sin(ea_fRoll * 0.5f);
        float  fCosHPitch = cos(ea_fPitch * 0.5f);
        float  fSinHPitch = sin(ea_fPitch * 0.5f);
        float  fCosHYaw = cos(ea_fYaw * 0.5f);
        float  fSinHYaw = sin(ea_fYaw * 0.5f);

        w = fCosHRoll * fCosHPitch * fCosHYaw + fSinHRoll * fSinHPitch * fSinHYaw;
        x = fCosHRoll * fSinHPitch * fCosHYaw + fSinHRoll * fCosHPitch * fSinHYaw;
        y = fCosHRoll * fCosHPitch * fSinHYaw - fSinHRoll * fSinHPitch * fCosHYaw;
        z = fSinHRoll * fCosHPitch * fCosHYaw - fCosHRoll * fSinHPitch * fSinHYaw;
}
Quaternion_ToEulerAngle(float  w,float  x,float  y,float  z)                            //四元转欧拉
{
        

        ea_fRoll  = atan2(2 * (w * z + x * y) , 1 - 2 * (z * z + x * x));
        ea_fPitch = asin(2 * (w * x - y * z));
        ea_fYaw   = atan2(2 * (w * y + z * x) , 1 - 2 * (x * x + y * y));

        
}


main()
{       
    Stm32_Clock_Init(9); //系统时钟设置
        delay_init(72);             //延时初始化
        LED_Init();                           //初始化与LED连接的硬件接口
        Adc_Init();      
        uart_init(72,115200);
        //Timerx_Init(200,7199);//计数到2048为2048us 步进 1us               
        //EXTIX_Init();
    JTAG_Set(SWD_ENABLE);          //关闭JTAG,打开swd  释放出三个JTAG的口,做普通IO口线  

        read_inti_gyro();

        ACCRead();                                //读取acc
          ea_EulerAngle[0]=atan2(ax,az);           //根据acc算出欧拉(弧度)
//    ea_EulerAngle[1]= asin(ay / 0.981);   
//    ea_EulerAngle[0]=-atan(ax/sqrt((ay*ay)+(az*az)));
      ea_EulerAngle[1]=atan(ay/sqrt((ax*ax)+(az*az)));
      ea_EulerAngle[2]=0;

   Quaternion_FromEulerAngle( ea_EulerAngle[0],ea_EulerAngle[1],ea_EulerAngle[2] ); //欧拉转四元 初始值
     q0=w;
         q1=x;
         q2=y;                          //放入初始化数组
         q3=z;


//   Quaternion_ToEulerAngle(q0,q1,q2,q3);        //四元转欧拉(弧度)
//      Roll=ea_fRoll*rad;                                                //弧度转化为度         便于测试观察
//          Pitch=ea_fPitch*rad;
//          Yaw=ea_fYaw*rad;

         delay_ms(20);

        while(1)
        {test=!test;
          GyroRead();                                           //读取gyro
          ACCRead();                                //读取acc
          new_EulerAngle[0]=(gx/rad*f);          //读取到的为度/s   /pi/180
          new_EulerAngle[1]=(gy/rad*f);
          new_EulerAngle[2]=(gz/rad*f);

     IMUupdate(new_EulerAngle[0],new_EulerAngle[1],new_EulerAngle[2],ax,ay,az);        //根据刷新gyro和acc计算新的四元姿态

     Quaternion_ToEulerAngle(q0,q1,q2,q3);        //四元转欧拉(弧度)

      Yaw=ea_fRoll*rad;                                                //弧度转化为度         xyz传感器方向不同调节了x与z的位置
          Pitch=ea_fPitch*rad;
          Roll=ea_fYaw*rad;

      LED1=!LED1;
          delay_us(19500);
          if(Roll>30)LED0=0;                 //ROLL大于30度时指示
          else LED0=1;
        }

}       

感觉基本正常,有待进一步测试。。。

[ 本帖最后由 峰回路转 于 2012-3-12 13:26 编辑 ]

欢迎继续阅读楼主其他信息

沙发
发表于 2012-3-12 13:28 | 只看该作者
飞控也自己写    高手蛮多的!!

[ 本帖最后由 dannyzdzd 于 2012-3-12 13:31 编辑 ]
3
发表于 2012-3-12 13:36 | 只看该作者
:em21:
4
发表于 2012-3-12 14:01 | 只看该作者
高手,期待进一步完善,开源
5
发表于 2012-3-12 22:03 | 只看该作者
全部程序就这些了吗?
6
发表于 2012-3-13 00:17 | 只看该作者
。。。。
7
发表于 2012-3-13 00:18 | 只看该作者
完全看不懂:em20:
8
发表于 2012-3-14 11:03 | 只看该作者
关于加速度和角速度的融合,有些疑问:

// estimated direction of gravity
         vx = 2*(q1*q3 - q0*q2);
         vy = 2*(q0*q1 + q2*q3);
         vz = q0*q0 - q1*q1 - q2*q2 + q3*q3;

这段是另一个四元数转欧拉角的版本吧,不知准确度如何,是不是欧拉角。
         
        // error is sum of cross product between reference direction of field and direction measured by sensor
         ex = (ay*vz - az*vy);
         ey = (az*vx - ax*vz);
         ez = (ax*vy - ay*vx);

这段应该是测出上次倾斜和本次倾斜的夹角,不知道是不是欧拉角
        
        // integral error scaled integral gain
         exInt = exInt + ex*Ki;
         eyInt = eyInt + ey*Ki;
         ezInt = ezInt + ez*Ki;

这个积分的意义是什么呢?

        // adjusted gyroscope measurements
         gx = gx + Kp*ex + exInt;
         gy = gy + Kp*ey + eyInt;
         gz = gz + Kp*ez + ezInt;

为什么这里既要考虑积分又要考虑当前的ex,ey,ez呢?
9
发表于 2012-3-14 12:03 | 只看该作者
原帖由 dongfang 于 2012-3-14 11:03 发表
关于加速度和角速度的融合,有些疑问:

// estimated direction of gravity
         vx = 2*(q1*q3 - q0*q2);
         vy = 2*(q0*q1 + q2*q3);
         vz = q0*q0 - q1*q1 - q2*q2 + q3*q3;

这段是另一个四元数转欧拉角的版本吧,不知准确度如何,是不是欧拉角。
这不是欧拉角,这是把四元数换算成《方向余弦矩阵》中的第三列的三个元素。
根据余弦矩阵和欧拉角的定义,地理坐标系的重力向量,转到机体坐标系,正好是这三个元素。
所以这里的vx\y\z,其实就是当前的欧拉角(即四元数)的机体坐标参照系上,换算出来的重力向量。
         
        // error is sum of cross product between reference direction of field and direction measured by sensor
         ex = (ay*vz - az*vy);
         ey = (az*vx - ax*vz);
         ez = (ax*vy - ay*vx);

这段应该是测出上次倾斜和本次倾斜的夹角,不知道是不是欧拉角
axyz是机体坐标参照系上,加速度计测出来的重力向量,也就是实际测出来的重力向量。
axyz是测量得到的重力向量,vxyz是陀螺积分后的姿态来推算出的重力向量,它们都是机体坐标参照系上的重力向量。
它们之间的误差向量,就是陀螺积分后的姿态和加计测出来的姿态之间的误差。
向量之间的误差,可以用向量叉积(也叫向量外积、叉乘)来表示,exyz就是两个重力向量的叉积。
这个叉积向量仍旧是位于机体坐标系上的,而陀螺积分误差也是在机体坐标系,而且叉积的大小与陀螺积分误差成正比,正好拿来纠正陀螺。(你可以自己拿东西想象一下)
        
        // integral error scaled integral gain
         exInt = exInt + ex*Ki;
         eyInt = eyInt + ey*Ki;
         ezInt = ezInt + ez*Ki;

这个积分的意义是什么呢?

        // adjusted gyroscope measurements
         gx = gx + Kp*ex + exInt;
         gy = gy + Kp*ey + eyInt;
         gz = gz + Kp*ez + ezInt;

为什么这里既要考虑积分又要考虑当前的ex,ey,ez呢?
这两段就是用叉积来做PI修正陀螺零偏。

这段代码很巧妙,要懂关键在于叉积的概念。

[ 本帖最后由 heuyck 于 2012-3-14 12:19 编辑 ]
10
发表于 2012-3-14 12:09 | 只看该作者
这是以前那个帖子里我贴的方程式
CbE = Cγ·Cθ·Cψ =
[cosψcosθ                                        sinψ cos θ                                        -sinθ]
[cosψsinθsinγ - sinψcosγ                sinψsinθsinγ + cosψcosγ                cosθsinγ ]
[cosψsinθcosγ + sinψsinγ                sinψsinθcosγ - cosψsinγ                cosθcosγ]
这是姿态矩阵,也就是余弦矩阵,也可以看成是欧拉角转余弦矩阵的方程,其中γ是横滚roll,θ是俯仰pitch,ψ是航向yaw。

重力向量Ge在地理坐标系上的xyz分量是
[0]
[0]
[1]

那么可以算出机体坐标系上重力向量Gb的xyz分量是 Cbe * Ge =
[-sinθ]
[cosθsinγ]
[cosθcosγ]

也就是余弦矩阵的第三列三个元素。三个vxyz右边的四元数算法,实际是四元数转成了余弦矩阵这三个元素。

捷联算法的关键在于理解地理坐标系和机体坐标系的概念,然后知道怎么把向量从地理和机体之间换算,另外就是姿态的三种表示方式:欧拉角、四元数、方向余弦矩阵及它们之间的转换。


原理和算法分析得这么明白了,懂了的话给鼓个掌:em15:

[ 本帖最后由 heuyck 于 2012-3-14 12:14 编辑 ]
11
 楼主| 发表于 2012-3-14 22:57 | 只看该作者
呵呵。两位大佬解释的通彻,我只是知其然不知其所以然。。。。。。
慢慢折腾吧。等忙完这段时间做个简单的平衡仪上机试试。
12
发表于 2012-3-14 23:16 | 只看该作者
全然不懂。。都是高手。
13
发表于 2012-3-14 23:51 | 只看该作者
一堆乱码  都是高手啊
14
发表于 2012-3-15 07:36 | 只看该作者
老外就是大方~
15
发表于 2012-3-15 07:49 | 只看该作者
看傻了:em20: 正文没一句看懂的,注解也迷迷糊糊:em15: 晚上给儿子看——看看!这才是骨灰级的玩家~:em15:
16
发表于 2012-3-15 09:54 | 只看该作者
:em21:
17
发表于 2012-3-15 10:20 | 只看该作者

标题

数学不好对学习这些有影响吗?
18
 楼主| 发表于 2012-3-15 10:37 | 只看该作者
原帖由 mrduke 于 2012-3-15 10:20 发表
数学不好对学习这些有影响吗?

很有影响啊。。。切身体会
19
发表于 2012-3-15 11:22 | 只看该作者
:em26: :em26: :em26: 自从研究姿态算法以来,就一直在复习高数和线代。今天又学了四元数和方向余弦的转换,这要感谢H.E.U.Y.C.K的热心了。
20
发表于 2012-3-26 21:43 | 只看该作者
电脑坏了,全是乱码:em15:
您需要登录后才可以回帖 登录 | 我要加入

本版积分规则

关闭

【站内推荐】上一条 /2 下一条

快速回复 返回顶部 返回列表