Evan Rust
Published © GPL3+

Raspberry Pi - Powered Candy Dispenser

Make a candy machine that can give candy with a push of a button or a tweet!

AdvancedFull instructions provided15 hours14,164
Raspberry Pi - Powered Candy Dispenser

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×1
Raspberry Pi Zero Wireless
Raspberry Pi Zero Wireless
×1
NEMA 17 Stepper Motor
OpenBuilds NEMA 17 Stepper Motor
×1
RGB LED common cathode
×1
Dual H-Bridge motor drivers L293D
Texas Instruments Dual H-Bridge motor drivers L293D
×1
20x4 Character LCD
×1
Pushbutton switch 12mm
SparkFun Pushbutton switch 12mm
×1
Single Turn Potentiometer- 10k ohms
Single Turn Potentiometer- 10k ohms
×1
Jumper wires (generic)
Jumper wires (generic)
×1
Perma-Proto Breadboard Half Size
Perma-Proto Breadboard Half Size
×1

Software apps and online services

Arduino IDE
Arduino IDE
Enthought Canopy (Python IDE)
Fusion 360
Autodesk Fusion 360

Hand tools and fabrication machines

CNC Router
3D Printer (generic)
3D Printer (generic)
Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Custom parts and enclosures

Rotating Candy Mover

Attach to stepper motor

Button

Slot into front plate

Schematics

Schematic

Code

Arduino Nano code

Arduino
#include <Stepper.h>

const int stepsPerRevolution = 200;

Stepper myStepper(stepsPerRevolution, 8, 9, 10, 11);

void setup() {
myStepper.setSpeed(30);
Serial.begin(115200);
}

void loop() {
  if(Serial.available()>0){
    char data = Serial.read();
    if (data == 'c'){
      Serial.println("Giving candy!");
      myStepper.step(50);
    }
  }

}

Raspberry Pi Code

Python
Copy and paste your Twitter app credentials
#import libraries
from twython import Twython
from time import sleep
import math
import time
import serial
import Adafruit_CharLCD as LCD
import RPi.GPIO as GPIO

#setup pin numbers
lcd_rs        = 27
lcd_en        = 22
lcd_d4        = 25
lcd_d5        = 24
lcd_d6        = 23
lcd_d7        = 18
lcd_backlight = 4

#LCD dimensions
lcd_columns = 20
lcd_rows    = 4

#make an LCD object with our pin variables
lcd = LCD.Adafruit_CharLCD(lcd_rs, lcd_en, lcd_d4, lcd_d5, lcd_d6, lcd_d7, 
                           lcd_columns, lcd_rows, lcd_backlight)
                           
#RGB LED pin numbers                         
redP = 16
greenP = 20
blueP = 21
buttonP = 5 #Tact switch pin number
ser = serial.Serial(port='/dev/ttyS0',baudrate=115200,timeout=1) #create a serial object for UART communication
pin_list = [redP,greenP,blueP] #put RGB LED pins in an array (simpler to control)
GPIO.setmode(GPIO.BCM) #BCM pin numbering for GPIO
GPIO.setwarnings(False) #Don't give a warning on startup about GPIO
for pin in pin_list: #Make every pin an output
    GPIO.setup(pin, GPIO.OUT)
    
GPIO.setup(buttonP, GPIO.IN, pull_up_down=GPIO.PUD_UP) #make button pin detect a FALLING edge (pull up resistor)

prev_message = "" #make a previous message variable to detect duplicate tweets

def reset_lcd(): #make a function that will clear the LCD
    lcd.clear()
    lcd.home()
    
#create out Twitter app variables
APP_KEY = "KEY"
APP_SECRET = "SECRET"
OAUTH_TOKEN = "TOKEN"
OAUTH_TOKEN_SECRET = "TOKEN_SECRET"

#make a twitter object with out variables
twitter = Twython(APP_KEY, APP_SECRET,
                  OAUTH_TOKEN, OAUTH_TOKEN_SECRET)

#turn off all LED colors
def all_off():
    for pin in pin_list:
        GPIO.output(pin,GPIO.LOW)
        
all_off() #turn off the LED

def candy_dispense(channel): #This will send the command to the Arduino Nano to dispense candy
    reset_lcd()
    lcd.message("Dispensing candy\nBe sure to say\n'Trick-or-treat'!")
    ser.write('c')
    sleep(5)
    reset_lcd()

GPIO.add_event_detect(buttonP, GPIO.FALLING, callback=candy_dispense,bouncetime=300) #add an interrupt that will call candy_dispense

while 1: #infinite loop
    tweet = twitter.get_mentions_timeline()[0] #get the latest tweet in which you are mentioned
    
    reset_lcd() #clear the LCD
    
    print "Latest tweet: "+tweet['text']+"\n\n" #print latest wteet to console
    text_len = len(tweet['text']) #get the length of the tweet
    #make the text fit in a 20x4 space
    if text_len < 20:
        lcd.message(tweet['text'])
    elif text_len > 20 and text_len < 41:
        lcd.message(tweet['text'][0:20]+'\n'+tweet['text'][20:40])
    elif text_len > 20 and text_len < 61:
        lcd.message(tweet['text'][0:20]+'\n'+tweet['text'][20:40]+'\n'+tweet['text'][40:60])
    elif text_len > 20 and text_len < 81:
        lcd.message(tweet['text'][0:20]+'\n'+tweet['text'][20:40]+'\n'+tweet['text'][40:60] \
       + '\n'+ tweet['text'][60:80])                                                                                                

    if prev_message != tweet['text']:
        #check if "color" and which color were mentioned in tweet (will change           the LED color)
        if "color" in tweet['text'].lower():
            if "red" in tweet['text'].lower():
                all_off()
                GPIO.output(redP,GPIO.HIGH)
            elif "green" in tweet['text'].lower():
                all_off()
                GPIO.output(greenP,GPIO.HIGH)
            elif "blue" in tweet['text'].lower():
                all_off()
                GPIO.output(blueP,GPIO.HIGH)
            if "off" in tweet['text'].lower():
                all_off()
            
    #if the word "candy" appears in the tweet, give out candy
        if "candy" in tweet['text'].lower():
            reset_lcd()
            lcd.message("Dispensing candy\nBe sure to say\n'Trick-or-treat'!")
            ser.write('c')
            sleep(2)
            
            
    sleep(10) #pause for 10 seconds (You can only update the tweet every 20 seconds due to Twitter query limits)
    reset_lcd() #clear the LCD
    #say who it's from and when it will update again
    lcd.message("From user: \n@"+tweet['user']['screen_name']+"\n"+
                "This will update in\n20 seconds.")
    print "From user: \n@"+tweet['user']['screen_name']+"\nThis will update every 20 seconds\n--------------------------------------\n"
    sleep(10) #pause for 10 more seconds
    prev_message = tweet['text'] #make the previous message the current one (to check for a duplicate tweet)
    

Credits

Evan Rust

Evan Rust

120 projects • 1049 followers
IoT, web, and embedded systems enthusiast. Contact me for product reviews or custom project requests.

Comments