智能车制作

 找回密码
 注册

扫一扫,访问微社区

查看: 87973|回复: 29
打印 上一主题 下一主题

mpu6050的陀螺仪的角速度换成角度算法

    [复制链接]

5

主题

19

帖子

0

精华

知名人物

Rank: 15Rank: 15Rank: 15Rank: 15Rank: 15

积分
44740
威望
37147
贡献
7523
兑换币
84
注册时间
2014-2-27
在线时间
35 小时
毕业学校
华中科技大学
跳转到指定楼层
1#
发表于 2014-3-18 16:14:52 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
本帖最后由 huster_tjs 于 2014-3-18 14:09 编辑


下面是我的读取陀螺仪数据的程序
/************************陀螺仪计算Y轴的角速度***************/
float Read_Gry(void)
{
   static float angleG;
   int read_gyro_y;
   float Angle_gyro;
   int Gyro_y_offset=0x00;                             
                                       //角速度量程见配置   本处使用2000 deg/s。scal系数为16.4 LSB

        read_gyro_y= GetData(GYRO_YOUT_H)+Gyro_y_offset; //静止时角速度Y轴输出            //Gyro_y_offset计算方法gyro静止时候N多个数据的算术均值        
        Angle_gyro= -(float)read_gyro_y/16.4; //去除零点偏移,计算角速度值,负号为方向处理
        angleG+=Angle_gyro*0.05;                          //角速度积分
        return angleG;
}

下面是测得的图像
怎么回事这个样子呢?,,,程序有什么问题没有?
我不知道时间怎么确定,,那个0.05是估计的,可不可以用调试程序测出两次调用函数时的时间间隔?
黄色是加速度计的,蓝色是陀螺仪的。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

1

主题

8

帖子

0

精华

注册会员

Rank: 2

积分
45
威望
33
贡献
8
兑换币
7
注册时间
2014-5-3
在线时间
2 小时
推荐
发表于 2014-5-3 23:59:03 | 只看该作者
你主控是用什么的,我是第一次做小车用STC12C5A60S2芯片,就是不知道什么什么结合上位机得到数据在生成参数以便在程序中中使用。上位机也不知道什么连接。下面是程序
                                                                  
/***********************************************************************
// 两轮自平衡车最终版控制程序(6轴MPU6050+互补滤波+PWM电机)
// 单片机STC12C5A60S2
// 晶振:20M
// 日期:2012.11.26 - ?
***********************************************************************/

#include <REG52.H>       
#include <math.h>     
#include <stdio.h>   
#include <INTRINS.H>

typedef unsigned char  uchar;
typedef unsigned short ushort;
typedef unsigned int   uint;

//******功能模块头文件*******

#include "DELAY.H"                    //延时头文件
#include "STC_ISP.H"            //程序烧录头文件
#include "SET_SERIAL.H"                //串口头文件
#include "SET_PWM.H"                //PWM头文件
#include "MOTOR.H"                        //电机控制头文件
#include "MPU6050.H"                //MPU6050头文件



//******角度参数************

float Gyro_y;        //Y轴陀螺仪数据暂存
float Angle_gy;      //由角速度计算的倾斜角度
float Accel_x;             //X轴加速度值暂存
float Angle_ax;      //由加速度计算的倾斜角度
float Angle;         //小车最终倾斜角度
uchar value;                 //角度正负极性标记       

//******PWM参数*************

int   speed_mr;                 //右电机转速
int   speed_ml;                 //左电机转速
int   PWM_R;         //右轮PWM值计算
int   PWM_L;         //左轮PWM值计算
float PWM;           //综合PWM计算
float PWMI;                         //PWM积分值

//******电机参数*************

float speed_r_l;        //电机转速
float speed;        //电机转速滤波
float position;            //位移

//******蓝牙遥控参数*************
uchar remote_char;
char  turn_need;
char  speed_need;

//*********************************************************
//定时器100Hz数据更新中断
//*********************************************************

