A simple and easy to use PID controller in Python. If you want a PID controller without external dependencies that just works, this is for you! The PID was designed to be robust with help from Brett Beauregards guide.
Translation from Jason:Python中的一个简单并且容易使用的PID控制器。如果你想要一个不依靠外部环境的PID控制器,这正好适合你。设计更加具有鲁棒性的PID controller,可以从 Brett Beauregards guide得到帮助。
下面是来自官方的程序框架:
from simple_pid import PID
pid = PID(1, 0.1, 0.05, setpoint=1)
# assume we have a system we want to control in controlled_system
v = controlled_system.update(0)
while True:
# compute new ouput from the PID according to the systems current value
control = pid(v)
# feed the PID output to the system and get its current value
v = controlled_system.update(control)
这个程序是不能运行的,因为这个程序里面并没有被控制的系统(controlled_system),这个被控制的系统(controlled_system)是需要我们来决定的。
我们只需要在这个框架中加入由我们设计的需要被控制的系统并调整PID controller 的三个参数(比例系数:Kp,积分系数:Ki,微分系数:Kd)就可以完成一个由PID controller 控制的完整闭环系统,因此这个是非常容易使用的PID contraller 。
class heater:
def __init__(self):
self.temp = 25
def update(self, power, dt):
if power > 0:
#加热时房间温度随变量power和时间变量dt 的变化
self.temp += 2 * power * dt
#表示房间的热量损失
self.temp -= 0.5 * dt
return self.temp
变量temp是整个系统的输出,它反映的是变量power的情况,变量power是我们用PID controller 控制的变量。dt 是时间变量。
if __name__ == '__main__':
#将创建的模型写进主函数
heater = heater()
temp = heater.temp
#设置PID的三个参数,以及限制输出
pid = PID(2, 0.01, 0.1, setpoint=temp)
pid.output_limits = (0, None)
#用于设置时间参数
start_time = time.time()
last_time = start_time
#用于输出结果可视化
setpoint, y, x = [], [], []
#设置系统运行时间
while time.time() - start_time < 10:
#设置时间变量dt
current_time = time.time()
dt = (current_time - last_time)
#变量temp在整个系统中作为输出,变量temp与理想值之差作为反馈回路中的输入,通过反馈回路调节变量power的变化。
power = pid(temp)
temp = heater.update(power, dt)
#用于输出结果可视化
x += [current_time - start_time]
y += [temp]
setpoint += [pid.setpoint]
#用于变量temp赋初值
if current_time - start_time > 0:
pid.setpoint = 100
last_time = current_time
#输出结果可视化
plt.plot(x, setpoint, label='target')
plt.plot(x, y, label='PID')
plt.xlabel('time')
plt.ylabel('temperature')
plt.legend()
plt.show()
可以观察到,系统超调量几乎为零,震荡次数也几乎为零,系统表现比较好。这是因为系统得到反馈的频率非常高。
将语句:
pid = PID(2, 0.01, 0.1, setpoint=temp)
改为:
pid = PID(100, 0.01, 0.1, setpoint=temp)
输出结果:此时系统的超调量非常大,但是响应非常快,并且其存在下降趋势可知,最终还是会收敛与target。
将语句:
pid = PID(2, 0.01, 0.1, setpoint=temp)
改为:
pid = PID(2, 1, 0.1, setpoint=temp)
输出结果:此时系统超调量较大,但相比更改比例系数,系统的响应相对缓慢。是因为比例系数较小。但是存在较大的积分系数,累计误差对系统的影响太大,依旧存在超调,但是最终还是会收敛于target。
将语句:
pid = PID(2, 0.01, 0.1, setpoint=temp)
改为:
pid = PID(2, 0.01, 10, setpoint=temp)
输出结果:由于巨大的微分系数Kp,系统存在过冲现象,他最终不会收敛与target。
通过添加语句:
pid.sample_time = 0.01
将PID controller改为:
pid = PID(2, 0.01, 0.1, setpoint=temp)
pid.output_limits = (0, None)
pid.sample_time = 0.01
输出结果:系统表现的提升表现并不明显,这是因为在之前的系统中PID controller 接收到反馈的频率已经很快了,所以系统的表现不会有明显的提高。