Thanks Everyone for the support. YOUR COMMENTS ARE WELCOME AND NEEDED!!!
All of this code can be found here: https://github.com/GettinDatFoShow/closetV1
All of this code can be found here: https://github.com/GettinDatFoShow/closetV1
_____________________HERE IS THE CODE_________________________
++++++++++++++++++++++++++++++++++++++++++++++++++
************** This is the C++ Arduino storageCode.ino **********************
//START CODE
//Author: Robert Morris
#include <Servo.h> //import arduino serial library
Servo table; // servo class table initialization
Servo door; // servo class door initialization
int detector; // analog detector variable
String order = ""; // command string variable setup
String inputString = ""; // a string builder for serial communication
boolean stringComplete = false; // boolean for bytes to string is completion
unsigned long previousMillis = 0; // long variable for timeout timer
unsigned long currentMillis = 0; // long variable for timeout timer
long interval = 14000; // total time before timeout during analog hand detection
void setup() { // setup for variables and system
Serial.begin(9600); //master/slave serial channel set
pinMode(A5, INPUT); //analog light reader pin set
pinMode(2, OUTPUT); //led for analog reader pin set
inputString.reserve(200); //reserver buffer size for serial string reader
door.attach(6);// door motor power attatchment
door.write(10); // setting door to close position on startup
//Serial.print("Running");
delay(1000);
door.detach();// door motor power detatchment
}
void loop() { // system main loop
serialEvent(); // checking buffer for serial info from master
if (stringComplete) { // boolean from serial buffer check function
stringComplete = false; // boolean reset
order = inputString; // string comparrison setter
// ---- BEGIN TABLE CONTROL ----
if(order == "turnL"){ //command turn table left
table.attach(9);// table motor power attactment
table.write(180);
delay(1100);
table.detach(); // table motor power detatchment
}
else if(order == "turnR"){ //command turn table right
table.attach(9);// table motor power attactment
table.write(0);
delay(1100);
table.detach();// table motor power detatchment
}
else if(order == "rotate"){//slow table rotate for calibration
table.attach(9); // table motor power attactment
while(stringComplete != true){ //stops with new serial string detected
table.write(89);
serialEvent(); // checking for serial string in buffer
}
table.detach();// table motor power detatchment
}
// ---- END TANBLE CONTROL ----
// ============================
// ---- BEGIN DOOR CONTROL ----
else if(order == "close"){ //command to close door
//Serial.println("close recieved");
door.attach(6); // door motor power attatchment
door.write(10);
delay(2000);
door.detach();// door motor power detatchment
}
else if(order == "open"){ // command to open door, free from detection
door.attach(6); // door motor power attatchment
//Serial.print("open recieved");
door.write(120);
delay(2000);
door.detach(); // door motor power detatchment
}
else if(order == "openwait"){ // command to open door, wait for hand detection or new string
digitalWrite(2, HIGH); // led light power for detector
door.attach(6); // door motor power attatchment
door.write(120);
delay(2000);
detector = analogRead(A5); // analog light reading
//Serial.println(detector);
previousMillis = millis(); // timer for timeout on hand detection
while(detector != 0){ // detectoin loop terminator
currentMillis = millis(); // timer update
detector = analogRead(A5); // detector update
detector -+ 20; // adjustment for over lighting
if(currentMillis - previousMillis > interval){ // timelapse comparrison
Serial.println("0"); // serial timeout notification
break; // timeout loop terminator
}
}
digitalWrite(2, LOW); // turn off light for detector
Serial.println("1"); // serial detection notification
door.detach(); // door motor power detatchment
}
// ---- END DOOR CONTROL ----
inputString = ""; // reset string builder to empty
order = ""; // reset command string to empty
}
}
void serialEvent() { // slave serial listener function, waiting for bytes
while (Serial.available()) { // if bytes in buffer
// get the new byte:
char inChar = (char)Serial.read(); // typecast bytes from ascii to char
// add it to the inputString:
// if the incoming character is a newline, set a flag
// so the main loop can do something about it:
if (inChar == '\n') { // if char new line char
stringComplete = true; // change boolean true
break; // break out of reader loop
}
inputString += inChar; // adding char to string builder variable
}
}
//END CODE
++++++++++++++++++++++++++++++++++++++++++++++++++
********************* This is the python guts.py file ****************************
#START CODE
#Author Robert Morris
__author__ = 'Robert Morris'
import serial
from PIL import Image, ImageTk
import time
import RPi.GPIO as gpio
import picamera
gpio.setwarnings(False)
gpio.cleanup()
gpio.setmode(gpio.BCM)
class InfoSender:
"""
creates master/slave serial communication object
:param: connection: slave device location on serial
:param: baud: default baud rate for communication with Arduino (Arduino must be same baud)
"""
def __init__(self, connection, baud):
self.connection = connection # updates com serial variable with location of slave device
self.baud = baud # updates default baud rate for serial byte transfer variable
self.serial = serial.Serial(self.connection, self.baud) # call to python serial module to create serial object
def sendInfo(self, info):
"""
function to allow the conversion and sending of information (string commands) in a python 3
formate over the serial connection to the Arduino.
:param: info: string
:return: None
"""
self.serial.write(bytes(info, 'utf-8')) # converts string to bytes in utf-8 format and sends over serial
class TrayImage():
"""
Tray Image Object, creates a stores an Image for tkinter buffer
"""
def __init__(self, location, name, imageType):
self.location = location # image location variable
self.imageType = "." + imageType # image time variable
self.name = name # image name variable
self.image = self.getImage(self.location, self.name, self.imageType) # call to function to update object with first image
def getImage(self, location, name, imageType):
"""
function to get or update an image from a file location
:return: tkinter image
"""
imageSize = 570, 500 # image size bounds
location = location + name + imageType # full image file name+pathway
load = Image.open(location) # read image into buffer
load.thumbnail(imageSize, Image.ANTIALIAS) # create tumbnail image for tkinter processing
image = ImageTk.PhotoImage(load) # create tkinter usable photo from thumbnail
return image # return tkinter image
def updateImage(self):
"""
funtion to mutate current object image with new image.
:reference: self.getImage()
:return: None
"""
self.image = self.getImage(self.location, self.name, self.imageType)
class LEDCounter:
"""
Seven Segment LED Dispaly Object
"""
def __init__(self, num):
top, ltop, rtop, mid, lbot, rbot, bot, single,= 21, 20, 16, 12, 6, 13, 26, 19 # gpio pin numbers
self.pinList = [top, ltop, rtop, mid, lbot, rbot, bot, single] #gpio pin list
self.setUpPins() # call to gpio pin setup function
self.one = [rtop, rbot] # pin list for LEDs that form the visual number 1
self.two = [top, rtop, mid, lbot, bot] # pin list for LEDs that form the visual number 2
self.three = [top, rtop, mid, rbot, bot] # pin list for LEDs that form the visual number 3
self.four = [ltop, rtop, mid, rbot] # pin list for LEDs that form the visual number 4
self.single = single # single dot on bottom of display (UNUSED)
self.current = self.updateLED(num) # call to display update function with integer param to update
def updateLED(self, num):
"""
function that updates the LED display to the number provided
:param: integer
:return: None
"""
self.displayOff() # call to function turn off any currently display number
if num == 1:
self.oneOn() # call to fucntion for Display of number 1
elif num == 2:
self.twoOn() # call to fucntion for Display of number 2
elif num == 3:
self.threeOn() # call to fucntion for Display of number 3
elif num == 4:
self.fourOn() # call to fucntion for Display of number
else:
self.singleOn() # call to fucntion for Display of single bottom led dot (if shown means error)
def setUpPins(self):
"""
function to setup up gpio led pins as output channels
:return: None
"""
for i in self.pinList:
gpio.setup(i, gpio.OUT) # setup each pin in list to output pin
def displayOff(self):
"""
function that gaurentees LED display is off
:return: None
"""
self.oneOff() # call to fucntion for one off
self.twoOff() # call to fucntion for two off
self.threeOff()# call to fucntion for three off
self.fourOff() # call to fucntion for four off
self.singleOff() # call to fucntion for single dot led off
def oneOn(self):
"""
function that turns on display LEDs in shape 1
:return: None
"""
for i in self.one:
gpio.output(i, True)
def twoOn(self):
"""
function that turns on display LEDs in shape 2
:return: None
"""
for i in self.two:
gpio.output(i, True)
def threeOn(self):
"""
function that turns on display LEDs in shape 3
:return: None
"""
for i in self.three:
gpio.output(i, True)
def fourOn(self):
"""
function that turns on display LEDs in shape 4
:return: None
"""
for i in self.four:
gpio.output(i, True)
def oneOff(self):
"""
function that turns OFF display LEDs
:return: None
"""
for i in self.one:
gpio.output(i, False)
def twoOff(self):
"""
function that turns OFF display LEDs
:return: None
"""
for i in self.two:
gpio.output(i, False)
def threeOff(self):
"""
function that turns OFF display LEDs
:return: None
"""
for i in self.three:
gpio.output(i, False)
def fourOff(self):
"""
function that turns OFF display LEDs
:return: None
"""
for i in self.four:
gpio.output(i, False)
def singleOn(self):
"""
function that turns ON display LED for bottom dot
:return: None
"""
gpio.output(self.single, True)
def singleOff(self):
"""
function that turns OFF display LED
:return: None
"""
gpio.output(self.single, False)
class TrayCam:
"""
System camera class
"""
def __init__(self):
self.cam = picamera.PiCamera() # initializes a Raspberry Pi camera from the Pi camera module
camL1, camL2 = 2, 3 # set up pin numbers for camera led lights for camera flash
self.camList = [camL1, camL2] # led list
self.setUpPins() # Call to gpio setup function
def captureImage(self, location, name, type):
"""
fucntion that captures and stores and image using the camera and the led flash
:param location: the directory in which to store the images
:param name: what to name to label the image file
:param type: the image file time (i.e. .jpeg)
:return: None
"""
self.camLightOn() #turn flash on
time.sleep(.25)
self.cam.capture(location+name+type) # call to camera image capture function
time.sleep(.25)
self.camLightOff() # flash off
def setUpPins(self):
"""
function that sets up the led pins for use as flash
:return: None
"""
for i in self.camList:
gpio.setup(i, gpio.OUT) # sets the led pin to output
def camLightOn(self):
"""
function that turns the LED lights to on.
:return: None
"""
for i in self.camList:
gpio.output(i, True) # sets the LED pin output to HIGH
def camLightOff(self):
"""
function that turns the LED lights to off.
:return: None
"""
for i in self.camList:
gpio.output(i, False) # sets the LED pin output to LOW
#END CODE
++++++++++++++++++++++++++++++++++++++++++++++++++
****************** This is the main python displayGUI.py file *******************
#START CODE
#Author: Robert Morris
__author__ = 'Robert Morris'
'''This file contains the tkinter code for the creation of the GUI
interface of the closetV1 storage system.'''
from tkinter import *
import time
from guts import * # import classes for the guts of the system
# GLOBAL Variables
LARGE_FONT = ("Verdana", 11, 'bold italic') # Bottom Button fonts
QUIT_FONT = ("Verdana", 11, 'bold italic') # quit button font
BB_COLOR = "#4682b4" #(70, 130, 180) # Bottom Button Colors = steel blue
TB_FG_COLOR = "#000000" # Tray Button fore ground color = black
TB_BG_COLOR = "#a0522d" #(160, 82, 45) # Tray Button back ground color = sienna
BOT_COLOR = TB_FG_COLOR # Bottom window Color = sienna
class Closet:
def __init__(self, master=None, start=False):
self.setUpVariables(start=start) # call to system variable setup function
self.frame = Frame(master) # initialize app frame
self.topWindow = Frame(master, bg=TB_BG_COLOR) # initialize inner top 2 tray buttons host frame with color
self.midWindow = Frame(master, bg=TB_BG_COLOR) # initialize inner bottom 2 tray buttons host frame with color
self.botWindow = Frame(master, bg=BOT_COLOR) # initialize bottom frame to hose user input buttons with color
self.createTrays() # call to tray button creation function
self.createButtons() # call to user input button creation function
self.topWindow.pack(expand=1, side='top', fill='both') # finalize top window
self.midWindow.pack(expand=1, fill='both' )# finalize middle window
self.botWindow.pack(side='bottom', fill='x') # finalize bottome window
self.frame.pack() # finalize app window
def setUpVariables(self, start=False):
"""
Function sets the system Atributes
:return: None
"""
self.sender = InfoSender('/dev/ttyACM0', 9600) # initialize serial class connection to arduino
self.cam = TrayCam() #initializes camera class
self.cam.camLightOff() # sets camera flash off
self.sender.sendInfo("close\n") # serial command to initialize the door to close on startup
self.start = start # variable for system startup tray picture loader commmand
self.imageArchive = "/home/pi/pyCode/closetV1/Images/" #location for picture storage
self.ledNumber = LEDCounter(1) #seven seg display class initialization
self.open = 0 # open/close boolean door variable
self.rotating = 0 # table rotating boolean variable
if self.start == True: # check for tray picture load apon startup
self.startUp()
self.AllImageUpdater()
else:
self.AllImageUpdater()
def createTrays(self):
"""
function sets up storage trays, creates tkinter buttons for trays and pictures and configures them
:return: None
"""
self.tray1 = Button(self.topWindow, text="Tray 1",
bg=TB_FG_COLOR, fg='white', command=self.buttonPress1)
self.tray2 = Button(self.topWindow, text="Tray 2",
bg=TB_FG_COLOR, fg='white', command=self.buttonPress2)
self.tray3 = Button(self.midWindow, text="Tray 3",
bg=TB_FG_COLOR, fg='white', command=self.buttonPress3)
self.tray4 = Button(self.midWindow, text="Tray 4",
bg=TB_FG_COLOR, fg='white', command=self.buttonPress4)
self.trayConfig() # calls pictures configure function
# place buttons inside master window
self.tray1.pack(side='left', expand=1, fill='both')
self.tray2.pack(side='right', expand=1, fill='both')
self.tray3.pack(side='left', expand=1, fill='both')
self.tray4.pack(side='right', expand=1, fill='both')
def createButtons(self):
"""
function sets up system/user control buttons for bottom window in gui and configures them
:return: None
"""
self.exitProgButton = quitButton(self.botWindow)
self.reload = Button(self.botWindow, text=" "*10+ "Reload" + " " *10 ,
bg=BB_COLOR, fg='black', font=LARGE_FONT, command=self.RELOADALL)
self.door = Button(self.botWindow, text=" "*8 + "Open/Close" + " "*8,
bg=BB_COLOR, fg='black', font=LARGE_FONT, command=self.OPENCLOSE)
self.turnl = Button(self.botWindow, text=" "*10+ "Turn L" + " "*10,
bg=BB_COLOR, fg='black', font=LARGE_FONT, command=self.TURNL)
self.turnr = Button(self.botWindow, text=" "*10 + "Turn R" + " "*10,
bg=BB_COLOR, fg='black', font=LARGE_FONT, command=self.TURNR)
self.table = Button(self.botWindow, text=" "*7+ "Adjust Table" + " "*7,
bg=BB_COLOR, fg='black', font=LARGE_FONT, command=self.CALIBRATE)
# place buttons inside master window
self.door.pack(padx=5, side='left', expand=1)
self.reload.pack(padx=5, side='left', expand=1)
self.turnr.pack(padx=5, side='left', expand=1)
self.table.pack(padx=5, side='right', expand=1)
self.turnl.pack(padx=5, side='right', expand=1)
self.tray3.pack(side='left', expand=1, fill='both')
self.tray4.pack(side='right', expand=1, fill='both')
def AllImageUpdater(self):
"""
class settor/mutator and image initialization function
:return: None
"""
self.tray_one_image = TrayImage(self.imageArchive, "tray1", "jpg")
self.tray_two_image = TrayImage(self.imageArchive, "tray2", "jpg")
self.tray_three_image = TrayImage(self.imageArchive, "tray3", "jpg")
self.tray_four_image = TrayImage(self.imageArchive, "tray4", "jpg")
def trayConfig(self):
"""
function that configures previously set up tray buttons with images
:return: None
"""
self.tray1.config(image=self.tray_one_image.image)
self.tray2.config(image=self.tray_two_image.image)
self.tray3.config(image=self.tray_three_image.image)
self.tray4.config(image=self.tray_four_image.image)
def CALIBRATE(self):
"""
function that sends commands via serial to the Arduino to
start or stop the table motor for adjument based on boolean rotate variable.
Event trigger based on user/Adjust Table button
:return: None
"""
if self.rotating == 0:
time.sleep(.5)
self.sender.sendInfo('rotate\n') # sends serial command to Arduino to start rotation
self.rotating = 1 # sets boolean variable to true
else:
time.sleep(.5)
self.sender.sendInfo('x\n') # sends random event serial command to Arduino to stop rotation
self.rotating = 0 # sets boolean variable to false
def RELOADALL(self):
"""
function that allows user to reset all of the tray button pictures with current pictures
upon event from user/reload button
:return: None
"""
self.startUp()
self.open = 0 # reset open variable to false
self.AllImageUpdater() #call to tray image update function
self.trayConfig()# call to tray button configure function
def OPENCLOSE(self):
"""
:return: None
function that sends commands via serial to the Arduino to
open or close door based on boolean open. Triggered based on event from user/door button
"""
if self.open == 0: # if door closed
time.sleep(.5)
self.sender.sendInfo('open\n') # open command string sent over serial to Arduino
self.open = 1 # boolean open variable set to true
else:
time.sleep(.5) # if door open
self.sender.sendInfo('close\n') # close command string sent over serial to Arduino
self.open = 0 # boolean close variable set to false
def TURNR(self):
"""
function send a command string over serial to Arduino to turn
table right one tray. Triggered by event from user/Turn R button
:return: None
"""
time.sleep(.5)
self.sender.sendInfo("turnR\n") # command string sent over serial to Ardunio
def TURNL(self):
"""
function send a command string over serial to Arduino to turn
table left one tray. Triggered by event from user/Turn L button
:return: None
"""
time.sleep(.5)
self.sender.sendInfo("turnL\n") # command string sent over serial to Ardunio
def startUp(self):
"""
fucntion that loads loads each tray with a new image.
:return: None
"""
trayList = [] # create a list for tray strings
for i in range(4): # for loop to populate list with 4 tray strings
trayList.append("tray"+str(i+1))
time.sleep(2)
self.sender.sendInfo("open\n") # command sent to Arduino over serial to open door
time.sleep(2)
for i in range(4): # loop through each tray to take a picture
self.ledNumber.updateLED(i+1) # updating the SSDisplay number for user
time.sleep(2)
self.cam.captureImage(location=self.imageArchive, name=trayList[i], type=".jpg") # capture/store image with type and name
time.sleep(.5)
if i != 3: # skip last turn on 4th tray
self.sender.sendInfo("turnL\n") # command sent to Arduino over serial to turn table one tray to left
self.ledNumber.updateLED(1) # reset SSDisplay to 1st tray
self.sender.sendInfo("close\n") # command sent to Arduino over serial to close door
time.sleep(2)
for i in range(3): # return the tray to the first tray
self.sender.sendInfo("turnR\n") # command sent to Arduino over serial to turn table one tray to right
time.sleep(1)
self.open = 0 # gaurentee boolean door variable is false
def buttonPress1(self):
"""
function that upon user/first tray 1 event, turns table to tray and opens door.
waits for user to take item out of tray or insert item
:return: None
"""
self.ledNumber.updateLED(1) # updates SSdipslay for user
self.sender.sendInfo("openwait\n") # command sent to Arduino over serial to open the door and wait for detection or timeout
#print("Tray1 Selected")
command = self.reciever(self.sender.serial) # call to master serial buffer to wait for and recieve command from Arduino
#print(command)
if command == '1': # if detection
time.sleep(1)
self.cam.captureImage(location=self.imageArchive, name="tray1", type=".jpg") # capture new picture
time.sleep(.5)
self.tray_one_image.updateImage() # update tray image with new image
self.tray1.config(image=self.tray_one_image.image) # configure tray button with new image
self.sender.sendInfo("close\n") # command sent to Arduino over serial to close door
self.open = 0 # gaurentee boolean door variable is false
def buttonPress2(self):
"""
function that upon user/first tray 2 event, turns table to tray and opens door.
waits for user to take item out of tray or insert item
:return: None
"""
self.ledNumber.updateLED(2) # updates SSdipslay for user
self.sender.sendInfo("turnL\n")
time.sleep(2)
print("Tray2 Selected")
self.sender.sendInfo("openwait\n") # command sent to Arduino over serial to open the door and wait for detection or timeout
command = self.reciever(self.sender.serial) # call to master serial buffer to wait for and recieve command from Arduino
#print(command)
if True or (command == '1' or command == "0"): # if detection
time.sleep(1)
self.cam.captureImage(location=self.imageArchive, name="tray2", type=".jpg") # capture new picture
time.sleep(.5)
self.tray_two_image.updateImage() # update tray image with new image
self.tray2.config(image=self.tray_two_image.image) # configure tray button with new image
self.sender.sendInfo("close\n") # command sent to Arduino over serial to close door
time.sleep(2)
self.sender.sendInfo("turnR\n")
self.open = 0 # gaurentee boolean door variable is false
def buttonPress3(self):
"""
function that upon user/first tray 3 event, turns table to tray and opens door.
waits for user to take item out of tray or insert item
:return: None
"""
self.ledNumber.updateLED(3) # updates SSdipslay for user
for i in range(2):
self.sender.sendInfo("turnL\n")
time.sleep(1.5)
print("Tray3 Selected")
self.sender.sendInfo("openwait\n") # command sent to Arduino over serial to open the door and wait for detection or timeout
command = self.reciever(self.sender.serial) # call to master serial buffer to wait for and recieve command from Arduino
#print(command)
if True or (command == '1' or command == '0'): # if detection
time.sleep(1)
self.cam.captureImage(location=self.imageArchive, name="tray3", type=".jpg") # capture new picture
time.sleep(.5)
self.tray_three_image.updateImage() # update tray image with new image
self.tray3.config(image=self.tray_three_image.image) # configure tray button with new image
self.sender.sendInfo("close\n") # command sent to Arduino over serial to close door
time.sleep(2)
for i in range(2):
self.sender.sendInfo("turnR\n")
time.sleep(1.5)
self.open = 0 # gaurentee boolean door variable is false
def buttonPress4(self):
"""
function that upon user/first tray 4 event, turns table to tray and opens door.
waits for user to take item out of tray or insert item
:return: None
"""
self.ledNumber.updateLED(4) # updates SSdipslay for user
self.sender.sendInfo("turnR\n")
time.sleep(2)
print("Tray4 Selected")
self.sender.sendInfo("openwait\n") # command sent to Arduino over serial to open the door and wait for detection or timeout
command = self.reciever(self.sender.serial) # call to master serial buffer to wait for and recieve command from Arduino
#print(command)
if True or (command == '0' or command == '0'): # if detection
time.sleep(2)
self.cam.captureImage(location=self.imageArchive, name="tray4", type=".jpg") # capture new picture
time.sleep(.5)
self.tray_four_image.updateImage() # update tray image with new image
self.tray4.config(image=self.tray_four_image.image) # configure tray button with new image
self.sender.sendInfo("close\n") # command sent to Arduino over serial to close door
time.sleep(2)
self.sender.sendInfo("turnL\n")
self.open = 0 # gaurentee boolean door variable is false
def reciever(self, port):
"""
function that listens to the serial for bytes of information from the Arduino,
then converts the information upon detection of new line character to string.
:param port: Arduino serial port for buffer listener
:return: string command from Arduino via serial
"""
while True:
info = port.readline().decode('utf-8') # read buffer until bytes are detected, then convert
#those bytes to a string utf-8 format until new line char detected
if info: # there is a string
#print("<<<<"+info+">>>>")
return info
class quitButton:
"""
Quit Button object, Terminates program upon even from user/Exit Program button
"""
def __init__(self, master):
self.quitButton = Button(master, text=" "*7+"Exit Program"+" "*7,
bg=BB_COLOR, fg='black', font=QUIT_FONT, command=quit)
self.quitButton.pack(padx=5, side='right', expand=1)
def main():
"""
main program function
:return: None
"""
window = Tk() # Tk Object intialization of main app frame
w, h = window.winfo_screenwidth(), window.winfo_screenheight() # get info on monitor display width and height
window.overrideredirect(1) # get rid top system window bar with minimize, maximize, and x button
window.geometry("%dx%d+0+0" % (w,h)) # set man window frame to info of width and height previously gathered
#window.title("Closet v.1") #set system window bar title
app = Closet(master=window, start=False) #initialize and create app/program object frame
window.mainloop() # run program main loop
main() #start program call
#END CODE