Project Summary Starting Design CAD Design Purchased Materials Fabrication Electronics Software Assembly Testing Final Product Relevant Files

Drink Mixing Machine (EECS Machine Week 2019)

Project Summary and Inspiration

For Machine Week the EECS section thought it would be a lot of fun to make a drink mixing machine that would pump liquids from four sources into a cup and mix it. Last year's arch section had already attempted this. However, their implementation did not contain the usage of pumps (it utilized valves) that we thought using pumps, along with a completely new design, to implement this would make the project sufficiently different. Another place we pulled inspiration from was a similar arduino project we looked at here.

Starting Design

The starting design for this project was pulled from Jake Read's platonic gantry repo, using the RCTN23-0375HDPE Fusion CAD File. We knew that we wanted to get the machine chassis done first to get a better idea of how everything would fit together in the end. The general shape and function of the machine was clear: it would need 4 motor mounts for the pumps and a box-ier, more linear shape (since we had previously decided to focus on linear movement. Outside of that, we weren't exactly sure on the measurements of any of the pieces, since we were not completely sure on what components would need to ultimately end up on the machine. These uncertainties were things that the chassis CAD needed to account/leave room for.

brainstorming for the machine brainstorming for the machine brainstorming for the machine brainstorming for the machine brainstorming for the machine

After considering the drink mix machine more in depth we realized we needed to add the following design considerations:

Jake's design uses joinery between acrylic pieces that are mediated with small 3D printed inserts. This allows us to avoid stress concentrations that would normally cause acrylic to crack. Noticing this, we decided to use this kind of joinery throughout our machine chassis. This presented a couple pain points, though. We pulled the .step file of the gantry into Solidworks to understand how exactly the joinery worked. Essentially, there are these dog bone shaped holes with a hole in the center. On the other side, there are two nubs and a valley (of some sorts) in the center. The nubs nestle between the side of the dog bones that are closer to the center hole and the center hole itself. A screw fits through this center hole of the primer and into the valley of the latter. The 3D printed pieces fill in the gaps in between.

We decided on magnetically stirring the drink and a linear movement of the cup below the containers. Considering these design restrictions and the ones outlined above we proceeded to design the CAD for the relevant parts.

CAD Designs

It's a bit of a convoluted process trying to get the joinery into a Solidworks sketch. First, isolate each of the pieces you need sketches from. Then, select the contours of the joints that you want to trace using "convert entities" and save them as blocks. These blocks would later be used in all of the pieces of the chassis for joinery. In general, some design constraints/assumptions we followed/made throughout the CAD process include:

Cup and Motor Holder

In order to hold the cup, we had to add a design that would fit in with what Jake had, the CAD design for the cup holder and the motor below that would move it is below.The size of the cup will be about the size of a standard 12oz Solo cup with an upper diameter of 3.5''. The cup will need to rest on the gantry such that it's under the pump tubes.

Machine Frame/Chassis

The chassis was designed from scratch and the relevant files are listed below and can be found in the Relevant Files section

Gantry/Linear Movement

Here's a good image from Jake's documentation explaining the different components of the gantry:

In the folder with all of the parts, you'll see drinkmachine.SLDASM. This is a Solidworks assembly made of the chassis .SLDPRT files and a .STEP file of the gantry. You'll also see that the back panel and bottom of motor mount panel have holes cut out of them. We prioritized the chassis CAD, we weren't yet sure of what wiring would happen and decided to add holes proactively. The holes were proactively made in case wires needed to pass through the back panels (for the gantry) or the bottom of the motor mount panel (for the pumps). Additionally, you'll see that the side panel, there are three rectangular holes. The corresponding teeth were added onto the edges of the flat panel. These teeth fit into the side panels and would later be secured with super glue. The only other thing we changed about the gantry CAD was its length so that it would fit within the side panels of the chassis.

Machine Connectors

The connectors were also pulled from Jake's CAD design

connectors 3d layout

Purchased Materials

Total Cost: USD $59.08

Fabrication

Cup and Motor Holder

These parts were 3D printed

top of cupholder 3d print

Machine Frame/Chassis

These parts were laser cut in acrylic

Gantry/Linear Movement

These parts were laser cut in acrylic using the CAD

Machine Connectors

These parts were 3D printed and assembled with a bolt

connectors 3d layout connectors 3d print

Telephone Cords

These parts were created through cutting ~10 inch wires, stripping ~1cm off of each end, inserting them into a 4 pin tool, and crimping them. The parts were then tested with a multimeter to ensure connectivity.

wires and cutting final small telephone wire

Power Supply Mount

This part was provided by Jake, and thus it was not necessary to CAD/fabricate a new one. The part was then wired successfully.

power supply power supply mount

Electronics

DC Motor Control Board

