PID控制算法 – 0、PID原理

news/2024/10/18 16:49:19/

1、开局一张图

很多地方都觉得PID的控制结构示意图是这样的:

2、目标值(Setpoint)、输入值(Input)、误差(Error)

其实把上图那个输入改为目标值(Setpoint)更合适,因为不管是什么控制系统,都应该有个目标值,比如水位控制系统,水位的高度就是目标值;温度控制系统,想要的温度就是目标值;速度控制系统,想要的速度就是目标值。目标值是所有控制系统的前提,所以PID控制结构示意图应该改 为这样:

要想知道你的控制系统是否达到你的目标值,你需要干什么?当然是不断地看结果,比如温度控制系统,你通过加热的方式把一个铁块的温度控制在60℃,要想知道有没有达到这个目标温度,就需要搞一个温度传感器来测量铁块的温度,这个温度传感器就是测量元件

温度传感器测量铁块温度的目的是什么?就是看铁块的温度是否到60℃了。怎么看,就是把这个测量值与目标值作比较,比大小,比出来的结果就叫误差。温度传感器测出来的温度就是反馈值,因为反馈值是不断地送到控制系统的,所以这个反馈值叫做输入更合适。

 误差值 = 目标值 - 输入值

 也可以写成这样 :    Error = Setpoint - Input

一般把Error写成e,也就是    e = Setpoint - Input

某个时刻的误差值可以写成e(t), 也就是   e(t) = Setpoint - Input

控制系统的计算核心就是根据这个误差e(t)来展开的,这个后面来展开。

比如温度传感器检测出来的温度是50摄氏度,误差Error = 60 - 50 = 10℃,这就表示温度还不够,还得继续加热,这个加热机构就是执行机构,这个执行机构可以是烧柴火,也可以是烧煤气,也可以是电加热条、电加热块...... 

不管是火、还是煤气、还是电,都只是个媒介,我们要的是控制思想。如果温度传感器测出来的温度是10度,远低于60℃,该怎么办,当然是把火烧旺点,电流加大点;如果温度传感器测出来的温度超过60℃,超过目标值了该怎么办,当然是把火或者电给关了。

执行机构执行之后,也就是烧火,或者烧电之后,应该有个结果,这个结果就是铁块的温度,我们通过温度传感器来采集这个结果,并作为反馈值(输入值)送给控制机构,所以那个控制结构示意图还是有些欠妥,应该改为:

3、控制核心

前面说的温度比目标值小就加火加电,温度比目标值大就停火停电,这个加和停就是控制,要烧多大的火或者要放多大的电,这个量就是输出,PID控制就是控制这个火的大小,电的大小,从而达到控制温度的目的,所以,那个控制结构示意图应该这样标注:

 PID的控制核心就是算一下该输出多大的火力或者电力,或者其他什么,反正都叫做输出(Output)。

现在大家应该都理解目标值、输入值(反馈值)、结果、输出、误差这些概念了,那个经典的公式应该可以出来了:

Output = K_{p}*e(t) + K_{i}*\int e(t)d_{t} + K_{d}*\frac{de(t)}{d_{t}}

这个Output就是经过计算之后,应该输出的火力大小;

这个e(t)就是前面所说的误差:e(t) = Setpoint - Input

比例、积分、微分

上面的经典公式又引入了3个新东西

这个K_{p}就是比例系数(它是什么,要它干啥)

这个K_{i}就是积分系数(它是什么,要它干啥)

这个K_{d}就是微分系数(它是什么,要它干啥)

PID相关参数讲解:1、比例系数Kp与静态误差_资深流水灯工程师的博客-CSDN博客

PID代码实现

把这位外国网友的代码拿来分析一下,Arduino的某个PID库就是这哥们写的,原文链接如下

PID « Project Blog (brettbeauregard.com)

PID的开局都是这个公式:

Output = K_{p}*e(t) + K_{i}*\int e(t)d_{t} + K_{d}*\frac{de(t)}{d_{t}}

e(t) = Setpoint - Input

上面的公式是理想的情况,在代码实现的时候,需要将其离散化。

PID算法调用时间的分析

积分与微分与时间是直接相关的,咱也不提什么采样周期的事了,就是随机的调用PID算法,记录每次调用PID算法的时间间隔(timeChange)

这个时间间隔(timeChange)就等于当前的时间减去上一次调用PID算法的时间:

d_{t} = \Delta t = now-lastTime = timeChange

所以累计

误差errSum

errSum = \int e(t)d_{t}= e(0)*d_{t0} + e(1)*d_{t1} +e(2)*d_{t2}+...+e(t)*d_{t}

用C语言表示累计误差可以是这样:

errSum += (error * timeChange);

误差的微分dErr,等于本次的误差减去上次一PID计算时的误差,除以时间间隔:

dErr=\frac{de(t)}{d_{t}} =(error - lastErr)/timeChange

综上,公式Output = K_{p}*e(t) + K_{i}*\int e(t)d_{t} + K_{d}*\frac{de(t)}{d_{t}}用C语言表示出来可以是这样的:

Output = kp * error + ki * errSum + kd * dErr;

