diff --git a/SUMMARY.md b/SUMMARY.md index d76af219d..1542d9d19 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -38,6 +38,7 @@ * [Verlet Integration](contents/verlet_integration/verlet_integration.md) * [Quantum Systems](contents/quantum_systems/quantum_systems.md) * [Split-Operator Method](contents/split-operator_method/split-operator_method.md) +* [PID Controller](contents/pid_controller/pid_controller.md) * [Data Compression](contents/data_compression/data_compression.md) * [Huffman Encoding](contents/huffman_encoding/huffman_encoding.md) * [Computer Graphics](contents/computer_graphics/computer_graphics.md) diff --git a/contents/pid_controller/code/c/pid_controller.c b/contents/pid_controller/code/c/pid_controller.c new file mode 100644 index 000000000..52bb102d9 --- /dev/null +++ b/contents/pid_controller/code/c/pid_controller.c @@ -0,0 +1,46 @@ +#include + +struct pid_context { + double kp; + double ki; + double kd; + double setpoint; + double last_error; + double integral; + double dt; // Normally you calculate the change in time. +}; + +struct pid_context get_pid(double setpoint, double dt, double kp, double ki, + double kd) { + + struct pid_context ctx = {0}; + ctx.setpoint = setpoint; + ctx.dt = dt; + ctx.kp = kp; + ctx.ki = ki; + ctx.kd = kd; + + return ctx; +} + +double pid_calculate(struct pid_context ctx, double input) { + // Here you would calculate the time elapsed. + double error = ctx.setpoint - input; + ctx.integral += error * ctx.dt; + double derivative = (error - ctx.last_error) / ctx.dt; + ctx.last_error = error; + + return ctx.kp * error + ctx.ki * ctx.integral + ctx.kd * derivative; +} + +int main() { + struct pid_context ctx = get_pid(1.0, 0.01, 1.2, 1.0, 0.001); + double input = 0.0; + + for (int i = 0; i < 100; ++i) { + input += pid_calculate(ctx, input); + printf("%g\n", input); + } + + return 0; +} diff --git a/contents/pid_controller/pid_controller.md b/contents/pid_controller/pid_controller.md new file mode 100644 index 000000000..a95286115 --- /dev/null +++ b/contents/pid_controller/pid_controller.md @@ -0,0 +1,129 @@ +# Proportional-Integral-Derivative Controller + +The Proportional-Integral-Derivative controller (PID controller) is a control loop feedback mechanism, used for continuously modulated control. +The PID controller has three components: proportional controller, integral controller, and derivative controller. + +Before we get into how a PID controller works, we need a good example to explain things. +For the following sections, imagine you are designing a self driving RC car that tries to remain on a line as it is moving with a constant speed. How would you keep it on course? + +### Proportional Controller + +Imagine our RC car is too far to the right of the line, in this case it makes sense to turn left. +Since there are a range of angles you could turn the wheel by, it is unclear what strategy would work best to return the RC car to the line; however, it is clear that if the angle chosen is proportional to the distance from the line, the car will always be moving towards it. +This is what the proportional controller (P controller) does, which is described by + +$$ P = K_{p} e(t), $$ + +Where $$K_{p}$$ is an arbitrary constant and $$e(t)$$ is the current distance from the line, which is called the error. +The performance of the controller improves with larger $$K_{p}$$; +however, if $$K_{p}$$ and $$e(t)$$ are too high then the system becomes unstable. +If the proportional controller is used alone, the car will not move appropriately. + +For example, if the car is too far out, the angle will be above $$2\pi$$, which means that the car cannot quite return to the line and will instead move in circles, as shown below: + +
+ +
+ +On the other hand, if the car is sufficiently close to the line, it will oscillate back and forth, but never rest on the line, itself, as shown below: + +
+ +
+ +### Derivative Controller + +The P controller works well but it has the added problem of overshooting, we need to dampen this motion. +One way to do this is to make the RC car resistant to sudden changes of error. +This is what the derivative controller (D controller) does, which is described by + +$$ D = K_{d} \frac{de(t)}{dt}$$ + +Where $$K_{d}$$ is a constant and $$\frac{de(t)}{dt}$$ is the derivative of the error function $$e(t)$$. +If $$K_{d}$$ is too high then the system is overdamped, i.e. the car takes too long to get back on track. +If it's too low, the system is underdamped, i.e. the car oscillates around the line. +When the car returns to the track and there is little to no oscillations, the system is critically damped. + +
+ +
+ +### Integral Controller + +The Proportional and Derivative controllers are robust enough to keep the RC car on course, but what if some wind or other external force starts pushing the car constantly off track? +Well, we would need to know if we are spending too long on one side to account for this, and we can figure that out by taking the sum of all the displacements, usually referred to as errors, and multiplying it by a constant. +This is what the integral controller (I controller) does, which is described by + +$$ I = K_{i} \int_{0}^{t} e(\uptau) d\tau, $$ + +Where $$K_{i}$$ is a constant. +The peformance of the controller is better with higher $$K_{i}$$; but with higher $$K_{i}$$ it can introduce oscillations. + +### Proportional-Integral-Derivative Controller + +The PID controller is just a sum of all three controllers and is of the form + +$$ U = K_{p} e(t) + K_{i} \int_{0}^{t} e(x) dx + K_{d} \frac{de(t)}{dt} $$ + +To use a PID controller, you need to tune it by setting the constants, $$K_{p}$$, $$K_{i}$$, and $$K_{d}$$. +If you choose the parameters for your PID controller incorrectly, the output will be unstable, i.e., the output diverges. +There are multiple methods of tuning like manual tuning, Ziegler–Nichols, Tyreus Luyben, Cohen–Coon, and Åström-Hägglund.{{ "wikipid" | cite }} + +Theoretically, PID controllers can be used for any process with a measurable output and a known ideal output, +but controllers are used mainly for regulating temperature, pressure, force, flow rate, feed rate, speed and more. + +## Putting it all together + +Luckily the algorithm is very simple, you just need to make the PID equation discrete. +Thus, the equation looks like this: + +$$ U = K_{p} e(t_{j}) + \sum_{l=0}^{j} K_{i} e(t_{l}) \Delta t + K_{d} \frac{e(t_{j-1}) - e(t_{j})}{\Delta t}. $$ + +In the end the code looks like this: + +{% method %} +{% sample lang="c" %} +[import:26-34, lang:"c"](code/c/pid_controller.c) +{% endmethod %} + +## Example Code + +The example code is of a 1-dimensional RC car that is trying to change from the first lane to the second lane, where the numbers represent the center of the lane. +In this example, we can't calculate the time elapsed, so we are instead setting a value called dt for time elapsed. + +{% method %} +{% sample lang="c" %} +[import, lang:"c"](code/c/pid_controller.c) +{% endmethod %} + +### Bibliography + +{% references %} {% endreferences %} + + +## License + +##### Code Examples + +The code examples are licensed under the MIT license (found in [LICENSE.md](https://github.com/algorithm-archivists/algorithm-archive/blob/master/LICENSE.md)). + +##### Text + +The text of this chapter was written by Gathros and is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). + +##### Images/Graphics +- The animation "[damping](res/damping.mp4)" was created by Gathros and is licenced under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). +- The animation "[circling](res/circling.mp4)" was created by Gathros and is licenced under the [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/legalcode). + +[

](https://creativecommons.org/licenses/by-sa/4.0/) diff --git a/contents/pid_controller/res/circling.mp4 b/contents/pid_controller/res/circling.mp4 new file mode 100644 index 000000000..dba9a1b36 Binary files /dev/null and b/contents/pid_controller/res/circling.mp4 differ diff --git a/contents/pid_controller/res/damping.mp4 b/contents/pid_controller/res/damping.mp4 new file mode 100644 index 000000000..3aa9ce07f Binary files /dev/null and b/contents/pid_controller/res/damping.mp4 differ diff --git a/contents/pid_controller/res/oscillation.mp4 b/contents/pid_controller/res/oscillation.mp4 new file mode 100644 index 000000000..d46209531 Binary files /dev/null and b/contents/pid_controller/res/oscillation.mp4 differ diff --git a/literature.bib b/literature.bib index 2f22c0dc8..3cf3a71ce 100644 --- a/literature.bib +++ b/literature.bib @@ -39,6 +39,16 @@ @article{gs1972 publisher={Elsevier} } + +#------------------------------------------------------------------------------# +# PID +#------------------------------------------------------------------------------# +@online{wikipid, + title={PID controller - Wikipedia}, + url={https://en.wikipedia.org/wiki/PID_controller}, + urldate={2018-12-30} +} + #------------------------------------------------------------------------------# # Plotting #------------------------------------------------------------------------------#