top of page

Week #18 - 05/28 - 06/04

  • Nicolo Agostini
  • Jun 3, 2024
  • 5 min read

Updated: Jun 17, 2024

Nick:


The week was spent working on the proximity sensor implementation to prevent the door to roll down if an obstruction is detected.

The proximity sensor shown below was chosen for its simplicity: the board itself takes care of the sensor's controls and provides a HIGH or LOW to the output pin accordingly.



First, I measured the range of the sensor using a random object and determined that 5in is the maximum distance at an object is detected consistently.


This short video shows the LED on the sensor's board turning on whenever an object is detected withing 5 inches.





The next step was measuring the distance between the location where the sensor would be installed and the center of the door.


Given the 5 inches range, the sensor should be able to detect if a dog is obstructing the door.



The sensor was powered from the 5V DC outputs of the RaspberryPi GPIO, and its data output was connected to the GPIO17 pin.


The following lines of code have been added at the beginning of the program to enable GPIO17 and set it as an input.

import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(17, GPIO.IN)

Finally, the code was adjusted to include the sensor's output in the rolldown() function.


In particular, the rolldown() function was changed from:


def rolldown():
	doormotor.backward()
	sleep(7)
	doormotor.stop()

to

def rolldown():
	i = 0
  	while i < 7:
   		i = i+1
		doormotor.backward()
    		sleep(1)
 		if not GPIO.input(17):
			doormotor.forward()
  			sleep(2)
  			i = i-2
	doormotor.stop()

The program executes the loop 7 times, each time checking for the presence of the dog obstructing the door. If the dog is detected, the motor rolls up for 2 seconds, and then tries to close again. This loop is repeated until no obstruction is detected.


At this point, this is the final code that was sent to Ryan for the scheduling feature implementation:


import cv2

from gpiozero import Motor

from time import sleep

from tkinter import *

from tkinter import Tk, font

import datetime

import time

import RPi.GPIO as GPIO

doormotor = Motor(24,23)

GPIO.setmode(GPIO.BCM)

GPIO.setup(17, GPIO.IN)


def rollup():

doormotor.forward()

sleep(7)

doormotor.stop()

def rolldown():

i = 0

while i < 7:

i = i+1

doormotor.backward()

sleep(1)

if not GPIO.input(17):

doormotor.forward()

sleep(2)

i = i-2

doormotor.stop()

def opensequence():

log_list.insert(END, datetime.datetime.now().strftime("%D - %H:%M:%S"))

rollup()

sleep(2)

rolldown()

cascade_path = '/home/nick/Desktop/haarcascade_frontalface_default.xml'

cascade_file = cv2.CascadeClassifier(cascade_path)

def dog_detection(img):

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

dog_face = cascade_file.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(50, 50))

return img, len(dog_face)

cam1 = cv2.VideoCapture(0)

cam1.set(cv2.CAP_PROP_FRAME_WIDTH, 640)

cam1.set(cv2.CAP_PROP_FRAME_HEIGHT, 360)

def scan():

ret1, frame1 = cam1.read()

frame1_with_dogs, num_dogs1 = dog_detection(frame1)

if num_dogs1 > 0:

opensequence()

main_window = Tk()

main_window.configure(background = "SkyBlue4")

main_window.geometry("800x600")

main_window.attributes("-fullscreen", False)

main_window.title("Smart Doggy Door")

main_window.option_add( "*font", "SegoeUI 24" )

status=str("Locked")

tw_start = Label(main_window, bg = 'yellow', text = 'Time Window Start: ')

tw_start.grid(row=0, column=0)

tw_end = Label(main_window, bg = 'yellow', text = 'Time Window End: ')

tw_end.grid(row=1, column=0)

tw_start_hour_slider = Scale(main_window, label = "HH", orient=HORIZONTAL, from_=0, to=23, background= 'SteelBlue3', font = ('SegoeUI', 20))

tw_start_hour_slider.grid(row=0, column=1, sticky=W, padx = 10, pady = 10)

