Schleife in vorhandenes Skript erstellen

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
krischeu1
User
Beiträge: 19
Registriert: Freitag 2. Oktober 2020, 09:52

Hi,
ich habe mir als Codefledderer ein Skript zusammengebaut, welches die Unterbrechungen zählt und die Uhrzeit als Unixzeit in eine Textdatei schreibt, die später zum Auslesen und Grafischer Darstellung genutzt wird.

Leider bin ich zu blöd i = i + 1 an die richtige Stelle zu bringen. Das sollte am Besten in der Textdatei Kommagetrennt neben der Uhrzeit stehen.
Kann mir da jemand helfen.

Code: Alles auswählen

import RPi.GPIO as GPIO
import os, time
from time import strftime,localtime
 
RECEIVER_PIN = 23
 
def callback_func(channel):
    if GPIO.input(channel):
        print("Sensor1: Lichtschranke wurde unterbrochen")
        date_local = strftime("%Y-%m-%d %H:%M:%S", localtime())
        ticks = time.time()
        print(date_local)
        print(ticks)
        with open("/home/pi/Documents/sensors/sensor01_tageswert.txt","a+") as sensor01:
        #    sensor01.write(date_local)
            sensor01.write(str(ticks))
            sensor01.write("\n")
        # alternativ kann ein Script / Shell Befehl gestartet werden
        # os.system("ls")
 
if __name__ == '__main__':
    
    GPIO.setmode(GPIO.BCM)
    GPIO.setwarnings(False)
    
    GPIO.setup(RECEIVER_PIN, GPIO.IN)
    GPIO.add_event_detect(RECEIVER_PIN, GPIO.RISING, callback=callback_func, bouncetime=200)
        
    try:
        while True:
            time.sleep(0.25)
    except:
        # Event wieder entfernen mittels:
        GPIO.remove_event_detect(RECEIVER_PIN)
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

In einem Callback sollte möglichst wenig passieren, Dateienöffnen geht eigentlich gar nicht. Der Dateimodus a+ ist eigentlich nie sinnvoll. `as` bei Import ist zum Umbenennen da, `GPIO` wird aber gar nicht umbenannt. `os` wird importiert, aber gar nicht benutzt.
Warnungen sind dazu da, um sie zu beheben, nicht um sie zu ignorieren. Dazu muß aber zum Schluß auch GPIO.cleanup aufgerufen werden.
Nakte except sollte man nicht benutzen, da werden wirklich alle Fehler abgefangen und eine Fehlersuche unmöglich.

Code: Alles auswählen

from RPi import GPIO
import time
from queue import Queue
from functools import partial 
 
RECEIVER_PIN = 23
 
def callback(queue, channel):
    queue.put(time.time())

def main():
    try:
        queue = Queue()
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(RECEIVER_PIN, GPIO.IN)
        GPIO.add_event_detect(RECEIVER_PIN, GPIO.RISING, callback=partial(callback, queue), bouncetime=200)
        with open("/home/pi/Documents/sensors/sensor01_tageswert.txt", "a") as sensor01:
            while True:
                ticks = queue.get()
                print("Sensor1: Lichtschranke wurde unterbrochen")
                sensor01.write(f"{ticks}\n")
    finally:
        GPIO.cleanup()

if __name__ == '__main__':
    main()
Wenn Du ein i = i + 1 noch in die Datei schreiben willst, dann pack das doch einfach mit in den String:

Code: Alles auswählen

sensor01.write(f"{ticks}, i = i + 1\n")
Falls Du einen Zähler willst, der sollte jetzt trivial einbaubar sein.
krischeu1
User
Beiträge: 19
Registriert: Freitag 2. Oktober 2020, 09:52

Hi,
Leider kommt kein Eintrag hinzu.
Kannst du da noch mal schauen?
Grüße
Heinz
krischeu1
User
Beiträge: 19
Registriert: Freitag 2. Oktober 2020, 09:52

Achso,
mir ist auch noch aufgefallen, daß beim unterbrechen nun etwas neues passiert.
Wenn ich unterbreche, kommt die Meldung "Lichtschranke unterbrochen". Wenn das Licht dann wieder auf den Photowiderstand trifft, kommt auch die Meldung "Lichtschranke unterbrochen".

Grüße
Heinz
krischeu1
User
Beiträge: 19
Registriert: Freitag 2. Oktober 2020, 09:52

Achso,
mir ist auch noch aufgefallen, daß beim unterbrechen nun etwas neues passiert.
Wenn ich unterbreche, kommt die Meldung "Lichtschranke unterbrochen". Wenn das Licht dann wieder auf den Photowiderstand trifft, kommt auch die Meldung "Lichtschranke unterbrochen".

