Commercial Espresso Machine Automation

by rightbass in Circuits > Arduino

113 Views, 3 Favorites, 0 Comments

Commercial Espresso Machine Automation

IMG-20201012-WA0003.jpg

This project is a result of my personal needs of a automated espresso machine, my 2 months of research, and customer feedbacks.

I used to repair and maintain espresso machines. I had a workshop espresso machine with 2 group heads. My workflow was like this: Bring my machine to shop, install it, bring the shop's machine to may workshop. Repair and exchange the machines back again. I know it is lots of work but this is how i made my customers happy. Often times they frowned upon my machine as it was fully manual start stop kind of machine. So i decided to upgrade mine. First i didn't intend to share this project but since i closed my business, i no longer have any commercial interests. So this is Public license from now on.


This project is primarily intended for people who would like to make a sensory input driven automation project :) For those who would like to make an automated coffee machine as well, i hope this will be a valuable guide.

My job is a bit sloppy. I learn things on the way. Since i no longer have the machine i couldn't take a photo intended for a good intructable. The main board has gone through many iterations, lots of jumper wires, trial and error, electrical tapes. That's the reason it is ugly as hell :) The schematics and pcb layout on the other hand, are good. They're up to date, so no worries.

Also sorry for bad English.

Supplies

This project Uses:

Electronics side:

  • Arduino Nano -- 1 pcs
  • Custom made PCBs -- 2 pcs
  • Lots of RGB buttons -- 11 pcs
  • ULN2003A -- 2pcs
  • 4 Channel relay board -- 1 pcs
  • 12v power circuit -- 1pcs
  • DC-DC voltage converter (for 5v) --1 pcs
  • Ribbon cables
  • Snubber circuits ( simple LC couple) -- 2pcs (it will be explained later)

Mechanical side:

  • Flowmeters (espresso machine grade) -- 2pcs -- i used Gicar brand. they were 25 € each.
  • Copper tubing 1/4" -- ~1 meter
  • Copper fittings: Tee's, elbows, nipples -- depends on your machine and design.


*note: May need solder equipments to attach your copper contraption to your existing tubing.

I got the circuit boards from here. It's a Turkish supplier, but you'll get the idea. Custom boards manufacturer is PCBway

https://www.direnc.net/5v-4-kanal-role-karti

https://www.direnc.net/5v-700ma-ac-dc-step-down-modul

https://www.direnc.net/drn401-12mm-metal-beyaz-ledli-yayli-buton

https://www.direnc.net/klon-arduino-nano-328-ft232rl

https://www.direnc.net/12v-1a-adaptor-priz-tipi // i gutted out the internals and made it fit inside machine.

Electronics Side: Meeting the Boards

dgtrbd.PNG
mainbrd.PNG
resim_2023-11-29_235953068.png

Fore Word: First of all will be started with boards. Above schematics show all the circuitry. I have limited understanding about Proteus. Therefore for testing purposes i draw all the circuitry on one file. Please ignore voltmeters as they're there for debugging purposes. PCB layouts are drawn seperate files. Above, you can see images of them. I couldn't be able to upload proteus project files.

Complements: We have 2 different boards. Main controlling board, which does all controlling. And a daughter board, which controls buttons. With this design we won't be messing around with cables. (much :) )

PLEASE NOTE: This project doesn't control tank water level. This circuit especially work with existing control unit of the machine. This project is designed with the intention of being auxillary control, it can be powered down and the machine can be operated with its own buttons.

About buttons: Because of my lack of better judgement, this project uses individual buttons that mounted on the frame of the machine. Buttons are rgb backlit that uses 12V supply. Hence this project needs both 12v and 5v power supplies. About ULN2003A's, they are solely for driving button's backlights. With 5v lights, you can ignore them and redesign. But for the sake of reliability, i recommend using them.

About relay board: My machine controls 3 things with 2 buttons cleverly and simply. These are water pump electrical wiring, and group heads' solenoid valves. So i wired my 4 channel relay board's 3 relays to the buttons.

On final note, i'm not professional. I couldn't write the code elegantly, and couldn't install on the machine elegantly. I lacked professional tools to do so.


Understanding Code

This code is long and winding. Shortly explained, flow meters imputs are connected to interrupt pins of the nano. For each group heads, there are 5 buttons. These are SingleShot, DoubleShot, LongShot, LongShot2, Manual/Stop. And there is a calibration button which with the combination of shot buttons it will start calibration mod. The water will start pouring and when the stop button is pressed, current value will be recorded.

