平衡小车卡尔曼滤波算法

news/2025/3/19 16:05:22/

最近研究STM32的自平衡小车,发现有两座必过的大山,一为卡尔曼滤波,二为PID算法。
网上看了很多关于卡尔曼滤波的代码,感觉写得真不咋地。一怒之下,自己重写,不废话,贴代码



[pre lang="C" line="1" file="kalman.h"]/**
  ******************************************************************************
  * @file    kalman.h
  * @author  willieon
  * @version V0.1
  * @date    January-2015
  * @brief   卡尔曼滤波算法 
  *        
  *
  ******************************************************************************
  * @attention
  *本人对卡尔曼的粗略理解:以本次测量角速度(陀螺仪测量值)的积分得出的角度值
  * 与上次最优角度值的方差产生一个权重来衡量本次测量角度(加速度测量值)
  * 与上次最优角度值,从而产生新的最优角度值。好吧,比较拗口,有误处忘指正。
  *
  ******************************************************************************
  */

#ifndef __KALMAN_H__
#define __KALMAN_H__


#define Q_angle                        0.001        角度过程噪声的协方差
#define Q_gyro                        0.003        角速度过程噪声的协方差
#define R_angle                        0.5                测量噪声的协方差(即是测量偏差)
#define dt                                0.01                        卡尔曼滤波采样频率
#define C_0                                1

/**************卡尔曼运算变量定义**********************
*
***由于卡尔曼为递推运算,结构体需定义为全局变量
***在实际运用中只需定义一个KalmanCountData类型的变量即可
***无需用户定义多个中间变量,简化函数的使用
*/
typedef struct
{
        float                                Q_bias;                最优估计值的偏差,即估计出来的陀螺仪的漂移量
        float                                Angle_err;                实测角度与陀螺仪积分角度的差值
        float                                PCt_0;                                
        float                                PCt_1; 
        float                                E;                        计算的过程量
        float                                K_0;                        含有卡尔曼增益的另外一个函数,用于计算最优估计值
        float                                K_1;                        含有卡尔曼增益的函数,用于计算最优估计值的偏差
        float                                t_0;                                
        float                                t_1;
        float                                Pdot[4];                Pdot[4] = {0,0,0,0};过程协方差矩阵的微分矩阵
        float                                PP[2][2];                PP[2][2] = { { 1, 0 },{ 0, 1 } };协方差(covariance)
        float                                Angle_Final;        后验估计最优角度值(即系统处理最终值)
        float                                Gyro_Final;        后验估计最优角速度值

}KalmanCountData;

void Kalman_Filter(float Accel,        float Gyro ,KalmanCountData * Kalman_Struct);
void Kalman_Filter_Init(KalmanCountData * Kalman_Struct);



#endif

[/pre]

kalman.c

[pre lang="C" line="1"  file="kalman.c"]
#include "kalman.h"


/**
  ******************************************************************************
  * @file    void Kalman_Filter_Init(KalmanCountData * Kalman_Struct)
  * @author  willieon
  * @version V0.1
  * @date    January-2015
  * @brief   卡尔曼滤波计算中间量初始化
  *        
  *
  ******************************************************************************
  * @attention
  *
  * 
  * 
  *
  ******************************************************************************
  */

void Kalman_Filter_Init(KalmanCountData * Kalman_Struct)
{
        Kalman_Struct -> Angle_err                 = 0;
        Kalman_Struct -> Q_bias                         = 0;
        Kalman_Struct -> PCt_0                         = 0;
        Kalman_Struct -> PCt_1                         = 0;
        Kalman_Struct -> E                                 = 0;
        Kalman_Struct -> K_0                         = 0;
        Kalman_Struct -> K_1                         = 0;
        Kalman_Struct -> t_0                         = 0;
        Kalman_Struct -> t_1                         = 0;
        Kalman_Struct -> Pdot[0]                 = 0;
        Kalman_Struct -> Pdot[1]                 = 0;
        Kalman_Struct -> Pdot[2]                 = 0;
        Kalman_Struct -> Pdot[3]                 = 0;        
        Kalman_Struct -> PP[0][0]                 = 1;
        Kalman_Struct -> PP[0][1]                 = 0;
        Kalman_Struct -> PP[1][0]                 = 0;
        Kalman_Struct -> PP[1][1]                 = 1;        
        Kalman_Struct -> Angle_Final         = 0;
        Kalman_Struct -> Gyro_Final                 = 0;

}


