在线客服
服务投诉电话:0755-29469758
请稍候...
当前位置:深圳市中广芯源科技有限公司-中国的芯源 > 新闻资讯 > 行业资讯 >
新闻资讯
行业资讯
mpu6050的陀螺仪的角速度换成角度算法 软件设计要点指南
来源: 未知 发布时间: 2017-03-20 浏览次数:101
下面是我的读取陀螺仪数据的程序
/************************陀螺仪计算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是估计的,可不可以用调试程序测出两次调用函数时的时间间隔?
黄色是加速度计的,蓝色是陀螺仪的。
 
 
/***********************************************************************
// 两轮自平衡车最终版控制程序(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;
 
我是想做一个自平衡车,用卡尔曼滤波完了之后得到的就是角度啊,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);       //卡尔曼滤波计算倾角
        
我在做平衡小车,在卡尔曼滤波计算出倾角之后我再进行PID调节的时候,因为在PID调节函数里面加上了if(Angle>-3.0&&Angle<3.0){Angle=0.0;},然后发现倾角在我缓慢变化至3度后,刚过3度时倾角会突然猛的增加,然后减小最后稳定在正常值上,如果我不加这句话,倾角变化一直正常,百思不得其解,希望有大神能帮帮我。。。。
另外,卡尔曼滤波和速度PID控制我都是写在中断里的,周期5ms,PID参数我暂时只加了一个P调节,其他均为零。
//******卡尔曼参数************
                  
const float Q_angle=0.001;  
const float Q_gyro=0.003;
const float R_angle=0.5;
const float dt=0.07;                           //dt为kalman滤波器采样时间;或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;
 
 

返回

代理品牌
中广芯源-专业国产电源ic|大电流升压IC|同步整流IC|大功率降压芯片|马达驱动|以太网控制器|存储器|ESD抑制器|红外传感器|自恢复保险丝|压敏电阻|音频放大|霍尔开关|USB检测芯片|碳化硅二极管|编码器|时钟振荡器|光电器件|IGBT|单片机|法拉电容|模拟开关|快充方案|功放芯片|肖特基|场效应管|锂电充电芯片|LED驱动IC|触摸芯片|集成电路全供应链服务商! Copyright @ 2014-2020 本站技术文章和产品资讯未经许可不得复制镜像和转载,违者必究! 版权所有 深圳市中广芯源科技有限公司. All Rights reserved     旗下网站:国芯网粤ICP 申请中