@@ -11,43 +11,45 @@ def __init__(self,
11
11
kp = 1.0 ,
12
12
ki = 0.0 ,
13
13
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 ,
17
18
tolerance = 0.1 ,
18
- toleranceCount = 1
19
+ tolerance_count = 1
19
20
):
20
21
"""
21
22
:param kp: proportional gain
22
23
:param ki: integral gain
23
24
: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)
27
29
: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
29
31
"""
30
32
self .kp = kp
31
33
self .ki = ki
32
34
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
36
39
self .tolerance = tolerance
37
- self .toleranceCount = toleranceCount
40
+ self .tolerance_count = tolerance_count
38
41
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
42
45
43
- self .startTime = None
44
- self .prevTime = None
46
+ self .start_time = None
47
+ self .prev_time = None
45
48
46
49
# number of actual times in tolerance
47
50
self .times = 0
48
51
49
52
def _handle_exit_condition (self , error : float ):
50
-
51
53
if abs (error ) < self .tolerance :
52
54
# if error is within tolerance, increment times in tolerance
53
55
self .times += 1
@@ -65,43 +67,47 @@ def update(self, error: float) -> float:
65
67
:return: The system output from the controller, to be used as an effort value or for any other purpose
66
68
:rtype: float
67
69
"""
68
- currentTime = time .ticks_ms ()
69
- if self .prevTime is None :
70
+ current_time = time .ticks_ms ()
71
+ if self .prev_time is None :
70
72
# First update after instantiation
71
- self .startTime = currentTime
73
+ self .start_time = current_time
72
74
timestep = 0.01
73
75
else :
74
76
# 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
77
79
78
80
self ._handle_exit_condition (error )
79
81
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
82
88
83
89
# derive output
84
90
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
87
93
88
94
# Bound output by minimum
89
95
if output > 0 :
90
- output = max (self .minOutput , output )
96
+ output = max (self .min_output , output )
91
97
else :
92
- output = min (- self .minOutput , output )
98
+ output = min (- self .min_output , output )
93
99
94
100
# Bound output by maximum
95
- output = max (- self .maxOutput , min (self .maxOutput , output ))
101
+ output = max (- self .max_output , min (self .max_output , output ))
96
102
97
103
# 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 ))
102
108
103
109
# cache output for next update
104
- self .prevOutput = output
110
+ self .prev_output = output
105
111
106
112
return output
107
113
@@ -110,12 +116,11 @@ def is_done(self) -> bool:
110
116
:return: if error is within tolerance for numTimesInTolerance consecutive times, or timed out
111
117
:rtype: bool
112
118
"""
113
-
114
- return self .times >= self .toleranceCount
119
+ return self .times >= self .tolerance_count
115
120
116
121
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