Trouble with Arduino PID Slow Cooker (Crock Pot) Sous Vide

I have built a PID controller using Brett Beauregard's PID library with temperature input from DS18B20 and Output to SSR controlling AC power to a Slow cooker/ crock pot.

It all works... as in the PID computes and outputs to control the power...

However, no matter what tuning values I put into it using the same setpoint (50 degrees C) the performance profile is always the same;

Output ramps up to 100% and stays there until Setpoint is reached (64 mins +- 5) where it declines again.

This means that overshoot is up to 69 degrees C for 50 mins; it then takes 134 mins +-5 to reach setpoint again when it then cycles setpoint by +- 3.5 degrees on 100 min half waves.

I have tried Kp only on 0.1, 1, 2, 47.... I have added Ki and Kd at different levels as well... It is always exactly the same.

Does anyone know where I am going wrong?

I would have thought that the PID would ramp down from 100% before Setpoint to minimise overshoot?

Are you outputting variable power or is it on/off?

The Slow Cooker is set to high all of the time and the SSR controls the power on and off using the plug socket.

It controls the SSR on and off time by limiting output on the PID between 0 and 5000 which is the window in m/s used to drive output.

Er, right, so out of how many seconds? Eg. per 10 seconds? A "window" of output of 5 seconds must be 5 out of something.

I've been looking into this because I want to understand PIDs better. First, let's take a look at the proportional part (the Kp factor) and make the others zero.

Now the algorithm outputs the proportional amount as:

error = setPoint - Input;
output = Kp * error;

So, if we have 30 degrees, and we want 50 degrees, the error is 20, and the output is Kp times 20. Now if (for such a large difference in temperature) we want 5000 as an output then Kp must be high enough that 20 * Kp is at least 5000.

eg. Kp = 300. Ki = 0, Kd = 0.

So now:

error = 50 - 30;
output = 300 * 20;  // 6000

That gets scaled back to 5000 by making it the maximum:

  myPID.SetOutputLimits (0, 5000);  // 0 to 5 seconds

Test results using simulated data:

input = 30.00, Error = 20.00, kp * error = 6000.00, Adjusted output = 5000.00
input = 31.00, Error = 19.00, kp * error = 5700.00, Adjusted output = 5000.00
input = 32.00, Error = 18.00, kp * error = 5400.00, Adjusted output = 5000.00
input = 33.00, Error = 17.00, kp * error = 5100.00, Adjusted output = 5000.00
input = 34.00, Error = 16.00, kp * error = 4800.00, Adjusted output = 4800.00
input = 34.96, Error = 15.04, kp * error = 4512.00, Adjusted output = 4512.00
input = 35.86, Error = 14.14, kp * error = 4241.28, Adjusted output = 4241.28
input = 36.71, Error = 13.29, kp * error = 3986.80, Adjusted output = 3986.80
input = 37.51, Error = 12.49, kp * error = 3747.60, Adjusted output = 3747.60
input = 38.26, Error = 11.74, kp * error = 3522.74, Adjusted output = 3522.74
input = 38.96, Error = 11.04, kp * error = 3311.38, Adjusted output = 3311.38
input = 39.62, Error = 10.38, kp * error = 3112.69, Adjusted output = 3112.69
input = 40.25, Error = 9.75, kp * error = 2925.93, Adjusted output = 2925.93
input = 40.83, Error = 9.17, kp * error = 2750.38, Adjusted output = 2750.38
input = 41.38, Error = 8.62, kp * error = 2585.35, Adjusted output = 2585.35
input = 41.90, Error = 8.10, kp * error = 2430.23, Adjusted output = 2430.23
input = 42.39, Error = 7.61, kp * error = 2284.42, Adjusted output = 2284.42
input = 42.84, Error = 7.16, kp * error = 2147.35, Adjusted output = 2147.35
input = 43.27, Error = 6.73, kp * error = 2018.51, Adjusted output = 2018.51
input = 43.68, Error = 6.32, kp * error = 1897.40, Adjusted output = 1897.40
input = 44.05, Error = 5.95, kp * error = 1783.56, Adjusted output = 1783.56
input = 44.41, Error = 5.59, kp * error = 1676.54, Adjusted output = 1676.54
input = 44.75, Error = 5.25, kp * error = 1575.95, Adjusted output = 1575.95
input = 45.06, Error = 4.94, kp * error = 1481.39, Adjusted output = 1481.39
input = 45.36, Error = 4.64, kp * error = 1392.51, Adjusted output = 1392.51
input = 45.64, Error = 4.36, kp * error = 1308.96, Adjusted output = 1308.96
input = 45.90, Error = 4.10, kp * error = 1230.42, Adjusted output = 1230.42
input = 46.14, Error = 3.86, kp * error = 1156.60, Adjusted output = 1156.60
input = 46.38, Error = 3.62, kp * error = 1087.20, Adjusted output = 1087.20
input = 46.59, Error = 3.41, kp * error = 1021.97, Adjusted output = 1021.97
input = 46.80, Error = 3.20, kp * error = 960.65, Adjusted output = 960.65
input = 46.99, Error = 3.01, kp * error = 903.01, Adjusted output = 903.01
input = 47.17, Error = 2.83, kp * error = 848.83, Adjusted output = 848.83
input = 47.34, Error = 2.66, kp * error = 797.90, Adjusted output = 797.90
input = 47.50, Error = 2.50, kp * error = 750.03, Adjusted output = 750.03
input = 47.65, Error = 2.35, kp * error = 705.02, Adjusted output = 705.02
input = 47.79, Error = 2.21, kp * error = 662.72, Adjusted output = 662.72
input = 47.92, Error = 2.08, kp * error = 622.96, Adjusted output = 622.96
...
input = 49.53, Error = 0.47, kp * error = 141.10, Adjusted output = 141.10
input = 49.56, Error = 0.44, kp * error = 132.63, Adjusted output = 132.63
input = 49.58, Error = 0.42, kp * error = 124.67, Adjusted output = 124.67
input = 49.61, Error = 0.39, kp * error = 117.19, Adjusted output = 117.19
input = 49.63, Error = 0.37, kp * error = 110.16, Adjusted output = 110.16
input = 49.65, Error = 0.35, kp * error = 103.55, Adjusted output = 103.55
input = 49.68, Error = 0.32, kp * error = 97.34, Adjusted output = 97.34
input = 49.70, Error = 0.30, kp * error = 91.50, Adjusted output = 91.50
input = 49.71, Error = 0.29, kp * error = 86.01, Adjusted output = 86.01
input = 49.73, Error = 0.27, kp * error = 80.85, Adjusted output = 80.85
input = 49.75, Error = 0.25, kp * error = 76.00, Adjusted output = 76.00
input = 49.76, Error = 0.24, kp * error = 71.44, Adjusted output = 71.44
input = 49.78, Error = 0.22, kp * error = 67.15, Adjusted output = 67.15
input = 49.79, Error = 0.21, kp * error = 63.12, Adjusted output = 63.12
input = 49.80, Error = 0.20, kp * error = 59.34, Adjusted output = 59.34
input = 49.81, Error = 0.19, kp * error = 55.78, Adjusted output = 55.78
input = 49.83, Error = 0.17, kp * error = 52.43, Adjusted output = 52.43
input = 49.84, Error = 0.16, kp * error = 49.28, Adjusted output = 49.28
input = 49.85, Error = 0.15, kp * error = 46.33, Adjusted output = 46.33
input = 49.85, Error = 0.15, kp * error = 43.55, Adjusted output = 43.55
input = 49.86, Error = 0.14, kp * error = 40.93, Adjusted output = 40.93
input = 49.87, Error = 0.13, kp * error = 38.48, Adjusted output = 38.48
input = 49.88, Error = 0.12, kp * error = 36.17, Adjusted output = 36.17
input = 49.89, Error = 0.11, kp * error = 34.00, Adjusted output = 34.00
input = 49.89, Error = 0.11, kp * error = 31.96, Adjusted output = 31.96
input = 49.90, Error = 0.10, kp * error = 30.04, Adjusted output = 30.04
input = 49.91, Error = 0.09, kp * error = 28.24, Adjusted output = 28.24
input = 49.91, Error = 0.09, kp * error = 26.54, Adjusted output = 26.54
input = 49.92, Error = 0.08, kp * error = 24.95, Adjusted output = 24.95
input = 49.92, Error = 0.08, kp * error = 23.45, Adjusted output = 23.45
input = 49.93, Error = 0.07, kp * error = 22.05, Adjusted output = 22.05
input = 49.93, Error = 0.07, kp * error = 20.72, Adjusted output = 20.72
input = 49.94, Error = 0.06, kp * error = 19.48, Adjusted output = 19.48
input = 49.94, Error = 0.06, kp * error = 18.31, Adjusted output = 18.31
input = 49.94, Error = 0.06, kp * error = 17.21, Adjusted output = 17.21
input = 49.95, Error = 0.05, kp * error = 16.18, Adjusted output = 16.18
input = 49.95, Error = 0.05, kp * error = 15.21, Adjusted output = 15.21
input = 49.95, Error = 0.05, kp * error = 14.30, Adjusted output = 14.30
input = 49.96, Error = 0.04, kp * error = 13.44, Adjusted output = 13.44
input = 49.96, Error = 0.04, kp * error = 12.63, Adjusted output = 12.63
input = 49.96, Error = 0.04, kp * error = 11.88, Adjusted output = 11.88
input = 49.96, Error = 0.04, kp * error = 11.16, Adjusted output = 11.16
input = 49.97, Error = 0.03, kp * error = 10.49, Adjusted output = 10.49
input = 49.97, Error = 0.03, kp * error = 9.86, Adjusted output = 9.86
input = 49.97, Error = 0.03, kp * error = 9.27, Adjusted output = 9.27
...
input = 49.99, Error = 0.01, kp * error = 1.86, Adjusted output = 1.86
input = 49.99, Error = 0.01, kp * error = 1.75, Adjusted output = 1.75
input = 49.99, Error = 0.01, kp * error = 1.64, Adjusted output = 1.64
input = 49.99, Error = 0.01, kp * error = 1.54, Adjusted output = 1.54
input = 50.00, Error = 0.00, kp * error = 1.45, Adjusted output = 1.45
input = 50.00, Error = 0.00, kp * error = 1.36, Adjusted output = 1.36

