Zwei while-Schlaufen parallel laufen lassen in Python?

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
BlackJack

@Swi_Mo: Eine Einrücktiefe von *einem* Leerzeichen pro Ebene ist arg wenig. Konvention sind vier Leerzeichen. Und auch welche nach Kommata und um binäre Operatoren, damit es leichter lesbar ist.

Das `os`-Modul wird importiert, aber nicht verwendet.

`GPIO.cleanup()` also Aufräumen, gehört ans Ende des Programms und es sollte sichergestellt werden, dass das auch tatsächlich aufgerufen wird. Also zum Beispiel auch wenn das Programm durch eine Ausnahme endet. Dann kann man sich auch das ausstellen der Warnungen sparen. Bei Warnungen sollte man überlegen was falsch läuft und sie nicht ignorieren.

Hauptprogramm und Definitionen von Funktionen sollte man nicht vermischen und das Hauptprogramm sollte auch nicht direkt auf Modulebene stehen, sondern auch in einer Funktion. Wenn man das macht, dann fällt auf das die Funktion zur Aktualisierung der Anzeige einfach so auf `segment` zugreift ohne diesen Wert als Argument übergeben zu bekommen. Der Kommentar erscheint überflüssig. Die Angabe 7 Zeilen zu genau und man müsste das immer anpassen wenn man etwas an der Funktion ändert so das sich die Zeilenanzahl ändert. Wenn man schon beschreibt was eine Funktion macht, dann wäre das als Docstring besser aufgehoben als als Kommentar.

In der Funktion wird in den beiden ``if``-Zweigen fast das gleiche gemacht. Die unterscheiden sich nur durch den Index der Ziffern für die Anzeige. Die Bedigungen beeinflussen also eigentlich nur diesen Index. Die beiden Abfragen schliessen sich auch gegenseitig aus, also ist für den zweiten Zweig auch eher ein ``elif`` angebracht. Und dann würde ich noch ein ``else`` hinzufügen das den Fall behandelt das etwas anderes als `team` übergeben wurde.

Der `int()`-Aufruf ist überflüssig. Wenn man Python 3 berücksichtigen möchte, könnte man an der Stelle den Ganzahldivisionsoperator ``//`` verwenden.

Werte die man im Programm mehrfach wiederholt und/oder die man einfach anpassen können möchte, werden am Anfang als Konstanten definiert. Magische Zahlen haben so dann auch gleich einen Namen an dem der Leser erkennt wofür die gut sind.

`GPIO.setup()` kann man auch mehr als einen Pin übergeben.

`Rot` und `Blau` vermitteln nicht wirklich, dass es sich dabei um Punkte handelt.

Der Kommentar mit den parallelen Schlaufen (sagt das tatsächlich jemand so?) ist verwirrend weil da weder zwei Schleifen noch irgend etwas paralleles folgt. Das ist eine Schleife mit sequentieller Abfrage der beiden Taster (oder wirklich Schalter?).

Die Klammern gehören da nicht um die Bedingung und auf literale Wahrheitswerte vergleicht man nicht. Da kommt nur wieder ein Wahrheitswert bei heraus, also kann man entweder gleich den Ausgangswert nehmen, oder wie in diesem Fall seine Negation mit ``not``.

Beim Kommentar fand ich den letzten Satz ein wenig verwirrend. Den sollte man in Bezug zu dem davor geschriebenen setzen. Ausserdem würde ich das was die **input()**-Funktion liefert nicht als *Ausgabewert* bezeichnen.

Da nicht auf die Flanke reagiert wird, sondern wirklich die ganze Zeit mit Zehntelsekunden-Päuschen auf geschlossenen Kontakt geprüft wird, ist das ein bisschen fehleranfällig für zu langes Drücken IMHO.

Code: Alles auswählen

#!/usr/bin/env python
import time
from Adafruit_7Segment import SevenSegment
from RPi import GPIO

ROT, BLAU = 'rot', 'blau'
TEAM_PINS = ROTES_TEAM_PIN, BLAUES_TEAM_PIN = [27, 24]


