Sleep Mode zZ
Posts: 319
Joined: Sun Aug 19, 2012 5:56 am
Location: Finland

Re: Stopwatch

Mon Nov 04, 2013 3:37 pm

Wibbes wrote:hi bard
long time since i have being looking into this, i have started working back in windows to give it a bit more power for a 6 lane setup.
one the main problems for the pi is its speed, especially when trying to monitor 2 or more lanes it becomes very hard to time them accurately , think best i got to be reliable was around 0.25 of a second on 2 lanes maybe 0.2 if i trimmed it down a bit on the drawing cycles for the screen.

to be fair even in windows its hard to do real timings without dedicated external hardware to do the timing( arduino or over micro).
You probably could get more speed by changing how you draw and update the screen - if graphics is the bottleneck. Pygame is not very fast at drawing and updating the screen on the Pi. But the whole approach of having the timing (stopping of the timer) depend on the GUI loop seems to me flawed. With that approach you can't expect to get better timing resolution than the GUI's frame rate.

Maybe you could separate the timing loop from the display/control loop into a separate thread or process?

Another idea: While I don't know anything about how the GPIO works - but would it somehow be possible to use interrupts instead of reading the state periodically?

You code seems clean and simple and hope that some more experienced in Python and GPIO would take a look and show how to achieve a better timing resolution.

nigel.arnold
Posts: 1
Joined: Wed Dec 04, 2013 1:33 pm

Re: Stopwatch

Wed Dec 04, 2013 1:45 pm

Hi

This is something I'm also working towards - when I get some free time that is ;)

I've already built an HO slot table - please see http://www.slickslots.co.uk

In building this table I've drawn heavily from Gregory Braun's site - http://www.hoslotcarracing.com/

However, the current lap time and power control is via a clunky old laptop with a parallel printer port so I was always looking to convert the control element to an integral Raspberry Pi at some point.

Hopefully the links will help those in need of some more info on the basic slot car control electronics at least.

Cheers.

bard
Posts: 3
Joined: Sun Nov 03, 2013 2:10 pm
Location: France

Re: Stopwatch

Sun Dec 08, 2013 1:57 pm

Hi all,

After double-checking, I really think a Pi unit can easily track a few events per second (start the clock, record track times for a few lanes, ....).
I will investigate more wth Python and C# to find pieces of code or a friend that could do it for me (I haven't coded in decades and have to see if I can do it again in langages I would have to learn...).
Let's keep investigating and keep in touch.

@joan and @Sleep Mode zZ: totally agree with you guys

@nigel.arnold: the different electronic setups for lap timing (photocells, dead strip, webcams, Reed or Hall effect sensors,....) amount to the same for the prog: recording an event (line x, time) after seeing a pulse on a "port"

My approach would be as Sleep Mode zZ suggested:

- a process/thread for the display
- another process for the clock

When a car passes the line (thus generating an interrupt/pulse), recording of the time and the lane is sent to the "database" and the display process.
In this case, even if the display in a little slow, we are closer to getting accurate timing on all events stated before (timing sectors, jump starts,...)

I'm sure as soon as this project gets momentum, more coding experts will contribute.

Cheers.

Bard

benson1658
Posts: 1
Joined: Thu Oct 30, 2014 1:24 am

Re: Stopwatch

Thu Oct 30, 2014 1:31 am

Hi
I'm pretty New to coding and was given the task of making a time attack system for drift trike racing. I'm thinking of getting some pir motion sensors and rigging them up as start and finish lines on the course. This project seems to be suited although I don't require laptimes. Just a start and stop. How could I modify the code for 2 sets of gpio pins one to start. The other to stop the stopwatch? Any help would be fantastic

Marre
Posts: 6
Joined: Thu Dec 31, 2015 11:02 am

Re: Stopwatch

Thu Dec 31, 2015 11:22 am

Hi all,
I put a litte stop watch, race timer together using my Pi 2, IR-LEDs and Python. It's not pretty and I'm going to add some Pygame graphics later on (any help here highly appreciated), but it's working :)

It handles 2 lanes, best lap time for each track (please note you need to create the empty files using the files names in the code for this).

The electrical circuits are presented in attached pictures along with component lists.

I'm sure it can be improved and any suggestions are welcome.

Anyways you can see a presentation here with further instructions in the end: https://youtu.be/TH52RCSOLeo

