pid被广泛应用于电机控制,本文章就是关于PID控制电机运动,包括速度环和位置环。
一.设置电机旋转方向
AIN1和AN2是指STM32上的两个引脚
//设置方向
void motor_set_direction(int direction)
{
if(direction == 1)
{
HAL_GPIO_WritePin(AIN1_GPIO_Port,AIN1_Pin,GPIO_PIN_RESET);
HAL_GPIO_WritePin(AIN2_GPIO_Port,AIN2_Pin,GPIO_PIN_SET);//即01,正转
}
else if(direction == 2)
{
HAL_GPIO_WritePin(AIN1_GPIO_Port,AIN1_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(AIN2_GPIO_Port,AIN2_Pin,GPIO_PIN_RESET);//即01,反转
}
else
{
HAL_GPIO_WritePin(AIN1_GPIO_Port,AIN1_Pin,GPIO_PIN_SET);
HAL_GPIO_WritePin(AIN2_GPIO_Port,AIN2_Pin,GPIO_PIN_SET);//停止
}
}
二.获取编码器中的脉冲数
void GET_NUM(void)
{
encoder_counter=myabs((short) __HAL_TIM_GET_COUNTER(&htim2));
__HAL_TIM_SET_COUNTER(&htim2,0);//将编码器模式的定时器清零
}
三.速度PID
如果需要快速到达目标速度时,可以设置全量输出
int Incremental_PI (int Encoder,int Target)
{
static float Bias,Pwm,Last_bias,last_last_bias;//bias=Err
Encoder=myabs(Encoder);
Bias=Target-Encoder;//计算偏差
// Integral_bias+=Bias;
// Integral_bias=Xianfu(Integral_bias,5000);
/*全量输出*/
// if(Bias>30)
// Pwm=5000;
// else if(Bias<-30)
// Pwm=-5000;
// else //一般
Bias = Xianfu(Bias,30);
Pwm+=(Velocity_KP*(Bias-Last_bias)+Velocity_KI*Bias+Velocity_KD*(Bias+last_last_bias-2*Last_bias)); //增量式PID控制
last_last_bias = Last_bias;
Last_bias=Bias;
Xianfu(Pwm,8000);
return Pwm;
}
四.位置PID
整个原理大家应该都懂,其他各位大佬有很详细的解说,我在这里就不解释了。
int Position_PID (int position,int target)
{
static float Bias,Pwm,Integral_bias,Last_Bias;
Bias=target-position;
Integral_bias+=Bias;
Integral_bias=Xianfu(Integral_bias,myabs(Target_Velocity));
// Integral_bias=Xianfu(Integral_bias,30);
Pwm=Position_KP*Bias+Position_KI*Integral_bias+Position_KD*(Bias-Last_Bias);//位置式PID控制
Last_Bias=Bias;
Pwm=Xianfu(Pwm,9000);
return Pwm;
}
五.设置PWM输出
void Set_Pwm(int moto)
{
moto=myabs(moto);
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1,moto);
}
六.定时回调函数
这里后期可以在VOFA中,既可以呈现出正的目标位置脉冲曲线,又可以呈现负的目标位置脉冲曲线。
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
t++;
if (htim == &htim6)
{
GET_NUM(); // 获取编码器的脉冲数
if(Target_Position==0)
{
output = Incremental_PI(encoder_counter,Target_Velocity);//只有速度pid控制
}
else
{
if(Target_Position>0)
{Position += encoder_counter; } // 累积脉冲数
else
{Position -= encoder_counter; }
// 计算位置控制的PWM值
Position_PWM = Position_PID(Position, Target_Position);
output = Incremental_PI(encoder_counter, Xianfu(Position_PWM, Target_Velocity));//串级
}
}
}
七.其他函数
(一).绝对值函数
float myabs(float num)
{
float temp;
if(num<0) temp=-num;
else temp =num;
return temp;
}
(二).限幅函数
int Xianfu(int value,int Amplitude)
{
int temp;
if(value>Amplitude) temp = Amplitude;
else if(value<-Amplitude) temp = -Amplitude;
else temp = value;
return temp;
}
八.小结
后期在main.c中设置目标值,调用方向函数和设置PWM函数即可。祝大家都能实现PID控制。