Robotic Bartender with Arduino
A DIY robot that makes mixed drinks. Four 12V peristaltic pumps are controlled by an Arduino through a relay module. A control panel on the front allows the user to tweak the ingredient levels (+/- %50). As the drink is powered an agitator shakes the cup to help stir the fluids. The project is housed in a laser cut acrylic case was design with MakerCase (en.makercase.com) and cut on a Boss Laser. All the grey parts were designed in Fusion 360 and printed on a MK3S Prusa 3D printer.
Motivation
When I was first getting into Arduino it seemed like every other video I saw online was some kind of robotic cocktail mixer. Not being a guy that ever drinks liquor, I put a mental “that’s neat” bookmark on the idea, but always had something more interesting to explore first. After week 10 of the 2020 Corona Virus lock down rolled around, I had exhausted most of my other project ideas and figured it was finally time to give this one a go.
I’d made a motion activated dripping fountain for my cat a few years back, which was a good prototype for this project. It introduced me to peristaltic pumps, how to control them with relays, and some of the issues of power both of those without crashing the Arduino.
Process
Schematic
Code
/*
Robotic Bartender
This program runs on an Arduino Uno and controls a robot that makes mixed drinks.
A rotary selector switch allow for one of six settings (one for mixing the drink and 5 for flushing the lines)
4 slide potentiometers allow the ingredients amounts to be tweaked manually.
An "execute" NO push buttons is the main user input.
Output of the Arduino is through a 8-relay module board, which controls 5, 12V DC motors (4 four pumping, one for stirring)
Johnny Devine 2020
*/
//Define inputs
const int execute = 13; //red wire; normally open push button
const int mixDrink = 12; //white wire; rotatry selector switch
const int flushAll = 11; //yellow wire; rotatry selector switch
const int flushOne = 10; //green wire; rotatry selector switch
const int flushTwo = 9; //white wire; rotatry selector switch
const int flushThree = 8; //red wire; rotatry selector switch
const int flushFour = 7; //blue wire; rotatry selector switch
const int ingOne = A0; //blue wire; slide potentiometer
const int ingTwo = A1; //white wire; slide potentiometer
const int ingThree = A2; //green wire; slide potentiometer
const int ingFour = A3; //yellow wire; slide potentiometer
//Define outputs
const int relayStir = 0; //relay 8, white wire; stir plate motor
const int relayOne = 1; //relay 7, blue wire; pump motor
const int relayTwo = 2; //relay 6, green wire; pump motor
const int relayThree = 3; //relay 5, white wire; pump motor
const int relayFour = 4; //relay 4, yellow wire; pump motor
const int relayBell = 5; //relay 3, blue wire; solenoid for bell
//Drink pump times (in milliseconds)
//rate of pumps is about 35 ml/s. One fluid oz is about 30 ml. That's about 429 ms per half oz. 857 ms per 1 oz. 1286 ms per 1.5 oz.
//7oz is about 200 ml (a "highball")
//"Sex on the Beach":
//{1 oz vodka, 1 oz peach schnapps, 3 oz cranberry juice, 3 oz orange juice}
int drink[4] = {857,857,2572,2572}; //The milliseconds to run reach pump
int adjDrink[4] = {0,0,0,0}; //an array to hold the times after adjusted by pots
// could list other ingredient and pump timese here for easy switching...
//Timing variables to use with the pumps
int nowTime = millis();
int thenTime = millis();
//Variables to hold readings from slider pots:
float ingOneAdj;
float ingTwoAdj;
float ingThreeAdj;
float ingFourAdj;
//Define range (think percentage) of ingredient adjustments. 100 is normal amount
int highAdj = 150;
int lowAdj = 50;
void setup() {
pinMode(execute,INPUT_PULLUP);
pinMode(mixDrink, INPUT_PULLUP);
pinMode(flushAll, INPUT_PULLUP);
pinMode(flushOne, INPUT_PULLUP);
pinMode(flushTwo, INPUT_PULLUP);
pinMode(flushThree, INPUT_PULLUP);
pinMode(flushFour, INPUT_PULLUP);
pinMode(ingOne, INPUT);
pinMode(ingTwo, INPUT);
pinMode(ingThree, INPUT);
pinMode(ingFour, INPUT);
pinMode(relayStir, OUTPUT);
pinMode(relayOne, OUTPUT);
pinMode(relayTwo, OUTPUT);
pinMode(relayThree, OUTPUT);
pinMode(relayFour, OUTPUT);
pinMode(relayBell, OUTPUT);
digitalWrite(relayStir, HIGH);
digitalWrite(relayOne, HIGH);
digitalWrite(relayTwo, HIGH);
digitalWrite(relayThree, HIGH);
digitalWrite(relayFour, HIGH);
digitalWrite(relayBell, HIGH);
digitalWrite(6, HIGH);
//Be sure to comment out before use or pin 1 and 0 can't be used for relay
//Serial.begin(9600); //can be used for debugging
}
void loop() {
if(!digitalRead(mixDrink)){ //If switch is on "Mix Drink"
if(!digitalRead(execute)){ //and the "execute" button is pressed
thenTime = millis();
nowTime = millis();
//Look at the ingredient tweaks and adjust pump times accordingly
ingOneAdj = analogRead(ingOne);
ingOneAdj = constrain(ingOneAdj, 680, 1015);
ingOneAdj = map(ingOneAdj, 1015, 680, lowAdj, highAdj);
ingTwoAdj = analogRead(ingTwo);
ingTwoAdj = constrain(ingTwoAdj, 680, 1015);
ingTwoAdj = map(ingTwoAdj, 1015, 680, lowAdj, highAdj);
ingThreeAdj = analogRead(ingThree);
ingThreeAdj = constrain(ingThreeAdj, 680, 1015);
ingThreeAdj = map(ingThreeAdj, 1015, 680, lowAdj, highAdj);
ingFourAdj = analogRead(ingFour);
ingFourAdj = constrain(ingFourAdj, 680, 1015);
ingFourAdj = map(ingFourAdj, 1015, 680, lowAdj, highAdj);
adjDrink[0] = drink[0]*ingOneAdj/100;
adjDrink[1] = drink[1]*ingTwoAdj/100;
adjDrink[2] = drink[2]*ingThreeAdj/100;
adjDrink[3] = drink[3]*ingFourAdj/100;
//Run each pump, one at a time, for the adjusted amount of times, stirring the whole time
digitalWrite(relayStir, LOW);
while(nowTime - thenTime < adjDrink[0]){
digitalWrite(relayOne, LOW);
nowTime = millis();
}
digitalWrite(relayOne, HIGH);
delay(1000);
thenTime = millis();
nowTime = millis();
while(nowTime - thenTime < adjDrink[1]){
digitalWrite(relayTwo, LOW);
nowTime = millis();
}
digitalWrite(relayTwo, HIGH);
delay(1000);
thenTime = millis();
nowTime = millis();
while(nowTime - thenTime < adjDrink[2]){
digitalWrite(relayThree, LOW);
nowTime = millis();
}
digitalWrite(relayThree, HIGH);
delay(1000);
thenTime = millis();
nowTime = millis();
while(nowTime - thenTime < adjDrink[3]){
digitalWrite(relayFour, LOW);
nowTime = millis();
}
digitalWrite(relayStir, HIGH);
digitalWrite(relayOne, HIGH);
digitalWrite(relayTwo, HIGH);
digitalWrite(relayThree, HIGH);
digitalWrite(relayFour, HIGH);
//ring bell
delay(1000);
digitalWrite(relayBell, LOW);
delay(8);
digitalWrite(relayBell, HIGH);
} else {
digitalWrite(relayOne, HIGH);
digitalWrite(relayTwo, HIGH);
digitalWrite(relayThree, HIGH);
digitalWrite(relayFour, HIGH);
digitalWrite(relayStir, HIGH);
digitalWrite(relayBell, HIGH);
}
//Code for other switch settings. Run the appropriate pumps as long as the "execute" button is held down.
} else if(!digitalRead(flushAll)){
if(!digitalRead(execute)){
digitalWrite(relayOne, LOW);
digitalWrite(relayTwo, LOW);
digitalWrite(relayThree, LOW);
digitalWrite(relayFour, LOW);
delay(10);
} else {
digitalWrite(relayOne, HIGH);
digitalWrite(relayTwo, HIGH);
digitalWrite(relayThree, HIGH);
digitalWrite(relayFour, HIGH);
delay(10);
}
} else if(!digitalRead(flushOne)){
if(!digitalRead(execute)){
digitalWrite(relayOne, LOW);
delay(10);
} else {
digitalWrite(relayOne, HIGH);
delay(10);
}
} else if(!digitalRead(flushTwo)){
if(!digitalRead(execute)){
digitalWrite(relayTwo, LOW);
delay(10);
} else {
digitalWrite(relayTwo, HIGH);
delay(10);
}
} else if(!digitalRead(flushThree)){
if(!digitalRead(execute)){
digitalWrite(relayThree, LOW);
delay(10);
} else {
digitalWrite(relayThree, HIGH);
delay(10);
}
} else if(!digitalRead(flushFour)){
if(!digitalRead(execute)){
digitalWrite(relayFour, LOW);
delay(10);
} else {
digitalWrite(relayFour, HIGH);
delay(10);
}
} else {
digitalWrite(relayOne, HIGH);
digitalWrite(relayTwo, HIGH);
digitalWrite(relayThree, HIGH);
digitalWrite(relayFour, HIGH);
digitalWrite(relayStir, HIGH);
digitalWrite(relayBell, HIGH);
delay(10);
}
}