Raspberry Pi- GPIO Events in Python
Asked Answered
A

4

22

I am using the GPIO pins on my Raspberry Pi with a PIR sensor to detect motion. When the sensor detects motion I want to then move the software onto other functions.

At the moment, to detect motion I have my program constantly running in a loop while it is waiting for motion to be detected. While this works at the moment, for use in the future this will be incredibly inefficient and am hoping to improve on this by assigning it to an event.

Is there any way to bind my GPIO input to an event that is detected by the program without manually running a loop.

Here is my current loop for detection motion:

var = 1
counter = 0
while var == 1:
    if GPIO.input(7):
        counter += 1
        time.sleep(0.5)
    else:
        counter = 0
        time.sleep(1)

    if counter >= 3:
        print "Movement!"
        captureImage()
        time.sleep(20)

The counter and detecting motion multiple times is used to reduce the number of false positives that the sensor picks up.

Austen answered 22/4, 2013 at 9:37 Comment(0)
C
34

The RPi.GPIO Python library now supports Events, which are explained in the Interrupts and Edge detection paragraph.

So after updating your Raspberry Pi with sudo rpi-update to get the latest version of the library, you can change your code to:

from time import sleep
import RPi.GPIO as GPIO

var=1
counter = 0

GPIO.setmode(GPIO.BOARD)
GPIO.setup(7, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

def my_callback(channel):
    if var == 1:
        sleep(1.5)  # confirm the movement by waiting 1.5 sec 
        if GPIO.input(7): # and check again the input
            print("Movement!")
            captureImage()

            # stop detection for 20 sec
            GPIO.remove_event_detect(7)
            sleep(20)
            GPIO.add_event_detect(7, GPIO.RISING, callback=my_callback, bouncetime=300)

GPIO.add_event_detect(7, GPIO.RISING, callback=my_callback, bouncetime=300)

# you can continue doing other stuff here
while True:
    pass

I chose the Threaded callbacks method because I suppose that your program does some other things in parallel to change the value of var.

Calv answered 3/9, 2013 at 15:29 Comment(0)
U
3

Now the RPi GPIO library has inbuilt interrupt driven GPIO control which can happen in separate thread freeing up resources. You may wish to read the following http://raspi.tv/2013/how-to-use-interrupts-with-python-on-the-raspberry-pi-and-rpi-gpio-part-3

Unconventionality answered 4/6, 2013 at 13:59 Comment(0)
M
1

You could wrap the GPIO-code into it's own thread and have the rest of your program do something else while the GPIO is waiting for input. Check out the threading module

First I'd wrap your code into a function

def wait_input():
    var=1
    counter = 0
    while var == 1:
        if GPIO.input(7):
            counter += 1
        time.sleep(0.5)
        else:
            counter = 0
            time.sleep(1)
        if counter >= 3:
            print "Movement!"
            captureImage()
            time.sleep(20)

And then in your main program you could something like this

input_thread = threading.Thread(target = wait_input)
input_thread.start()
# do something in the meanwhile
input_thread.join()

There are plenty of questions on SO concerning python threading, so you might want to dig them up. Please note that there are also plenty of things to consider when using threads, especially in python which has a global interpreter lock (GIL) which allows only one process to run at a time. It might also be smart to check out the multiprocessing module with which one can route around the GIL.

Maker answered 22/4, 2013 at 9:44 Comment(2)
Would this method work with say a GUI? What I want to do is call the motion detector class that this loop is running in from my GUI, but with the loop it just crashes the GUI. If I use this with the thread, will it cause the motion detection loop to run in the background while the GUI listens for the input associated with it?Austen
@Austen this is pretty much how GUI programming works. Your GUI will run in it's own thread and motion detecting code runs in its own.Maker
S
-1

kapcom01 gives some great ideas but it's better to make not make a lot of instructions in the a interrupt.

Usually you put a flag to 1 when the callback is call and you make the processing in the main function. In thes manner there is no risk of freesing the programm.

Somethings like this :

     from time import sleep
     import RPi.GPIO as GPIO



     def init():
         # make all your initialization here
         flag_callback = False
         # add an interrupt on pin number 7 on rising edge
         GPIO.add_event_detect(7, GPIO.RISING, callback=my_callback, bouncetime=300)


     def my_callback():
         # callback = function which call when a signal rising edge on pin 7
         flag_callback = True


     def process_callback():
         # TODO: make process here
         print('something')


     if __name__ == '__main__':
     # your main function here

     # 1- first call init function
     init()

     # 2- looping infinitely 
     while True:
         #3- test if a callback happen
         if flag_callback is True:
             #4- call a particular function
             process_callback()
             #5- reset flagfor next interrupt
             flag_callback = False
    pass
Serna answered 3/10, 2018 at 8:15 Comment(1)
@Calv uses threaded callback: the callback runs in a new threadAlmemar

© 2022 - 2025 — McMap. All rights reserved.