Ampelschaltung mit Taster

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

    Ich habe seit Heute einen Raspberry Pi 2. Ich teste schon den ganzen Abend mein neues Spielzeug ;)... Habe schon verschiedene Schaltungen ausprobiert und bis jetzt hat auch alles soweit funktioniert.

    Ich bin im Moment an einer Ampelschaltung mit Taster. Habe eine für Autofahrer und eine für Fußgänger. Wird der Taster gedrückt, soll die Autofahrerampel auf Rot springen und die Fußgängerampel auf Grün. Dies soll einen realistischen (bis auf die Zeit) Ablauf haben. Leider bekomme ich immer die Fehlermeldung das etwas mit meiner IF Formel nicht stimmen würde. Invaldi Syntax. Ich sitze nun 2 Stunden hier und durchforste das Internet, aber ich werde einfach nicht schlauer. Kann mir jemand helfen und sagen was ich falsch gemacht habe?


    #Bibliotheken einbinden
    import RPi.GPIO as GPIO
    import time

    #GPIO Modus (BOARD / BCM)
    GPIO.setmode(GPIO.BCM)

    #Richtung der GPIO-Pins festlegen (IN / OUT)
    GPIO.setup(26, GPIO.OUT)
    GPIO.setup(19, GPIO.OUT)
    GPIO.setup(13, GPIO.OUT)
    GPIO.setup(06, GPIO.OUT)
    GPIO.setup(05, GPIO.OUT)
    GPIO.setup(21, GPIO.IN)

    #Warnungen Aus
    GPIO.setwarnings(False)


    #Bibliotheken einbinden
    import RPi.GPIO as GPIO
    import time

    #GPIO Modus (BOARD / BCM)
    GPIO.setmode(GPIO.BCM)

    #Richtung der GPIO-Pins festlegen (IN / OUT)
    GPIO.setup(26, GPIO.OUT)
    GPIO.setup(19, GPIO.OUT)
    GPIO.setup(13, GPIO.OUT)
    GPIO.setup(06, GPIO.OUT)
    GPIO.setup(05, GPIO.OUT)
    GPIO.setup(21, GPIO.IN)

    #Warnungen Aus
    GPIO.setwarnings(False)


    #unendliche Schleife
    while True:


    #Gruen
    GPIO.output(13, True)
    #Fussgaenger Rot
    GPIO.output(06, True)
    #Status des Tasters
    taster = GPIO.input(21)
    if (taster = true):
    time.sleep (2)
    GPIO.output(13, False)
    GPIO.output(19, True)
    time.sleep (2)
    GPIO.output(19, False)
    GPIO.output(26, True)
    time.sleep (1)
    GPIO.output(06, False)
    GPIO.output(05, True)
    time.sleep (5)
    GPIO.output(05, False)
    GPIO.output(06, True)
    time.sleep (2)
    GPIO.output(19, True)
    time.sleep (2)
    GPIO.output(13, True)

    Würde mich über Antworten sehr freuen!

    Grüße
    Benni

  • 1) Exakte Fehlermeldung posten.

    2) if Bedingungen werden immer mit " == " geprüft. Du setzt keine Variable sondern eine Bedingung/Vergleich.

    3) In python gibt es nur True, kein true. Case-Sensitiv.

    4) Die while ungehindert rotieren zu lassen verursacht 100% CPU Auslastung. FAQ --> Nützliche Links / Linksammlung --> Interrupt --> #6

    5) Variable pro Ampel speichern, prüfen ob Variable == True und dann entsprechende Aktionen durchführen.

  • Danke für die schnelle Antwort. Habe es jetzt wie folgt abgeändert:


    #Bibliotheken einbinden
    import RPi.GPIO as GPIO
    import time

    #GPIO Modus (BOARD / BCM)
    GPIO.setmode(GPIO.BCM)

    #Richtung der GPIO-Pins festlegen (IN / OUT)
    GPIO.setup(26, GPIO.OUT)
    GPIO.setup(19, GPIO.OUT)
    GPIO.setup(13, GPIO.OUT)
    GPIO.setup(06, GPIO.OUT)
    GPIO.setup(05, GPIO.OUT)
    GPIO.setup(21, GPIO.IN)

    #Warnungen Aus
    GPIO.setwarnings(False)


    #unendliche Schleife
    while True:


    #Gruen
    GPIO.output(13, True)
    #Fussgaenger Rot
    GPIO.output(06, True)


    if GPIO.input(21)== True:
    time.sleep (2)
    GPIO.output(13, False)
    GPIO.output(19, True)
    time.sleep (2)
    GPIO.output(19, False)
    GPIO.output(26, True)
    time.sleep (1)
    GPIO.output(06, False)
    GPIO.output(05, True)
    time.sleep (5)
    GPIO.output(05, False)
    GPIO.output(06, True)
    time.sleep (2)
    GPIO.output(19, True)
    time.sleep (2)
    GPIO.output(13, True)
    GPIO.output(19, False)
    GPIO.output(26, False)
    time.sleep (0.1)


    Jetzt ist meine Fehlermeldung weg! Aber leider ignoriert das Programm den Taster: Ich starte das Programm und es läuft von oben bis unten durch. Die Ampeln sollen eigentlich Dauer Rot bzw. Grün leuchten und erst schalten wenn der Taster gedrückt wird. Habe das == und True eingefügt sowie den time.sleep für den interrupt eingebaut.

  • Ersteinmal muss ich sagen, dass ich keine Ahnung von Python habe!
    Ich versuche trotzdem mal ein wenig mein Wissen in die Runde zu werfen ;) :s

    Ohne Interrupt wäre dein IF-Abfrage glaube ich so richtig:

    Hier ein Versuch als Interrupt:


    Auch dieser Code basiert auf meiner Unwissenheit! Wenn es stimmt gerne bescheid geben, dann kann ich mir das merken :D:P
    Das Wissen stammt einzig aus meigrafd's Link...

    Hoffe es läuft so ;)

  • Hi,
    ich hab' zwar auch keine Ahnung von Python und auch nicht vor, das zu ändern, aber:

    1. In Interrupt-Routinen ist ein sleep() ein NoGo ... zudem sollte eine -> ISR <- so kurz und resourcenschonend wie möglich sein (evtl. ist das im Leben der sonderbaren Riesenschlange anders ... glaub ich aber nicht, weil es für alle anderen Sprachen gilt). Die "Standard-"Vorgehensweise ist im Idealfall lediglich Flags zu setzen, die wiederum eine -> finite state machine <- steuern.
    2. Was passiert in der Interrupt-Variante, wenn Du den Taster zweimal kurz hintereinander drückst?
    3. Auf steigende und fallende Flanke abzufragen ist in der Regel eher eine suboptimale Idee. Beachte das, wenn Du Dir Frage Nr. 2 beantwortest.

    Zum Rest kann ich, wie schon erwähnt, nichts weiter sagen.

    cu,
    -ds-

  • Naja also erst mal solltest du Code als solchen hier auch in CODE oder PHP Blöcken posten. Das erhält dann nicht nur die Einrückungen (die für Python extrem wichtig sind) sondern lässt sich dann auch einfacher lesen und macht den Beitrag nicht so riesig.

    Dann hatte ich ja bereits erwähnt dass wenn eine while verwendet wird, ist es schlecht wenn man diese völlig ungehindert im Kreis drehen lässt, da das 100% CPU Last verursacht. Deshalb am Ende (oder am Anfang) der while zumindest eine Blockade von 0.01 einbauen.

    Interrupt wird nur zur Taster-Betätigung Erkennung genutzt - entsprechende Erklärungen und Beschreibungen habe ich oben verlinkt, das möchte ich ungerne immer wieder wiederholen..
    Wie dreamshader bereits anmerkte, ist es sehr wichtig möglichst keine Verzögerung innerhalb der ISR-Callback-Funktion zu haben, auch wenn diese in einem separaten Thread läuft, vielmehr gerade deshalb.. Deshalb sollte hier die unter dem #6-Beitrag beschriebene Lösung mithilfe von Queue zur Anwendung kommen.

    Wie an dem von Thinline verlinkten Blog zu sehen, trägt es enorm zur Übersicht bei wenn man die GPIO's entsprechenden Variablen zuweißt, sodass man, sofern die Variable entsprechend benannt wurde, genau weiß was sich hinter dem Pin verbirgt.
    Das Problem bei dem Blog ist allerdings das bereits angesprochene "100% CPU Auslastung"s Problem, denn auch da wird die while quasi 1000x pro Sekunde durchlaufen.
    (An die Goldwaagenleger: Das ist nur ein Fiktiver Wert, bitte nicht drüber Diskutieren ob die while 10000 oder nur 100x pro Sekunde durchlaufen wird! leider muss man sowas Hier ja erwähnen...)
    Das nächste was in dem Blogbeitrag verkannt wurde ist dass '#zurueck zu Phase 1' in der umschalten() Funktion überflüssig ist, da die while ja immer wieder von Vorne beginnt und dort bereits 'Phase 1' enthalten ist.
    Und zu guter letzt fehlt das zurücksetzen der GPIO's auf Werkszustand nachdem das Script beendet oder durch STRG+C gekillt wurde - damit wird dann auch "GPIO.setwarnings(False)" überflüssig.
    Last but not least ist auch ein GPIO als Eingang ohne Pull-Up/Down Problematisch, da sich der Zustand dann willkührlich/unvorhersehbar ändern kann - da jedes an den GPIO angeschlossene Kabel aus Antenne fungiert und ein HIGH-Pegel bereits ab 0,8V erkannt wird...
    Da vom 'time' Module aber auch nur 'sleep' zum Einsatz kommt, sollte man lieber nur diese eine Funktion importieren um das laden des Scripts zu beschleunigen und den RAM Verbrauch zu minimieren.

    Also Mein Verbesserungsvorschlag zu dem auf tutorials-raspberrypi.de gezeigtem Script wäre:

    [code=php]
    #Bibliotheken einbinden
    import RPi.GPIO as GPIO
    from time import sleep

    #GPIO Pin Belegung
    ROT = 02
    GELB = 14
    GRUEN = 15
    TASTER = 07

    #Phasen-Zeiten (dictionary)
    PhaseTime = {"phase2": 2, "phase3": 15, "phase4": 3}

    #GPIO Modus (BOARD / BCM)
    GPIO.setmode(GPIO.BCM)

    # internen Pull-... Widerstand aktivieren
    #PULL = GPIO.PUD_DOWN #GPIO -> GND
    PULL = GPIO.PUD_UP #GPIO -> 3V3

    #Richtung der GPIO-Pins festlegen (IN / OUT)
    GPIO.setup(ROT, GPIO.OUT) #rot
    GPIO.setup(GELB, GPIO.OUT) #gelb
    GPIO.setup(GRUEN, GPIO.OUT) #gruen
    GPIO.setup(TASTER, GPIO.IN, pull_up_down=PULL) #Taster

    #Umschaltung definieren
    def umschalten():
    #Phase 2
    GPIO.output(ROT, True)
    GPIO.output(GELB, True)
    GPIO.output(GRUEN, False)
    sleep(PhaseTime["phase2"])
    #Phase 3
    GPIO.output(GRUEN, True)
    GPIO.output(ROT, False)
    GPIO.output(GELB, False)
    sleep(PhaseTime["phase3"])
    #Phase 4
    GPIO.output(GELB, True)
    GPIO.output(GRUEN, False)
    sleep(PhaseTime["phase4"])

    def ampel():
    #Endlosschleife
    while True:
    #Phase 1
    GPIO.output(ROT, True)
    GPIO.output(GELB, False)
    GPIO.output(GRUEN, False)

    #Status des Tasters einlesen
    if GPIO.input(TASTER) == GPIO.HIGH:
    umschalten()
    sleep(0.1)

    try:
    ampel()
    except (KeyboardInterrupt, SystemExit):
    GPIO.cleanup()
    [/php]

    Das sollte es dann aber auch zum Einstieg erst mal reichen. Man kann das aber selbstverständlich noch weiter optimieren und anders schreiben - insbesondere wenn man sich an PEP halten möchte usw.

  • Kleiner Mann: Ohne Interrupt läuft es genauso wie meine Schaltung vorher auch, leider wird der Taster ignoriert. Mit Interrupt gibt es leider eine Fehlermeldung:

    File "ampel_skript2.py", line 15
    SyntaxError: Non-ASCII character '\xc3' in file ampel_skript2.py on line 15, but no encoding declared; see http://www.python.org/peps/pep-0263.html for details

    Thinline: Genau da hatte ich die Idee her :) Ich habe es aber selber ohne Hilfe programmieren wollen. Naja nun habe ich das Script komplett kopiert und siehe da, auch diese Schalterfunktion läuft nicht. Vielleicht ist er Hardwareseitig falsch angeschlossen!? Ich werde das nochmal überprüfen...

  • Hallo Benni,

    gibt es auch eine Schaltung dazu? Wenn die Software so gar nicht reagiert, dann wird vermutlich ein Pin abgefragt, an dem sich der Schalter inkl. Pullup-/Pulldown-Widerstand NICHT zu befinden scheint.

    Wenn sich irgendeine funktionierende Schaltung an dem abgefragten GPIO-Pin befinden würde, dann müsste da irgendwas passieren - und wenn es das Gegenteil der gewünschten Aktion ist.


    Beste Grüße

    Andreas
    zusammen

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    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.

  • Habe jetzt die Schaltung aufgebaut wie auf dem Bild vom Tutorial zu sehen ist. Habe einen 10k Ohm Widerstand eingebaut.

    10k Ohm Widerstand und GPIO Eingang parallel auf den Taster und der 3V Anschluss auf die andere Seite vom Taster.

    Edit: PS. Geht nicht!

    Einmal editiert, zuletzt von Benni989 (30. Dezember 2015 um 17:38)

  • Hallo Benni,


    Habe jetzt die Schaltung aufgebaut wie auf dem Bild vom Tutorial zu sehen ist. Habe einen 10k Ohm Widerstand eingebaut.

    10k Ohm Widerstand und GPIO Eingang parallel auf den Taster und der 3V Anschluss auf die andere Seite vom Taster.

    hmm ... da fehlt mi die Vorstellungskraft.

    Kannst Du Dir mal die Software Fritzing installieren und damit DEINE Schaltung zeichnen und hier als Graphik posten?

    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

    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.




  • Rote Linie sind die 3V und die Blaue Linie ist der GPIO... Der Widerstand geht auf GND
    Automatisch zusammengefügt:
    Update: Taster ist richtig angeschlossen und funktioniert mit dem Script von dem Tutorial auch. Das überarbeitete Script von meigrafd funktioniert leider nicht .

    (Fehlermeldung: ampel_skript4.py:22: RuntimeWarning: A physical pull up resistor is fitted on this channel!
    GPIO.setup(ROT, GPIO.OUT) #rot)


    Also kann man ja zusammen fassen es liegt an meinem Script..

  • Hallo Benni,

    dann sind wir schon einen Schritt weiter. Bist Du Dir sicher, dass Du den Taster richtig verbaut hast? Hast Du ihn mal um 90 ° gedreht - oder mit einem Durchgangsprüfer getestet, in welcher Orientierung er als Taster fungiert?

    Kannst Du in der Fritzing-Schaltung auch den Raspberry Pi einbauen, damit man erkennen kann, welche Pins des GPIO-Ports du womit verbunden hast.

    Wenn Du es so verbunden hast, dann sollte es funktionieren:
    3.3V ==> Taster ==> R=620 Ohm ==> GPIO21 ==> R=10k8 ==> GND

    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

    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.

  • Habe die Schaltung nun überarbeitet. Anstelle von dem 620 Ohm habe ich 2x 330 Ohm in Reihe geschaltet. Denke 40 Ohm sollten den Bock nicht fett machen...

    Getestet habe ich ihn ja.. Habe ja oben geschrieben, dass er mit der Schaltung vom Tutorial funktioniert.
    Automatisch zusammengefügt:
    Ich könnte ja jetzt einfach zu dem Tutorial Script meine Ampelschalten vollenden, aber das ist mir nicht der Sinn der Sache. Möchte ja meinen Fehler verstehen.

  • Hallo Benni,

    das mit den 330 Ohm-Widerständen sollte kein Problem machen ;) .

    Sehe ich das richtig, dass Dein Progrsamm unabhängig vom Taster-Ereignis die Ampeln schaltet?
    Das kann ich nur nachvollziehen, falls Dein Programm so aussieht (Ausschnitt):

    Es sollte aber so eingerückt sein:

    (in Python startet alles nach einem Doppelpunkt eine weitere Verschachtelungsebene - alle Zeilen der neuen Verschachtelungsebene werden mit der gleichen Anzahl an Leerzeichen oder Tabulator eingerückt, wobei Du nur entweder Leerzeichen oder Tabs verwenden darfst - nicht beides mischen! Fehlt die Einrückung, dann gehört diese Zeile nicht mehr zur Verschachtelungsebene sondern wird nach der Zeile mit dem Doppelpunkt durchgeführt.)

    EDIT: Und wenn es das auch nicht ist:
    Du hast einen PullDown-Widerstand, dass heißt ein Taster-Ereignis wird nicht mit

    Code
    if GPIO.input(21)== True:


    sondern mit

    Code
    if GPIO.input(21)== False:


    erkannt.

    Hm, das erklärt auch das Durchlaufen der Ampelschaltung, ohne dass der Taster gedrückt wurde (auch bei korrekter Einrückung hinter

    Code
    if GPIO.input(21)== True

    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

    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.

    Einmal editiert, zuletzt von Andreas (30. Dezember 2015 um 19:02)

  • Genau so sieht das aus, habe leider ohne Code den Text reinkopiert.

  • Hallo Benni,

    dann schaue noch mal in #18 - meine letzte Änderung überschnitt sich mit Deinem Beitrag #19. Das sollte die Lösung sein.

    Und die Erklärung des Ganzen:

    Verbindest Du 3V3 mit Taster und über einen Widerstand mit GND und GPIO, der das Taster-Ereignis erkennen soll, dann wird der Pegel auf LOW = False = < 0,8 V heruntergezogen. Der Widerstand heißt deswegen PULLDOWN-Widerstand.

    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

    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.

    Einmal editiert, zuletzt von Andreas (30. Dezember 2015 um 19:08)

Jetzt mitmachen!

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