Tuesday, December 04, 2007

When computing meets coffee

The goal of this project is to create a computer interface for my Gaggia Espresso machine replacing the factory thermal switches with a PID controller and the “steam” and “pump” toggle switches with a LCD/button menu system.

After seeing the various instructions and kits geared toward modding a home espresso machine with a PID, and their costs and features compared to something like the PID PIC MOD, I decided I would start from scratch and build my own PID. Then I could easily extend it to control the rest of the espresso machine, such as adding a timer to monitor or control the shot time and adding temperature presets.

Parts list:

1x Arduino Decimillia
1x 25A zero-cross SSR (for pump, could be much smaller, > 5A)
1x 40A zero-cross SSR (for heating element, could be 25A)
1x AD595 thermocouple conditioner/interface IC
1x Type-K thermocouple (could use type T or possibly other)
1x 16×2 character LCD with HD44780 parallel interface
3x SPST normally-open momentary push-button switch
10AWG stranded wire for 125V wiring (12AWG is probably good enough)
22AWG solid wire for 5V wiring
Power supply for Arduino
Various resistors, capacitors, quick-disconnect connectors for 10AWG wire, etc.

I’m using an Arduino Decimillia micro-controller which utilizes the AVR AtMega168. The hookup of the components is pretty straight-forward; The LCD uses 6 digital IO pins - 4 for a 4 bit parallel data bus, one for Register Select and one for Operation (data read/write) enable signal. The SSRs take one digital IO pin each. The AD595 takes one 10 bit AD converter pin. The three buttons share one external interrupt pin and use two digital IO pins to indicate which button has been pressed; with this scheme, one interrupt can be used with 2^n buttons taking only n+1 pins. Various resistors, capacitors and other components are used, but the details are rather tedious and boring.

The software was written in the Arduino Programming Language, which is based on Processing and is similar to C++ with a few java-like syntactical niceties thrown in.

The main loop is executed at about 100Hz. During each iteration of the loop the AD595 is read and summed 100 times and after 100 iterations the average is taken and the current temp is updated. I started by oversampling 100x but found that that resulted in poor accuracy and provided many more readings than I was using. After some experimentation I found that oversampling 10,000 times gave great accuracy (about +/- 0.1 deg. Farenheit) and didn’t introduce any negative side effects due to excessive smoothing of the temperature curve. Also, since the PID period is one second, oversampling 10,000 times, giving me one reading per second, is just enough for the PID to have an updated reading at each iteration.

The PID algorithm is based off of this article: PID without a PHD. One of the bigger problems I had was tuning the PID, as seems to be the case for many people. What gave me such a hard time was all the instructions on the internet about how to tune a PID. Most say to start with Ki and Kd set to 0 and adjust Kp first. They go on to say that Ki can then be set to remove any static offset from the setpoint. Kd is said to be tricky to set and unnecessary for most applications.

After having trouble with that tuning technique and observing the system in operation a bit I realized that those instuctions wouldn’t work for me. The problem with relying on Kp to correct most of the error is that you have to be below the setpoint before any correction occurs (unless you add a constant positive error term to each reading). Because the system takes a few seconds to respond, the temp dips pretty low before it starts to reverse. Likewise, as the temp is climbing towards the setpoint, proportional error correction is applied right up until hitting the setpoint, at which point too much heat has been added and the temp overshoots the setpoint considerably. Adding ANY Ki just makes things worse. It dawned on me that the system was responding way too late, so the PID needed to anticipate the future state of the system in order to be effective. The future temp depends on two things, the current temp and the rate of change of temp. After observing that the temp would climb about 15 deg. after shutting off the boiler at maximum rate of change and doing some simple math to figure out what some reasonable values for Kd and Kp should be, I came up with settings which hold the temp to within +/- 1 deg. farenheit of the setpoint, and not more than 4 or 5 deg. of over/undershoot when turning on or recovering from steam mode. Intra-shot stability is also quite good usually dipping no more than a couple of deg. farenhiet and ending back at setpoint by the end of a 30 sec. 1.75 - 2 oz. shot. This is with Kd set to an aggressive 5x Kp and Ki set to 0. I believe this can be improved with further tuning of the PID parameters.

Because the boiler is either off or on, I use a PWM (pulse width modulation) technique to control the boiler. I treat the PID output as a percentage and keep the boiler on for that percent of a second, updating every second. Anything < 0% is treated as 0% and anything > 100% is treated as 100%. I round the output to the tens so that I limit the minimum on-off cycle time of the boiler to 0.1 seconds. This is for several reasons; anything faster is really unnecessary, it wears the SSR less and it limits the amount of EM interference caused by switching 1300 watts on and off that quickly.

The machine works great! I get better stability and control than I was expecting, and it came together pretty quickly with no major problems. Additionally, I still need to finish fine-tuning the PID parameters to maximize stability.

As for the Espresso, that is a whole other subject that I will dedicate a whole post to, but for now I will say that I’m getting some great results with my local San Francisco favorites — Blue Bottle Espresso Temescal, Blue Bottle Roman Espresso and Coffee to the People’s Beatnik Espresso. I’ll be picking up some Blue Bottle Hayes Valley Espresso and some Blue Bottle Retrofit Espresso shortly.

What I have left to do:

Fine-tune the PID parameters
Improve the accuracy of the temperature reading by using an equation to adjust for the slight non-linearity of the AD595
Fix the sometimes flaky button circuit
Save settings to EEPROM instead of reverting to defaults upon power cycle.
Add persistent settings profiles that can be chosen via the setup menu.
Calibrate the temp circuit
Correlate the boiler temp to group head temp or add secondary thermometer to group head
Show average error in +/- deg. F/C
The program is still pretty beta, with some features requiring cleaning up and others needing to be implemented. When it’s a bit more finished I will post the GPL’d source code, if there is any interest.

Nash Lincoln

No comments: