2

I'm new at python and raspberry pi. I was looking to make a visual voting game using graphics and the PI and python. I will be using a non touch screen hdmi in display, the Pi, and two physical buttons hooked up to the Pi's gpio ports. i was going to start with an introductory screen, and wait for a voter to push one of the buttons, which would then bring him to the first 2 choice voting screen. When he/she pushes a button to vote, it would refresh the screen to the results for those 2 choices for a few seconds, then bring up the 2nd voting screen. This would loop for however many voting screens i make. At the end I would display a "high score" like tally of all the votes. And then it would loop back to the introductory screen again.

I am having issues with the wait time for the first voting selection screen. I can get it to display, and am using the add_event_detect for the GPIO buttons, but i don't know how to "pause" the voting selection screen on screen without delaying the program from running, thus not allowing the button selection to be made. The program loops too fast and goes back to the intro screen and does not wait for user input on the voting screen.

Below is a sample of what i have so far. I have omitted the voting variables and incrementing and displaying the text as that works ok. I just need to figure out how to keep each voting screen displayed until user input and then move onto the next. Mahalo for the help!

import RPi.GPIO as GPIO2
import time
import pygame

BUTTON_1 = 3
BUTTON_2 = 5 
GPIO2.setmode(GPIO2.BOARD)
pygame.init()
pygame.display.init()

WIDTH = 1900
HEIGHT = 1000

display = pygame.display.set_mode((WIDTH, HEIGHT))

intro = pygame.image.load('intro.png')
voting1 =  pygame.image.load('voting1.png')

def button_callback(channel):
    pygame.time.delay(1000)
    while True:
        display.fill((125,125,125))
        display.blit(intro, (0,0)) #display intro game screen
        pygame.display.update()
        while True:
            if (BUTTON_1.is_pressed or BUTTON_2.is_pressed):  #start game and switch to first voting screen
                display.blit(voting1,(0,0))
                pygame.display.update()
                pygame.time.delay(1000)
        while True:  #wait for user vote
        if Button_1.is_pressed:
        *** increment couting variables here and vote 1 results screen for a few secs ***
        elif Button_2.is_pressed:
        *** increment couting variables here and vote 1 results screen for a few secs ***
       *** display 2nd, 3rd voting screen, looped til last screen
    *** display high score screen for a few secs, kick back to intro screen ***

GPIO2.setup(BUTTON_1, GPIO2.IN)
GPIO2.setup(BUTTON_2, GPIO2.IN)

GPIO2.add_event_detect(BUTTON_1, GPIO2.FALLING, callback=button_callback,bouncetime=50)
GPIO2.add_event_detect(BUTTON_2, GPIO2.FALLING, callback=button_callback,bouncetime=50)

try:
    while True:
        time.sleep(0.01)
        print("in while")
except KeyboardInterrupt:
    GPIO2.cleanup()
chawancut
  • 23
  • 2
  • You could implement a [state machine](https://stackoverflow.com/questions/14700889/pygame-level-menu-states) to manage your different game states: *intro*, *vote1*, ..., *voteN*, *final score* and the transition between them. – import random Jun 06 '22 at 12:37
  • oh, thanks! i will read up on that. so you're saying with the "states" i can make that each different voting image, and loop a function to wait for the gpio events to trigger the vote and then call up the next voting screen? – chawancut Jun 07 '22 at 09:03

1 Answers1

1

It is usually bad practice to hold up callbacks with a lot of code, otherwise you'll prevent further callbacks - as you've found out.

As mentioned in the comments - you could run the main program as a state machine - and the button presses would cause the state to change, and move through the program.

For example - I've taken your code and written a quick state machine that would take you through the voting screens. (I've taken out the pygame code for simplicity to concentrate on the state machine).

You should be able to follow the main application through the state changes, and see how the buttons affect the state whilst the application is currently waiting for input.

Please note - I haven't tried to run this program as I don't have a Pi to hand with buttons attached, so if you have any issues let me know.

Hopefully this will help you progress your voting game.

import RPi.GPIO as GPIO2
import time

BUTTON_1 = 3
BUTTON_2 = 5 
GPIO2.setmode(GPIO2.BOARD)

VOTING_RESULT_TIME = 2

# The different states the application could be in (could use an Enum class for this)
STATE_WELCOME=0
STATE_WAITING_TO_START=1
STATE_SHOWING_NEXT_SCREEN=2
STATE_WAITING_TO_VOTE=3
STATE_SHOWING_VOTE_RESULTS=4
STATE_SHOWING_FINAL_RESULTS=5

current_state = STATE_WELCOME 

welcome_screen = "Press any button to start ..." 
voting_screens = ["Cats or Dogs", "Cars or Bikes?", "Apples or Pears?"]
current_screen = 0 

def button_callback(channel):
    if current_state == STATE_WAITING_TO_START:
        current_state = STATE_SHOWING_NEXT_SCREEN 

    elif current_state == STATE_WAITING_TO_VOTE: 

        if channel == BUTTON_1:
            # do counting for button 1
            pass 
        elif channel == BUTTON_2:
            # do counting for button 2 
            pass
        current_state = STATE_SHOWING_VOTE_RESULTS 
    else:
        # buttons won't have any effect whilst the main app is not waiting for input
        pass 

GPIO2.setup(BUTTON_1, GPIO2.IN)
GPIO2.setup(BUTTON_2, GPIO2.IN)

GPIO2.add_event_detect(BUTTON_1, GPIO2.FALLING, callback=button_callback,bouncetime=50)
GPIO2.add_event_detect(BUTTON_2, GPIO2.FALLING, callback=button_callback,bouncetime=50)

try:
    while True:

        if current_state == STATE_WELCOME:
            print(welcome_screen); 
            current_state == STATE_WAITING_TO_START; 

        elif current_state == STATE_WAITING_TO_START: 
            pass # button callback will change state. 

        elif current_state == STATE_SHOWING_NEXT_SCREEN: 
            print(voting_screens[current_screen]) 
            current_state = STATE_WAITING_TO_VOTE 

        elif current_state == STATE_WAITING_TO_VOTE:
            pass # button callback will change state  

        elif current_state == STATE_SHOWING_VOTE_RESULTS: 
            print("Here are the voting results") 
            time.sleep(2000)
            current_screen += 1 
            if ( current_screen >= len(voting_screens) ):
                current_state = STATE_SHOWING_FINAL_RESULTS 
            else:
                current_state = STATE_SHOWING_NEXT_SCREEN 

        elif current_state == STATE_SHOWING_FINAL_RESULTS:
            print("Here are the final results ....")
            time.sleep(2000) 
            current_screen = 0 
            current_state = STATE_WELCOME 

        time.sleep(0.01)

except KeyboardInterrupt:
    pass 
finally:
    GPIO2.cleanup()
cguk70
  • 611
  • 3
  • 7