Code: Select all

''' Race Timer
This timer uses
Best time is loaded into
False start and best laptime
Clean exit
Stop if cheat
Average speeds
Buzzer
''' 
from decimal import Decimal
import RPi.GPIO as GPIO
import time
import random
import pickle
GPIO.setmode(GPIO.BCM)

redlight = 17
greenlight = 27
buzzer = 22

#Pin for start lights & buzzer
GPIO.setup(redlight, GPIO.OUT)

GPIO.setup(greenlight, GPIO.OUT)

GPIO.setup(buzzer, GPIO.OUT)

#Pin for Racer 1
GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

#Pin for Racer 2
GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

#Declare variables  
L1_time = 0
L2_time = 0
best_Ferrari1 = pickle.load( open( "Ferrari.p", "rb" ) ) #Lane 1 save file
best_RedBull2 = pickle.load( open( "RedBull.p", "rb" ) ) #Lane 2 save file
L1_best_time = time.time()
L2_best_time = time.time()
L1_lap = -1    #1st pass of finish line starts the 1st lap
L2_lap = -1    #1st pass of finish line starts the 1st lap
Total_time = 0
Laps = 10       #Set No. of laps
falsestart = 1 #Default false start, set to false same time as green light is lit
cheat = False
course_length = 8.9 #This is the lenght of the track
avg_speed = 0
top_speed_1 = 0
top_speed_2 = 0

