Introduction: EAL - Instant Drink Cooler (IDC)

About: Dane studying Automation Engineering

This Instructable shows you how to build an instant drink cooling machine. The drink cooling machine works by pouring cold water over a spinning drink, either a can or a bottle. This method helps cool down the bottle material, while the fluid inside is mixed.

Step 1: Materials

In this project I have used:

  • One cordless drill motor, with the gearing and the speed controller
  • The battery of the cordless drill ( 12V )
  • A windshield washer pump
  • An Arduino Uno R3
  • One LCD display
  • A rotary encoder with clickbutton
  • One relay module
  • Various pieces of wire
  • M3 nuts and bolts
  • A USB power bank, for powering the Arduino, due to the onboard voltage regulator being underpowered for this purpose.

Furthermore, the cordless drill has an LED attached. This looks nice but is not necessary!

Step 2: Tank - Design and Assembly

The tank is made out of acrylic glass.

The design of the tank was done using a 3D sketch program, which provides a base for the whole building process. Making the sketch creates a design template on where to cut pieces of acrylic glass, and where to mount the different parts.

The tank itself is made out of 5 sheets of acrylic glass in various sizes, which are scored with a knife, and thereafter, broken along the score line. To glue the pieces together, acrylic glue is used. In this example, Acrifix 1R 0192 was used, which is hardened by UV light.

A step drill is a nice tool to work with in these sheet sizes, because it has several steps with different hole diameters.

Step 3: Machine Assembly

The machine is assembled with the rod attached to a bearing part on one end, and the motor on the other. The motor and gear is screwed directly onto the tank, and it is press fitted to the shaft.

The LCD, Arduino, and the rotary encoder are bolted to the front panel after being fitted in their respective slots.

The water hose from the pump is run along the back up to its bracket along with the LED from the cordless drill. A holder for the battery was printed, allowing for the battery poles to connect the right way. This was then attached with zip-ties.

Step 4: Arduino Code

#include <liquidcrystal.h>

LiquidCrystal lcd(13, 12, 11, 10, 9, 8);

//CLK signal
const int PinA = 3; 

//DT signal
const int PinB = 2;

//push button switch
const int PinSW = 4;

//Menu variables 
int menuselect = 0;
int submenu = 0;
int menuitems = 2;

//rotary value
int lastCount = 2;

//Runtime variables
unsigned long runtime = 0;
unsigned long timetorun = 60000;
unsigned long lasttimetorun = 60000;


// Updated by the ISR (Interrupt Service Routine)
volatile int virtualPosition = 1;
static unsigned long lastInterruptTime=0;

//Motor I/O
int Motors = 6;</p><p>void setup() {
  // Just whilst we debug, view output on serial monitor
  Serial.begin(9600);  

// Rotary pulses are INPUTs
  pinMode(PinA, INPUT);
  pinMode(PinB, INPUT);  

// Motors are OUTPUTs
  pinMode(Motors, OUTPUT);  

// Switch is floating so use the in-built PULLUP so we don't need a resistor
  pinMode(PinSW, INPUT_PULLUP);  

// Attach the routine to service the interrupts
  attachInterrupt(digitalPinToInterrupt(3), isr, LOW);  

// Ready to go!
// Print to LCD
  lcd.begin(16, 2);
  Serial.println("Start");
  lcd.setCursor(7, 0);
  lcd.print("IDC"); 

// Make sure Motors are off at startup
  digitalWrite(Motors,LOW);
}

