Raspberry Pi- События GPIO в Python

Я использую контакты GPIO на моем Raspberry Pi с датчиком PIR для обнаружения движения. Когда датчик обнаруживает движение, я хочу перенести программное обеспечение на другие функции.

На данный момент для обнаружения движения моя программа постоянно работает в цикле, пока она ожидает обнаружения движения. Хотя в настоящее время это работает, для использования в будущем это будет невероятно неэффективно, и я надеюсь улучшить это, назначив его событию.

Есть ли способ привязать мой ввод GPIO к событию, обнаруженному программой, без ручного запуска цикла.

Вот мой текущий цикл для обнаружения движения:

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)

Счетчик и многократное обнаружение движения используются для уменьшения количества ложных срабатываний датчика.


person Stefoth    schedule 22.04.2013    source источник


Ответы (4)


Библиотека Python RPi.GPIO теперь поддерживает События, которые описаны в Прерывания и обнаружение края абзаца.

Итак, после обновления Raspberry Pi с sudo rpi-update, чтобы получить последнюю версию библиотеки, вы можете изменить свой код на:

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

Я выбрал метод потоковых обратных вызовов, потому что полагаю, что ваша программа остальное параллельно менять значение var.

person kapcom01    schedule 03.09.2013

Теперь в библиотеку RPi GPIO встроено управление GPIO, управляемое прерываниями, которое может происходить в отдельном потоке, освобождая ресурсы. Вы можете прочитать следующее http://raspi.tv/2013/how-to-use-interrupts-with-python-on-the-raspberry-pi-and-rpi-gpio-part-3

person Nipun Batra    schedule 04.06.2013

Вы можете обернуть GPIO-код в его собственный поток, а остальная часть вашей программы будет делать что-то еще, пока GPIO ожидает ввода. Ознакомьтесь с модулем потоковой передачи

Сначала я бы превратил ваш код в функцию

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)

И тогда в своей основной программе вы могли бы что-то вроде этого

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

Есть много вопросов по SO, касающихся потоковой передачи Python, так что вы можете их откопать. Обратите внимание, что при использовании потоков также следует учитывать множество вещей, особенно в Python, который имеет глобальную блокировку интерпретатора (GIL), которая позволяет запускать только один процесс за раз. Также было бы разумно проверить многопроцессорный модуль, с помощью которого можно обойти ГИЛ.

person msvalkon    schedule 22.04.2013
comment
Будет ли этот метод работать, скажем, с графическим интерфейсом? Что я хочу сделать, так это вызвать класс детектора движения, в котором работает этот цикл, из моего графического интерфейса, но с циклом он просто вызывает сбой графического интерфейса. Если я использую это с потоком, вызовет ли это выполнение цикла обнаружения движения в фоновом режиме, пока графический интерфейс прослушивает связанный с ним ввод? - person Stefoth; 22.04.2013
comment
@Stefoth, вот как работает программирование GUI. Ваш графический интерфейс будет работать в собственном потоке, а код обнаружения движения будет работать отдельно. - person msvalkon; 22.04.2013

kapcom01 дает отличные идеи, но лучше не делать много инструкций в прерывании.

Обычно вы устанавливаете флаг в 1, когда обратным вызовом является call, и вы выполняете обработку в основной функции. Таким образом, нет риска освободить программу.

Что-то вроде этого:

     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
person Lemaitre Cedric    schedule 03.10.2018