-
Notifications
You must be signed in to change notification settings - Fork 4
/
pid.py
135 lines (122 loc) · 4.69 KB
/
pid.py
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#!/home/robot/roboliga/bin/python
# -*- coding: utf-8 -*-
from time import time
class PID():
"""
Implementacija algoritma za regulacijo PID.
Nekaj virov za razjasnitev osnovnega načela delovanja:
- https://en.wikipedia.org/wiki/PID_controller
- https://www.csimn.com/CSI_pages/PIDforDummies.html
- https://blog.opticontrols.com/archives/344
- https://www.youtube.com/watch?v=d2AWIA6j0NU
"""
def __init__(
self,
setpoint: float,
Kp: float,
Ki: float = None,
Kd: float = None,
integral_limit: float = None):
"""
Ustvarimo nov regulator PID s pripadajočimi parametri.
Argumenti:
setpoint: ciljna vrednost regulirane spremenljivke
Kp: ojačitev proporcionalnega dela regulatorja.
Visoke vrednosti pomenijo hitrejši odziv sistema,
vendar previsoke vrednosti povzročijo oscilacije in nestabilnost.
Ki: ojačitev integralnega člena regulatorja.
Izniči napako v ustaljenem stanju. Zmanjša odzivnost.
Kd: ojačitev odvoda napake.
Zmanjša čas umirjanja in poveča odzivnost.
integral_limit: najvišja vrednost integrala
"""
self._setpoint = setpoint
self._Kp = Kp
self._Ki = Ki
self._Kd = Kd
self._integral_limit = integral_limit
self._error = None
self._time = None
self._integral = None
self._value = None
def reset(
self,
setpoint: float = None,
Kp: float = None,
Ki: float = None,
Kd: float = None,
integral_limit: float = None):
"""
Ponastavitev regulatorja.
Lahko mu tudi spremenimo katero od vrednosti parametrov.
Napaka, integral napake in čas se ponastavijo.
"""
if setpoint is not None:
self._setpoint = setpoint
if Kp is not None:
self._Kp = Kp
if Ki is not None:
self._Ki = Ki
if Kd is not None:
self._Kd = Kd
if integral_limit is not None:
self._integral_limit = integral_limit
self._error = None
self._time = None
self._integral = None
self._value = None
def update(self, measurement: float) -> float:
"""
Izračunamo vrednost izhoda regulatorja (regulirna veličina)
glede na izmerjeno vrednost regulirane veličine (measurement)
in ciljno vrednost (setpoint).
Argumenti:
measurement: s tipali izmerjena vrednost regulirane veličine
Izhodna vrednost:
regulirna veličina, s katero želimo popraviti delovanje sistema
(regulirano veličino), da bo dosegel ciljno vrednost
"""
if self._value is None:
# Na začetku še nimamo zgodovine meritev, zato inicializiramo
# integral in vrnemo samo proporcionalni člen.
self._value = measurement
# Zapomnimo si začetni čas.
self._time = time()
# Ponastavimo integral napake.
self._integral = 0
# Napaka = ciljna vrednost - izmerjena vrednost regulirane veličine.
self._error = self._setpoint - measurement
return self._Kp * self._error
else:
# Sprememba časa
time_now = time()
delta_time = time_now - self._time
self._time = time_now
# Izmerjena vrednost regulirane veličine.
self._value = measurement
# Napaka = ciljna vrednost - izmerjena vrednost regulirane veličine.
error = self._setpoint - self._value
# Proporcionalni del
P = self._Kp * error
# Integralni in odvodni člen sta opcijska.
if self._Ki is None:
I = 0
else:
# Integral se poveča za (sprememba napake) / (sprememba časa).
self._integral += error * delta_time
# Ojačitev integralnega dela.
I = self._Ki * self._integral
if self._integral_limit is not None:
# Omejimo integralni del.
I = max(min(I, self._integral_limit),
(-1)*(self._integral_limit))
if self._Kd is None:
D = 0
else:
# Odvod napake z ojačitvijo.
D = self._Kd * (error - self._error) / delta_time
# Posodobimo napako.
self._error = error
# Vrnemo regulirno veličino, sestavljeno iz proporcionalnega,
# integralnega in odvodnega člena.
return P + I + D