Automated Drink Dispenser With Light & Sound Feedback

by hwangjin in Circuits > Raspberry Pi

46 Views, 1 Favorites, 0 Comments

Automated Drink Dispenser With Light & Sound Feedback

IMG_0701.jpeg
5612A4DE-1F1B-4746-9635-41E19145C328_1_105_c.jpeg

This project is an automated drink dispenser built on a wheeled tank platform. It features 3 large cups and 1 water tank as liquid reservoirs, 4 mini submersible pumps that move liquid through silicone tubes into a cup, and NeoPixel LED strips for robot feedback output.

Press one of 5 buttons to choose your drink — the machine handles the rest. When dispensing is complete, the LEDs flash and a melody plays to let you know your drink is ready.

Available drinks:

  1. White Monster
  2. Apple Juice
  3. Caffeine Bomb (Monster + Coffee)
  4. Caffe Americano
  5. Mineral Water

Built on a Raspberry Pi Pico 2W running CircuitPython, with 4 pumps controlled via an L298N motor driver, NeoPixel strips for visual feedback, and an MP3 speaker for audio notification.

Supplies

  1. Raspberry Pi Pico 2W ×1 https://www.adafruit.com/product/6315
  2. L298N Motor Driver Board ×2 https://www.amazon.com/HiLetgo-Controller-Stepper-H-Bridge-Mega2560/dp/B07BK1QL5T
  3. Mini submersible aquarium pump (5V) ×4 https://www.amazon.com/ALAMSCN-Submersible-Aquariums-Fountain-Hydroponics/dp/B08PBQ1N1G
  4. NeoPixel LED Strip ×2 https://www.adafruit.com/product/2538
  5. Small buttons ×5 https://www.adafruit.com/product/1010
  6. Mono Enclosed Speaker - 3W 4Ohm ×2 https://www.adafruit.com/product/3351
  7. Food-safe silicone tubing 5mm ID ×1 https://www.amazon.com/Quickun-Silicone-Tubing-Flexible-Transfer/dp/B0852J5JQJ
  8. Dupont jumper wires

non-electronic parts

Any liquid container

Hot glue + zip ties

1/8th inch birch wood laser cut parts

3D printed movable wheel

Building the Structure

IMG_0625.jpeg
IMG_0626.jpeg

Design the Laser-cut enclosure

Design a hexagonal box using Boxes.py — it's free and generates ready-to-cut SVG files automatically. Add cutouts for 5 buttons, a USB-C cable hole, and a speaker grille pattern on one face before cutting.

3D Print the wheels that is going to be on the machine and paste it onto the hexagonal box using hot glue

Solder the Buttons

IMG_0655.jpeg

Solder pin-to-pin wires onto each of the 5 buttons. For each button — one end is connected to ground and one end is connected to signal. Once soldered, push each button through its hole on the button mounting plate from the inside and secure it using hot glue.

Wire the L298N Motor Driver

Screen Shot 2026-04-29 at 22.12.19.png
Screen Shot 2026-04-29 at 22.12.31.png

Connect two L298N boards to the Pico 2W and pumps as shown below.

Wire Buttons and NeoPixels

Screen Shot 2026-04-29 at 22.18.21.png
EF5ECB5C-52AD-4EA7-8EF9-6D314605EC54_1_105_c.jpeg

Upload the Code

import board, time, digitalio, neopixel, pwmio
from adafruit_led_animation.color import BLACK, RED, BLUE, GREEN, YELLOW

BLACK = (0, 0, 0)
RED = (180, 0, 0)
BLUE = (0, 80, 200)
GREEN = (0, 160, 30)
YELLOW = (200, 180, 0)
CAPYBARA = (180, 120, 40)

BUTTON_PINS = [board.GP0, board.GP1, board.GP2, board.GP3, board.GP4]
BUTTON_COLORS = [RED, BLUE, CAPYBARA, GREEN, YELLOW]
DRINK_NAMES = ["Monster", "Apple Juice", "Caffeine Bomb", "Americano", "Water"]

PUMP_PINS = [
(board.GP10, board.GP11),
(board.GP12, board.GP13),
(board.GP18, board.GP19),
(board.GP20, board.GP21),
]

