Teddy Hoisington
Published

Guest Counter

Ever wondered how many people were in your room? Ever wondered how many people have ever entered your room??? Look no further!!

BeginnerWork in progress1,336
Guest Counter

Things used in this project

Hardware components

Mikroe OLED C Click
×1
PocketBeagle
BeagleBoard.org PocketBeagle
×1
Ultrasonic Sensor - HC-SR04 (Generic)
Ultrasonic Sensor - HC-SR04 (Generic)
×2
Generic Push Button
×1
Jumper wires (generic)
Jumper wires (generic)
×1
Speaker, Mini
Speaker, Mini
×1

Story

Read more

Custom parts and enclosures

Enclosure Assembly

Front Part

Side Part

Top Part

Back Part

Bottom Part

Schematics

Fritzing Diagram

Code

guest_counter.py

Python
Main File, This file is run to start the device
"""
--------------------------------------------------------------------------
Guest Counter
--------------------------------------------------------------------------
License:   
Copyright 2019 Theodore Hoisington

Redistribution and use in source and binary forms, with or without 
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this 
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, 
this list of conditions and the following disclaimer in the documentation 
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors 
may be used to endorse or promote products derived from this software without 
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------

Uses Ultrasonic sensors to detect if a person has passed by the device.
When someone passes the device, a tone plays and the values on the OLED display
are updated to represent how many people are inside the room, have entered, and 
have exited.

"""
import display
import sonar
import time
import threading
import Adafruit_BBIO.PWM as PWM

#setup the speaker
piezo_pin = "P2_1"

#Piezo Note
NOTE_C5  = 523

def play_note(Note, Length):
    """
    Plays a given note for a given length.
    """
    PWM.start(piezo_pin, 50, Note)
    #time.sleep(Length)
    

    
    
#Creating Threads
#Thread for reading sensor values
readings = threading.Thread(name = 'reading',target = sonar.ultrasonic)
#Thread for checking if someone has passed through the device
exit = threading.Thread(name = 'exit',target = sonar.exit)
#Thread to initialize the screen and display the loading animation
screen_init = threading.Thread(name = 'init', target = display.init_file)
#Thread to play jingle

    
def main():
    #clear PWM
    PWM.stop(piezo_pin)
    PWM.cleanup()
    
    #initialize the screen and display the loading animation
    screen_init.start()
    #starts the ultrasonic readings
    readings.start()
    #sleeps the program for 10 seconds to allow the program to calculate the max distance/running average
    time.sleep(10)
    #Starts the function to check if someone is passed the sensors.
    exit.start()

    while(True):
        sonar.check_button()
        
        #If someone is in the sensors, the speaker will play tone
        if sonar.passed == False:
            play_note(NOTE_C5,.1)
        else:
            PWM.stop(piezo_pin)
            PWM.cleanup()
        pass
        
if __name__ == '__main__':
    main()

display.py

Python
Contains the functions used to control the display
"""
--------------------------------------------------------------------------
Display
--------------------------------------------------------------------------
License:   
Copyright 2019 Theodore Hoisington

Redistribution and use in source and binary forms, with or without 
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this 
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, 
this list of conditions and the following disclaimer in the documentation 
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors 
may be used to endorse or promote products derived from this software without 
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------

Uses the pillow library to create and save new images to send to the 
Mikroe OLED C Click board for display

"""
from PIL import Image, ImageDraw, ImageFont
import os
import time
import sonar


#Sets the screen to black initially
os.system("dd if=/dev/zero of=/dev/fb0 > /dev/null 2>&1")


local_num_inside = 0
local_total_entered = 0
local_total_exited = 0

num_inside_pos = (2, 25)
total_entered_pos = (2, 45)
total_exited_pos = (2, 65)

fontname = "arial.ttf"
txt = Image.new('RGB', (100,130), (255, 255, 255))
font = ImageFont.truetype(fontname, 17)
write = ImageDraw.Draw(txt)  

def new_PIL():
    """Resets txt which is the new image being written on"""
    global txt
    txt = Image.new('RGB', (100,130), (255, 255, 255))
    write = ImageDraw.Draw(txt)
    
def write_text(location, text):
    """Add string text to the image at the inputted location"""
    prefix = ""
    if location == num_inside_pos: 
        prefix = "Inside: "
    if location == total_entered_pos: 
        prefix = "Entered: "
    if location == total_exited_pos: 
        prefix = "Exited: "

    write = ImageDraw.Draw(txt)
    write.text(location, (prefix + text), font=font, fill = (0,0,0))
""" unused?
def write_other(location, text):
    """"""
    write.text(location, text, font=font, fill = (0,0,0))
   """ 
def setup_screen():
    """Creates initial image to be displayed on screen after loading"""
    write_text((2,0), "Guest Count")
    write_text(num_inside_pos, "0")
    write_text(total_entered_pos, "0")
    write_text(total_exited_pos, "0")


def load_screen(num):
    """Creates graphic for loading screen"""
    write_text((2,0), "Guest Count")
    write_text((2, 20*num), "LOADING")
    
def flip_image(image_path, saved_location):
    """
    Flip or mirror the image
 
    @param image_path: The path to the image to edit
    @param saved_location: Path to save the cropped image
    """
    image_obj = Image.open(image_path)
    rotated_image = image_obj.transpose(Image.FLIP_LEFT_RIGHT)
    rotated_image.save(saved_location)

