I am trying to implement a basic PID algorithm on an Arduino Leonardo to mix hot and cold tap water using servo-controlled valves. The goal is to hold the temperature as close to a setpoint as possible. Especially important is preventing the output temperature from overshooting the setpoint to protect the user from burns. Secondarily important is getting the temperature near the setpoint as quickly as possible.

For small changes in temperature, a standard implementation of the PID algorithm seems to work OK. But I don't know how to account for the long delays that may occur when waiting for hot water to reach the valve, since these delays are much longer than standard delays after changing the valve positions.

Obviously depending on the length of the hot water line and time since last use of hot water, it can take multiple tens of seconds for the hot water to reach the valve, so during this time, the water temperature remains fairly constant at a low temperature and the hot water valve soon opens 100%. The integral component begins to accumulate a large error value.

When hot water finally reaches the valve, the detected temperature rises very rapidly to the max hot water temperature. Due to the large integral error, the hot water valve is held at 100% for a long time after the temperature exceeds the setpoint, due to waiting on the integral value be reduced to normal levels. Thus the result is maximum-temperature water for several (tens) of seconds.

I'm not sure how to account for this possible long delay. In such a case, would it be wise to set an upper (and lower) bound on the integral error value, in order to limit max response time? This seems to defeat the purpose of the integral component, and would also still impose some lag after reaching the setpoint.

Or is there a better way to handle fast input changes after a long delay?

Thanks for any advice!

  • 1
    \$\begingroup\$ In fact, I'm wondering whether you need the I-action at all, because I think the water temperature changes are relatively slow compared to the valve actuation. Worse still, you might get oscillatory behaviour because of the extremely poor phase margin you're likely to get (your system may be stable in theory, but may never stop oscillating in practice, because I-action adds phase lag). Also, because you'll possibly burn people, I can't stress enough to take a look at Chu's and JonRB's comments! \$\endgroup\$
    – Sanchises
    May 25, 2015 at 7:36

6 Answers 6


Your problem is called Integral Windup, it's a common control problem. In a non-linear or otherwise bounded region, the controller can't track the setpoint, and the integral increases to a large value. This causes a large overshoot when the setpoint is finally reached, which is exactly what you have deduced is the problem.

The simplest solution is to limit the Integrator value itself to a sensible maximum. Limiting the integral contribution won't work as well, because the integrator will still be wound up to some large value.

Mathworks has a page with some other solutions to integral windup.

In a PID controller, you generally want as little integral term as possible. In a standard mechanical temperature control valve, only proportional control is used, and they work ok. Keep the integral term as small as you can - the user isn't going to notice a small error in the final temperature. You might find that you get acceptable performance with just PD.

As this is a very special, known case, you might consider having a different mode for the controller. Measure the hot inlet temperature, and while it is below the setpoint, just run hot 100%, cold 20%. When it warms up, switch to the PID, with good initial conditions.

  • 1
    \$\begingroup\$ Yes. Ideally you can measure the hot inlet temperature independently, and inhibit windup that way. \$\endgroup\$
    – user16324
    May 24, 2015 at 8:54
  • 2
    \$\begingroup\$ Wind-up may be a problem, but if the integrator were not implemented, e.g., the destabilising effect of the delay would still remain. Smith Predictor is a good method for mitigating the effects of a pure time delay. Addressing integrator wind-up alone does nothing to overcome the inherent phase lag introduced by the time delay. \$\endgroup\$
    – Chu
    May 24, 2015 at 13:32
  • 2
    \$\begingroup\$ exactly, I don't think this is purely integrator windup, even if it is that. its a valid concern that should always be mitigate for EVEN if normal operations does not hit the needed conditions \$\endgroup\$
    – user16222
    May 24, 2015 at 13:59
  • \$\begingroup\$ Wow, great answer! I was thinking along this line (limiting the integrator maximum value) but did not phrase the question properly so I was misunderstood. It's good to see that I'm at least in the ballpark with a solution. I'm thinking the simplest solution would be to disable the "I" factor until the temperature reaches a controllable range. This would allow for very fast response to changes. Then when we see some actual temperature change and get near the desired result, re-enable the integral to add the extra push needed. Thanks for a detailed answer! \$\endgroup\$ May 25, 2015 at 3:12
  • \$\begingroup\$ But the integral term isn't there to speed it up, it's there to correct for a systematic error, especially a proportional coefficient that isn't quite right. No? And in this situation the P coef. can't be perfect all the time because it will vary depending on water pressure in both pipes. \$\endgroup\$ May 26, 2015 at 22:43

