C语言实现PID之算法

首先,要知道,PID拿来干什么?我说说我的理解。

好像一个漏水的水桶,高2米,我们要加水到1米。现在我们要往里面加水,那怎么加呢,每次加多少呢?

又好比温室大棚,我们要控制这个温度到20度,大棚会导热散热,环境的影响,都会使温度发生变化,加热器怎么加热呢?

这就用PID了。就拿漏水水桶加水来说吧。

先看看PID系统长什么样。

PID(proportion integration differentiation)其实就是指比例,积分,微分控制

理解一下这个图,

一个实际测量到的值output(即上次你执行命令后产生的),一个设定值setpoint。

Error=Setpoint-Output

进入PID系统,求和之后,输出到执行器Process。

再次测量Output,回馈给系统,再与Setpoint对比,直到Error为0。

 PID系统理想方程

kp              比例系数

err(r)     理想和实际的偏差

T1              积分系数

TD              微分系数

系数都是调节作用,固定值。

err(r) 是一个变化的值。它是我们想要水桶加到1米,与实际中你每次加水总要漏掉0.2米的水桶,实际测的高度的值。

第一次加水,加进去1米,它又漏掉0.2,剩着0.8。所以实际值为0.8。

err(r) =1-0.8=0.2

静差、稳态误差

再往里加水,加kp*err(r) ,但总不能加到整整1米,液位离我们想要的高度总是差那么一点,这也就是所谓的稳态误差,或者叫静差

具体 P、I、D各是什么作用自己了解。我给出两篇不错的文章连接。

http://www.sohu.com/a/209432412_488169

https://blog.csdn.net/qq_25352981/article/details/81007075

最简单的位置型PID 代码实现:

struct _pid
{
    float SetSpeed;            //定义设定值
    float ActualSpeed;         //定义实际值
    float err;                 //定义偏差值
    float err_last;            //定义上一个偏差值
    float Kp,Ki,Kd;            //定义比例、积分、微分系数
    float voltage;             //定义电压值(控制执行器的变量)
    float integral;            //定义积分值
}pid;
void PID_init()
{
    printf("PID_init begin \n"); //开始初始化PID,其实就设定 PID系数

    pid.SetSpeed=0.0;         //你想要执行器输出的值
    pid.ActualSpeed=0.0;      //实际从执行器测量得到的值

    pid.err=0.0;
    pid.err_last=0.0;        //上一次的误差
    pid.voltage=0.0;         //执行器的输入值
    pid.integral=0.0;        //积分值

    pid.Kp=0.2;
    pid.Ki=0.015;
    pid.Kd=0.2;

    printf("PID_init end \n");
}
float PID_realize(float speed)
{
    pid.SetSpeed=speed;

    pid.err=pid.SetSpeed-pid.ActualSpeed;    //计算误差

    pid.integral+=pid.err;                   //积分值就是误差的积累

    pid.voltage=pid.Kp*pid.err+pid.Ki*pid.integral+pid.Kd*(pid.err-pid.err_last);

    pid.err_last=pid.err;

    pid.ActualSpeed=pid.voltage*1.0;

    return pid.ActualSpeed;
}

增量式PID  代码实现



struct _pid
{
    float SetSpeed;            //定义设定值
    float ActualSpeed;         //定义实际值
    float err;                 //定义偏差值
    float err_next;            //定义上一个偏差值
    float err_last;            //定义最上前的偏差值
    float Kp,Ki,Kd;            //定义比例、积分、微分系数
}pid;

void PID_init()
{
    pid.SetSpeed=0.0;
    pid.ActualSpeed=0.0;
    pid.err=0.0;
    pid.err_last=0.0;
    pid.err_next=0.0;
    pid.Kp=0.2;
    pid.Ki=0.015;
    pid.Kd=0.2;
}

float PID_realize(float speed)
{
    pid.SetSpeed=speed;

    pid.err=pid.SetSpeed-pid.ActualSpeed;

    float incrementSpeed=pid.Kp*(pid.err-pid.err_next)+pid.Ki*pid.err+pid.Kd*(pid.err-2*pid.err_next+pid.err_last);

    pid.ActualSpeed+=incrementSpeed;

    pid.err_last=pid.err_next;

    pid.err_next=pid.err;

    return pid.ActualSpeed;
}

猜你喜欢

转载自blog.csdn.net/fzf1996/article/details/88547887
今日推荐