单片机之C语言实现简单的PID算法

说到PID算法,想必大部人并不陌生,PID算法在很多方面都有重要应用,比如电机的速度控制,恒温槽的温度控制,四轴飞行器的平衡控制等等,作为闭环控制系统中的一种重要算法,其优点和可实现性都成为人们的首选。下面简单来讲解一下PID算法:

首先PID算法是有比例,积分,微分三部分组成,先说下比例部分,所谓比例部分,就是呈线性关系,举个例子,一个电热丝加热水,开始的时候温度很低,离50℃很大,这时应该加大功率,离目标温度越大,其功率应该越大,反之越小,这就是比例部分。

乍一看,既然比例部分已经可以控制温度了为啥还需要积分和微分部分呢,难道是多此一举么?其实不然,在实际中会出现这种情况,当加热到50℃时,系统很难停止下来,而是会持续一段时间,这样就会超过预设值,所以仅有比例控制并不完美,这是就需要积分部分和微分部分。积分部分就是把之前的误差全部累加起来,这样起始时由于误差很大加热功率就大,随着接近预设值后功率开始减少,微分部分就是起始时温度增加很快,表示此时需要很大的功率,随着温度接近预设值,其斜率开始减小最后为零,意味着功率也减少,当然很难为零,一般在一定的范围内波动。

现在开始用C语言来实现PID算法:

位置式:

比例部分:

Kp:比例系数  SetValue:预设值  FactValue:当前实际值  Error_1:当前误差

则比例部分为:

Sp  =   Kp*(SetValue - FactValue)

或者

Sp  =  Kp*Error_1

注解:Sp大小反应需要控制的量大小,比如Sp越大,功率越大。当Sp为负值时,表示要超过预设值,如果是电机,则需要反转

积分部分:

Ki:积分系数  Error_1:当前误差  Error_2:上一次误差  Error_3:上上一次误差 …Error_n:开始时的误差

则积分部分为:

Si  =  Ki*(Error_1+Error_2+Error_3+…+Error_n)

注解:因为整个是一个过程,所以上一次误差其实就是上一次的当前误差

微分部分:

Kd:微分系数  Error_1:当前误差  Error_2:上一次误差

则微分部分为:

Sd  =  Kd*(Error_1-Error_2)

综上部分的PID得:

PID=Sp + Si + Sd = KpError_1 + Ki(Error_1+Error_2+Error_3+…+Error_n) + Kd*(Error_1-Error_2)

增量式:

将上述推导的PID记作时间为k时刻的PID控制量,则

PID(k) =Sp + Si + Sd = KpError_1(k) + Ki(Error_1(k)+Error_2(k-1)+Error_3(k-2)+…+Error_n(0)) + Kd*(Error_1(k)-Error_2(k-1))        1

将上式k=k-1代入得:

PID(k-1) =Sp + Si + Sd = KpError_1(k-1) + Ki(Error_1(k-1)+Error_2(k-2)+Error_3(k-3)+…+Error_n(0)) + Kd*(Error_1(k-1)-Error_2(k-2)) 2

1-2得:

PID(k) - PID(k-1) = Kp*(Error_1(k)-Error_1(k-1)) + Ki*(Error_1(k)) + Kd*(Error_1(k)-2*Error_2(k-1)+Error_2(k-2))

将PID(k) - PID(k-1)记作detPID

detPID = Kp*(Error_1(k)-Error_1(k-1)) + Ki*(Error_1(k)) + Kd*(Error_1(k)-2*Error_2(k-1)+Error_2(k-2))

这样就得到了增量式的PID算法,其计算的结果为增加的控制量

增量式的PID有个好处就是只与当前三个误差量有关系,与其他无关,这样就简化的处理过程,而且提高了精度,下面是PID源码:

/文件名称:PID.h/

#ifndef PID_H
#define PID_H

extern float Kp,Ki,Kd; //系数(全局变量)
extern float AclValue; //实际值
extern float SetValue;

int PID(void);

#endif

/########################################################################
文件名:PID.c
编写人:张**
时间: 2018.9.7
备注:无
#########################################################################
/

#include “PID.h”

float Kp=10,Ki=0.8,Kd=0.5; //系数

float SetValue=2000; //设定值

float AclValue=0; //实际

float Error1=0,Error2=0,Error3=0; //误差

/* 下面为增量式PID算法 */

/**********************************************************************************
函数名:PID
返回值:输出增量
参数:无
备注:当输出大于0表示小于预设值,当输出小于0表示大于预设值
***********************************************************************************/
int PID(void)
{
float OutValue =0;
Error3 = SetValue - AclValue;

OutValue = Kp*(Error3-Error2)+Ki*(Error3)+Kd*(Error3-2*Error2+Error1);

Error1=Error2;         //这部分是迭代,因为上次的误差就是上次的当前误差
Error2=Error3;

if(OutValue>3000)        //这部分是规定最大输出增量
    OutValue=3000;
if(OutValue<-3000)
    OutValue=-3000;

return OutValue;

}

下面是计算机给出的模拟代码;

#include “stdio.h”

float Kp=10,Ki=2,Kd=0.5; //系数

float SetValue=1256; //设定值

float AclValue=0; //实际

float Error1=0,Error2=0,Error3=0; //误差

/* 下面为增量式PID算法 */

/**********************************************************************************
函数名:PID
返回值:输出增量
参数:无
备注:当输出大于0表示小于预设值,当输出小于0表示大于预设值
***********************************************************************************/
int PID(void)
{
float OutValue =0;
Error3 = SetValue - AclValue;

OutValue = Kp*(Error3-Error2)+Ki*(Error3)+Kd*(Error3-2*Error2+Error1);

Error1=Error2;
Error2=Error3;

return OutValue;

}

int main(void)
{
unsigned int i=1000;
while(i)
{

    PID();  //特别注意这里:必须要运行,因为需要执行这一步:Error1=Error2; Error2=Error3;         printf("当前实际值为:%f \n",AclValue); AclValue += PID(); i--;
}     return 0;}

运行结果:

单片机之C语言实现简单的PID算法_第1张图片
未完待续。。。。。。

谢谢

你可能感兴趣的:(单片机,编程,马达控制算法)