PID是由三部分组成,分别是P(比例), I(积分),D(微分)三部分组成。
由于作者水平有限,对其理解只停留在表层,有错误恳请大家指出。下面我用火车进站的例子来简述一下我理解的PID。
一 . P 比例项
比例项可以理解为一辆火车,想要在站台停车,在距离站台1000米的地方关闭引擎,此刻速度为10m/s。此时的1000/10就相当于P值,火车会滑行过去,但火车因为惯性肯定会超过站台,超过站台后再以一个速度倒车进站台。对于P的值,将它定的较大的话,火车进站的速度提高了,但是因为速度过快,火车会在站台附近来回震荡。P的值设定的小一点,火车虽然不会出现震荡的情况,但火车进站的速度会很慢很慢,所以设定一个合理的P值是非常有必要的。
二,微分项
这里将微分项放在积分项之前可以好的理解。如果只用一个P的话,火车在距离站台1000米时速度为10m/s,在距离站台100米时的速度也是10m/s,这显然不合理,这时候我们就需要引入一个微分项来解决这一问题,通过测算当前距离站台的距离和前一秒距离站台的距离,就可以实现距离站台2000米时速度为30m/s,在距离站台300米时让其速度为5m/s,在距离站台10米时让其速度为1m/s,这样就可以在站台下停下,而不用来回震荡。简单的来说,D就是一个防过冲装置,作为一个预判,使系统更快趋于稳定。D会限制P的作用,调试的时候,先将D设为0,再设置一个P的值,再逐渐增大D的值,直到系统不出现震荡。
三.积分项
积分项是I,积分项可理解为系统会有一些固定的偏差,这些偏差是系统硬件或者本身决定的,通过P无法调节,虽然这个误差很小很小,但他会逐渐累加,累加到一定程度以后就会系统产生不可忽视的影响。对于火车进站来说,第一次误差有0.1米,这也算是一次成功的进站,但下一站呢,10站之后呢,这个小误差将会是一个不可忽视的误差,所以我们会在999.9米的时候在关闭引擎,这一过程就是I积分。对于玩位置式和增量式来说,I积分的过程还要考虑积分饱和等情况,所以我们要添加积分分离过程,抗饱和过程,这些在后续会有讲解。
下面是一个简单的代码实现
struct pid{ //定义一个结构体
float SetSpeed; //目标值
float ActualSpeed; //当前值
float err; //误差值
float err_last; //上次误差值
float kp,ki,kd; //三个过程中的比例系数
float pwm; //输出
float integral; //积分值
}pid;
void PID_init(void) //PID初始化
{
printf("PID_init begin \r\n");
pid.ActualSpeed=0.0;
pid.SetSpeed=0.0;
pid.err=0.0;
pid.err_last=0.0;
pid.integral=0.0;
pid.pwm=0.0;
pid.kp=0.0;
pid.ki=0.0;
pid.kd=0.0;
printf("PID_init end\r\n");
}
float PID_realize(float speed) //PID执行函数
{
pid.SetSpeed=speed;
pid.err= pid.SetSpeed-pid.ActualSpeed;
pid.integral+=pid.err;
pid.pwm= pid.kp*pid.err+ pid.ki*pid.integral+pid.kd*(pid.err_last-pid.err);
pid.err_last=pid.err;
pid.ActualSpeed=pid.pwm*1.0;
pwm=pid.pwm;
return pid.ActualSpeed;
}
以上就是我理解的PID,如果有不对的地方,请大家批评指出,谢谢阅读。