The key to controlling this process efficiently is to realize that the hot and cold taps do not operate symmetrically, and any optimal algorithm has to take this into account.

When you don't use the hot water for a time, it cools in the pipe.

When you don't use the cold water for a time, it remains the same as it ever was (unless the cold water is from a cold water tank with a chiller, which would be awesome to have on hot summer days but I'm betting is quite rare in practice).

Thus we assume we don't know what we get from the hot water pipe, but we can depend on the cold water pipe being pretty much constant throughout a run.

Thus, from the temperature of the mixed water, and from knowing the valve setting, and from an estimate of the temperature of the cold water, we can estimate how hot the water currently coming from the hot water pipe is. Then you can adjust the valve to get the correct output temperature without PID, just based on evaluation of a thermodynamic formula.

To get the "estimate of the temperature of the cold water" you can run cold water for a short time (few seconds maybe) at the start of the cycle and read the temperature. Then assume it won't change thereafter, as you don't have enough data to solve for both temperatures.

This scheme won't be perfectly accurate, but I estimate it will reliably get within the ballpark without the possibility of drastic overshooting. Then you run PID on top of this scheme to fine-tune the results, but limit the change to the valve setting that PID is allowed to produce. And possibly reset the PID state when you have significant changes in the hot water input temperature.

Fancier solutions are possible with multiple temperature sensors.

  • \$\begingroup\$ Another great answer - thinking outside the PID box. I had considered just testing the water temperatures and creating some sort of lookup table with approximate valve positions to yield the desired output temperature. You're right that the cold is relatively constant, albeit possibly colder in winter. The water lines are buried at about 24-36 inches and we usually have mild temperatures here. Then I could also account for the maximum hot water output temperature (about 120 F) and create a lookup table that positions the valves appropriately, using PID for fine-tuning after warm-up. \$\endgroup\$ May 25, 2015 at 3:14
  • 1
    \$\begingroup\$ Well water can stay very cool even during warm summers depending on the depth/source. The "cold" water resting in the house pipes is warmer than what will be pumped from below. So the cold water actually gets colder with use (until it approaches the underground water temperature). I'm always "surprised" when I go to the "big city" and the cold water never gets cold. \$\endgroup\$
    – rickhg12hs
    May 25, 2015 at 5:36

I just wanted to add one detail to the nice answers above about what control engineers do for the integral wind-up possibilities. This also happens in many industrial processes and it is an art rather than science.

There are typical textbook actions against this without sacrificing from the integral gain which might be really required for the performance spec.

  1. Every time you cross the zero error level you reset the integrator. This makes the integrator an integrator on-demand type of nonlinear element instead of a blind accumulator.

  2. You basically connect the integral action input block to an indicative element in the loop. This might either be the output of the integrator to judge whether it started the build-up (which requires an understanding of the process to make the judgement proper). Or you check whether your actuators saturated or not and form a feedback loop based on that information. I just randomly picked the first link that came out of google and at the end of this video there is a graphical explanation of my last point. https://www.youtube.com/watch?v=H4YlL3rZaNw

  • \$\begingroup\$ Good points, thanks for expanding on the idea. Thanks for the video, it explains the problem very well. \$\endgroup\$
    – tomnexus
    May 31, 2015 at 18:32

Sometimes it can be helpful to have multiple sets of PID parameters, for coarse-grained stages of the system's range of operation, which you change on the fly as the system passes from one stage of behaviour to another. For example, one set of Kp, Ki, & Kd for when you turn on the hot tap & get only cold water; then once you start seeing the temperature jump up, switch to another set of Kp, Ki & Kd. Then tune the two accordingly.