void Init_Timer1(void)        //10毫秒@20MHz,100Hz刷新频率
{
        AUXR &= 0xBF;                //定时器时钟12T模式
        TMOD &= 0x0F;                //设置定时器模式
        TMOD |= 0x10;                //设置定时器模式
        TL1 = 0xE5;                    //设置定时初值
        TH1 = 0xBE;                    //设置定时初值
        TF1 = 0;                    //清除TF1标志
        TR1 = 1;                    //定时器1开始计时
}



//*********************************************************
//中断控制初始化
//*********************************************************

void Init_Interr(void)         
{
        EA = 1;     //开总中断
    EX0 = 1;    //开外部中断INT0
    EX1 = 1;    //开外部中断INT1
    IT0 = 1;    //下降沿触发
    IT1 = 1;    //下降沿触发
        ET1 = 1;    //开定时器1中断
}



//******卡尔曼参数************
               
float code Q_angle=0.001;  
float code Q_gyro=0.003;
float code R_angle=0.5;
float code dt=0.01;                          //dt为kalman滤波器采样时间;
char  code C_0 = 1;
float xdata Q_bias, Angle_err;
float xdata PCt_0, PCt_1, E;
float xdata K_0, K_1, t_0, t_1;
float xdata Pdot[4] ={0,0,0,0};
float xdata PP[2][2] = { { 1, 0 },{ 0, 1 } };

//*********************************************************
// 卡尔曼滤波
//*********************************************************               
//在程序中利用Angle+=(Gyro - Q_bias) * dt计算出陀螺仪积分出的角度,其中Q_bias是陀螺仪偏差。
//此时利用陀螺仪积分求出的Angle相当于系统的估计值,得到系统的观测方程;而加速度计检测的角度Accel相当于系统中的测量值,得到系统状态方程。
//程序中Q_angle和Q_gyro分别表示系统对加速度计及陀螺仪的信任度。根据Pdot = A*P + P*A' + Q_angle计算出先验估计协方差的微分,用于将当前估计值进行线性化处理。其中A为雅克比矩阵。  
//随后计算系统预测角度的协方差矩阵P。计算估计值Accel与预测值Angle间的误差Angle_err。
//计算卡尔曼增益K_0,K_1,K_0用于最优估计值,K_1用于计算最优估计值的偏差并更新协方差矩阵P。
//通过卡尔曼增益计算出最优估计值Angle及预测值偏差Q_bias,此时得到最优角度值Angle及角速度值。


//Kalman滤波,20MHz的处理时间约0.77ms;                       

void Kalman_Filter(float Accel,float Gyro)                  
{
        Angle+=(Gyro - Q_bias) * dt; //先验估计

       
        Pdot[0]=Q_angle - PP[0][1] - PP[1][0]; // Pk-先验估计误差协方差的微分

        Pdot[1]=- PP[1][1];
        Pdot[2]=- PP[1][1];
        Pdot[3]=Q_gyro;
       
        PP[0][0] += Pdot[0] * dt;   // Pk-先验估计误差协方差微分的积分
        PP[0][1] += Pdot[1] * dt;   // =先验估计误差协方差
        PP[1][0] += Pdot[2] * dt;
        PP[1][1] += Pdot[3] * dt;
               
        Angle_err = Accel - Angle;        //zk-先验估计
       
        PCt_0 = C_0 * PP[0][0];
        PCt_1 = C_0 * PP[1][0];
       
        E = R_angle + C_0 * PCt_0;
       
        K_0 = PCt_0 / E;
        K_1 = PCt_1 / E;
       
        t_0 = PCt_0;
        t_1 = C_0 * PP[0][1];

        PP[0][0] -= K_0 * t_0;                 //后验估计误差协方差
        PP[0][1] -= K_0 * t_1;
        PP[1][0] -= K_1 * t_0;
        PP[1][1] -= K_1 * t_1;
               
        Angle        += K_0 * Angle_err;         //后验估计
        Q_bias        += K_1 * Angle_err;         //后验估计
        Gyro_y   = Gyro - Q_bias;         //输出值(后验估计)的微分=角速度

}



//*********************************************************
// 倾角计算(卡尔曼融合)
//*********************************************************