RECIPES = [
(True, False, False, False),
(False, False, True, False),
(True, False, False, True),
(False, False, False, True),
(False, True, False, False),
]

DISPENSE_TIME = 10
NEO_TOP_PIN = board.GP16
NEO_BOT_PIN = board.GP17
NEO_TOP_COUNT = 30
NEO_BOT_COUNT = 30
SPEAKER_PIN = board.GP14

buttons = []
for pin in BUTTON_PINS:
b = digitalio.DigitalInOut(pin)
b.switch_to_input(pull=digitalio.Pull.UP)
buttons.append(b)

pumps = []
for (pin_a, pin_b) in PUMP_PINS:
a = digitalio.DigitalInOut(pin_a)
a.direction = digitalio.Direction.OUTPUT
a.value = False
b = digitalio.DigitalInOut(pin_b)
b.direction = digitalio.Direction.OUTPUT
b.value = False
pumps.append((a, b))

neo_top = neopixel.NeoPixel(NEO_TOP_PIN, NEO_TOP_COUNT, brightness=0.5, auto_write=False)
neo_bot = neopixel.NeoPixel(NEO_BOT_PIN, NEO_BOT_COUNT, brightness=0.5, auto_write=False)
neo_top.fill(BLACK); neo_top.show()
neo_bot.fill(BLACK); neo_bot.show()

speaker = pwmio.PWMOut(SPEAKER_PIN, frequency=440, duty_cycle=0, variable_frequency=True)

def all_pumps_off():
for (a, b) in pumps:
a.value = False; b.value = False

def start_pump(index):
pumps[index][0].value = True
pumps[index][1].value = False

def dispense(drink_index):
recipe = RECIPES[drink_index]
print(f"Dispensing: {DRINK_NAMES[drink_index]}")
for i, active in enumerate(recipe):
if active:
start_pump(i)
time.sleep(DISPENSE_TIME)
all_pumps_off()

def play_tone(freq, duration):
speaker.frequency = freq
speaker.duty_cycle = 2000
time.sleep(duration)
speaker.duty_cycle = 0
time.sleep(0.04)

def dim(color, factor=3):
return tuple(min(255, c // factor) for c in color)

def celebration(color):
melody = [(523,0.12),(659,0.12),(784,0.12),(1047,0.12),(784,0.08),(1047,0.35)]
for freq, dur in melody:
for j in range(NEO_BOT_COUNT):
neo_bot.fill(BLACK)
neo_bot[j] = color
neo_bot[(j+1) % NEO_BOT_COUNT] = dim(color, 2)
neo_bot.show()
time.sleep(dur / NEO_BOT_COUNT)
play_tone(freq, dur)
for _ in range(4):
neo_bot.fill(color); neo_bot.show(); time.sleep(0.15)
neo_bot.fill(BLACK); neo_bot.show(); time.sleep(0.1)

def read_button():
for i, b in enumerate(buttons):
if b.value == False:
return i
return None

all_pumps_off()
print("Robot Coffee Maker ready!")

while True:
pressed = read_button()
if pressed is not None:
color = BUTTON_COLORS[pressed]
time.sleep(0.3)
neo_top.fill(color); neo_top.show()
dispense(pressed)
celebration(color)
neo_top.fill(BLACK); neo_top.show()
neo_bot.fill(BLACK); neo_bot.show()
print("Ready for next drink!")
time.sleep(0.05)

Troubleshooting

Pump not spinning:

  1. Check L298N red LED is on (power OK)
  2. Check ENA and ENB jumpers are still on the L298N board
  3. Test with minimal code: set IN1=True, IN2=False for 5 seconds
  4. If spinning backwards, swap OUT1 and OUT2 wires on that pump

Water looks oily:

  1. New pumps have factory lubricant — flush with clean water 2-3 times before use
  2. If oiliness persists, label drinks as display only

Buttons not working:

  1. External buttons use Pull.UP — reads False when pressed
  2. Check SW (NO) → GPIO, SW (COM) → GND
  3. Run button test: print(button.value) in a loop

Speaker too loud:

  1. Lower duty_cycle value from 2000 to 500-1000