打印
[STM32F1]

mpu6050卡尔曼滤波

[复制链接]
104|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
mnynt121|  楼主 | 2025-3-24 07:05 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
#include "kalman.h"
#include "mpu6050.h"
#include "math.h"


short aacx,aacy,aacz;                /*加速度传感器原始数据*/
short gyrox,gyroy,gyroz;        /*陀螺仪原始数据*/
short temperature;                        /*陀螺仪温度数据*/
float Accel_x;                             /*X轴加速度值暂存*/
float Accel_y;                            /*Y轴加速度值暂存*/
float Accel_z;                             /*Z轴加速度值暂存*/
float Gyro_x;                                /*X轴陀螺仪数据暂存*/
float Gyro_y;                        /*Y轴陀螺仪数据暂存*/
float Gyro_z;                                 /*Z轴陀螺仪数据暂存*/
float Angle_x_temp;                  /*由加速度计算的x倾斜角度*/
float Angle_y_temp;                  /*由加速度计算的y倾斜角度*/
float Angle_X_Final;                 /*X最终倾斜角度*/
float Angle_Y_Final;                 /*Y最终倾斜角度*/

/**
  * [url=home.php?mod=space&uid=247401]@brief[/url]  读取数据预处理
  *         
  * @param  NULL
  *
  * @retval NULL
  */
void Angle_Calcu(void)         
{
        /*1.原始数据读取*/
        float accx,accy,accz;                                                /*三方向角加速度值*/
        MPU_Get_Accelerometer(&aacx,&aacy,&aacz);        /*得到加速度传感器数据*/
        MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz);        /*得到陀螺仪数据*/
        temperature = MPU_Get_Temperature();                /*得到温度值*/
        Accel_x = aacx;
        Accel_y = aacy;
        Accel_z = aacz;
        Gyro_x  = gyrox;
        Gyro_y  = gyroy;
        Gyro_z  = gyroz;
        
        /*2.角加速度原始值处理过程*/        
        /*加速度传感器配置寄存器0X1C内写入0x01,设置范围为±2g。换算关系:2^16/4 = 16384LSB/g*/
        if(Accel_x<32764) accx=Accel_x/16384;
        else              accx=1-(Accel_x-49152)/16384;
        if(Accel_y<32764) accy=Accel_y/16384;
        else              accy=1-(Accel_y-49152)/16384;
        if(Accel_z<32764) accz=Accel_z/16384;
        else              accz=(Accel_z-49152)/16384;
        /*加速度反正切公式计算三个轴和水平面坐标系之间的夹角*/
        Angle_x_temp=(atan(accy/accz))*180/3.14;
        Angle_y_temp=(atan(accx/accz))*180/3.14;
        /*判断计算后角度的正负号*/                                                                                       
        if(Accel_x<32764) Angle_y_temp = +Angle_y_temp;
        if(Accel_x>32764) Angle_y_temp = -Angle_y_temp;
        if(Accel_y<32764) Angle_x_temp = +Angle_x_temp;
        if(Accel_y>32764) Angle_x_temp = -Angle_x_temp;
        
        /*3.角速度原始值处理过程*/
        /*陀螺仪配置寄存器0X1B内写入0x18,设置范围为±2000deg/s。换算关系:2^16/4000=16.4LSB/(°/S)*/
        /*计算角速度*/
        if(Gyro_x<32768) Gyro_x=-(Gyro_x/16.4);
        if(Gyro_x>32768) Gyro_x=+(65535-Gyro_x)/16.4;
        if(Gyro_y<32768) Gyro_y=-(Gyro_y/16.4);
        if(Gyro_y>32768) Gyro_y=+(65535-Gyro_y)/16.4;
        if(Gyro_z<32768) Gyro_z=-(Gyro_z/16.4);
        if(Gyro_z>32768) Gyro_z=+(65535-Gyro_z)/16.4;
        
        /*4.调用卡尔曼函数*/
        Kalman_Filter_X(Angle_x_temp,Gyro_x);  /*卡尔曼滤波计算X倾角*/
        Kalman_Filter_Y(Angle_y_temp,Gyro_y);  /*卡尔曼滤波计算Y倾角*/                                                                                                                          
}


/************************ 卡尔曼参数 ****************************/               
float Q_angle = 0.001;                /*角度数据置信度,角度噪声的协方差*/
float Q_gyro  = 0.003;                /*角速度数据置信度,角速度噪声的协方差*/
float R_angle = 0.5;                /*加速度计测量噪声的协方差*/
float dt      = 0.02;                /*滤波算法计算周期,由定时器定时20ms*/
char  C_0     = 1;                        /*H矩阵值*/
float Q_bias, Angle_err;        /*Q_bias:陀螺仪的偏差  Angle_err:角度偏量*/
float PCt_0, PCt_1, E;                /*计算的过程量*/
float K_0, K_1, t_0, t_1;        /*卡尔曼增益  K_0:用于计算最优估计值  K_1:用于计算最优估计值的偏差 t_0/1:中间变量*/
float P[4] ={0,0,0,0};                /*过程协方差矩阵的微分矩阵,中间变量*/
float PP[2][2] = { { 1, 0 },{ 0, 1 } };/*过程协方差矩阵P*/

