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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
//! PID Controller
//!
//! The PID controller is one of the most widely used feedback control algorithms in
//! industrial control systems, robotics, and process control. It computes a control signal
//! based on three terms: **proportional**, **integral**, and **derivative**.
//!
//! # Components
//!
//! - The **proportional** term produces an output proportional to the current error,
//! multiplied by the gain constant `kp`. This provides the main control action:
//! larger errors result in larger corrective responses and vice versa.
//!
//! - The **integral** term sums the error over time, multiplied by the gain constant `ki`.
//! This term eliminates *steady-state error* by ensuring that even small errors will
//! eventually accumulate a large enough response to reach the setpoint. Without integral
//! action, a system might stabilize with a small, persistent error if the control
//! signal becomes too small to overcome system friction, gravity, or other external
//! factors on the system. For example, a motor might need some minimum voltage to start
//! moving, or a drone might need extra thrust to hover against gravity. The integral term
//! accumulates over time to provide this additional correction.
//!
//! - The **derivative** term measures the error's change over time, multiplied by the
//! gain constant `kd`. This provides a damping effect that reduces overshoot and
//! oscillation by counteracting rapid changes in error. The derivative term helps
//! anticipate and smooth out the system's response, preventing sudden changes resulting
//! from large proportional or integral gains.
//!
//! # Tuning
//!
//! Tuning a PID controller requires adjusting `kp`, `ki`, and `kd` to allow the system to reach a setpoint
//! in a reasonable amount of time without oscillations (rapid, unpredictable changes in output).
//!
//! Tuning methods are typically dependent on the application that the PID controller is used
//! in, but a common method is as follows:
//!
//! 1. Start with all gains at zero (`kp = 0.0`, `ki = 0.0`, `kd = 0.0`).
//!
//! 2. Tune proportional gain first:
//! - Gradually increase `kp` until the system starts to oscillate around the setpoint.
//! - *Oscillation* occurs when the system reaches and overshoots the setpoint, then repeatedly overadjusts
//! itself around the setpoint, resulting in a "back-and-fourth" motion around the setpoint.
//!
//! 3. Tune the derivative gain:
//! - Start with a very small `kd` gain (0.05 × `kp` or less is a safe bet to start with).
//! - Gradually increase by small increments until oscillations from the proportional term stop occurring.
//!
//! 4. Add integral gain if necessary:
//! - Integral gain is only necessary if your controller's proportional and derivative terms
//! become small enough to where they can no longer overcome some external factor (such as friction)
//! of the system, resulting in what's called *steady-state error*.
//! - Start with a very small `ki` gain (such as 0.01 × `kp`).
//! - Increase `ki` slowly until steady-state errors are eliminated within an acceptable time.
//! - If oscillation occurs, reduce both `ki` and `kp` slightly.
//!
//! Common signs of poor tuning:
//!
//! - Slow response: `kp` is too low.
//! - Excessive overshoot: `kd` is too low or `ki` is too high.
//! - Oscillation: `kp` is too high or `kd` is too low.
//! - Noisy, unpredictable response: `kd` is too high.
//!
//! # Integral Windup (and Mitigations)
//!
//! In some scenarios, a PID controller may be prone to *integral windup*, where a controlled system
//! reaches a saturation point preventing the error from decreasing. In this case, integral will rapidly
//! accumulate, causing large and unpredictable control signals. This specific implementation provides
//! two mitigations for integral windup:
//!
//! 1. **Sign-based reset:** When the sign of error changes (in other words, when the controller has
//! crossed/overshot its target), the integral value is reset to prevent overshoot of the target.
//! 2. **Integration bounds:** An optional `integration_range` value can be passed to the controller,
//! which defines a range of error where integration will occur. When `|error| > integration_range`,
//! no integration will occur if used.
use Duration;
use Float;
use Feedback;
/// A proportional-integral-derivative (PID) feedback controller with integral windup prevention.