上一节讲了PID算法概述(见帖子 https://bbs.elecfans.com/jishu_580161_1_1.html),继续讲PID算法的分类与应用实例。
将偏差的比例(Proportion)、积分(Integral)和微分(Differential)通过线性组合构成控制量,用这一控制量对被控对象进行控制,这样的控制器称PID控制器。PID按其控制量可分为:模拟PID控制和数字PID控制,其中数字PID控制算法又分为位置式PID和增量式PID控制算法,但是无论哪种分类,都大致符合如图所示的PID模型。
或许一看这个图,感觉好难懂,因为要涉及高数中的微积分运算,不用慌,接下来,我们以一个实例,并以计算量最小的增量式PID控制算法为例,来介绍PID。此时大家可能觉得PID不可能和C语言、单片机扯上关系,更不可能与温度控制系统扯上关系,要只能否扯上关系,请看接下来的实例应用。
在讲述实例之前,大家需要了解一下增量式PID的运算公式,这个表达式比较多,加之个人运算的习惯,更是层出不穷,这里以较为常用的为例,望读者掌握。
PID = Uk + KP*[E(k)-E(k-1)] + KI*E(k) + KD*[E(k)-2E(k-1)+E(k-2)];
在单片机中运用PID,处于速度和RAM的考虑,一般不用浮点数,这里以整型变量为例来讲述PID在单片机中的应用,等大家以后学了像STM32F4这样的M4核处理器以后,就可以考虑用浮点数来计算了。由于是用整型来做的,所以不是很精确,但是对于一般的场合来说,这个精度也够了,关于系数和温度笔者都统统放大了10倍,所以精度不是很高。但是也不是那么低,大部分的场合也是够了。实在觉得精度不够,可以再放大10倍或者100倍处理,但是要注意不能超出整个数据类型的范围就可以了。本程序包括PID计算和输出两部分,当偏差>10度全速加热,偏差在10度以内为PID计算输出,具体的参考代码参见下面(该实例以飛天一號开发板为硬件平台)。
难理解的加了注释,不难理解的,没必要说。剩下的就是将温度传感器部分的子程序综合进来,之后动手自己做实物,并调试程序,只有多实践,才是“玩”好单片机王道,因此强烈建议读者以FSST15开发板为平台,同时借助LM75A温度传感器,再搭建一个温控设备,亲自进行试验,在实际中不断提高自己的能力。
这里读者需要注意,前面讲述的口诀法和经验值法似乎没用到,那是因为PID算法除了增量式以外,还有两种:位置式和微分先行法,这些知识点,才是后面四轴控制的核心,笔者放后面再来讲述,感兴趣的读者可以先去看看下面链接的博文,写的甚好,通俗易懂。
/* http://blog.sina.com.cn/s/blog_7c7e2d5a01011ta9.html */
老外的位置式PID算法
该PID算法例程摘自网络,作者不详,版权归原创作者所有。为了保持地道,笔者没有做一点点改动,其中中文注释为笔者所加。平心而论,老外的代码确实很独特,思路也很清晰,源码如下,具体含义留读者慢慢研究了,这里不赘。
- #include
- #include
- struct _pid
- {
- int pv; //integer that contains the process value 过程量
- int sp; //integer that contains the set point 设定值
- float integral; //积分值 -- 偏差累计值
- float pgain;
- float igain;
- float dgain;
- int deadband; //死区
- int last_error;
- };
- struct _pid warm,*pid;
- int process_point, set_point,dead_band;
- float p_gain, i_gain, d_gain, integral_val,new_integ;
- //-----------------------------------
- //pid_init DESCRIPTION This function initializes the pointers in the _pid structure to the //process
- //variable and the setpoint.*pv and *sp are integer pointers.
- //-----------------------------------
- void pid_init(struct _pid *warm, int process_point, int set_point)
- {
- struct _pid *pid;
- pid = warm;
- pid->pv = process_point;
- pid->sp = set_point;
- }
- //-----------------------------------
- //pid_tune DESCRIPTION Sets the proportional gain (p_gain), integral gain (i_gain),
- //derivitive gain (d_gain), and the dead band (dead_band) of a pid control structure _pid.
- //设定PID参数 ----P,I,D,死区
- //-----------------------------------
- void pid_tune(struct _pid *pid, float p_gain, float i_gain, float d_gain, int dead_band)
- {
- pid->pgain = p_gain;
- pid->igain = i_gain;
- pid->dgain = d_gain;
- pid->deadband = dead_band;
- pid->integral= integral_val;
- pid->last_error=0;
- }
- //--------—---------------------------
- //pid_setinteg DESCRIPTION Set a new value for the integral term of the pid equation.
- //This is useful for setting the initial output of the pid controller at start up.
- //设定输出初始值
- //---------------------—--------------
- void pid_setinteg(struct _pid *pid,float new_integ)
- {
- pid->integral = new_integ;
- pid->last_error = 0;
- }
- //------------------------------------
- //pid_bumpless DESCRIPTION Bumpless transfer algorithim. When suddenly changing
- //setpoints,or when restarting the PID equation after an extended pause,the derivative of
- //the equation can cause a bump in the controller output. This function ill help smooth out
- //that bump.
- //The process value in *pv should be the updated just before this function is used.
- //pid_bumpless 实现无扰切换
- //当突然改变设定值时,或重新启动后,将引起扰动输出。这个函数将能实现平顺扰
- //动,在调用该函数之前需要先更新PV值
- //-----------------------------------
- void pid_bumpless(struct _pid *pid)
- {
- pid->last_error = (pid->sp)-(pid->pv); //设定值与反馈值偏差
- }
- //------------------------------------
- //pid_calc DESCRIPTION Performs PID calculations for the _pid structure *a.
- //This function uses the positional form of the pid equation, and incorporates an integral
- //windup prevention algorithim.Rectangular integration is used, so this function must be
- //repeated on a consistent time basis for accurate control.
- //RETURN VALUE The new output value for the pid loop. USAGE #include "control.h"
- //本函数使用位置式PID计算方式,并且采取了积分饱和限制运算
- //-----------------------------------
- float pid_calc(struct _pid *pid)
- {
- int err;
- float pterm, dterm, result, ferror;
- err = (pid->sp) - (pid->pv); // 计算偏差
- if (abs(err) > pid->deadband) // 判断是否大于死区
- {
- ferror = (float) err; //do integer to float conversion only
- //once 数据类型转换
- pterm = pid->pgain * ferror; // 比例项
- if (pterm > 100 || pterm < -100)
- {
- pid->integral = 0.0;
- }
- else
- {
- pid->integral += pid->igain * ferror; // 积分项
- if (pid->integral > 100.0) // 输出为0--100%
- {
- pid->integral = 100.0; // 如果结果大于100,则等于100
- }
- else if (pid->integral < 0.0)
- // 如果计算结果小于0.0,则等于0
- pid->integral = 0.0;
- }
- dterm = ((float)(err - pid->last_error)) * pid->dgain;
- // 微分项
- result = pterm + pid->integral + dterm;
- }
- else
- result = pid->integral; // 在死区范围内,保持现有输出
- pid->last_error = err; // 保存上次偏差
- return (result); // 输出PID值(0-100)
- }
- void main(void)
- {
- float display_value;
- int count=0;
- pid = &warm;
- // printf("Enter the values of Process point, Set point, P gain, I gain, D gain n");
- // scanf("%d%d%f%f%f", &process_point, &set_point, &p_gain, &i_gain, &d_gain);
- // 初始化参数
- process_point = 30;
- set_point = 40;
- p_gain = (float)(5.2);
- i_gain = (float)(0.77);
- d_gain = (float)(0.18);
- dead_band = 2;
- integral_val =(float)(0.01);
- printf("The values of Process point, Set point, P gain, I gain, D gain n");
- printf(" %6d %6d %4f %4f %4fn", process_point, set_point, p_gain, i_gain, d_gain);
- printf("Enter the values of Process pointn");
- while(count<=20)
- {
- scanf("%d",&process_point);
- // 设定PV,SP值
- pid_init(&warm, process_point, set_point);
- // 初始化PID参数值
- pid_tune(&warm, p_gain,i_gain,d_gain,dead_band);
- // 初始化PID输出值
- pid_setinteg(&warm,0.0);
- //pid_setinteg(&warm,30.0);
- //Get input value for process point
- pid_bumpless(&warm);
- // how to display output
- display_value = pid_calc(&warm);
- printf("%fn", display_value);
- //printf("n%f%f%f%f",warm.pv,warm.sp,warm.igain,warm.dgain);
- count++;
- }
- }
复制代码
最后说明下和本文配套的STC15开发板目前正在电子发烧友销售,如果需要请戳这里购买: https://bbs.elecfans.com/product/stc15.html 下一节讲四轴飞行器的硬件模型建立。
|