45 comments

[ 2.9 ms ] story [ 99.9 ms ] thread
I used a PID controller once to build a drone for a class for my masters. I wish I had the write you just produced than because I had an issue with integral windup and just couldn't express that is was an issue in words. I didn't really understand what each of the coefficients were doing because it was a Hardware based PID controller and being a software engineer that made it very very tricky. Thanks for sharing this
I wrote a super basic 2 axis "autopilot" with Python for X-Plane. The concepts are super simple. Getting the controller tuned properly is not.

For a surprisingly large number cases, setting a P value in the 1-3 range and a I value as P/10 works extremely well.

I now write Python for my day job. This code was written before that and now that I look at it, it is quite ugly:

https://austinsnerdythings.com/2021/10/19/coding-a-wing-leve...

A different part of my day job includes, tangentially, tuning PID control parameters for 200-500 HP electric submersible pumps in oil wells. Again, it is amazing how setting an P value in the 1-3 range and an I value P/10 works there as well.

A slightly more advanced autopilot with altitude set and hold (code is even more ugly):

https://austinsnerdythings.com/2021/12/06/coding-a-pitch-rol...

Does that rule-of-thumb assume specific units/value ranges for the input and output signals?
Yes it does, you have to manipulate the expression to make it adimensional. But this rule-of-thumb is only valid for systems whose response time is less than 500ms.
Writing your PID controller is a few minutes work. Tuning your PID controller is a day job. Most people just don't actually make it their day job =D
(comment deleted)
I once used a $25 off-the-shelf PID temp controller that came with a type K thermocouple and integrated 12v control line to build an air intake regulator for my meat smoker. I couldn't believe the outcome - 3 hours of fuel turned into 11 hours, and the (logged) temperature stayed between 118.4 and 122 degrees celsius for 10 hours of that. This was outdoors, with all the variance that comes with it, and all I did was attach an old 12v case fan and some aluminium ducting to one of the vents. Blows my mind to this day.
The interesting thing is that if you can reframe the problem correctly, a PID controller will probably be involved in the closed loop solution. And most of the time you don't even need the derivative term.

The last few systems I've worked on professionally have been nested PI controllers with some filters on the front or back of them. Just needed the correct framing for the problem (the hard part) and it becomes straightforward to solve.

Maybe I'm misunderstanding something, but wouldn't you still want/need a D term unless you have a system with a nearly instant response?

I'd think that even if you stop applying a delta the second you hit the set-point, if you've built up non-trivial inertia, then you'll overshoot the target fairly significantly?

D term is complicated and it really depends on the situation. You can usually get away without a D term and have acceptable overshoot as long as you have the right anti-integral windup setup, and your I vs P ratio isn't too high.
It’s actually a pretty common practice in the industry and academic. You can change your system block diagram to have the measured value as some sort of rate of change rather than the value itself (this is a non trivial exercise). In return, your system is more stable and you can get rid of the D constant since it’s another value you need to tune and sometimes causes instability in a control sense. It’s a pretty popular technique in high safety applications like aerospace.
It's all a tradeoff of how system response vs. stability and how much overshoot is tolerable.

For the domains I've worked in, with physical components, system response isn't instantaneous, but some level of overshoot is tolerable as long as the system rapidly converges and (this is the important part) cannot end up in a positive feedback scenario. The derivative term tends to amplify noise, which is never what you want.

A little anti-windup, some generous limits around your max extents, and perhaps a gear-shift to switch bandwidths when you approach steady-state, and it's surprising how many problems can be solved with a filter and a PI controller for the closed-loop component of the system. Maybe the actuator is walking you up and down a complicated model space, maybe you've got multiple PIs driving multiple models...but there's a good chance a PI will do a decent job somewhere in the solution.

Use a PID if you want to make more work for yourself.

Specifics will depend on your exact system.