That heats fully for a while then drops off as the error amount reduces to zero. That alone might be suitable for your purposes.

In my simulation the temperature goes up in proportion to the output (that is, output / 5000 per iteration).

You could make it heat fully for longer by making Kp higher, but then it might overshoot more. Try and see.

The output window is 5 seconds so the PID returns a value between 0 and 5000 for 0 to 100%.

The relay is then turned on for the output and off for the remainder of the window; e.g. if the output is 20% the output will be 1000 and the Relay will be on for 1000 m/s and off for 4000 m /s every 5 seconds etc etc

Ok, that makes sense. How then with the settings I entered for Kp = 0.1 and Kp = 1 with Ki and Kd at 0 does it ramp up to 100% and why do you think the profiles were the same?

Without seeing your code it is hard to answer that.

The code is long, as I use a menu library for it so I can add further applications to the controller for a vacuum chamber at a later date.

I can post it if it would help? but the PID code is included in Brett Beauregard's PID library.

It is a implementation of the standard textbook PID equation.

I also have the excel data sheets if that would help but I'm not sure how to post them?

At least post your PID part. But really, it is probably simpler to zip up the lot and post it. We can quickly skim the irrelevant parts.

Based on what I said before, with Kp of 1, and an error of 30, it should have output 30, not 5000. I don't believe it just made 5000 up, so you must be multiplying somewhere.

Also, something slow-acting like a crock pot could probably just be controlled by a simple algorithm, like:

if (temperature < 50)
  {
  turnHeaterOn ();
  }
else
  {
  turnHeaterOff ();
  } 
delay (1000);  // to avoid thrashing

Ok, here is the code

Sous Vide Code.zip (7.66 KB)

And the first lot of data

Sous Vide Log 1.zip (1.17 MB)

And the last lot, this includes some power profiling on 20%, 40% and 100% without PID control

Sous Vide Log 2.zip (955 KB)

Agreed that the simple algorithm would work but if it doesn't turn off until SP the I still end up with 50 mins overshoot and 130 mins to get back to SP with 60 mins to reach SP that is 4 hours of run up. I was hoping by using PID I could eliminate the overshoot and pull straight to SP in less than 100 mins.

I also know that it settles at about 56 degrees at 20% power as per data, so theoretically I could just map the settle points at different power inputs and work an algorithm from that... but its a lot of work at approx 12 hrs per experiment and again, long run up times...

dave_robinson_022:
The output window is 5 seconds so the PID returns a value between 0 and 5000 for 0 to 100%.

How is that?

  Timer1.initialize(15000);
  Timer1.attachInterrupt(TimerInterrupt);

You are only updating “now” every 15 seconds.

Oops, 15 milliseconds. Oh well.

I think I would make "now" volatile, as it is updated in an ISR, but that probably is not the whole problem.

Would it be better to increase interrupt time to match PID computing by now?

I did consider running the whole thing in the interrupt but this would only really work if Sous Vide was the only application of the controller?