这是一篇我在学习PID控制算法的过程中的学习记录。在一开始学习PID的时候,我也看了市面上许多的资料,好的资料固然有,但是更多的是不知所云。(有的是写的太过深奥,有的则是照搬挪用,对原理则一问三不知)这一直让我对PID摸不着头脑。所以我打算从0开始去一层层学习它,直到自己掌握它的精髓。我不认为我有多聪明,所以相当多的部分我都写的很详细,觉得过于冗余的小伙伴可以跳着看。
我并不是计算机科学\电控类专业的学生,所以对知识的理解可能有不到位的地方,还请大家指正。
最后,希望这篇长文对大家有所帮助,这也是我完成它的目标之一。
这里强烈建议还不理解PID基本原理的同学观看视频:【自动控制原理】12_PID控制器_Matlab/Simulink仿真【开场三分钟闲话】_哔哩哔哩_bilibili
单级PID也就是只使用一个PID控制块。一般讲到PID,大家都喜欢用调节洗澡水的水温来举例:
然后将上面三项相加,就得到了基本的PID控制:
即下图
谈谈我对于PID控制的一些理解:
以上就是一个简单的PID控制系统的介绍。从实现来看,其实有着两种不同的实现方式,一种叫位置式PID,另外一种则为增量式PID。其中位置式PID我较少在平衡控制等项目中见过,而增量式PID则大量运用在电机的控制上(驱动平衡类项目),下面来简单说一下这两种PID控制的实现。
其中我们知道PID的公式如下:
但是我们会选用下面这个式子来进行实际的工程运用。可以看到除了积分变为累加之外(毕竟现实中数据都是一段一段不是连续的),D(微分项)中的形式变了,这是为了避免一个被称为“微分冲击”的现象,具体的原因在系列3中会有提到,这里可以暂时不去管它。
这里使用的是以tank_like模型(即四个电机的角度固定,靠转动的差速转弯的小车模型,与之相对的是Car_like模型,前面两个轮子可以偏转一定角度转弯)的四轮小车为例,需要控制其四轮转动同步(也就是能走直线)。
tank_like模型与Car_like模型:
为了能够判断小车每个轮子的转动方向以及转动的幅度,需要使用带有编码器的电机,或者使用光电门也是同样的原理。这样就能获取到小车每一个轮子的实时速度值,与目标的速度 作差 后就是这个PID系统的输入。
而小车上单片机向电机输入的PWM波(可以控制小车电机油门),就这个PID系统的输出。
如下图:
//位置式PID
//定义所需要的变量
float Kp, Ki, Kd;
float Motor1_speed;//电机当前的速度
float target_speed;//我们需要电机达到的速度
float err_now;//当前速度与电机期望值的差,也就是当前的误差值
float err_last;//上一次计算的误差值
float err_Sum;//积分项,将累计时间内所有的误差值
float output;//经过PID算法后输出的数据,其实是一个控制PWM占空比的参数,我们只需要直接放在输出PWM的函数里就好了
//PID算法
err_now = target_speed -Motor1_speed;
err_Sum += err_now;
if(err_Sum > x) err_Sum = x;//这里需要设定一个极限值,以防积分变量溢出,其实一般来说并不会达到这个极限值,因为误差并不都是正数
//没有对D进行操作
output = Kp * err_now + Ki * err_Sum +Kd * (err_now - err_last);//PID公式
if(output > x) output = x;//这里需要对输出也进行一个限制,这里倒不是限制溢出,而是PWM输出的参数本身就有最大值,超过了就无效了。
TIM_SetCompare1(TIMx, output);//对产生PWM的定时器通道一进行输出
err_last = err_now;//将使用完的当前误差值赋给上一次的误差值,进行下一轮循环
增量式PID的原理就是不直接使用每一次PID产生的输出,而是将两次PID产生的输出相减,得到一个PID增量,再使用这个增量对系统进行输出。与位置式PID不同的地方就在于因为需要使用到前后两次的PID公式,那么也就需要当前误差、上一次误差与上上次的误差。在得到输出的增量之后就类似使用积分项一样直接将时间上的每一次增量相加,得到的结果在TIM_SetCompare1()中输出就可以,代码就不赘述了。