Grüße
Heinz
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Willst du die Daten sofort parallel dazu lesen? Dann brauchst du noch ein flush nach dem write.
krischeu1
User
Beiträge: 19
Registriert: Freitag 2. Oktober 2020, 09:52

mir würde ein flush nach i = 120 reichen
krischeu1
User
Beiträge: 19
Registriert: Freitag 2. Oktober 2020, 09:52

Hi,
leider kommt nun folgendes im LOG
1602524641.0321817, i = i + 1

i=i+1 sollte halt Zählen
krischeu1
User
Beiträge: 19
Registriert: Freitag 2. Oktober 2020, 09:52

Hier die aktuelle Version mit dem Zählerproblem

Code: Alles auswählen

from RPi import GPIO
import time
from queue import Queue
from functools import partial 
 
RECEIVER_PIN = 23
 
def callback(queue, channel):
    queue.put(time.time())

def main():
    try:
        queue = Queue()
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(RECEIVER_PIN, GPIO.IN)
        GPIO.add_event_detect(RECEIVER_PIN, GPIO.RISING, callback=partial(callback, queue), bouncetime=200)
        with open("/home/pi/Documents/sensors/sensor01_tageswert.txt", "a+") as sensor01:
            while True:
                ticks = queue.get()
                print("Sensor1: Lichtschranke wurde unterbrochen")
                sensor01.write(f"{ticks}, i = i + 1\n")
                sensor01.flush()
    finally:
        GPIO.cleanup()

if __name__ == '__main__':
    main()
Benutzeravatar
sparrow
User
Beiträge: 4187
Registriert: Freitag 17. April 2009, 10:28

Aber das ist doch genau das, was du wolltest.
krischeu1 hat geschrieben: Freitag 2. Oktober 2020, 10:02Leider bin ich zu blöd i = i + 1 an die richtige Stelle zu bringen. Das sollte am Besten in der Textdatei Kommagetrennt neben der Uhrzeit stehen.
Wenn du eunen Zähler möchtest, musst du eine Variable entsprechend hochzählen.
krischeu1
User
Beiträge: 19
Registriert: Freitag 2. Oktober 2020, 09:52

Im LOG kommt aber immer:
112341234.12341 i=i+1
1234123412.1234 i=1+1
12341234.123412 i=i+1

Es hätte aber eher sein sollen
112341234.12341 1
1234123412.1234 2
12341234.123412 3
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Für einen Zähler bietet sich `itertools.count` an:

Code: Alles auswählen

from RPi import GPIO
import time
from queue import Queue
from functools import partial 
from itertools import count

RECEIVER_PIN = 23
OUTPUT_FILENAME = "/home/pi/Documents/sensors/sensor01_tageswert.txt"

def callback(queue, channel):
    queue.put(time.time())

def main():
    try:
        queue = Queue()
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(RECEIVER_PIN, GPIO.IN)
        GPIO.add_event_detect(RECEIVER_PIN, GPIO.RISING, callback=partial(callback, queue), bouncetime=200)
        with open(OUTPUT_FILENAME, "a+") as sensor01:
            for counter in count(1):
                ticks = queue.get()
                print("Sensor1: Lichtschranke wurde unterbrochen")
                sensor01.write(f"{ticks}, {counter}\n")
                sensor01.flush()
    finally:
        GPIO.cleanup()

if __name__ == '__main__':
    main()
krischeu1
User
Beiträge: 19
Registriert: Freitag 2. Oktober 2020, 09:52

Das ist sooo cool. Und ich probier schon ewig mit dem i=i+1 rum.

Vielen Dank Sirius3.

Das letzte Problem wäre jetzt noch, warum Zählt die Funktion die Unterbrechung der Lichtschranke UND wenn der Lichstrahl wieder auf den Photowiderstand kommt?
bzw. wie kann ich wirklich nur die Unterbrechungen zählen?
krischeu1
User
Beiträge: 19
Registriert: Freitag 2. Oktober 2020, 09:52

Hi,
warum kann man den counter bei einem Stand von z.B. 6 nicht wieder auf 1 zurück setzen?
Wie kann man das angehen?

Grüße
Heinz

Code: Alles auswählen

from RPi import GPIO
import time
from queue import Queue
from functools import partial 
from itertools import count

RECEIVER_PIN = 23
OUTPUT_FILENAME = "/home/pi/Documents/sensors/sensor01_tageswert.txt"

def callback(queue, channel):
    queue.put(time.time())

