PID算法

作者: 恰似一碗咸鱼粥 | 来源:发表于2019-07-15 17:24 被阅读0次

    1.比例控制

    设定一个标准值S_v,传感器每次返回一个值P_v,这两个值之差构成了一个序列E_1,E_2,...,E_k,每次根据这个偏差输出一个POUT=K_pE_k+OUT_0,OUT0为偏置值,Kp为比例系数。其中偏差包括当前偏差、历史偏差和最近偏差。

    2.积分控制

    对每一次得到传感器的返回值E_k,返回之前所有偏差值之和S_kIOUT=K_pS_k,但是单纯的积分控制也会出现问题,如果历史的偏差值是好的,便不再管现在的偏差值到底是大是小,会导致历史情况干扰当前情况。所以与比例控制相同,我们也许增加一个偏置值IOUT=K_pS_k+OUT_0

    3.微分控制

    前一个时刻差值为E_{k-1},当前时刻差E_{k},对这两个时间点,将其偏差相减。D_k=E_k-E_{k-1},它可以说明我们的偏差的变化趋势。同样也会加一个偏置,D_k=E_k-E_{k-1}+OUT_0,out0用于维持。

    4.参数设置

    PID_{out}=K_p*(E_k+S_k+D_k)+OUT_0

    (1)Sk处理

    S_k=\frac{1}{T_i}*\sum_{k=0}^{n}E_k*T,T称为采样周期,即间隔一部分时间,保证上一次算出得结果已经输出,在不同的情况下,采样周期要改变。Ti称为积分常数,它是人为确定的,它越大,则PID最终输出结果越强,反之则削弱。若果Ti过小,则非常容易产生过冲,即先超过额定值,再慢慢下降到额定值。积分项在比例项失效时发生作用。

    (2)Dk处理

    D_k=\frac{E_k-E_{k-1}}{T}*T_d,这里的T也是采样周期,Td为微分常数。

    此时新的单片机中PID算法表达式:
    OUT=K_pE_k+K_p\frac{T}{T_i}S_k+K_p\frac{T_d}{T}(E_k-E_{k-1})+out_0
    这种方法称为位置式PID,但是有大量历史数据累加,计数比较繁琐。

    5.增量式PID

    对于控制系统本身具有记忆功能,可以采用增量式PID
    增量式PID即\Delta out=out_k-out_{k-1}

    6.C语言PID伪代码

    //pid.h
    #ifndef _pid_
    #define _pid_
    #include "stm32f10x_conf.h"
    
    typedef struct{
        float Sv;//用户设定值
        float Pv;//实际值
    
        float Kp;
        float T;//计算周期或者采样周期
        float Ti;
        float Td;
    
        float Ek,Ek_1;//本次偏差与上一次偏差
        float SEk;//历史偏差之和
    
        float OUT0;
    
        float C10ms;
        float pwmcycle;//pwm周期
    
        float OUT;//本次应该输出的值
    }PID;
    
    extern PID pid;//存放pid算法所需的数据 
    void PID_calc();
    #endif
    
    //pid.c
    #include "pid.h"
    
    PID pid;//存放PID的数据
    
    void PID_calc(){//pid计算
        float DelEk;
        float ti=pid.T/pid.Ti;
        float ki=ti*pid.Kp;
    
        float td=pid.Td/pid.T;
        float kd=pid.Kp*td;
    
        float Iout,Pout,Dout;
    
        if(pid.C10ms<pid.T/10){
            //计算周期没到
            return;
        }
        pid.Ek=pid.Sv-pid.Pv;//得到当前的偏差值
    
        pid.SEk+=pid.Ek;//历史偏差总和 
    
        DelEk=pid.Ek-pid.Ek_1;//最近两次的偏差之差
    
        Pout=pid.Kp*pid.Ek;//比例
        Iout=pid.SEk*ki;//积分
        Dout=kd*DelEk;//微分
    
        if(Pout+Iout+Dout+pid.OUT0>pid.pwmcycle){
            pid.OUT=pid.pwmcycle;
        }
        else if(Pout+Iout+Dout+pid.OUT0<0){
            pid.OUT=0;
        }else{
            pid.OUT=Pout+Iout+Dout+pid.OUT0;
        }
    
        pid.Ek_1=pid.Ek;//更新偏差 
    
        pid.C10ms=0;
    }
    

    对于控制输出部分:

    void PID_out{
        static u16 pw;
        pw++;
        if(pw>=pid.pwmcycle){
            pw=0;
        }
        //每次dosomething为1ms
        if(pw<pid.OUT){
            //do something
        }
        else{
            //do something else
        }
    }
    

    相关文章

      网友评论

          本文标题:PID算法

          本文链接:https://www.haomeiwen.com/subject/ebbnkctx.html