PID算法入门与C语言代码实现

PID算法的入门理解以及C代码实现

在结束了自控原理的学习后,了解到PID算法是一种万能算法,在课设中也是经常使用到的一种算法,所以想具体的来进行以下总结与学习,如果有错漏的地方,欢迎大家共同来探讨与批评指正,嘿嘿。


什么是PID算法

PID三个字是英文单词比例(Proportion),积分(Integral),微分(Differential coefficient)的缩写,顾名思义,PID控制就是由比例、积分、微分三种控制方法综合起来来对系统进行控制的方法,比如,飞行器要稳定飞行,而不是忽上忽下,机器人要稳定准确快速的到达目标,而不走偏,都可以用PID算法来进行反馈调节,从而让执行器做出最有利于达成目标的动作,在工程领域有着广泛的应用。


一、三大控制算法的作用以及matlab仿真演示

PID 控制器(Proportion Integration Differentiation,比例积分微分控制器)作为最早实用
化的控制器已有 70 多年的历史,是目前工业控制中应用最广泛的控制器。PID 控制器由于
其结构简单实用,且使用中无需精确的系统模型等优点,因此,95%以上的现代工业过程控
制中仍然采用 PID 结构。下图就是PID控制器的基本结构,仿真会基于如下结构进行

在这里插入图片描述
PID 控制器由比例单元 P、积分单元 I 和微分单元 D 三部分组成,其结构原理框图如图 6-1
所示。简单来说,PID 控制器就是对输入信号 r(t)和输出信号c(t)的差值 e(t)(即误差信号)进行比
例、积分和微分处理,再将其加权和作为控制信号u(t)来控制受控对象,从而完成控制过程的。
PID控制器的公式如下图所示:
在这里插入图片描述
式中, K P 、 K I 和 K D 分别为比例、积分和微分系数; T I 和 T D 分别为积分和微分时间。
一个 PID 控制器的设计重点在于设定 K P 、 K I 和 K D 三个参数的值。实际使用时,不一定
三个单元都具备,也可以只选取其中的一个或两个单元组成控制器

(1)比例调节的作用:

比例调节是按比例反应系统的偏差,系统一旦出现了偏差,比例调节立即产生调节作用用以减少偏差。比例控制只改变系统增益,不影响相位。仅采用比例控制时系统输出存在稳态误差。增大 K P 可以提高系统开环增益,减小系统稳态误差,但是会降低系统稳定性,甚至可能造成闭环系统的不稳定。,比例控制器的输出与输入误差信号成比例关系,传递函数如下
G(s)=Kp
接下来matlab仿真说明,比例调节的优缺点:
系统框图如下:
在这里插入图片描述
其中
在这里插入图片描述
在控制单元施加比例控制,并且采用不同的比例系数 K P =0.1 , 0.5 , 1 , 2 , 5 , 10 ,观察各比例系数下系统的单位阶跃响应及控制效果,matlab程序如下:

Kp=[0.1,0.5,1,2,5,10];
Go=tf(1, conv(conv([1,1],[2,1]),[3,1]) )%系统开环传递函数
for i=1:6
G=feedback(Go.*Kp(i),1)%不同比例系数下的系统闭环传递函数
step(G); hold on; %求系统的单位阶跃响应
end
gtext('Kp=0.1')gtext('Kp=0.5')gtext('Kp=1')%放置 Kp 值的文字注释
gtext('Kp=2')gtext('Kp=5')gtext('Kp=10')

运行程序得到不同比例系数下的系统单位阶跃响应曲线,如下图所示:
在这里插入图片描述
从图 中可以看出,随着比例系数 K P 值的增大,系统的响应速度加快,稳态误差减小,超调量却在增加,调节时间变长,而且随着 K P 值增大到一定程度,系统最终会变得不稳定。这也验证了前面对比例控制的描述。

(2)积分调节的作用:

是使系统消除稳态误差,提高无差度。因为有误差,积分调节就进行,直至无差,积分调节停止,积分调节输出一常值。积分作用的强弱取决与积分时间常数Ti,Ti越小,积分作用就越强。反之Ti大则积分作用弱,加入积分调节可使系统稳定性下降,动态响应变慢。积分作用常与另两种调节规律结合,组成PI调节器或PID调节器,单独的积分单元的引入会带来相位滞后,为系统的稳定性带来不良影响,其传递函数为G(s)=Ki/s,仍然使用上面的框图
在这里插入图片描述
在控制单元施加积分控制 1/s ,观察施加积分控制前后系统稳态误差的变化,matlab代码如下:

Go=tf(1, conv([1,1],[2,1]) )%系统开环传递函数
Gc=tf(1,[1,0])%积分控制函数
subplot(2,1,1)step(feedback(Go,1))%原系统闭环传递函数的单位阶跃响应曲线
title('加积分控制前')subplot(2,1,2)step( feedback(Go*Gc,1))%加积分控制后系统单位阶跃响应曲线
title('加积分控制后')

