Every year Rice University celebrates Beer Bike. The event is full of spectators and fun, and is centered around a bike race. Beer Bike was the inspiration for this game where an LED races around a track as the user quickly presses the button, racing the timer.
Hardware
The game utilizes a PocketBeagle for the program processing, a shift register to control the LEDs, and the Adafruit 0.56" 4-Digit 7-Segment Display with I2C Backpack.
The shift register is soldered onto the back of the "race track" so the front is more aesthetically pleasing.
Shift Register
Fritzing Diagram
The Fritzing diagram for the device is shown in schematics.
Gameplay
Gameplay proceeds as follows:
1. User twists potentiometer to set the difficulty of the game. The more lights that are illuminated, the higher the difficulty setting.
2. The user presses the button to begin the game and the timer counts down from 3 seconds.
3. The user rapidly presses the button to lead the LED around the "track" while the timer is running.
4. Once the LED has made it all the way around the track, the final time is displayed.
"""--------------------------------------------------------------------------PocketBeagle LED Racing Beer Bike Game--------------------------------------------------------------------------License: Copyright 2017Redistribution 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.--------------------------------------------------------------------------"""# Peripheral pathGPIO_BASE_PATH="/sys/class/gpio"ADC_BASE_PATH="/sys/bus/iio/devices/iio:device0"# GPIO directionIN=TrueOUT=False# GPIO output stateLOW="0"HIGH="1"# LEDs GPIO valuesCLEAR=(1,27)# gpio59CLOCK=(1,26)# gpio58DATA=(0,26)# gpio26BUTTON0=(1,12)# gpio44# count variableCOUNT=0# HT16K33 valuesDISPLAY_I2C_BUS=1# I2C 1 DISPLAY_I2C_ADDR=0x70DISPLAY_CMD="i2cset -y 1 0x70"# ADC voltage rangemin_adc_voltage=0max_adc_voltage=1.65# ------------------------------------------------------------------------# Display Library# ------------------------------------------------------------------------importosimportAdafruit_BBIO.ADCasADCADC.setup()HEX_DIGITS=[0x3f,0x06,0x5b,0x4f,# 0, 1, 2, 30x66,0x6d,0x7d,0x07,# 4, 5, 6, 70x7f,0x6f,0x77,0x7c,# 8, 9, A, b0x39,0x5e,0x79,0x71]# C, d, E, FCLEAR_DIGIT=0x7FPOINT_VALUE=0x80DIGIT_ADDR=[0x00,0x02,0x06,0x08]COLON_ADDR=0x04HT16K33_BLINK_CMD=0x80HT16K33_BLINK_DISPLAYON=0x01HT16K33_BLINK_OFF=0x00HT16K33_BLINK_2HZ=0x02HT16K33_BLINK_1HZ=0x04HT16K33_BLINK_HALFHZ=0x06HT16K33_SYSTEM_SETUP=0x20HT16K33_OSCILLATOR=0x01HT16K33_BRIGHTNESS_CMD=0xE0HT16K33_BRIGHTNESS_HIGHEST=0x0FHT16K33_BRIGHTNESS_DARKEST=0x00defdisplay_setup():"""Setup display"""# i2cset -y 0 0x70 0x21os.system("{0} {1}".format(DISPLAY_CMD,(HT16K33_SYSTEM_SETUP|HT16K33_OSCILLATOR)))# i2cset -y 0 0x70 0x81os.system("{0} {1}".format(DISPLAY_CMD,(HT16K33_BLINK_CMD|HT16K33_BLINK_OFF|HT16K33_BLINK_DISPLAYON)))# i2cset -y 0 0x70 0xEFos.system("{0} {1}".format(DISPLAY_CMD,(HT16K33_BRIGHTNESS_CMD|HT16K33_BRIGHTNESS_HIGHEST)))# End defdefdisplay_clear():"""Clear the display to read '0000'"""# i2cset -y 0 0x70 0x00 0x3Fos.system("{0} {1} {2}".format(DISPLAY_CMD,DIGIT_ADDR[0],HEX_DIGITS[0]))# i2cset -y 0 0x70 0x02 0x3Fos.system("{0} {1} {2}".format(DISPLAY_CMD,DIGIT_ADDR[1],HEX_DIGITS[0]))# i2cset -y 0 0x70 0x06 0x3Fos.system("{0} {1} {2}".format(DISPLAY_CMD,DIGIT_ADDR[2],HEX_DIGITS[0]))# i2cset -y 0 0x70 0x08 0x3Fos.system("{0} {1} {2}".format(DISPLAY_CMD,DIGIT_ADDR[3],HEX_DIGITS[0]))os.system("{0} {1} {2}".format(DISPLAY_CMD,COLON_ADDR,0x0))# End defdefdisplay_set(data):"""Display the data."""foriinrange(0,3):display_set_digit(i,data[i])# End defdefdisplay_set_digit(digit_number,data,double_point=False):"""Update the given digit of the display."""os.system("{0} {1} {2}".format(DISPLAY_CMD,DIGIT_ADDR[digit_number],display_encode(data,double_point)))# End defdefdisplay_encode(data,double_point=False):"""Encode data to TM1637 format."""ret_val=0if(data!=CLEAR_DIGIT):ifdouble_point:ret_val=HEX_DIGITS[data]+POINT_VALUEelse:ret_val=HEX_DIGITS[data]returnret_val# End def# ------------------------------------------------------------------------# GPIO / ADC access library# ------------------------------------------------------------------------importosimporttimedefgpio_setup(gpio,direction,default_value=False):"""Setup GPIO pin * Test if GPIO exists; if not create it * Set direction * Set default value """gpio_number=str((gpio[0]*32)+gpio[1])path="{0}/gpio{1}".format(GPIO_BASE_PATH,gpio_number)ifnotos.path.exists(path):# "echo {gpio_number} > {GPIO_BASE_PATH}/export"print("Create GPIO: {0}".format(gpio_number))withopen("{0}/export".format(GPIO_BASE_PATH),'w')asf:f.write(gpio_number)ifdirection:# "echo in > {path}/direction"withopen("{0}/direction".format(path),'w')asf:f.write("in")else:# "echo out > {path}/direction"withopen("{0}/direction".format(path),'w')asf:f.write("out")ifdefault_value:# "echo {default_value} > {path}/value"withopen("{0}/value".format(path),'w')asf:f.write(default_value)# End defdefgpio_set(gpio,value):"""Set GPIO ouptut value."""gpio_number=str((gpio[0]*32)+gpio[1])path="{0}/gpio{1}".format(GPIO_BASE_PATH,gpio_number)# "echo {value} > {path}/value"withopen("{0}/value".format(path),'w')asf:f.write(value)# End defdefgpio_get(gpio):"""Get GPIO input value."""gpio_number=str((gpio[0]*32)+gpio[1])path="{0}/gpio{1}".format(GPIO_BASE_PATH,gpio_number)# "cat {path}/value"withopen("{0}/value".format(path),'r')asf:out=f.read()returnfloat(out)# End def# ------------------------------------------------------------------------# Setup# ------------------------------------------------------------------------gpio_setup(CLEAR,OUT)gpio_setup(DATA,OUT)gpio_setup(CLOCK,OUT)gpio_setup(BUTTON0,IN)display_setup()# ------------------------------------------------------------------------# setshift function# Set LED value script# Takes input of 8 bites (1 or 0)# and will shift that into register# ------------------------------------------------------------------------defsetshift(shift):gpio_set(CLEAR,LOW)gpio_set(DATA,LOW)gpio_set(CLEAR,HIGH)foriinshift:gpio_set(CLOCK,LOW)time.sleep(0.00001)ifi==0:gpio_set(DATA,LOW)else:gpio_set(DATA,HIGH)gpio_set(CLOCK,HIGH)time.sleep(0.0001)gpio_set(CLOCK,LOW)answer=gpio_get(BUTTON0)# End def# ------------------------------------------------------------------------# Set display to value# ------------------------------------------------------------------------defupdate_display(value):"""Update the value on the display."""# print("Score = {0}".format(value)) if(value==0):display_clear()else:if(value<10):display_set_digit(3,value)else:if(value<100):display_set_digit(3,(value%10))display_set_digit(2,(value/10))else:if(value<1000):display_set_digit(3,(value%10))display_set_digit(2,((value/10)%10))display_set_digit(1,(value/100),True)else:if(value<10000):display_set_digit(3,(value%10))display_set_digit(2,((value/10)%10))display_set_digit(1,((value/100)%10),True)display_set_digit(0,(value/1000))else:print("Value too big to display.")# End def# Reset displayupdate_display(0)# Set difficultyfromtimeimportsleepanalogPin="P9_33"print("Twist knob to select difficulty")potValcurrent=0difficulty=0whilegpio_get(BUTTON0)==0:time.sleep(.5)potVal=ADC.read(analogPin)ifpotVal>0.15andpotVal<.225anddifficulty!=1:difficulty=1setshift(map(int,str(10000000)))elifpotVal>0.225andpotVal<.3anddifficulty!=2:difficulty=2setshift(map(int,str(11000000)))elifpotVal>0.3andpotVal<.375anddifficulty!=3:difficulty=3setshift(map(int,str(11100000)))elifpotVal>0.375andpotVal<.43anddifficulty!=4:difficulty=4setshift(map(int,str(11110000)))elifpotVal>0.43andpotVal<.48anddifficulty!=5:difficulty=5setshift(map(int,str(11111000)))elifpotVal>0.48andpotVal<.52anddifficulty!=6:difficulty=6setshift(map(int,str(11111100)))elifpotVal>0.52andpotVal<.60anddifficulty!=7:difficulty=7setshift(map(int,str(11111110)))elifpotVal>0.60anddifficulty!=8:difficulty=8setshift(map(int,str(11111111)))else:passsetshift(map(int,str(00000000)))print("Difficulty = "+str(difficulty))# begin gameprint("Game beginning in")update_display(3)time.sleep(1)update_display(2)time.sleep(1)update_display(1)time.sleep(1)# initial LED onsetshift(map(int,str(00000000)))setshift(map(int,str(00000001)))# start timerstart=time.time()update_display(int(start-time.time()))# gameplayforiinrange(0,8*difficulty):whilegpio_get(BUTTON0)==0:update_display((int(100*round(time.time()-start,2))))COUNT+=1ifCOUNT==difficulty:#if COUNT == 5:update_display((int(100*round(time.time()-start,2))))gpio_set(CLOCK,LOW)time.sleep(0.00001)gpio_set(DATA,LOW)gpio_set(CLOCK,HIGH)time.sleep(0.0001)COUNT=0whilegpio_get(BUTTON0):passend=time.time()update_display((int(100*round(time.time()-start,2))))print(end-start)
Comments
Please log in or sign up to comment.