/**
  ******************************************************************************
  * @file    void Kalman_Filter(float Accel,        float Gyro ,KalmanCountData * Kalman_Struct)
  * @author  willieon
  * @version V0.1
  * @date    January-2015
  * @brief   卡尔曼滤波计算
  *        
  *
  ******************************************************************************
  * @attention
  *                Accel:加速度计数据处理后进来的角度值
  *                Gyro :陀螺仪数据处理后进来的角速度值
  *                Kalman_Struct:递推运算所需要的中间变量,由用户定义为全局结构体变量
  *                Kalman_Struct -> Angle_Final  为滤波后角度最优值
  *                Kalman_Struct -> Gyro_Final   为后验角度值
  ******************************************************************************
  */

void Kalman_Filter(float Accel,        float Gyro ,KalmanCountData * Kalman_Struct)
{
                //陀螺仪积分角度(先验估计)
                Kalman_Struct -> Angle_Final += (Gyro - Kalman_Struct -> Q_bias) * dt; 
                
                //先验估计误差协方差的微分
                Kalman_Struct -> Pdot[0] = Q_angle - Kalman_Struct -> PP[0][1] - Kalman_Struct -> PP[1][0]; 
                Kalman_Struct -> Pdot[1] = - Kalman_Struct -> PP[1][1];
                Kalman_Struct -> Pdot[2] = - Kalman_Struct -> PP[1][1];
                Kalman_Struct -> Pdot[3] = Q_gyro;
                
                //先验估计误差协方差的积分
                Kalman_Struct -> PP[0][0] += Kalman_Struct -> Pdot[0] * dt;   
                Kalman_Struct -> PP[0][1] += Kalman_Struct -> Pdot[1] * dt;   
                Kalman_Struct -> PP[1][0] += Kalman_Struct -> Pdot[2] * dt;
                Kalman_Struct -> PP[1][1] += Kalman_Struct -> Pdot[3] * dt;
                
                //计算角度偏差
                Kalman_Struct -> Angle_err = Accel - Kalman_Struct -> Angle_Final;        
                
                //卡尔曼增益计算
                Kalman_Struct -> PCt_0 = C_0 * Kalman_Struct -> PP[0][0];
                Kalman_Struct -> PCt_1 = C_0 * Kalman_Struct -> PP[1][0];
                
                Kalman_Struct -> E = R_angle + C_0 * Kalman_Struct -> PCt_0;
                
                Kalman_Struct -> K_0 = Kalman_Struct -> PCt_0 / Kalman_Struct -> E;
                Kalman_Struct -> K_1 = Kalman_Struct -> PCt_1 / Kalman_Struct -> E;
                
                //后验估计误差协方差计算
                Kalman_Struct -> t_0 = Kalman_Struct -> PCt_0;
                Kalman_Struct -> t_1 = C_0 * Kalman_Struct -> PP[0][1];

                Kalman_Struct -> PP[0][0] -= Kalman_Struct -> K_0 * Kalman_Struct -> t_0;                 
                Kalman_Struct -> PP[0][1] -= Kalman_Struct -> K_0 * Kalman_Struct -> t_1;
                Kalman_Struct -> PP[1][0] -= Kalman_Struct -> K_1 * Kalman_Struct -> t_0;
                Kalman_Struct -> PP[1][1] -= Kalman_Struct -> K_1 * Kalman_Struct -> t_1;

                Kalman_Struct -> Angle_Final += Kalman_Struct -> K_0 * Kalman_Struct -> Angle_err;         //后验估计最优角度值
                Kalman_Struct -> Q_bias        += Kalman_Struct -> K_1 * Kalman_Struct -> Angle_err;                 //更新最优估计值的偏差
                Kalman_Struct -> Gyro_Final   = Gyro - Kalman_Struct -> Q_bias;                                                 //更新最优角速度值

}

