Tastaturabfrage, während Script weiterläuft

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

    da ich jedesmal, wenn ich meinen RasPi neu aufsetze (passier eher selten ;)), vergessen habe, an welchem Pin mein Taster angeschlossen ist, lese ich mit

    Code
    gpio redall


    die Pins aus, drücke den Taster und lese nochmal aus. Aber in dem Wust im Terminal die Änderung zu finden, ist mühsam.
    Also schnell ein Script geschnitzt, das den "gpio readall" immer im Kreis rum ausführt.

    Code
    !/bin/sh
    
    
    clear                                     #Bildschirm leeren
    tput home                                 #Cursor auf position 0:0 setzen
    while true
      do
       gpio readall                           #GPIO auslesen und anzeigen
       tput home
      done


    Dieses Script kann ich dann nur mit Ctrl-C beenden.
    Ich würde es aber gerne mit "q" beenden.
    Als Eingabemöglichkeit habe ich folgendes gefunden:

    Code
    stty raw -echo
    INPUT=`dd count=1 bs=1 2> /dev/null`
    stty -raw echo

    Beides zusammen geklöppelt (mit trivialer Änderung der Schleife von while auf until):


    Leider wartet mein Script jetzt beim "dd count ..." immer noch auf einen Tastendruck. :baeh2:
    Ich kann es zwar laufen lassen mit einem Druck auf irgendeine Taste außer "q", aber ich würde es halt gerne dauerhaft ohne Tastendruck laufen lassen.

    Hat einer von Euch eine Idee (oder noch besser eine Lösung)? :bravo2:

  • Hast du denn sonst noch was an die GPIO's angeschlossen?
    Ich würd sonst einfach dazu übergehen und alle GPIO's auf Input zu schalten und wenn du den Taster drückst zeigt er dir welcher GPIO das ist ;)

    Das ließe sich relativ einfach mithilfe von Python und Interrupts umsetzen, ansonsten wenns denn unbedingt bash sein muss auch damit, nur etwas umfangreicher :D

    Wie hast du den Taster angeschlossen? GPIO -> GND oder GPIO -> 3V3 ?

    //EDIT: Hier ein bash Script:


    reagiert aber nur wenn GPIO -> 3V3

    Würde aber Python mit Interrupts bevorzugen ;)


  • Hast du denn sonst noch was an die GPIO's angeschlossen?


    Nur ein paar LED. Die werden aber (nach einer Neuinstallation ohne zusätzliche Programme) sowieso nicht angesprochen.


    Ich würd sonst einfach dazu übergehen und alle GPIO's auf Input zu schalten und wenn du den Taster drückst zeigt er dir welcher GPIO das ist ;)


    Mach ich doch (sozusagen). Lieferzustand der Pins ist in, "gpio readall" liest aus.


    Das ließe sich relativ einfach mithilfe von Python und Interrupts umsetzen, ansonsten wenns denn unbedingt bash sein muss auch damit, nur etwas umfangreicher :D

    Janee, is' klar. Nur ein paar klitzekleine Interrupts. Schüttel ich doch mal eben so aus dem Ärmel. :auslachen:
    Im Ernst, Interrupts habe ich noch nicht wirklich verstanden. Prinzip ja, Umsetzung nein.
    Wobei, wenn Du mir natürlich das mit den Interrupts auf dem Silbertablett mit Sahnehäubchen und Kirsche obendrauf servierst, sag' ich nicht nein. flag_of_truce.gif


    Wie hast du den Taster angeschlossen? GPIO -> GND oder GPIO -> 3V3 ?


    GPIO -> GND mit Strombegrenzungswiderstand gegen zu großen Strom bei versehentlicher Schaltung des GPIO als Ausgang/High und externem Pullup.

    EDIT: Deine Edith hat noch ein Programm nachgeliefert. Meine Edith ist daraufhin umgekippt, weil sie nix kapiert.
    Hättest Du evtl. noch so ein bis zwei Kommentare dazu (# im Script)?

    Einmal editiert, zuletzt von Oerks (5. Februar 2015 um 01:24)

  • Wer brauch schon Kommentare :lol:

    Vielleicht reicht das?


    gpio -g wfi $gpio both
    wait for interrupt ... wenn also auf dem pin ein interrupt ausgelöst wird, wird der befehl beendet und die echo zeile vom temp script wird ausgegeben, was dann den gpio pin echo'd

    ansonsten bitte gezielt fragen was du nicht verstehst :fies:


    //EDIT: Und hier das ganze als Python Script :fies:

    [code=php]
    #!/usr/bin/python
    import RPi.GPIO as GPIO
    import time
    import signal

    RaspiRevision = GPIO.RPI_REVISION
    if RaspiRevision == 1:
    GPIOpins = [0,1,4,17,21,22,10,9,11,18,23,24,25,8,7]
    elif RaspiRevision == 2:
    GPIOpins = [2,3,4,17,27,22,10,9,11,18,23,24,25,8,7]

    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BCM)

    for gpin in GPIOpins:
    GPIO.setup(gpin, GPIO.IN, pull_up_down = GPIO.PUD_DOWN) #GPIO -> GND
    # GPIO.setup(gpin, GPIO.IN, pull_up_down = GPIO.PUD_UP) #GPIO -> 3V3

    def Interrupt_event(pin):
    Zeit = time.asctime()
    print("{} -> GPIO {} ausgeloest!".format(Zeit, pin))

    try:
    for gpin in GPIOpins:
    GPIO.add_event_detect(gpin, GPIO.RISING, callback=Interrupt_event, bouncetime=100)
    #keep script running
    signal.pause()
    except KeyboardInterrupt:
    print("\nQuit\n")

    GPIO.cleanup()
    [/php]


  • Wer brauch schon Kommentare :lol:


    Na bitte, geht doch. :bussi2:

    Soweit verstehe ich es schon. Du erstellst für jeden Port ein eigenes Script, das im Hintergrund läuft und die Pin-Nummer ausgibt, wenn der Pin auf high schaltet. Das Hauptscript bleibt bei der "pause" stehen und wartet auf die Eingabe.
    Hmmm, ist natürlich auch eine Möglichkeit.
    Ich könnte das vielleicht bei mir so lösen, daß ich den "gpio readall" auch auslagere und das Hauptscript wie bei Dir auf eine Pause laufen lasse.
    Werde ich mal probieren.
    Danke schonmal dafür.:bravo2:

    Code
    #execute when this script exits. kill temp scripts and cleanup
    function finish() {
    	for pid in $(pidof gpio); do
    		kill -9 $pid >/dev/null 2>&1
    	done
    	rm -rf /tmp/sg
    }
    trap finish EXIT

    ansonsten bitte gezielt fragen was du nicht verstehst :fies:

    Den Teil mit dem "pidof" und "trap" muß ich mir nochmal genau anschauen.
    Vielleicht frag ich danach nochmal genauer.

    Dennoch interessiert mich, ob es innerhalb eines Scripts möglich ist, die Tastatur abzufragen, ohne daß das Script stoppt.

    EDIT: Das Python-Script schaue ich mir an, wenn mein Hirn wieder etwas entraucht ist. Mir reicht erstmal bash. :lol:

    Einmal editiert, zuletzt von Oerks (5. Februar 2015 um 01:57)

  • trap wird ausgeführt wenn ein entsprechendes Signal in dem Script auftritt. Siehe dazu: man signal
    Wenn also das Script mit EXIT beendet wird, wird die finish Anweisung ausgeführt.
    pidof ermittelt alle PID's des angegebenen Prozesses, also in diesem Fall ' gpio ', was von den temporären Script gestartet wurde. Werden diese Prozesse beendet wird auch das temporäre Script beendet.


    Ich glaub eine andere Möglichkeit, mitten im Script auf eine Tastatureingabe zu reagieren, als die die Du genannt hast, gibt es nicht.

    Eine Kombination von Deinem und meinem Script wäre vermutlich die einzig machbare Lösung mit bash.
    bash ist halt nicht Multithread fähig, zumindest nicht in nur einem Script. Nicht so wie es bei Python eben der Fall ist bzw werden dort die "add_event_detect" über einen separaten Thread ausgeführt (aber nur einer) und somit unabhängig vom Hauptscript.

    Ich denke der Einfachkeitshalber solltest du das Python Script verwenden, zumal das eben keine temporären Scripts anlegen muss usw :fies:
    Da kannst du dann einbauen das es auf speziell der Taste ' q ' reagiert und das Script beendet:

    [code=php]
    #!/usr/bin/python
    import RPi.GPIO as GPIO
    import time, curses

    RaspiRevision = GPIO.RPI_REVISION
    if RaspiRevision == 1:
    GPIOpins = [0,1,4,17,21,22,10,9,11,18,23,24,25,8,7]
    elif RaspiRevision == 2:
    GPIOpins = [2,3,4,17,27,22,10,9,11,18,23,24,25,8,7]

    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BCM)

    for gpin in GPIOpins:
    GPIO.setup(gpin, GPIO.IN, pull_up_down = GPIO.PUD_DOWN) #GPIO -> GND
    # GPIO.setup(gpin, GPIO.IN, pull_up_down = GPIO.PUD_UP) #GPIO -> 3V3

    def Interrupt_event(pin):
    global stdscr
    stdscr.addstr(2, 20, ""+time.asctime()+" -> GPIO "+str(pin)+" ausgeloest!")
    stdscr.refresh()

    def _exit():
    stdscr.keypad(0)
    curses.nocbreak()
    curses.echo()
    curses.endwin()
    GPIO.cleanup()

    try:
    #for KeyPress Events
    stdscr = curses.initscr() #init curses
    curses.cbreak() #react on keys instantly without Enter
    curses.noecho() #turn off echoing of keys to the screen
    stdscr.keypad(1) #returning a special value such as curses.KEY_LEFT
    stdscr.addstr(0, 10, "Hit 'q' to quit") #display text on pos y, x
    for gpin in GPIOpins:
    GPIO.add_event_detect(gpin, GPIO.RISING, callback=Interrupt_event, bouncetime=100)
    running = True
    while running:
    key = stdscr.getch()
    stdscr.refresh()
    if key == ord('q'):
    stdscr.addstr(2, 20, "..Quitting..")
    raise KeyboardInterrupt
    if key == curses.KEY_UP:
    stdscr.addstr(2, 20, "Up")
    elif key == curses.KEY_DOWN:
    stdscr.addstr(3, 20, "Down")
    except KeyboardInterrupt:
    print("\nQuit\n")
    running = False
    _exit()
    except Exception, e:
    print("\nError: " + str(e))
    running = False
    _exit()
    [/php]


    Aber vielleicht wäre auch folgendes etwas für dich: http://www.raspberrypi.org/forums/viewtopic.php?f=63&t=35600
    Da musste dir aber RPIO für installieren, da ist das dann enthalten

    //EDIT: Etwas schönere Version von meinem oben geposteten:

    Spoiler anzeigen

    [code=php]
    #!/usr/bin/python
    import RPi.GPIO as GPIO
    import time, curses

    #---------------------------------------------------------------------
    # only one of following:
    PULL = GPIO.PUD_DOWN #GPIO -> GND
    #PULL = GPIO.PUD_UP #GPIO -> 3V3
    #---------------------------------------------------------------------

    RaspiRevision = GPIO.RPI_REVISION
    if RaspiRevision == 1:
    GPIOpins = [0,1,4,17,21,22,10,9,11,18,23,24,25,8,7]
    elif RaspiRevision == 2:
    GPIOpins = [2,3,4,17,27,22,10,9,11,18,23,24,25,8,7]
    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BCM)
    for gpin in GPIOpins:
    GPIO.setup(gpin, GPIO.IN, pull_up_down = PULL)

    def Interrupt_event(pin):
    global stdscr
    stdscr.addstr(1+pin, 5, ""+time.strftime("%d.%m.%Y %H:%M:%S")+" -> GPIO "+str(pin)+" ausgeloest!")
    stdscr.refresh()

    def _exit():
    stdscr.keypad(0)
    curses.nocbreak()
    curses.echo()
    curses.endwin()
    GPIO.cleanup()

    try:
    #for KeyPress Events
    stdscr = curses.initscr() #init curses
    curses.cbreak() #react on keys instantly without Enter
    curses.noecho() #turn off echoing of keys to the screen
    stdscr.keypad(1) #returning a special value such as curses.KEY_LEFT
    stdscr.addstr(0, 0, "Hit 'q' to quit") #display text on pos y, x
    for gpin in GPIOpins:
    GPIO.add_event_detect(gpin, GPIO.RISING, callback=Interrupt_event, bouncetime=100)
    running = True
    while running:
    key = stdscr.getch()
    stdscr.refresh()
    if key == ord('q'): raise KeyboardInterrupt
    except KeyboardInterrupt:
    stdscr.addstr(1, 0, "..Quitting..")
    stdscr.refresh()
    running = False
    _exit()
    except Exception, e:
    print("\nError: " + str(e))
    running = False
    _exit()
    [/php]

  • Hi Oerks,

    Ich benutze dazu ganz gerne das tool watch.

    watch macht nichts anderes wie ein beliebiges Programm immer und immer wieder auszuführen und dabei dessen Ausgabe anzuzeigen.
    (und jetzt kommt der "Haken": bis Strg+C gedrückt wurde)

    Das ist gerade bei gpio readall recht praktisch.

    Code
    watch 'gpio readall'

    Standardmäßig setzt watch dabei den Aktualisierungs Intervall auf 2 Sekunden, was aber mit der Option -n geändert werden kann.
    Im diesem Fall würde ich einen eher kurzen Aktualisierungs Intervall von z.b. 0.2 (oder sogar 0.1) Sekunden setzten, somit werden auch relativ kurze Tastendrücker erkennt.
    Wenn du dann noch die Option -d dazu setzt wird auch schön hervorgehoben was sich geändert hat. Leider verschwindet die Hervorhebung gleich schnell wie sie gekommen ist (in diesem Fall nach ca. 0.2 Sekunden) aber das reicht aus um zu sehen wohin man sein Augenmerk richten muss.

    Code
    watch -d -n.2 'gpio readall'

    (Das lässt sich zwar auch nicht q beenden aber macht im Grunde genau was du willst.)

    Da das ganze so zwar ganz nett aber dennoch nicht so praktisch ist wie ich es gerne hätte, z.b. ist es eher mühsam herauszufinden zu welchem Pin die änderung gehört,
    hab ich mir überlegt wie man das ganze noch übersichtlicher machen könnte und bin auf die Idee gekommen da noch etwas Farbe ins Spiel zu bringen.

    Also hab ich mir ein kleines Shellskript geschrieben dass in die Ausgabe von gpio readall einfach noch mit sed ein paar ANSI Farb Sequencen "hinein substituiert" und mit echo -e ausgibt.
    Die Start und Reset Sequenz sowie die einzelnen Farben habe ich damit man das leichter anpassen kann in Variablen ausgelagert.
    Ausserdem habe ich noch die letzten zwei Zeilen (genau das gleiche wie die ersten 2 Zeilen) mit 'head -n -2' gelöscht da ich finde das diese das ganze nur noch unübersichtlicher machen.


    Hier noch ein Screenshot der Ausgabe:
    uA6D3xu.png

    Spoiler anzeigen

    Nach einem 'gpio reset'
    IK8woiE.png

    Damit auch watch die Ausgabe des Skriptes korrekt anzeigen kann muss die Option -c gesetzt werden. Diese aktiviert die Interpretation der ANSI Farb Sequenzen.


    PS: Werde das Skript die nächsten Tage hier im Forum veröffentlichen und zur diskussion stellen. Mich würde nämlich interessieren wie das auf einem B+ aussieht und ob ihr noch ein paar Ideen/Tipps dazu habt
    (Will jetzt Oerks Thread nicht hijacken)


    EDIT:Mehr Screenshots :)

    Schöne Grüße,
    Joh

    DON'T PANIC!

    Einmal editiert, zuletzt von joh.raspi (5. Februar 2015 um 18:06)

  • Boa ey, wat 'ne schwere Geburt. :X
    Aber ich hab's mit Hilfe von meigradf's Script und viel Suchmaschinenquälerei geschafft.

    Das Programm ist wahrscheinlich vom Stil eher holprig, aber ...; es läuft so, wie ich will.
    Comments welcome.


    PS: Werde das Skript die nächsten Tage hier im Forum veröffentlichen und zur diskussion stellen. Mich würde nämlich interessieren wie das auf einem B+ aussieht und ob ihr noch ein paar Ideen/Tipps dazu habt
    (Will jetzt Oerks Thread nicht hijacken)


    Ich habe mal in einem stillen Moment mit meinem Thread gesprochen, er fühlt sich nicht gehijacked. :cool:

    Einmal editiert, zuletzt von Oerks (7. Februar 2015 um 13:12)

Jetzt mitmachen!

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