Hackster is hosting Impact Spotlights: Industrial Automation. Watch the stream live on Thursday!Hackster is hosting Impact Spotlights: Industrial Automation. Stream on Thursday!
Erick MoralesErik Welsh
Published © GPL3+

PocketBeagle Bop It Project

Looking for yet another reason to waste time? Look no further than this homemade Bop It! This game is sure to provide fun for all ages.

IntermediateFull instructions provided204
PocketBeagle Bop It Project

Things used in this project

Hardware components

PocketBeagle
BeagleBoard.org PocketBeagle
×1
Adafruit 3.2" TFT LCD Breakout Board+
×1
Arcade Button
×1
Potentiometer
×1
Limit Switch
×1
Joystick
×1
Buzzer
Buzzer
×1
Resistor 1k ohm
Resistor 1k ohm
×4
Resistor 2.21k ohm
Resistor 2.21k ohm
×2
Jumper wires (generic)
Jumper wires (generic)
×1
Breadboard (generic)
Breadboard (generic)
×2

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Solder Wire, Lead Free
Solder Wire, Lead Free

Story

Read more

Schematics

Fritzing Diagram for Project

Fritzing File Developed with Components from this Project

Code

Main Project Code

Python
Here is the python code used that allows the game to work. Check out the python file in the github!
"""
--------------------------------------------------------------------------
Bop It Interactive Game
--------------------------------------------------------------------------
License:   
Copyright 2021 Erick Morales

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.
--------------------------------------------------------------------------

Use the following hardware components to make a homemade Bop It:
 - Arcade Button
 - Limit Switch
 - Joystick
 - Potentiometer
 - SPI Display
 - Buzzer
 
Requirements
    - Hardware: 
        - At beginning of game: display start screen on SPI Display, beep buzzer 3x
        - Button
            - Wait for button press to initialize game
        - Once game starts: SPI Display countdown "3,2,1, GO", Display First Level along
            with time given to receive response
        - During each level: Randomize input needed, record current values of selected
            input and current time, wait until input values change, record time when 
            input values change, compare time difference to time given to respond,
            when time given is less than time difference - do not advance to next level,
            when time given is greater than time difference - advance to next level
        - If input is in time, display green screen on SPI Display while buzzer beeps 1x 
            and then Next Level Screen with new adjusted time given. Add one point to 
            score.  
        - If input is delayed, display red screen on SPI Display while buzzer beeps 2x
            and then display last score. 
        - When last score is displayed: Display screen offering option to return to start
        - Ability to return to start and start game over again like new.
        - User Interaction
            - Needs to be able to start game by pressing button
            - Needs to be able to interact with all inputs
            
Uses:
    - spi_screen library developed by Erik Welsh
            

"""

import time
import busio
import board
import digitalio
import random

import Adafruit_BBIO.GPIO as GPIO
import Adafruit_BBIO.ADC as ADC
import Adafruit_BBIO.PWM as PWM

import spi_screen as SPI

# ------------------------------------------------------------------------
# Constants
# ------------------------------------------------------------------------

# None

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

# None

# ------------------------------------------------------------------------
# Functions / Classes
# ------------------------------------------------------------------------