try:

    def my_racer1(channel):
        global L1_best_time
        global start_time
        global L1_lap
        global L1_time
        global cheat
        L1_lap += 1
        if (L1_lap == 0):
            if falsestart == 1:
                print ("Team Ferrari jumped the start!")
                cheat = True
            else:
                pass
        elif (L1_lap == 1):
            elap = time.time() - start_time
            L1_best_time = elap
            L1_time = time.time()
            print ("Racer 1 Lap: " + str(L1_lap) + " - " + time_converter(elap))
            
        else:
            elap = time.time() - L1_time
            if (elap < L1_best_time):
                L1_best_time = elap #Keeping the best lap time for this race
            L1_time = time.time()
            print ("Racer 1 Lap: " + str(L1_lap) + " - " + time_converter(elap))

            
    def my_racer2(channel):
        global L2_best_time
        global start_time
        global L2_lap
        global L2_time
        global cheat
        L2_lap += 1
        if (L2_lap == 0):
            if falsestart == 1:
                print ("Team RedBull jumped the start!")
                cheat = True
            else:
                pass
        elif (L2_lap == 1):
            elap = time.time() - start_time
            L2_best_time = elap
            L2_time = time.time()
            print ("Racer 2 Lap: " + str(L2_lap) + " - " + time_converter(elap))
            
        else:
            elap = time.time() - L2_time
            if (elap < L2_best_time):
                L2_best_time = elap #Bara hlla koll på bästa tiden this race
            L2_time = time.time()
            print ("Racer 2 Lap: " + str(L2_lap) + " - " + time_converter(elap))


    def time_converter(conv_time):
        minutes = int(conv_time/60)
        seconds = int(conv_time - minutes*60.0)
        hseconds = int((conv_time - minutes*60.0 - seconds)*100)
        return str('%02d:%02d:%02d' % (minutes, seconds, hseconds))
         
    #Start lights reset
    GPIO.output(redlight, 0)
    GPIO.output(greenlight, 0)
    GPIO.output(buzzer, 0)
    
    print ("Ferrari best laptime is: " + time_converter(best_Ferrari1))
    print ("RedBull best laptime is: " + time_converter(best_RedBull2))
    print ("Race is set to: " + str(Laps) + " laps.")
    
    input ("Press Enter when ready to race!\n>")  
    print ("Press CTRL+C to end race.") 

    #Racer 1 event
    time.sleep(0.1)
    GPIO.add_event_detect(23, GPIO.RISING, callback=my_racer1, bouncetime=2500)
      
    #Racer 2 event
    time.sleep(0.1)
    GPIO.add_event_detect(24, GPIO.RISING, callback=my_racer2, bouncetime=2500)  

    #Start light sequence
    time.sleep(1)
    for x in range(0, 3):
        GPIO.output(redlight, 1)
        GPIO.output(buzzer, 1)
        time.sleep(0.3)
        GPIO.output(redlight, 0)
        GPIO.output(buzzer, 0)
        time.sleep(1)
    time.sleep(random.uniform(1, 3))
    falsestart = 0
    GPIO.output(greenlight, 1)
    #Timing starts and ensures no false start
    start_time = time.time()

    GPIO.output(buzzer, 1)
    time.sleep(1)
    GPIO.output(buzzer, 0)

    while ((L1_lap < Laps) and (L2_lap < Laps) and cheat == False):
        continue

    print("\n") #Just to printout nicely

    if cheat == True:
        print("We have a cheater, race stops!")
        GPIO.output(greenlight, 0)
        for x in range(0, 5):
            GPIO.output(redlight, 1)
            GPIO.output(buzzer, 1)
            time.sleep(0.3)
            GPIO.output(redlight, 0)
            GPIO.output(buzzer, 0)
            time.sleep(0.3)
    else:        
        Total_time = time.time() - start_time

        if L1_lap > L2_lap:
            print ("Team Ferrari is the winner!\n")
            
        else:
            print ("Team RedBull is the winner!\n")

        avg_speed = Decimal((course_length * Laps) / float(Total_time) * 3.6)
        top_speed_1 = Decimal(course_length / float(L1_best_time) * 3.6)
        top_speed_2 = Decimal(course_length / float(L2_best_time) * 3.6)
        
        if (L1_lap < 1):
            print ("Team Ferrari did not complete 1 lap.\n")
        else:
            print ("Team Ferrari's best lap: " + time_converter(L1_best_time))
            print ("Team Ferrari's top avg. speed: " + str(round(top_speed_1, 2)) + " km/h\n")

        if (L2_lap < 1):
            print ("Team RedBull did not complete 1 lap.\n")
        else:
            print ("Team RedBull's best lap: " + time_converter(L2_best_time))
            print ("Team RedBull's top avg. speed: " + str(round(top_speed_2, 2)) + " km/h\n")

        print ("\nTotal time of race for winner: " + time_converter(Total_time))
        print ("Winner's avg. speed: " + str(round(avg_speed, 2)) + " km/h\n")

        if (L1_best_time < best_Ferrari1): #Check and save Ferrari lap record on lane 1
            print("We have a new Ferrari lap record on lane 1! " + time_converter(L1_best_time))
            pickle.dump(L1_best_time, open("Ferrari.p", "wb" ))
        else:
            print("No new lap record for Ferrari this race.")


        if (L2_best_time < best_RedBull2): #Check and save RedBull lap record on lane 2
            print("We have a new RedBull lap record on lane 2! " + time_converter(L2_best_time))
            pickle.dump(L2_best_time, open("RedBull.p", "wb" ))
        else:
            print("No new lap record for RedBull this race.")

        for x in range(0, 3):
            GPIO.output(redlight, 1)
            GPIO.output(buzzer, 1)
            time.sleep(0.3)
            GPIO.output(redlight, 0)
            GPIO.output(buzzer, 0)
            time.sleep(1)
                        
except KeyboardInterrupt:
    print("User controlled exit")

except:
    print ("Another exception")

finally:
    print("Cleaning up PINS")
    GPIO.cleanup()  #cleanup regardless of reason for exit.  
    

Attachments
Buzzer.png
Buzzer scematics
Buzzer.png (10 KiB) Viewed 2399 times
IR sensor.png
IR-sensor and components list
IR sensor.png (51.97 KiB) Viewed 2399 times

Marre
Posts: 6
Joined: Thu Dec 31, 2015 11:02 am

Re: Stopwatch

Mon Jan 18, 2016 9:29 pm

As promised, I've now managed to learn some basic Pygame and updated the Race timer accordingly.
You can also run another race without exiting the program. Fonts, images and sounds can be downloaded from enywhere.

A couple of lessons learned:
1. GPIO.cleanup() did not remove GPIO.add_event_detect, which was causing trouble with multiple firing of events at the same time during reruns of the timer.
2. Running python from IDLE3 over vnc client on my PC rendered no graphics. It was solved using gksu to start IDLE3. Another way was to start it using /usr/bin/python3.4 without gksu.

Here is the code for anyone interested. My kids slotcar track has become so much more fun with this :)
Good luck with your projects! I'm happy to help if anyone has questions related to this.

