Friday, July 6, 2012

Repurposed Garage Door Opener

A while back, one of our craftsman 1/2 HP chain drive garage door openers stopped functioning properly. The doors stopped moving, even though the motor still ran. A quick inspection revealed that the sprocket on top of the unit sheared off the shaft. Not knowing any better (and being under a time crunch to get the door working), a new opener was bought and installed. However, it seemed like a waste to throw away the old unit, since everything else still functioned properly (the motor, electronics, etc.), and so I put it aside for future scavenging.

Recently, I came into some free time, and decided to automate the closing of my bedroom door. Plenty of times, when I'm all comfortable in my bed watching television, it gets noisy outside of the room; getting up to close the door, at the time, always seems like such an undertaking (and then you have to get comfortable all over again). I brainstormed through some concepts for a while, and decided to try to revive the old opener and re-purpose it for the task.

A quick search on Google revealed a replacement gear shaft assembly that included the broken sprocket for around $23 on Amazon ( I wish I had known earlier instead of paying for a new opener). When the parts arrived, the new gear shaft assembly was installed in a snap, and the unit was back to fully functioning condition in no time. After dis-assembly, I decided to look at the failed part to see what went wrong, and lo and behold, our old friend "planned obsolescence" showed its head. It seemed that the engineers at Sears purposely ground down a segment of the shaft in order to lower its endurance limit. For those not familiar, in materials science and mechanical engineering, a concept known as the "endurance limit" for a material determines the maximum cyclic stress that a material can experience and have infinite life. If that stress is exceeded, the material then has a finite life cycle (amount of stress cycles before fatigue failure). Since the tension of the chain is always pointing in the same direction, and the sprocket rotates, then the shaft experiences cycling loading.

The modification can best be seen in the picture below. Note that the ground down portion is completely hidden under a metal cap, and cannot be seen by the user (even if the unit is disassembled). Very sneaky.


Because of the metal cap that can only be removed once the shaft snaps, It is not clear if the new shaft also has this feature (I would guess yes, since it is a craftsman replacement part). Just for my own curiosity, I am going to run some calculations in the future and see if the stresses are indeed above the endurance limit.

In order to convert the linear motion of the garage door opener into something that will swing a door shut, several options were considered. What  made it more challenging was the fact that the door followed a path that traced an obtuse angle (see figure below).

 
I could not simply use the rotation of the sprocket itself, since it rotated way too fast. One option was to slow down that rotation using some bicycle gears, but it seemed too cumbersome and would need a lot of parts and work. another option was to use a rack and pinion system (rack on the trolley, pinion on a separate shaft that swings and closes the door). That option also required a lot work and could potentially take up too much space. The final design used simple linkages to push on the door, shown better in the illustration below:



The lengths of the linkages had to be chosen precisely in order to complete the required motion, while also avoiding the condition of "singularity," a point where the two linkages line up and theoretically requiring an infinite amount of force to move (in reality, it will yield the material and buckle the beams).

Surprisingly, I was able to build the whole mechanism using only parts found in a standard garage door opener kit and $5 worth of hardware from the hardware store. Since I re-used all of the old parts with the new motor that I purchased, all of the new parts that came with it (brackets, track, chain, etc.) were just laying around. This saved me a lot of money, work, and frustration, and made it that much more awesome when completed.

After the motor was back in working order, the track was shortened to only half of the original length, and consequently, so was the chain. The whole unit was reassembled and the travel was adjusted for the shortened track length using the built in adjustment screws. The trolley assembly was flipped 180 degrees to make the assembly more compact, and a bracket was installed at the end of the trolley to serve as a pivot for the upper linkage.

The kit came with two pieces of angle iron that had holes every 2 inches or so, to be used to hang the motor from the ceiling. I instead used those pieces to prototype the linkages (the holes also allowed for on the fly adjustment of the intersection point of the linkages). After the linkages were set and the travel fine tuned, the prototype was attached to the wall using the regular mounting brackets from the kit. The safety sensors were taped facing each other, or else the motor will not function (SEE NOTE BELOW), and the activation switch was wired up. Finally, a cover was made for the motor to make it look nicer.

NOTE: I AM NOT RESPONSIBLE FOR ANY HARM CAUSED BY NEGATING THE SAFETY MECHANISMS. THIS IS PURELY FOR INFORMATIVE PURPOSES ONLY. the amount of force produced by this machine is tremendous (mechanical advantage is no joke) and should be treated with respect. Do not attempt to replicate this unless you know what you are doing.

The finalized prototype is shown in the images and video below:










 
 
 Action video for both conditions: fully opened, and partially opened:




Overall, the project seemed to fulfill the goals I had set out. It was relatively cheap, was pretty compact and out of the way (the motor fit nicely underneath my desk), and only took about two days of work. In the future, the linkages will be replaced with stronger steel flat bar, since these bars are intended for tensile applications and not compressive forces. And also as a bonus, all of the parts can be found in a garage door opener kit and at your local hardware store.

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)