I had learned a few things from doing the Saeco project, many of which I had forgotten in the intervening 3+ years, but here were the things that I wanted to do better/differently on this one (in no particular order, now that I am working again my blog posts are written late at night and so have a stream-of-consciousness style):
- Take control of the pump as well as the boiler to allow for feedforward control while a shot was being pulled, and to add an interlock to shut the pump off when the water tank was empty. There is actually an additional relay needed on the Silvia for the solenoid that is involved in the hot water function so this project would have 3 relays to control instead of the single one on the Saeco project.
- Use an OLED display instead of a back-lit LCD. OLEDs have way better contrast than LCDs, and since Miss Silvia is a higher end machine I thought she deserved a sexier display.
- Make it safer. The Saeco physical arrangement was a bit of a hack job with the mains voltages on the single board mounted out in the open on top of the water tank. Nobody electrocuted themselves in its 3 years of operation, but I was always a little nervous about that setup.
- Do a better job integrating it. This is related to the previous one, on the Saeco the display was on a piece of plexiglass that extended up from the machine, I wanted this one to be built into the face plate.
- Add a float switch to detect when the water level was low. This would allow for the boiler/pump interlock mentioned in the first bullet to be integrated, and is also more needed on the Silvia because while the Saeco has a clear water tank that is visible from the side through a cutout in the housing, the water tank on the Silvia is completely concealed.
- Add a separate voltage regulator to generate a clean supply for the A/D reference and make better use of the full range of the temperature sensor. I wanted to get better temperature then I had on the Saeco where I was just using the 5V rail for the analog reference on the MCU.
- Have the display co-located with the MCU board. On the Saeco they there connected by a long-ish ribbon cable, and with all the E-M noise being thrown around by pumps, relays, and switches, the cable would pick up enough where it would occasionally put the LCD display into a weird state so that it showed a bunch of gibberish and needed to be reset. In this one I wanted to mount the MCU board directly on the back of the display.
I started with the schematics from the Aroma project and made updates as needed. The most significant was that in order to achieve the goals above I divided the design into two separate boards: the MCU board with all of the low voltage electronics was located directly behind the display, inside the main upper compartment of the Silvia. The second board was located down below the water tank, beside the pump, and would have the AC/DC converter and the three solid-state relays. There were two reasons for this: first, these components were the most bulky so it would have been a bit of a squeeze to fit them all in the upper compartment (though it could have been done), and second, heat dissipation is an issue for the SSRs so putting them next to a 140 degree celsius boiler didn't seem like a great idea.
I did the schematics in Eagle which may not have the smoothest work flow but the price is right (free for small non-commercial projects) and it gets the job done. Here is the schematic for the main board. As with the Saeco project it was based around an Atmel ATMEGA328 MCU that was programmed with the Arduino framework.
And here is the schematic for the power/relay board, not much here compared to the other one:
I then moved on to the layouts which is a nice diversion if you like playing with shapes and colors. Here is the main board layout, which is the same size as the outline of the OLED display that I used with the row of 16 pins along the top plugging directly into that:
And here is the layout for the power/relay board. The 4 large blocks are the high voltage connectors, I used pluggable ones that there really nice and easy to connect (with an eminently satisfying "click") but given that only happens once during assembly I think they are not worth the board real estate and I would use quick connect tabs from Faston or equivalent next time (similar to the stock electrical connections in the Silvia). Another change I would make for next time is that I would only use a solid-state relay for the boiler where you need it to implement the PWM heat control scheme, I would use mechanical relays for the pump and solenoid since they are way cheaper.
Once the layout was complete I kicked the boards out for fabrication at OSH Park (what a great service, thank you to the people who run it!), ordered the parts from Digikey, and two weeks later I had shiny purple PCBs ready to be populated. By that point I was again gainfully employed which significantly hampered my rate of progress but I was determined to finish what I had started.
There was the odd hiccup in getting things up and running but things more or less worked, so before too long I had done enough testing to start building them into Miss Silvia. Here is a shot of the power board installed beside the pump. The rainbow ribbon cable connects to the main board in the upper compartment and carries the relay drive signals and low voltage power/ground.
And here is a shot of main board installed on the back of the display in the main compartment. I guess I totally skipped over this, but cutting out the slot in the sheet metal enclosure to mount the display was a bit of an adventure. Another thing I did was replace the original incandescent indicators in the panel switches with LEDs. I did this mostly because I no longer was running mains voltage to these switches, but it had the nice side benefit that the LEDs are way brighter than the original incandescents so it looks a lot better. This was actually a lot easier than I thought it would be, 3mm through-hole LEDs nestled right into the slot formerly occupied by the incandescent bulb.
And here is a shot of the complete unshrouded machine from the back:
And here is a workbench shot of Miss Silvia from the front with her clothes back on, right after I breathed life back into her. I hadn't yet replaced the LED in the power switch at this stage so it isn't illuminated yet. That one took a little more work since I wasn't naturally running the low voltage required by the LED so that switch, and it was still switching the line voltage.
Next up was to bring Miss Silvia up out of the depths of our basement where my work bench has been relegated and into the kitchen to start pulling some shots and tuning the PID constants. I guess I skipped over the part where I wrote the firmware, but it was based to a large extent on what I had done previously for the Saeco project so it wasn't too bad. The firmware is implemented in a pretty simple state machine that moves between states depending on the condition of the switches and the boiler temperature.
One of the nicer things I was able to do with now having control of the pump and having a float switch to detect when the water reservoir is low is add an interlock condition that shuts down the pump and boiler when this happens. If a low water condition is detected during the hot water function (pumping hot water out of the steam wand) then it shuts both down automatically. If a lot water condition is detected while a shot is being pulled then it waits a until either the shot is complete (by the user stopping it via the panel switch) or for a maximum of 30 seconds after the condition was detected. This is so that you don't ruin your shot if the float switch activates partway through. Another nice thing was that since I took over control of the panel light next to the power switch (by replacing the original lights with LEDs) I was able to make it part of the UI, so that it pulses while the boiler is heating, goes solid once the final temperature is reached, and then shuts off while cooling from steam to brew or if the low water state is entered. One other improvement of this over my Silvia project was that because I had control of the pump I was able to add a shot timer to the display.
Anyway, back to the PID tuning: I did this by using the serial port on the MCU to push the current tenperature, all of the PID variables (P, I, and D), and the heater drive out to a logging program on a laptop (actually a Microsoft Surface 3, which is what I used for all of the development work on this project). I used the Cool Term application on the Surface to log the data to a text file, and would then import to Excel, plot the results, and adjust the constants for the next run. One thing I learned part way through is that the boiler can have a variable water level depending on what operation was last carried out (steam vs. brew) which changes the thermal mass of the system which in turn changes the system dynamics and how it will respond for a given set of P, I, and D gain constants. So, I now run the pump briefly until water comes out of the group head at the start of each heating cycle to make sure the boiler water level is at a known state.
Here is an example of one of the tuning plots:
Things worth noting:
- The boiler temperature is not plotted here, but the P-term (blue) gives the same information since it is the error (target - actual) multiplied by the P constant, so as the blue line drops to zero that is the temperature reaching the target.
- The red line is the I-term, I adjusted the code for this so that the I-term does not start accumulated until the temperature is around 15 degrees out from the target. Otherwise it winds way up during the initial heating and would then blow way past the target. The range within which the I-term starts accumulating was one of the variables that I optimized for (in addition to the P, I, and D gain constants).
- The grey line is the D-term, this one is spiky because the terms are updated every second but the temperature does not change every second (at least once the rate of change slows down as it approaches the target).
- The yellow line is the heater drive which is the sum of the previous three terms, it is capped at 1000 since the PWM-drive for the boiler has a scale of 0-1000 (corresponding with how many milliseconds of the 1 second window that the boiler will be active for).
Okay, now for the punchline: does it work? Of course it does! The real question is how much better is it than the stock thermostat, so I did a run with the stock boiler thermostat hooked back up for comparison purposes (I left it intact in the rebuild) and the comparative results are shown below.
You can see that the temperature swings with the thermostat are pretty dramatic, dropping from a high of 96.8 degrees C to a low of 80.1 degrees C and repeating the cycle over and over (although you can see the period lengthens as the rest of the machine heats up which slows down the rate of cooling for the boiler). This means that the temperature of a given shot is a random variable with a uniform distribution from 80.1 C to 96.8 C, not ideal. It is pretty easy to see that the temperature stability is better with the PID control.
Once the shot is pulled there isn't much difference since while I did add some feedforward control to drive the boiler at 100% when the pump is active (to counteract the effect of cold water rushing into the boiler), the time delays in the system are such that there isn't much benefit seen from that during the relatively short 20-30 second window during which the shot is being pulled. So, if you happen to start the shot with the stock Silvia during one of the peaks where the temperature coincides with the PID set point then it would be no different, the PID will just provide more consistent shots.
Another benefit is in the steaming performance (though I never actually tried steaming with the stock Silvia, I am just interpolating from what I saw on the Saeco Aroma project), since at the low extreme of the temperature swing for the steam thermostat the steam power gets pretty weak, while with the PID control it responds more quickly and never lets the boiler temperature drop that low.
Well, that is about all I can think off, I guess I'll end with a few photos of Miss Silvia doing her thing on my kitchen counter. Here she is getting warmed up:
And here is a zoomed out shot with other coffee paraphernalia. The cable exiting on the left side of Miss Silvia is the UART lines connected to the laptop through an FTDI cable.
And finally, here is the obligatory pulling a shot image. Sadly, I pulled this one at 11pm while finishing off this write-up so I wasn't able to enjoy it. Thanks for reading!
Great job. I always enjoy reading about Silvia PID'ing projects with a happy end.
ReplyDeleteI like the idea with the two separate boards - the boiler does get rather hot after all. The float-switch should help avoiding boiler "burns"; I wonder if an ultrasonic water level sensor would've worked better (no physical contact)?
Still impressive with two young daughters. My two young boys are the reason why I started twice (Arduino + Bluetooth + Android App) and (Raspberry Pi + Touchscreen) but never got anywhere.
Friendly,
Patrick
Thanks! I did consider some alternate level sensing methods, but in the end the float switch seemed like the cheapest and easiest to implement. The only drawback is that you can't pull the tank out to fill it, but I usually find myself filling it from a container anyway so it isn't too bad.
DeleteHa ha, yes the kids definitely put a damper on project activity! My hours to work on this are from 9:30pm - 11:30pm most evenings :-). I like the idea of connecting an app to it over Bluetooth, it would be nice to have a richer interface for plotting the temperature profiles that it can gather.
I love this! I might try a modified version for my Starbucks Barista. Would you be willing to share the source code, and Eagle files? And is this board public on OSH Park?
ReplyDeleteThanks David! I actually modified a barista on a subsequent project, I just haven't had a chance to do a write-up about it yet. I am happy to share the source code, though maybe I'll actually share what I have from the barista project since I made it a little more robust. I put that up on github here, let me know if you can't access it (I haven't used github much and might not have done it right): https://github.com/ctcharle/barista-pid.git
DeleteI think the boards should be public on OSH park, they weren't before but I just tried to share them. Let me know if it doesn't work, I can send you the files directly also. Let me know if you do decide to use or adapt them, there were some things I would have changed in retrospect that I can let you know about.