Besseren Code schreiben

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
Hard_Veur
User
Beiträge: 14
Registriert: Dienstag 16. Mai 2017, 14:31

Was Python angeht beschäftige ich mich jetzt schon länger aber bis jetzt habe ich noch nicht wie praktisches Programmiert was Schaltungen angeht also hab ich ein Python Programm geschrieben was Daten eines Controllers welcher über Bluetooth verbunden ist auf vier PWM Kanälen ausgeben soll damit das auch alles Zeitgleich geht brauchte ich vier Threads nur was Threads angeht habe ich leider gar keine Ahnung.

Mein Code wird von einer anderen Datei aufgerufen mit einer Liste von 20 int von den ich nur 4 brauche. Der aufrufe sieht ungefähr so aus:
ausgeben(Liste)

Hier ist die PWM.py Datei:

Code: Alles auswählen

#!/usr/bin/env python3

import RPi.GPIO as GPIO
import threading

use_GPIO_Pins = [2,3,4,14]    #for GPIO(BCM)
counter = 1
Hertz = 750
data = [124, 128, 129, 128]

def ausgeben(da):
    global data
    data = da[0:4]
    global counter 
    if counter:
        main()
        counter = 0

def PWM(dataindex, pin, Hertz):        
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(pin, GPIO.OUT)
    p = GPIO.PWM(pin, Hertz)
    p.start(0)        
    while True:
        p.ChangeDutyCycle(round(data[dataindex]/255*100, 1))

def main():
    GPIO.setwarnings(True)
    GPIO.cleanup()
    threading.Thread(target=PWM, args=(0,2,Hertz)).start()
    threading.Thread(target=PWM, args=(1,3,Hertz)).start()  
    threading.Thread(target=PWM, args=(2,4,Hertz)).start()  
    threading.Thread(target=PWM, args=(3,14,Hertz)).start()
Der Code ist echt nicht schön wegen global und so aber ich hab absolut keine Idee wie man die Daten sonst an die Threads übergibt. Kann man es vlt auch ohne Threads schaffen weil die PWM Instanz läuft ja weiter nur weiß ich nicht wie das ist, weil besteht die Instanz wirklich weiter weil die ausgeben() Funktion wird ja nur aufgerufen und wenn man damit fertig ist springt man ja im Programmlauf weiter, also ausgeben() wird wieder geschlossen und somit auch die Instanzen???(Wobei die Counter variable trotz schließen der Funktion nach dem ersten aufruf auf 0 bleibt) und dann wird ausgeben() erst wieder aufgerufen. Ich muss noch dazu sagen da der Controller dauerhaft Daten sendet werden diese Daten aus den Datenpaketen in die Liste eingesteckt und an die ausgebe() Funktion weitergeben durch immer wieder aufrufen.


Also zusammengefasst wie ist das mit der Lebensdauer von Instanzen und Variabeln bei einer Funktion die immer wieder neu aufgerufen wird und nicht dauerhaft läuft???
Und wie kann ich diesen Code deutliche besser und übersichtlich schreiben kenne mich nicht wirklich mit Threads und so größern 'Projekten' mit mehreren Dateien aus.
Zuletzt geändert von Anonymous am Sonntag 2. Juli 2017, 18:09, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Hard_Veur: use_GPIO_Pins wird gar nicht benutzt. GPIO.setmode sollte nur einmal aufgerufen werden, GPIO.setwarnings ist sowieso schon True und GPIO.cleanup sollte zum Schluss aufgerufen werden. Weder ausgeben wird jemals aufgerufen. Es ist auch ungewöhnlich, dass darin main aufgrufen wird.
Eigentlich müßte da so aussehen:

Code: Alles auswählen

#!/usr/bin/env python3
from RPi import GPIO

use_GPIO_Pins = [2,3,4,14]    # for GPIO(BCM)
Hertz = 750

def main():
    try:
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(use_GPIO_Pins, GPIO.OUT)
        pwms = []
        for pin in use_GPIO_Pins:
            p = GPIO.PWM(pin, Hertz)
            p.start(0)
            pwms.append(pin)
        while True:
            data = woher_auch_immer()
            for p, value in zip(pwms, data):
                p.ChangeDutyCycle(data[dataindex]/255*100)
    finally:
        GPIO.cleanup()

