久久久国产精品视频袁燕,99re久久精品国产,亚洲欧美日韩国产综合v,天天躁夜夜躁狠狠久久,激情五月婷婷激情五月婷婷

嵌入式STM32中的各類PID介紹

1. 位置式 PID(用于位置環(huán))

  測量位置就是通過 stm32 去采集編碼器的脈沖數(shù)據(jù),通過脈沖計算出位置(角度)。目標位置和測量位置之間做差這個就是目前系統(tǒng)的偏差。送入 PID 控制器進行計算輸出,然后再經(jīng)過電機驅(qū)動的功率放大控制電機的轉(zhuǎn)動去減小偏差, 最終達到目標位置的過程。

(1)公式

(2)代碼

pid.c

typedef struct PID {
		float  Kp;         //  Proportional Const  P系數(shù)
		float  Ki;           //  Integral Const      I系數(shù)
		float  Kd;         //  Derivative Const    D系數(shù)
		
		float  PrevError ;          //  Error[-2]  
		float  LastError;          //  Error[-1]  
		float  Error;              //  Error[0 ]  
		float  DError;            //pid->Error - pid->LastError	
		float  SumError;           //  Sums of Errors  
		
		float  output;
		
		float  Integralmax;      //積分項的最大值
		float  outputmax;        //輸出項的最大值
} PID;

//為了防止積分項過度累積,引入積分項的限幅是一種常見的做法。
//限制積分項的幅值可以防止積分項過度增加,從而限制了系統(tǒng)的累積誤差。這樣可以避免系統(tǒng)過度響應或者不穩(wěn)定。
float abs_limit(float value, float ABS_MAX)   //積分限幅,設置最大值。
{
	if(value > ABS_MAX)
		value = ABS_MAX;

	if(value< -ABS_MAX)
		value = -ABS_MAX;
	return value;
}


//函數(shù)里傳入指針,修改時會修改指針里的值。
float PID_Position_Calc(PID *pid, float Target_val, float Actual_val)  //位置式PID
{   

	pid->Error = Target_val - Actual_val;      //與pid P系數(shù)相乘。比例誤差值 當前差值=目標值-實際值
	pid->SumError += pid->Error;                 //與pid I系數(shù)相乘。穩(wěn)態(tài)誤差值 誤差相加作為誤差總和,給積分項
	pid->DError = pid->Error - pid->LastError;   //與pid D系數(shù)相乘。 微分項-消除震蕩

	pid->output =   pid->Kp* pid->Error +        
					abs_limit( pid->Ki* pid->SumError, pid->Integralmax ) +   
					pid->Kd* pid->DError ;  
								
   pid->LastError = pid->Error; //更新誤差
   
  //限制輸出最大值,防止出現(xiàn)突發(fā)意外。輸出outputmax的最大值
	if(pid->output > pid->outputmax )  pid->output = pid->outputmax; 
	if(pid->output < - pid->outputmax )  pid->output = -pid->outputmax;
	
	return pid->output ;   //輸出為pwm值
}

//PID初始化
void PID_Init(PID *pid, float Kp , float Ki , float Kd , float Limit_value)  
{  
	pid->Kp= Kp;
	pid->Ki= Ki;
	pid->Kd= Kd;
	
	pid->PrevError =pid->LastError = pid->Error =pid->SumError= pid->output =  0; 
	pid->Integralmax = pid->outputmax  = Limit_value;
}  

(3)使用代碼

#include "sys.h"

PID postion_pid;
float Encoder_Speed =0;
float Position =0;
float Speed=0;
float Target_val =500;

int main()
{
	Time2_Init(10000-1,7200-1); //定時器2用于定時 10000*7200/72 = 1s
	Encoder_Init();  //定時器4的編碼器
	Motor_PWM_Init(7200-1,0); //定時器1,初始化pwm輸出
	PID_Init(&postion_pid, 1.0, 0, 1.0, 7000);
	
	while(1)
	{
	
	}
}

//---- 獲得電機的脈沖
int16_t Encoder_Get(void)
{
	int16_t Temp;
	Temp = TIM_GetCounter(TIM4); //獲取編碼器當前值
	TIM_SetCounter(TIM4, 0);  //將編碼器計數(shù)器清0
	return Temp;
}

//設置pwm
void Set_Pwm(int motor_pwm)
{
	TIM_SetCompare4(TIM1, motor_pwm);
}