Control theory doesn't come up much in what I do but as a practitioner are Root Locus ever utilized? I've been unpleasantly surprised to see that exact positive feedback instance existing in places you wouldn't want (things wobbling above earth after a control input). Poles and Zeros felt like a lot of magic until a foray into complex analysis ripped that band aid off ;)
Oh yeah, it comes up. It's a way to check for stability and visualize the system. Phase and gain margin have come up more frequently for me, but a lot is going to depend on what you find the most natural way of attacking the problem to be.
Everyone will say "depends on the system" but generally the D term is not only not needed, but typically considered counter-productive or even against best practices. PI-loops tend to be much more stable than PID-loops and far easier to successfully tune for an acceptable response. You do get overshoot with a decently tuned PI-loop, but it's not enough to cause problems. A bit of overshoot doesn't tend to hurt anything.

Of course, a "perfectly" tuned PID loop will be "better" - more efficient, faster to reach setpoint, and minimize overshoot. But the effort/engineering time/operation time involved in tuning it, combined with the risks presented by a subtly poorly tuned loop that goes haywire one day when the system paradigm (characteristic) changes...just isn't worth it.

Obviously there are times when you really do need a D term, but I can confidently say that they're not commonly used in HVAC or petrochemical plants. I'm sure there are other domains where the D term is needed, but in my time as a controls engineer I didn't run across them.

Especially in a video game context, where you can always go in and change how the system works.

A really good way to tell is to consider the relationship between your input and output. PID get's thrown around all the time because a lot of the time you are talking about controlling an accerlation (gas pedal, throttle) to effect a position, so you theoretically need a PID to stand in for a 2nd order differential equation since position and acceleration are two derivatives apart with respect to time. But as you pointed out, you usually can generalize your input and not worry about the D term.

In the video game I'm making, I don't really worry about derivative control, but PID control is mostly there to give the illusion that someone is driving a vehicle rather than it be controlled perfectly by a computer program. I don't want to model out how "skilled" the driver is - all I have to do to give that impression is just give the vehicle better handling.

Yep, D terms are needed in systems where there isn't a natural dampening or reversing force that will naturally bring the value away from what your output tries to do.

With a heater,once you get to zero error, any overshoot will reduce back the opposite way because heat is always lost.

The D term is complicated.

Where you do you get the derivative? If you have to differentiate the input, and there is noise, the raw derivative will have huge variations. Then you need a low pass filter before the differentiator. This introduces lag. So you now have both D gain and filter frequency to tune.

See any classical control theory book for the theory on this.

Even when tuning PID loops for chemical plants as a controls engineer, myself and my colleagues (across multiple companies) generally just set the D term to zero. If the D term (derivative) was needed, tuning that one loop would often be assigned a whole formal project by itself. When I hear people say "PID loop" I almost always subconsciously translate it to hear "PI loop" in my head unless there's evidence that it's a truly complex system.
I've had to use the D term recently in a self guided model rocket project.

When the rocket had an angle error it needed to point it's thrust to rotate itself back to 0. There is no built in stopping force that stops the rocket rotating when the thrust is not angled. So a D term was needed in order to take into account how fast the rotation was happening. When it was rotating to 0 degrees of error, it needed that d term to not overshoot. With the d term, the thrust would swing in the opposite direction to prevent it overshooting.

Do you have a link to the setup you used?
There was a website where you entered little snippets of code IIRC to adjust how a cube moves with friction and then the examples move on to a car moving up a ramp. It was a very sneaky and intuitive way to learn about PID controllers.

I think that was posted here on HN but I can't find the link...

15 years ago I had to create a display system written in Unity for cinemas, there was a capacitive PID controller I had to interface with - at the time it was impossible in Unity - it was a generic PID which just returned a stream of data, meaning there was no discrete driver for the device.

I ended up writing a program in another language - can't recall which - which interfaced with the controller and linked to unity c# through some obscure windows IPC (I think it was Pipes?).

Fun days in early Unity... nostalgia ;-)

My favorite use of a PID controller in Unity was to act as a camera operator for a VR football game.

