LED Strip Animationen und Effekte mit Python programmieren

LED Strip Animationen und Effekte mit Python programmieren - Control-LED

Die rpi_ws281xx library ist auf dem Pi erfolgreich installiert und das Testprogramm läuft. Nein???
Kein Problem! Lese dir meinen letzten Beitrag: Adressierung von LED Strips mit dem Raspberry Pi  durch und installier die library.

Und es funktioniert?
Perfekt, in dem Post möchte ich dir coole Animationen zeigen, die du damit programmieren kannst.
Die Codes kannst du aus den Code Containern kopieren oder du lädst dir das fertige Programm aus dem Anhang herunter!


Vielleicht kannst du die Effekte noch verschönern? Die Programme habe ich in Anlehung an das GitHub Repository rpi_ws281xx_library und aus den Arduino Codebeispielen von der Seite Tweaking4All erstellt.  cheeky

 

 

import time, math
from rpi_ws281x import PixelStrip, Color
import argparse

# LED strip configuration:
LED_COUNT = 70       # Number of LED pixels.
LED_PIN = 13          # GPIO pin connected to the pixels (18 uses PWM!).
# LED_PIN = 10        # GPIO pin connected to the pixels (10 uses SPI /dev/spidev0.0).
LED_FREQ_HZ = 800000  # LED signal frequency in hertz (usually 800khz)
LED_DMA = 10          # DMA channel to use for generating signal (try 10)
LED_BRIGHTNESS = 255  # Set to 0 for darkest and 255 for brightest
LED_INVERT = False    # True to invert the signal (when using NPN transistor level shift)
LED_CHANNEL = 1       # set to '1' for GPIOs 13, 19, 41, 45 or 53

 

RPI_ws281x library mit Paramter initialisieren

Als erstes legen wir die Parameter der library fest und importieren die nötigen librarys.

 

Main Routine

 

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('-c', '--clear', action='store_true', help='clear the display on exit')
    args = parser.parse_args()
    strip = PixelStrip(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL)
    strip.begin()

    print('Press Ctrl-C to quit.')
    if not args.clear:
        print('Use "-c" argument to clear LEDs on exit')
    try:
        while True:
            #Entkommentieren um Programm auszuwählen
            #colorWipe(strip, color)
            #theaterChase(strip)
            theaterChaseRainbow(strip)
            #pulsing_light(strip)
            #snow_sparkle(strip)
            #strobe(strip)
            #bouncing_balls()
    except KeyboardInterrupt:
        if args.clear:
            colorWipe(strip, Color(0, 0, 0), 10)

 

Erklärung: Die Effekte werden in der while Schleife abgespielt. Wird dem Programm das Argument "-c" übergeben, wird bei einem Keyboard Interrupt mit STRG+ C alle LEDs ausgeschalten.

 

1. LED Strip Animation "color_wipe"

"Die Animation "color_wipe" wischt die Farben rot, grün und blau über den LED Streifen. Zum Testen ob alles funktioniert."

 

def colorWipe(strip, color, wait_ms=50):
    """Wipe color across display a pixel at a time."""
    for i in range(strip.numPixels()):
        strip.setPixelColor(i, color)  #Funktion rpi_ws281x.color wandelt DEC in BIN  um
        strip.show()
        time.sleep(wait_ms / 1000.0)

 

Erklärung:
Über die Main Routine wird die Funktion "color_wipe" aufgerufen. Als Funktionsargument wird der Wert Color(r,g,b) übergeben. Durch den import der Datei ws281xx findet man zu der Funktion color den Code. Dort werden die RGB Werte in binäre Werte umgewandelt.
Der Befehl strip.setPixelColor(i, color) benötigt binäre Werte!
 

2. LED Strip Animation "theaterChase"

"In der Animation "theaterChase" wird vorest jede dritte Pixel mit einer definierten Farbe gesetzt(LED=ON). Im Verlauf wird die Pixelnummeriung chronologisch um 1 erhöht. Der Effekt baut Spannung auf."

 

def theaterChase(strip, color, wait_ms=50, iterations=10):
    """Movie theater light style chaser animation."""
    for j in range(iterations):
        for q in range(3):
            for i in range(0, strip.numPixels(), 3):
                strip.setPixelColor(i + q, color)
            strip.show()
            time.sleep(wait_ms / 1000.0)
            for i in range(0, strip.numPixels(), 3):
                strip.setPixelColor(i + q, 0)

 

 

Erklärung:
Der Wert "iterations=10" gibt der Funktion die Anzahl der Wiederholungen, die die Anzahl der Iterationen der for loop bestimmen. In der zweiten for loop wird die Pixelnummerierung jeweils um 1 erhöht. In der dritten for loop werden die LEDs nach dem 3er Intervall System auf die ganze Länge des LED Strips erweitert. In der vierten for loop, die in der dritten eingebettet ist, werden die gesetzten LEDs wieder ausgeschalten.

 

