zoukankan      html  css  js  c++  java
  • 单片机之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;
    }

    运行结果:

        

  • 相关阅读:
    CS224n, lec 10, NMT & Seq2Seq Attn
    CS231n笔记 Lecture 11, Detection and Segmentation
    CS231n笔记 Lecture 10, Recurrent Neural Networks
    CS231n笔记 Lecture 9, CNN Architectures
    CS231n笔记 Lecture 8, Deep Learning Software
    CS231n笔记 Lecture 7, Training Neural Networks, Part 2
    pytorch坑点排雷
    Sorry, Ubuntu 17.10 has experienced an internal error
    VSCode配置python插件
    tmux配置与使用
  • 原文地址:https://www.cnblogs.com/listenscience/p/9648374.html
Copyright © 2011-2022 走看看