This mod starts with the boiler_pid_worker() function that is called by a mbed Ticker at a configurable frequency (which you can change with PID_WORKER_PERIOD in brewcontrol.cpp). Every time the function runs, it reads the boiler temperature from our high precision temperature sensor and feeds this data into the PID function, which then returns a boiler power setting between 0 and 1. This PID algorithm is telling us the power setting we need to set on the boiler to reach our target temperature in the most optimal fashion. The more times per second it runs (PID_WORKER_PERIOD), the more efficient it will be.
In order to set a specific power setting on the boiler, we control the SSR with a PWM (pulse width modulation) signal from the micro-controller to “pulse” (fast on and off) power to the boiler. By controlling the frequency of the pulse, we are able to control the amount of power given to the boiler over a period of time. So if we only switch the power on for 0.5 seconds every second, we are essentially giving the boiler 50% of the full available power.
The SSR being used is a zero-cross type. If we try to switch in the middle of an AC cycle, the SSR will wait until the end of the half-cycle to switch. This is an important feature because it eliminates power surges when we switch our heating elements on and off. Unfortunately, it also limits our ability to switch instantly, which in turn limits our switching speed or “resolution”, i.e. we can only switch as fast as the value of the AC signal frequency. So, for a 50Hz signal, we can switch a maximum of 100 times per second (50 cycles = 100 half-cycles), for a 60Hz signal, 120 times per second.
Assuming a 50Hz AC signal, if our PID algorithm tells us to set the boiler power to 1%, our fastest option is to switch on for 1/100 of a second and to switch off for 99/100 of a second and to repeat this every second. This means that we can only accept new power values from our PID algorithm at the most once per second, otherwise we would be overwriting the previous value. So there is a trade-off between PID_WORKER_PERIOD and the max resolution of the power setting. If we want a 1% resolution (up to 100 discreet values), we can run the PID algorithm a maximum of once per second. 2% resolution (up to 50 discreet values) means a maximum of 2 PID runs per second, 10% resolution (up to 10 discreet values) gives us a maximum of 10 PID runs per second, etc…
The maximum resolution is configured by setting the period of our PWM signal (BOILER_PWM_PERIOD in brewcontrol.cpp). On a 50Hz AC signal, a PWM period of 1 second means 1% resolution, 0.5 seconds means 2% resolution, etc…
More experimentation needs to be done to determine the optimal resolution/PID_WORKER_PERIOD. Right now we are working with 1% resolution, so we have these:
50Hz -> BOILER_PWM_PERIOD=1 PID_WORKER_PERIOD=1
60Hz -> BOILER_PWM_PERIOD=0.8333 PID_WORKER_PERIOD=0.8333
Obviously at 60Hz, we get 20% faster PID runs for the same resolution.
The other bits that need calibration/tweaking are the PID parameters. We started with some values we found online on other mods and then calibrated manually by tweaking and looking at temperature graphs until we got the shape we wanted. When you switch your machine on, you want your temperature to get to your target as quickly as possible without going over. When pulling a shot or steaming, you want the temperature to be a straight line! Here is a writeup if you want to read more on the PID parameters.
There is also the possibility to add a PID auto-tune feature at some point in the future.
We got the graphs by dumping numbers via printf to the USB console, saving them and copying them into a spreadsheet. Hopefully in the future we can have better visualization tools.