大家好,欢迎来到IT知识分享网。
思维随笔——PID
PID的概念
PID是什么
PID,即比例(Proportional)、积分(Integral)、微分(Derivative),是一种常见的控制算法。
它是根据给定值(期望值)和实际输出值(当前值)构成控制偏差(误差),将偏差按比例、积分和微分通过线性组合构成控制量,对被控对象进行控制。常规PID 控制器作为一种线性控制器。
PID算法公式:u(t) = Kp * e(t) + Ki * ∫e(t) dt + Kd * de(t)/dt

其中:Kp为比例系数,Ki为积分系数,Kd为微分系数;e(t)为反馈误差,t为时间。
Kp*e(t)
:比例控制,反馈误差大则输出值大,反馈误差小则输出值小;
Ki*∫e(t)
:积分控制,误差积分越大,输出值越大,积分越小,输出值就越小;
Kd*de(t)/dt
:微分控制,反馈误差快速减小时,相应的输出值减小,反馈误差减慢时,输出值加大,使控制系统的收敛增快。
P、I、D三个环节的作用
P)比例环节:能迅速反映误差,从而减小误差,但比例控制不能消除稳态误差,KP增大可以减小系统的稳态误差,提高控制精度,但KP太大会引起系统的不稳定;
I)积分环节:提高系统的无差度,从而使系统的稳态性能得到改善和提高。但是积分作用太强会使系统超调加大,甚至使系统出现振荡,一般不单独使用;
D)微分环节:可以减小超调量,克服振荡,使系统的稳定性提高,同时加快系统的动态响应速度,减小调整时间,从而改善系统的动态性能。不足之处是放大了噪声信号。微分控制对时不变的偏差不起作用,只是在偏差刚刚出现时产生一个很大的调节作用,所以不单独使用。
PID的使用
位置型PID算法一般形式的c代码实现
PID的流程:通过误差信号控制被控量,而控制器本身就是比例、积分、微分三个环节的加和。这里我们规定(在t时刻):
1.输入量为rin(t);
2.输出量为rout(t);
3.偏差量为err(t)=rin(t)-rout(t);
离散化后得:
即
算法的C语言实现过程具有一般性,通过PID算法的C语言实现,可以以此类推,设计其它算法的C语言实现。
1、定义PID变量结构体;
2、初始化变量;
3、编写控制算法。
第一步:定义PID变量结构体,代码如下:
struct _pid { float SetSpeed; //定义设定值 float ActualSpeed; //定义实际值 float err; //定义偏差值 float err_last; //定义上一个偏差值 float Kp,Ki,Kd; //定义比例、积分、微分系数 float voltage; //定义电压值(控制执行器的变量) float integral; //定义积分值 }pid;
控制算法中所需要用到的参数在一个结构体中统一定义,方便后面的使用。
第二步:初始化变量,代码如下:
void PID_init(){ printf("PID_init begin \n"); pid.SetSpeed=0.0; pid.ActualSpeed=0.0; pid.err=0.0; pid.err_last=0.0; pid.voltage=0.0; pid.integral=0.0; pid.Kp=0.2; pid.Ki=0.015; pid.Kd=0.2; printf("PID_init end \n"); }
统一初始化变量,尤其是Kp,Ki,Kd三个参数,调试过程当中,对于要求的控制效果,可以通过调节这三个量直接进行调节。
第三步:编写控制算法,代码如下:
float PID_realize(float speed){ pid.SetSpeed=speed; pid.err=pid.SetSpeed-pid.ActualSpeed; pid.integral+=pid.err; pid.voltage=pid.Kp*pid.err+pid.Ki*pid.integral+pid.Kd*(pid.err-pid.err_last); pid.err_last=pid.err; pid.ActualSpeed=pid.voltage*1.0; return pid.ActualSpeed; }
注意:这里用了最基本的算法实现形式,没有考虑死区问题,没有设定上下限,只是对公式的一种直接的实现。
到此为止,PID的基本实现部分就初步完成了。下面是测试代码:
int main(){ printf("System begin \n"); PID_init(); int count=0; while(count<1000) { float speed=PID_realize(200.0); printf("%f\n",speed); count++; } return 0; }
自己写的小PID(有没有用我也不知道):
.c类型:
#include <stdio.h> // PID参数 double Kp = 1.0; //比例系数 double Ki = 0.0; //积分系数 double Kd = 0.0; //微分系数 //PID变量 double error = 0.0; //当前误差 double last_error = 0.0; //上一次误差 double integral = 0.0; //积分项 double derivative = 0.0; //微分项 //PID计算函数 //setpoint:设定值; //actual_value:实际值 double pid(double setpoint, double actual_value) { //计算当前误差 error = setpoint - actual_value; //计算积分项 integral += error; //计算微分项 derivative = error - last_error; //计算输出值 double output = Kp * error + Ki * integral + Kd * derivative; //记录上一次误差 last_error =error; return output; } int main() { //测试PID算法 double setpoint = 10.0; double actual_value = 0.0; double output= pid(setpoint, actual_value); printf("PID'output: %f\n", output); printf("nihao"); return 0; }
.py类型:
import random import matplotlib.pyplot as plt import numpy as np import math def temple_syetem(x, y): for i in x: y.append(np.cos(i) + random.uniform(-0.5, 0.5)) # 产生信号 t = np.linspace(0, 6*np.pi, 100) y = [] temple_syetem(t, y) class PIDController: def __init__(self, kp, ki, kd, setpoint): self.kp = kp self.ki = ki self.kd = kd self.setpoint = setpoint self.proportional = 0 self.integral = 0 self.derivative = 0 self.previous_error = 0 def update(self, current_value, dt): error = self.setpoint - current_value self.proportional = error self.integral += error * dt self.derivative = (error - self.previous_error) / dt self.previous_error = error output = (self.kp * self.proportional + self.ki * self.integral + self.kd * self.derivative) return output pid = PIDController(kp=1, ki=0.1, kd=0.01, setpoint=np.cos(t)) z = [] for j in t: system_output = y[j] control_input = pid.update(system_output, 0.01) z.append(control_input) plt.figure() plt.xlabel('t') plt.ylabel('y') plt.title('cos(t)') plt.plot(t, y, color='red',) plt.plot(t, z, color='blue') plt.show() ''' class PIDController: def __init__(self, kp, ki, kd, setpoint): self.kp = kp self.ki = ki self.kd = kd self.setpoint = setpoint self.proportional = 0 self.integral = 0 self.derivative = 0 self.previous_error = 0 def update(self, current_value, dt): error = self.setpoint - current_value self.proportional = error self.integral += error * dt self.derivative = (error - self.previous_error) / dt self.previous_error = error output = (self.kp * self.proportional + self.ki * self.integral + self.kd * self.derivative) return output # 创建一个简单的控制系统 def simple_system(input): output = input + random.uniform(-1, 1) # 存在一些扰动和噪声 return output # 创建一个 PID 控制器实例并应用于控制系统 pid_controller = PIDController(kp=1, ki=0.1, kd=0.01, setpoint=0) dt = 0.1 # 时间步长 t = range(100) y = [] z = [] for i in t: current_value = simple_system(i) # 获取当前系统的输出值 y.append(current_value) control_input = pid_controller.update(current_value, dt) # 获取控制器的输出值 z.append(control_input) plt.figure(figsize=(8, 6), dpi=80) plt.plot(t, y, color="blue", linewidth=1.0, linestyle="-") plt.plot(t, z, color="red", linewidth=1.0, linestyle="-") plt.show() print("nihao") ''' control_input = pid_controller.update(current_value, dt) # 获取控制器的输出值 z.append(control_input) plt.figure(figsize=(8, 6), dpi=80) plt.plot(t, y, color="blue", linewidth=1.0, linestyle="-") plt.plot(t, z, color="red", linewidth=1.0, linestyle="-") plt.show() print("nihao") '''
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/128891.html