void MotorControl(void)
{
	Encoder_Speed = Encoder_Get();//1.獲取電機1s的脈沖數(shù)。即1s獲取的脈沖數(shù)。即速度
	Position +=Encoder_Speed ; //累計實際脈沖數(shù)。與時間無關。即總路程
	
	Speed=PID_Position_Calc(&postion_pid, Target_val , Position);//2.輸入增量式PID計算
	Set_Pwm(Speed);  //3.PWM輸出給電機
	//set_computer_value(SEND_FACT_CMD, CURVES_CH2, &Encoder_Speed, 1);   /*4.給上位機通道2發(fā)送實際的電機速度值*/
}



void TIM2_IRQHandler(void)  //定時器中斷函數(shù),1s進一次中斷
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		MotorControl();
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}

2. 增量式 PID(用于速度環(huán))

  增量式 PID 也稱速度環(huán) PID,速度閉環(huán)控制就是根據(jù)單位時間獲取的脈沖數(shù)測量電機的速度信息,并與目標值進行比較,得到控制偏差,然后通過對偏差的比例、積分、微分進行控制,使偏差趨向于零的過程。

(1)公式

(2)代碼

typedef struct PID {
		float  Kp;         //  Proportional Const  P系數(shù)
		float  Ki;           //  Integral Const      I系數(shù)
		float  Kd;         //  Derivative Const    D系數(shù)
		
		float  PrevError ;          //  Error[-2]  
		float  LastError;          //  Error[-1]  
		float  Error;              //  Error[0 ]  
		float  DError;            //pid->Error - pid->LastError	
		float  SumError;           //  Sums of Errors  
		
		float  output;
		
		float  Integralmax;      //積分項的最大值
		float  outputmax;        //輸出項的最大值
} PID;


float PID_Incremental_Calc(PID *pid, float Target_val, float Actual_val)  
{  
	pid->Error = Target_val- Actual_val;                        

	pid->output  +=  pid->Kp* ( pid->Error - pid->LastError )+   
					 pid->Ki* pid->Error +   
					 pid->Kd* ( pid->Error +  pid->PrevError - 2*pid->LastError);  
								 
	pid->PrevError = pid->LastError;  
	pid->LastError = pid->Error;

	if(pid->output > pid->outputmax )    pid->output = pid->outputmax;
	if(pid->output < - pid->outputmax )  pid->output = -pid->outputmax;
	
	return pid->output ;   //輸出為pwm值
}

//PID初始化
void PID_Init(PID *pid, float Kp , float Ki , float Kd , float Limit_value)  
{  
	pid->Kp= Kp;
	pid->Ki= Ki;
	pid->Kd= Kd;
	
	pid->PrevError =pid->LastError = pid->Error =pid->SumError= pid->output =  0; 
	pid->Integralmax = pid->outputmax  = Limit_value;
}  

(3)使用代碼

#include "sys.h"

PID speedpid;
float Encoder_Speed =0;
float Target_val =500;  //目標1s的脈沖數(shù)
float Speed=0;//實際速度


int main()
{
	Time2_Init(10000-1,7200-1); //定時器2用于定時 10000*7200/72 = 1s
	Encoder_Init();  //定時器4的編碼器
	Motor_PWM_Init(7200-1,0); //定時器1,初始化pwm輸出
	PID_Init(&speedpid, 1.0, 0, 1.0, 7000);
	
	while(1)
	{
	
	}
}

//獲得電機的脈沖
int16_t Encoder_Get(void)
{
	int16_t Temp;
	Temp = TIM_GetCounter(TIM4); //獲取編碼器當前值
	TIM_SetCounter(TIM4, 0);  //將編碼器計數(shù)器清0
	return Temp;
}

//設置pwm
void Set_Pwm(int motor_pwm)
{
	TIM_SetCompare4(TIM1, motor_pwm);
}

void MotorControl(void)
{
	Encoder_Speed = Encoder_Get();//1.獲取電機1s的脈沖數(shù)。即1s獲取的脈沖數(shù)。即速度。
	Speed=PID_Incremental_Calc(&speedpid,Target_val ,Encoder_Speed);//2.輸入增量式PID計算
	Set_Pwm(Speed);  //3.PWM輸出給電機
	//set_computer_value(SEND_FACT_CMD, CURVES_CH2, &Encoder_Speed, 1);   /*4.給上位機通道2發(fā)送實際的電機速度值*/
}




void TIM2_IRQHandler(void)  //定時器中斷函數(shù),1s進一次中斷
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		MotorControl();
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}

3. 串級 PID