Recorded calibration values will be written to EEPROM and will be called upon power-on.

This is it. That's all the code does. The buttons have its own bouncing problem workaround. I'll explain later.

Here we go:

#include <EEPROM.h>

//---pin assignments----------
const int P1 = 13;
const int P2 = 12;
const int P3 = 11;
const int P4 = 10;
const int P5 = 9;
const int K = 8;
const int P6 = 6;
const int P7 = 5;
const int P8 = 4;
const int P9 = 0;
const int P10 = 1;
const int flowmeter1 = 2;
const int flowmeter2 = 3;
//---calibrated values-------------
volatile unsigned long flpulse;
volatile long flpulse2;
volatile long ltek1;
volatile long lduble1;
volatile long ltek2;
volatile long lduble2;
volatile long rtek1;
volatile long rduble1;
volatile long rtek2;
volatile long rduble2;
//---- these are here for millis function
unsigned long basma;
  unsigned long bekle = 150;
  unsigned long suan;
//-----------button debouncing i know not elegant but it works.
bool lt1 = false;
 bool ld1 = false;
 bool lt2 = false;
 bool ld2 = false;
 bool lt1s = false;
 bool ld1s = false;
 bool lt2s = false;
 bool ld2s = false;
 bool mol = false;
 bool rt1 = false;
 bool rd1 = false;
 bool rt2 = false;
 bool rd2 = false;
 bool rt1s = false;
 bool rd1s = false;
 bool rt2s = false;
 bool rd2s = false;
 bool mor = false;
 bool klt1 = false;
 bool klt1s = false;
 bool kld1 = false;
 bool kld1s = false;
 bool klt2 = false;
 bool klt2s = false;
 bool kld2 = false;
 bool kld2s = false;
 bool krt1 = false;
 bool krt1s = false;
 bool krd1 = false;
 bool krd1s = false;
 bool krt2 = false;
 bool krt2s = false;
 bool krd2 = false;
 bool krd2s = false;

//---- interrupt functions----
void flow() {
  flpulse++;
  interrupts();
}
void flow2() {
  flpulse2++;
  interrupts();
}
//----eeprom functions----
void eepromayaz(int address, int number)
{
  EEPROM.write(address, number >> 8);
  EEPROM.write(address + 1, number & 0xFF);
}
int eepromdanoku(int address)
{
  return (EEPROM.read(address) << 8) + EEPROM.read(address + 1);
}


Still with me? Let's continue :)

void setup() {
  // this is the setup. Its pretty self explatory. Buttons are initialized. Relay are in open mode. Eeprom data is
// read and values are loaded.
  pinMode(A2, OUTPUT);
  digitalWrite(A2, HIGH);
  pinMode(A3, OUTPUT);
  digitalWrite(A3, HIGH);
  pinMode(A4, OUTPUT);
  digitalWrite(A4, HIGH);
  pinMode(A5, OUTPUT);
  digitalWrite(A5, HIGH);
  pinMode(A0, OUTPUT);
  pinMode(A1, OUTPUT);
  pinMode(flowmeter1, INPUT);
  pinMode(flowmeter2, INPUT);
  digitalWrite(A1, LOW);
  digitalWrite(A0, LOW);  
  pinMode(P1, OUTPUT);
  pinMode(P2, OUTPUT);
  pinMode(P3, OUTPUT);
  pinMode(P4, OUTPUT);
  pinMode(P5, OUTPUT);
  pinMode(P6, OUTPUT);
  pinMode(P7, OUTPUT);
  pinMode(P8, OUTPUT);
  pinMode(P9, OUTPUT);
  pinMode(P10, OUTPUT);
  pinMode(K, OUTPUT);
  digitalWrite(P1, HIGH);
  digitalWrite(P2, HIGH);
  digitalWrite(P3, HIGH);
  digitalWrite(P4, HIGH);
  digitalWrite(P5, HIGH);
  digitalWrite(P6, HIGH);
  digitalWrite(P7, HIGH);
  digitalWrite(P8, HIGH);
  digitalWrite(P9, HIGH);
  digitalWrite(P10, HIGH);
  digitalWrite(K, HIGH);
 
  ltek1 = eepromdanoku(10);
  lduble1 = eepromdanoku(20);
  ltek2 = eepromdanoku(30);
  lduble2 = eepromdanoku(40);
  rtek1 = eepromdanoku(50);
  rduble1 = eepromdanoku(60);
  rtek2 = eepromdanoku(70);
  rduble2 = eepromdanoku(80);
 
  interrupts();
  detachInterrupt(0);
  detachInterrupt(1);
  delay(200);
}

