Sunday, June 5, 2011

Automatic Espresso Loader


Problem
For the personal semester project, I chose to create a machine that will load and compact the coffee grounds holder in an espresso machine. To load the machine manually, first you remove the holder (which we will call the “pot”). The pot is shown in the figure below:



 Figure 1 - Espresso coffee grounds holder, the “pot”

Afterwards, the coffee grounds are scooped in until the pot is filled to the appropriate height (either 2 or 4 shots of espresso). The grounds are then compacted using a flat surface. The loaded pot is then secured in the espresso machine in order to begin the process.

The aim of the machine is to automate the process, while adding the flexibility of selection from three different coffee flavors. 

Requirements
The machine will need three hoppers to hold the three different flavors of coffee grounds. Each of these hoppers will be controlled by some type of valve. The machine will also include some type of mechanism to compact the grounds afterwards. To take the selection, some type of user interface will also be provided, and a microcontroller to run the show.


The Design
The machine I created revolves around the Parallax Propeller MSR1 board. The board includes handy features to interface with accessories (i.e. Servos, LCD, etc) that use the standard 3-pin connection (power, ground, signal). It also includes an on-board H-bridge to control external DC motors. And of course, it comes with voltage regulation.
The final machine is shown in the figures below:



  Figure 2 - Completed Machine



 Figure 3 - Completed Machine





 To use the machine, the pot is first secured in the pot holder. The clip is used to secure the pot in the circle on the base (made of hot glue). After the pot is secured, the machine can be turned on using the red power button underneath the keypad. The screen will then prompt the user for the flavor (1-3) and the number of espresso shots (2 or 4). The user then presses OK, which starts the dispensing sequence.
The machine first moves the chute into position on top of the pot, and then the appropriate valve is opened depending on the flavor selected. The valve is held open for a pre-determined amount of time, depending on whether the user selected 2 or 4 shots. After the pot is full, the chute is moved out of the way of the compacter. The compacter then comes down onto the pot, compacting the coffee grounds. The sequence is then complete, and the user takes out the pot to be used in the espresso machine. Refer to the detailed subsystems below for more information.

Hoppers

 The hoppers, made from plastic liquid bottles, hold the three flavors of coffee. The flavors are actuated by the three servo motors on the bottom, which rotate a valve to control the flow of coffee grounds.


 Figure 4 – Hoppers and valves

Compacter

The compactor is a repurposed ink cartridge carrier from a dead inkjet printer. It has a circular head on the bottom to compact the grounds. The compactor is driven by a DC motor on the bottom, providing power through a belt system. There is a limit switch on the top to tell the microcontroller when the compacter has reached the upper limit.



Figure 5 – Compacter


User Interface / Microcontroller

The user interface consists of a custom build keypad with the flavors, # of shots, OK and Cancel buttons. The microcontroller communicates with the user using the 2-line LCD screen above the keypad. Power to the system is actuated by the red push button below the keypad. Finally, the show is run by the Parallax Propeller board shown below. The board, servos, and Dc motor are all powered by the 11.1v 3200 mAh Li-Po battery.



Figure 7 – backside of UI panel

Software / Control


As the mentioned above, the system is controlled by the Parallax Propeller MSR1 board, running a custom SPIN program. 



Figure 8 – Propeller Board






The software’s algorithm can be broken down in a linear fashion. There was no need to have simultaneous routines running, and so only one cog was utilizes for simplicity’s sake. The program first defines constants, which mostly include the pins for the servos, pushbuttons, and DC motor. LCD information and clock frequency are also set.


Next, three objects are called: Servo32v5, the serial terminal, and the debug_lcd. The servo object is used for easy servo control (no need to fuss with timing pulses). The lcd object is used to initialize and write to the LCD screen. Finally, the serial terminal is used for diagnostic purposes, and has no role in the final product. 

Next, the two variables that the user chooses are defined: the flavor and the shot size. 

Finally, the main program can begin. The servos are first set to the closed position, then the LCD displays a welcome message. 

Afterwards, the flavor subroutine is called, which then prompts the user for the flavor. After the appropriate key press is detected, the shot subroutine is called, which prompts the user for the shot size. After the appropriate key press is detected, the program waits for the OK button to be pressed. After the OK is detected, the dispense subroutine is called. The dispense subroutine then sets the chute to the dispensing position, opens the appropriate valve for the appropriate time, then closes the valve. Afterwards, the compact subroutine is called, which moves the chute out of the way of the compacter, and calls the compacter twice. Afterwards, a “done” message is displayed, and the routine is finished. Refer to the appendix for the SPIN code.


Problems/ Praises
The main problem encountered while building this machine is intermittent interference with the servos. The most likely suspect is noise from the wires used to extend the servo wires; however, every attempt to mitigate this noise didn’t work. Otherwise, the machine works flawlessly and is awesome. Several people commented on how cool it was, and that they would totally buy one.



SPIN Code

CON
Flavor1 = 0
Flavor2 = 1
Flavor3 = 2
Shot2 = 3
Shot4 = 4
Start = 5
Cancel = 6

Servo1 = 8
Servo2 = 21
Servo3 = 18
Servo4 = 11

MotorPos = 24
MotorNeg = 25

Limiter = 16