def main():
    try:
        queue = Queue()
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(RECEIVER_PIN, GPIO.IN)
        GPIO.add_event_detect(RECEIVER_PIN, GPIO.FALLING, callback=partial(callback, queue), bouncetime=200)
        with open(OUTPUT_FILENAME, "a+") as sensor01:
            for counter in count(1):
                ticks = queue.get()
                print("Sensor1: Lichtschranke wurde unterbrochen")
                sensor01.write(f"{ticks}, {counter}\n")
                print (counter)
                if counter == 6:
                    print ("Counter ist 6")
                    count = 1
                else: 
                    print ("Counter ist nicht 6")
                sensor01.flush()
    finally:
        GPIO.cleanup()

if __name__ == '__main__':
    main()
Zuletzt geändert von krischeu1 am Mittwoch 14. Oktober 2020, 19:44, insgesamt 1-mal geändert.
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wenn du counter meinst, musst du schon counter schreiben.
krischeu1
User
Beiträge: 19
Registriert: Freitag 2. Oktober 2020, 09:52

Geändert ...
__deets__ hat geschrieben: Mittwoch 14. Oktober 2020, 19:43 Wenn du counter meinst, musst du schon counter schreiben.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Natürlich hat das Ändern der Laufvariable einer for-Schleife keinen Einfluß auf den Wert im nächsten Durchgang. Das wäre ja auch sehr verwirrend.
Du willst also immer wieder durch die Folge 1,2,3,4,5,6 durchgehen, dafür gibt es itertools.cycle:

Code: Alles auswählen

from RPi import GPIO
import time
from queue import Queue
from functools import partial 
from itertools import cycle

RECEIVER_PIN = 23
OUTPUT_FILENAME = "/home/pi/Documents/sensors/sensor01_tageswert.txt"

def callback(queue, channel):
    queue.put(time.time())

def main():
    try:
        queue = Queue()
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(RECEIVER_PIN, GPIO.IN)
        GPIO.add_event_detect(RECEIVER_PIN, GPIO.FALLING, callback=partial(callback, queue), bouncetime=200)
        with open(OUTPUT_FILENAME, "a+") as sensor01:
            for counter in cycle([1, 2, 3, 4, 5, 6]):
                ticks = queue.get()
                print("Sensor1: Lichtschranke wurde unterbrochen")
                sensor01.write(f"{ticks}, {counter}\n")
                sensor01.flush()
    finally:
        GPIO.cleanup()

if __name__ == '__main__':
    main()
krischeu1
User
Beiträge: 19
Registriert: Freitag 2. Oktober 2020, 09:52

So funktioniert das nun mit den 60 Impulsen und dass er danach erst die Werte schreibt.
Leider fängt er aber auch wieder bei 0 an zu Zählen. Naja. Bin noch dran.
Aber so langsam wird das.


Grüße
Heinz

Code: Alles auswählen

from RPi import GPIO
import time
from queue import Queue
from functools import partial 
from itertools import cycle

RECEIVER_PIN = 23
OUTPUT_FILENAME = "/home/pi/Documents/sensors/sensor01_tageswert.txt"

def callback(queue, channel):
    queue.put(time.time())

def main():
    liste01=[]
    for zaehler01 in range (60):
       liste01.append(zaehler01)
         
    try:
        queue = Queue()
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(RECEIVER_PIN, GPIO.IN)
        GPIO.add_event_detect(RECEIVER_PIN, GPIO.FALLING, callback=partial(callback, queue), bouncetime=200)
        with open(OUTPUT_FILENAME, "a+") as sensor01:
             for counter in cycle(liste01):
                ticks = queue.get()
                print("Sensor1: Lichtschranke wurde unterbrochen")
                sensor01.write(f"{ticks}, {counter}\n")
                sensor01.flush()
    finally:
        GPIO.cleanup()

if __name__ == '__main__':
    main()
Zuletzt geändert von krischeu1 am Mittwoch 14. Oktober 2020, 20:28, insgesamt 1-mal geändert.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Eine Liste erzeugt man mit `list`: `list(range(60))`, ist aber gar nicht nötig, weil man auch das range-Objekt direkt verwenden kann.
Der Lichtschrankeneingang scheint wohl zu flackern.
krischeu1
User
Beiträge: 19
Registriert: Freitag 2. Oktober 2020, 09:52

Sirius3 hat geschrieben: Mittwoch 14. Oktober 2020, 20:26 Eine Liste erzeugt man mit `list`: `list(range(60))`, ist aber gar nicht nötig, weil man auch das range-Objekt direkt verwenden kann.
Der Lichtschrankeneingang scheint wohl zu flackern.
Da flackert leider nix. Finger rein. Unterbechung wird gezählt. Ich halte das noch unterbrochen für ca. 5 Sekunden. Dann wieder Finger weg. Strahl ist wieder auf dem Sensor. Und das wird dann auch wieder gezählt.
Antworten