@@ -11,43 +11,45 @@ def __init__(self,
1111 kp = 1.0 ,
1212 ki = 0.0 ,
1313 kd = 0.0 ,
14- minOutput = 0.0 ,
15- maxOutput = 1.0 ,
16- maxDerivative = None ,
14+ min_output = 0.0 ,
15+ max_output = 1.0 ,
16+ max_derivative = None ,
17+ max_integral = None ,
1718 tolerance = 0.1 ,
18- toleranceCount = 1
19+ tolerance_count = 1
1920 ):
2021 """
2122 :param kp: proportional gain
2223 :param ki: integral gain
2324 :param kd: derivative gain
24- :param minOutput: minimum output
25- :param maxOutput: maximum output
26- :param maxDerivative: maximum derivative (change per second)
25+ :param min_output: minimum output
26+ :param max_output: maximum output
27+ :param max_derivative: maximum derivative (change per second)
28+ :param max_integral: maximum integral windup allowed (will cap integral at this value)
2729 :param tolerance: tolerance for exit condition
28- :param numTimesInTolerance : number of times in tolerance for exit condition
30+ :param tolerance_count : number of times the error needs to be within tolerance for is_done to return True
2931 """
3032 self .kp = kp
3133 self .ki = ki
3234 self .kd = kd
33- self .minOutput = minOutput
34- self .maxOutput = maxOutput
35- self .maxDerivative = maxDerivative
35+ self .min_output = min_output
36+ self .max_output = max_output
37+ self .max_derivative = max_derivative
38+ self .max_integral = max_integral
3639 self .tolerance = tolerance
37- self .toleranceCount = toleranceCount
40+ self .tolerance_count = tolerance_count
3841
39- self .prevError = 0
40- self .prevIntegral = 0
41- self .prevOutput = 0
42+ self .prev_error = 0
43+ self .prev_integral = 0
44+ self .prev_output = 0
4245
43- self .startTime = None
44- self .prevTime = None
46+ self .start_time = None
47+ self .prev_time = None
4548
4649 # number of actual times in tolerance
4750 self .times = 0
4851
4952 def _handle_exit_condition (self , error : float ):
50-
5153 if abs (error ) < self .tolerance :
5254 # if error is within tolerance, increment times in tolerance
5355 self .times += 1
@@ -65,43 +67,47 @@ def update(self, error: float) -> float:
6567 :return: The system output from the controller, to be used as an effort value or for any other purpose
6668 :rtype: float
6769 """
68- currentTime = time .ticks_ms ()
69- if self .prevTime is None :
70+ current_time = time .ticks_ms ()
71+ if self .prev_time is None :
7072 # First update after instantiation
71- self .startTime = currentTime
73+ self .start_time = current_time
7274 timestep = 0.01
7375 else :
7476 # get time delta in seconds
75- timestep = time .ticks_diff (currentTime , self .prevTime ) / 1000
76- self .prevTime = currentTime # cache time for next update
77+ timestep = time .ticks_diff (current_time , self .prev_time ) / 1000
78+ self .prev_time = current_time # cache time for next update
7779
7880 self ._handle_exit_condition (error )
7981
80- integral = self .prevIntegral + error * timestep
81- derivative = (error - self .prevError ) / timestep
82+ integral = self .prev_integral + error * timestep
83+
84+ if self .max_integral is not None :
85+ integral = max (- self .max_integral , min (self .max_integral , integral ))
86+
87+ derivative = (error - self .prev_error ) / timestep
8288
8389 # derive output
8490 output = self .kp * error + self .ki * integral + self .kd * derivative
85- self .prevError = error
86- self .prevIntegral = integral
91+ self .prev_error = error
92+ self .prev_integral = integral
8793
8894 # Bound output by minimum
8995 if output > 0 :
90- output = max (self .minOutput , output )
96+ output = max (self .min_output , output )
9197 else :
92- output = min (- self .minOutput , output )
98+ output = min (- self .min_output , output )
9399
94100 # Bound output by maximum
95- output = max (- self .maxOutput , min (self .maxOutput , output ))
101+ output = max (- self .max_output , min (self .max_output , output ))
96102
97103 # Bound output by maximum acceleration
98- if self .maxDerivative is not None :
99- lowerBound = self .prevOutput - self .maxDerivative * timestep
100- upperBound = self .prevOutput + self .maxDerivative * timestep
101- output = max (lowerBound , min (upperBound , output ))
104+ if self .max_derivative is not None :
105+ lower_bound = self .prev_output - self .max_derivative * timestep
106+ upper_bound = self .prev_output + self .max_derivative * timestep
107+ output = max (lower_bound , min (upper_bound , output ))
102108
103109 # cache output for next update
104- self .prevOutput = output
110+ self .prev_output = output
105111
106112 return output
107113
@@ -110,12 +116,11 @@ def is_done(self) -> bool:
110116 :return: if error is within tolerance for numTimesInTolerance consecutive times, or timed out
111117 :rtype: bool
112118 """
113-
114- return self .times >= self .toleranceCount
119+ return self .times >= self .tolerance_count
115120
116121 def clear_history (self ):
117- self .prevError = 0
118- self .prevIntegral = 0
119- self .prevOutput = 0
120- self .times = 0
121- self .prevTime = None
122+ self .prev_error = 0
123+ self .prev_integral = 0
124+ self .prev_output = 0
125+ self .prev_time = None
126+ self .times = 0
0 commit comments