Nur eine Flanke wird erkannt

  • Moin, ich habe wieder mal ein kleines Problem mit Python.
    Ich habe eine Türe mit einem Schalter versehen, welcher an den GPIO 21 am Pi angeschlossen ist:
    schalter_an_gpio_mit_widerstand.jpg
    Nutze ich dieses Pythonscript, wird mir nur eine geschlossene Türe erkannt, aber keine offene:


    Irgendwie muss das mit dem Script zu tun haben, denn mit "gpio readall" wird mir immer eine "0" bei geschlossener Türe und eine "1" bei geöffneter Türe ausgegeben.
    Entweder stehe ich wieder auf dem Schlauch, oder habe sonst etwas übersehen.
    Da ich im programmieren eine Null bin, hoffe ich mal wieder auf euch. :helpnew:
    Wo liegt der Fehler ? (Meist sitzt der Fehler ja vor dem Gerät)
    MfG

  • Muss ja nicht mit Python gelöst werden. Da ich zu doof zum programmieren bin, habe das Script eh geklaut.
    Ich möchte nur wissen, ob die Türe auf ist, oder zu, da ich einen autom. Türöffner per Smartphone bauen will, das ist dann aber Offtopic:
    Smartphone greift per WLAN auf Homepage des Pi zu, auf dem Smartphone wird ein Button betätigt, "Klingeln" oder "Tür öffnen", je nach Berechtigung, Tür darf geöffnet werden.
    Fehlt jetzt noch die Rückmeldung, "Türe ist seit x Sekunden offen", oder "Türe ist wieder geschlossen" und vllt. ein noch Video, dass nur aufgenommen wird, wenn die Türe offen ist.

  • Bin absolut kein Profi, aber hast Du schon mal statt:
    if GPIO.input(21) == GPIO.HIGH:

    if GPIO.input(21) == 1:

    probiert?

    rasray
    ------------------
    Ok, müsste dasselbe sein, wie aus dem Link von root zu sehen ist, aber an dieser Stelle:
    @root: Schön, doch noch von dir zu lesen, nachdem Du letztens ziemlich frustriert zu sein schienst.

    Welcome back!!!

    Einmal editiert, zuletzt von rasray (5. März 2016 um 11:29)

  • @rasrey: Habe ich gerade probiert, genau das gleiche, "Türe geschlossen" :wallbash:

    Ich habe das Script "Steigende und fallende Flanke" kopiert und angepasst, genau das gleiche, es wird nur der Low-Zustand erkannt, kein High, obwohl "gpio readall" eindeutigt sagt, dass der Pin auf "1" ist, wenn die Türe offen steht:


    Auch mit diesem Shellscript wird mir das Türe schliessen nicht erkannt, nur beim öffnen der Türe kommt einmalig "Zustandsänderung erkannt !", dann wieder "Keine Änderung erkannt":


    Mit diesem Script bekomme ich komischerweise die High-Meldung:

  • Die gezeigten Beispiele unterscheiden sich nicht wirklich von dem aus Beitrag#1. fred0815 verwendet einen externen PullDOWN Widerstand, der von root gezeigte nutzt den GPIO-Internen. Wie es fred0815 gemacht hat ist es aber besser da man diesen dann nicht vergessen kann ;)

    Was mich allerdings etwas verwirrt ist dass fred0815 zwei Widerstände verbaut hat? :-/ Es würde ein Widerstand reichen:
    Von 3V3 gehts direkt zum Taster. Vom Taster gehts dann direkt zum Widerstand, und dann ein mal vom Widerstand nach GND und noch mal zum GPIO

    Code
    3V3 -> Switch -> PullDown -> GND
                  `-> GPIO


    Die Variable GPIO.HIGH enthält True.
    in Python3 ist es besser/schneller mit True / False zu arbeiten als mit den Pendanten 1 / 0 ... Das war in Python2 noch andersherum. Aber das sei nur nebenbei erwähnt.


  • ...
    ... zwei Widerstände verbaut hat?
    ...


    der zweite (kleinere) dient i.d.R. zur Strombegrenzung (z.B. beim Hochfahren). Ist nur zur Sicherheit, kann weggelassen werden (weil hochohmig wenn der Pin auf Eingang gestellt wird) kann aber auch nicht schaden ;)
    cu,
    -ds-

  • So, jetzt komme ich der Sache schon näher, ich habe alle Script von hier getestet:
    http://indibit.de/raspberry-pi-g…ingaenge-lesen/
    Das Script für die steigende Flanke funktioniert einwandfrei, ich bekomme nur ein HIGH, wenn die Türe geöffnet wird. :bravo2:
    Das Script für die fallende Flanke erkennt das öffnen und schliessen der Türe als HIGH. :no_sad:
    Das Script für die steigende und fallende Flanke erkennt das öffnen und schliessen der Türe immer als LOW. :no_sad:

    Nur warum erkennt das Script für die fallende Flanke eine fallende Flanke, auch wenn das Signal steigt ?
    Und warum erkennt das Script für die steigende und fallende Flanke immer ein LOW ?
    :-/ :s

  • Hallo zusammen,

    da ja immer wieder PullUP- und PullDOWN-Widerstand durcheinandergeschmissen wird, hier ein Link auf eine Seite, durch die ich verstanden habe, wann ein Widerstand zu einem PullUP oder PullDOWN wird.

    Die beiden gezeigten Schaltungen sind so einfach wie einprägend.

    Beste Grüße

    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

  • ...jetzt mal für mein Verständnis:
    Bildet das System mit den zwei Widerständen jetzt einen Spannungsteiler?
    Am 4,7 kOhm-Widerstand müsste doch eine Spannung abfallen, Verhältnis der Widerstände ist ~1:2 ?
    Also Ich würde die 4,7- kOma mal weglassen...

    rasray

    Einmal editiert, zuletzt von rasray (5. März 2016 um 12:40)

  • Die Scripts unterscheiden sich in sofern als dass die ersten sog. Polling nutzen und das letzte Interrupt

    Polling verursacht mehr CPU Last und ist ungenauer, vor allem wenn es um schnelle Abfragen geht da das Script durch die sleep's blockiert wird in der Zeit also nicht registrieren und auch nichts abarbeiten kann. Keine sleep's zu nutzen würde aber 100% CPU Last verursachen.
    Interrupt hat diese Probleme nicht da die Callback in einem eigenen Thread läuft, also unabhängig vom Script und somit das Script selbst auch noch nebenbei etwas verarbeiten könnte.. Sofern die Callback nicht künstlich ausbremst wird, wird sofort eine Veränderung registriert und verarbeitet.

    Ich empfehle dir das ganze mal mit der elegantesten Möglichkeit zu probieren => queue

    [code=php]
    #!/usr/bin/python3
    import RPi.GPIO as GPIO
    import time
    import queue as Queue # https://pymotw.com/2/Queue/
    from functools import partial
    from threading import Thread

    #------------------------------------------------------------------------
    # use the raspi board pin number
    #GPIO.setmode(GPIO.BOARD)
    # use the gpio number
    GPIO.setmode(GPIO.BCM)

    Taster = 25

    #------------------------------------------------------------------------

    def interrupt_event(qF, qR, pin):
    if GPIO.input(pin) == GPIO.HIGH:
    qR.put(pin)
    else:
    qF.put(pin)

    def rising_edge(queue):
    while running:
    if not queue.empty():
    pin = queue.get()
    zeit = time.strftime("%d.%m.%Y %H:%M:%S")
    print("{} Rising edge detected on {}".format(zeit, pin))
    time.sleep(0.5)

    def falling_edge(queue):
    while running:
    if not queue.empty():
    pin = queue.get()
    zeit = time.strftime("%d.%m.%Y %H:%M:%S")
    print("{} Falling edge detected on {}".format(zeit, pin))
    time.sleep(0.5)

    def main():
    queueFalling = Queue.Queue()
    queueRising = Queue.Queue()
    rising_thread = Thread(target=rising_edge, args=(queueRising,))
    falling_thread = Thread(target=falling_edge, args=(queueFalling,))
    rising_thread.start()
    falling_thread.start()
    GPIO.setup(Taster, GPIO.IN)
    GPIO.add_event_detect(Taster, GPIO.BOTH, callback=partial(interrupt_event, queueFalling, queueRising), bouncetime=200)
    #keep script running
    while True:
    time.sleep(5)


    if __name__ == '__main__':
    try:
    running = True
    main()
    except (KeyboardInterrupt, SystemExit):
    running = False
    print("\nQuit\n")
    GPIO.cleanup()
    [/php]

    Was das macht ist im Prinzip folgendes:
    - es werden zwei Queue's erstellt. Eins für Rising und ein anderes für Falling.
    - es werden zwei Threads gestartet in denen jeweils das Queue verarbeitet wird. Zum Beispiel wird in der "rising_edge" Funktion solange gewartet bis etwas ins queueRising eingetragen wurde.. Man könnte das auch über nur eine Funktion regeln aber für den Anfang sollte das hier verständlicher sein.
    - die Threads prüfen alle 500ms ob etwas im queue steht.
    - sobald ein Flankenwechsel erkannt wird, trägt interrupt_event in das jeweilig zutreffende queue den gpio pin ein.

  • Mich wundert, dass noch keiner genannt hat, dass der Taster wohl prellt. Hast du ein Oszilloskop zur Hand, um das mal zu prüfen? Oder noch einfacher, nimm mal die bouncetime raus und schau, wie viele Flanken der Pi bei einem Öffnen/Schließen der Tür erkennt. Dann kannst du dir ausmalen, dass das Auslesen des aktuellen Zustands in deiner Interrupt-Routine mehr Zufall ist, als Determinismus

  • @ KrawallKurt : Ob der Taster prellt oder nicht spielt nur eine untergeordnete Rolle. Wenn man einen Kontakt schließt ist der GPIO HIGH oder LOW, wie oft das aufgrund des Prell-Effekts zwischendurch wechselt ist für das endgültige Resultat unwichtig denn irgendwann bleibt der Kontakt fest betätigt.....
    Deine Hand mag auf dem Weg zur Tischplatte zittern aber sobald diese auf die Tischplatte gedrückt wird besteht unmittelbarer Kontakt zwischen Hand und Holz -> HIGH. Hebst du die Hand dann langsam wieder hoch, kannst du dabei ruhig zittern dennoch wirst du irgend wann vollständig vom Holz gelöst sein.
    Also muss auch der GPIO einen eindeutigen Zustand darstellen, egal ob etwas prellt. Schließt er die Tür wird der Taster geschlossen und bleibt das auch. Das hat er zumindest auch im ersten Beitrag beschrieben denn der Konsolen Befehl "gpio readall" erkennt dies richtig.

  • Ich habe neulich selbst mal mit prellenden Kontakten erfahrung sammeln muessen. Es war destastroes mit RPi.GPIO. Zumindest fuer meinen Fall - Erkennung von Impulswahlverfahren - war die Software-Entprellung fuer nur einen Flanke brauchbar - aber bei zwei wurde es abenteuerlich. Genauere Diagnose habe ich noch nicht angestellt, aber schon ein erster Versuch mit pigpio hat *deutlich* bessere Ergebnisse geliefert - bei meinen simulierten 500uS Prellungen mittels eines Propeller-uCs habe ich nur mit pipgio vernuenftige Ergebnisse erzielt.

    Nachteil ist natuerlich, dass man dann selbst "entprellen" muss . Ich bin noch nicht dazu gekommen, da mal einen sauberen Filter-Algorithmus fuer zu schreiben. Und es ist natuerlich auch ein etwas aufwendigeres Setup, aufgrund des pigpiod den man laufen lassen muss.

  • rasray: Mit gpio readall wirds mir ja korrekt angezeigt.
    @meigraf: Mit deinem Script 2x Falling Edge beim öffnen der Tür, 1x Falling Edge beim schliessen.
    KrawallKurt: Ich habe zwar kürzlich ein Oszi bekommen, aber mir fehlen noch die Kabel und Tastspitzen dazu.

    Der 10k-Ohm Widerstand ist dazu gedacht, dass das Signal immer LOW ist, wenn die Türe zu ist.
    Der 4,7k-Ohm ist zur Strombegrenzung.

  • Hallo.


    Mich wundert, dass noch keiner genannt hat, dass der Taster wohl prellt. Hast du ein Oszilloskop zur Hand, um das mal zu prüfen? Oder noch einfacher, nimm mal die bouncetime raus und schau, wie viele Flanken der Pi bei einem Öffnen/Schließen der Tür erkennt. Dann kannst du dir ausmalen, dass das Auslesen des aktuellen Zustands in deiner Interrupt-Routine mehr Zufall ist, als Determinismus

    ...und genau deswegen gibt es diese Bouncetime(x).
    Wenn der Taster gedrückt wird wird also die erste steigende Flanke erkannt und alles anderen weiteren für die Zeit (x) ignoriert.
    Beim loslassen ist es eben umgekehrt. Also 1. fallende und fertig.
    ...Taster ist entprellt.

    gruß root

  • Klar ist der Zustand irgendwann stabil. Das Problem ist doch aber, dass er bei Flankenerkennung eine Interrupt-Routine aufruft und in dieser der aktuelle Status des Pins abgefragt wird - nicht, welche Flanke den Interrupt ausgelöst hat. Zum Zeitpunkt der Abfrage muss dieser nicht unbedingt schon stabil sein. Und wenns dann einmal falsch erkannt wurde, wird dank bouncetime die Routine nicht nochmal ausgeführt und u.U. der falsche Status erkannt.

    Einfacher Workaround: Starte doch mal deine Interrupt Routine mit einem einfachen time.sleep(0.5). Soooo oft wird die Tür ja nicht geöffnet und geschlossen werden


    PS: Normal sollte der Pi schnell genug sein, noch vor dem Prellen den Status abzufragen, aber normal macht man das auch direkt und fragt nicht erst die Systemzeit ab, was auch ne Weile dauert - evtl zu lang.

    Einmal editiert, zuletzt von KrawallKurt (5. März 2016 um 13:09)

  • Denkdenkdenk..
    Also die Ursache muss ja in der Flankenerkennung liegen, der statische Zustand "Dauerhaft 0/1" wird ja korrekt ausgelesen.
    Jetzt öffnest du die Tür, der Kontakt schließt sich, Spannung liegt an: sind jetzt wirlich 3,3 Volt am Pin messbar?
    ---
    Krawallkurt ist anscheined der schnellere Tipper....

    Einmal editiert, zuletzt von rasray (5. März 2016 um 13:12)

  • Ja, definitiv messbar 3,3V bei offener Tür, 0V bei geschlossener Tür.
    gpio readall zeigts ja auch richtig an.
    Bouncetime habe ich jetzt auf 500, gleiches Ergebnis.
    Sleep habe ich auch schon geändert, gleiches Ergebnis.
    Was mir jetzt aber noch aufgefallen ist:
    Beim Script für steigende und fallende Flanke wird beim öffnen 2x LOW erkannt und beim schliessen 1x LOW.
    Während beim Script für fallende Flanke nur 1x HIGH beim öffnen und 1x HIGH beim schliessen.
    Sollte ich mal Softwaretechnisch was deinstallieren und neu aufspielen ?
    Vllt. ist ja irgendwo etwas buggy, weil ich bin schon am verzweifeln.

    EDIT:
    Jetzt habe ich mal die Türe geöffnet und den Schalter manuell ganz schnell getriggert, dann wird mir mit dem Script für steigende und fallende Flanke doch tatsächlich ab und zu ein HIGH ausgeworfen:
    low_high.jpg

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!