This is the loop:

void loop() {
  // p's are button press, machine making desired amount of coffee.
// k's are calibration functions.
// millis is there for button debouncing purposes.
  suan = millis() ;
karsila();
p1();
p6();
p2();
p7();
p3();
p8();
p4();
p9();
p5();
p10();
k1();
k2();
k3();
k4();
k6();
k7();
k8();
k9();

}

Program buttons' code:

// there is no need for other ps' :D
void p1() {
if (digitalRead(P1) == LOW && digitalRead(P2) == HIGH && digitalRead(P3) == HIGH && digitalRead(P4) == HIGH && digitalRead(K) == HIGH && digitalRead(P5) == HIGH && digitalRead(A5) == HIGH && digitalRead(A4) == HIGH )  //p1 dozajlı ver
  {
   basma = suan;
   lt1 = true; // for p functions debounce
   lt1s = true; // for k functions debounce
   }
// button press makes the lt1 true. lt1 being true makes the machine work. Debouncing works like this.
   if (lt1){
   
    if ((unsigned long)(suan - basma) >= bekle) {
    flpulse = 0;
  attachInterrupt(0, flow, CHANGE);
          digitalWrite(P1, LOW);
          digitalWrite(P2, LOW);
          digitalWrite(P3, LOW);
          digitalWrite(P4, LOW);
               
  digitalWrite(A5, LOW);
  digitalWrite(A4, LOW);
    lt1 = false;
   }}
   }

Manual buttons' code:

void p5() { 
  if (digitalRead(P5) == LOW )  //full küskü
  {
    basma = suan;
    mol = true;
   }
   if (mol){
   
    if ((unsigned long)(suan - basma) >= bekle) {
      switch(digitalRead(A5) && digitalRead(A4)){
        case HIGH:
          digitalWrite(P1, LOW); // if machine is already working, makes it stop
          digitalWrite(P2, LOW);
          digitalWrite(P3, LOW);
          digitalWrite(P4, LOW);
          digitalWrite(A5, LOW);
          digitalWrite(A4, LOW);
          mol = false;
          break;
        case LOW:
          digitalWrite(A5, HIGH);     // if machine is working, makes it go burr burr :)
          digitalWrite(A4, HIGH);
          digitalWrite(P1, HIGH);
          digitalWrite(P2, HIGH);
          digitalWrite(P3, HIGH);
          digitalWrite(P4, HIGH);
          mol = false;
          break;}
      }
    }}

Kalibration functions:

void k1() {
if (digitalRead(K) == LOW && digitalRead(P1) == LOW && digitalRead(A5) == HIGH && digitalRead(A4) == HIGH && digitalRead(P2) == HIGH && digitalRead(P3) == HIGH && digitalRead(P4) == HIGH && digitalRead(P5) == HIGH && digitalRead(P6) == HIGH && digitalRead(P7) == HIGH && digitalRead(P8) == HIGH && digitalRead(P9) == HIGH && digitalRead(P10) == HIGH) //p1 kalibre et
  {
    basma = suan;
    klt1 = true;
   }
   if (klt1){
    if ((unsigned long)(suan - basma) >= bekle) {
 
  flpulse = 0;
  attachInterrupt(0, flow, CHANGE);


  digitalWrite(P2, LOW);
  digitalWrite(P3, LOW);
  digitalWrite(P4, LOW);
   delayMicroseconds(300);
  digitalWrite(A5, LOW);
  digitalWrite(A4, LOW);
  do {suan = millis() ;
  if (digitalRead(P5) == LOW ) {
     basma = suan;
    klt1s = true;
  }
  if (klt1s){
    if ((unsigned long)(suan - basma) >= bekle) {
   
        digitalWrite(A5, HIGH);
         digitalWrite(A4, HIGH);
        delayMicroseconds(300);
       
    }
  }}
  while (digitalRead(A5) == LOW && digitalRead(A4) == LOW );
  digitalWrite(A5, HIGH);
  digitalWrite(A4, HIGH);
  digitalWrite(P2, HIGH);
  digitalWrite(P3, HIGH);
  digitalWrite(P4, HIGH);
//  digitalWrite(P4, HIGH);
//  digitalWrite(P2, HIGH);
//  digitalWrite(P3, HIGH);
  detachInterrupt(0);
  ltek1 = flpulse;
  rtek1 = flpulse;
  delayMicroseconds(200);
  eepromayaz(10, ltek1);
  eepromayaz(50, ltek1);
  klt1s = false;
  klt1 = false;
  delayMicroseconds(200);
}}}