tw_start_minute_slider = Scale(main_window, label = "MM", orient=HORIZONTAL, from_=0, to=59, background= 'SteelBlue3', font = ('SegoeUI', 20))

tw_start_minute_slider.grid(row=0, column=2, sticky=W, padx = 10, pady = 10)

tw_end_hour_slider = Scale(main_window, label = "HH", orient=HORIZONTAL, from_=0, to=23, background= 'SteelBlue3', font = ('SegoeUI', 20))

tw_end_hour_slider.grid(row=1, column=1, sticky=W, padx = 10, pady = 10)

tw_end_minute_slider = Scale(main_window, label = "MM", orient=HORIZONTAL, from_=0, to=59, background= 'SteelBlue3', font = ('SegoeUI', 20))

tw_end_minute_slider.grid(row=1, column=2, sticky=W, padx = 10, pady = 10)

manual_button = Button(main_window, text = "Manual Open", bg = "Navy" , fg = "White", command=opensequence, font = ('SegoeUI', 26))

manual_button.grid(row = 0, column = 3,padx = 10, pady = 10)

log_list = Listbox(main_window, fg = 'blue', bg = 'SeaShell3', width = 25, height = 6, borderwidth = 3, font = ('SegoeUI', 13))

log_list.grid(row = 4, column = 0, padx=10, pady=10)

history_label = Label(main_window, bg= 'LightCyan3', text = 'Access History', font = ('SegoeUI', 15))

history_label.grid(row = 3, column = 0, padx = 10, pady=10, sticky = W)

status_label = Label(main_window,bg = 'DodgerBlue', text = 'Current Status: ', font = ('SegoeUI', 18))

status_label.grid(row=5, column=0, padx = 10, pady=10, sticky = E)

current_status_label = Label(main_window, bg = 'Salmon', text = status, font = ('SegoeUI', 22))

current_status_label.grid(row=5, column=1, padx=10, pady=10, sticky = W)

current_time = Label(main_window, font = ('SegoeUI', 15))

current_time.grid(row=1, column=3, padx=10, pady=10)

def clock():

time = datetime.datetime.now().strftime("Current Time: %H:%M:%S")

current_time.config(text=time)

scan()

main_window.after(1000, clock)

clock()

mainloop()




Ryan: The task I was given this week was to continue work on the GUI and implement the sliders which would allow the user to set the time for which the door would be able to open.


The first step was write a function that would pull the set time from the sliders in the GUI and allow the user to create the window of operation as shown above.


Next, I added to the scan function that the open sequence should not run if the time window is not currently active.



The next addition to the code was to write a section to change the door status from locked to unlocked if the time window was currently active.



The code was tested using the same method as done previously. I went ahead and placed the camera in front of the image of the dog, and the open sequence ran as expected. A video showing the testing means can be found at the link below.



Code:

import cv2

from gpiozero import Motor

from time import sleep

from tkinter import *

from tkinter import Tk, font

import datetime


doormotor = Motor(24, 23)


def rollup():

doormotor.forward()

sleep(7)

doormotor.stop()


def rolldown():

doormotor.backward()

sleep(7)

doormotor.stop()


def opensequence():

log_list.insert(END, datetime.datetime.now().strftime("%D - %H:%M:%S"))

rollup()

sleep(2)

rolldown()


cascade_path = '/home/nick/Desktop/haarcascade_frontalface_default.xml'

cascade_file = cv2.CascadeClassifier(cascade_path)



def dog_detection(img):

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

dog_face = cascade_file.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(50, 50))

return img, len(dog_face)


cam1 = cv2.VideoCapture(0)

cam1.set(cv2.CAP_PROP_FRAME_WIDTH, 640)

cam1.set(cv2.CAP_PROP_FRAME_HEIGHT, 360)



def in_time_window(current_time):

start_time = datetime.time(tw_start_hour_slider.get(), tw_start_minute_slider.get())

end_time = datetime.time(tw_end_hour_slider.get(), tw_end_minute_slider.get())

return start_time <= current_time <= end_time


def scan():