Are you using the PID Library in the Arduino Playground by Brett Beauregard? This one is quite nice. And there's an 'adaptive' example of this in there too.

  • \$\begingroup\$ Thanks for the suggestions. Not using the pid library, I wrote it myself to learn more about how it works. \$\endgroup\$ May 24, 2015 at 5:23
  • \$\begingroup\$ Did you consider feed forward? It's like fast changes affect output through open loop, so you don't wait to closed loop to react. \$\endgroup\$
    – user76844
    May 24, 2015 at 6:03
  • \$\begingroup\$ I'm trying to wrap my brain around how "feed forward" would work in this instance. Would the input be the desired temperature, and the output would set the valves to a pre-determined position (as discussed in my other comment above) using a lookup table or simple equation? \$\endgroup\$ May 25, 2015 at 3:26
  • \$\begingroup\$ You can use feedforward in addition to your feedback (closed loop PID). You simply add the action of the feedback controller to the action of the feedforward controller. Ideally the feedforward controller would be an inverse model of the valve. Feedforward essentially gives you instant action on a setpoint change. Even with feedforward plus feedback you do still need to account for windup in the feedback control compensator. The feedback component needs to be factored in. \$\endgroup\$
    – docscience
    May 27, 2015 at 19:35

Have you modeled the system?

Do you have some time-based data showing the overshoot - especially the freq

These are two questions that should be asked with any control-based query.

From what you have described, your integral gain is too high, way to high. It could be due to integrator windup: the code shown has some real practical concerns one of which is it isn't the greatest of discrete integrators

  • Very poor discrete integrator topology
  • No clamps/limits either on the I output let alone on the P+I output

It equally could be because it is very high and it takes time to decrement down.

So yes the value stored in the I register could have wound up to say ... 1000C because the P+I were not set to the response of the system and then it has to wind down.

First thing I would do is capture realtime data for post processing.Next I would run P-only and ensure the proportional gain achieve ALMOST the desired temperature (control theory states it won't). The depending on whether

  1. Analysis of the present capture data facilitating in determining suitable I gain
  2. A plant model is derived to create suitable gains

I would start by changing the PID code to be a better implementation and then add a small bit of I, just to prove a point.

You really need to determine what these gains are meant to against. The input is temperature, the output is... flow? so there should be a flow/C transfer and a Flow/Cs transfer function.

  • \$\begingroup\$ Good answer also, thanks. I have not modeled the system, as I don't know how yet - just beginning to get my feet wet in this study. You are correct that the I value increases out of reasonable bounds. Can you direct me to a better implementation algorithm for the Integrator? Pseudocode is best, as it allows me to learn and put the code into my own words, rather than copy/paste. Also, can you direct me to any introductions to modeling simple systems like this? You are correct that flow levels (hot & cold mix) are the outputs of this system. Currently it's just inversely proportional H/C. \$\endgroup\$ May 25, 2015 at 3:20
  • 1
    \$\begingroup\$ Ill add a tweak shortly \$\endgroup\$
    – user16222
    May 26, 2015 at 8:59

One way I like to solve the Integral Windup is to stop accumulating the error whenever your control output is at its maximum deflection. Or scale it by how far it is from the maximum deflection. So whenever your controller outputs "hot water 100%, cold water 0%", just don't accumulate the error, but don't reset it to zero either.

I don't like limiting the integral to a maximum because then there's a limit to what systematic error your PID can compensate for.

I would also suggest that instead of making a "dumb" PID that only has one parameter it's trying to control without knowledge of the underlying system, you install two extra temperature sensors, on both the hot and the cold input. You then attempt to find a function that approximates the desired position based on the input temperatures, and you only use the PID loop to adjust for the error in the output of this function.

The error will be significant because you don't measure flow (well, unless you do of course), which depends not only on the valve positions (known) but also on water pressure (unknown).

Still, this should help a lot with the problem of hot water finally reaching the tap because in a well-damped PID loop, you have to rely on the D element being well-calibrated to quickly reduce the hot flow. In my experience getting the derivative coefficient correct is usually the hardest. But if you had the two extra sensors, the main output would change exactly as quickly as the input water temperature, so basically instantaneous, without any need for the derivative element at all.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.