LCD_Pin = 15
LCD_Baud = 19_200
LCD_Lines = 2

_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000

OBJ
  servo : "Servo32v5.spin"
  pst : "Parallax Serial Terminal"
  lcd : "debug_lcd"
 
VAR
  byte  Flavor
  byte  Shot      
 
PUB main
servo.start
servo.set(Servo1, 1350)
servo.set(Servo2, 570)
servo.set(Servo3, 980)
servo.set(Servo4, 1000)

LCD.init(LCD_Pin, LCD_Baud, LCD_Lines)               
LCD.cursor(0)                                  
LCD.cls
LCD.gotoxy(0,0)
LCD.cls                                                 
LCD.str(string("Espresso Magic",13, "By Roy Eid",13))
waitcnt(clkfreq*2 + cnt)

dira[MotorPos]~~
dira[MotorNeg]~~



Flavor := 0
Shot := 0

flava

PUB shat
repeat  
  if ina[Shot2]==1   
    LCD.gotoxy(9, 1)
    LCD.str(string("2"))   
    Shot := 1
    commander
                      
  if ina[Shot4]==1
    LCD.gotoxy(9, 1)
    LCD.str(string("4"))       
    Shot := 2
    commander
   
  if ina[Cancel]==1
    LCD.cls
    LCD.str(string("Cancelled by",13, "User"))   
    waitcnt(clkfreq + cnt)
    flava

PUB flava
LCD.cls
LCD.str(string("Flavor :",13,"Shots  :"))
repeat  
  if ina[Flavor1]==1   
    LCD.gotoxy(9, 0)
    LCD.str(string("1"))   
    Flavor := 1
    shat
                      
  if ina[Flavor2]==1
    LCD.gotoxy(9, 0)
    LCD.str(string("2"))        
    Flavor :=2
    shat
   
  if ina[Flavor3]==1
    LCD.gotoxy(9, 0)
    LCD.str(string("3"))      
    Flavor :=3
    shat
   
PUB  commander
repeat
  if ina[Start]==1 
      LCD.cls
      LCD.str(string("Dispensing..."))
      dispense

  if ina[Cancel]==1
    LCD.cls
    LCD.str(string("Cancelled by",13,"User"))   
    waitcnt(clkfreq + cnt)
    flava
   
PUB dispense

servo.set(Servo4, 1600)
waitcnt(clkfreq*1 + cnt)

  case  Flavor
    1:
      servo.set(Servo1, 1800)
      if Shot ==1
        waitcnt(clkfreq*2 + cnt)
        servo.set(Servo1, 1350)
        waitcnt(clkfreq*1 + cnt)
        compact                
               
      if Shot ==2
        waitcnt(clkfreq*4 + cnt)
        servo.set(Servo1, 1350)
        waitcnt(clkfreq*1 + cnt)
        compact
    2:
      servo.set(Servo2, 1000)
      if Shot ==1
        waitcnt(clkfreq*2 + cnt)
        servo.set(Servo2, 570)
        waitcnt(clkfreq*1 + cnt)
        compact
        
      if Shot ==2
        waitcnt(clkfreq*4 + cnt)
        servo.set(Servo2, 570)
        waitcnt(clkfreq*1 + cnt)
        compact
    3:
      servo.set(Servo3, 550)
      if Shot ==1
        waitcnt(clkfreq*2 + cnt)
        servo.set(Servo3, 980)
        waitcnt(clkfreq*1 + cnt)
        compact
        
      if Shot ==2
        waitcnt(clkfreq*4 + cnt)
        servo.set(Servo3, 980)
        waitcnt(clkfreq*1 + cnt)
        compact


PUB compact
servo.set(Servo4, 1000)
waitcnt(clkfreq*2 + cnt)
repeat 2
  if ina[Limiter]==0
    up                 
  if ina[Limiter]==1
    down
    up

LCD.cls
LCD.str(string("done!"))
waitcnt(clkfreq*2 + cnt)
flava

PUB up

repeat
  LCD.gotoxy(0,0)
  LCD.str(string("Compacting..."))
  outa[MotorNeg] :=1
  outa[MotorPos] :=0
  if ina[Limiter]==1
    outa[MotorNeg] :=0
    outa[MotorPos] :=0
    quit

PUB down
       
LCD.cls
LCD.str(string("Compacting..."))        
repeat 100
  outa[MotorPos] :=1
  outa[MotorNeg] :=0
  waitcnt(clkfreq/500 + cnt)
  outa[MotorNeg] :=0
  outa[MotorPos] :=0
  waitcnt(clkfreq/500 + cnt)   
    

2 comments:

  1. Hey Roy,

    I just noticed your crazy awesome automatic espresso loader. I work at Instructables.com and wanted to give you a shout out and let you know about the Make It Move Contest we launched this week. We're giving away a a Pirate Bus Prototype Board and iTunes gift certificates and I think this would be a great entry for the contest.

    I would be happy to feature it on our site if you decide to post the instructions there and help get it noticed among our 10 million visitors. Let me know if you have any questions!

    Hope to hear from you soon!
    Cheers,

    Mike
    mike [at] instructables. com
    http://www.instructables.com/contest/makeitmove

    ReplyDelete
  2. Sounds good Mike; I will make one soon

    ReplyDelete