void Angle_Calcu(void)         
{
        //------加速度--------------------------

        //范围为2g时,换算关系:16384 LSB/g
        //角度较小时,x=sinx得到角度(弧度), deg = rad*180/3.14
        //因为x>=sinx,故乘以1.3适当放大

        Accel_x  = GetData(ACCEL_XOUT_H);          //读取X轴加速度
        Angle_ax = (Accel_x - 1100) /16384;   //去除零点偏移,计算得到角度(弧度)
        Angle_ax = Angle_ax*1.2*180/3.14;     //弧度转换为度,


    //-------角速度-------------------------

        //范围为2000deg/s时,换算关系:16.4 LSB/(deg/s)

        Gyro_y = GetData(GYRO_YOUT_H);              //静止时角速度Y轴输出为-30左右
        Gyro_y = -(Gyro_y + 30)/16.4;         //去除零点偏移,计算角速度值,负号为方向处理
        //Angle_gy = Angle_gy + Gyro_y*0.01;  //角速度积分得到倾斜角度.       

       
        //-------卡尔曼滤波融合-----------------------

        Kalman_Filter(Angle_ax,Gyro_y);       //卡尔曼滤波计算倾角


        /*//-------互补滤波-----------------------

        //补偿原理是取当前倾角和加速度获得倾角差值进行放大,然后与
    //陀螺仪角速度叠加后再积分,从而使倾角最跟踪为加速度获得的角度
        //0.5为放大倍数,可调节补偿度;0.01为系统周期10ms       
               
        Angle = Angle + (((Angle_ax-Angle)*0.5 + Gyro_y)*0.01);*/
                                                                                                                          
}  



//*********************************************************
//电机转速和位移值计算
//*********************************************************

void Psn_Calcu(void)         
{
       
        speed_r_l =(speed_mr + speed_ml)*0.5;
        speed *= 0.7;                                  //车轮速度滤波
        speed += speed_r_l*0.3;       
        position += speed;                          //积分得到位移
        position += speed_need;
        if(position<-6000) position = -6000;
        if(position> 6000) position =  6000;

         
}


static float code Kp  = 7.0;       //PID参数
static float code Kd  =0.22;            //PID参数
static float code Kpn = 0.004;      //PID参数
static float code Ksp =0.1;            //PID参数

//*********************************************************
//电机PWM值计算
//*********************************************************

void PWM_Calcu(void)         
{
   
        if(Angle<-40||Angle>40)               //角度过大,关闭电机
        {  
          CCAP0H = 0;
      CCAP1H = 0;
          return;
        }
        PWM  = Kp*Angle + Kd*Gyro_y;          //PID:角速度和角度
        PWM += Kpn*position + Ksp*speed;      //PID:速度和位置
        PWM_R = PWM + turn_need;
        PWM_L = PWM - turn_need;
        PWM_Motor(PWM_L,PWM_R);
         
}




//*********************************************************
//手机蓝牙遥控
//*********************************************************

void Bluetooth_Remote(void)         
{

        remote_char = receive_char();                                   //接收蓝牙串口数据

        if(remote_char ==0x02) speed_need = -80;           //前进
        else if(remote_char ==0x01) speed_need = 80;   //后退
             else speed_need = 0;                                           //不动

    if(remote_char ==0x03) turn_need = 15;                   //左转
        else if(remote_char ==0x04) turn_need = -15;   //右转
             else turn_need = 0;                                           //不转
         
}


/*=================================================================================*/

//*********************************************************
//main
//*********************************************************
void main()
{

        delaynms(500);           //上电延时
        Init_PWM();               //PWM初始化
    Init_Timer0();     //初始化定时器0,作为PWM时钟源
        Init_Timer1();     //初始化定时器1
        Init_Interr();     //中断初始化
        Init_Motor();           //电机控制初始化
        Init_BRT();                   //串口初始化(独立波特率)
        InitMPU6050();     //初始化MPU6050
        delaynms(500);           

        while(1)
        {
          
         Bluetooth_Remote();

        }
}


/*=================================================================================*/

//********timer1中断***********************