class Project():
    """ Project """
    startupimage       = None
    clk_pin            = None
    miso_pin           = None
    mosi_pin           = None
    cs_pin             = None
    dc_pin             = None
    reset_pin          = None
    baudrate           = None
    rotation           = None
    display            = None
    button             = None
    limitswitch        = None
    potentiometer      = None
    joystickx          = None
    joysticky          = None
    buzzer             = None
    buttonimage        = None
    limitswitchimage   = None
    potentiometerimage = None
    joystickimage      = None
    
    
    def __init__(self, startupimage="intro.jpg", 
                        buttonimage="button.jpg", 
                        limitswitchimage="limitswitch.jpg", 
                        potentiometerimage="potentiometer.jpg",
                        joystickimage="joystick.jpg", 
                        clk_pin=board.SCLK, miso_pin=board.MISO, 
                        mosi_pin=board.MOSI,cs_pin=board.P1_6, 
                        dc_pin=board.P1_4, reset_pin=board.P1_2,
                        baudrate=24000000, rotation=90, button="P2_2", 
                        limitswitch="P2_4", potentiometer="P1_19", 
                        joystickx="P1_21", joysticky="P1_23", buzzer="P2_1"):
        
        """Initialize variables and set up display"""
        self.display = SPI.SPI_Display(clk_pin, miso_pin, mosi_pin, cs_pin, 
                                            dc_pin, reset_pin, baudrate, 
                                            rotation)
        self.button             = button
        self.limitswitch        = limitswitch
        self.potentiometer      = potentiometer
        self.joystickx          = joystickx
        self.joysticky          = joysticky
        self.buzzer             = buzzer
        self.startupimage       = startupimage
        self.buttonimage        = buttonimage
        self.limitswitchimage   = limitswitchimage
        self.potentiometerimage = potentiometerimage
        self.joystickimage      = joystickimage
        
        self._setup()
    
    # End def
    
    
    def _setup(self):
        """Setup the hardware components."""
        
        # Initialize Display
        self.display.image(self.startupimage)
        self.singlebuzzer()      
        self.singlebuzzer()
        self.singlebuzzer()
        # Initialize Button
        GPIO.setup(self.button, GPIO.IN)
        
        # Initialize Limit Switch
        GPIO.setup(self.limitswitch, GPIO.IN)
        
        # Initialize Analog Inputs Potentiometer and Joystick
        ADC.setup()
        
        time.sleep(0.1)
        
    # End def
    
    
    def singlebuzzer(self):
        """Code for Single Buzzer Noise."""
        PWM.start(self.buzzer, 20, 440)
        time.sleep(0.5)
        PWM.stop(self.buzzer)
        PWM.cleanup()
    # End def
    
    
    def goodbuzzer(self):
        """Code for whenever entry is successful."""
        PWM.start(self.buzzer, 20, 380)
        time.sleep(1)
        PWM.stop(self.buzzer)
        PWM.cleanup()
    # End def
        
        
    def badbuzzer(self):
        """Code for whenever entry is unsuccessful"""
        PWM.start(self.buzzer, 80, 600)
        time.sleep(0.5)
        PWM.stop(self.buzzer)
        PWM.start(self.buzzer, 80, 600)
        time.sleep(0.5)
        PWM.stop(self.buzzer)
        PWM.cleanup()   
    # End def
    
    
    def countdown(self):
        """Code for initial countdown at start of game."""
        self.display.text("3")
        self.singlebuzzer()
        self.display.text("2")
        self.singlebuzzer()
        self.display.text("1")
        self.singlebuzzer()
        self.display.text("GO")
        time.sleep(1)
    # End def
    
        
    def buttonlevel(self, TimetoScore):
        """Code for whenever button input is necessary."""
        self.display.image(self.buttonimage)
        TimeInitial = time.time()
        while (GPIO.input(self.button) == 1):
            time.sleep(0.1)
            
        TimeFinal = time.time()
        
        if (TimeFinal-TimeInitial) < TimetoScore:
            LevelUp = 1
        else:
            LevelUp = 0
            
        return LevelUp
    # End def
    
        
    def potentiometerlevel(self, TimetoScore):
        """Code for whenver potentiometer input is necessary."""
        self.display.image(self.potentiometerimage)
        TimeInitial = time.time()
        potentiometerstale = ADC.read_raw(self.potentiometer)
        potentiometercurrent = ADC.read_raw(self.potentiometer)
        potentiometerstale = int(potentiometerstale // 32)
        potentiometercurrent = int(potentiometercurrent // 32)
        while potentiometercurrent == potentiometerstale:
            potentiometercurrent = ADC.read_raw(self.potentiometer)
            potentiometercurrent = int(potentiometercurrent // 32)
            time.sleep(0.4)
            
        TimeFinal = time.time()
        
        if (TimeFinal-TimeInitial) < TimetoScore:
            LevelUp = 1
        else:
            LevelUp = 0
            
        return LevelUp
    #End def
    
        
    def joysticklevel(self, TimetoScore):
        """Code for whenever joystick input is necessary."""
        self.display.image(self.joystickimage)
        TimeInitial = time.time()
        joystickxstale = ADC.read_raw(self.joystickx)
        joystickystale = ADC.read_raw(self.joysticky)
        joystickxcurrent = ADC.read_raw(self.joystickx)
        joystickycurrent = ADC.read_raw(self.joysticky)
        while (joystickxcurrent - joystickxstale) < 30 and (joystickycurrent - joystickystale) < 30:
            joystickxcurrent = ADC.read_raw(self.joystickx)
            joystickycurrent = ADC.read_raw(self.joysticky)            
            time.sleep(0.1)
            
        TimeFinal = time.time()
        
        if (TimeFinal-TimeInitial) < TimetoScore:
            LevelUp = 1
        else:
            LevelUp = 0
            
        return LevelUp 
    # End def
        
    def limitswitchlevel(self, TimetoScore):
        """Code for whenever limit switch input is necessary."""
        self.display.image(self.limitswitchimage)
        TimeInitial = time.time()
        while (GPIO.input(self.limitswitch) == 1):
            time.sleep(0.1)
            
        TimeFinal = time.time()
        
        if (TimeFinal-TimeInitial) < TimetoScore:
            LevelUp = 1
        else:
            LevelUp = 0
            
        return LevelUp  
    # End def    
    
    
    def levelone(self):
        """Code for first level display"""
        self.display.text(["Level 1","Respond in:","","10","seconds"])
        time.sleep(2)
    # End def
    
        
    def leveldisplayupdate(self,CurrentLevel,TruncatedTimetoScore):
        """"Code for updating the display with next level information"""
        str1 = "Level "
        str2 = str(CurrentLevel)
        Line1 = str1 + str2
        
        self.display.text([Line1,"Respond in:","",TruncatedTimetoScore,"seconds"])
        time.sleep(1)
    # End def
    
    
    def run(self):
        """Execute the main program."""
        while(1):
        # Wait until button is pressed to start game
            while (GPIO.input(self.button) == 1):
                time.sleep(0.1)
        
            self.countdown()
            
            Score = 0
            TimetoScore = 10
            CurrentLevel = 1
            
            self.levelone()
            
            while(2):
                choice = random.randint(1,4)
                LevelUp = 0
                
                if choice == 1:
                    LevelUp = self.buttonlevel(TimetoScore)
                elif choice == 2:
                    LevelUp = self.potentiometerlevel(TimetoScore)
                elif choice == 3:
                    LevelUp = self.joysticklevel(TimetoScore)
                elif choice == 4:
                    LevelUp = self.limitswitchlevel(TimetoScore)
                    
                if LevelUp == 1:
                    self.display.fill((0,255,0))
                    self.goodbuzzer()
                    TimetoScore = 0.9*TimetoScore
                    Score = Score + 1
                    TimetoScoreString = str(TimetoScore)
                    TruncatedTimetoScore = TimetoScoreString[:4]
                    CurrentLevel = CurrentLevel + 1
                    
                    self.leveldisplayupdate(CurrentLevel,TruncatedTimetoScore)
                    self.display.blank()
                else:
                    self.display.fill((255,0,0))
                    self.badbuzzer()
                    time.sleep(1)
                    self.display.text(["Final Score: ", "" , str(Score)])
                    time.sleep(4)
                    break
                
            self.display.text(["Press button to return", "to start screen"])
                
            while (GPIO.input(self.button) == 1):
                time.sleep(0.1)
                
            self._setup()        
            
    # End def


    
    def cleanup(self):
        """Execute exit message for game end."""
        self.display.text(["Goodbye!", "Thanks for Playing :)"])    
    # End def
    
# End class    


# ------------------------------------------------------------------------
# Main script
# ------------------------------------------------------------------------

if __name__ == '__main__':
    
    print("Start")
    
    #Create instantation of the project
    project = Project()
    
    try:
        #run project
        project.run()
        
    except KeyboardInterrupt:
        #Display exit message
        project.cleanup()
        
    print("End of Game")
    
    

    

Run Script

Python
Here is the run script that allows the program to run in one command. This can also be used to set up an automatic boot
#!/bin/bash
# --------------------------------------------------------------------------
# Bop It Project Run Script
# --------------------------------------------------------------------------
# License:   
# Copyright 2021 
# 
# 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.
# --------------------------------------------------------------------------
# 
# Run Bop It Project in /var/lib/cloud9/ENGI301/project_01/mainproject/code
# 
# --------------------------------------------------------------------------
cd /var/lib/cloud9/ENGI301/project_01/mainproject/code
./configure_pins.sh
python3 project.py

Credits

Erick Morales
1 project • 0 followers
Contact
Erik Welsh
33 projects • 19 followers
Contact

Comments

Please log in or sign up to comment.