We used cameras for the screen-display (we could either show you the VR player's perspective, or one of several cameras), and for the jumbotron in the stadium. This ended up being really cool for downfield throws. When you bombed the ball 45 yards to a receiver, it could be a little hard to see the action. It was really natural to be able to glance up at the jumbotron in the stadium to get a closer view of what's happening downfield.

A small custom little PID controller worked really well for tracking the ball in flight, and giving a more natural "human operated" camera feel than perfectly tracking the ball.

We'd also randomly vary the terms within a set range for different virtual camera operators, so you'd get a little bit of variance in the tracking between different cameras and different play sessions.

Also a lot of pretty fun "bugs" from badly tuned PIDs.

Wouldn't it be better to model imperfections separately rather than rely on PID oscillations? I can see how this can easily fail and cause some dramatic and unnatural camera movements.
Well, yes and no. PID is very simple to integrate in a state loop, so it is simple to implement, and gives the illusion of imperfect tracking very quickly. So I imagine this implementation worked rather well. Because the imperfectness isn't random noise, but it is a model of someone trying to aim something, and they do it imperfectly.

Generally though, It would be pretty trivial to add noise for this stuff. You would probably want some noise on the orientation if you wanted to model more of a camera shake. Perlin noise is my go to if I want to introduce randomness to positions really quickly.

Maybe?

It was, like, 15 minutes of work to find a range of acceptable PID values, then generate a random variable from a normal distribution with a mean at the expected value (we just hard-trimmed the random value at 1 std deviation, because we didn't want a 99th percentile result to cause craziness).

Other than the hilarity that ensued while I was playing around with PID values to find the acceptable ranges, I can't recall ever seeing a bug that was problematic from this, so I didn't really give it much thought. Honestly, there were much bigger things to work on.

The nice thing about this system though, is it created "personality" for the camera. If a virtual camera operator had a lower D-value, they'd overshoot just a little bit, semi-consistently. Another one might have a slightly lower I-value, and end up just a little bit further back in the tracking.

It was a super quick way to give a little bit of organic variance to the camera operation, so it didn't feel "samey" every time.

One method that solves 99% of your control problems is the Ziegler-Nichols method [1]. It's a shame it's not taught more often.

No need to model your system, just increase the P gain until the system oscillates naturally. Measure the oscillation period, and then refer to the tables at [1] to choose the P, I, D gains depending on how you like your system response to look like.

[1]: https://en.wikipedia.org/wiki/Ziegler%E2%80%93Nichols_method

You can actually use that method for the remainder constants too. I built an analog motor controller for my control systems lab and the constants were just pots. We would increase the resistance until instability and back off a little. Rinse and repeated for the remainder two pots.
ZN tuning is taught in engineering schools in the US. I even had a lab on it. As far as I remember it was kind of painful to work through and didn’t yield that much better results than hand tuning.

Ah I remembered something else… it needs to find the max Kp which in some cases is just not possible (or wise) to attempt with a real world plant.

On the contrary, ZN is taught is almost every undergrad control course — and not actually used industry. It’s a classic textbook method to demonstrate the concept in simulations but it has many downsides in practice (pushing the system to its boundaries is not a good idea).

Most professionals tune with starting values obtained using model inversion (IMC, direct synthesis) and then hand tune. There is also software like Loop Pro that analyzes the data and proposes tunings.

A lot of gaming doesn't really have the luxury of waiting for the oscillation to kick in, in order to then balance the system, though. By the time there's oscillation, it's already too late to fix, you need to preempt the oscillation.
A thermostat is not an on/off-controller but a proportional controller. The lower the temperature, the higher the flow rate. At least for thermostatic radiator valves this is true.
FWIW everywhere I've lived has an on/off thermostat, maybe it's regional
At least in Europe I've seen plenty of thermostats/boilers that support OpenTherm which allows the thermostat to set the boiler temperature instead of only switching on/off
Control theory is also used by databases (probably not as often as it should be). It's great for "self tuning" [1], for example tuning the various cache sizes a database has to maximize throughput under changing workload conditions. Its definitely worth spending the time to understand PID controllers if your an engineer working on databases.

[1] https://www.vldb.org/conf/2006/p1081-storm.pdf

It's worth looking at any time you're doing dynamic alterations to the system.

There's a lot of terrible things people do in ignorance of control theory while trying to come up with solutions in that space.

Awesome article! None of the videos played for me on mobile Safari, but the text descriptions were enough. I do a lot of Unity development and typically just lerp things with different easing curves. It's great to add PID to the toolbox for elements that are more procedural. Thanks for the sharing.