3. LED Strip Animation "theaterChaseRainbow"

"Bei der Animation "theaterChaseRainbow" wird jedes dritte Pixel auf einen Wert im Farbspektrum(Regenbogen) gesetzt. Dadurch entsteht ein farbenprächtiges Spektakel."

 

def theaterChaseRainbow(strip, wait_ms=50):
    """Rainbow movie theater light style chaser animation."""
    for j in range(256):
        for q in range(3):
            for i in range(0, strip.numPixels(), 3):
                strip.setPixelColor(i + q, wheel((i + j) % 255))
            strip.show()
            time.sleep(wait_ms / 1000.0)
            for i in range(0, strip.numPixels(), 3):
                strip.setPixelColor(i + q, 0)

 

Erklärung:
Der Wert für j gibt die Position im Farbrad(Funktion wheel) an. .
Funktion wheel:
♦Zwischen 0-85 wird Rot auf 255 erhöht und Grün sinkt auf 0. Blau bleibt unverändert.
♦Zwischen 85-170 sinkt Rot auf 0 und erhöht und blau steight auf 255. Grün bleibt unverändert.
♦Zwischen 170-255 steigt Grün auf 255 und blau sinkt auf 0. Rot bleibt unverändert.

Sobald die Iteration über das Farbrad den Wert 255 erreicht hat ist der Farbfade vorbei und die Animation zu Ende. Die zweite for loop setzt wie bei dem Programm theaterChase schaltet jeweils eine LED weiter. Die dritte erweitert dieses Muster auf die ganze LED Strip.

 

4. LED Strip Animation "rainbow"

"Das Programm erstellt das Farbspektrum im Abstand zwischen zwei vollen Farben.Ein Rgenbogen ohne Regen. Sowas gibts nur auf LED Strips"

 

 

def rainbow(strip, wait_ms=20, iterations=1):
    """Draw rainbow that fades across all pixels at once."""
    for j in range(256 * iterations):
        for i in range(strip.numPixels()):
            strip.setPixelColor(i, wheel((i + j) & 255))
        strip.show()
        time.sleep(wait_ms / 1000.0)

 

Erklärung:

Der Regenbogen wird über das Farbrad (Funktion wheel erzeugt). Da der Regenbogen jedoch 10 mal angezeigt werden soll würden die Werte wheel(i+j) den Wert 255 überschreiten. Aus diesem Grund wird der Wert 255 mit einem logisch & verglichen. Dieser Vergleich setzt die binären Ziffern nur bei Übereinstimmung auf 1. Die Folge davon ist, das die Zahl 256 eine binäre 00000000  darstellt. So wiederholt sich das Farbrad wieder von vorne.

5. LED Strip Animation "pulsing_light"

"Wie der Name sagt, pulsieren die LEDs auf dem Streifen. Pulsieren deshalb, da die Helligkeitswerte in jedem Pixel nach dem System einer Sinusfunktion sich verändern. Erstaunlich was?"

 

 

 

def pulsing_light(strip, wait_ms=50, iterations=10):
    """Helle LIchteffekte in Kette"""
    position = 0
    for i in range(strip.numPixels() * 2):
        position = position+1
        for j in range(strip.numPixels()):
            strip.setPixelColor(j,Color(round(((math.sin(j+position) * 127 + 128)/255)*255),round(((math.sin(j+position) * 127 + 128) /255)*100), round(((math.sin(j+position) * 127 + 128) /255)*100)))
        strip.show()
        time.sleep(wait_ms/1000.0)

 

 

