关于PID的类型详解和应用,以及基于Vofa+软件的PID调参详解
By:weixiao
前言
针对智能车大赛学习控制电机转速,写出此篇blog
控制电机并不是简单的输出PWM大或者小就可以,由于负载或者电机性能,单独给相同的PWM值电机并不会保持相同转速,因此我们需要加入PID算法,来保持电机转速,以达到保持速度的目的,我们使用编码器来获取当前电机的速度,将当前电机的速度作为一个模拟量,来转化为数字量传给单片机获取数据,通过PID算法将电机PWM变为实时PWM,将电机速度稳定。
一、单级PID介绍
1.比例环节(P值)
我们将当前速度值Actual与目标速度值Target之间的差值称之为误差值Error,如果这个Error值非常大,我们增大电机的PWM值能够缩小当前速度值到达目标速度值的时间,PWM值、比例P、Error之间的公式为:
PWM=Kp*Error
因此可以增大P值来缩短这个时间,理论来讲如果我们把P增加的足够大就可以直接快速达到目标值,通过matlab仿真波形图发现,我们将P增大后响应时间的确减小了,可是当前速度值会在目标速度值做出一个剧烈的简谐振动,减小P值后响应时间又会增大,因此为了抑制简谐振动我们可以通过调节微分值(D值)来实现。
2.微分环节(D值)
简单来讲,加入D值就会产生一个阻尼效果,来抑制简谐振动,使当前速度值稳定在目标速度值上,增大D值也就是加快当前速度值运动到目标速度值的收敛,加快了响应速度。
3.积分环节(I值)
光有P值和D值已经可以实现目的了,但是我们能够发现一个bug,拿蔬菜大棚举例,如果想让大棚内温度达到30℃(也就是目标温度),当前大棚内温度为25℃,我们让25℃升温到30℃,假设升温时间为半小时,在这半小时中,室外温度使大棚产生温差,使大棚在半小时内又能够降温5℃,升温与降温一直相互抵消,这5℃,我们称之为静态误差。I值就是用于消除静态误差,加入I值,即为完美的PID功能。
4.代码实现
代码模板:
typedef struct
{
float target_val; //目标值
float actual_val; //当前值
float error; //偏差值
float err_last; //上一个偏差值
float kp,ki,kd; //比例、积分、微分系数
float integral; //定义积分值
}pid;
/*PID初始化*/
void PID_init()
{
/* 初始化参数 */
pid.target_val=0.0;
pid.actual_val=0.0;
pid.err=0.0;
pid.err_last=0.0;
pid.integral=0.0;
pid.Kp = 0.31;
pid.Ki = 0.070;
pid.Kd = 0.3;
}
/*导入实际转速值*/
float .....=pid.actual_val//为编码器获得的电机转速转化的数字量
/*PID算法实现*/
float PID_realize(float temp_val)
{
pid.err=pid.target_val-temp_val;
/*误差累积*/
pid.integral+=pid.err;
/*PID算法实现*/
pid.actual_val=pid.Kp*pid.err+pid.Ki*pid.integral+pid.Kd*(pid.err-pid.err_last);
/*误差传递*/
pid.err_last=pid.err;
/*返回的值是经过pid运算以后的值*/
return pid.actual_val;
}
/*定时器周期函数调用*/
void time_motor()
{
float val=PID_realize(.....);
int temp=val;
//发送PWM
set_compare_val(.....); //根据不同单片机的PWM例程更改
}