python 클릭 파이썬 버튼 기능이 이상하게도 같은 일을하지 않습니다.



파이썬 버튼 클릭 이벤트 (1)

나는 현재 2 개의 버튼을 내 Raspberry Pi에 연결했는데 (이것들은 ring LED가있는 것들이다) 나는이 코드를 수행하려고 노력하고있다.

#!/usr/bin/env python
import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(17, GPIO.OUT) #green LED
GPIO.setup(18, GPIO.OUT) #red LED
GPIO.setup(4, GPIO.IN, GPIO.PUD_UP) #green button
GPIO.setup(27, GPIO.IN, GPIO.PUD_UP) #red button

def remove_events():
        GPIO.remove_event_detect(4)
        GPIO.remove_event_detect(27)

def add_events():
        GPIO.add_event_detect(4, GPIO.FALLING, callback=green, bouncetime=800)
        GPIO.add_event_detect(27, GPIO.FALLING, callback=red, bouncetime=800)

def red(pin):
        remove_events()
        GPIO.output(17, GPIO.LOW)
        print "red pushed"
        time.sleep(2)
        GPIO.output(17, GPIO.HIGH)
        add_events()

def green(pin):
        remove_events()
        GPIO.output(18, GPIO.LOW)
        print "green pushed"
        time.sleep(2)
        GPIO.output(18, GPIO.HIGH)
        add_events()

def main():
    while True:
        print "waiting"
        time.sleep(0.5)

GPIO.output(17, GPIO.HIGH)
GPIO.output(18, GPIO.HIGH)
GPIO.add_event_detect(4, GPIO.FALLING, callback=green, bouncetime=800)
GPIO.add_event_detect(27, GPIO.FALLING, callback=red, bouncetime=800)

if __name__ == "__main__":
    main()

표면에 그것은 꽤 쉬운 스크립트처럼 보입니다. 버튼 누름이 감지되면 :

  1. 이벤트를 제거하십시오.
  2. 메시지를 인쇄하다
  3. 이벤트를 추가하고 LED를 다시 켜기 전에 2 초 정도 기다리십시오.

초록색 버튼을 누르면 정상적으로 작동합니다. 나는 여러 번 그것을 연속적으로 시도했고 실패없이 작동한다. 그러나 빨간색은 처음에는 잘 작동하고 두 번째에는 제대로 작동하지만 두 번째 빨간색 (핀) 싸이클이 완료되면 스크립트가 멈 춥니 다.

두 사건 모두 상당히 비슷하다고 생각하여 두 번째 빨간 버튼의 끝에서 왜 실패하는지 설명 할 수 없습니다.

편집 : 나는 빨간색과 녹색에서 핀을 각각 바꿨다. (다른 핀은 완전히 바꾸거나 스왑한다.) 어느 쪽이든, 항상 빨간 버튼 코드 (실제로는 녹색 버튼)가 오류를 일으 킵니다. 그래서 그것은 물리적 인 빨간 버튼 문제가 아니라 핀 문제 일 것입니다. 이것은 단지 코드가 잘못되었다고 생각합니다.


스크립트를 실행하고 바닥과 GPIO27 사이의 점퍼 케이블을 연결하여 빨간 버튼을 누르는 방식으로 내 Raspberry Pi 1, Model B에서 문제를 재현 할 수있었습니다. (이들은 내 특정 Pi 모델의 핀 25와 13입니다.)

파이썬 인터프리터는 버튼 누름을 처리 할 때 red 반환 이후에 GPIO 이벤트를 폴링하는 데 사용되는 스레드에서 세그먼트 오류로 인해 충돌합니다. 파이썬 GPIO 모듈의 구현을 살펴본 후, 이벤트 핸들러 콜백 내에서 remove_event_detect 를 호출하는 것이 안전하지 않으며, 이로 인해 충돌이 발생한다는 것이 확실합니다. 특히 이벤트 핸들러가 현재 실행 중일 때 이벤트 핸들러를 제거하면 메모리 손상이 발생할 수 있으며 이로 인해 충돌이 발생하거나 다른 이상한 동작이 발생할 수 있습니다.

이벤트 처리기를 제거하고 다시 추가하는 것은 의심 스럽습니다. 버튼을 누를 때 콜백을받는 것이 걱정되기 때문입니다. 이것을 할 필요가 없습니다. GPIO 모듈은 GPIO 이벤트를 모니터링하기 위해 단일 폴링 스레드를 가동하고보고있는 GPIO 이벤트 수에 관계없이 한 콜백이 돌아 오기 전에 다시 콜을 기다립니다.

스크립트가 시작될 때 add_event_detect 를 호출하고 콜백을 절대로 제거하지 않는 것이 좋습니다. 스크립트에서 add_eventsremove_events (및 해당 호출)를 제거하기 add_events 문제가 해결됩니다.

GPIO 모듈에서 문제의 세부 사항에 관심이 있다면 해당 모듈C 소스 코드를 살펴보십시오. RPi.GPIO-0.6.2/source/event_gpio.c 파일에서 run_callbacksremove_callbacks 를 살펴보십시오. 이 두 함수는 struct callback 노드의 글로벌 체인을 사용합니다. run_callbacks 는 한 노드를 잡고 콜백을 호출 한 다음 체인의 다음 콜백에 대한 해당 노드의 링크를 run_callbacks 하여 콜백 체인을 처리합니다. remove_callbacks 는 동일한 콜백 체인을 처리하고 특정 GPIO 핀에서 콜백과 관련된 메모리를 해제합니다. run_callbacks 의 중간에서 remove_callbacks 가 호출 run_callbacks , run_callbacks 에 의해 현재 보유 된 노드는 다음 노드에 대한 포인터가 추적되기 전에 해제 (메모리가 잠재적으로 재사용 및 겹쳐 쓰기) 될 수 있습니다.

빨간색 버튼에 대해서만이 문제가 나타나는 이유는 add_event_detectremove_event_detect 대한 호출 순서 때문에 이전에 콜백 노드에서 사용한 빨간 버튼이 다른 용도로 회수되어 사용 된 메모리보다 먼저 덮어 쓰기되기 때문입니다 초록색 버튼 콜백 노드의 버튼도 마찬가지로 재생됩니다. 그러나 두 버튼 모두에 문제가 있음을 확인하십시오. 다음 콜백 노드에 대한 포인터를 추적하기 전에 녹색 버튼 콜백과 관련된 메모리가 변경되지 않는다는 점이 좋습니다.

일반적으로 GPIO 모듈에서 콜백 체인 사용과 관련하여 스레드 동기화에 관한 부족한 점이 있습니다. 이벤트가 다른 이벤트에서 제거 되더라도 remove_event_detect 또는 add_event_detect 가 호출되면 이벤트 핸들러가 실행 중일 때 비슷한 문제가 발생할 수 있습니다. 실! RPi.GPIO 모듈 작성자는 콜백이 수행되는 동안 콜백 체인을 수정할 수 없도록 일부 동기화를 사용해야한다고 제안합니다. 아마도 폴링 스레드 자체에서 체인이 수정되고 있는지 확인하는 것 외에도 폴링 스레드에서 다른 스레드가 콜백 체인을 수정하는 것을 방지하기 위해 pthread_mutex_lockpthread_mutex_unlock 을 사용할 수 있습니다.

불행히도, 그것은 현재의 경우가 아니며, 이런 이유로 피할 수 있으면 remove_event_detect 완전히 호출하지 않는 것이 좋습니다.





gpio