The board was revised (from what?) and includes the addition of a 12V linear regulator (power from supply is 24v). Routing was added for 5V power to the module board, as more power means more capacitance. The board was then milled and soldered

board design board schematic milled PCB soldered PCB soldered PCB

Drink Stirrer Board

The power board for the stirrer is just a linear regulator, and there’s a switch attached to it.

Software

Low Level Firmware to be Added to Jake's Module Board

Firmware was added using platform.io . Important ponyo files:

PlatformIo and ponyo setup:

  1. Add hunk class (example code hunk_pin_pa12_output.h, hunk_pin_pa12_output.cpp) and add to build_bootstrap.h
  2. Upload code to Jake's board
  3. Create .js code for hunks, under :cuttlefish/hunks/interface
  4. Add hunks with inputs and outputs connected to toggle and errlight to output to LED

Code example:


		hunklist[hlc++] = "driver/errlight";
		if (type == "driver/errlight"){
			ret = new Hunk_ErrLight();
		}
 		

Writing Jake's code to the module board: (using linux is easiest)

  1. Download platformio in visual studio code and open Jake's repo called ponyo folder from platformio home (not visual studio). Then start debugging and fix the following things:
  2. Run this command to change all "arduino.h" to "Arduino.h"
  3. find . -type f -exec sed -i 's/"<"arduino.h">"/"<"Arduino.h">"/g' {} \;
  4. Check if it worked by running this to search for any remaining "arduino.h"'s:
  5. grep -R arduino.h *
  6. Look for this in the code. It's important to do this otherwise things won't compile. You need to comment out SERCOM5_2_Handler and SERCOM5_0_Handler.
  7. 
    // need to comment out arduino's instantiation of this,
    // platformio keeps these things elsewhere,
    // for (windows) this was (the .- proceeding the folder name means it's hidden)
    // you'll have to make sure hidden files are exposed in your finder
    // users/"<"me">"/.platformio/packages/framework-arduinosam/variants/feature_m4/variant.cpp
    			
  8. Check your devices in platformio and if it doesn't say 8031, go to cuttlefish/processes/vfpts.js and change the product ID to match whatever your device reads. let pid = '8031'

To test things, the name of one of Jake's modules was changed as well as the name in the hunks list in the bootstrap file, and it successfully updated in the GUI side.

javascript/GUI code interface between cuttlefish and the module board/stepper motor board

Repository:git@github.mit.edu:premila/eds_cuttlefish.git

Cuttlefish:link - connecting the serial port hunk to your computer to interact with boards. Defining pins:

 
        #define PUMP1_PIN 20
	#define PUMP1_PORT PORT->Group[0]
	#define PUMP2_PIN 21
	#define PUMP2_PORT PORT->Group[0]
	#define PUMP3_PIN 22
	#define PUMP3_PORT PORT->Group[0]
	#define PUMP4_PIN 23
	#define PUMP4_PORT PORT->Group[0]


	#define PUMP1_BM (uint32_t)(1 << PUMP1_PIN)
	#define PUMP1_SETUP PUMP1_PORT.DIRSET.reg = PUMP1_BM
	#define PUMP1_ON PUMP1_PORT.OUTCLR.reg = PUMP1_BM
	#define PUMP1_OFF PUMP1_PORT.OUTSET.reg = PUMP1_BM

	#define PUMP2_BM (uint32_t)(1 << PUMP2_PIN)
	#define PUMP2_SETUP PUMP2_PORT.DIRSET.reg = PUMP2_BM
	#define PUMP2_ON PUMP2_PORT.OUTCLR.reg = PUMP2_BM
	#define PUMP2_OFF PUMP2_PORT.OUTSET.reg = PUMP2_BM

	#define PUMP3_BM (uint32_t)(1 << PUMP3_PIN)
	#define PUMP3_SETUP PUMP3_PORT.DIRSET.reg = PUMP3_BM
	#define PUMP3_ON PUMP3_PORT.OUTCLR.reg = PUMP3_BM
	#define PUMP3_OFF PUMP3_PORT.OUTSET.reg = PUMP3_BM

	#define PUMP4_BM (uint32_t)(1 << PUMP4_PIN)
	#define PUMP4_SETUP PUMP4_PORT.DIRSET.reg = PUMP4_BM
	#define PUMP4_ON PUMP4_PORT.OUTCLR.reg = PUMP4_BM
	#define PUMP4_OFF PUMP4_PORT.OUTSET.reg = PUMP4_BM
    

Added hunk to list in bootstrap


	  hunklist[hlc++] = "driver/pour";
	  if (type == "driver/pour"){
	    ret = new Hunk_Pour();
	  }
    

We created a state machine that transitions between pouring and moving in a javascript hunk to use in cuttlefish to set the workflow for our machine. We created two outputs: one for the pump number we want to pour out of and one for the position we want our cup to be at.


	// pumpState output -> microcontroller input
	let pumpState = this.output('int32', 'pumpState', 0);
	// stepperPosition output -> saturn posn input 
	let stepperPosition = this.output('array', 'stepperPosition', 0);
	

