pythonraspberry-pigpiozero

Continue running a loop until a button is pressed using gpiozero - button press not registered


I have some python code on a raspberry pi that I want to run and carry on a loop until a button is pressed.

The button.wait_for_press() is not suitable because that pauses the program until it runs, but I have tried it out to see if the hardware is working and it does.

def shutterPressed():
    global shutterHasBeenPressed
    shutterHasBeenPressed = True

def main():

    """
    Main program loop
    """

    #start camera preview
    camera.start_preview(resolution=(SCREEN_W, SCREEN_H))

    #Display Intro screens
    intro_image_1 = REAL_PATH + '/assets/intro_1.png'
    intro_image_2 = REAL_PATH + '/assets/intro_2.png'
    overlay_1 = overlay_image(intro_image_1, 0, 3)
    overlay_2 = overlay_image(intro_image_2, 0, 4)

    #Wait for button press
    i = 0
    blink_speed = 10

    button.when_pressed = shutterPressed

    while True:
        global shutterHasBeenPressed
        shutterHasBeenPressed = False
        #Stay in loop until button is pressed
        if shutterHasBeenPressed is False:
            i += 1
            if i == blink_speed:
                overlay_2.alpha = 255
            elif i == (2 * blink_speed):
                overlay_2.alpha = 0
                i = 0
            #Restart while loop
            sleep(0.1)
            continue
        #button has been pressed!
        print("Button Pressed!")

When I run this code, the button press is not registered at all.

What have I got wrong?

EDIT: so I added a print statement to the shutterPressed() function and confirmed that it is running when the button is pressed.

In also added a statement to print the value of shutterHasBeenPressed just before the if statement. This never changed from false.

However, if I removed the line changing the variable to false at the beginning of the loop, then code worked, so it is obviously something to do with when various bits get run. Maybe the while loop starts again after the shutterPressed() function runs?

Either way, i have fixed it by moving the reassignment of the variable to after the if statement.


Solution

  • Welcome to the world of concurrency (somewhat)!

    Just imagine your program running: the instructions are being executed one after the other in the order in which they are written, according to the execution flow that they define with the exception of shutterPressed which is asynchronously executed (maybe).

    Therefore, imagine we enter the loop and are at the first line, <here>:

          while True:
            global shutterHasBeenPressed
            shutterHasBeenPressed = False                 # <here>
            #Stay in loop until button is pressed
            if shutterHasBeenPressed is False:
                i += 1
                if i == blink_speed:
                    overlay_2.alpha = 255
                elif i == (2 * blink_speed):
                    overlay_2.alpha = 0
                    i = 0
                #Restart while loop
                sleep(0.1)
                continue
            #button has been pressed!
            print("Button Pressed!")
    

    Now, shutterHasBeenPressed has been set to False and the condition that follows is verified so that we enter the if.

    the program keeps running until, unexpectedly, the button is pressed. Say, it reached <here>:

          while True:
            global shutterHasBeenPressed
            shutterHasBeenPressed = False
            #Stay in loop until button is pressed
            if shutterHasBeenPressed is False:
                i += 1
                if i == blink_speed:
                    overlay_2.alpha = 255           # <here>
                elif i == (2 * blink_speed):
                    overlay_2.alpha = 0
                    i = 0
                #Restart while loop
                sleep(0.1)
                continue
            #button has been pressed!
            print("Button Pressed!")
    

    At this point, shutterPressed runs, sets shutterHasBeenPressed to True. Then, back in our loop, the iteration finishes, we continue at the start of the loop and ... what's there?!

            shutterHasBeenPressed = False
    

    and the button press just went completely unnoticed!

    I believe this answers your question asking what you have got wrong.