def aktualisiere_punkte_anzeige(segment, team, punktestand):
    if team == ROT:
        index = 0
    elif team == BLAU:
        index = 3
    else:
        assert False, 'Falscher Wert fuer `team`: {}'.format(team)
    segment.writeDigit(index, punktestand // 10)
    segment.writeDigit(index + 1, punktestand % 10)


def main():
    try:
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(TEAM_PINS, GPIO.IN, pull_up_down=GPIO.PUD_UP)
        segment = SevenSegment(address=0x70)

        print '------------------'
        print 'Programm fuer Tischkicker mit zwei Druckschaltern.'
        print 'Torstands-Ausgabe an Adafruit 7-Segment Display'
        print '------------------'

        punkte_rot = 0
        punkte_blau = 0

        aktualisiere_punkte_anzeige(segment, ROT, punkte_rot)
        aktualisiere_punkte_anzeige(segment, BLAU, punkte_blau)

        while True:
            # ``not`` kehrt den Eingabewert des Schalterzustands um.
            # Ohne diese Operation zaehlen die Torstaende bei nicht
            # gedruecktem Schalter hoch, sondern druecken der Schalter 
            # unterbricht das Hochzaehlen.
            if not GPIO.input(ROTES_TEAM_PIN):
                punkte_rot += 1
                aktualisiere_punkte_anzeige(segment, ROT, punkte_rot)

            if not GPIO.input(BLAUES_TEAM_PIN):
                punkte_blau += 1
                aktualisiere_punkte_anzeige(segment, BLAU, punkte_blau)

            time.sleep(0.1)
    finally:
        GPIO.cleanup()


if __name__ == '__main__':
    main()
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Oder mit einem Team-Objekt, um die restlichen Code-Wiederholungen zu eliminieren:

Code: Alles auswählen

#!/usr/bin/env python
import time
from Adafruit_7Segment import SevenSegment
from RPi import GPIO

ROTES_TEAM_PIN, BLAUES_TEAM_PIN = [27, 24]

class Team(object):
    def __init__(self, segment, pin, index):
        self.pin = pin
        self.index = index
        self.segment = segment
        self.punkte = 0
        self.aktualisiere_punkte_anzeige()
        GPIO.setup(self.pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)

    def aktualisiere_anzeige(self):
        for index, ziffer in enumerate(divmod(self.punkte, 10), self.index):
            self.segment.writeDigit(index, ziffer)
 
    def aktualisiere_punkte(self):
        # ``not`` kehrt den Eingabewert des Schalterzustands um.
        # Ohne diese Operation zaehlen die Torstaende bei nicht
        # gedruecktem Schalter hoch, sondern druecken der Schalter
        # unterbricht das Hochzaehlen.
        if not GPIO.input(self.pin):
            self.punkte += 1
            self.aktualisiere_anzeige()
 
def main():
    try:
        GPIO.setmode(GPIO.BCM)
        segment = SevenSegment(address=0x70)
 
        print '------------------'
        print 'Programm fuer Tischkicker mit zwei Druckschaltern.'
        print 'Torstands-Ausgabe an Adafruit 7-Segment Display'
        print '------------------'
 
        teams = [
            Team(segment, ROTES_TEAM_PIN, 0),
            Team(segment, BLAUES_TEAM_PIN, 3),
        ]
 
        while True:
            for team in teams:
                team.aktualisiere_punkte()
            time.sleep(0.1)
    finally:
        GPIO.cleanup()


if __name__ == '__main__':
    main()
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Swi_Mo hat geschrieben:Unsere zwei Schlaufen laufen inzwischen.
Ehe sich der Fehler einschlauft: Schlaufe vs. Schleife
Swi_Mo
User
Beiträge: 5
Registriert: Donnerstag 15. September 2016, 08:27

Inzwischen ist unser RaspberryPi-Projekt zu einem Arduino-Projekt geworden und abgeschlossen. :D Unser sehr beschränktes Python-Wissen liess sich problemlos in C++ vom Arduino transferieren. Die beiden Schlaufen laufen inzwischen anstandslos im Tischkicker-Zähler.
Bild
Am Ende der 1. Seite von folgendem Thread gibt es Infos des fertigen Projekts und den verwendeten Code.
http://www.forum-raspberrypi.de/Thread- ... t-geworden

Beste Grüsse!
Antworten