PID控制器开发——位置型和增量型PID的实现

前言

位置型和增量型是PID控制器中最基础的两种方式,经过一段时间的探索之后也渐渐地知道一些他们的优劣。但我的理解可能仍然处于一个浅显的层面,因此仅仅为初学者提供参考。

什么是PID

PID是在自动控制领域运用的非常广泛的一种控制方法,P即比例单元他通过将受控单元进行一定比例的缩放来达到一个控制效果。
举个栗子,你有个容量是10的空水缸,你要将水缸里的水维持在8。
你和目标的误差error=8通过比例控制,你的输出u=p*error,那么持续下去你总能把水缸维持在8。
但是这是在理想条件下的假设,我们再来考虑另外一种情况。如果你的水缸漏水。
比如你的p是0.2,你水缸漏水的速度也是0.2,那么在你水缸的水位达到6的时候:error=2,u=p*error=0.2而你水缸漏水的速度也是0.2,那么无论你怎么加,水缸的高度只能维持在6!这就是P单元控制器存在的稳态误差。那么怎么解决呢?这就要说说I项的作用了。
I是对所有误差的累积,只要误差存在积分就会一直进行。这样就会避免稳态误差所带来的问题。
而D项,即微分项,通俗的说就是求导。在数学中求导是表示曲线的增减趋势和幅度,在这里同样适应。因此微分就相当于对未来的预测,能够起到一个阻尼的作用,可以让系统快速趋于稳定。

位置型PID和增量型PID

位置型PID是一串不连续的输出,他的输出与过去所有误差都有关,起到了误差的累积作用。而增量型PID的输出只与过去两拍的误差有关。
位置型PID输出的是控制量,而增量型PID输出的是控制量的增量。

位置型PID的公式及代码实现

u(k)=e(k)*p+d*(e(k)-e(k-1)+i*∑e
C++实现:

struct _pid{  
    double set;         //定义设定值
    double last_error;         //定义上一个偏差值  
    double Kp,Ki,Kd;         //定义比例、积分、微分系数  
    double integral;         //定义积分值  
}pid;
void init()
{
    pid.set = 0;
    pid.last_error = 0;
    pid.Kp = 0.3;
    pid.Ki = 0.01;
    pid.Kd = 0.2;
    pid.integral = 0;
}
double getPid(double actual)
{
    double error, result, d_error;
    error = actual - pid.set;
    d_error = error - pid.last_error;
    pid.integral = error + pid.integral;
    result = pid.Kp * error + pid.Kd * d_error + pid.Ki * pid.integral;
    pid.last_error = error;
    return result;
}

增量型PID的公式及代码实现

△u(k)=(error(k)-error(k-1))*p+error*d+(error(k)-2*error(k-1)+error(k-2))
u(k)=△u(k)+u(k-1)

C++实现:

struct _pid{  
    double set;         //定义设定值
    double last_error;         //定义上一个偏差值
    double pre_error;           //定义上上个偏差值
    double Kp, Ki, Kd;       //定义比例、积分、微分系数 
}pid;
void init()
{
    pid.set = 0;
    pid.last_error = 0;
    pid.pre_error = 0;
    pid.Kp = 0.3;
    pid.Ki = 0.01;
    pid.Kd = 0.2;
}
double getPid(double actual)
{
    double error, result;
    error = actual - pid.set;
    result = pid.Kp * (error - pid.last_error) + pid.Ki * error + pid.Kd * (error - 2 * pid.last_error + pid.pre_error);
    pid.pre_error = pid.last_error;
    pid.last_error = error;
    return result;
}
添加新评论