基于C++的PID控制器

来源:互联网 发布:video.js 编辑:程序博客网 时间:2024/05/17 04:03

PID控制器是一种广泛用于各种工业控制场合的控制器,它结构简单,可以根据工程经验整定参数Kp,Ki,Kd. 虽然现在控制专家提出了很多智能的控制算法,比如神经网络,模糊控制等,但是PID仍然被广泛使用。
常见的PID控制器有位置PID控制器,增量PID控制器。两个PID控制器各有自己的优点,需要根据具体的场合来使用。
pid控制器的结构框图为:
这里写图片描述
(1)位置PID
连续形式公式如下:
连续形式的位置型PID公式
也可以写成如下形式:
一般形式PID公式
为了方便软件编程实现,一般转换成离散形式,即用连加代替积分,有差分代替微分,
离散变换
离散型PID公式:
离散形式的PID公式
使用C++实现一个位置PID控制器,首先需要创建一个PID_position的类,其定义如下:

//位置式PIDclass PID_position{private:    float kp;//比例系数    float ki;//积分系数    float kd;//微分系数    float target;//目标值    float actual;//实际值    float e;//误差    float e_pre;//上一次误差    float integral;//积分项public:    PID_position();    ~PID_position(){};    PID_position(float p,float i,float d);    float pid_control(float tar,float act);//执行PID控制    void pid_show();//显示PID控制器的内部参数};

接下来,对类中声明的方法进行定义;

//位置PIDPID_position::PID_position():kp(0),ki(0),kd(0),target(0),actual(0),integral(0){    e=target-actual;    e_pre=e;}PID_position::PID_position(float p,float i,float d):kp(p),ki(i),kd(d),target(0),actual(0),integral(0){   e=target-actual;   e_pre=e;}float PID_position::pid_control(float tar,float act){    float u;    target=tar;    actual=act;    e=target-actual;    integral+=e;    u=kp*e+ki*integral+kd*(e-e_pre);    e_pre=e;    return u;}void PID_position::pid_show(){    using std::cout;    using std::endl;    cout<<"The infomation of this position PID controller is as following:"<<endl;    cout<<"       Kp="<<kp<<endl;    cout<<"       Ki="<<ki<<endl;    cout<<"       Kd="<<kd<<endl;    cout<<" integral="<<integral<<endl;    cout<<"   target="<<target<<endl;    cout<<"   actual="<<actual<<endl;    cout<<"        e="<<e<<endl;    cout<<"    e_pre="<<e_pre<<endl;}

以上代码就可以实现一个位置PID控制器,只需要实例化PID_position类对象,调用相关的方法就可以实现P位置ID控制。
位置PID结构简单,但是由于有积分项,容易产生积分饱和的现象,而且它每次输出的都是全量,此全量均和过去的输出有关,易产生累计误差。需要对其进行改进,由此产生的改进型PID控制器——增量型PID控制器。其区别在于,控制器输出的不是全量,而只是增量,每次输出均与过去的所有状态无关,而且它没有积分项,运算量小,容易实现手动到自动的无冲击切换。
增量型PID控制器的公式如下:
增量PID
可以表示为更一般的形式:
PID ABC
由此可以编写增量式PID的C++代码:
类声明为:

//增量式PIDclass PID_incremental{private:    float kp;    float ki;    float kd;    float target;    float actual;    float e;    float e_pre_1;    float e_pre_2;    float A;    float B;    float C;public:    PID_incremental();    PID_incremental(float p,float i,float d);    float pid_control(float tar,float act);    void pid_show();};

方法定义:

//增量PIDPID_incremental::PID_incremental():kp(0),ki(0),kd(0),e_pre_1(0),e_pre_2(0),target(0),actual(0){   A=kp+ki+kd;   B=-2*kd-kp;   C=kd;   e=target-actual;}PID_incremental::PID_incremental(float p,float i,float d):kp(p),ki(i),kd(d),e_pre_1(0),e_pre_2(0),target(0),actual(0){   A=kp+ki+kd;   B=-2*kd-kp;   C=kd;   e=target-actual;}float PID_incremental::pid_control(float tar,float act){   float u_increment;   target=tar;   actual=act;   e=target-actual;   u_increment=A*e+B*e_pre_1+C*e_pre_2;   e_pre_2=e_pre_1;   e_pre_1=e;   return u_increment;}void PID_incremental::pid_show(){    using std::cout;    using std::endl;    cout<<"The infomation of this incremental PID controller is as following:"<<endl;    cout<<"     Kp="<<kp<<endl;    cout<<"     Ki="<<ki<<endl;    cout<<"     Kd="<<kd<<endl;    cout<<" target="<<target<<endl;    cout<<" actual="<<actual<<endl;    cout<<"      e="<<e<<endl;    cout<<"e_pre_1="<<e_pre_1<<endl;    cout<<"e_pre_2="<<e_pre_2<<endl;}

下面可以对两个控制器进行简单的测试,这里需要对PID的参数进行整定,笔者也是通过多次试验,最终获得了比较合理的kp,ki,kd。
测试代码如下:

#include<iostream>#include"pid_controller.h"using namespace std;int main(){    //测试增量PID    PID_incremental pid1(0.35,0.65,0.005);    float target=1000.0;    float actual=0;    float pid_increment=0.0;    int N=50;    pid1.pid_show();    cout<<"target="<<target<<endl;    for(;N>0;N--)    {        pid_increment=pid1.pid_control(target,actual);        actual+=pid_increment;        cout<<"N="<<50-N<<"   actual="<<actual<<endl;    }    pid1.pid_show();    //测试位置PID    PID_position pid2(0.59,0.35,0.002);    pid2.pid_show();    cout<<"target="<<target<<endl;    N=100;    for(;N>0;N--)    {        actual=pid2.pid_control(target,actual);        cout<<"N="<<100-N<<"   actual="<<actual<<endl;    }    pid2.pid_show();    system("pause");    return 0;}

测试结果显示增量PID,28次到达目标值1000,位置PID,61次达到1000.
结果1
结果2

完整代码见https://github.com/shuoyueqishi/PID-controller

原创粉丝点击