ret1, frame1 = cam1.read()

frame1_with_dogs, num_dogs1 = dog_detection(frame1)


if num_dogs1 > 0 and in_time_window(datetime.datetime.now().time()):

opensequence()


main_window = Tk()

main_window.configure(background="SkyBlue4")

main_window.geometry("800x600")

main_window.attributes("-fullscreen", False)

main_window.title("Smart Doggy Door")

main_window.option_add("*font", "SegoeUI 24")


status = str("Locked")


tw_start = Label(main_window, bg='yellow', text='Time Window Start: ')

tw_start.grid(row=2, column=0)

tw_end = Label(main_window, bg='yellow', text='Time Window End: ')

tw_end.grid(row=3, column=0)


tw_start_hour_slider = Scale(main_window, label="HH", orient=HORIZONTAL, from_=0, to=23, background='SteelBlue3', font=('SegoeUI', 20))

tw_start_hour_slider.grid(row=2, column=1, sticky=W, padx=10, pady=10)

tw_start_minute_slider = Scale(main_window, label="MM", orient=HORIZONTAL, from_=0, to=59, background='SteelBlue3', font=('SegoeUI', 20))

tw_start_minute_slider.grid(row=2, column=2, sticky=W, padx=10, pady=10)


tw_end_hour_slider = Scale(main_window, label="HH", orient=HORIZONTAL, from_=0, to=23, background='SteelBlue3', font=('SegoeUI', 20))

tw_end_hour_slider.grid(row=3, column=1, sticky=W, padx=10, pady=10)

tw_end_minute_slider = Scale(main_window, label="MM", orient=HORIZONTAL, from_=0, to=59, background='SteelBlue3', font=('SegoeUI', 20))

tw_end_minute_slider.grid(row=3, column=2, sticky=W, padx=10, pady=10)


manual_button = Button(main_window, text="Manual Open", bg="Navy", fg="White", command=opensequence, font=('SegoeUI', 26))

manual_button.grid(row=4, column=0, padx=10, pady=10)


log_list = Listbox(main_window, fg='blue', bg='SeaShell3', width=25, height=6, borderwidth=3, font=('SegoeUI', 13))

log_list.grid(row=6, column=0, padx=10, pady=10)


history_label = Label(main_window, bg='LightCyan3', text='Access History', font=('SegoeUI', 15))

history_label.grid(row=5, column=0, padx=10, pady=10, sticky=W)


status_label = Label(main_window, bg='DodgerBlue', text='Current Status: ', font=('SegoeUI', 18))

status_label.grid(row=0, column=2, padx=10, pady=10, sticky=E)


current_status_label = Label(main_window, bg='Salmon', text=status, font=('SegoeUI', 18))

current_status_label.grid(row=0, column=3, padx=10, pady=10, sticky=W)


current_time = Label(main_window, font=('SegoeUI', 15))

current_time.grid(row=0, column=0, columnspan=2, padx=10, pady=10)


def clock():

time_str = datetime.datetime.now().strftime("Current Time: %H:%M:%S")

current_time.config(text=time_str)

if in_time_window(datetime.datetime.now().time()):

current_status_label.config(text="Unlocked")

else:

current_status_label.config(text="Locked")

scan()

main_window.after(1000, clock)


clock()

mainloop()

1596494170937.jfif

Nicolo is a 26-years-old student at Valencia College, pursuing a B.S. in Electrical and Computer Engineering Technology. Nicolo is currently an intern at a MEP engineering firm in Orlando, FL, working on a variety of projects including the local theme parks and rocket launch sites. When not in class, Nicolo enjoys working on DIY electrical projects, outdoors activities, and visiting the theme parks. 

image.png

Ryan is a 28-year-old Electrical and Computer Engineering Technology student at Valencia College. When not in class, he enjoys working on DIY projects, repairing cars, and cooking. Ryan recently began a Systems Engineering Internship at Walt Disney Imagineering for the Spring 2024 semester. After graduation, he hopes to continue his engineering career at Walt Disney Imagineering.

bottom of page