void loop() {
  // Is someone pressing the rotary switch?
  // If yes, and submenu is 0, we select the desired item, and goes 1 deeper in its submenu.
  // If submenu is larger than 0, we go one back to the mainpage
  if ((!digitalRead(PinSW))) {
    if (submenu > 0) submenu --;
    else {
      menuselect = virtualPosition;
      submenu++;
    }
    while (!digitalRead(PinSW)) delay(10);
 //Print what happens in the Serial monitor... Debugging info only
    Serial.print("Select: ");
    Serial.println(menuselect);
    lastCount = 10;
  }

  // If the current rotary switch position has changed then update everything, and send info to the Serial monitor

  if (virtualPosition != lastCount || timetorun != lasttimetorun) {
    // Write out to serial monitor the value and direction
    Serial.print(virtualPosition > lastCount ? "Up  :" : "Down:");
    Serial.println(virtualPosition);

  //Two switch cases, Submenu and virtualposition. If submenu is 0, we are on the mainpage.
    //If submenu is 1 we are in a submenu to one of the main items.
    switch (submenu) {

     case 0:
	switch (virtualPosition) {
          case 1:
            lcd.setCursor(0, 1);
            lcd.print("                ");
            lcd.setCursor(0, 1);
            lcd.print("Start");
            break;
          case 2:
            lcd.setCursor(0, 1);
            lcd.print("                ");
            lcd.setCursor(0, 1);
            lcd.print("Run time");
            break;      
        }
        break;
     case 1:
        //Submenu for one of the main items.
        switch (menuselect) {
          //Menuselect is what the last virtual position was, therefore it shows the corresponding menu.
          case 1:
              //Print to screen, and start the cooling program.
            lcd.setCursor(0, 1);
            lcd.print("                ");
            lcd.setCursor(0, 1);
            lcd.print("Running...");
            virtualPosition = 1;
            CoolDrink();
            break;
          case 2:
              //Show the time for a run cycle in seconds, set with the rotary encoder
            lcd.setCursor(0, 1);
            lcd.print("                ");
            lcd.setCursor(0, 1);
            lcd.print(timetorun / 1000 );    //Print remaining seconds to the LCD
            lcd.print(" Seconds");
            break;
            
        }
    }
    // Set everything to the current value, so we can skip if nothing changes
    lastCount = virtualPosition ;
    lasttimetorun = timetorun;
  }

void isr ()  {
    //Rotary encoder interrupt loop
    unsigned long interruptTime = millis();
  // If interrupts comes faster than 10ms, assume it's a bounce and ignore
  if (interruptTime - lastInterruptTime > 10) {
    if (digitalRead(PinB) == LOW)
    {
      //Depending on the menu and submenu, change some values
      if (menuselect == 2 && submenu ==1)  timetorun=timetorun-1000;
      else                                      virtualPosition-- ;
    }
    else {
      //Depending on the menu and submenu, change some values
      if (menuselect == 2 && submenu ==1)  timetorun=timetorun+1000;
      else                                      virtualPosition++ ;
    }</p><p>    // Restrict menuvalue from 1 to 3
    if (virtualPosition > menuitems) virtualPosition = 1;
    if (virtualPosition < 1) virtualPosition = menuitems;    

// Keep track of when we were here last (no more than every 5ms)
     lastInterruptTime = interruptTime;
  }
}

void CoolDrink () {
//Register when we started the loop.
  runtime = millis();
  digitalWrite(Motors,HIGH);                              //Turn on the two motors

while (millis() < runtime + timetorun) {            // While the current time is less than the run timer
  lcd.setCursor(10, 1);
  lcd.print((timetorun + runtime - millis()) / 1000 );    //Print remaining seconds to the LCD
  lcd.print("     ");
    if ((!digitalRead(PinSW)) && millis() > runtime + 1000) {   //If the button is pressed after 1 second, cancel. 1 second to avoid fail clicks
    while (!digitalRead(PinSW)) delay(10);
      break;
    }
  }
  digitalWrite(Motors, LOW);                           //Turn off the two motors
  menuselect = 0;                                     // Reset all values set, so loop returns to menu.
  submenu = 0;                                        
  lastCount = 10;
  virtualPosition = 1;
  lcd.setCursor(0, 1);
  lcd.print("                ");
 loop();

}

Step 5: Schematics

Step 6: 3D Parts

Various parts of the machine have been printed by a 3D printer.

This includes the motor shaft that connects the motor to the rotary shaft, a shaft holder that acts as a bearing (a bearing would have been better), and a motor bracket that press fits onto the gearing, and attaches, with screws, onto the motor and tank.

If you want to check out the 3D parts, I have attached most of them here as STL files.

Step 7: Function

The drink cooler can cool cans and 0.5L plastic bottles. First, fill the tank with two litres of water. Next, plug in the batteries. The onboard screen starts at "Start", from here you can scroll either way to "Run time". If you press the encoder, you can choose the time for the machine to run. The standard runtime is 60 seconds. You can press the encoder again to return to the main menu. Here, you can scroll back to "Start", and press the encoder to begin the cooling process. The Arduino will then time the process, and print the remaining time onto the LCD screen. When it is done, the process stops and returns to the main menu. If you want the machine to stop while the process is running, simply press the encoder.