Introduction: Automated Cocktail Drink Machine

About: I’m a maker, an engineer, and most definitely a dreamer! Roses are red. Violets are blue. I’m a maker... just like you!

Hey guys,

In this instructables I want to show you how to build your own automated mixed-drink maker to satisfy all your liquid (and alcohol ;) )needs.

For a while now, I have been satisfying my thirst and taste-buds with pre-made concentrates from sodastream. The unit allows you to easily carbonate water and add flavoring to it. However, where it exceeds in easy of use, it lacks in quality. After nearly 4 months of research and planning, I can finally say that i have built my own solution that goes above and beyond anything currently on the market. Having gone through all the steps, this project is great for those who want to build a full-tier product, involving both software and hardware. This project has been a great starting point for the exploration of arduino and manufacturing.

With that being said, Follow along to build your own Automated Mixed-Drink Machine..


Take a look at the 3D model below, this is an outline of what the final product should like once your done.

(If you can't see the interactive 3D model below, its probably because you're not using a WebGL - enabled browser, or your using the instructables app))

However, Before we get any further, its a good idea for you to know what you are going to build, so take a look at these wonderful beauty shots. (yes there is a top, but the internals look cool for the photos :D )

Below are GIFs of each station. As the drink is being constructed, it is transported to each station on the a motorized sliding rail. Depending on the recipe, the drink may or may not need to move in different patterns.

Stations Include:

  1. Automated Mint, Sugar, and Lime Muddle for releasing all the flavors
  2. Automated Lime Slicer and Dispenser
  3. Automated Mint and Sugar Dispenser
  4. Automated Liquid Dispenser

Additionally all these processes are controlled by multiples Arduinos and 10.1" tablet via a Serial Connection. (Refer to coding steps)

WOW!!!!