EDIT: I amended the code slightly to add sound in the end of race and not to reflect -1 lap in the beginning.
EDIT2: I've uploaded a video here: https://youtu.be/dPD9qsKATBE

Code: Select all

''' Race Timer using Pygame for graphics
Best lap times  is saved in files
False starts are handled as aborted races
Start and end signal with buzzer
Enables rerun of race
3.1 1st lap not -1
'''
from decimal import Decimal
import RPi.GPIO as GPIO
import time
import random
import pickle
import pygame

# Declare variables 
L1_time = 0
L2_time = 0
elap_f = 0
elap_r = 0
path = "/home/pi/Programming/Pygame/RaceTimer" # Set full path
best_Ferrari = pickle.load(open(path + "/SG/Ferrari.p", "rb")) # Lane 1 save file
best_RedBull = pickle.load(open(path + "/SG/RedBull.p", "rb")) # Lane 2 save file
L1_best_time = 10
L2_best_time = 10
L1_lap = -1    # 1st pass of finish line starts the 1st lap
L2_lap = -1    # 1st pass of finish line starts the 1st lap
Total_time = 0
Laps = 5       # Set No. of laps
Laps_Ferrari = 0 #Used to print laps
Laps_RedBull = 0 #Used to print laps
falsestart = True # Default false start, set to false same time as green light is lit
cheat = False
Ferrari_cheat = False
RedBull_cheat = False
course_length = 8.9 # This is the lenght of the track
avg_speed = 0
top_speed_1 = 0
top_speed_2 = 0


# Startlight & buzzers GPIO PIN numbers
redlight = 17
greenlight = 27
buzzer = 22

# Define some colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255,40,0)
DARKBLUE = (0,0,128)

# Define separator line thickness (lh) and relative position separator (th)
lh = 15
th = 70
 
# Call this function so the Pygame library can initialize itself
pygame.init()
pygame.font.init()

# Create an 1600x900 sized screen, good to to use fullscreen when testing code.
screen = pygame.display.set_mode((1600, 900), pygame.FULLSCREEN)
#screen = pygame.display.set_mode((1600, 900))


# This sets the name of the window
pygame.display.set_caption("Race Timer")
 
# Add refresh rate ability
clock = pygame.time.Clock()
 
# Before the loop, load the sounds:
pygame.mixer.init()
pygame.mixer.music.set_volume(1.0)
click_sound = pygame.mixer.Sound(path + "/F1-new3.ogg")

 
# Set positions of graphics
dI = pygame.display.Info()
background_position_ferrari = [lh, lh]
background_position_redbull = [lh, dI.current_h/2 + lh*2]

# Create background and copy images to screen:
rectFerrari = pygame.Rect(0,0,dI.current_w,dI.current_h/2)
rectLine = pygame.Rect(0,dI.current_h/2,dI.current_w,lh)
rectRedbull = pygame.Rect(0,dI.current_h/2 + lh,dI.current_w,dI.current_h/2 - lh)

# Font for text in GUI
myFont = pygame.font.Font(path + "/Fonts/DS-DIGI.TTF", 75)
myFont2 = pygame.font.Font(path + "/Fonts/DS-DIGI.TTF", 45)

# Create labels variables
BT = myFont.render("Best Lap", 1, WHITE)
LT = myFont.render("Last Lap ", 1, WHITE)
RT = myFont.render("Record", 1, WHITE)
Lap_No = myFont.render("Lap No:", 1, WHITE)

# Load and set up graphics.
ferrari_image = pygame.image.load(path + "/Pics/ferrari.jpg").convert()
redbull_image = pygame.image.load(path + "/Pics/redbull.jpg").convert()
ferrari_image = pygame.transform.scale(ferrari_image, (341, 148))
redbull_image = pygame.transform.scale(redbull_image, (341, 148))

def time_converter(conv_time):
    minutes = int(conv_time/60)
    seconds = int(conv_time - minutes*60.0)
    hseconds = int((conv_time - minutes*60.0 - seconds)*100)
    return str('%02d:%02d:%02d' % (minutes, seconds, hseconds))

def wait():
    while True:
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN and event.key == pygame.K_RETURN:
                return

def raceAgain():
    global reRun
    global cheat
    global Ferrari_cheat
    global RedBull_cheat
    while True:
        for event in pygame.event.get():
            if event.type == pygame.KEYDOWN and event.key == pygame.K_y:
                return
            if event.type == pygame.KEYDOWN and event.key == pygame.K_n:
                reRun = False
                return

