Thread sauber beenden

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.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Bei deinem zuletzt geposteten Code passiert aber nichts gleichzeitig, obwohl du zuvor davon gesprochen hast. Es hörte sich so an (vermutlich auch für BlackJack), dass die LEDs parallel zueinander von dir gesteuert würden.
DatMichi
User
Beiträge: 29
Registriert: Montag 25. Mai 2015, 20:35

Oh da muss ich mich entschuldigen... Das nächste mal versuche ich mein Problem etwas genau zu schildern.

Der zuletzt gepostete Code ist für BlackJack da er mich frage welche Bibliothek usw. ich verwende. Darum habe ich gleich mal alles veröffentlicht.
Das Python Skript soll aber so umgebaut werden das die EINE Diode angesteuert wird. So das es zu Mischfarben kommt und somit zu Farbverläufen kommt.
Benutzeravatar
noisefloor
User
Beiträge: 3854
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

die gpiozero Bibliothek (welche "moderner und empfehlenswerter ist als das ältere rpi.gpio) hat fertige Klassen und Methoden, um RGB-LEDs direkt anzusteuern, optional auch mit PWM und optional auch direkt als Hintergrundthread.

Gruß, noisefloor
DatMichi
User
Beiträge: 29
Registriert: Montag 25. Mai 2015, 20:35

noisefloor hat geschrieben:Hallo,

die gpiozero Bibliothek (welche "moderner und empfehlenswerter ist als das ältere rpi.gpio) hat fertige Klassen und Methoden, um RGB-LEDs direkt anzusteuern, optional auch mit PWM und optional auch direkt als Hintergrundthread.

Gruß, noisefloor

OH danke für deine Info dann werde ich mir diese auch mal anschauen.
BlackJack

@DatMichi: Da sehe ich aber immer noch nicht wo das Threads ins Spiel kommen sollen. Wenn man nicht `gpiozero` verwendet, würde man sich so eine RGBLED-Klasse wie dort halt einfach selbst schreiben. Wofür braucht man da Threads? (Die startet `GPIO` schon selbst im Hintergrund pro PWM-Objekt.)

Ich würde übrigens nicht immer wieder `start()` aufrufen wenn ich eigentlich `ChangeDutyCycle()` meine.
DatMichi
User
Beiträge: 29
Registriert: Montag 25. Mai 2015, 20:35

DatMichi hat geschrieben:
noisefloor hat geschrieben:Hallo,

die gpiozero Bibliothek (welche "moderner und empfehlenswerter ist als das ältere rpi.gpio) hat fertige Klassen und Methoden, um RGB-LEDs direkt anzusteuern, optional auch mit PWM und optional auch direkt als Hintergrundthread.

Gruß, noisefloor

So habe das mal "grob" getestet... Die Ansteuerung der LED ist damit echt sehr einfach.

Danke für den Tip. Ich werde mein Vorhaben mal versuchen ohne Thread's zu verwirklichen.
DatMichi
User
Beiträge: 29
Registriert: Montag 25. Mai 2015, 20:35

Hallo,

so habe die Sache jetzt ganz anders gelöst.
Das ganze soll ja ein Stimmungslicht für den Nachttisch werden.

Habe es jetzt so gemacht das man sich ein Bild mit einem Farbverlauf aussucht und mein kleines Programm tastet das Bild Punkt für Punkt ab
und stellt die Farbe des Bildpunktes mit der LED dar.

Es wird horizontal abgetastet, ist das ende des Bildes erreicht geht es genau mit den gleichen Werten wieder zurück. Erst dann kommt die nächste Zeile dran.

Es sieht sehr gut aus...

Code: Alles auswählen

from time import sleep
import sys
import Image

im=Image.open(sys.argv[1]).convert('RGB')
pix=im.load()

# GPIO Festlegen
led1 = RGBLED(red=16, green=20, blue=21)

for y in range(im.size[1]):
    for x1 in range(im.size[0]):
        r=pix[x1,y][0]
        g=pix[x1,y][1]
        b=pix[x1,y][2]
        led1.color = (float(r)/255,float(g)/255,float(b)/255)
        sleep(float(sys.argv[2]))

    for x2 in range(im.size[0]-1, 1, -1):
        r=pix[x2,y][0]
        g=pix[x2,y][1]
        b=pix[x2,y][2]
        led1.color = (float(r)/255,float(g)/255,float(b)/255)
        sleep(float(sys.argv[2]))
Ich hoffe das am Dienstag das Gehäuse für den Raspberry kommt und ich das dann ordentlich verbauen kann.
BlackJack

@DatMichi: Auch wenn es gut aussieht noch ein paar Anmerkungen:

Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert.

Leerzeichen um Zuweisungen und nach Kommas machen den Quelltext leichter lesbar.

Das `Image`-Modul sollte explizit aus dem `PIL`-Package importiert werden. Das es einfach so importierbar ist, ist „deprecated“, wird also in einer Folgeversion von `PIL` oder Pillow nicht mehr funktionieren.

Die `sys.argv`-Zugriffe im Code zu verteilen ist unübersichtlich. Jemand der den Code nicht kennt, und herausfinden möchte mit welchen Argumenten er das Programm aufrufen muss, ist gezwungen sich den gesamten Code durchzulesen um die Zugriffe auf die Kommandozeilenargumente zu finden, und muss dann auch noch herausfinden was die Werte die er angeben muss, bedeuten.

Kryptische Abkürzungen bei Namen sollte man vermeiden. Also `image` statt `im` und `pixels` statt `pix`.

Was soll die 1 bei `led1` bedeuten? Nicht nur das es gar keine weiteren LEDs gibt, will man Namen auch nicht durchnummerieren. Das ist in der Regel ein Zeichen das man entweder bessere Namen braucht, oder das man die Werte eigentlich in eine Datenstruktur packen möchte. Meistens eine Liste.

Für ”magische Zahlen” wie die PIN-Nummern definiert man am Anfang Konstanten. Dann weiss man im Programm immer wenn sie verwendet werden, was sie bedeuten, und man kann sie am Anfang des Quelltextes leicht verändern.

Die Werte für Breite und Höhe des Bildes würde ich auch an Namen binden, damit es verständlicher wird.

Dann kommt mit `x1` und `x2` wieder ein nummerierter Name. Was in diesem Fall unnötig ist, weil man in beiden Schleifen einfach `x` verwenden kann. Das `x` hat ja nur innerhalb der jeweiligen Schleife eine Bedeutung. Und in beiden Schleifen die gleiche Bedeutung. Also warum verschiedene Namen?

Wenn man das geändert hat, sieht man, dass die beiden Schleifenkörper exakt die gleichen fünf Zeilen Code enthalten. Sowohl Code als auch Daten sollte man nicht wiederholen. Das verletzt das DRY-Prinzip („Don't Repeat Yourself“). Kopien blähen den Code unnötig auf und erhöhen die Fehleranfälligkeit bei Änderungen, weil man Änderungen immer an allen Kopien durchführen muss, und auch bei allen äquivalent.

Eine Änderung wäre beispielsweise aus den drei Zeilen für die `r`, `g`, `b`-Zuweisungen *eine* ohne die Indexzahlen zu machen, in dem man das Pixel einfach auf die drei Namen entpackt:

Code: Alles auswählen

            r = pixels[x, y][0]
            g = pixels[x, y][1]
            b = pixels[x, y][2]

            # =>

            r, g, b = pixels[x, y]
Da mit jedem der drei Werte das gleiche gemacht wird, braucht man die Namen aber auch nicht wirklich. Das lässt sich gleich bei der Zuweisung an das `color`-Attribut per „list comprehension“ erledigen.

Umgekehrte `range()`\es zu berechnen ist fehleranfällig. Ich weiss zum Beispiel jetzt nicht ob es Absicht von Dir ist, das `x` von 0 bis `width`-1 hochgezählt, dann aber nur von `width`-1 bis 2 runtergezählt wird:

Code: Alles auswählen

In [16]: range(10)
Out[16]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

In [17]: range(10-1, 1, -1)
Out[17]: [9, 8, 7, 6, 5, 4, 3, 2]
Ich vermute mal Du wolltest eigentlich komplett wieder runter. `reversed()` ist da IMHO leichter zu verstehen:

Code: Alles auswählen

In [18]: list(reversed(range(10)))
Out[18]: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
Und um aus den beiden inneren Schleifen eine einzige Schleife zu machen, braucht man dann noch `itertools.chain()`. Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python
from __future__ import absolute_import, division, print_function
import sys
from itertools import chain
from time import sleep

from gpiozero import RGBLED
from PIL import Image

RED_PIN = 16
GREEN_PIN = 20
BLUE_PIN = 21


def main():
    image_filename = sys.argv[1]
    delay = float(sys.argv[2])

    image = Image.open(image_filename).convert('RGB')
    width, height = image.size
    pixels = image.load()
     
    led = RGBLED(RED_PIN, GREEN_PIN, BLUE_PIN)

    for y in range(height):
        for x in chain(range(width), reversed(range(width))):
            led.color = [rgb_component / 255 for rgb_component in pixels[x, y]]
            sleep(delay)


if __name__ == '__main__':
    main()
DatMichi
User
Beiträge: 29
Registriert: Montag 25. Mai 2015, 20:35

Danke für deine Kritik vor allem weil du gleich erklärst warum und wie man es einfacher / besser machen kann und nicht einfach schreibst ist scheiße.
Ich fange erst gerade mit Python oder überhaupt mit einer Programmiersprache an.

Ich werde das was du mir geschrieben hast anschauen und den Code dahin ändern.

Vielen Danke erstmal ich komme bestimmt mit weitern Fragen zurück.
Antworten