Interrupt ? Event ? für Lirc

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
mollyman
User
Beiträge: 27
Registriert: Samstag 24. Februar 2018, 12:10

Hallo zusammen

ich bin dabei ein Programm zu schreiben, das auf dem Raspberry eine Gui(TKINTER) anzeigt.
In der Gui wird festgelegt wie und wann Servos, Sound und LEDS aktiviert/gestellt/ausgegeben werden.
Das ganze funktioniert sehr gut
Gestartet werden soll der Zyklus über eine Infrarot Fernbedienung.

Dazu habe ich mir passenden Code für Lirc herausgesucht:

Code: Alles auswählen

sockid=lirc.init("black", blocking = False)
 
while True:
    codeIR = lirc.nextcode()
    if codeIR != KEY_OK:
       Training()
Jetzt geht es darum, dass dieser Code unabhängig von der GUI starten soll, wenn ein Signal über den Lirc Socket kommt.
Aber genau da ist mein Problem. ich weiß nicht wie und die google Suchen dazu haben mir nicht wirklich geholfen.
AUs meiner Sicht müsste es mit einem Interrupt laufen, aber wie ?

Danke im voraus
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

also rein prinzipiell du musst halt auf dem Socket lauschen und wenn das richtige Signal reinkommen den Code ausführen. Machst du ja schon im gezeigten Code. Wo ist denn genau den Problem... Kann ich gerade nicht nachvollziehen...

Gruß, noisefloor
mollyman
User
Beiträge: 27
Registriert: Samstag 24. Februar 2018, 12:10

HI

das Problem ist, dass er nicht auf die Signale reagiert während die GUI läuft

Code: Alles auswählen

sockid=lirc.init("black", blocking = False)

def GUI()
     .
     .
     . 
     . Frames, Labels und Buttons usw. 
     while True:
        codeIR = lirc.nextcode()
          if codeIR != KEY_OK:
              Training()

     root.mainloop()
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

du musst ja auch den Code unabhängig von der GUI starten - sagst du ja selber. Da darfst auch in eine GUI nie sowas wie `while True` einbauen. Die Kontrolle muss beim `mainloop()` bleiben, sonst reagiert die GUI nicht.

Also entweder startest du den LIRC-Teil in einem eigenen Skript oder einem eigenen Thread und lässt dann die GUI und den LIRC-Teil über eine Socket, eine NamedPipe, eine Queue, ... miteinander kommunizierten.

Ich denke, ich würde hier einen Thread nehmen und die Queue zur Kommunikation.

Gruß, noisefloor
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Der socket aus der Rückgabe ist ein filedeskriptor. Der benachrichtigt dich, wenn es neue Daten gibt. Dazu einfach den FD mit createfilehandler registrieren für lese-Ereignisse, und im callback dann next aufrufen.

https://docs.python.org/2/library/tkint ... e-handlers
mollyman
User
Beiträge: 27
Registriert: Samstag 24. Februar 2018, 12:10

HI noisefloor

und genau da scheitere ich.
Wie kann ich das machen, dass die Lirc Schleife separat läuft.
Wenn ich die Aufrufe vor der GUI komme ich nicht in die GUI.
Es muss parallel sein aber wie geht das bei Python
mollyman
User
Beiträge: 27
Registriert: Samstag 24. Februar 2018, 12:10

__deets__ hat geschrieben:Der socket aus der Rückgabe ist ein filedeskriptor. Der benachrichtigt dich, wenn es neue Daten gibt. Dazu einfach den FD mit createfilehandler registrieren für lese-Ereignisse, und im callback dann next aufrufen.

https://docs.python.org/2/library/tkint ... e-handlers
Danke, das hört sich gut an. ich schaue mir das gleich an
mollyman
User
Beiträge: 27
Registriert: Samstag 24. Februar 2018, 12:10

mollyman hat geschrieben:
__deets__ hat geschrieben:Der socket aus der Rückgabe ist ein filedeskriptor. Der benachrichtigt dich, wenn es neue Daten gibt. Dazu einfach den FD mit createfilehandler registrieren für lese-Ereignisse, und im callback dann next aufrufen.

https://docs.python.org/2/library/tkint ... e-handlers
Danke, das hört sich gut an. ich schaue mir das gleich an
Ich habe die Anleitung nicht wirklich verstanden.
Es gibt keine Fehlermeldung aber auch keine GUI mehr:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from Tkinter import *
import Tkinter as tk
import time
import pygame
import lirc

.....

# Gui Grundlagen definieren
root = Tk() # Fenster erstellen
root.wm_title("Pistol Shoot Trainer") # Fenster Titel
root.wm_geometry('480x320+0+0')
root.config(background = "#FFFFFF") # Hintergrundfarbe des Fensters

# Socket fuer die Fernbedienung
sockid=lirc.init("black", blocking = False)

....

def Training():
    if Modus == 1:
        ....
        GPIO.output(06, True)
    return
 
def callback(sockid, mask):
    if codeIR == [KEY_OK]:
        Training
    return
     
