button.wait_for_press() wartet nur einmal

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Hallo,

    ich wollte mir ein Skript schreiben, dass bei Knopfdruck ein Video aufnimmt, bei erneutem Knopfdruck das Video stoppt und dann, durch eine Dauerschleife, beim nächsten Knopfdruck wieder ein Video aufnimmt.

    Aber leider wird beim zweiten Knopfdruck das erste Video beendet und gleichzeitig das zweite gestartet. Kann mir jemand einen Tipp geben, was ich falsch gemacht habe?

    Gruß, Tom

  • Als Tipp vorweg: Innerhalb der Schleife Konstanten wie filePath immer wieder aufs neue zu setzen ist Quatsch.

    Allgemein etwas mehr Struktur wär gut, zB eine Variable "Dunkelheit" zu nennen ist etwas verwirrend, insbesondere dann wenn "Dunkelheit.on()" geschaltet wird :D

    Wenn deine while Schleife nicht erneut von Vorne beginnt dann tritt während des ersten Ablaufs ein Fehler auf und beeinflusst dadurch dessen Bedingung.

    Deine Schleife rotiert zum Schluss ungebremst, dh der letzte "press" könnte noch vom ersten als solches erfasst werden. Abhilfe: Kurze Blockade.

  • Hallo,

    Denke auch, dass du den Button zu lange drückst und der immer noch gedrückt ist, wenn das 1. `when_pressed` erreicht ist. Abhilfe: danach ein `when_released` einbauen. Noch besser: kein Polling, sondern Event-getrieben programmieren.

    Ansonsten:

    • Variablen- und Funktionsnamen werden per Konvention klein_mit_unterstricht geschrieben.
    • Dateinamen baut man mit `os.path.join()` zusammen, nicht mit `+`
    • `Dunkelheit` als Variablenname ist ein bisschen schräg - zumal man Dunkelheit nicht an schalten kann... Warum nennst du die Variable nicht `lampe` - treffender. Außerdem ist Dunkelheit der einzige deutsche Variablennamen - normalerweise macht man das einheitlich, also alles deutsch oder alles englisch.

    Gruß, noisefloor

    Edit: meigrafd war schneller :)

    Einmal editiert, zuletzt von noisefloor (28. Januar 2018 um 21:39) aus folgendem Grund: Denke, nicht danke...

  • Danke auch, dass du den Button zu lange drückst und der immer noch gedrückt

    Oh man, natürlich ^^ Oops.

    `Dunkelheit` als Variablenname ist ein bisschen schräg - zumal man Dunkelheit nicht an schalten kann... Warum nennst du die Variable nicht `lampe` - treffender.

    Hatte ich vorher auch, aber dann war lampe.on() = Licht aus und lampe.off() = Licht an. Daher erschien es mir so logischer. Und so konnte ich gewissermaßen tatsächlich die Dunkelheit "anschalten" :D
    Ich habe die Lampe am Relais so angeschlossen, dass es im "Grundzustand" nicht verbunden ist. Da mir auch das so am logischsten schien, weil die Lampe die meiste Zeit aus ist.

    Noch besser: kein Polling, sondern Event-getrieben programmieren.

    Das sagt mir leider noch nichts :saint:Bin noch am lernen. Mit was für commands programmiere ich denn event-getrieben? Dann kann ich mal googlen und mich weiterbilden. Ist das Stichwort: Threading? ^^ Sonst weiß ich es noch nicht. Wobei ich threading auch noch nicht kann :P

    Danke für die Hilfe.

    Gruß, Tom

  • Hallo,

    Zitat


    Mit was für commands programmiere ich denn event-getrieben?

    Mit gpiozero geht das. Die `Button` Klasse kennt `button.when_pressed = do_something` Dann wird beim Druck auf den Taster die Funktion `do_something` aufgerufen. Ist aber auch in der Doku von gpiozero erklärt.

    Zitat

    Ist das Stichwort: Threading?

    Nein. Threads braucht man (bzw. kann man einsetzen), wenn man mehrere Sachen parallel machen will / muss.

    Gruß, noisefloor

  • Mit gpiozero geht das. Die `Button` Klasse kennt `button.when_pressed = do_something` Dann wird beim Druck auf den Taster die Funktion `do_something` aufgerufen. Ist aber auch in der Doku von gpiozero erklärt.

    Achso, ja das kenne ich schon. Ich dachte "Event-getrieben" wäre noch was anderes ^^

    Dann ersetze ich einfach button.wait_for_press() mit button.when_pressed() erstelle vorher ein def und experimentiere ein bisschen damit rum.

    Danke nochmal. Gruß, Tom

  • So könnte es aussehen wenn beim drücken des Button mehrere Sachen auf ein mal ausgeführt werden sollen, ohne dafür extra eine Funktion zu definieren. Allerdings deckt das nicht dein Szenario ab, da das drücken an sich keinen Zustand ändert also kein Flag gesetzt und somit Schaltzustände nicht unterschieden wird.

    Wenn du nun daher gehst und 2 Funktionen deklarierst, achte auf eben diese Problematik die dir begegnen wird. Fortgeschritten Programmierer versuchen ohne global aus zukommen.


    PS: Dein verdrehtes Problem mit on() und off() hab ich oben evtl. auch gelöst... Aber ob die von Dir gewählte Methode überhaupt die richtige ist? :conf:

    http://gpiozero.readthedocs.io/en/stable/api_…taloutputdevice Vs. http://gpiozero.readthedocs.io/en/stable/api_…ml#outputdevice

    schließen tuste das auch nirgends - auch hier hast du noch Nachholbedarf.

  • Aber ob die von Dir gewählte Methode überhaupt die richtige ist?

    Ja, das weiß ich auch nicht. ^^ Mir wurde hier im Forum empfohlen für ein Relais DigitalOutputDevice zu nehmen.

    Hätte ich das nicht tun sollen?

    schließen tuste das auch nirgends - auch hier hast du noch Nachholbedarf.

    schließen? =O Verstehe ich nicht. Ich hatte das so verstanden, dass ich auf das Relais Spannung gebe, damit der Kontakt da ist und Strom durchfließt. Und eben kein Strom fließt wenn am GPIO-Pin keine Spannung anliegt.

    Was muss ich denn nun noch schließen?

  • Ja, das weiß ich auch nicht. Mir wurde hier im Forum empfohlen für ein Relais DigitalOutputDevice zu nehmen.

    Da steht "lässt vermuten" :fies:

    DigitalOutputDevice ähnelt OutputDevice stark... Ersteres unterstützt aber "blink", was du hier aber vermutlich nicht nutzen willst, daher würde ich letzteres nutzen ;)

    Wollte nur sicherstellen dass du dir des Unterschied bewusst bist - und die Konfigurationsmöglichkeit der Methode(n) gelesen hast :S

    Bezüglich Relais schalten siehe zB auch https://gist.github.com/johnwargo/ea5edc8516b24e0658784ae116628277

    schließen? Verstehe ich nicht.

    Die .close() Methode von gpiozero entspricht .cleanup() von RPi.GPIO. Was es damit auf sich hat kannst du der Doku entnehmen :angel:

    Normalerweise nutzt man das wie folgt:

    with kümmert sich selbstständig ums schließen.

  • Was es damit auf sich hat kannst du der Doku entnehmen

    Also, ich versuche mal das zu verstehen. Ich schließe z.B. das DigitalOutputDevice, damit es nicht zu Prolemen kommt, wenn in einem anderen Skript dasselbe DigitalOutputDevice am selben Pin genutzt wird, richtig?

    Das bedeutet für mein Skript aus Beitrag #1, dass ich am ende camera.close() und Dunkelheit.close() hinzufügen sollte. Dementsprechend müsste ich vermutlichcamera = picamera.PiCamera() etc. mit in die Dauerschleife reinziehen.

    Sehe ich das richtig, dass es bei OutputDevice und LED kein .close() gibt. Schließe ich das dann gar nicht?

    Gruß, Tom

  • kannst du mir sagen für welche meiner drei Fragen das nein gilt und für welche evlt. ja

    Ich schließe z.B. das DigitalOutputDevice, damit es nicht zu Prolemen kommt, wenn in einem anderen Skript dasselbe DigitalOutputDevice am selben Pin genutzt wird, richtig?

    Das bedeutet für mein Skript aus Beitrag #1, dass ich am ende camera.close() und Dunkelheit.close() hinzufügen sollte.

    Dementsprechend müsste ich vermutlichcamera = picamera.PiCamera() etc. mit in die Dauerschleife reinziehen.

    Sehe ich das richtig, dass es bei OutputDevice und LED kein .close() gibt. Schließe ich das dann gar nicht?


    Sehr gerne eine Antwort a la:

    1.ja 2.nein 3.nein 4.doch

    und dann mache ich mich auf neu zu überlegen ;)

  • 1. Nein. Das .close() gibt die Ressource wieder frei, dh die Werkseinstellung des jeweiligen GPIO's wird gesetzt.

    2. & 4. Nein. Jede Verknüpfung solltest du mit .close() am Ende des Scripts abhandeln, das gilt für sowohl DigitalOutputDevice als auch light, button und led usw..

    3. Das wäre eine sehr schlechte Idee. picamera.PiCamera() brauch nur ein mal initialisiert und das Objekt mit einer Variablen verknüpft werden.

  • Nein. Das .close() gibt die Ressource wieder frei, dh die Werkseinstellung des jeweiligen GPIO's wird gesetzt.

    achso, ich hatte es erst so verstanden, dass ledR = LED(16) durch ledR.close() "rückgängig" gemacht wird und man es wieder neu definieren müsse. Aber das scheint ja dann nicht zu passieren ^^

    Ich habe mein Skript, so wie ich es bisher kann, einmal beispielhaft aufgeschrieben. Mit dem schließen ist so alles in Ordnung, oder?

    Soll ich es lieber eventgetrieben schreiben oder soll ich es einfach so lassen, weil es ja einfach von Vorne bis Hinten durchlaufen soll und dann ist gut.

    ich hatte jetzt alternativ an eine definition gedacht:

    def main(videos, pause, routine): ...

    und danach main(3,20,bb1) 

    auf Knopfdruck warten

    main(4,25,bb2) ...

  • achso, ich hatte es erst so verstanden, dass ledR = LED(16) durch ledR.close() "rückgängig" gemacht wird und man es wieder neu definieren müsse. Aber das scheint ja dann nicht zu passieren

    Doch so passt es. Zuvor hast du es aber nicht so beschrieben:

    Ich schließe z.B. das DigitalOutputDevice, damit es nicht zu Prolemen kommt, wenn in einem anderen Skript dasselbe DigitalOutputDevice am selben Pin genutzt wird, richtig?

    ...Wenn eins der beiden Script .close() setzt während das andere noch darauf zugreifen will aber nicht erneut initialisiert, gibts nen Fehler.... Der eine pumpt Luft auf, der andere lässt es wieder ab.

    Soll ich es lieber eventgetrieben schreiben oder soll ich es einfach so lassen

    ..das wurde hier schon beantwortet :fies:

    Du hast schon wieder eine falsche Platzierung deiner Abläufe... Sachen die nicht abhängig vom drücken des buttons relevant sind solltest du vorher setzen, nicht erst dann wenn der button gedrückt wird.

    Davon abgesehen wurde hier auch schon was zu os.path.join() geschrieben... Auch in deinem aktuellen Script solltest du das nutzen.

  • Ich würde dir gerne noch erklären, warum ich es falsch verstanden habe.

    Doch so passt es. Zuvor hast du es aber nicht so beschrieben:

    Ich haber aber das geschrieben.

    Dementsprechend müsste ich vermutlich camera = picamera.PiCamera() etc. mit in die Dauerschleife reinziehen.

    Wenn ich an's Ende der Dauerschleife aus Beitrag #1 beispielsweise button.close() schreibe, weiß das Skript am Anfang der Dauerschleife doch nicht mehr was es ist. Also muss ich es doch wohl mit hineinziehen.

    Das habe ich damit gemeint (etc.) und daher meine Schlussfolgerung.

    Davon abgesehen wurde hier auch schon was zu os.path.join() geschrieben

    Das habe ich ja versucht. Auch gemacht.

    1. camera.start_recording(os.path.join(filePath, routine, datetime.now().strftime("%Y.%m.%d"), end))

    Du sprichst sicher von end = 'Video_' + str(i+1) + '.h264'. Ich habe es leider nicht geschafft das zusammenzufügen ohne, dass ein "/" zwischen jedem Term steht.

  • Du sprichst sicher von end = 'Video_' + str(i+1) + '.h264'. Ich habe es leider nicht geschafft das zusammenzufügen ohne, dass ein "/" zwischen jedem Term steht.

    Klar. os.path.join soll ja auch Pfade bilden bzw. zusammenfügen.

    konstanten schreibt man bitte groß, keine Variablen camelCase, sondern mit_unter_strichen. Dank os.path.join brauchst du in BB* keinen /.

Jetzt mitmachen!

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