def my_racer1(channel):
    global L1_best_time
    global start_time
    global L1_lap
    global L1_time
    global Laps_Ferrari
    global cheat
    global elap_f
    global Ferrari_cheat
    L1_lap += 1
    if (L1_lap == 0):
        if falsestart:
            Ferrari_cheat = True
            cheat = True
        else:
            pass
    elif (L1_lap == 1):
        Laps_Ferrari = L1_lap
        elap_f = time.time() - start_time
        if (elap_f < L1_best_time):
            L1_best_time = elap_f # Keeping the best lap time for this race
        L1_time = time.time()
    else:
        Laps_Ferrari = L1_lap
        elap_f = time.time() - L1_time
        if (elap_f < L1_best_time):
            L1_best_time = elap_f # Keeping the best lap time for this race
        L1_time = time.time()

def my_racer2(channel):
    global L2_best_time
    global start_time
    global L2_lap
    global L2_time
    global Laps_RedBull
    global cheat
    global elap_r
    global RedBull_cheat
    L2_lap += 1
    if (L2_lap == 0):
        if falsestart:
            RedBull_cheat = True
            cheat = True            
        else:
            pass
    elif (L2_lap == 1):
        Laps_RedBull = L2_lap
        elap_r = time.time() - start_time
        if (elap_r < L2_best_time):
            L2_best_time = elap_r # Keeping the best lap time for this race
        L2_time = time.time()
    else:
        Laps_RedBull = L2_lap
        elap_r = time.time() - L2_time
        if (elap_r < L2_best_time):
            L2_best_time = elap_r # Keeping the best lap time for this race
        L2_time = time.time()

def drawResults():
    #Update times & Laps
    L1_best_time_text = myFont.render(time_converter(L1_best_time), 1, DARKBLUE)
    L1_time_text = myFont.render(time_converter(elap_f), 1, DARKBLUE)
    L1_lap_text = myFont.render(str(Laps_Ferrari), 1, DARKBLUE)

    L2_best_time_text = myFont.render(time_converter(L2_best_time), 1, RED)
    L2_time_text = myFont.render(time_converter(elap_r), 1, RED)
    L2_lap_text = myFont.render(str(Laps_RedBull), 1, RED)
        
    # Draw background and copy images to screen:
    screen.fill(RED, rectFerrari)
    screen.fill(BLACK, rectLine)
    screen.fill(DARKBLUE, rectRedbull)
    screen.blit(ferrari_image, background_position_ferrari)
    screen.blit(redbull_image, background_position_redbull)
        
    # Print Ferrari labels + time
    screen.blit(LT,                 (dI.current_w/3 + lh    , lh))
    screen.blit(BT,                 (2*dI.current_w/3 + lh  , lh))
    screen.blit(RT,                 (lh                     , dI.current_h/5 + lh))
    screen.blit(Lap_No,             (dI.current_w/3 + lh    , dI.current_h/5 + lh))
        
    screen.blit(L1_time_text,       (dI.current_w/3 + lh    , lh + th))
    screen.blit(L1_best_time_text,  (2*dI.current_w/3 + lh  , lh + th))
    screen.blit(RT_Ferrari,         (lh                     , dI.current_h/5 + lh + th))
    screen.blit(L1_lap_text,        (dI.current_w/2 - lh    , dI.current_h/5 + lh))

    # Print RedBull labels + time
    screen.blit(LT,                 (dI.current_w/3 + lh    , dI.current_h/2 + lh))
    screen.blit(BT,                 (2*dI.current_w/3 + lh  , dI.current_h/2 + lh))
    screen.blit(RT,                 (lh                     , dI.current_h/2 + dI.current_h/4))
    screen.blit(Lap_No,             (dI.current_w/3 + lh    , dI.current_h/2 + dI.current_h/4))

    screen.blit(L2_time_text,       (dI.current_w/3 + lh    , dI.current_h/2 + lh + th))
    screen.blit(L2_best_time_text,  (2*dI.current_w/3 + lh  , dI.current_h/2 + lh + th))
    screen.blit(RT_RedBull,         (lh                     , dI.current_h/2 + dI.current_h/4 + th))
    screen.blit(L2_lap_text,        (dI.current_w/2 - lh    , dI.current_h/2 + dI.current_h/4))

    pygame.display.flip()