We initialized the drinking machine hunk:


	this.init = () => {
		this.log('hello drinking machine')
	}
	

We have a dictionary mapping drink numbers to lists of the ratios/amount of each ingredient for each drink.


	  const dictDrinks = { //apparently you can't have integer keys
	    '0': [0], // a state to reset everything
	    '1': [1,1,2,2,2,4,5], // end with 5 so we go to the end
	    '2': [1,1,1,2,3,3,5],
	    '3': [2,2,2,3,3,4,4,4,5],
	    '4': [1,1,3,3,4,4,4,4,5]
	  };

	 

We also created a dictionary for positions to move to via the stepper motor, with the states below:


	  const dictPositions = { // Pass an array to Saturn
	    '0': [0,0,0],  // far left
	    '1': [20,0,0], // under first pump
	    '2': [40,0,0], // under second pump
	    '3': [60,0,0], // under third pump
	    '4': [80,0,0], // under fourth pump
	    '5': [100,0,0],// far right
	  };

	  const states = {
	    IDLE: 0,
	    GET_NEXT_ITEM: 1,
	    MOVE_STEPPER: 2,
	    MOVE_DELAY: 3,
	    POUR_DRINK: 4,
	    POUR_DELAY: 5
	  };

      //We used a delay technique to wait for different states to finish:

	  const delayInMillisecondsMove = 1000; //3 second
	  const delayInMillisecondsPour = 2000; //30 seconds


       //Here's the list of drinks we can make for you!

	    const pairList = [
	      [0, 'Reset'],
	      [1, 'Mojito'],
	      [2, 'Manhattan'],
	      [3, 'Screwdriver'],
	      [4, 'Tropical Sunset']
	    ];
 
      //This is the loop that switches between states:

	  this.loop = () => {
	    switch(state){
	      case states.IDLE:
	        // do nothing while idling
	        break;
	      case states.GET_NEXT_ITEM:
	        // check to see if there's anything left to grab
	        if (currentIngredient >= drinkList.length){ // nothing left to do!
	          state = states.IDLE;
	          console.log("Drink Complete");
	          break;
	        }
	        // pull the next drink
	        let oldMove = curMove; // check previous move to see if we've done it already
	        curMove = dictPositions[drinkList[currentIngredient]];
	        curPour = drinkList[currentIngredient];
	        console.log("Preparing ingredient " + currentIngredient);
	        currentIngredient++;
	        if (oldMove == curMove) { // if we've already moved the stepper here, don't do it again
	          state = states.POUR_DRINK;
	        }
	        state = states.MOVE_STEPPER;
	        break;
	      case states.MOVE_STEPPER:
	        stepperPosition.put(curMove); // move the stepper
	        console.log("Moving to " + curMove);
	        setTimeout(function() { // after 3 seconds, switch to pour state
	          state = states.POUR_DRINK;
	        }, delayInMillisecondsMove);
	        state = states.MOVE_DELAY;
	        break;
	      case states.MOVE_DELAY:
	        // do nothing while waiting for move to complete
	        break;
	      case states.POUR_DRINK:
	        if (curPour == 5){ // don't pour if we're at the end
	          state = states.IDLE;
	          console.log("At the end, no pour");
	          break;
	        }
	        console.log("Pouring " + curPour);
	        pumpState.put(curPour);
	        if (curPour == 0){ // there's nothing to pour
	          state = states.GET_NEXT_ITEM;
	          break;
	        }
	        setTimeout(function() { // after 30 seconds, switch to get 
	          pumpState.put(0); // stop pouring after complete
	          state = states.GET_NEXT_ITEM;
	        }, delayInMillisecondsPour);
	        state = states.POUR_DELAY;
	        break;
	      case states.POUR_DELAY:
	        // do nothing while waiting for pour to complete
	        break;
	    }
	

The GUI for one drink, cuttlefish saturn pump success, and the successful state machine are below:

Assembly

After fabricating all of our parts we ended up assembling them we realized the cup holder was too tall to fit in the chassis correctly. We ended up adding this to the side of the machine to hold the cup for magnetic stirring and fabricated another shorter cup holder to go in the chassis. We then tested the product without the holder (with duct tape) while we waited for the part to print. We hooked all the pumps up and covered everything with electric tape.

intermediary assembly intermediary assembly intermediary assembly

Testing

We first tested the silicone tubing and magnetic stirring

We then tested the gantry and the pumping of liquid together. The first build failed due to another program not being started. The second build succeeded and we successfully made the drink "Green Monster"

Final Product

Introducing UDrink!

Relevant Files

The relevant CAD files (not created by Jake, you can find his CAD files in his repo here) for this project can be found here