因为是随机的调用PID算法,所以需要记录每次PID计算时的时间点和误差

   lastErr = error;lastTime = now;

 比例系数、积分系数、微分系数的设置函数实现

void SetTunings(double Kp, double Ki, double Kd)
{kp = Kp;ki = Ki;kd = Kd;
}

完整的PID实现代码如下所示

/*working variables*/
unsigned long lastTime;
double Input, Output, Setpoint;
double errSum, lastErr;
double kp, ki, kd;
void Compute()
{/*How long since we last calculated*/unsigned long now = millis();double timeChange = (double)(now - lastTime);/*Compute all the working error variables*/double error = Setpoint - Input;errSum += (error * timeChange);double dErr = (error - lastErr) / timeChange;/*Compute PID Output*/Output = kp * error + ki * errSum + kd * dErr;/*Remember some variables for next time*/lastErr = error;lastTime = now;
}void SetTunings(double Kp, double Ki, double Kd)
{kp = Kp;ki = Ki;kd = Kd;
}

这个Compute()函数是被不定期的调用,一般情况下效果也可以,能正常的工作起来,但距离工业应用还差的很远,还需要解决下面一系列的问题:

  1. 采样时间 :如果定期对PID算法进行评估,则其效果最佳。如果算法知道此间隔,我们还可以简化一些内部数学运算。
  2. 微分冲击 :这不是最大的问题,但是很容易解决,因此我们将这样做。
  3. 动态调整参数 : 一种好的PID算法可以在不影响内部工作的情况下更改调整参数。
  4. 缓解积分饱和 : 我们将介绍什么是缓解积分饱和,并实施具有附带好处的解决方案。
  5. 开/关(自动/手动):在大多数应用中,有时需要关闭PID控制器并手动调节输出,而不会干扰控制器。
  6. 初始化 : 控制器首次开启时,我们希望进行”无扰动的传输“,也就是说,我们不希望输出突然变为某个新值。
  7. 控制方向 : 最后一个不是鲁棒性本身名称的更改,它旨在确保用户输入具有正确符号的调优参数。
  8. 新增 测量比例(Proportional on Measurement) :添加这个特性使得它更加容易控制特定类型的过程。

本系列后面的文章就是围绕着8个问题展开,这8个问题全部解决之后,就是一个比较完善的PID控制算法了。


http://www.ppmy.cn/news/533274.html

相关文章

windows进程结构体

了解进程线程的概念后,我们就来看看windows里面的进程长什么样子的。进程本质上就是一个结构体。在Linux里面也称之为进程描述符。当操作系统创建一个进程的时候,它会填充一个结构体,往这个结构体里写入数据,这个结构体就用于管理…

Queue,List,Deque联系

如图所示,可以得出LinkedList既可以是双向链表也可以是双端队列,Deque接口继承了Queue接口 Queue add(E):boolean 在队尾添加元素,添加成功返回true,如果队列已满无法添加则抛出异常。offer(E):boolean 在队尾添加元素&#xff0…

Web服务器群集:链路聚合与桥接

目录 一、理论 1.链路聚合 2.bond模式 3.team模式 4.bond和team区别 二、实验 1.实现bond网络接口 2.实现team网络接口 三、总结 一、理论 1.链路聚合 (1)概念 链路聚合(Link Aggregation),它是一个计算机…

洛谷 B2025 输出字符菱形 题解

题目描述 用 * 构造一个对角线长 55 个字符,倾斜放置的菱形。 输入格式 没有输入要求。 输出格式 如样例所示。用 * 构成的菱形。 输入输出样例 输入 #1 输出 #1 **** ********* 本题是输出一个菱形即可,但注意末尾不要有空格,一定要…

洛谷B2025输出字符菱形

洛谷B2025 题目描述 用 * 构造一个对角线长 5 个字符&#xff0c;倾斜放置的菱形。 输入格式 没有输入要求。 输出格式 如样例所示。用 * 构成的菱形。 运行代码&#xff1a; #include<bits/stdc.h> using namespace std; int main() {cout<<" *"<…

距离2025年倒计时

css样式&#xff1a; <style>* {margin: 0;padding: 0;}p {font-size: 50px;text-align: center;}p span {color: orange;}p span.time {color: #4BAC3E;}body {padding-top: 200px;}</style>html <p>距离2025年还有</p><p><span></spa…

洛谷B2025 输出字符菱形

输出字符菱形 题目描述 用 * 构造一个对角线长 5 5 5 个字符&#xff0c;倾斜放置的菱形。 输入格式 没有输入要求。 输出格式 如样例所示。用 * 构成的菱形。 样例 #1 样例输入 #1 样例输出 #1 **** *********#include<stdio.h> #include<string.h> #in…

2025规划

2025规划 中国宝安 000009 超级电容, 广东板块, 新能源 公司主营业务包括两大块:高新技术业和生物医药业。高新技术业,公司控股的新三板企业贝特瑞,是全球第一的致力于锂离子二次电池用的负极材料及纳米材料应用企业,控股企业大地和是国内最早介入新能源汽车驱动系统领域的企业…