Erklärung:
Die Farbwerte werden in der Sinus-Funktion generiert. Funktion: math.sin(j+position) * 127 + 128/255) *255
Der Wert der Sinuskurve liegt zwischen 0 und 1. Umso länger die LED Kette, desto höher wird der Wert   (j+position) in deKlammer.
Gefolgt von der Sinusfunktion werden die Werte mit *127+128/255 multipliziert und addiert und zusätzlich durch 255 geteilt. Dese Zahlen verschieben einmal die Sinus-Funktion um +128 Punkte auf der y-Achse und stellen den Sinuswert in Korellation mit dem RGB Wert. (sprich: Welche Werteveränderung der Sinusfunktion , ändern den RGB Wert um 1 Punkt. Durch die Muliplikation von 255 wird der maximale RGB Wert (i.d.Fall 255)
(sprich: Der Hochpunkt der Sinusfunktion hat den RGB Wert 255)

 

6. LED Strip Animation "strobe"

"Schnelle helle Blitze wie aus einem Stroboskop. Das flasht richtig!"

 

 

def strobe(strip, wait_ms=400, strobe_count=7, pulse_count=12):
    from random import randrange
    """LED als springender Ball"""
    for strobe in range(strobe_count):    
        for pulse in range(pulse_count):
            for i in range(strip.numPixels()):
                strip.setPixelColorRGB(i, 255,255,255)
            strip.show()
            time.sleep(randrange(0,45,1)/1000.0)
            for i in range(strip.numPixels()):
                strip.setPixelColorRGB(i, 0,0,0)
            strip.show()
        time.sleep(wait_ms/1000.0)

 

 

Erklärung:
In strobe_count wird die Häufigkeit der Blitze eingestellt. Die Variable pulse_count stellt die Wiederholung der Blitze ein. Die Zeit zwischen den Pulsen ist eine Zufallszahl zwischen 0 und 45 ms time.sleep(randrange(0,45,1). 

 

7. LED Strip Animation "snow_sparkle"

"Aufleuchtender Schneesplitter auch mit Sonnenbrille sehbar. Ja der ist hell!"

 

 

def snow_sparkle(strip,sparkle_delay=20):
    from random import randint
    pixel= randint(0,strip.numPixels())
    speed_delay=randint(100,1000)
    for i in range(strip.numPixels()):
        strip.setPixelColor(i, Color(0x10,0x10,0x10))
    strip.show()
    time.sleep(speed_delay/1000.0)
    strip.setPixelColorRGB(pixel, 255,255,255)
    strip.show()
    time.sleep(sparkle_delay/1000.0)

 

Erklärung:
Eine Zufallspixel, sowie eine Zufallszeit zwischen 100ms und 1 s  werden "ausgewürfelt". Die Ganze LED Strip leuchten leicht weiss mit den Werten(0x10,0x10,0x10) in RGB(16,16,16). Der Zufallspixel leuchtet in der Zufallszeit kurz auf und verschwindet wieder.

8. LED Strip Animation "bouncing_balls"

"Schleudernde LED Pixel nach physikalischen Gesetzen. Wie im Film!"

 

 

def bouncing_balls(strip,ball_count=4, wait_ms=200):

    start_time = time.time()
    ClockTimeSinceLastBounce = [0 for i in range(ball_count)]
    StartHeight=1

    for i in range(ball_count):
        ClockTimeSinceLastBounce[i] = time.time()
    
    Height = [0 for i in range(ball_count)]
    Position = [0 for i in range(ball_count)]
    ImpactVelocity = [0 for i in range(ball_count)]
    ImpactVelocityStart= math.sqrt(-2 * -9.81 * 1)
    Dampening = [0 for i in range(ball_count)]
    TimeSinceLastBounce = [0 for i in range(ball_count)]

    for i in range(0,ball_count,1):
        last_ClockTimeSinceLastBounce = ClockTimeSinceLastBounce[i]
        ClockTimeSinceLastBounce[i] = time.time() - last_ClockTimeSinceLastBounce

        Height[i] = StartHeight
        Position[i] = 0
        ImpactVelocity[i] = math.sqrt(-2 * -9.81 * 1)
        TimeSinceLastBounce[i] = 0
        Dampening[i] = 0.90 - (float(i)/(ball_count**2))

    while True:
        for i in range(ball_count):
            TimeSinceLastBounce[i] = time.time() - ClockTimeSinceLastBounce[i]
            Height[i] = 0.5 * (-9.81) * (TimeSinceLastBounce[i]**2) + ImpactVelocity[i] * TimeSinceLastBounce[i]
            if (Height[i] < 0):
                Height[i] = 0
                ImpactVelocity[i] = Dampening[i] * ImpactVelocity[i]
                ClockTimeSinceLastBounce[i] = time.time()
                if (ImpactVelocity[i] < 0.01):
                    ImpactVelocity[i] = ImpactVelocityStart
                                  
            Position[i] = round(Height[i] * (strip.numPixels()-1)/StartHeight)   #Hier wird die relative Höhe auf die absolute Höhe mit der LED Anzahl umgewandelt.
        for i in range(ball_count):
            strip.setPixelColorRGB(Position[i], 0, 0,255)    
        strip.show()
        for i in range(strip.numPixels()):
            strip.setPixelColorRGB(i, 0,0,0)
            
def snow_sparkle(strip,sparkle_delay=20):
    from random import randint
    pixel= randint(0,strip.numPixels())
    speed_delay=randint(100,1000)
    for i in range(strip.numPixels()):
        strip.setPixelColor(i, Color(0x10,0x10,0x10))
    strip.show()
    time.sleep(speed_delay/1000.0)
    strip.setPixelColorRGB(pixel, 255,255,255)
    strip.show()
    time.sleep(sparkle_delay/1000.0)

 

 

Erklärung:
Es werden Listen erstellt, in denen die Werte(Height, ClockTimeSinceLastBounce, Position...) gespeichert sind. In der Endlosschleife werden die Pixel anhand den Werten die zu setzenden Pixel gerechnet...