Schalter für GPIO Emulator programmieren

  • Guten Tag,

    ich bin dabei für die Uni einen GPIO Emulator mit Python zu programmieren.

    Es geht darum eine Ampelschaltung zu simulieren. Dafür habe ich schon einen Schalter zu auslösen programmiert. Nun soll ich laut aufgabenstellung noch einen zweiten Schalter zum beenden der Anwendung erstellen. Das war auch kein Problem. Mein Problem liegt nun darin , dass ich als Vorgabe habe das ganze mit einem Modul und dem Befehl exit() durchzuführen. Ich verstehe nun nicht, was ich tun muss, um den Schalter mit dem Modul bzw dem befehl zu verknüpfen. Wenn ich das ganze mit in die while schleife setze funktioniert die ganze anwendung nicht mehr.

    Schönes Wochenende

    Paul

  • Zur hilfreichsten Antwort springen
  • Warum stellst du die Frage gleich in mehreren Foren?

    Es gibt so diverse Wege nach Rom fuer diese Aufgabe. Der einfachste: benutze add_event_detect fuer deinen Abbruch-Knopf. Im angegebenen Callback rufst du dann sys.exit() auf. Die Randbedingung mit dem Modul verstehe ich nicht.

  • Wusste nicht ob es da gelesen wird. Sorry.

    Habe das jetzt gerade probiert hat leider nicht geklappt.

    Die Aufgabenstellung lautet im Wortlaut:

    "Erstellen Sie einen weiteren Schalter. Beim „Drücken“
    des zweiten Schalter soll das Programm mit dem Befehl
    „exit()“ beendet werden. Dafür benötigen Sie ein
    bestimmtes Modul."

  • Das wird schon gelesen, keine Sorge.

    Und ich habe keine Ahnung was der mit Modul meint. exit ist in __builtins__ drin.

    Die Loesung fuer deine Aufgabe habe ich dir schon genannt. Lies dich ein, wie add_event_detect funktioniert.

    • Offizieller Beitrag

    Die Loesung fuer deine Aufgabe habe ich dir schon genannt.

    paulkannkeininfo Deine Aufgabe hier im Forum ist es nun uns diese Lösung zu zeigen und lies Dir https://www.linux-tips-and-tricks.de/de/linux/212-m…mag-die-keiner/ dazu auch mal durch!

  • @__deets__: Mit Modul wird `sys` gemeint sein, denn das `exit()` auch so erreichbar ist, ist soweit ich weiss nirgends dokumentiert und eigentlich nur da weil das in der Interaktiven Shell verfügbar ist.

    Und es könnte sein dass das mit `add_event_detect()` so direkt nicht funktioniert, weil der Callback in einem anderen Thread ausgeführt wird, und `sys.exit()` funktioniert nur im Hauptthread. Man könnte die Information mit einem `threading.Event` wieder in den Hauptthread kommunizieren und das für die Ampel auch als `sleep()` verwenden, damit das auch die Pausen unterbrechen kann. Ist für einen Anfänger IMHO aber alles ziemlich heftig.

    “Dawn, n.: The time when men of reason go to bed.” — Ambrose Bierce, “The Devil's Dictionary”

  • __blackjack__ :

    hi :) und willkommen im forum ...

    --- wer lesen kann, ist klar im Vorteil ---

    --- man sollte keine Dummheit zweimal begehen, die Auswahl ist schließlich groß genug ---

    --- der Fortschritt der Menschheit ist das Werk der Unzufriedenen ---

    --- Freude entsteht aus Mangel an Information ---

    --- Scheiße ist, wenn der Furz etwas wiegt ---

  • @__deets__: Mit Modul wird `sys` gemeint sein, denn das `exit()` auch so erreichbar ist, ist soweit ich weiss nirgends dokumentiert und eigentlich nur da weil das in der Interaktiven Shell verfügbar ist.

    Und es könnte sein dass das mit `add_event_detect()` so direkt nicht funktioniert, weil der Callback in einem anderen Thread ausgeführt wird, und `sys.exit()` funktioniert nur im Hauptthread. Man könnte die Information mit einem `threading.Event` wieder in den Hauptthread kommunizieren und das für die Ampel auch als `sleep()` verwenden, damit das auch die Pausen unterbrechen kann. Ist für einen Anfänger IMHO aber alles ziemlich heftig.

    Vielen Dank für die nette Antwort. Ich bin absolut neu im Thema Python.. ich habe mich weiter informiert und, sys ist das richtige Modul, da haben Sie recht. Das Programm soll dann mit sys.exit beendet werden. Ich bin mir nur noch nicht ganz sicher wie ich den Befehl nun mit dem Schalter verknüpfe, so dass das Programm bei auslösen des Schalters beendet wird.

  • Wie oft muss man dir das Stichwort "add_event_detect" noch nennen, bis du mal auf die Idee kommst, das wenigestens mal zu probieren?

    Womit __blackjack__ recht hat: einfach nur sys.exit aufrufen wird nicht funktionieren, das war mir nicht bewusst. Du wirst stattdessen zB eine Flagge setzen muessen, die dann in der Hauptschleife ausgewertet wird.

  • Wie oft muss man dir das Stichwort "add_event_detect" noch nennen, bis du mal auf die Idee kommst, das wenigestens mal zu probieren?

    Womit __blackjack__ recht hat: einfach nur sys.exit aufrufen wird nicht funktionieren, das war mir nicht bewusst. Du wirst stattdessen zB eine Flagge setzen muessen, die dann in der Hauptschleife ausgewertet wird.

    Was glaubst du was ich gestern probiert habe? Ich schreibe doch nicht aus Spaß hier rein und suche nach Hilfe.

  • paulkannkeininfo Lass uns doch nicht etwas glauben müssen, sag das konkret. Und nicht nur *das* Du `add_event_detect()` probiert hast, sondern auch wie. Und was ist daraufhin passiert? Wie ist das von Deinen Erwartungen abgewichen? Passierte nichts? Gab es eine Ausnahme? Falls ja, welche?

    Wo kommt eigentlich das `EmulatorGUI`-Modul her? Ist das irgendwo öffentlich zugänglich?

    “Dawn, n.: The time when men of reason go to bed.” — Ambrose Bierce, “The Devil's Dictionary”

  • Ach. Hast du? Woher soll ich (oder sonst wer) das denn wissen? Ich sehe keinen Code, der den Versuch zeigt. Ich sehe auch keine Frage, die sich darauf bezieht. Ich sehe keine Fehlermeldung, die aus den Versuchen resultiert. Alles was zu sehen ist, ist

    Das ist mein Problem. Helft mir.

    Das ist mein Problem. Helft mir.

    Das ist mein Problem. Helft mir.

    Verstreut ueber diverse Unterforen hier, und auch noch im Python-Forum. Es ist genau NULL Auseinandersetzung mit gegebener Hilfestellung erkennbar. Aber pampig, das geht offensichtlich super.

    Zeig, was du versuchst. Nur dann kann dir auch geholfen werden.

  • Okay, ich kann deine Auffassung verstehen, ich setzte mich nochmal mit deinem Tipp add_event_detect ran, vielleicht klappts ja doch.

  • paulkannkeininfo Lass uns doch nicht etwas glauben müssen, sag das konkret. Und nicht nur *das* Du `add_event_detect()` probiert hast, sondern auch wie. Und was ist daraufhin passiert? Wie ist das von Deinen Erwartungen abgewichen? Passierte nichts? Gab es eine Ausnahme? Falls ja, welche?

    Wo kommt eigentlich das `EmulatorGUI`-Modul her? Ist das irgendwo öffentlich zugänglich?

    https://roderickvella.wordpress.com/2016/06/28/ras…-gpio-emulator/

  • Na, da gibt es dann ja ein sehr offensichtliches Problem mit `add_event_detect()`.

    Zudem ist das Modul kaputt. Das mag so aussehen als wenn es funktioniert, aber das lässt a) die Tk-Hauptschleife in einem anderen Thread als dem Hauptthread laufen, und b) verändert es die GUI aus einem anderen Thread heraus als dem in dem die Hauptschleife läuft. Beides ist nicht erlaubt und kann im besten Fall zu komischen Verhalten führen und im schlechtesten Fall zu harten Abstürzen des gesamten Programms.

    “Dawn, n.: The time when men of reason go to bed.” — Ambrose Bierce, “The Devil's Dictionary”

  • Ich habe den Befehl add_event_detected eingefügt.

    Wenn ich den Emulator nun ausführe bekomme ich folgende Fehlermeldung

    AttributeError: type object GPIO has no attribute 'add_event_detected'

    Liegt das vielleicht daran das ich den Befehl an einer vollkommen falschen Stelle eingefügt habe? oder das ich ihn falsch definiert hab?

  • Nein, das liegt daran, das `EmulatorGUI.GPIO` nicht vollständig ist. Das ist halt nicht wirklich geeignet `RPi.GPIO` zu ersetzen oder zu emulieren.

    Das Projekt hier ist ein Fork der die GUI in einem separaten Prozess laufen lässt und auch `add_event_detected()` & Co implementiert hat: https://gitlab.com/shezi/GPIOSimulator

    “Dawn, n.: The time when men of reason go to bed.” — Ambrose Bierce, “The Devil's Dictionary”

    • Hilfreichste Antwort

    paulkannkeininfo : Dein Ansatz würde auf echter Hardware übrigens funktionieren. Das `sys.exit()` hat nur deshalb keine Wirkung, weil sowohl bei `EmulatorGUI` als auch bei `RPiSim` von den jeweiligen Modulen Threads im Hintergrund gestartet werden, die weiterlaufen wenn man den Hauptthread beendet, wodurch man das Programm dann nicht so einfach beenden kann. Wenn man das im `RPiSim` fixt, dann beendet sich das Programm auch normal.

    Ansonsten gäbe es da noch ein paar Anmerkungen zum Quelltext.

    `os` wird importiert, aber überhaupt nicht verwendet.

    Kommentare sollten dem Leser einen Mehrwert über den Code bieten. Was will mir der Kommentar ``# allgemein`` sagen? Faustregel: Kommentare beschreiben nicht was der Code tut, denn das steht da bereits als Code, sondern warum er das so tut. Sofern das nicht offensichtlich ist. Und offensichtlich ist in der Regel auch das was in der Sprachspezifikation und der Dokumentation der verwendeten Module und Funktionen steht. Sonst würde man ja immer die halbe Dokumentation noch mal als Kommentare abschreiben. Wenn jemand nicht weiss was `time.sleep()` macht, kann er in der das in der Doku nachlesen. Und wer bei `GPIO.setwarnings(False)` ohne Dokumentation und ohne den Kommentar ``# Warnungen werden ausgeschaltet`` nicht drauf kommt, dass damit Warnungen ausgeschaltet werden, der sollte besser die Finger vom programmieren lassen.

    Wobei: Die Warnungen sollte man gar nicht ausgeschalten, die haben ja einen Sinn. Wenn da Warnungen kommen, sollte man die Ursache dafür beseitigen. Beim `GPIO`-Modul ist das eigentlich immer die gleiche, einfache Massnahme: wirklich sicherstellen, dass am Ende des Programmablaufs `GPIO.cleanup()` aufgerufen wird.

    Zurück zu den Kommentaren: Da bleibt letztlich nur ein einziger mit Informationsgehalt übrig: ``# Pin 23 wird als Schalter definiert,``. Denn das Pin 23 ein Schalter ist, kann man nicht wirklich am Code ablesen. Allerdings bräuchte man den Kommentar nicht, wenn man die Pin-Nummern nicht als ”magische” Zahlen im Quelltext stehen hätte, sondern Konstanten dafür definiert, die beschreiben wofür der jeweilige Pin steht.

    Ohne sinnvolle Namen kann man als Leser hier nur raten was die Pin-Nummern bedeuten sollen. Da im Beitrag etwas von Ampelschaltung steht, gehe ich einfach mal von einem Fussgängerüberweg mit Taste für Fussgänger aus, die dann die Ampelphasen für den Strassenverkehr schaltet. Wobei da der Ablauf nicht den deutschen Ampelphasen entspricht‽ Und die scheinen „low active“ geschaltet zu sein. (Und der Fussgänger hat verdammt wenig Zeit zum überqueren.)

    Beim `setup()` kann man mehr als einen Pin angeben und auch den initialen Zustand bei Pins zur Ausgabe.

    Man vergleicht nicht mit literalen Wahrheitswerten. Da kommt ja nur wieder ein Wahrheitswert heraus. Entweder der, den man sowieso schon hatte, oder dessen Gegenteil. Im ersten Fall kann man den Wert direkt verwenden. Für das Gegenteil gibt es ``not``.

    Beim schalten der Ampelphasen stehen im Grunde fünf mal die gleichen drei Code-Zeilen im Quelltext. Die unterscheiden sich jeweils nur durch die Pin-Nummer und die Anzahl der Sekunden. Code- und Datenwiederholungen vermeidet man als Programmierer in dem man die Gemeinsamkeiten aus solch ähnlichen Codeabschnitten heraus zieht und dann per Schleife und/oder Funktionsaufrufe einsetzt.

    Wenn man das ganze dann noch in eine Funktion steckt, was man eigentlich immer machen sollte, damit man das Modul auch importieren kann, ohne dass das Programm gleich los läuft, kann man sich das `sys.exit()` auch sparen und einfach die Schleife mit ``break`` verlassen.

    `sys.exit()` sollte man eigentlich nur verwenden wenn man dem Aufrufer mindestens potentiell einen anderen Rückgabecode als 0 mitteilen möchte. Sonst ist das entweder überflüssig, oder gar ein hässlicher Hack weil man eine Abkürzung haben wollte um das Programm zu verlassen, statt sich über einen Programmablauf Gedanken zu machen, der ganz ”natürlich” am Ende der Ausführung ankommt.

    Ungetestet:

    “Dawn, n.: The time when men of reason go to bed.” — Ambrose Bierce, “The Devil's Dictionary”

Jetzt mitmachen!

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