极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 11205|回复: 7

按照一个教学贴写了个融合算法,前几秒不错,可后来明显反应滞后

[复制链接]
发表于 2013-8-12 23:15:05 | 显示全部楼层 |阅读模式
本帖最后由 ShadowWalker 于 2013-8-13 13:53 编辑

  1. #include "Wire.h"
  2. #include "I2Cdev.h"
  3. #include "MPU6050.h"
  4. MPU6050 accelgyro;

  5. const float Ac_xs = 16384.0;      //重力加速度系数
  6. const float Pa_xs = 131.0;        //角速度系数
  7. const float Ra=180/PI ;         //弧度转角度系数

  8. double  G;                  //重力加速度
  9. unsigned long T_Now=0,T_Last=0;      //系统当前时间

  10. int Ac[3];                  //读取加速度xyz
  11. int Pa[3];                  //读取角速度xyz
  12. float P[3];     //真实角速度
  13. float C_Pa[3];              //角速度漂移xyz
  14. float C_Ac[3];              //加速度计漂移

  15. float Pa_X_Now,Pa_X_Last,Pa_Y_Now,Pa_Y_Last;     //积分角速度
  16. float Rg[3];        //过程单位矢量
  17. float A[3];             //真实惯性合力分量 |A|=1
  18. float A_X,A_Y;           //x,y与Z轴夹角
  19. float Gr[3];             //重力分量         |G|=1  算法输出
  20. float W=10;             //Rg陀螺仪滤波权重

  21. void setup()
  22. {
  23.     Wire.begin();
  24.     Serial.begin(38400);
  25.     accelgyro.initialize();

  26.     for(int a=0;a<3;a++)            //获取角速度偏移
  27.     {
  28.         for(int i=0;i<50;i++)
  29.         {
  30.             accelgyro.getMotion6(&Ac[0], &Ac[1], &Ac[2], &Pa[0], &Pa[1], &Pa[2]);
  31.             C_Pa[a]=C_Pa[a]+Pa[a];   
  32.         }
  33.         C_Pa[a]=C_Pa[a]/50;  
  34.     }
  35.     C_Ac[2]=-0.1;        
  36. }

  37. void loop()
  38. {
  39.     CalculateGr();
  40.     printdata();
  41.     delay(20);
  42. }

  43. void printdata ()
  44. {

  45.     Serial.print(acos(Gr[0])*Ra);Serial.print(",");
  46.     Serial.print(acos(A[0])*Ra);Serial.print(",");
  47.     Serial.println(acos(Rg[0])*Ra);
  48.   
  49. }

  50. void CalculateGr ()           
  51. {
  52.     accelgyro.getMotion6(&Ac[0], &Ac[1], &Ac[2], &Pa[0], &Pa[1], &Pa[2]);
  53.     for(unsigned char a=0;a<3;a++)                //处理角速度漂移
  54.     {
  55.         Pa[a]=Pa[a]-C_Pa[a];
  56.     }

  57.     for(unsigned char a=0;a<3;a++)                //得到真实加速度和角速度
  58.     {
  59.         A[a]=Ac[a]/Ac_xs;           
  60.         P[a]=Pa[a]/Pa_xs;
  61.     }
  62.     A[2]=A[2]-C_Ac[2];              //处理加速度漂移
  63.     G=sqrt(A[0]*A[0]+A[1]*A[1]+A[2]*A[2]);      
  64.    


  65.     if(T_Last==0)           //第一次
  66.     {
  67.         for(unsigned char a=0;a<3;a++)               
  68.         {
  69.             for(unsigned char b=0;b<10;b++)
  70.             {
  71.                 accelgyro.getMotion6(&Ac[0], &Ac[1], &Ac[2], &Pa[0], &Pa[1], &Pa[2]);
  72.                 A[a]=A[a]/Ac_xs;                  
  73.                 A[a]=A[a]+A[a];
  74.             }
  75.             A[a]=A[a]/10.0;
  76.             Gr[a]=A[a];
  77.         }
  78.         A_X=acos(A[0]);
  79.         A_Y=acos(A[1]);
  80.         T_Last=micros();
  81.         Pa_Y_Last=Pa[1];
  82.         Pa_X_Last=Pa[0];
  83.     }
  84.     if(T_Last>0)
  85.     {           
  86.         Pa_X_Now=P[0];
  87.         Pa_Y_Now=P[1];
  88.         T_Now=micros();
  89.         A_X=A_X+(Pa_Y_Now+Pa_Y_Last)*(T_Now-T_Last)/2000000.0;          //XY轴角度,从陀螺仪积分
  90.         A_Y=A_Y+(Pa_X_Now-Pa_X_Last)*(T_Now-T_Last)/2000000.0;
  91.         if(abs(G-1)>0.05)
  92.         {
  93.             Rg[0]=sq(sin(A_Y))/sqrt(1+sq((cos(A_X)))*sq(tan(A_Y)));
  94.             Rg[1]=sq(sin(A_X))/sqrt(1+sq((cos(A_Y)))*sq(tan(A_X)));
  95.             Rg[2]=sqrt(1-sq(Rg[0])-sq(Rg[1]));
  96.         }
  97.         
  98.         if(abs(G-1)>=0.03)          //校正
  99.         {
  100.             for(unsigned char a=0;a<3;a++)               
  101.             {
  102.                 A[a]=A[a]/G;
  103.             }
  104.             G=sqrt(A[0]*A[0]+A[1]*A[1]+A[2]*A[2]);   //此时G化为1

  105.             for(unsigned char v=0;v<3;v++)               
  106.             {
  107.                 Rg[v]=A[v]/G;
  108.             }
  109.             A_X=acos(A[0]);
  110.             A_Y=acos(A[1]);
  111.         }
  112.         
  113.         for(unsigned char b=0;b<3;b++)          //互补滤波
  114.         {
  115.             Gr[b]=(A[b]+Rg[b]*W)/(W+1);
  116.         }
  117.         G=sqrt(sq(Gr[0])+sq(Gr[1])+sq(Gr[2]));
  118.         for(unsigned char b=0;b<3;b++)      //再次单位化 重力矢量
  119.         {
  120.             Gr[b]=Gr[b]/G;
  121.         }
  122.         T_Last=micros();
  123.         Pa_X_Last=P[0];
  124.         Pa_Y_Last=P[1];
  125.     }
  126. }