def send_image():
    """Sends a completed image to the screen using terminal commands"""
    txt.save('img.png') 
    flip_image('img.png', 'flipped_img.jpg')
    os.system("sudo fbi -T 1 -a flipped_img.jpg")
    
def rewrite():
    """Update the counters"""
    write_text((2,0), "Guest Count")
    write_text(num_inside_pos, str(sonar.num_inside))
    write_text(total_entered_pos, str(sonar.total_entered))
    write_text(total_exited_pos, str(sonar.total_exited))
    
def update_image():
    """Checks if any of the numbers have changed, then rewrites and updates the image"""
    new_PIL()
    global local_num_inside
    global local_total_entered
    global local_total_exited
    new_image_bool = False
    if local_num_inside != sonar.num_inside:
        
        local_num_inside = int(sonar.num_inside)
        new_image_bool = True
    if local_total_entered != sonar.total_entered:
        
        local_total_entered = int(sonar.total_entered)
        new_image_bool = True
    if local_total_exited != sonar.total_exited:
     
        local_total_exited = int(sonar.total_exited)    
        new_image_bool = True
    if new_image_bool == True:
        rewrite()
        send_image()
        

def ready(): 
    """Screen following the Loading Screen"""
    new_PIL()
    #setup_screen()
    rewrite()
    send_image()
def init_file():
    """Initializes screens"""
    
    load_screen(1)
    send_image()
    time.sleep(3)
    load_screen(2)
    send_image()
    time.sleep(3)
    load_screen(3)
    send_image()
    time.sleep(3)
    load_screen(4)
    send_image()
    time.sleep(1)
    ready()
    

sonar.py

Python
Contains the functions used to run the Ultrasonic Sensors
"""
--------------------------------------------------------------------------
Sonar
--------------------------------------------------------------------------
License:   
Copyright 2019 Theodore Hoisington

Redistribution and use in source and binary forms, with or without 
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this 
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, 
this list of conditions and the following disclaimer in the documentation 
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors 
may be used to endorse or promote products derived from this software without 
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------

Uses the adafruit_hcsr04 library to measure distances with 
two HC-SR04 ultrasonic sensors

"""

import time
import board
from adafruit_hcsr04 import HCSR04
import Adafruit_BBIO.GPIO as GPIO
import display
import threading


BUTTON0 = "P2_3"

GPIO.setup(BUTTON0, GPIO.IN)


#HCSR04(trigger pin, echo pin)
sonar0 = HCSR04(board.P2_2, board.P2_4)
sonar1 = HCSR04(board.P2_6, board.P2_8)

# ------------------------------------------------------------------------
# Global variables
# ------------------------------------------------------------------------

left_sonar = 0
right_sonar = 0
passed = True
#Value that is the max distance for the device.
running_average = 0
distance_buffer = 10
reset_distance = 3

#Initializing display values
num_inside = 0
total_entered = 0
total_exited = 0


def check_button():
    """
    On button press it resets the values on display.
    """
    global num_inside
    global total_entered
    global total_exited
    
    if GPIO.input(BUTTON0) == 0:
        
        num_inside = 0
        total_entered = 0
        total_exited = 0
        display.update_image()
        return True
    return False
    
#------------------------

count = 1
value_list = []
def keep_average():
    """Gets average distance of first 20 sensor readings"""
    global count
    global value_list
    global running_average
    total = 0
    while count < 20:
        value_list.append(sonar0.distance)
        time.sleep(.1)
        
        count += 1
    for num in value_list:
        total += num    
    running_average = total / len(value_list)
    print(running_average)
    
def ultrasonic():
    """Constantly updates left_sonar and right_sonar with sensor vales"""
    global left_sonar
    global right_sonar
    global running_average
    
    keep_average()
    
    try:
        while True:
            try:
                
                left_sonar = int(sonar0.distance)
                print("0:", left_sonar)
                
                time.sleep(.1)
                right_sonar = int(sonar1.distance)
                print("1:", right_sonar)
                
                time.sleep(.1)
                sonar_algorithm(left_sonar,right_sonar)
            except RuntimeError:
                pass
    except KeyboardInterrupt:
        pass

def exit():
    global passed
    while(True):
    
    
        while left_sonar < (running_average - 10) or right_sonar < (running_average - 10):
            passed == False
        passed = True
        #jingle()
        #print("passed")
       
        display.update_image()

def sonar_algorithm(left,right):
    """Checks to see which direction a person is entering from"""
    global num_inside
    global total_entered
    global total_exited
    global passed
    
    #The exit thread is constantly updating the values for passed
    if left < running_average - 10 and passed == True:
        print("entered left")
        passed = False
        total_entered += 1
        num_inside += 1
    elif right < running_average - 10 and passed == True:
        print("entered right")    
        passed = False
        total_exited += 1
        num_inside += -1
        

run_guest_counter.sh

Python
Shell script used to start the device
#!/bin/bash
"""
--------------------------------------------------------------------------
Guest Counter Run Shell Script
--------------------------------------------------------------------------
License:   
Copyright 2019 Theodore Hoisington

Redistribution and use in source and binary forms, with or without 
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this 
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, 
this list of conditions and the following disclaimer in the documentation 
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors 
may be used to endorse or promote products derived from this software without 
specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------

Navigates to the proper directory, then runs the main.py script.

"""

cd /var/lib/cloud9/ENGI301/python/project_1
python3 guest_counter.py

Guest Counter Github

Credits

Teddy Hoisington

Teddy Hoisington

3 projects • 0 followers

Comments