Gegengleicher Zähler in Python

  • Hallo zusammen,

    ich hab mir vor einigen Wochen einen Raspberry gekauft und schon das ein oder andere Projekt umgesetzt. Jetzt komm ich aber leider nicht mehr weiter...

    Ich möchte in meinem Python Skript einen Zähler nach jeder Sekunde um 1 verringern lassen. Gleichzeitig soll jedoch, wenn auf einem I/O-Port ein Signal eintrifft (in meinem Fall ein Bewegungssensor) der Zähler um 1 erhöht werden.

    Für's Runterzählen hab ich einfach eine Endlosschleife mit sleep(1) und anschließendem counter = counter - 1

    Wenn ich den Sensor in einem eigenen Thread starte, wird ständig zwischen den beiden hin und her gesprungen und es dauert viel länger bis der Zähler um 1 reduziert wird.

    Gerne kann ich euch auch den Source Code posten, wenn meine Erklärungen nicht ganz klar sind :s

    Wie kann ich den Zähler jede Sekunde um 1 verringern und gleichzeitig bei einem I/O Signal um 1 erhöhen?

    Danke schon mal vorab für eure Hilfe!

    Einmal editiert, zuletzt von CeyxRemains (22. November 2015 um 17:26)

  • Ich habe den Code jetzt so weit zusammengeschnitten dass er übersichtlich ist:


    #!/usr/bin/env python
    import RPi.GPIO as GPIO
    from threading import Thread
    import time

    ir_signal = 15
    counter = 10

    def setup():
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(ir_signal, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

    #Hier wird das Eingangssignal geprueft
    def count_up():
    flag_input = False
    global counter
        
    while True:
    if(GPIO.input(ir_signal) == True and flag_input == False):
    counter = counter + 1
    print "count_up %d" % counter
    flag_input = True
    time.sleep(0.5)

    if(GPIO.input(ir_signal) == False and flag_input == True):
    flag_input = False

    #Hier wird der Zaehler jede Sekunde um 1 verringert
    def count_down():
    global counter
    while True:
    time.sleep(0.99)
    if counter > 0:
    counter = counter - 1
    print "count_down %d" % counter
    time.sleep(0.01)

    def destroy():
    GPIO.cleanup()
            
    #Programm beginnt hier
    if __name__ == '__main__':
    setup()
    try:
    t = Thread(target=count_up)
    t.start()
    count_down()
    except KeyboardInterrupt:
    destroy()

    Einmal editiert, zuletzt von CeyxRemains (22. November 2015 um 17:22)

  • Du musst einen Thread starten, damit deine Prozesse gleichzeitg laufen können. Dann lässt du sie über ein Objekt wie folgendes Kommunizieren.

    [code=php]from threading import Lock


    class Counter(object):
    def __init__(self, value=0):
    self.value = value
    self.lock = Lock()

    def increase(self):
    with self.lock:
    self.value += 1
       
    def decrease(self):
    with self.lock:
    self.value -= 1

    def show_count(self):
    return self.value

    def get_and_reset(self):
    with self.lock:
    result = self.value
    self.value = 0
    return result[/php]

    Als Tipp noch, die Threads sollten sich selber beenden und nicht mit "Gewalt" von außen gekillt werden. Folgendes Stichwort:

    [code=php]from threading import Thread, Event


    event = Event()


    def function():
    while not event.wait(0.5):
    print 'Hello World!'


    def end_thread():
    event.set()


    thread = Thread(target=function)
    thread.setDaemon(True)
    thread.start()[/php]

  • Danke mobby für deine schnelle Antwort,

    ich habe die Klassendefintion und das Objekte in den Code eingearbeitet.

    Aber wenn ich mich nicht täusche, starte ich doch schon einen Thread mit
    t = Thread(target=count_up)
    t.start()

    oder?

    Was passiert bei deinem Codebeispiel bei
    def end_thread():
    event.set()

    Hier mein aktualisierter Code:
    #!/usr/bin/env python
    import RPi.GPIO as GPIO
    from threading import Thread
    import time
    from threading import Lock

    ir_signal = 15

    class Counter(object):
    def __init__(self, value=10):
    self.value = value
    self.lock = Lock()

    def increase(self):
    with self.lock:
    self.value += 1

    def decrease(self):
    with self.lock:
    self.value -= 1

    def show_count(self):
    return self.value

    def get_and_reset(self):
    with self.lock:
    result = self.value
    self.value = 0
    return result

    def setup():
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(ir_signal, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

    #Hier wird das Eingangssignal geprueft
    def count_up():
    flag_input = False
    #global counter

    while True:
    if(GPIO.input(ir_signal) == True and flag_input == False):
    counter.increase()
    flag_input = True
    time.sleep(0.5)

    if(GPIO.input(ir_signal) == False and flag_input == True):
    flag_input = False

    #Hier wird der Zaehler jede Sekunde um 1 verringert
    def count_down():
    #global counter
    while True:
    zeit = time.time()
    time.sleep(0.99)
    if counter.show_count() > 0:
    counter.decrease()
    print "count_down %d" % counter.show_count()
    time.sleep(0.01)

    def destroy():
    GPIO.cleanup()

    #Programm beginnt hier
    if __name__ == '__main__':
    counter = Counter()
    setup()
    try:
    t = Thread(target=count_up)
    t.setDaemon(True)
    t.start()

    count_down()
    except KeyboardInterrupt:
    destroy()

  • Mit dem Event kannst du die Threads sich von alleine beenden lassen, sobald das Script fertig ist, oder wenn allgemeinen ein Thread beendet werden soll. Dafür musst du die while True Ansätze aber natürlich auch so ändern wie oben beschrieben. Und ich hoffe, dass dein Code eingerückt ist, weil dein Posting sieht nicht so aus. Verwende dafür doch bitte die Code Funktion. Zudem würde ich das Objekt an die Funktionen übergeben. Aber wichtigste Frage, funkioniert es jetzt? ^^

    Für Flags über Threads hinweg setzen würde ich prinzipiell auch Objekte benutzen ...

    [code=php]class Status(object):
    def __init__(self, bol_status):
    self.status = bol_status

    def get_status(self):
    return self.status

    def set_status_on(self):
    self.status = True

    def set_status_off(self):
    self.status = False[/php]

  • Du bist ein Genie! Mit deiner Hilfe hat es jetzt funktioniert :thumbs1:

    Vielen Dank!

    Hier noch der Code falls einmal irg. jemand ein ähnliches Problem hat (jetzt auch besser gekennzeichnet mit der Code-Funktion :D )

Jetzt mitmachen!

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