def GUI():
    rightLabel1 = Label(buttonFrame, text="Pistol Shoot Trainer", font = "Verdana 27 bold", background="#58FA58")
    rightLabel1.grid(row=0, column=0, padx=1, pady=3, columnspan=5)
  ....
    BT42 = Button(buttonFrame, text="Ende",  height=1, width=4, font = "Verdana 12 bold", command=herunterfahren)
    BT42.grid(row=5, column=2, padx=5, pady=5,)

    # File Handler (Descriptor) fuer Socket
    RemoteDaten = tk.Tk()
    mask= tk.READABLE
    RemoteDaten.tk.createfilehandler(sockid , mask, Training())

    root.mainloop() # GUI wird upgedated. Danach keine Elemente setzen

buttonFrame = Frame(root, background="#58FA58")
buttonFrame.grid(row=0, column=0, padx=10, pady=10)        
...
GUI()
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du sollst ja auch einen callback übergeben. Und ihn nicht gleich aufrufen, so wie du es tust. Und Training muss dann natürlich auch die Argumente nehmen dir jeder filedeskriptor callback nimmt.
mollyman
User
Beiträge: 27
Registriert: Samstag 24. Februar 2018, 12:10

__deets__ hat geschrieben:Du sollst ja auch einen callback übergeben. Und ihn nicht gleich aufrufen, so wie du es tust. Und Training muss dann natürlich auch die Argumente nehmen dir jeder filedeskriptor callback nimmt.
Da scheint das Problem zu sein, ich habe offensichtlich nicht verstanden, was ein callback ist. auch das was ich dazu googlen konnte hat mir dabei nicht geholfen.

kannst du das bitte mir erklären
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ein callback ist ein “callable”, also etwas das aufrufbar ist. Wenn du in deiner GUI einen Button haben willst, und der Button soll etwas tun wenn man ihn drückt. Zb einen Hupton abspielen. Dann erzeugst du einen Button in etwa so

button = Button(frame, command=hupen) # Achtung: keine Klammern hinter hupen!

und dann ist hupen dein callback. Wenn der Benutzer auf den Button drückt, dann ruft der Button das command auf. Und weil du eben hupen reingereicht hast, ruft er halt hupen auf.

Das Prinzip ist generalisierbar. Callbacks benutzt man, wenn man Dinge tun will als Reaktion auf ein Ereignis. ZB auch wenn ein LIRC Ereignis reinkommt.

Was du getan hast ist einfach gleich bei Programmstart laut los zu hupen. Und nie wieder aufzuhören. Weil du dienen Callback Training gleich aufrufst mit den () dahinter.
mollyman
User
Beiträge: 27
Registriert: Samstag 24. Februar 2018, 12:10

HI

ok ich glaube es wird jetzt etwas klarer.

Wenn ich das richtig verstanden habe, reagiert dieser Code,

Code: Alles auswählen

RemoteDaten.tk.createfilehandler(sockid , mask, Training)
nur wenn über sockid ein Object kommt und ruft dann die Funktion Training auf .

Das wäre aber falsch, weil ich ja erst prüfen möchte was im Objekt ist.

dann müsste es dann so sein? :

Code: Alles auswählen

def Training():
    if Modus == 1:
        ....
        GPIO.output(06, True)
    return

def callback(sockid, mask):
    if codeIR == [KEY_OK]:
        Training()
    return
....
def GUI():
    RemoteDaten.tk.createfilehandler(sockid , mask, callback)
habe ich das so richtig verstanden ?
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ob das richtig ist weiß ich nicht, weil ich nicht wirklich verstehe was du da machst. Aber der callback sieht besser aus, ja, weil er richtig angegeben ist & auch die zwei notwendigen Parameter bekommt.

Was in dem callback steht sieht aber falsch aus, weil da irgendwelche Namen stehen, die nirgendwo herkommen, und weil der eigentliche aufruf an lirc den du am Anfang noch gezeigt hast auch fehlt.
mollyman
User
Beiträge: 27
Registriert: Samstag 24. Februar 2018, 12:10

HI

zum Programm selbst.
Das ist eine Trainingsanlage, die Lampen (LED) und einen Servo steuert.
Auf der GUI (3,5 Zoll display) habe ich eine Reihe Buttons, mit denen Variablen definiert werden . Damit werden die Zyklen konfiguriert in denen die Servos und LED leuchten.
Das ist z.B. so ein Zyklus Gelbe LED und Servo 90 Grad für 10 Sek dann rote LED und Servo 180 Grad für 7 Sekunden und grüne LED 90 Grad für 3 sekunden und dann weiter mit rote Led und Servo 180 ... 5 Widerholungen.
Der Anwender steht aber 2 m entfernt. daher soll der Zyklus über ein Fernbedienung gestartet werden. Dazu die Einbindung von LIRC.
Der Raspi wird gestartet die GUI wird aufgerufen, der Zyklus definiert und dann geht der Anwende rin Position und startet den Ablauf mit der Fernbedienung.

Sorry ich hatte etwas vergessen:
so ist es "komplett":

Code: Alles auswählen

import lirc
...
sockid=lirc.init("black", blocking = False)
..
    def Training():
        if Modus == 1:
            ....
            GPIO.output(06, True)
        return
     
    def callback(sockid, mask):
        codeeIR = lirc.nextcode()
        if codeIR == [KEY_OK]:
            Training()
        return
    ....
    def GUI():

       # File Handler (Descriptor) fuer Socket
    RemoteDaten = tk.Tk()
    mask= tk.READABLE
    RemoteDaten.tk.createfilehandler(sockid , mask, callback)
Antworten