• 单片机之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 = Kp*Error_1 + Ki*(Error_1+Error_2+Error_3+......+Error_n) + Kd*(Error_1-Error_2)

    增量式

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

        PID(k) =Sp + Si + Sd = Kp*Error_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 = Kp*Error_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 ",AclValue); AclValue += PID(); i--);
        } 

    return 0;
    }

    运行结果:

        

  • 相关阅读:
    MY_0003:设置界面显示单位
    H5_0024:对于事先无法确定css大小的情况,可以通过JS动态修改
    H5_0023:html页面禁止放大缩小页面
    MY_0002:导出单位设置
    MY_0001:添加命令到自定义工具栏
    H5_0020:判断安卓苹果平台
    Web_0003:关于PHP上传文件大小的限制
    H5_0019:JS中定义json结构
    H5_0018:z-index失效的原因
    H5_0017:通过元素自定义属性值获取元素对象,并获取属性值
  • 原文地址:https://www.cnblogs.com/listenscience/p/9648374.html
Copyright © 2020-2023  润新知