(This looks even better in real life. If you guys want more photos, please don't hesitate to ask in the comments - i will be happy to upload more :D)

Step 1: Mechanical Parts List

The entire machine was modeled and designed in Fusion 360. Below you can find all the required technical parts and files for the machine.

Standard Hardware Parts:

Most of these parts you can buy at a local hardware store or online from Amazon/Aliexpress:

QuantityDescriptionLinkPrice
4x32-35 mm (1") pipe mounting bracketsBauhaus3,50€
4x

32-35 mm (1") pipe mounting brackets

Bauhaus3,50€
2x

74-80 mm (21/2") pipe mounting brackets

Bauhaus4,50€
10xSquare mounting bracketsBauhaus15,00€
1x500mmx1500mmx60mm Styrofoam PanelBauhaus3,00€

Nails, Screws, Nuts, Bolts, and Washers:

QuantityDescriptionWhere to buy
Price
8xM5x20mm DIN912 cylinderhead screw
local hardware store
-
4xM5x10mm DIN912 cylinderhead screw

local hardware store

-
6xM4x20mm DIN912 cylinderhead screw

local hardware store

-
4x1.2mmx20mm Steel Nailslocal hardware store-
20xM3x30mm DIN912 cylinderhead screw

local hardware store

-
10xM3x25mm DIN912 cylinderhead screw

local hardware store

-
30x5mmx15mm Wood Screwslocal hardware store-
20x5mmx30mm Wood Screwslocal hardware store-
2x30mmx50mm Brass Hingeslocal hardware store-
20xM3 Nut

local hardware store

-
15xM5 washer

local hardware store

-
6xM4 washer

local hardware store

-
30xM3 washer

local hardware store

-

Pipes & Rails:

QuantityDescriptionLinkPrice
1x20x1000mm round aluminium extrusion

local hardware store

3,50€
1x15x15x1000 square stainless steel extrusionlocal hardware store8,80€
1x

12x1000mm round aluminium extrusion

local hardware store5,80€
1x75mm Y PVC Pipe Fittinglocal hardware store0,50€
1x75mm T PVC Pipe Fitting
local hardware store0,50€
1x75mmx500mm round PVC pipe
local hardware store0,75€

CNC-Laser-Cut Parts:

All laser cut parts were cut on a BOSS LS-1630 laser cutter. I was able to get access to a laser cutter from a nearby school, but there are more and more maker-shops poping up, and those often have similar equipment. For 3mm Acrylic, power was set to 90 and speed 25. For 5mm Acrylic parts the power was set to 95 and speed 10. These settings seemed to work well - it always cut through the plastic and protective covering without any problems, however depending on your machine these settings will likely need to be changed.

These are the "must-have" laser cut parts - additional laser cut parts from 3mm&5mm acrylic sheets are included in the files, however these only for atheistic purposes.

DXF Files can be found at the bottom of this step

QuantityDescriptionHow the part looks like
1x

Top Bracket

2x

Side Bracket

1x

Bottom Slider

1x

Copper Backing

1x

Wood Bracket

1x

Left Panel

2xTop & Bottom Electronic Structure
2x

Side Panel Electronic Structure

8x

Braces

3D-Printed Parts:
The 3D-Printed parts are made out of PLA with a resolution of 0.1mm. I used a Prusa I3 Mk3 3D printer to print the parts. Total Print time was around 48 hours and used almost 500g of filament at 20% infill.

All the required STL files are available at the end of this step in addition to GrabCAD and Fusion360 Gallery.

QuantityDescriptionHow the part looks like
1x

Mint Container

1x

Sugar Container

1x

Mint Auger

1x

Sugar Auger

Step 2: Electronics Part List

Below you can find a list of all the electrical and technical parts (and links to the purchased parts). Many of these can be found in pre-made kits from elegoo, such as:

I Highly recommend these as they also come with tutorials and other projects for future DIYing! :)

QuantityDescriptionName on PCB
LinkPrice
1xArduino Uno R3
Elegoo Kit-
1xArduino Mega 2560

Elegoo Kit-
8x1k Resistor
Elegoo Kit-
1x500N, 100mm, Linear Actuator 20mm/s
Bangood
38$
1x200N, 200mm, Linear Actuator 50mm/s
Bangood
45$
3x5x 60w Peltier Modules

Amazon
12$
1x9g Servo Motor
Glass SliderElegoo Kit-
1x10.1" Samsung Tablet
-
1xLN298 Motor Driver
Elegoo Kit-
50xM-M BreadBoard Wires
Elegoo Kit-
1xBread Board
Elegoo Kit-
2x8 Channel Relay

Amazon
7$
2x120mm Fans
-
7xPumps
-

Step 3: Build the Base and Drink Cabinet

Here comes the most important part, build the structural frame for all the technical parts. The goal here was to make the entire product look and feel as professional as possible. Using materials such as shiny acrylic, hard PVC sheets and thick dark wood did just that. They provided a feed that resembled the strength and functionality of an industrial appliance, but also emitted a sense of homeliness and luxury.

After all, this is just that, a luxury machine. I mean... Its a cocktail maker with copper sheets just for looks! WOW!

The Process:

First things first, we need to cut each material to its required size. A list of hand drawn dimensions and diagrams can be seen below, but also obtained via the 3D model above and DXF files for each part. (I'll Include those at the end of this step)

Step 4: Construct the Mint & Sugar Dispensers

First things first - Print the parts. The 3D-Printed parts are made out of PLA with a resolution of 0.1mm. I used a Prusa I3 Mk3 3D printer to print the parts. I found 20% infill to be the best compromise between strength and filament used.

Below is a cross section of a failed print. Here you can see the internal grid structure that provides the 3D object its strength. I even took this piece and ran over it with a car, it still looks the same. :)

Once you have all your 3D printed parts, its time to clean them up. I used a chisel and pliers to remove all the support structure, and then sanded every surface with 100,200, and 400, grit sand paper. It is important that these parts have a smooth surface as they will be rubbing against each other.

Next, you want to insert your motor into the square cavity (you can see this clearly above). Make sure the shaft lines up with the hollowed out circular hole. the tab of the motor should also fit in the tiny square hole perpendicular to the shaft. Once the motor is in place, use hotglue to secure to the 3D printed structure.

After the glue is dry, take the matching auger and slide it into the container. there is a D shaped mounting bracket at the end of the auger shaft which matches that of the motor, use super glue to attach the two for a strong fit.

Once the product is complete, mint and sugar will fill the large and small containers respectively. The rotating auger/Archimedes screw will transport the material to the T-shaped pipe, where they both fall down the same shaft into the glass.

Using a screw to dose materials allows us to be very accurate (to the gram in my experiments). With this accuracy, we can make the perfect drink!

Step 5: Slider Module (Moves the Glass)

As you can see in the 3D model above, this is the sliding mechanism used to transport the glass between stations (Liquid Fill, Lime Fill, Sugar/Mint Fill, & Linear Actuator Muddle Station)

Parts Needed:

  1. 15x15mm Square Chrome Pipe
  2. 12mm Diameter Chrome Pipe
  3. 9g Continuous Servo Motor
  4. 70mmx100mmx18mm Dark Wood

Cut the Pipes:

You will need to make adjustments to the side of the Pipe Stock. Below you can find the dimensions and quantity required for each part.

  1. 430mmx12mm Diameter Chrome Pipe (2x)
  2. 100x15x15mm Square Chrome Pipe (2x)
  3. 70x100x18mm Stained Wooden Block (1x)

Adjusting the wooden block:

As shown in the interactive 3D model, underneath you will need to house the 9g servo motor. Using a chisel remove 12(d)x34(w)x40(l) of material. I also found that using a 30-35mm circular drill bit was a fast and easy method to remove the majority of material.

Once the square is removed, using hot-glue, mount the 9g servo motor underneath. The orientation isn't important, but i found it is better to have the side with the cable on it closer to the wall so it doesn't get stuck.

Next, using the mounting brackets that come with the servo, attach them to a circular (20mm Diameter) disk (Laser cut DXF Files). This will be the wheel that provides traction to move the slider.

Once the servo is mounted, Hot glue the wooden block to the two square chrome pipes. Attach the pipes on the two longer sides of the block. Once attached, the entire piece should make a 100x100mm square.

Next slide the two longer 12mm round chrome pipes though the 15x15mm square pipes.

The Slider Is now complete, and can be mounted in a future step!

Step 6: How to Select a Peltier Module

Common thermal management solutions used in electronics applications address cooling objects with heat exchangers and fluid flow. The heat exchanger is typically either the electronic package itself or an extruded or stamped heat sink attached to the package. Air is the most common fluid used in thermal solutions, either with natural convection or propelled by a fan. In most of these solutions the temperature of the object being cooled remains above the ambient temperature. Peltier modules are electronic devices designed for cooling objects to below the ambient temperature or maintaining objects at a specific temperature by controlled heating or cooling. Selecting or specifying a Peltier module is not difficult but a basic understanding of module characteristics can be helpful to ensure the process flows smoothly.

Peltier Module Basics

Peltier modules contain two external ceramic plates separated by semiconductor pellets. One of the plates absorbs heat (becomes cooler) and the other plate dissipates heat (becomes hotter) when a current is passed through the semiconductor pellets. More details regarding the construction and operation of Peltier modules can be found in this technical paper.

The following constraints should be understood when selecting or specifying a Peltier module:
Heat transfer through the module

  • Temperature difference across the module
  • Temperature of hot side of the module
  • Surface area of module
  • Required operating current
  • Required driving voltage

Heat Transfer Through Peltier Modules

The amount of heat to be transferred through a Peltier module from the cold side to the hot side is denoted Q and is specified in Watts. This parameter may be the heat generated by an object to be cooled or it may be the heat conducted to the ambient environment from the object being cooled. It should be understood that Peltier modules do not possess the ability to absorb thermal energy. Peltier modules only transfer thermal energy and the energy being transferred will need to be dissipated on the hot side of the module.

Temperature Difference Across Peltier Modules
The temperature difference specified in a Peltier module datasheet (ΔT) is measured on the outside surfaces of the two ceramic plates of the module. Care must be taken to understand if there is any temperature difference between the Peltier module plates and the external system temperatures of interest. The following diagram indicates five potentially different temperature regions of a Peltier module system.

Temperature of the Hot Side of Peltier Modules
The characteristics of Peltier modules also change with operating temperature. Some vendors, such as CUI, provide specification data for more than one operating temperature. Specification data will probably not be available for the specific operating temperatures of the application and thus the closest available data should be used.

Surface Area of Peltier Modules

The surface area of Peltier modules is typically specified based upon either the area of the object to be cooled or the area available for heat dissipation. An area mismatch between the area available and the area of the Peltier module can be compensated for by the use of a low thermal impedance heat spreader. A simple heat spreader can be manufactured from aluminum or copper.

Required Operating Current
Peltier modules are current-driven devices similar to LEDs. The desired operating parameters are most conveniently achieved by driving the module with a controlled current source and allowing the current source to provide the required load voltage (the voltage compliance of the current source). This is analogous to providing a specific voltage to a voltage driven device and then letting the voltage source provide the required current (i.e. providing a voltage to a microprocessor and ensuring the voltage source can provide the required load current). Peltier modules can be driven with voltage sources but doing so will make it more difficult to accurately control the heat flow and temperature difference across the module.

Required Operating Voltage

The required voltage compliance of the current source will be determined from the Peltier module datasheet and operating constraints.

The Peltier Module I Chose:

I Chose a 40mmx40mm Standard 60w Peltier Module. The Module Peaks at 12v, however i found that it seems to work better at around 8, where 12 just makes both sides hot.

Step 7: Temperature Controlled Chamber

For many drink additives (Juices & Tonic Water), it is imperative that they are kept cool. In order to achieve this, an insulated temperature controlled chamber was designed using peltier technology and temperature sensors.

At a local hardware store i was able to purchase a large sheet of 60mm thick insulation foam. so far this has done a great job keeping the insides of the container cool.

Using a handsaw saw, cut the sheet to the dimensions listed below:

  1. 426mmx226mm (1x) (base)
  2. 470mmx426mm (2x) (side wall)
  3. 470mmx226mm (2x) (side wall)

Using hotglue or super glue, construct the 5 sided container. I recommend building it vertically ontop of the base. Sometimes hotglue guns can melt the stryrofoam, but if you hold the glue about 30cm away from the surface you are applying it too, it has enough time to cool down to the point where it does melt. I found that this worked best, even better than superglue.

Once the foam frame is constructed, Gather the acrylic parts cut on the laser cutter. In case you don't have access to a laser cutter, they have also been designed to be able to be cut on a table saw or with a circular saw. Remember, these parts are not required, but they do make the product feel complete.

  1. 306mmx106mm (1x) (Cooler Bottom)
  2. 300mmx467mm (2x) (Cooler Sides)
  3. 106mmx467mm (2x) (Cooler Sides)

In this case, the smaller walls sandwich the larger ones, with all the walls ontop of the bottom place.

Once the cooler's structure is complete, You will need 3 peltier modules and 3 heat sinks. I was able to find extra heatsinks at an electronics recycling bin. It is important to note that your heat sinks should be able to disperse the energy transferred from the peltier modules. (In my case, the larger one is rated to handle 250w, and the smaller ones 100w. More than enough for the 60w peltier modules)

Using a steaknife, cuttout the foot print of your coolers on one of the larger foam sides. Then using a drill and 40-50mm diameter bit, cut three holes in the acrylic sheet where the heatsinks will go.

On the inside of the cooler, glue a sheet of copper to the wall with the holes in it. I used super glue, but make sure to only glue along the outer edge and away from the holes.

Next, Using thermal paste (Common at any computer store like fryes or radioshack), stick the peltier modules too the copper from the outside. I tend to use an X shape when applying thermal paste, and then let the force of application spread the rest. This seemed to work well.

On the other side of the peltier module, apply more thermal paste, and mount the heat sink to it. If necessary, you may have to drill through the wall and mount the heatsink with nuts and bolts if it is too heavy. Make sure to then attach a fan to the heat sink if it doesn't already have one.

In order to accurately control the temperature of the cooled container, I used a Bluetooth-Temperature Module. The temperature of the container can also be viewed via an app on you android or IOS device. Remotely, you can review the temperature and humidity levels as well as set the desired temp.

Step 8: Lime Slicer

One of the stations on the automated drink maker is an automated Lime dispenser and slicer. A lime drops down a Y-shaped pipe, where it is then forced against a sharp metal grid by a 500N 12v Linear actuator. The grid slices the lime into 4 equal parts, and then drops into the glass. This step is followed by others such muddling and filling the glass with liquid.

In order to mount the linear actuator to the frame and keep all the moving parts stable, I used 32-34mm Pipe claims with Bolt holes on either side. These provided a simple way to mount the actuators and pipes in the upper compartment while keeping everything sturdy. (This actuator provides 500N of force - that"s a lot!)

Step 9: Programming the User Interface (Android Studio)

In order to create a slick user interface to accompany the final product, i decided to use a an android tablet. The tablet has a screen side of 10.1" which makes it perfect for viewing and easily selecting the desired drink. The app's main purpose is to send commands to the arduino over a USB serial connection.

In order to do this, drinks have been put into scrollable horizontal carousels based on their type (Rum, Whisky, Gin.. etc). Each item has an image and name associated with it to make the drink easily identifiable. Once the user clicks on the desired drink, we will make a popup where the user can then change the size (the amount of liquid) they want in addition to inputting personal tweaks (e.g. more ice, more alcohol, more sugar, etc..). Once the drink's characteristics are chosen, the drink can be ordered. A long chain of numbers, each representing a different variable (e.g. quantity of ice), is then generated and sent to the arduino. The arduino interprets this unique drink ID and makes the desired drink as requested.

The Code:

The app consists of three main sections:

  1. MainActivity.java (this is where all the java and code will go to provide functionality to the app)
  2. activity_main.xml (This is where the list of drinks are located)
  3. custompopup.xml (This is the layout page for the custom ordering popup)

Creating the template:

Open up android studio or your IDE of choice and create a new blank app template. This process should automatically create MainActivity.java and activity_main.xml for you. I Also chose to develop my app on android 4.4 (Kit Kat) as this supports almost 90% of devices. Once this is done, we can move on to designing our first page.

Activity_Main.xml:

Activity_main.xml is the primary android layout. For us it will house our list of drinks, an order button, and a custom edit-text forum to insert your own drinkIDs and testing the serial connection.

Start off by creating a linear layout. This will allow us to stack our elements on top of each other for a nice and tidy look.

<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" <br=""><p><LinearLayout</p><p><linearlayout <br="">xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimaryDark"
android:gravity="center|top"
android:orientation="vertical"
tools:context="MainActivity"></linearlayout></p><p><linearlayout <br=""><br></linearlayout></p><p><linearlayout <br=""><br></linearlayout></p></LinearLayout></linearlayout>

Take a look at the steps below and the code that follows for each step.

  1. Next, we want to add specific elements inside this linear layout. For the custom edit-text bar and controls for the serial connection, create a relative layout and put it inside of the linear layout.
  2. Now we want to create a carousel for each drink type (Gin, Rum, etc..). This consists of a Text box labeling it, and the carousel itself. I will have three drink types.
  3. This is what your file should look like

activity_main.xml

<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_gravity="top"
tools:context=".MainActivity">
<EditText
android:id="@+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_marginStart="0dp"
android:layout_marginLeft="0dp"
android:layout_marginTop="0dp"
android:layout_marginEnd="0dp"
android:layout_marginRight="0dp" />
<Button
android:id="@+id/buttonStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/editText"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:onClick="onClickStart"
android:text="Begin" />
<Button
android:id="@+id/buttonSend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/editText"
android:layout_toEndOf="@+id/buttonStart"
android:layout_toRightOf="@+id/buttonStart"
android:onClick="onClickSend"
android:text="Send" />
<TextView
android:id="@+id/textView"
android:layout_width="50dp"
android:layout_height="100dp"
android:layout_below="@+id/buttonSend"
android:layout_alignEnd="@+id/editText"
android:layout_alignRight="@+id/editText"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true" />
<Button
android:id="@+id/buttonStop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/editText"
android:layout_toEndOf="@+id/buttonSend"
android:layout_toRightOf="@+id/buttonSend"
android:onClick="onClickStop"
android:text="Stop" />
<Button
android:id="@+id/buttonClear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/editText"
android:layout_toEndOf="@+id/buttonStop"
android:layout_toRightOf="@+id/buttonStop"
android:onClick="onClickClear"
android:text="Clear" />
RelativeLayout>

Activity_Main.xml

<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_gravity="center"
android:gravity="center"
android:text="Vodka Drinks"
android:textColor="@color/White"
android:textSize="20dp"
android:textStyle="bold" />
<in.goodiebag.carouselpicker.CarouselPicker
android:id="@+id/carouselPicker1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:background="#FFF"
app:items_visible="three"
/>

Step 3) This is what your file should look like

xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimaryDark"
android:gravity="center|top"
android:orientation="vertical"
tools:context="MainActivity">
<RelativeLayoutxmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_gravity="top"
tools:context=".MainActivity">
<EditText
android:id="@+id/editText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_marginStart="0dp"
android:layout_marginLeft="0dp"
android:layout_marginTop="0dp"
android:layout_marginEnd="0dp"
android:layout_marginRight="0dp" />
<Button
android:id="@+id/buttonStart"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/editText"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:onClick="onClickStart"
android:text="Begin" />
<Button
android:id="@+id/buttonSend"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/editText"
android:layout_toEndOf="@+id/buttonStart"
android:layout_toRightOf="@+id/buttonStart"
android:onClick="onClickSend"
android:text="Send" />
<TextView
android:id="@+id/textView"
android:layout_width="50dp"
android:layout_height="100dp"
android:layout_below="@+id/buttonSend"
android:layout_alignEnd="@+id/editText"
android:layout_alignRight="@+id/editText"
android:layout_alignParentStart="true"
android:layout_alignParentLeft="true"
android:layout_alignParentBottom="true" />
<Button
android:id="@+id/buttonStop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/editText"
android:layout_toEndOf="@+id/buttonSend"
android:layout_toRightOf="@+id/buttonSend"
android:onClick="onClickStop"
android:text="Stop" />
<Button
android:id="@+id/buttonClear"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/editText"
android:layout_toEndOf="@+id/buttonStop"
android:layout_toRightOf="@+id/buttonStop"
android:onClick="onClickClear"
android:text="Clear" />
RelativeLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_gravity="center"
android:gravity="center"
android:text="Vodka Drinks"
android:textColor="@color/White"
android:textSize="20dp"
android:textStyle="bold" />
<in.goodiebag.carouselpicker.CarouselPicker
android:id="@+id/carouselPicker1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:background="#FFF"
app:items_visible="three"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_gravity="center"
android:gravity="center"
android:text="Rum Drinks"
android:textColor="@color/White"
android:textSize="20dp"
android:textStyle="bold" />
<in.goodiebag.carouselpicker.CarouselPicker
android:id="@+id/carouselPicker2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:background="#FFF"
app:items_visible="three" />
<TextView
android:layout_width="match_parent"
android:layout_height="30dp"
android:layout_gravity="center"
android:gravity="center"
android:text="Gin Drinks"
android:textColor="@color/White"
android:textSize="20dp"
android:textStyle="bold" />
<in.goodiebag.carouselpicker.CarouselPicker
android:id="@+id/carouselPicker3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
android:background="#FFF"
app:items_visible="three" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/buttonstyle"
android:onClick="ShowPopup"
android:text="Order Drink"
android:textColor="@color/colorAccent" />
LinearLayout>

Step 10: Editing MainActivy.java

This one is a little more complicated. Here we will have to make all the functions,classes, and variables that allow the app to run. We will also need to include a method to make a serial connection with the arduino. Yikes!

Please Look at this Gist file for what the entire file should look like or the GitHub Repository for all the files(sorry instructables wouldn't let me embed it.. too big i guess.) I also included all the files in addition to the apk at the end of this step so you can easily install the application on your android deice.

In this step we will create the serial connection that attaches the android app and the arduino together. In addition there will be buttons that will call functions to initiate specific tasks like sending, closing, and opening the connection.

publicclassMainActivityextendsAppCompatActivity {
//--------------------------------
// Serial Connection
//-------------------------------
publicfinalStringACTION_USB_PERMISSION="com.hariharan.arduinousb.USB_PERMISSION";
Button startButton, sendButton, orderButton, clearButton, stopButton;
TextView textView;
EditText editText;
UsbManager usbManager;
UsbDevice device;
UsbSerialDevice serialPort;
UsbDeviceConnection connection;
UsbSerialInterface.UsbReadCallback mCallback =newUsbSerialInterface.UsbReadCallback() { //Defining a Callback which triggers whenever data is read.
@Override
publicvoidonReceivedData(byte[] arg0) {
String data =null;
try {
data =newString(arg0, "UTF-8");
data.concat("/n");
tvAppend(textView, data);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
};
privatefinalBroadcastReceiver broadcastReceiver =newBroadcastReceiver() { //Broadcast Receiver to automatically start and stop the Serial connection.
@Override
publicvoidonReceive(Contextcontext, Intentintent) {
if (intent.getAction().equals(ACTION_USB_PERMISSION)) {
boolean granted = intent.getExtras().getBoolean(UsbManager.EXTRA_PERMISSION_GRANTED);
if (granted) {
connection = usbManager.openDevice(device);
serialPort =UsbSerialDevice.createUsbSerialDevice(device, connection);
if (serialPort !=null) {
if (serialPort.open()) { //Set Serial Connection Parameters.
setUiEnabled(true);
serialPort.setBaudRate(9600);
serialPort.setDataBits(UsbSerialInterface.DATA_BITS_8);
serialPort.setStopBits(UsbSerialInterface.STOP_BITS_1);
serialPort.setParity(UsbSerialInterface.PARITY_NONE);
serialPort.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);
serialPort.read(mCallback);
tvAppend(textView,"Serial Connection Opened!\n");
} else {
Log.d("SERIAL", "PORT NOT OPEN");
}
} else {
Log.d("SERIAL", "PORT IS NULL");
}
} else {
Log.d("SERIAL", "PERM NOT GRANTED");
}
} elseif (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
onClickStart(startButton);
} elseif (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) {
onClickStop(stopButton);
}
}
;
};

Here we are adding the buttons to force serial-connection related functions.

//-------------------------------
//Serial Connection Functions
//----------------------
usbManager = (UsbManager) getSystemService(this.USB_SERVICE);
startButton = (Button) findViewById(R.id.buttonStart);
sendButton = (Button) findViewById(R.id.buttonSend);
orderButton = (Button) findViewById(R.id.btnorder);
clearButton = (Button) findViewById(R.id.buttonClear);
stopButton = (Button) findViewById(R.id.buttonStop);
editText = (EditText) findViewById(R.id.editText);
textView = (TextView) findViewById(R.id.textView);
setUiEnabled(false);
IntentFilter filter =newIntentFilter();
filter.addAction(ACTION_USB_PERMISSION);
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
registerReceiver(broadcastReceiver, filter);

These variables are the characteristics of any given drink. Changing these will change the drink produced. These are also the values that are sent to the arduino in a string of numbers. (i call that the DrinkID)

Dialog myDialog;
StringDrinkName="A Drink"; //Note these strings should never appear
StringDrinkType="A Drink Type"; //Note these strings should never appear
publicintVodka_Measure;
publicintRum_Measure;
publicintGin_Measure;
publicintWhiskey_Measure;
publicintTonicWater_Measure;
publicintCranberryJuice_Measure;
publicintOrangeJuice_Measure;
publicintPineapple_Measure;
publicintMint_Measure;
publicintSugar_Measure;
publicintLime_Measure;
publicintLime_Slice;
publicintStir;
publicintMash;
//Human Functions
publicintIce_Measure;
publicintShake;
publicintKalua;
publicintCointreau;
publicintVermouth;
publicintPeach_Schnapps;
publicintCream_De_Cacao;
publicStringDrinkSizeText;
publicintDrinkSize;

Here we are actually creating the carousels and the items within them. Each item has an image associated with it. The name of each drink is already included in the image so it makes it easy to view.

//---------------------------------------------
// DRINK ITEMS / IMAGES ON CAROUSEL!
//---------------------------------------------
carouselPicker1 = findViewById(R.id.carouselPicker1);
carouselPicker2 = findViewById(R.id.carouselPicker2);
carouselPicker3 = findViewById(R.id.carouselPicker3);
//VODKA BASED DRINKS
List<CarouselPicker.PickerItem> itemsImages =newArrayList<>();
itemsImages.add(newCarouselPicker.DrawableItem(R.mipmap.ic_launcher_round));
itemsImages.add(newCarouselPicker.DrawableItem(R.mipmap.drinkpic01));
itemsImages.add(newCarouselPicker.DrawableItem(R.mipmap.drinkpic02));
itemsImages.add(newCarouselPicker.DrawableItem(R.mipmap.drinkpic03));
itemsImages.add(newCarouselPicker.DrawableItem(R.mipmap.drinkpic04));
CarouselPicker.CarouselViewAdapter imageAdapter =newCarouselPicker.CarouselViewAdapter(this, itemsImages, 0);
carouselPicker1.setAdapter(imageAdapter);
//RUM BASED DRINKS
/**
List textItems = new ArrayList<>();
textItems.add(new CarouselPicker.TextItem("One", 2));
textItems.add(new CarouselPicker.TextItem("Two", 2));
textItems.add(new CarouselPicker.TextItem("Three", 2));
CarouselPicker.CarouselViewAdapter textAdapter = new CarouselPicker.CarouselViewAdapter(this, textItems, 0);
carouselPicker2.setAdapter(textAdapter);
**/
List<CarouselPicker.PickerItem>RumImages=newArrayList<>();
RumImages.add(newCarouselPicker.DrawableItem(R.mipmap.ic_launcher_round));
RumImages.add(newCarouselPicker.DrawableItem(R.mipmap.drinkpic01));
RumImages.add(newCarouselPicker.DrawableItem(R.mipmap.drinkpic02));
RumImages.add(newCarouselPicker.DrawableItem(R.mipmap.drinkpic03));
RumImages.add(newCarouselPicker.DrawableItem(R.mipmap.drinkpic04));
CarouselPicker.CarouselViewAdapter imageRumAdapter =newCarouselPicker.CarouselViewAdapter(this, RumImages, 0);
carouselPicker2.setAdapter(imageRumAdapter);
//GIN BASED DRINKS
/**
List mixItems = new ArrayList<>();
mixItems.add(new CarouselPicker.TextItem("One", 2));
mixItems.add(new CarouselPicker.DrawableItem(R.mipmap.drinkpic06));
mixItems.add(new CarouselPicker.TextItem("Three", 2));
mixItems.add(new CarouselPicker.DrawableItem(R.mipmap.drinkpic07));
CarouselPicker.CarouselViewAdapter mixAdapter = new CarouselPicker.CarouselViewAdapter(this, mixItems, 0);
carouselPicker3.setAdapter(mixAdapter);
**/
List<CarouselPicker.PickerItem>GinImages=newArrayList<>();
GinImages.add(newCarouselPicker.DrawableItem(R.mipmap.ic_launcher_round));
GinImages.add(newCarouselPicker.DrawableItem(R.mipmap.drinkpic01));
GinImages.add(newCarouselPicker.DrawableItem(R.mipmap.drinkpic02));
GinImages.add(newCarouselPicker.DrawableItem(R.mipmap.drinkpic03));
GinImages.add(newCarouselPicker.DrawableItem(R.mipmap.drinkpic04));
CarouselPicker.CarouselViewAdapter imageGinAdapter =newCarouselPicker.CarouselViewAdapter(this, GinImages, 0);
carouselPicker3.setAdapter(imageGinAdapter);

In this section of code we are adding click functionality to each image. When the desired drink is in the center of the carousel, the code is ran for each case.

//---------------------------------------------
// DRINK SELECTORS / DRINK RECIPES
//---------------------------------------------
//VODKA BASED DRINKS
carouselPicker1.addOnPageChangeListener(newViewPager.OnPageChangeListener() {
@Override
publicvoidonPageScrolled(intposition, floatpositionOffset, intpositionOffsetPixels) {
}
@Override
publicvoidonPageSelected(intposition) {
//position of the selected item
switch (position) {
case0:
DrinkName="Black Russian";
DrinkType="A Vodka Drink";
Vodka_Measure=2;
Rum_Measure=0;
Gin_Measure=0;
Whiskey_Measure=0;
TonicWater_Measure=0;
CranberryJuice_Measure=0;
OrangeJuice_Measure=0;
Pineapple_Measure=0;
Mint_Measure=0;
Sugar_Measure=0;
Lime_Measure=0;
Lime_Slice=0;
Stir=1;
Mash=0;
Shake=0;
Ice_Measure=0;
Kalua=0;
Cointreau=0;
Vermouth=0;
Peach_Schnapps=0;
Cream_De_Cacao=0;
ToastBlackRussian=Toast.makeText(getApplicationContext(),
"Black Russian",
Toast.LENGTH_SHORT);
BlackRussian.show();
break;
case1:
DrinkName="Black Russian";
DrinkType="A Vodka Drink";
Vodka_Measure=2;
Rum_Measure=0;
Gin_Measure=0;
Whiskey_Measure=0;
TonicWater_Measure=0;
CranberryJuice_Measure=0;
OrangeJuice_Measure=0;
Pineapple_Measure=0;
Mint_Measure=0;
Sugar_Measure=0;
Lime_Measure=0;
Lime_Slice=0;
Stir=1;
Mash=0;
Shake=0;
Ice_Measure=0;
Kalua=0;
Cointreau=0;
Vermouth=0;
Peach_Schnapps=0;
Cream_De_Cacao=0;
ToastBlackRuian=Toast.makeText(getApplicationContext(),
"Black ttttRussian",
Toast.LENGTH_SHORT);
BlackRuian.show();
break;
case2:
DrinkName="Black Russian";
DrinkType="A Vodka Drink";
Vodka_Measure=2;
Rum_Measure=0;
Gin_Measure=0;
Whiskey_Measure=0;
TonicWater_Measure=0;
CranberryJuice_Measure=0;
OrangeJuice_Measure=0;
Pineapple_Measure=0;
Mint_Measure=0;
Sugar_Measure=0;
Lime_Measure=0;
Lime_Slice=0;
Stir=1;
Mash=0;
Shake=0;
Ice_Measure=0;
Kalua=0;
Cointreau=0;
Vermouth=0;
Peach_Schnapps=0;
Cream_De_Cacao=0;
ToastBlaRussian=Toast.makeText(getApplicationContext(),
"Black Ruyyyssian",
Toast.LENGTH_SHORT);
BlaRussian.show();
break;
case3:
DrinkName="Black Russian";
DrinkType="A Vodka Drink";
Vodka_Measure=2;
Rum_Measure=0;
Gin_Measure=0;
Whiskey_Measure=0;
TonicWater_Measure=0;
CranberryJuice_Measure=0;
OrangeJuice_Measure=0;
Pineapple_Measure=0;
Mint_Measure=0;
Sugar_Measure=0;
Lime_Measure=0;
Lime_Slice=0;
Stir=1;
Mash=0;
Shake=0;
Ice_Measure=0;
Kalua=0;
Cointreau=0;
Vermouth=0;
Peach_Schnapps=0;
Cream_De_Cacao=0;
ToastBlackRussin=Toast.makeText(getApplicationContext(),
"Black Russiytrreean",
Toast.LENGTH_SHORT);
BlackRussin.show();
break;
case4:
DrinkName="Black Russian";
DrinkType="A Vodka Drink";
Vodka_Measure=2;
Rum_Measure=0;
Gin_Measure=0;
Whiskey_Measure=0;
TonicWater_Measure=0;
CranberryJuice_Measure=0;
OrangeJuice_Measure=0;
Pineapple_Measure=0;
Mint_Measure=0;
Sugar_Measure=0;
Lime_Measure=0;
Lime_Slice=0;
Stir=1;
Mash=0;
Shake=0;
Ice_Measure=0;
Kalua=0;
Cointreau=0;
Vermouth=0;
Peach_Schnapps=0;
Cream_De_Cacao=0;
ToastBlackian=Toast.makeText(getApplicationContext(),
"Black456 Russian",
Toast.LENGTH_SHORT);
Blackian.show();
break;
}
}
@Override
publicvoidonPageScrollStateChanged(intstate) {
}
});
view rawjava.java hosted with ❤ by GitHub

now we need to create the order button that shows the popup for the final order. here you can select the size of the drink.

//BUTTON TO INITIATE POPUP
publicvoid ShowPopup(View v) {
TextView txtclose;
Button btnOrder;
myDialog.setContentView(R.layout.custompopup);
txtclose = (TextView) myDialog.findViewById(R.id.txtclose);
btnOrder = (Button) myDialog.findViewById(R.id.btnorder);
txtclose.setOnClickListener(newView.OnClickListener() {
@Override
publicvoidonClick(Viewv) {
myDialog.dismiss();
}
});
myDialog.getWindow().setBackgroundDrawable(newColorDrawable(Color.TRANSPARENT));
myDialog.show();
TextViewDrinkNameText;
DrinkNameText= (TextView) myDialog.findViewById(R.id.DrinkNameText);
DrinkNameText.setText(DrinkName);
TextViewDrinkTypeText;
DrinkTypeText= (TextView) myDialog.findViewById(R.id.DrinkNameTypeText);
DrinkTypeText.setText(DrinkType);
/**
TextView SetDrinkNameText = (TextView) findViewById(R.id.DrinkNameText);
SetDrinkNameText.setText(DrinkName);
TextView SetDrinkTypeText = (TextView) findViewById(R.id.DrinkNameTypeText);
SetDrinkTypeText.setText(DrinkType);
**/
LinearLayoutSetDrinkSizeSmall;
SetDrinkSizeSmall= (LinearLayout) myDialog.findViewById(R.id.SetDrinkSize_Small);
SetDrinkSizeSmall.setOnClickListener(newView.OnClickListener() {
//SETTING THE SIZE OF THE DRINK USING THE 3 BUTTONS IN THE POP UP! THIS IS ONE VALUE OF THE DRINK ORDER
@Override
publicvoidonClick(Viewv) {
DrinkSize=1;
DrinkSizeText="Small";
ToastSmall=Toast.makeText(getApplicationContext(),
"Drink Size Set To Small",
Toast.LENGTH_SHORT);
Small.show();
}
});
LinearLayoutSetDrinkSizeMedium;
SetDrinkSizeMedium= (LinearLayout) myDialog.findViewById(R.id.SetDrinkSize_Medium);
SetDrinkSizeMedium.setOnClickListener(newView.OnClickListener() {
@Override
publicvoidonClick(Viewv) {
DrinkSize=2;
DrinkSizeText="Medium";
ToastMedium=Toast.makeText(getApplicationContext(),
"Drink Size Set To Medium",
Toast.LENGTH_SHORT);
Medium.show();
}
});
LinearLayoutSetDrinkSizeLarge;
SetDrinkSizeLarge= (LinearLayout) myDialog.findViewById(R.id.SetDrinkSize_Large);
SetDrinkSizeLarge.setOnClickListener(newView.OnClickListener() {
@Override
publicvoidonClick(Viewv) {
DrinkSize=3;
DrinkSizeText="Large";
ToastLarge=Toast.makeText(getApplicationContext(),
"Drink Size Set To Large",
Toast.LENGTH_SHORT);
Large.show();
}
});
}
view rawtest.java hosted with ❤ by GitHub

here the code creates the DrinkID and order. It then sends this list of numbers to the arduino.

//FINAL ORDER BUTTON (POPUP, SENDS DRINK ARRAY TO ARDUINO)
//------------------------------------------------
publicvoid onClickOrder(View view) {
//The Functions bellow are converting intiger values into strings which can then be written to the arduino via a Serial Connection
StringVodkaOrder=Integer.toString(Vodka_Measure);
StringRumOrder=Integer.toString(Rum_Measure);
StringGinOrder=Integer.toString(Gin_Measure);
StringWhiskeyOrder=Integer.toString(Whiskey_Measure);
StringTonicWaterOrder=Integer.toString(TonicWater_Measure);
StringCranberryJuiceOrder=Integer.toString(CranberryJuice_Measure);
StringOrangeJuiceOrder=Integer.toString(OrangeJuice_Measure);
StringPineappleJuiceOrder=Integer.toString(Pineapple_Measure);
StringMintOrder=Integer.toString(Mint_Measure);
StringSugarOrder=Integer.toString(Sugar_Measure);
StringLimeJuiceOrder=Integer.toString(Lime_Measure);
StringLimeSliceOrder=Integer.toString(Lime_Slice);
StringStirOrder=Integer.toString(Stir);
StringMashOrder=Integer.toString(Mash);
StringShakeOrder=Integer.toString(Shake);
StringIceOrder=Integer.toString(Ice_Measure);
StringKaluaOrder=Integer.toString(Kalua);
StringCointreauOrder=Integer.toString(Cointreau);
StringVermouthOrder=Integer.toString(Vermouth);
StringPeachSchnappsOrder=Integer.toString(Peach_Schnapps);
StringCreamDeCacoOrder=Integer.toString(Cream_De_Cacao);
StringDrinkSizeOrder=Integer.toString(DrinkSize);
//Actually writing the data to the arduino using the new strings created above
serialPort.write(VodkaOrder.getBytes());
serialPort.write(RumOrder.getBytes());
serialPort.write(GinOrder.getBytes());
serialPort.write(WhiskeyOrder.getBytes());
serialPort.write(TonicWaterOrder.getBytes());
serialPort.write(CranberryJuiceOrder.getBytes());
serialPort.write(OrangeJuiceOrder.getBytes());
serialPort.write(PineappleJuiceOrder.getBytes());
serialPort.write(MintOrder.getBytes());
serialPort.write(SugarOrder.getBytes());
serialPort.write(LimeJuiceOrder.getBytes());
serialPort.write(LimeSliceOrder.getBytes());
serialPort.write(StirOrder.getBytes());
serialPort.write(MashOrder.getBytes());
serialPort.write(ShakeOrder.getBytes());
serialPort.write(IceOrder.getBytes());
serialPort.write(KaluaOrder.getBytes());
serialPort.write(CointreauOrder.getBytes());
serialPort.write(VermouthOrder.getBytes());
serialPort.write(PeachSchnappsOrder.getBytes());
serialPort.write(CreamDeCacoOrder.getBytes());
serialPort.write(DrinkSizeOrder.getBytes());
//A small text so the user knows what he/she ordered!
tvAppend(textView, "\nYour Drink Order is one "+DrinkSizeText+""+DrinkName+" ("+DrinkType+")"+"\n");
myDialog.dismiss(); //Closes the popup after the order button is pressed, and order data is sent
view raworder.java hosted with ❤ by GitHub

Step 11: Drink Images

For the majority of drink icons and the images used throughout the android application, the came from depositphotos.

The specific icon set i used can be found here: Drink Images For purchase, however i have also included the free versions below (with water marks) if you would like to use those instead. In the files i have included, the images has already been split up into a 3x3 grid to isolate each icon and renamed to make coding easier.

Step 12: Programming the Machine (Arduino)

As mentioned above, the arduino interprets the chain of numbers and assigns a variable to each digit. Based on these variables, the drink machine then constructs your drink through a series of steps as shown below.

The arduino file can be downloaded below:

Step 13: All the Files

Here are all the files in one place, for easy access so you don't have to scroll through the instructables:

Epilog X Contest

Runner Up in the
Epilog X Contest