久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费
標題:
STM32運用之自平衡小車的卡爾曼算法封裝
[打印本頁]
作者:
51hei學習
時間:
2016-4-10 00:45
標題:
STM32運用之自平衡小車的卡爾曼算法封裝
最近研究STM32的自平衡小車,發現有兩座必過的大山,一為卡爾曼濾波,二為PID算法。
網上看了很多關于卡爾曼濾波的代碼,感覺寫得真不咋地。一怒之下,自己重寫,不廢話,貼代碼
/**
******************************************************************************
* @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
復制代碼
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; //更新最優角速度值
}
復制代碼
代碼可以放在實際工程中使用,也可以用VS等C編譯工具進行實驗學習。在VS中的main()實例使用如下
#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",m,n,k.Angle_Final,k.K_0);
}
}
復制代碼
繼卡爾曼之后,繼續對PID進行封裝~~~~~~~~
為平衡小車做準備
作者:
51hei學習
時間:
2016-4-10 00:46
/**
******************************************************************************
* @file PID_Control.h
* @author willieon
* @version V0.1
* @date January-2015
* @brief PID控制算法頭文件
* 定義結構體類型以及聲明函數
* #define IF_THE_INTEGRAL_SEPARATION 0/1 為積分分離標志
******************************************************************************
**/
#ifndef __PID_CONTROL_H__
#define __PID_CONTROL_H__
#define IF_THE_INTEGRAL_SEPARATION 0
//#define IF_THE_INTEGRAL_SEPARATION 1 //是否積分分離 0-不分離,1 -分離
typedef struct
{
double SetPoint; // 設定目標 Desired Value
double Proportion; // 比例常數 Proportional Const
double Integral; // 積分常數 Integral Const
double Derivative; // 微分常數 Derivative Const
double LastError; // Error[-1]
double PrevError; // Error[-2]
double SumError; // Sums of Errors
}PID;
#if IF_THE_INTEGRAL_SEPARATION //是否積分分離預編譯開始
double PIDCalc(double NextPoint ,double SepLimit, PID *pp); //帶積分分離的PID運算
#else
double PIDCalc( double NextPoint, PID *pp); //不帶積分分離的PID運算
#endif //是否積分分離預編譯結束
void PIDInit (double SetPoint, double Proportion, double Integral, double Derivative, PID *pp);
#endif
復制代碼
/**
******************************************************************************
* @file PID_Control.c
* @author willieon
* @version V0.1
* @date January-2015
* @brief PID控制算法函數代碼
*
*
******************************************************************************
**/
#include "PID_Control.h"
#include "math.h"
/*************************************************************************************
* 名 稱: double PIDCalc( PID *pp, double NextPoint ,double SepLimit)
* 功 能: PID控制運算
* 入口參數: PID *pp - 定義的運算所需變量的結構體
* NextPoint - 負反饋輸入值
* SepLimit - 積分分離上限
* 出口參數: 返回PID控制量
* 說 明: 默認不進行積分分離,如果用戶需要使用積分分離,需在PID_Control.h中
* 將 #define IF_THE_INTEGRAL_SEPARATION 0 改為
* #define IF_THE_INTEGRAL_SEPARATION 1
* 調用方法: 進行積分分離時入口參數為3個,具體方法如下:
* PID PIDControlStruct ; //定義PID運算結構體
* PIDInit(50, 0.24, 0.04, 0.2, &PIDControlStruct);//結構體初始化,注意&符號不能省
* ControlData = PIDCalc(ReadData, 200, &PIDControlStruct); //控制量 = PIDCalc(反饋值,積分分離上限,PID運算結構體)
*
***************************************************************************************
*/
#if IF_THE_INTEGRAL_SEPARATION
double PIDCalc(double NextPoint ,double SepLimit, PID *pp)
{
double dError, Error,Flag;
Error = pp->SetPoint - NextPoint; // 偏差
if(abs(Error) > SepLimit) //當偏差大于分離上限積分分離
{
Flag = 0;
}
else //當偏差小于分離上限,積分項不分離
{
Flag = 1;
pp->SumError += Error; // 積分
}
dError = pp->LastError - pp->PrevError; // 當前微分
pp->PrevError = pp->LastError;
pp->LastError = Error;
return (
pp->Proportion * Error // 比例項
+ Flag * pp->Integral * pp->SumError // 積分項
+ pp->Derivative * dError // 微分項
);
}
#else
double PIDCalc( double NextPoint, PID *pp)
{
double dError, Error;
Error = pp->SetPoint - NextPoint; // 偏差
pp->SumError += Error; // 積分
dError = pp->LastError - pp->PrevError; // 當前微分
pp->PrevError = pp->LastError;
pp->LastError = Error;
return (pp->Proportion * Error // 比例項
+ pp->Integral * pp->SumError // 積分項
+ pp->Derivative * dError // 微分項
);
}
#endif
/*************************************************************************************
* 名 稱: double PIDCalc( PID *pp, double NextPoint ,double SepLimit)
* 功 能: PID初始化設定
* 入口參數: PID *pp - 定義的運算所需變量的結構體
* SetPoint - 設定的目標值
* Proportion,Integral ,Derivative - P,I,D系數
* 出口參數: 無
* 說 明:
* 調用方法: PID PIDControlStruct ; //定義PID運算結構體
* PIDInit(50, 0.24, 0.04, 0.2, &PIDControlStruct);//結構體初始化,注意&符號不能省
* 因為函數需要傳入一個指針,需要對結構體取首地址傳給指針
*
***************************************************************************************
*/
void PIDInit (double SetPoint, double Proportion, double Integral, double Derivative, PID *pp)
{
pp -> SetPoint = SetPoint; // 設定目標 Desired Value
pp -> Proportion = Proportion; // 比例常數 Proportional Const
pp -> Integral = Integral; // 積分常數 Integral Const
pp -> Derivative = Derivative; // 微分常數 Derivative Const
pp -> LastError = 0; // Error[-1]
pp -> PrevError = 0; // Error[-2]
pp -> SumError = 0; // Sums of Errors
//memset ( pp,0,sizeof(struct PID)); //need include "string.h"
}
復制代碼
好了,現在把卡爾曼濾波和PID算法聯合起來,在VS平臺中運行實驗
#include "kalman.h"
#include "stdio.h"
#include "stdlib.h"
#include "PID_Control.h"
void main(void)
{
KalmanCountData k;
PID PIDControlStruct;
Kalman_Filter_Init(&k);
PIDInit(50, 1, 0.04, 0.2, &PIDControlStruct);
int m,n;
double out;
for(int a = 0;a<80;a++)
{
m = 1+ rand() %100;
n = 1+ rand() %100;
Kalman_Filter((float)m,(float)n,&k);
out = PIDCalc(k.Angle_Final, &PIDControlStruct);
printf("%3d and %3d is %6f -pid- %6f\r\n",m,n,k.Angle_Final,out);
}
}
復制代碼
寫到此處,我覺得,自平衡小車的兩座大山應該對讀者來說不是問題了,只要會調用函數,會做參數整定,就完全可以解決數據采集和數據融合以及控制了。
好吧!我承認我的代碼是仿照 STM32的庫的風格寫的,真心覺得這種代碼風格很NB。學習ing!
代碼本人測試過,如果有不足之處望不吝賜教!請直接跟帖討論
我最近在做的平衡車,硬件清單:
香蕉電機+輪子 6.4元*2
STM32F103C8Tb 最小系統板 31.5元*1
newwayL298N 光耦隔離電機驅動板 30元 *1
MPU6050姿態傳感器 9.3元*1
LM2596S DC-DC 降壓電源模塊 3.2元*1
藍牙4.0 BLE從模塊串口通信+直驅模式 CC2540 CC2541 RF-BM-S02 23元*1
光電測速傳感器模塊 4.8元*2
小車底盤用自己的小雕刻機雕的亞克力板,感覺可以用薄的鋁板做中間層,這樣底層放光電測速和姿態傳感器+薄鋁底板+電動機驅動板+鋁底板+STM32主控,可以屏蔽一部分干擾,在inventor里面建模畫好圖!
之前沒有用帶光耦隔離的驅動,速度一快STM32就死機,后來換光耦隔離才解決!
歡迎光臨 (http://m.zg4o1577.cn/bbs/)
Powered by Discuz! X3.1
主站蜘蛛池模板:
激情久久av
|
国产精品久久久一区二区
|
欧美激情视频一区二区三区
|
亚洲综合成人网
|
欧美日韩精品一区二区三区
|
五月激情丁香
|
av黄色网
|
亚洲激情视频在线观看
|
深夜福利免费
|
亚洲在线视频
|
午夜性色
|
国产精品99久久久久久久久久久久
|
一本在线
|
伊人免费
|
成人av免费看
|
成人扒开伸进免费观看
|
免费av片
|
一区在线视频
|
色爱天堂
|
亚洲精品福利视频
|
中文字幕一区二区三区在线观看
|
国产日韩欧美在线观看
|
国产成人三级一区二区在线观看一
|
日本韩国三级
|
91成人在线
|
亚洲天堂网站
|
五月激情综合网
|
欧美一区二区三区的
|
99久久久久久
|
91福利网
|
日韩欧美中文字幕在线观看
|
久久久久久久久久久国产
|
男男成人高潮片免费网站
|
亚洲网站在线
|
日韩一区二区在线播放
|
欧美国产日韩精品
|
亚洲精品在线视频观看
|
黄色网址免费看
|
欧美精品一区二
|
久久成人免费视频
|
手机看片欧美
|