/**
  * @brief  卡尔曼函数
  *         
  * @param  Accel
  * @param  Gyro
  *
  * @retval NULL
  */
void Kalman_Filter_X(float Accel,float Gyro)               
{
        /*
                步骤一,先验估计
                公式:X(k|k-1) = AX(k-1|k-1) + BU(k)
                X = (Angle,Q_bias)
                A(1,1) = 1,A(1,2) = -dt
                A(2,1) = 0,A(2,2) = 1
        */        
        Angle_X_Final += (Gyro - Q_bias) * dt;         /*状态方程,角度值等于上次最优角度加角速度减零漂后积分*/
        
        /*
                步骤二,计算过程协方差矩阵的微分矩阵
                公式:P(k|k-1)=AP(k-1|k-1)A^T + Q
                Q(1,1) = cov(Angle,Angle)        Q(1,2) = cov(Q_bias,Angle)
                Q(2,1) = cov(Angle,Q_bias)        Q(2,2) = cov(Q_bias,Q_bias)
        */
        P[0]= Q_angle - PP[0][1] - PP[1][0];
        P[1]= -PP[1][1];                                                /*先验估计误差协方差*/
        P[2]= -PP[1][1];
        P[3]= Q_gyro;
        PP[0][0] += P[0] * dt;   
        PP[0][1] += P[1] * dt;   
        PP[1][0] += P[2] * dt;
        PP[1][1] += P[3] * dt;        
        
        /*
                步骤三,计算卡尔曼增益
                公式:Kg(k)= P(k|k-1)H^T/(HP(k|k-1)H^T+R)
                Kg = (K_0,K_1) 对应Angle,Q_bias增益
                H = (1,0)        可由z=HX+v求出z:Accel
        */
        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;
        
        /*
                步骤四,后验估计误差协方差
                公式:P(k|k)=(I-Kg(k)H)P(k|k-1)
                也可写为:P(k|k)=P(k|k-1)-Kg(k)HP(k|k-1)
        */
        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;
        
        /*
                步骤五,计算最优角速度值
                公式:X(k|k)= X(k|k-1)+Kg(k)(Z(k)-X(k|k-1))
        */
        Angle_err = Accel - Angle_X_Final;                /*Z(k)先验估计 计算角度偏差*/
        Angle_X_Final += K_0 * Angle_err;                 /*后验估计,给出最优估计值*/
        Q_bias        += K_1 * Angle_err;                 /*后验估计,跟新最优估计值偏差*/
        Gyro_x         = Gyro - Q_bias;         
}

void Kalman_Filter_Y(float Accel,float Gyro)                 
{
        Angle_Y_Final += (Gyro - Q_bias) * dt;
        P[0]=Q_angle - PP[0][1] - PP[1][0];
        P[1]=-PP[1][1];
        P[2]=-PP[1][1];
        P[3]=Q_gyro;        
        PP[0][0] += P[0] * dt;
        PP[0][1] += P[1] * dt;  
        PP[1][0] += P[2] * dt;
        PP[1][1] += P[3] * dt;        
        Angle_err = Accel - Angle_Y_Final;               
        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_Y_Final        += K_0 * Angle_err;
        Q_bias        += K_1 * Angle_err;         
        Gyro_y   = Gyro - Q_bias;         
}

复制代码


/**
  ******************************************************************************
  * [url=home.php?mod=space&uid=288409]@file[/url]    main.c
  * [url=home.php?mod=space&uid=187600]@author[/url]  
  * [url=home.php?mod=space&uid=895143]@version[/url] V1.0
  * [url=home.php?mod=space&uid=212281]@date[/url]    2023-4-7
  * @brief   MPU6050陀螺仪数据解算(卡尔曼滤波)
  ******************************************************************************
  *
  *
  *
  ******************************************************************************
  */
#include "main.h"
/**
  * @brief  主函数
  * @param  无
  * @retval 无
  */
int main(void)
{        
        SYS_Init();
        while(1)
        {               
                /*MPU6050数据上报*/
                DATA_Report();
        }
}
/**
  * @brief  系统初始化总函数
  * @param  无
  * @retval 无
  */
void SYS_Init(void)
{
        delay_init();  
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
        uart_init(115200);
        LED_Init();
        MPU_Init();
        /*10Khz的计数频率,计数到200为20ms*/
        TIM4_Int_Init(199,7199);
}
/**
  * @brief  MPU6050数据上报
  * @param  无
  * @retval 无
  */
void DATA_Report(void)
{
        /*串口发送实时俯仰角,横滚角,XYZ三轴角加速度原始值,XYZ三轴角速度原始值*/
        printf("俯仰角:%.4f 横滚角:%.4f \
        X加速度:%5d y加速度:%5d z加速度:%5d \
        x速度:%5d y速度:%5d z速度:%5d\r\n",\
        Angle_X_Final,Angle_Y_Final,aacx,aacy,aacz,\
        gyrox,gyroy,gyroz);
        
        
}


使用特权

评论回复
沙发
lidi911| | 2025-3-24 07:38 | 只看该作者
MPU6050堪称MEMS六轴传感器的经典了,10多年前就在用了。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

28

主题

3171

帖子

2

粉丝