运行程序得到加积分控制前后系统的单位阶跃响应曲线,如下图所示。
在这里插入图片描述
从图 中可以看出,加入积分控制前,系统的稳态误差为 0.5 ,加入积分控制后,系统的稳态误差被减小为 0 ,这也验证了积分控制可以消除稳态误差的作用。

(3)微分调节的作用:

微分作用反映系统偏差信号的变化率,具有预见性,能预见偏差变化的趋势,因此能产生超前的控制作用,在偏差还没有形成之前,已被微分调节作用消除。因此,可以改善系统的动态性能。在微分时间选择合适情况下,可以减少超调,减少调节时间。微分作用对噪声干扰有放大作用,因此过强的加微分调节,对系统抗干扰不利。此外,微分反应的是变化率,而当输入没有变化时,微分作用输出为零。微分作用不能单独使用,需要与另外两种调节规律相结合,组成PD或PID控制器。

二、从计算机控制与算法的角度解析PID控制

1.模拟PID控制

框图如下:
在这里插入图片描述
其中 ,r(t)为参考输入或称为设定值,y(t)为系统输出,e(t)=r(t)-y(t)为偏差,u(t)为PID控制器的输出,Kp为比例系数,Ti为积分时间常数,Td为微分时间常数,G(s)为被控对象传递函数。时域上可以写成:
在这里插入图片描述
经过拉普拉斯变换后并整理得D(s):
在这里插入图片描述
其中Ki=Kp/Ti称为积分系数,Kd=Kp*Td称为微分系数

2.数字PID控制

当采样周期T足够小时,可以得到如下公式:
在这里插入图片描述

(1)位置式算法:

展开上述式子,并且令积分系数Ki=Kp*T/Ti,微分系数Kd=Kp*Kd/T,则可以得到:
在这里插入图片描述
用语言来表述这个公式就是:
PID偏差=比例系数 * 当前偏差+积分系数 * 偏差之和+微分系数 * (当前偏差-上次偏差)
总结下位置式控制算法的特点:
(1)输出控制量u(k)与各次采样值相关,需要占用较多的存储空间。
(2)计算u(k)需要做误差值的累加,容易产生较大的累加误差,甚至产生累加饱和现象。
(3)控制量u(k)以全量输出,误动作影响较大。当计算机出现故障时,u(k)的大幅度变化会引起执行机构位置的大幅度变化。

以下是基于C语言的位置式PID控制算法的代码:

