基于C++的PID控制器

原文地址:https://blog.csdn.net/shuoyueqishilove/article/details/73824173

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

//位置式PID
class 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控制器的内部参数
};

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

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

//位置PID
PID_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;
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

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

//增量式PID
class 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();
};
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

方法定义:

//增量PID
PID_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;
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

下面可以对两个控制器进行简单的测试,这里需要对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;
}
 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

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

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值