Downloads

Mounting the Electronics

IMG-20210526-WA0002.jpg
IMG-20210509-WA0000.jpg
IMG-20210509-WA0001.jpg
IMG-20210509-WA0003.jpg
IMG-20210509-WA0005.jpg
IMG-20210613-WA0007.jpeg
IMG-20210613-WA0009.jpeg
IMG_20210612_224725.jpg
IMG_20210624_213505.jpg
IMG_20210603_141431.jpg
IMG_20210603_193501.jpg
IMG_20210603_193511.jpg

Power supply: 5v ac-dc and 12v ac-dc modules. They are entering the board from different places. Honestly i can't remember how did i make it work. There were lots of ierations and debugging went on. My machine electrical connections splits into two different sections. One is directly responsible for resistant heater inside the tank. Other one is controlling solenoids and water pump. I got my ac supply from this circuit. My machine uses rotary switch with two settings for powering on. First setting only activates existing mcu for tank level control purposes. So machine can't run without water. After a while if everything is okay, then you switch one more notch so machine can go brrrr :)

Relay board: I mounted the relays to the back of the machine cause there was empty space. Im using 3 relays to control the buttons. 2 for solenoids and 1 for the pump.

Buttons: I'm a bit embarrased that i used single buttons for this prototype. All it managed to do was making me nuts, and looking ugly. Buttons are mounted on the detachable front frame. 4 wires come off from each button and they're connected to daughter board. The daughterboard is also mounted to the same frame. 2 boards are connected with each other via ribbon cable. It is the only neat thing about it. :) For each group there are 5 buttons - 4 are programmable, 1 is start/stop - and one calibration button that controls both groups.

Controlling unit: Main board is located at the left bottom corner on the machine. It is wrapped with nylon bag, making it IP66 compliant :D. For temporarily. After a while i 3d printed nice black box. After that i made the connections according to the schematics.

Switch Snubbing

resim_2023-12-01_000654688.png
IMG_20210526_000442.jpg

Everything works, but when you use the machines old buttons, suddenly everything go hay wire? Yeah this is the reason. Since water pump is inductive load, when pump shuts off it creates transient currents. So this little contraption snubbs these transients.

I used 1M 5W resistor and 300nF 400v capacitor with this formation. As you will researched online, there many ways to cancel out transient currents. This one worked for me, but your mileage may vary.

Mechanical Side: Piping

IMG-20210426-WA0009.jpg
IMG-20210426-WA0011.jpg
IMG-20210505-WA0012.jpg
IMG-20210505-WA0013.jpg
IMG-20210509-WA0002.jpg
IMG-20210613-WA0011.jpg
IMG-20210426-WA0015.jpg

The water line works like this. Each machine is differently built. But main idea is like this. You have to work your technician part.:)

I used fittings with rings. It was easier. I don't enough skills for soldering copper. It looks ugly as hell, but it works and it doesn't leak.

Some notations are in Turkish, but i don't think that will be a problem for understanding diagram.

Testing

Ok, here is testing video. Sorry for backgrouınd music, i like to work with music on. Video is in Turkish, i didn't intend to post it online. Here is a quick overview:

I'm calibrating nr 4 programmable button by pressing calibration button and nr4 prog. button of the left group together.When water is pouring i pull my hand back. Since i didn't put any coffee in, i'm counting to four and pressed the stop button. Once the water stops, flowmeter value is saved. Then i pressed nr4 button, and counted to four to see if it stops. And it did. :)

When i calibrate the left group, the right group also gets the same calibration data. If i want, i can calibrate the right group seperately in case i want different amount of coffee.

This design is heavily influenced by Casadio line of espresso machines.

I can stop any program buttons in mid brew by pressing Stop/Manual button.

Downloads