- /**
- ******************************************************************************
- * @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就死機,后來換光耦隔離才解決!
|