复制代码

参考的是http://www.geek-workshop.com/forum.php?mod=viewthread&tid=1695
真实效果:
前十来秒还行,时间一长就明显反应滞后。
各位帮忙看看怎么弄。
回复

使用道具 举报

发表于 2013-8-13 08:32:50 | 显示全部楼层
你是要得到加速度的重力分量?真看不懂,我怎么看出来好象在做"水平校准"........楼下的高手继续吧
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-8-13 11:24:01 | 显示全部楼层
拾瑞 发表于 2013-8-13 08:32
你是要得到加速度的重力分量?真看不懂,我怎么看出来好象在做"水平校准"........楼下的高手继续吧

嗯,得到重力的分量,就能根据余弦关系得到当前传感器的倾角。
回复 支持 反对

使用道具 举报

发表于 2013-8-13 12:07:09 | 显示全部楼层
参考的什么资料????
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-8-13 12:09:44 | 显示全部楼层
学慧放弃 发表于 2013-8-13 12:07
参考的什么资料????

http://www.geek-workshop.com/for ... thread&tid=1695
回复 支持 反对

使用道具 举报

发表于 2013-8-13 14:01:15 | 显示全部楼层
ShadowWalker 发表于 2013-8-13 11:24
嗯,得到重力的分量,就能根据余弦关系得到当前传感器的倾角。

我看一下,你的这种算法,是以加速度计为主的!我们通常所用的互补滤波,是以陀螺为主,加速度计辅助!(短时间内角度和角速度我们相信陀螺,加速计出的角度只是用来消除陀螺的积分误差)

回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-8-13 14:55:27 | 显示全部楼层
拾瑞 发表于 2013-8-13 14:01
我看一下,你的这种算法,是以加速度计为主的!我们通常所用的互补滤波,是以陀螺为主,加速度计辅助!( ...


嗯,你说得对,我也知道111行应该是[pre lang="arduino" line="111"]if(abs(G-1)<=0.03)          //校正[/code]但那样貌似情况更不好了,郁闷
你手里有现成的测试好用的算法吗,发一个我学习学习
回复 支持 反对

使用道具 举报

发表于 2013-8-13 19:54:57 | 显示全部楼层
ShadowWalker 发表于 2013-8-13 12:09
http://www.geek-workshop.com/forum.php?mod=viewthread&tid=1695

那个资料我早就打印了一份,还是外国资料牛,国内简直弱爆了
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊

GMT+8, 2026-6-9 07:24 , Processed in 0.040944 second(s), 19 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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