Callback in Callback-Prozedur aufrufen

  • Hallo Ihr,


    ich definiere für zwei Taster je eine Callback-Prozedur. Wenn eine der beiden Prozeduren in Aktion ist, wird das Ereignis für die zweite Callback-Funktion erst angenommen, wenn die erste Callback-Funktion beendet ist. Offensichtlich lässt Python3 Callbacks innerhalb Callbacks nicht zu. Ist diese Annahme richtig ?


    maksimilian

  • Hallp maksimilian,


    was Du zu suchen scheinst, sind Interrupts bzw. Pseudo-Interupts.


    Kann aber auch sein, dass Deine Callbacks Optimierungspotential in sich bergen.


    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

    • Icon-Tutorials (IDE: Geany) - GPIO-Library - µController-Programmierung in Icon! - ser. Devices - kein Support per PM / Konversation

    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.

  • maksimilian Das hat nichts mit Python zu tun sondern was Du da konkret machst, mit welchem Rahmenwerk und wie das Rückrufe realisiert. Ob das alles im Hauptthread läuft, oder in *einem* zusätzlichen Thread, oder ob es einen Thread pro Rückruf gibt.

    “If debugging is the process of removing software bugs, then programming must be the process of putting them in.” — Edsger Dijkstra

  • Ich verwende (mangels Kenntnis noch) keine Threads. Ich habe versucht, außerhalb einer Callback-Funktion als auch innerhalb des Ablaufs einer Callback-Funktion eine weitere zu definieren. Diese Funktionen werden offensichtlich in einen Stack gelegt. Es erfolgt kein sofortiger Aufruf der zweiten Funktion.

    Was unterscheidet Callbacks von Interrupts ?


    Ich versuche ein Problem in meinem aktuellen Projekt zu umgehen, was darin besteht, dass GPIO.input() Abfragen von Pins unsicher sind. Wechselnde Pegel an den entsprechenden Pins funktionieren zur Signalisierung aber einwandfrei.

  • Du verwendest threads. Du weißt es nur nicht. Die callbacks werden aus EINEM Hintergrund-Thread bedient. Wenn du den anderweitig blockierst bzw. benutzt, statt nur ein Signal an den Main thread zu wenden (zb über den hier schon 1000 & 1-mal besprochenen Queue-Mechanismus), dann ist ein solches Verhalten erwartbar. Und was hyle sagt.

  • im falschen Forum.

    Sag sowas nicht, dann wäre ich ja auch falsch hier und das nach dem es mir hier so gefällt :-/

    Das Forum ist super um zu lernen, egal ob Programmierung, Elektronik oder den Umgang mit Linux und was sonst noch dazu gehört.


    Ich denke du hast die Antwort von @__deets__ falsch verstanden, darin stecken doch nützliche Informationen für dein Problem.

    Bleib am Ball :thumbup:


    Grüße

    Dennis

    🎵🎸Die Nordsee schlägt dir ins Gesicht, trotzdem hast du verloren, du bist nicht weit gekommen, du läufst weiter nach vorn 🎵🎸

  • maksimilian Die Beschreibung ist mir zu abstrakt. Zeige mal bitte ein konkretes Beispiel dazu, was zu Problemen führt!

    Ich versuche, ausgehend von speziellen Problemen Prinzipien und Konzepte zu begreifen, was bei meinen Formulierungen wohl manchmal zu abstrakt klingt.

    Also konkret (leider wird's lang): Ich habe eine Falltür, an welcher sich am unteren Rand ein Magnet befindet. Dieser bewegt sich mit der Tür an zwei übereinander im Abstand der Türhöhe am Türrahmen angebrachten Reed-Kontakten vorbei. Diese sollen den Bewegungsspielraum der Tür begrenzen. Es gibt nun zwei Möglichkeiten, das Ansprechen eines Reed-Kontaktes festzustellen: einmal durch Abfrage des Spannungspegels des mit dem Kontakt verbundenen GPIO Pins (GPIO.input() ) und zum anderen duch die Definition einer Callback-Prozedur (add-event-detect() ). Ich möchte die zweite Lösung ausprobieren.

    Ich erzeuge im steuernden Python-Skript eine Zeit-Schleife, in welcher auf Ereignisse wie z.B. Betätigen eines Öffnen-Tasters über Callback reagiert werden soll. Innerhalb des Ablaufs der als Beispiel genannten Öffnen-Callback-Funktion wird eine weitere Callback-Funktion definiert, welche in einer inneren Zeit-Schleife sofort auf den Wechsel des Spannungspegels am Reed-Kontakt reagieren soll, um dann die Bewegung der Tür zu stoppen.

    Ich hoffe das geschilderte Problem ist ausreichend konkret und verständlich formuliert worden.

    • Official Post

    maksimilian Oh, da war mein Satz vermutlich auch zu abstarkt formuliert. Sorry! Gemeint mit "konkretem Beispiel" war eigentlich ein kurzer Pythoncode zum Drüberschauen, über den man diskutieren und ggf. Fehler aussieben könnte.

    Danke trotzdem für die komplette geschriebene Problemstellung!


    Ich denke übrigens auch, dass Du da etwas in den falschen Hals bekommen hast, was so nicht gemeint war. ;)

  • maksimilian Das verschachteln wäre auch nicht gut wenn das gehen würde. Alleine das `add_event_detect()` sollte man schon nicht wirklich ”dynamisch” machen sondern genau einmal für alle Ereignisse auf die man reagieren möchte. Denn sonst darf so etwas nur einmal passieren. Andernfalls würde man immer wieder neue Rückrufe registrieren oder man müsste die entsprechende Funktion zum entfernen einen Rückrufs verwenden — was bei GPIO meiner Erfahrung nach regelmässig unregelmässig zu Problemen führt. Die `gpiozero`-Bibliothek ist da robuster und hat IMHO auch die deutlich bessere API.

    “If debugging is the process of removing software bugs, then programming must be the process of putting them in.” — Edsger Dijkstra

  • maksimilian Das verschachteln wäre auch nicht gut wenn das gehen würde. Alleine das `add_event_detect()` sollte man schon nicht wirklich ”dynamisch” machen sondern genau einmal für alle Ereignisse auf die man reagieren möchte.

    Es funktioniert aber in meinem Beispiel nicht, wenn anfangs alle Callbacks deklariert werden, weil dann der Aufruf eines inneren Callbacks erst recht nicht sofort wirkt. Mit Hilfe von GPIO.remove_event_detect() ließe sich der Wirkungsbereich einer Callback-Funktion kontrollieren.

    Ich habe mich mit gpiozero noch nicht näher beschäftigt, glaube aber nicht, dass es da anders ausschaut, weil es sich wohl um ein konzeptionelles Problem bei der Kombi Python/Pi handelt.

  • Ich habe mich mit gpiozero noch nicht näher beschäftigt, glaube aber nicht, dass es da anders ausschaut, weil es sich wohl um ein konzeptionelles Problem bei der Kombi Python/Pi handelt.

    Eher um ein konzeptionelles Problem deines Denkmodells.


    Das Problem ist, dass du nicht genau sagst, was du machen willst, sondern einen Weg beschreibst, von dem du denkst, er sei der richtige Weg.

  • Wenn _deets_ darauf hinweist, dass Callbacks in einem Thread ablaufen, dann wäre das für mich vielleicht eine Spur, die ich verfolgen sollte.


    Kann man das irgendwo nachlesen, wie Callbacks vom Betriebssystem/Python verarbeitet werden ?

  • Wie viele Ebenen möchtest du graben? Unter Linux werden von Python POSIX Threads genutzt. Es sind echte Threads.

    Ein Callback impliziert nicht, dass dieser durch einen anderen Thread aufgerufen wird.


    Bei gpiozero bzw. RPi.GPIO ist es ein Thread, der den Callback aufruft.


    Callbacks sehr stark vereinfach ohne Threads:

    Code
    def greeter(text, callback):
        callback(text)
    
    # print ist auch eine Funktion
    # Funktionen können wie andere Objekte
    # an Funktionen übergeben werden    
    greeter("Hello World", print)


    Im Fall von Threaded Code, wird der Callback von einem anderen Thread aufgerufen. Es gibt den Main-Thread, der immer läuft und threading.Thread erstellt neben dem Main-Thread weitere Threads.


    Du kannst dir z.B. den Quellcode von RPi.GPIO laden: https://sourceforge.net/projec…PIO-0.7.0.tar.gz/download


    In RPi.GPIO-0.7.0/source/event_gpio.c ist in Zeile 455 add_edge_detect definiert und dort werden auch die Threads erstellt, falls ich jetzt nicht völlig daneben liege.

  • maksimilian Ich weiss jetzt nicht was Du mit „innerem Callback meinst“. Ich habe beschrieben wie man das macht: Mit `add_event_detect()` am Anfang des Programms entsprechende Handler registrieren. Nicht irgendwann ”wenn man sie braucht”. Weil: `remove_event_detect()` funktioniert erfahrungsgemäss nicht zuverlässig. GPIO ist alt. Hässlich. Kaputt. Scheisse. Nimm `gpiozero`.


    Das hat auch alles nichts mit der Kombination von Python und Raspi zu tun. Man kann in Python alle möglichen Varianten von Callbacks, mit und ohne Thread, mit einem oder mit mehreren Threads programmieren. Der Raspi ist in der Hinsicht einfach ein Linuxrechner wie jeder andere auch.


    Und auch bei `gpiozero` würde ich die Callbacks nicht immer registrieren und wieder de-registrieren (gibt's das Wort?). Verwalte Zustände explizit, mit passenden Namen und nicht implizit darüber wofür gerade ein Callback registriert ist oder nicht.

    “If debugging is the process of removing software bugs, then programming must be the process of putting them in.” — Edsger Dijkstra

  • Hallo DeaD_EyE, jetzt wird's ernst :) Danke für Deine fachliche Antwort. Die genauesten Antworten auf Fragen zu Abläufen im System erhält man natürlich immer (bei entsprechender Vorbildung!) durch Studium des Sourcecodes. Du hast mir dafür schon mal einen Ansatz geliefert. Nun muss ich aufpassen, dass ich nicht den dritten Schritt vor dem ersten tue und mir erst einmal Grundlagen verschaffe. Es war schon länger meine Absicht, mich mit dem Thema "Parallele Programmierung" zu beschäftigen. Nun muss ich mir einen Ruck geben und es endlich tun. Das bedeutet sicher, dass ich (zumindest zu diesem Thema) für einige Zeit in Schweigen verfallen werde.

  • GPIO ist alt. Hässlich. Kaputt. Scheisse. Nimm `gpiozero`.

    Das ist drastisch formuliert (ich denke, hyle wird es trotzdem gerne lesen). Es ist ja leider immer noch so, dass in der Literatur zum Pi bei der Behandlung von Python mit GPIO gearbeitet und evtl. nebenbei auf gpiozero hingewiesen wird. Und wenn man sich als Anfänger anhand der Beispiele einarbeitet, bleibt man auch erst mal da hängen bis bei fortgeschritteneren Aufgaben die Probleme auftreten. Ich hatte auch schon an anderer Stelle festgestellt, dass bei mir ein Umdenken stattfinden muss. Da sollte ich wohl meine Ungeduld zügeln und beim aktuellen Projekt inne halten.

    • Official Post

    ich denke, hyle wird es trotzdem gerne lesen

    :lol:


    Ich habe Dir nicht umsonst schon öfter und nicht nur in diesem Forum zu gpiozero geraten.


    Ich hatte auch schon an anderer Stelle festgestellt, dass bei mir ein Umdenken stattfinden muss.

    Das ist der richtige Ansatz! :thumbup: Und da gpiozero sehr gut dokumentiert ist, geht das ganz schnell.

  • Das ist drastisch formuliert (ich denke, hyle wird es trotzdem gerne lesen). Es ist ja leider immer noch so, dass in der Literatur zum Pi bei der Behandlung von Python mit GPIO gearbeitet und evtl. nebenbei auf gpiozero hingewiesen wird.

    Letztendlich wird RPi.GPIO von gpiozero verwendet. Andere Backends funktionieren aber auch mit gpiozero.

    Es ist ein schöner Wrapper um diese Low-Level Bibliotheken herum.


    Wenn man gpiozero bzw RPI.GPIO mit callbacks/event-detection nutzt, wird durch die Bibliothek im Hintergrund automatisch ein Thread gestartet.

    D.h. darum muss man sich nicht unbedingt kümmern.