if __name__ == '__main__':
    main()
wobei ich nicht verstanden habe, woher data kommt. Was heißt »von einer anderen Datei aus aufgerufen?«
Hard_Veur
User
Beiträge: 14
Registriert: Dienstag 16. Mai 2017, 14:31

Naja mein Ordner sieht ungefähr so aus: bluetooth.py transforming.py PWM.py
In der transforming.py läuft eine eventloop als infinity immer durch und ruft dabei immer ausgeben(da) aus der Datei PWM.py auf mit den neuen Daten von dem Controller. Weshalb das mit "Weder ausgeben wird jemals aufgerufen." So nicht stimmt was du aber nicht wissen konntest. Sry my fault ;)
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Hard_Veur: dann müßte man die anderen Dateien auch kennen. Aber mehr als die zwei Zeilen for-Schleife braucht man vom Event-loop heraus sowieso nicht aufzurufen.
Hard_Veur
User
Beiträge: 14
Registriert: Dienstag 16. Mai 2017, 14:31

Müsste in dem Code von Sirius3 in Zeile 15 pin nicht durch p ersetzt werden weil sonst ergibt der code kein sinn oder?!
Und in Zeile 19 müsste data[dataindex] durch value ersetzt werden oder bin ich da jetzt verkehrt? Aber vielen dank auf jden fall für diese eindeutig besser Variante war sehr hilfreich :)

Und noch kurz eine Frage wegen Threads kann mir da jemand sagdn wie man das normalerweise mit der Übergabe von Daten an Threads macht hatte da irgendwas von Queue gelesen?!
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Hard_Veur: ja da hab ich geschlafen, ähm, das war für Dich, ob Du den Code auch verstehst. Und ja, man benutzt Queues zum Übergeben von Daten an einen Thread, für Deine Aufgabe brauchst Du aber keine Threads.
Hard_Veur
User
Beiträge: 14
Registriert: Dienstag 16. Mai 2017, 14:31

Hatte jetzt Zeit wieder mal ein bisschen was mit dem Code zu probieren und zu Experimentieren dabei ist mir ein Problem aufgefallen.
Die Datei wird aufgerufen und müsste somit die Daten aus der Variable data beim Aufruf mitbekommen wenn man jedoch macht werden bei jedem Aufruf die Instanzen immer wieder neu erzeugt bzw. es kommt zu einem RuntimeError weil ja auf dem jeweiligen Channel/Pin schon eine Instanz läuft wie bekomme ich also die Daten in die Funktion ohne die Routine immer wieder neu zu starten. Mir würde eine if Verzweigung in den sinn kommen indem man die Funktion immer wieder neu aufruft aber nur beim ersten mal die ganz Routine durchlaufen lässt und die restlichen mal einfach nur die Funktion aufruft und wieder schließt um die Variable data zu "erneuern"/aktualisieren.

P.S. Mir fällt gerade auf das es eigentlich parallel zu der Eventloop laufen müsste weil jetzt wird in der Eventloop main() aus der PWM.py Datei aufgerufen (der Code oben) und dadurch das wir dort in eine infinity loop springen wird die Eventloop bis zum Programm ende (KeyboardInterrupt) ja gestoppt also funktioniert der Ansatz schon mal nicht und somit brauche ich wieder einen Thread oder?!
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Hard_Veur: Du brauchst keine Threads. Jede Funktionalität ist im Prinzip gleich aufgebaut. Initialisierung - Arbeiten - Finalisieren. Wenn Du jetzt mehrere Funktionalitäten mischen willst und Du hast mehrere Loops die Unendlich arbeiten, dann wäre es eine Haarbreite komplizierter, aber im Moment besteht das Arbeiten, was in PWM.py steht nur aus zwei Zeilen, die dann aufzurufen sind, wenn neue Daten anstehen. Als Pseudocode wird das Problem und die Lösung, glaube ich klarer:

Code: Alles auswählen

def main_A():
    try:
        init_A()
        while True:
            work_A()
    finally:
        cleanup_A()

def main_B():
    try:
        init_B()
        while True:
            work_B()
    finally:
        cleanup_B()
wird zu:

Code: Alles auswählen

def main():
    try:
        init_A()
        init_B()
        while True:
            work_A()
            work_B()
    finally:
        cleanup_B()
        cleanup_A()
Antworten