(1)位置環(huán)–速度環(huán)(用于控制電機)

         利用位置式 pid 的方法將位置環(huán)和速度環(huán)組合在一起使用。位置環(huán)的輸出作為速度環(huán)的輸入。位置環(huán)的輸出作為速度環(huán)的目標期望值。這意味著位置環(huán)的輸出被視為速度環(huán)應該追蹤的目標位置。速度環(huán)的任務是根據(jù)當前位置和目標位置之間的偏差來生成控制輸出,使系統(tǒng)盡可能快地接近目標位置。速度環(huán)將根據(jù)當前速度和目標速度之間的差異來調(diào)整電機的輸出,以便使實際速度接近目標速度。

簡易代碼

  將目標位置和實際位置傳入位置環(huán) PID 中,計算出期望轉(zhuǎn)速。然后通過期望轉(zhuǎn)速與實際轉(zhuǎn)速傳入速度環(huán) PID 中計算出對應的 pwm,然后通過 pwm 去控制電機。

#include "stdio.h"

PID  postion_pid;
PID  speed_pid;

float Encoder_Speed =0;
float Target_val =500;  //目標總的脈沖數(shù)
float Speed=0;//實際速度
float Position =0;

int main(void)
{

	  Time2_Init(10000-1,7200-1); //定時器2用于定時 10000*7200/72 = 1s,如果覺得時間太長可以縮短一些
	  Encoder_Init();  //定時器4的編碼器
	  Motor_PWM_Init(7200-1,0); //定時器1,初始化pwm輸出
	  // 初始化PID控制器
	  PID_Init(&postion_pid, 1.0, 0.1, 0.01, 300); // PID參數(shù)根據(jù)實際情況調(diào)整
	  PID_Init(&speed_pid, 1.0, 0.1, 0.01, 300);  // PID參數(shù)根據(jù)實際情況調(diào)整
  
	  while (1)
	  {

	  }
}

//獲得電機的脈沖
int16_t Encoder_Get(void)
{
	int16_t Temp;
	Temp = TIM_GetCounter(TIM4); //獲取編碼器當前值
	TIM_SetCounter(TIM4, 0);  //將編碼器計數(shù)器清0
	return Temp;
}


//設置pwm
void Set_Pwm(int motor_pwm)
{
	TIM_SetCompare4(TIM1, motor_pwm);
}


void MotorControl(void)
{
	Encoder_Speed = Encoder_Get(); //1.獲取電機1s的脈沖數(shù)。即1s獲取的脈沖數(shù)。即速度
	Position +=Encoder_Speed ;  //累計實際脈沖數(shù)。與時間無關。即總路程
	
	Speed=PID_Position_Calc(&postion_pid, Target_val , Position);//2.輸入位置式PID計算
	Speed=PID_Incremental_Calc(&speedpid,Speed, Encoder_Speed);//2.輸入增量式PID計算
	Set_Pwm(Speed);  //3.PWM輸出給電機
	//set_computer_value(SEND_FACT_CMD, CURVES_CH2, &Encoder_Speed, 1);   /*4.給上位機通道2發(fā)送實際的電機速度值*/
}


void TIM2_IRQHandler(void)  //定時器中斷函數(shù),1s進一次中斷
{
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
	{
		MotorControl();
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}

(2)位置環(huán)–位置環(huán)(用于控制舵機)

      因為舵機沒有編碼器,無法獲取實際速度,所以我們可以使用兩個位置環(huán)來進行串級 pid 的使用,這樣更加精準。兩個位置環(huán)的實際值輸入都為距離值。第一個位置環(huán)的輸出作為第二個位置環(huán)的目標值輸入。  

      實際舉例:假設我們使用舵機來進行目標追蹤。則第一個位置環(huán)的實際值輸入:當前坐標-上次坐標的差值,目標值為 0。將這兩個值傳入位置環(huán)計算的輸出作為第二個位置環(huán)的目標值,第二個位置環(huán)的實際值可以傳入:當前位置和攝像頭中心點位置的差值。計算第二個位置環(huán)的輸出。將其作為 pwm 值輸入定時器通道去控制舵機。

聲明:本內(nèi)容為作者獨立觀點,不代表電子星球立場。未經(jīng)允許不得轉(zhuǎn)載。授權事宜與稿件投訴,請聯(lián)系:editor@netbroad.com
覺得內(nèi)容不錯的朋友,別忘了一鍵三連哦!
贊 3
收藏 4
關注 13
成為作者 賺取收益
全部留言
0/200
成為第一個和作者交流的人吧