PID controllers: whether you are a control engineer or not, I am sure you have heard about it.
Due to their simplicity and robustness, PID controllers are one of the most popular control methods. They are being used in many different industries and many different applications. PID controllers can be (and need to be) tuned specifically for the application. Tuning will also impact the performance of the controller: how quick it responds, how much overshoot, how it reacts to vibrations, etc …
Of course, because they are so simple and popular, they are often misused and can lead to frustration during the tuning process. A lot of theory has been written about PID controllers, but in the end, you need to implement them in real life.
In this article, I want to give you a practical guide on how to use a PID controller and what I learned from my experience (I worked as a control engineer on drones, electrical race cars and Formula One). I will explain using an example where we will tune the cruise control of a road car.
PID is actually kind of an acronym. The controller consists of 3 components:
I would guess that 90% of all PID controllers in the world are actually just P-controllers. PI-controllers are also quite common, but the Derivative term is not commonly used. (Spoiler: if you need a Derivative term you probably have a problem with your system or design)
The flowchart represents the PID controller. Don’t focus on the details, the main takeaway is that there is an input, the 3 PID components and an output. The ‘Gains’ are the numbers we can tune.
PID controllers can only be used for linear systems. That means that there needs to be a linear relationship between the action of the PID controller and the variable you are trying to control. In very simple terms: higher action = higher output, lower action = lower output. There are cases where this is not true, think about systems with angles or quadratic systems.
PID controllers are actually quite simple, so they are usually also a good fit for simple systems. If a system is quite complex, you will have a bad time implementing a PID controller.
A PID controller to control the speed of a rotor? - Perfect!
A PID controller to control a double inverted pendulum? - think twice.
It is possible to use PID controllers in more complex systems, the trick is to linearize the system and you might need a combination of multiple PID controllers in series. But let’s not get into that.
As with many things in life, the first step is to think: “what would I do?”. This is also applicable when tuning a PID controller.
You are using a PID controller to solve some problem. What problem? Take a situation and think for yourself, what do I expect the controller to do?
Let’s use our cars cruise control example! If we are driving 80 km/h, but the cruise control is set to 100 km/h, what do you want the controller to do? It needs to accelerate the car! So it needs to add some throttle, maybe 20%. If we are driving 90 km/h, we also need to add throttle, but not as much as before, let’s say 10%. When we drive over the limit, let’s say 110 km/h, we do not want to accelerate anymore, maybe we even want to brake a bit. You could say -10% throttle (which is braking).
This step may seem silly, but it’s the basis of a good PID controller design! If you don’t understand the problem, your PID controller won’t understand it either and you won’t even know what is wrong with it.
As I mentioned at the beginning, 90% of all PID controllers are actually only P-controllers. The P-gain is therefore also a good one to start the tuning process. (PS: depending on your system, it can be interesting to set all gains to 0 and observe what happens to the system without any input).
To set the initial P-gain value, simply look back at step 1 and continue the reasoning. The input to the PID controller is usually the difference between the target and the actual value. With an initial guess of what output we want for a given input, we can calculate the P-gain. Looking at the table from step 1, the P-gain seems to be 1. This method will give you at least the correct order of magnitude for the P-gain.
Try out the initial gain using a step response in a simulated environment. How did that go? Next up you want to explore what happens if you make the P-gain 10x smaller and larger. This will give you a feel of what is too little, and what is way too much. If you are in a simulated environment, make sure you go over the limit and find out what value is too high.
If you notice that your controller goes to the setpoint, but never quite achieves it, that’s normal. It’s called the steady-state offset and we’ll fix it with the Integrator part of the PID.
The integral component of the PID controller is used to counter constant disturbances or offsets. Think about wind and friction. As the name suggests, the I-part will make use of an integral in order to determine the output. This makes things a bit more complicated.
Integral controllers can be quite dangerous as well. You should always bound the integral to prevent it from blowing up. I think about 25% of all the problems I have seen with PID controllers were due to badly capped integrals. Just make sure you bound it to whatever value is reasonable for your problem.
Look at the results from step 2. If you do not see a steady-state offset, you do not need an integral controller so you can leave the I-gain at 0. If you do have a steady-state offset we will need an integral controller. What I usually do is look at how big the steady-state error is and what the P-controller output is at that point. You also need to determine what a reasonable time range is for your integral controller to react. Then I do the following calculation to determine the initial I-gain.
In order to determine the bounds of the integral, you can simply take 5 times the expected error. If you want to be more strict you can do 2x or if you want to give more freedom to the controller you can do 10x.
Try out the initial gain and see what happens. Did it solve the steady-state error? Do you have an overshoot now?
If the initial gain did not solve the steady-state error, you probably need a higher I-gain. So feel free to make it 10x larger!
If you have massive overshoot and oscillations, you either need a smaller I-gain (larger I-gains can also solve it actually..) but most likely the bounds on your integral are too loose. If you are in a simulated environment you can quickly check what the integral value is and see if it blows up or not.
Note that the integral will always accumulate, even when the system is not in a steady state yet. There are more fancy methods than just bounding the integral, but personally, I feel like they create more problems than they solve. Have a look at ‘anti-windup’ if you are interested!
In my experience as a control engineer, I have never seen a successful PID controller with the derivative component. I have seen attempts, and I have seen them all fail miserably.
The idea of the derivative component is to create a damping or predictive effect. When your controller has a lot of overshoot, it will be very tempting to try and solve it with some D-gain. But actually, it just means there is something wrong with your controller or system.
The derivative part of the PID is very sensitive to noise and can usually only be tuned for one specific situation. In simulation, it might solve your problems for 1 specific case, but you’ll quickly run into trouble when implementing it in real life.
My advice: don’t use the D-component.
Create yourself a setup where you can easily (and safely!) test out different gains and different cases. This can often be achieved with a simple simulator. The simulator does not have to be an accurate model of reality, as long as the basic principles are the same you will already come a long way.
Make sure to log as much data as you can so you can see and understand what happens. Playing around in the simulated environment will create an understanding of the problem that will be useful when moving on to real-life testing.
Lastly, make sure you test different use cases. It is very tempting to tune your controller for only one situation but in reality, you encounter many different situations. Try to create a few different situations and check if your controller still performs as you expect.
Today we will tune the cruise control of a modern passenger car! In the article, I used the example of the cruise control already a few times. I made a simulated environment where we can try out different gains and see the effect.
The simulator has a very simple car model that uses a throttle % as an input. A PID controller will use the resulting speed and target speed to determine the amount of throttle needed. I also added a bit of a delay in the car's engine to make it a bit more difficult/realistic. Engines do not produce torque instantly.
The simulator can be found on the public repository https://gitlab.com/marple-public/marple-tutorials. For the visualizations, I made use of Marple and the python integration.
We actually did this exercise already in the explanation. If the car goes too slow, we need to add throttle. If the car is too fast, we need to brake. In practice you probably want to add some limits such that the cruise control won’t make your car go full throttle.
We start with an initial value of 1, as determined already in the explanation above. The resulting speed can be seen below. Blue is the actual speed, green is the target speed. This already looks quite good! We have a steady-state offset of about 12km/h, but that’s ok.
We can now try with a gain of 0.1 and 10 and see what happens. The results can be seen below, the colors now indicate the different gains. It can be seen that a gain of 10 responds quicker and that a gain of 0.1 is too little. You could argue that a gain of 10 is actually the best here, but given that it’s a passenger car I think this is a bit too aggressive. Let’s proceed with a gain of Kp = 2.
With a P-gain of 2 we have a steady state offset of about 6 km/h. At that point the P-action equals 12. We can determine the initial I-gain using the formula from above, we use 2 seconds as the time factor in the equation. This results in a I-gain of 1.
We also need to set a bound on our integral, using the equations above we get a bound of 60.
Simulating this results in the following response. There is a bit of overshoot, but the steady-state error has been solved!
The reason that we have overshoot is because of the integral that is building up in the first phase. We can set the bound a bit tighter in order to reduce the overshoot, this will however make it less robust for changing conditions. Using a bound of 20 you can clearly see the difference.
I also simulated without a bound to give you an idea of what happens… It’s all over the place.
Lastly, we still need to play around with the I-gain a bit to get a feeling if we are in the correct range. We can see that a gain of 10 does not work nicely and that a gain of 0.1 is not enough. So an I-gain of 1 was a good initial guess!
So far we have tested a constant step input, but what would happen if we created a more dynamic environment? Another popular way of testing a controller is using a sinusoidal input or multiple steps after each other. We can see that in both cases the controller performs quite OK. It obviously depends on the requirements for the car whether this performance is too quick or too slow.
I have given you a simple recipe to design and tune your PID (PI actually) controller. Use it for simple cases! When things get more complex, you will also need more complex solutions.
We created a cruise controller and applied the PID recipe, this worked quite well and we can be happy with the results.