=====================================================================
================================*/
#include <reg52.h>
#include <string.h> //C 语言中 memset 函数头文件
/*===================================================================
=================================
PID Function
The PID (比例、积分、微分) function is used in mainly
control applications. PIDCalc performs one iteration of the PID
algorithm.
While the PID function works, main is just a dummy program showing
a typical usage.
=====================================================================
================================*/
typedef struct PID {
double SetPoint; // 设定目标 Desired value
double Proportion; // 比例常数 Proportional Const
double Integral; // 积分常数 Integral Const
double Derivative; // 微分常数 Derivative Const
double LastError; // Error[-1]
double PrevError; // Error[-2]
double SumError; // Sums of Errors
} PID;
/*===================================================================
=================================
PID 计算部分
=====================================================================
================================*/
double PIDCalc( PID *pp, double NextPoint )
{
double dError, Error;
Error = pp->SetPoint - NextPoint; // 偏差
pp->SumError += Error; // 积分
dError = Error - pp->LastError; // 当前微分
pp->PrevError = pp->LastError;
pp->LastError = Error;
return (pp->Proportion * Error // 比例项
+ pp->Integral * pp->SumError // 积分项
+ pp->Derivative * dError // 微分项
);
}
/*===================================================================
=================================
Initialize PID Structure PID 参数初始化
=====================================================================
================================*/
void PIDInit (PID *pp)
{
memset ( pp,0,sizeof(PID));
}
/*===================================================================
=================================
Main Program 主程序
=====================================================================
================================*
double sensor (void) // Dummy Sensor Function
{
return 100.0;
}
void actuator(double rDelta) // Dummy Actuator Function
{}
void main(void)
{
PID sPID; // PID Control Structure
double rOut; // PID Response (Output)
double rIn; // PID Feedback (Input)
PIDInit ( &sPID ); // Initialize Structure
sPID.Proportion = 0.5; // Set PID Coefficients
sPID.Integral = 0.5;
sPID.Derivative = 0.0;
sPID.SetPoint = 100.0; // Set PID Setpoint
for (;;) { // Mock Up of PID Processing
rIn = sensor (); // Read Input
rOut = PIDCalc ( &sPID,rIn ); // Perform PID Interation
actuator ( rOut ); // Effect Needed Changes
}

(2)增量式算法:

当执行机构不需要控制量的全值而需要其增量时,可由位置式推导出增量式 PID 控制算法。根据上面的u(k),写出u(k-1),然后两个式子相减,得到:
在这里插入图片描述
用语言来表述公式就是:
PID偏差 = 比例×(当前偏差 - 上次偏差) + 积分 * 当前偏差 + 微分 * (当前偏差 - 2×上次偏差+上上次偏差)

增量式算法的特点:
(1)可以节省存储空间
(2)只输出控制增量,误动作影响小。
C语言代码如下:

/*==================== =====================================================
PID Function
The PID (比例、积分、微分) function is used in mainly
control applications. PIDCalc performs one iteration of the PID
algorithm.
While the PID function works, main is just a dummy program showing
a typical usage.
==========================================================================*/
typedef struct PID
{
int SetPoint; //设定目标 Desired Value
long SumError; //误差累计
double Proportion; //比例常数 Proportional Const
double Integral; //积分常数 Integral Const
double Derivative; //微分常数 Derivative Const
int LastError; //Error[-1]
int PrevError; //Error[-2]
} PID;
static PID sPID;
static PID *sptr = &sPID;
/*================================================================================
Initialize PID Structure PID 参数初始化
===============================================================================*/
void IncPIDInit(void)
{
sptr->SumError = 0;
sptr->LastError = 0; //Error[-1]
sptr->PrevError = 0; //Error[-2]
sptr->Proportion = 0; //比例常数 Proportional Const
sptr->Integral = 0; //积分常数 Integral Const
sptr->Derivative = 0; //微分常数 Derivative Const
sptr->SetPoint = 0;
}
/*===============================================================================
增量式 PID 计算部分
=================================================================================*/
int IncPIDCalc(int NextPoint)
{
register int iError, iIncpid; //当前误差
iError = sptr->SetPoint - NextPoint; //增量计算
iIncpid = sptr->Proportion * iError //E[k]项
- sptr->Integral * sptr->LastError //E[k-1]项
+ sptr->Derivative * sptr->PrevError; //E[k-2]项
//存储误差,用于下次计算
sptr->PrevError = sptr->LastError;
sptr->LastError = iError;
//返回增量值
return(iIncpid);
}

总结

本文对连续系统的PID控制理解到算法综合讲述了一遍,用matlab仿真能够更直观的理解各种调节方式对控制算法的影响,在不知道该如何对控制系统进行调试的时候,可以对照各种算法的优缺点进行选择调试,并最终使系统可以拥有正常的响应,如果要将该算法应用到实际中去,就是计算机控制的知识了,需要对传递函数进行离散化,再通过算法调控PWM等一系列方法将其实际应用,谢谢各位小伙伴们读完到这里,希望能够对大家有所帮助或者是有所启发,如果有不对的地方或者改进建议,欢迎大家的私信或者留言.

  • 8
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
下面是一个简单的PID算法的完整C语言代码: ```c #include <stdio.h> #include <stdbool.h> #define SAMPLE_TIME 0.1 #define KP 1.0 #define KI 0.1 #define KD 0.1 // PID控制器结构体 typedef struct { double Kp; // 比例系数 double Ki; // 积分系数 double Kd; // 微分系数 double SetPoint; // 设定值 double Integral; // 积分项 double LastError; // 上一次误差 } PIDController; // 初始化PID控制器 void pid_init(PIDController *pid, double set_point) { pid->Kp = KP; pid->Ki = KI; pid->Kd = KD; pid->SetPoint = set_point; pid->Integral = 0; pid->LastError = 0; } // PID控制器计算 double pid_compute(PIDController *pid, double input, double dt) { double error = pid->SetPoint - input; pid->Integral = pid->Integral + error*dt; double derivative = (error - pid->LastError)/dt; double output = pid->Kp*error + pid->Ki*pid->Integral + pid->Kd*derivative; pid->LastError = error; return output; } int main() { double set_point = 50.0; double input = 0.0; double output = 0.0; double time = 0.0; bool flag = true; PIDController pid; pid_init(&pid, set_point); while (flag) { output = pid_compute(&pid, input, SAMPLE_TIME); printf("Time: %lf, Input: %lf, Output: %lf\n", time, input, output); input = input + output*SAMPLE_TIME; time = time + SAMPLE_TIME; if (time > 10.0) { flag = false; } } return 0; } ``` 该代码中定义了一个PIDController结构体,用于存储PID控制器的相关参数和状态。在pid_init函数中,初始化PID控制器的参数。在pid_compute函数中,根据当前的输入值、采样时间和PID参数,计算出控制器的输出值。在main函数中,不断调用pid_compute函数计算输出值,直到模拟时间超过10秒为止。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值