【无标题】PID控制TT编码器电机

记录本人学习的笔记

开始学习PID感觉他很难,其实并不是的。首先我们需要取了解PID控制电机的基本流程,然后再搭配你学的理论知识。
【无标题】PID控制TT编码器电机_第1张图片
下面来讲讲具体的实现,首先设置单片机的定时器用来读取到AB相中的脉冲数目(首先注意的是获取脉冲的通道只能是定时器的前两个通道),然后在PID中将你设置的脉冲数目与测得的脉冲数目进行对比。通常来说我们设定的是转速,所以我们需要将转速转换成脉冲数目。举个例子:TT电机13线的使四倍频,一圈有2496个脉冲,我们设定50转每分钟(这里只轮子转速,如果是电机内部转速需要除以你的减速比),然后我们设置定时器10ms读取一次值。那么10ms脉冲数应该为50*2496/6000(一分钟有6000个10ms),因此将设定脉冲与目前测得得脉冲带入PID计算公式算出值,抽象地来说它就是个依据偏差,产生的控制作用。通过计算值产生一个PWM信号。

下面是部分代码,可以看一看,基本上就这些东西。

1.对定时器进行设置

#include "encoder.h"
#include "delay.h"
#include "usart.h"


//PA0
//PA1
void TIM5_Encoder_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure; 
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_ICInitTypeDef TIM_ICInitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);	
	
	GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_0 | GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;    
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);

	TIM_TimeBaseStructure.TIM_Prescaler = 0x00;  // No prescaling 
	TIM_TimeBaseStructure.TIM_Period = 65535;  
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;   
	TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);
	
	TIM_EncoderInterfaceConfig(TIM5, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
	TIM_ICStructInit(&TIM_ICInitStructure);
	TIM_ICInitStructure.TIM_ICFilter = 10;
	TIM_ICInit(TIM5, &TIM_ICInitStructure);

	TIM_SetCounter(TIM5,0);
	TIM_Cmd(TIM5, ENABLE);    
}

2.PID计算部分

这里有两种计算公式就是写法不同,用哪个都可以,PID计算公式用很多看你自己需求。

#include "pid.h"


static double Kp=10;
static double Ki=0;
static double Kd=0;
int shouxie_PID_ZLP(int now , int set)
{
  int PWM,Bias,Bias_D;
	static int error,last_Bias;
	Bias = now - set;
	error +=Bias;
	Bias_D=Bias-last_Bias;
	PWM = Kp*Bias + Ki*error +Kd*Bias_D;
	last_Bias = Bias;
	return PWM;

}
static double   ProportionA=70;                               
static double   IntegralA=25;                                
static double   DerivativeA=35;

int SPEED_PID_A(int now,int set)
{
	static int  LastError;	//Error[-1]
	static int  PrevError;  //Error[-2]
    int iError,Output;     
	iError=set-now;
	Output = ((ProportionA * (iError - LastError)) + (IntegralA * iError) + (DerivativeA * (iError - 2*LastError + PrevError)));	
  PrevError=LastError;                    
  LastError=iError;
  return Output;                              
}



3.对输出进行控制

#include "control.h"
#include "pid.h"
#include "datascope.h"
#include "motor.h"
#include "usart.h"

 
int para_A;
int Motor_A;
int SetRPMA=100;
#define SetPointA SetRPMA*2496/6000


int myabs(int a){
	int temp;
	if(a < 0) temp = -a;
	else temp = a;
	return temp;
}
int Read_Encoder(u8 x)
{
   int Encoder_TIM;    
   switch(x)
	 {
		 case 5:  Encoder_TIM= (short)TIM5 -> CNT;  TIM5 -> CNT=0;break;
	
		 default: 	Encoder_TIM=0;
	 }
		return Encoder_TIM;
}


int Encoder_A;  
int Send_Count,i;
extern int adc_data;
int position_out;
int ac_speed_b;
int bigout_B;

void TIM6_IRQHandler(void)
{

	if(TIM_GetFlagStatus(TIM6, TIM_IT_Update) != RESET) 
	{

		
		Encoder_A=Read_Encoder(5);  //读取编码器得值                       
		
		para_A=SPEED_PID_A(Encoder_A,SetPointA);
		/*
		将设定脉冲与测得脉冲带入到PID控制器中
		*/	
		
        printf("%d\r\n",Encoder_A);
		  
		

		if((para_A<-3)||(para_A>3)) 
		{
			Motor_A +=para_A;  
		} 
		if(Motor_A>7000)Motor_A=7000;//限幅
		if(Motor_A<-7000)Motor_A=-7000;
		
		if(Motor_A > 0){
		MotorA1 = 0;
		MotorA2 = 1;
		}else{
		MotorA1 = 1;
		MotorA2 = 0;
		}TIM8->CCR1 = myabs(Motor_A);
		/*定时器8 我使用得计数周期为一万,CCR1的值为 myabs(Motor_A)*/
	}
	TIM_ClearITPendingBit(TIM6, TIM_FLAG_Update);   

}

有不懂的或者是我错的可以写在评论区。

你可能感兴趣的:(单片机,stm32,c语言,pid)