这篇文章主要是帮助理解和使用pid,不会讲复杂的代码公式。

pid可以看作是一种控制器,用来控制某个变量达到你想要的地步。

单级pid

这里我举个例子来理解一下:

假设有一个水缸,最终的控制目的是要保证水缸里的水位永远的维持在1米的高度。假设初试时刻,水缸里的水位是0.2米,那么当前时刻的水位和目标水位之间是存在一个误差的error,且error为0.8.这个时候,假设旁边站着一个人,这个人通过往缸里加水的方式来控制水位。

如果单纯的用比例控制算法,就是指加入的水量u和误差error是成正比的。即
u=kp*error
假设kp取0.5,
那么t=1时(表示第1次加水,也就是第一次对系统施加控制),那么u=0.5*0.8=0.4,所以这一次加入的水量会使水位在0.2的基础上上升0.4,达到0.6.
接着,t=2时刻(第2次施加控制),当前水位是0.6,所以error是0.4。u=0.5*0.4=0.2,会使水位再次上升0.2,达到0.8.
如此这么循环下去,就是比例控制算法的运行方法。
可以看到,最终水位会达到我们需要的1米。
但是,单单的比例控制存在着一些不足,其中一点就是 –稳态误差!
像上述的例子,根据kp取值不同,系统最后都会达到1米,不会有稳态误差。但是,考虑另外一种情况,假设这个水缸在加水的过程中,存在漏水的情况(可以看作是一些其他外界因素的影响),假设每次加水的过程,都会漏掉0.1米高度的水。仍然假设kp取0.5,那么会存在着某种情况,假设经过几次加水,水缸中的水位到0.8时,水位将不会再变换!!!因为,水位为0.8,则误差error=0.2. 所以每次往水缸中加水的量为u=0.5*0.2=0.1.同时,每次加水缸里又会流出去0.1米的水!!!加入的水和流出的水相抵消,水位将不再变化!!
也就是说,我的目标是1米,但是最后系统达到0.8米的水位就不在变化了,且系统已经达到稳定。由此产生的误差就是稳态误差了。

如果仅仅用比例,可以发现存在暂态误差,最后的水位就卡在0.8了。于是,在控制中,我们再引入一个分量,该分量和误差的积分是正比关系。所以,比例+积分控制算法为:
u=kp*error+ kierror
还是用上面的例子来说明,第一次的误差error是0.8,第二次的误差是0.4,至此,误差的积分(离散情况下积分其实就是做累加),error=0.8+0.4=1.2. 这个时候的控制量,除了比例的那一部分,还有一部分就是一个系数ki乘以这个积分项。由于这个积分项会将前面若干次的误差进行累计,所以可以很好的消除稳态误差(假设在仅有比例项的情况下,系统卡在稳态误差了,即上例中的0.8,由于加入了积分项的存在,会让输入增大,从而使得水缸的水位可以大于0.8,渐渐到达目标的1.0.)这就是积分项的作用。

当水位接近10m时,error会很小,但是由于Kp很大,就会使水位超过10m,系统出现超调。此时就需要引入微分控制(Kd)

u=kd*(error(t)-error(t-1))

在离散情况下,就是error的差值,就是t时刻和t-1时刻error的差。在水位上升过程中,因为error是越来越小的,所以这个微分控制项一定是负数,在控制中加入一个负数项,他存在的作用就是为了防止注入的水太多而导致超过设定水位。

串级pid和并联pid

刚开始我一直以为串级pid就是把两个不相干的控制量串联起来,一起控制某个东西。这里拿小车举例,就是把前进环pid和转向环pid串联起来。后来学习后我才发现这种想法是完全错误的,你如果想让小车同时拥有前进环和转向环(用的是差速转向),让这两个环共同控制小车,这里其实要用到并联pid,就是把两个pid的输出量叠加起来的值赋给电机。

这里我附上了代码展示

继续说咋们的串级pid,串级pid的目的是更精细化的控制你想要控制的那个量。因此它的外环和内环是有物理联系的,这也是你写串级pid的依据或者说是原理。

假设我们需要解决这样一个问题:

控制小车从当走到红色标签位置,设小车实时位置为x0(t)eb0808dbb2fc45c497e6d02eea50205f.png

如果我们使用单级PID,运动框图应该如下图所示:

如果你按照图中的思路设计控制器,那就说明你只对位置有期望,这意味着你对加速度没有期望,也就意味着加速度是什么都无所谓。

所以实际效果变成什么呢?你会以一个你无所谓的加速度到达你的期望位置。

这时候奇怪的事情发生了,到达你的期望位置时有加速度和速度,那这个就不是到达期望位置了,这叫经过期望位置。你会发现小车在期望位置附近“反复横跳”,超过后,又退回去,退过了,又超过去。

我们想要的期望的是停在期望位置上。什么叫停在期望位置上?就是到达期望位置的同时加速度与速度都为0。

现在我们想控制位置,类似于控制车,你只能踩油门加速,或者刹车进行减速,你只能通过速度控制间接控制位置。

开车的时候是怎么控制位置的呢?你想停在指定位置的时候,你先以一定的速度前往指定位置,快到的时候,通过刹车不断减速,直到速度为0,停到期望的位置。

这时我们发现,我们可以通过控制加速度来控制速度,从而控制我们的位置。所以串级pid就诞生了。

我们重新设计一下控制器,也就是再加一个环控制我们的加速度。

3c88213598c540e59e83a23ad8172608.png

现在我们来重新复盘一下我们的控制器,当小车距离期望位置很远时,位置环输出就很大,因此速度环的期望值就很大,所以速度环输出(加速度)就很大,可以使小车很快到达期望位置。当小车靠近期望位置时,位置环输出很小,因此速度环的期望值就小,速度环输出就很小(加速度接近于0),因此小车在期望位置速度和加速度都为0,小车精准停在期望位置。

pid在循迹小车上应用

刚接触pid我一直纠结为什么输入和输出的完全使两种变量可以达到控制的效果,这其中涉及到数学和物理知识的推到。

我们其实只需要会用这个pid控制器就可以了,你只需要知道你输出什么量他就会控制什么量就欧克了。输入位置(循迹模块)他就会控制位置,输入速度(编码器值)就会控制速度。

对于循迹小车来说,一般只使用pd控制器。

一般来说pid的输入必须使线性的,但一般小车上都是用的数字灰度传感器,为了能够使用pid控制器就需要给每一路灰度赋予不同的权值,就比如5路灰度循迹(传感器越多肯定控制的越丝滑,如果要使用pid的话,最少应该有5路,不然pid毫无意义),左边第一个赋予权重是10,左边第二个权重是5,权重越大,输出的pwm值就越大,所以当小车偏移角度比较大时,也能摆回来。

使用数字量循迹对参数的配置要求比较高,但是更适合于那种复杂赛道,比如直角,岔路,十字路口等。模拟量灰度(一般三路就ok了,但是需要对adc采集到的数据进行处理才可以使用pid)更适合与那种简单赛道基本都是直线的那种。

无论是那种循迹模块在测试时都会出现小车频繁左右摇摆的情况(即使加入了积分控制也不行),此时就需要用到pid死区

当小车偏差非常小的适合不做处理,会有效解决掉小车摇摆的情况。