reRun = True

# Check to race again    
while reRun:

    # Initialize GPIO PINS
    GPIO.setmode(GPIO.BCM)
    
    GPIO.setup(redlight, GPIO.OUT)

    GPIO.setup(greenlight, GPIO.OUT)

    GPIO.setup(buzzer, GPIO.OUT)

    # GPIO PIN for Lane 1 sensor Team Ferrari
    GPIO.setup(23, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

    # GPIO PIN for Lane 2 sensor Team RedBull
    GPIO.setup(24, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

    #Racer 1 event
    time.sleep(0.1)
    GPIO.add_event_detect(23, GPIO.RISING, callback=my_racer1, bouncetime=2500)
                     
    #Racer 2 event
    time.sleep(0.1)
    GPIO.add_event_detect(24, GPIO.RISING, callback=my_racer2, bouncetime=2500) 

    # Reset variables for reRun 
    L1_time = 0
    L2_time = 0
    elap_f = 0
    elap_r = 0
    best_Ferrari = pickle.load(open(path + "/SG/Ferrari.p", "rb")) # Lane 1 save file   
    best_RedBull = pickle.load(open(path + "/SG/RedBull.p", "rb")) # Lane 2 save file
    L1_best_time = 10
    L2_best_time = 10
    L1_lap = -1    # 1st pass of finish line starts the 1st lap
    L2_lap = -1    # 1st pass of finish line starts the 1st lap
    Laps_Ferrari = 0 #Used to print laps
    Laps_RedBull = 0 #Used to print laps
    Total_time = 0
    falsestart = True # Default false start, set to false same time as green light is lit
    cheat = False
    Ferrari_cheat = False
    RedBull_cheat = False
    #course_length = 8.9 # This is the lenght of the track
    avg_speed = 0
    top_speed_1 = 0
    top_speed_2 = 0

    screen.fill(RED, rectFerrari)
    screen.fill(BLACK, rectLine)
    screen.fill(DARKBLUE, rectRedbull)
    screen.blit(ferrari_image, background_position_ferrari)
    screen.blit(redbull_image, background_position_redbull)

    #Define Record times & start message
    RT_Ferrari = myFont.render(time_converter(best_Ferrari), 1, DARKBLUE)
    RT_RedBull = myFont.render(time_converter(best_RedBull), 1, RED)
    Intro_text = myFont.render("Press Enter when ready to race!", 1, DARKBLUE)
    Exit_text = myFont.render("Press q to quit race.", 1, WHITE)
    Laps_text = myFont.render("Race is set to: " + str(Laps) + " laps.", 1, DARKBLUE)

    # Print Ferrari labels + record time
    screen.blit(LT, (dI.current_w/3 + lh            , lh))
    screen.blit(BT, (2*dI.current_w/3 + lh          , lh))
    screen.blit(RT, (lh                             , dI.current_h/5 + lh))
    screen.blit(RT_Ferrari, (lh                     , dI.current_h/5 + lh + th))

    # Print RedBull labels + record time
    screen.blit(LT, (dI.current_w/3 + lh            , dI.current_h/2 + lh))
    screen.blit(BT, (2*dI.current_w/3 + lh          , dI.current_h/2 + lh))
    screen.blit(RT, (lh                             , dI.current_h/2 + dI.current_h/4))
    screen.blit(RT_RedBull, (lh                     , dI.current_h/2 + dI.current_h/4 + th))

    # Print start message
    screen.blit(Intro_text, (dI.current_w/4         , lh + 2*th))
    screen.blit(Exit_text, (dI.current_w/3          , lh + 3*th))
    screen.blit(Laps_text, (dI.current_w/3 - lh     , lh + 4*th))

    # Update screen
    pygame.display.flip()

    # Play intro sound
    click_sound.play()
    pygame.mixer.fadeout(6000)
    
    # Waits for user to press Enter
    wait()
    pygame.mixer.quit()

    try:
        #Start lights reset
        GPIO.output(redlight, 0)
        GPIO.output(greenlight, 0)
        GPIO.output(buzzer, 0)
        
        #Start light sequence
        time.sleep(1)
        for x in range(0, 3):
            GPIO.output(redlight, 1)
            GPIO.output(buzzer, 1)
            time.sleep(0.3)
            GPIO.output(redlight, 0)
            GPIO.output(buzzer, 0)
            time.sleep(1)
        time.sleep(random.uniform(1, 3))
        falsestart = False
        GPIO.output(greenlight, 1)
        #Timing starts and ensures no false start
        start_time = time.time()

        GPIO.output(buzzer, 1)
        time.sleep(1)
        GPIO.output(buzzer, 0)

        done = False
        
        while ((L1_lap < Laps) and (L2_lap < Laps) and not cheat and not done):
            for event in pygame.event.get():
                if event.type == pygame.KEYDOWN and event.key == pygame.K_q:
                    done = True
        
            drawResults()
            clock.tick(60)

        #Present final results    
        drawResults()

        if cheat:
            if Ferrari_cheat:
                f_cheat_text = myFont.render("Team Ferrari jumped the start!", 1, DARKBLUE)
                screen.blit(f_cheat_text, (dI.current_w/4 , 5*th))
            if RedBull_cheat:
                r_cheat_text = myFont.render("Team RedBull jumped the start!", 1, RED)
                screen.blit(r_cheat_text, (dI.current_w/4 , dI.current_h/2 + 5*th))
            pickle.dump(best_Ferrari, open(path + "/SG/Ferrari.p", "wb" ))
            pickle.dump(best_RedBull, open(path + "/SG/RedBull.p", "wb" ))
            
            pygame.display.flip()

            # False start signal
            GPIO.output(greenlight, 0)
            for x in range(0, 5):
                GPIO.output(redlight, 1)
                GPIO.output(buzzer, 1)
                time.sleep(0.3)
                GPIO.output(redlight, 0)
                GPIO.output(buzzer, 0)
                time.sleep(0.3)

            # Before the loop, load the sounds:
            pygame.mixer.init()
            pygame.mixer.music.set_volume(1.0)
            click_sound = pygame.mixer.Sound(path + "/F1-new3.ogg")
            click_sound.play()
            pygame.mixer.fadeout(6000)
            
        else:       
            Total_time = time.time() - start_time
            if L1_lap > L2_lap:
                f_winner_text = myFont2.render("Team Ferrari is the winner with time: " + time_converter(Total_time), 1, WHITE)
                screen.blit(f_winner_text, (dI.current_w/4 , 4*th))
            if L1_lap < L2_lap:
                r_winner_text = myFont2.render("Team Redbull is the winner with time: " + time_converter(Total_time), 1, WHITE)
                screen.blit(r_winner_text, (dI.current_w/4 , dI.current_h/2 + 4.4*th))

            # Calculate race stats
            avg_speed = Decimal((course_length * Laps) / float(Total_time) * 3.6)
            top_speed_1 = Decimal(course_length / float(L1_best_time) * 3.6)
            top_speed_2 = Decimal(course_length / float(L2_best_time) * 3.6)
           
            if (L1_lap < 1):
                f_stats_text = myFont2.render("Team Ferrari did not complete 1 lap", 1, WHITE)
                screen.blit(f_stats_text, (dI.current_w/4 , 4*th))
            else:
                f_stats_text = myFont2.render("Team Ferrari's top avg. speed: " + str(round(top_speed_1, 2)) + " km/h", 1, WHITE)
                screen.blit(f_stats_text, (dI.current_w/4 , 4.7*th))

            if (L2_lap < 1):
                r_stats_text = myFont2.render("Team RedBull did not complete 1 lap", 1, WHITE)
                screen.blit(r_stats_text, (dI.current_w/4 , dI.current_h/2 + 4.4*th))
            else:
                r_stats_text = myFont2.render("Team RedBull's top avg. speed: " + str(round(top_speed_2, 2)) + " km/h", 1, WHITE)
                screen.blit(r_stats_text, (dI.current_w/4 , dI.current_h/2 + 5.1*th))

            if (L1_best_time < best_Ferrari): #Check and save Ferrari lap record on lane 1
                f_rec_text = myFont2.render("We have a new Ferrari lap record on lane 1! Press Enter.", 1, WHITE)
                screen.blit(f_rec_text, (dI.current_w/4 , 5.4*th))
                pickle.dump(L1_best_time, open(path + "/SG/Ferrari.p", "wb" ))
            else:
                f_rec_text = myFont2.render("No new lap record for Ferrari this race, press Enter.", 1, WHITE)
                screen.blit(f_rec_text, (dI.current_w/4 , 5.4*th))

            if (L2_best_time < best_RedBull): #Check and save RedBull lap record on lane 2
                r_rec_text = myFont2.render("We have a new RedBull lap record on lane 2! Press Enter", 1, WHITE)
                screen.blit(r_rec_text, (dI.current_w/4 , dI.current_h/2 + 5.8*th))
                pickle.dump(L2_best_time, open(path + "/SG/RedBull.p", "wb" ))
            else:
                r_rec_text = myFont2.render("No new lap record for Ferrari this race, press Enter.", 1, WHITE)
                screen.blit(r_rec_text, (dI.current_w/4 , dI.current_h/2 + 5.8*th))

            pygame.display.flip()

            # Before the loop, load the sounds:
            pygame.mixer.init()
            pygame.mixer.music.set_volume(1.0)
            click_sound = pygame.mixer.Sound(path + "/F1-new3.ogg")
            click_sound.play()
            pygame.mixer.fadeout(6000)
                            
            # End of race signal
            for x in range(0, 3):
                GPIO.output(redlight, 1)
                GPIO.output(buzzer, 1)
                time.sleep(0.3)
                GPIO.output(redlight, 0)
                GPIO.output(buzzer, 0)
                time.sleep(0.5)

        # Necessary as GPIO.cleanup() won't remove detect events. 
        GPIO.remove_event_detect(23)
        GPIO.remove_event_detect(24)

    except KeyboardInterrupt:
        print("User controlled exit")
        pygame.quit()
    except:
        print ("Another exception")
        pygame.quit()
    finally:
        print("Cleaning up PINS")
        GPIO.cleanup()  #cleanup regardless of reason for exit.
        
    # Waits for user to press enter
    wait()

    #Text to race again
    race_again_text = myFont.render("Race again (y/n)?", 1, DARKBLUE)
    drawResults()
    screen.blit(race_again_text, (dI.current_w/4 , 5*th))

    # Update screen
    pygame.display.flip()
    
    #Check to race again
    raceAgain()

# Under while loop
pygame.quit()

Last edited by Marre on Thu Jan 28, 2016 9:14 pm, edited 2 times in total.

paulv
Posts: 558
Joined: Tue Jan 15, 2013 12:10 pm
Location: Netherlands

Re: Stopwatch

Thu Jan 21, 2016 11:05 am

There is a (reported) bug in the GPIO.add_event_detect() code.
Detecting Falling edges work, Rising edges do not, they produce triggers on both edges, as if you used Both.

Marre
Posts: 6
Joined: Thu Dec 31, 2015 11:02 am

Re: Stopwatch

Thu Jan 21, 2016 9:39 pm

Good thing it's noted. I forgot to mention I solved it using:
GPIO.remove_event_detect(pin/channel), which clears it each rerun of the program, so no problem in my program with that.
So I didn't really have the problem with triggering on up+down, rather the add events kept stacking up, so run 1 was fine, rerun 1it detected 2 laps at a time, 2nd 3 laps etc, despite gpio.cleanup() was run before each rerun.

Keep in mind the bounce time of the events, I've set them to 2500ms, so if you've got faster lap times than that, you need to change it to cater for that or you'll be having problems.
/M

Marre
Posts: 6
Joined: Thu Dec 31, 2015 11:02 am

Re: Stopwatch

Sat Jan 23, 2016 6:10 pm

Due to the fact that I'm running the screen on my PC with TightVNC client, I learnt some other things today:
- There is a lot of "hissing" going on over the 3.5mm audio output. To handle this during the race, I've added stopped the sound (pygame.mixer.stop()) and reinitialized it for each run. The HDMI output does not seem to suffer from this, so use it if you can.
- My suggestion is not to run TightVNC over wifi, it's lagging and gets clogged up, whilst LAN-cable works just fine.

User avatar
with ice cream
Posts: 165
Joined: Mon Jul 30, 2012 7:25 am

Re: Stopwatch

Sun Mar 12, 2017 7:43 pm

Marre wrote:please note you need to create the empty files using the files names in the code for this
I came across your Stopwatch code and plan to adapt it to a solution with a 2.8" GPIO touch screen. It seems that simply touching the necessary files isn't enough. Would it be possible to provide an example?

Thanks!

Return to “Python”