一 PID 算法原理
在工业应用中 PID 及其衍生算法是应用最广泛的算法之一,是当之无愧的万能算法,如果能够熟练掌握 PID 算法的设计与实现过程,对于一般的研发人员来讲,应该是足够应对一般研发问题了,在我所接触的控制算法当中,PID 控制算法又是最简单,最能体现反馈思想的控制算法,可谓经典中的经典。经典的未必是复杂的,经典的东西常常是简单的,而且是最简单的,想想牛顿的力学三大定律吧,想想爱因斯坦的质能方程吧,何等的简单!简单的不是原始的,简单的也不是落后的,简单到了美的程度。先看看 PID 算法的一般形式: PID 的流程简单到了不能再简单的程度,通过误差信号控制被控量,而控制器本身就是比例、积分、微分三个环节的和。连续状态下pid 的控制规律为
二 PID 算法的离散化
上一节中,我论述了 PID 算法的基本形式,并对其控制过程的实现有了一个简要的说明,通过上一节的总结,基本已经可以明白 PID 控制的过程。这一节中先继续上一节内容补充说明一下。 1.说明一下反馈控制的原理,通过上一节的框图不难看出,PID 控制其实是对偏差的控制过程; 2.如果偏差为 0,则比例环节不起作用,只有存在偏差时,比例环节才起作用。 3.积分环节主要是用来消除静差,所谓静差,就是系统稳定后输出值和设定值之间的差值,积分环节实际上就是偏差累计的过程,把累计的误差加到原有系统上以抵消系统造成的静差。 4.而微分信号则反应了偏差信号的变化规律,或者说是变化趋势,根据偏差信号的变化趋势来进行超前调节,从而增加了系统的快速性。 假设采样间隔为 T,则在第 K T 时刻: 偏差 err(K)=rin(K)-rout(K); 积分环节用加和的形式表示,即 err(K)+err(K+1)+……; 微分环节用斜率的形式表示,即[err(K)-err(K-1)]/T; 从而形成如下 PID 离散表示形式
即 至于说 Kp、Ki、Kd 三个参数的具体表达式,我想可以轻松的推出了,这里节省时间,不再详细表示了。其实到这里为止,PID 的基本离散表示形式已经出来了。目前的这种表述形式属于位置型 PID。
三 程序分享
#include "main.h"
#include "stdlib.h"
typedef struct PID {
float SetPoint;
float P;
float I;
float D;
int LastError;
int sumERROR;
} PID;
PID pp;
u16 PID_Cal(PID *pp,u16 adc1_now_val);
u16 dac_val=1230;
u16 adc1_now_val=0;
u16 adc1_next_val=0;
int main(void)
{
pp.SetPoint=3000; pp.P=1.4; pp.I=0.1; pp.D=0.01; pp.sumERROR=0; pp.LastError=0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
uart_init(115200);
delay_init();
LED_Init();
Adc_Init();
Dac1_Init();
TIM3_Int_Init(3999,7299);
DAC_SetChannel1Data(DAC_Align_12b_R,dac_val);
while(1)
{
LED0_GREEN=!LED0_GREEN;
adc1_now_val=Get_Adc(1);
adc1_next_val=PID_Cal(&pp,adc1_now_val);
adc1_next_val=adc1_next_val+adc1_now_val;
DAC_SetChannel1Data(DAC_Align_12b_R,adc1_next_val);
printf("%d\r\n",adc1_now_val);
delay_ms(500);
}
}
u16 PID_Cal(PID *pp,u16 adc1_now_val)
{
int dERROR=0, ERROR=0,mid_pid_val=0;
ERROR=pp->SetPoint-adc1_now_val;
pp->sumERROR+=ERROR;
dERROR=ERROR-pp->LastError;
pp->LastError=ERROR;
if(pp->sumERROR>600)
pp->sumERROR=600;
if(pp->sumERROR<-600)
pp->sumERROR=-600;
mid_pid_val=pp->P*ERROR+pp->I*pp->sumERROR+pp->D*dERROR;
if(mid_pid_val>200)
mid_pid_val=200;
else if(mid_pid_val<0)
mid_pid_val=0;
adc1_next_val=mid_pid_val;
return adc1_next_val;
}
此外,在编写程序之前做了很多前期工作,手头有相当一部分PLC的资料,有需要者可留下联系方式我将其分享。
|