[/pre]

代码可以放在实际工程中使用,也可以用VS等C编译工具进行实验学习。在VS中的main()实例使用如下

[pre lang="C" line="1" file="main.c"]
#include "kalman.h"

#include "stdio.h"

#include "stdlib.h"

void main(void)
{


        KalmanCountData k;
        //定义一个卡尔曼运算结构体
        Kalman_Filter_Init(&k);
        //讲运算变量初始化
        int m,n;        

           for(int a = 0;a<80;a++)
        //测试80次
        {

                //m,n为1到100的随机数
                m = 1+ rand() %100;

                n = 1+ rand() %100;

                //卡尔曼滤波,传递2个测量值以及运算结构体
        
        Kalman_Filter((float)m,(float)n,&k);

                //打印结果
                printf("%d and %d is %f - %f\r\n",m,n,k.Angle_Final,k.K_0);
        
        }




}
[/pre]

http://www.ppmy.cn/news/325435.html

相关文章

手撕卡尔曼滤波器

手撕卡尔曼滤波器 卡尔曼滤波器&#xff08;Kalman Filter&#xff09;&#xff0c;从字面意思上来看&#xff0c;“Filter滤波器”一词并不能很好地体现其特性。卡尔曼滤波器用一句话来说就是“Optimal Recursive Data-Processing Algorithm”&#xff0c;即为“最优化 递归 …

芯弛V9 GPIO配置

这篇文章主要分享给没接触过芯弛芯片的同学们&#xff0c;以往做项目的经验&#xff0c;接触一个新的芯片平台&#xff0c;大家通常喜欢通过设置GPIO来评估下新平台的设置使用习惯&#xff0c;芯弛的芯片上手还是非常快的。 以AP域GPIO配置为例&#xff1a; 打开SDToolBox&am…

Verilog 乘法器

30那个地方改仿真的时长&#xff0c;默认是10us&#xff08;但实际上好像是1us&#xff09; 这里改成30us //加载被乘数&#xff0c;运算时每次左移一位 &#xff08;这里把被乘数位拓展了&#xff09; reg [63:0] multiplicand //加载乘数&#xff0c;运算时每次右移一位…

OpenFOAM v9 postProcessing

1.1 fields场计算 age:求解输运方程&#xff0c;以确定粒子从入口对流到流中位置所需的时间。components:写入场&#xff08;例如U&#xff09;的分量&#xff08;例如Ux&#xff0c;Uy&#xff0c;Uz&#xff09;。CourantNo:从通量场计算库朗数。ddt:计算场的欧拉时间导数。…

Ferrari(法拉利)历代车型

Ferrari历代车型(全部配图) <content></content> 1947 125 S 1947 159 S 1948 166 INTER 1950 195 S 1951 340 AMERICA 1952 250 S

【C/C++】回调函数

1. 概念 回调函数是一种在程序运行期间通过函数指针调用的函数&#xff0c;它通常用于实现事件驱动、异步通信、消息传递等功能。 在回调函数的使用中&#xff0c;当某些事件发生时&#xff0c;系统会调用预先注册好的回调函数&#xff0c;将事件相关的数据传递给回调函数&am…

硬件设计电源系列文章-LDO设计

文章目录 概要整体架构流程技术名词解释技术细节小结 概要 本文主要分享LDO的相关设计&#xff0c;尤其是LDO的并联设计 整体架构流程 提示&#xff1a;这里可以添加技术整体架构 主要是讲述LDO的并联&#xff1b;并联以增加输出驱动能力&#xff0c;其具体框架如下&#x…