void Timer1_Update(void) interrupt 3
{
  
   TL1 = 0xE5;                    //设置定时初值10MS
   TH1 = 0xBE;
   
   //STC_ISP();                    //程序下载
   Angle_Calcu();                  //倾角计算
   Psn_Calcu();                    //电机位移计算
   PWM_Calcu();                    //计算PWM值
   
   speed_mr = speed_ml = 0;         

}


//********右电机中断***********************

void INT_L(void) interrupt 0
{

   if(SPDL == 1)  { speed_ml++; }                 //左电机前进
   else                      { speed_ml--; }                 //左电机后退
   LED = ~LED;

}


//********左电机中断***********************

void INT_R(void) interrupt 2
{

   if(SPDR == 1)  { speed_mr++; }                 //右电机前进
   else                      { speed_mr--; }                 //右电机后退
   LED = ~LED;

}



回复 支持 1 反对 0

使用道具 举报

5

主题

57

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1664

优秀会员奖章活跃会员奖章

威望
821
贡献
539
兑换币
542
注册时间
2016-7-24
在线时间
152 小时
30#
发表于 2017-1-17 22:58:12 | 只看该作者
疯狂土豆儿 发表于 2016-8-15 18:39
我在做平衡小车,在卡尔曼滤波计算出倾角之后我再进行PID调节的时候,因为在PID调节函数里面加上了if(Ang ...

我跟你一样的 请问你的问题解决没有

回复 支持 反对

使用道具 举报

2

主题

15

帖子

0

精华

注册会员

Rank: 2

积分
124
威望
72
贡献
34
兑换币
33
注册时间
2016-8-8
在线时间
9 小时
毕业学校
北方工业大学
29#
发表于 2016-8-16 14:03:30 | 只看该作者
黄施泓 发表于 2016-8-15 22:28
嘻嘻加QQ交流893601353.答案是我的ID

好的~~谢谢
回复 支持 反对

使用道具 举报

0

主题

36

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1328
威望
596
贡献
384
兑换币
393
注册时间
2015-12-22
在线时间
174 小时
28#
发表于 2016-8-15 22:28:05 | 只看该作者
疯狂土豆儿 发表于 2016-8-15 18:39
我在做平衡小车,在卡尔曼滤波计算出倾角之后我再进行PID调节的时候,因为在PID调节函数里面加上了if(Ang ...

嘻嘻加QQ交流893601353.答案是我的ID
回复 支持 反对

使用道具 举报

2

主题

15

帖子

0

精华

注册会员

Rank: 2

积分
124
威望
72
贡献
34
兑换币
33
注册时间
2016-8-8
在线时间
9 小时
毕业学校
北方工业大学
27#
发表于 2016-8-15 18:39:59 | 只看该作者
黄施泓 发表于 2016-8-9 11:20
上图才好说话。你滤完波回来16位数据有归一化成90度吗?

我在做平衡小车,在卡尔曼滤波计算出倾角之后我再进行PID调节的时候,因为在PID调节函数里面加上了if(Angle>-3.0&&Angle<3.0){Angle=0.0;}然后发现倾角在我缓慢变化至3度后,刚过3度时倾角会突然猛的增加,然后减小最后稳定在正常值上,如果我不加这句话,倾角变化一直正常,百思不得其解,希望有大神能帮帮我。。。。
另外,卡尔曼滤波和速度PID控制我都是写在中断里的,周期5msPID参数我暂时只加了一个P调节,其他均为零。
//******卡尔曼参数************
                  
const float Q_angle=0.001;  
const float Q_gyro=0.003;
const float R_angle=0.5;
const float dt=0.07;                           //dtkalman滤波器采样时间;0.005,0.07
const char C_0 = 1;
float Q_bias=0.0, Angle_err=0.0;
float PCt_0=0, PCt_1=0, E=0;
float K_0=0, K_1=0, t_0=0, t_1=0;
float Pdot[4] ={0,0,0,0};
float PP[2][2] = { { 1, 0 },{ 0, 1 } };
float position;
static const float Kp  = 40.0;                             //PID参数  Angle  
static const float Kd  = 0.0;                                         //PID参数  Gyro_y  
static const float Ksp = 0.0;                                 //PID参数  motor_speed  
static const float Ksi = 0.0;                                  //PID参数    position         
  
/*****************卡尔曼滤波**************************************************/
void Kalman_Filter(float Accel,float Gyro)               
{
         Angle+=(Gyro- Q_bias) * dt; //先验估计
         
         Pdot[0]=Q_angle- PP[0][1] - PP[1][0]; // Pk-先验估计误差协方差的微分
         Pdot[1]=-PP[1][1];
         Pdot[2]=-PP[1][1];
         Pdot[3]=Q_gyro;
         
         PP[0][0]+= Pdot[0] * dt;   // Pk-先验估计误差协方差微分的积分
         PP[0][1]+= Pdot[1] * dt;   // =先验估计误差协方差
         PP[1][0]+= Pdot[2] * dt;
         PP[1][1]+= Pdot[3] * dt;
         
         Angle_err= Accel - Angle;        //zk-先验估计
         
         PCt_0= C_0 * PP[0][0];
         PCt_1= C_0 * PP[1][0];
         
         E= R_angle + C_0 * PCt_0;
         
         K_0= PCt_0 / E;
         K_1= PCt_1 / E;
         
         t_0= PCt_0;
         t_1= C_0 * PP[0][1];
         PP[0][0]-= K_0 * t_0;                  //后验估计误差协方差
         PP[0][1]-= K_0 * t_1;
         PP[1][0]-= K_1 * t_0;
         PP[1][1]-= K_1 * t_1;
                  
         Angle        += K_0 * Angle_err;           //后验估计
         Q_bias      += K_1 * Angle_err;           //后验估计
         Gyro_y   = Gyro - Q_bias;       //输出值(后验估计)的微分=角速度
}
void Angle_Calculate(void)
{
/****************************加速度****************************************/
         
         Accel_x  = MPU6050_Real_Data.Accel_X;           //读取X轴加速度
         Angle_ax= Accel_x*1.2*180/3.14;     //弧度转换为度
  
/****************************角速度****************************************/
         
          Gyro_y = MPU6050_Real_Data.Gyro_Y;            
   Angle_gy += (Gyro_y)*0.003;
         
/***************************卡尔曼融合*************************************/
         Kalman_Filter(Angle_ax,Angle_gy);       //卡尔曼滤波计算倾角
         
}
void Speed_Pid_Calculate(void)
{
           if(Angle>-3.0&&Angle<3.0){Angle=0.0;}
                  
                   Speed_control  = (Kp*Angle + Kd*Gyro_y);            //PID:角速度和角度调节
                 Speed_control +=(Ksp*motor_speed + Ksi*position);   
                  
                   //PID:车速度调节
                  
           speed_control_l= (int)Speed_control ;            //左轮速度
                   speed_control_r= (int)- Speed_control;    //右轮速度
                  
                   if(speed_control_l> MAX_SPEED) speed_control_l = MAX_SPEED;
                   if(speed_control_l< -MAX_SPEED) speed_control_l = -MAX_SPEED;
                   if(speed_control_r> MAX_SPEED) speed_control_r = MAX_SPEED;
                   if(speed_control_r< -MAX_SPEED) speed_control_r = -MAX_SPEED;
}

回复 支持 反对

使用道具 举报

2

主题

15

帖子

0

精华

注册会员

Rank: 2

积分
124
威望
72
贡献
34
兑换币
33
注册时间
2016-8-8
在线时间
9 小时
毕业学校
北方工业大学
26#
发表于 2016-8-15 18:39:36 | 只看该作者
我在做平衡小车,在卡尔曼滤波计算出倾角之后我再进行PID调节的时候,因为在PID调节函数里面加上了if(Angle>-3.0&&Angle<3.0){Angle=0.0;}然后发现倾角在我缓慢变化至3度后,刚过3度时倾角会突然猛的增加,然后减小最后稳定在正常值上,如果我不加这句话,倾角变化一直正常,百思不得其解,希望有大神能帮帮我。。。。
另外,卡尔曼滤波和速度PID控制我都是写在中断里的,周期5msPID参数我暂时只加了一个P调节,其他均为零。
//******卡尔曼参数************
                  
const float Q_angle=0.001;  
const float Q_gyro=0.003;
const float R_angle=0.5;
const float dt=0.07;                           //dtkalman滤波器采样时间;0.005,0.07
const char C_0 = 1;
float Q_bias=0.0, Angle_err=0.0;
float PCt_0=0, PCt_1=0, E=0;
float K_0=0, K_1=0, t_0=0, t_1=0;
float Pdot[4] ={0,0,0,0};
float PP[2][2] = { { 1, 0 },{ 0, 1 } };
float position;
static const float Kp  = 40.0;                             //PID参数  Angle  
static const float Kd  = 0.0;                                         //PID参数  Gyro_y  
static const float Ksp = 0.0;                                 //PID参数  motor_speed  
static const float Ksi = 0.0;                                  //PID参数    position         
  
/*****************卡尔曼滤波**************************************************/
void Kalman_Filter(float Accel,float Gyro)               
{
         Angle+=(Gyro- Q_bias) * dt; //先验估计
         
         Pdot[0]=Q_angle- PP[0][1] - PP[1][0]; // Pk-先验估计误差协方差的微分
         Pdot[1]=-PP[1][1];
         Pdot[2]=-PP[1][1];
         Pdot[3]=Q_gyro;
         
         PP[0][0]+= Pdot[0] * dt;   // Pk-先验估计误差协方差微分的积分
         PP[0][1]+= Pdot[1] * dt;   // =先验估计误差协方差
         PP[1][0]+= Pdot[2] * dt;
         PP[1][1]+= Pdot[3] * dt;
         
         Angle_err= Accel - Angle;        //zk-先验估计
         
         PCt_0= C_0 * PP[0][0];
         PCt_1= C_0 * PP[1][0];
         
         E= R_angle + C_0 * PCt_0;
         
         K_0= PCt_0 / E;
         K_1= PCt_1 / E;
         
         t_0= PCt_0;
         t_1= C_0 * PP[0][1];
         PP[0][0]-= K_0 * t_0;                  //后验估计误差协方差
         PP[0][1]-= K_0 * t_1;
         PP[1][0]-= K_1 * t_0;
         PP[1][1]-= K_1 * t_1;
                  
         Angle        += K_0 * Angle_err;           //后验估计
         Q_bias      += K_1 * Angle_err;           //后验估计
         Gyro_y   = Gyro - Q_bias;       //输出值(后验估计)的微分=角速度
}
void Angle_Calculate(void)
{
/****************************加速度****************************************/
         
         Accel_x  = MPU6050_Real_Data.Accel_X;           //读取X轴加速度
         Angle_ax= Accel_x*1.2*180/3.14;     //弧度转换为度
  
/****************************角速度****************************************/
         
          Gyro_y = MPU6050_Real_Data.Gyro_Y;            
   Angle_gy += (Gyro_y)*0.003;
         
/***************************卡尔曼融合*************************************/
         Kalman_Filter(Angle_ax,Angle_gy);       //卡尔曼滤波计算倾角
         
}
void Speed_Pid_Calculate(void)
{
           if(Angle>-3.0&&Angle<3.0){Angle=0.0;}
                  
                   Speed_control  = (Kp*Angle + Kd*Gyro_y);            //PID:角速度和角度调节
                 Speed_control +=(Ksp*motor_speed + Ksi*position);   
                  
                   //PID:车速度调节
                  
           speed_control_l= (int)Speed_control ;            //左轮速度
                   speed_control_r= (int)- Speed_control;    //右轮速度
                  
                   if(speed_control_l> MAX_SPEED) speed_control_l = MAX_SPEED;
                   if(speed_control_l< -MAX_SPEED) speed_control_l = -MAX_SPEED;
                   if(speed_control_r> MAX_SPEED) speed_control_r = MAX_SPEED;
                   if(speed_control_r< -MAX_SPEED) speed_control_r = -MAX_SPEED;
}
回复 支持 反对

使用道具 举报

2

主题

15

帖子

0

精华

注册会员

Rank: 2

积分
124
威望
72
贡献
34
兑换币
33
注册时间
2016-8-8
在线时间
9 小时
毕业学校
北方工业大学
25#
发表于 2016-8-10 13:11:47 | 只看该作者
人呢?!!!求助啊,help
回复 支持 反对

使用道具 举报

2

主题

15

帖子

0

精华

注册会员

Rank: 2

积分
124
威望
72
贡献
34
兑换币
33
注册时间
2016-8-8
在线时间
9 小时
毕业学校
北方工业大学
24#
发表于 2016-8-9 18:13:12 | 只看该作者
疯狂土豆儿 发表于 2016-8-9 16:17
我是想做一个自平衡车,用卡尔曼滤波完了之后得到的就是角度啊,16位数据是什么啊?不太懂

************ ...

现在情况就是,就算我是在减小倾角,只要我快速地改变,它显示的倾角都会先增大再减小,而如果我慢速改变的话,倾角就会缓慢减小而不会出现那些增大的角
回复 支持 反对

使用道具 举报

2

主题

15

帖子

0

精华

注册会员

Rank: 2

积分
124
威望
72
贡献
34
兑换币
33
注册时间
2016-8-8
在线时间
9 小时
毕业学校
北方工业大学
23#
发表于 2016-8-9 16:17:09 | 只看该作者
我是想做一个自平衡车,用卡尔曼滤波完了之后得到的就是角度啊,16位数据是什么啊?不太懂

*************读取数据********************
//定义MPU6050内部地址
#define        SMPLRT_DIV                0x19        //陀螺仪采样率 典型值 0X07 125Hz
#define        CONFIG                          0x1A        //低通滤波频率 典型值 0x00
#define        GYRO_CONFIG                0x1B        //陀螺仪自检及测量范围                 典型值 0x18 不自检 2000deg/s
#define        ACCEL_CONFIG        0x1C        //加速度计自检及测量范围及高通滤波频率 典型值 0x01 不自检 2G 5Hz
#define INT_PIN_CFG     0x37
#define INT_ENABLE      0x38
#define INT_STATUS      0x3A    //只读
#define        ACCEL_XOUT_H        0x3B
#define        ACCEL_XOUT_L        0x3C
#define        ACCEL_YOUT_H        0x3D
#define        ACCEL_YOUT_L        0x3E
#define        ACCEL_ZOUT_H        0x3F
#define        ACCEL_ZOUT_L        0x40
#define        TEMP_OUT_H                0x41
#define        TEMP_OUT_L                0x42
#define        GYRO_XOUT_H    0x43
#define        GYRO_XOUT_L                0x44       
#define        GYRO_YOUT_H        0x45
#define        GYRO_YOUT_L                0x46
#define        GYRO_ZOUT_H        0x47
#define        GYRO_ZOUT_L                0x48

//读取寄存器原生数据
           
        MPU6050_Raw_Data.Accel_X = (buf[0]<<8 | buf[1]);
        MPU6050_Raw_Data.Accel_Y = (buf[2]<<8 | buf[3]);
        MPU6050_Raw_Data.Accel_Z = (buf[4]<<8 | buf[5]);
        MPU6050_Raw_Data.Temp =    (buf[6]<<8 | buf[7]);  
        MPU6050_Raw_Data.Gyro_X = (buf[8]<<8 | buf[9]);
        MPU6050_Raw_Data.Gyro_Y = (buf[10]<<8 | buf[11]);
        MPU6050_Raw_Data.Gyro_Z = (buf[12]<<8 | buf[13]);
      
      
        //将原生数据转换为实际值,计算公式跟寄存器的配置有关
        MPU6050_Real_Data.Accel_X = -(float)(MPU6050_Raw_Data.Accel_X)/8192.0;
        MPU6050_Real_Data.Accel_Y = -(float)(MPU6050_Raw_Data.Accel_Y)/8192.0;
        MPU6050_Real_Data.Accel_Z = (float)(MPU6050_Raw_Data.Accel_Z)/8192.0;
              MPU6050_Real_Data.Gyro_X=-(float)(MPU6050_Raw_Data.Gyro_X - gyroADC_X_offset)/65.5;   
        MPU6050_Real_Data.Gyro_Y=-(float)(MPU6050_Raw_Data.Gyro_Y - gyroADC_Y_offset)/65.5;   
        MPU6050_Real_Data.Gyro_Z=(float)(MPU6050_Raw_Data.Gyro_Z - gyroADC_Z_offset)/65.5;   
    }
   


//******卡尔曼参数************
               
const float Q_angle=0.001;  
const float Q_gyro=0.003;
const float R_angle=0.5;
const float dt=0.01;                          //dt为kalman滤波器采样时间;
const char  C_0 = 1;
float Q_bias, Angle_err;
float PCt_0, PCt_1, E;
float K_0, K_1, t_0, t_1;
float Pdot[4] ={0,0,0,0};
float PP[2][2] = { { 1, 0 },{ 0, 1 } };

/*****************卡尔曼滤波**************************************************/
void Kalman_Filter(float Accel,float Gyro)               
{
        Angle+=(Gyro - Q_bias) * dt; //先验估计
       
        Pdot[0]=Q_angle - PP[0][1] - PP[1][0]; // Pk-先验估计误差协方差的微分

        Pdot[1]= -PP[1][1];
        Pdot[2]= -PP[1][1];
        Pdot[3]=Q_gyro;
       
        PP[0][0] += Pdot[0] * dt;   // Pk-先验估计误差协方差微分的积分
        PP[0][1] += Pdot[1] * dt;   // =先验估计误差协方差
        PP[1][0] += Pdot[2] * dt;
        PP[1][1] += Pdot[3] * dt;
               
        Angle_err = Accel - Angle;        //zk-先验估计
       
        PCt_0 = C_0 * PP[0][0];
        PCt_1 = C_0 * PP[1][0];
       
        E = R_angle + C_0 * PCt_0;
       
        K_0 = PCt_0 / E;
        K_1 = PCt_1 / E;
       
        t_0 = PCt_0;
        t_1 = C_0 * PP[0][1];

        PP[0][0] -= K_0 * t_0;                 //后验估计误差协方差
        PP[0][1] -= K_0 * t_1;
        PP[1][0] -= K_1 * t_0;
        PP[1][1] -= K_1 * t_1;
               
        Angle        += K_0 * Angle_err;         //后验估计
        Q_bias        += K_1 * Angle_err;         //后验估计
        Gyro_y   = Gyro - Q_bias;         //输出值(后验估计)的微分=角速度

}

******************倾角计算*****************
void Angle_Calculate(void)
{

/****************************加速度****************************************/
       
        Accel_x  =  MPU6050_Real_Data.Accel_X;          //读取X轴加速度
        Angle_ax = Accel_x*1.2*180/3.14;     //弧度转换为度

/****************************角速度****************************************/
       
         Gyro_y = MPU6050_Real_Data.Gyro_Y;             
时间dt,所以此处不用积分
/***************************卡尔曼融合*************************************/
        Kalman_Filter(Angle_ax,Gyro_y);       //卡尔曼滤波计算倾角
       
回复 支持 反对

使用道具 举报

0

主题

36

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1328
威望
596
贡献
384
兑换币
393
注册时间
2015-12-22
在线时间
174 小时
22#
发表于 2016-8-9 11:20:47 | 只看该作者
疯狂土豆儿 发表于 2016-8-8 21:00
楼主,我用卡尔曼滤波了烧完程序后发现,我快速改变板子的倾角时得到的角度数值很大,比如变化10度时,如 ...

上图才好说话。你滤完波回来16位数据有归一化成90度吗?
回复 支持 反对

使用道具 举报

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

本版积分规则

关于我们|联系我们|小黑屋|智能车制作 ( 黑ICP备2022002344号

GMT+8, 2024-9-28 02:16 , Processed in 0.165151 second(s), 33 queries , Gzip On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

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