ESP32 Mikrocontroller mit RGB-LEDs

ESP | Kreativ mit RGB-LEDs - additive Farbmischung, Farbverlauf, Lauflicht


Mit RGB-LEDs lassen sich alle Farben mischen, Farbverläufe kreieren, Blinkmuster erzeugen und sich verändernde Farbmuster in Lauflichtern darstellen. Jede RGB-LED besitzt eine rote, grüne und blaue LED die so eng beinander platziert sind, dass sich die Farben mischen lassen.

In diesem Abschnitt lernst Du die additive Farbmischung kennen, kannst Farbverläufe erzeugen und Blinkmuster sowie Lauflichter programmieren.

🎨 Farbmischung mit der RGB-LED

RGB-LED an Pin 4
Abb. 1 RGB-LED an Pin 4.
Farbmischungstest

Wir demonstrieren das Grundprinzip der RGB-Farbmischung. Jede Farbe: rot, grün, blau, gelb, cyan, magenta und weiß werden programmiert und die zehn RGB-LEDs an Pin 4 (s. Abb. 1) angesteuert.

produkt = ("Tesla", "Model X", 100000)

Tupel ähneln Listen. Die meisten üblichen Listenoperationen sind auch mit Tupeln möglich. Sie werden aber mit runden statt mit eckigen Klammern geschrieben.

Wichtige Eigenschaften von Tupeln:

  • unveränderlich (immutable)
  • es kann auch kein Wert hinzugefügt oder gelöscht werden
  • unterschiedliche Datentypen möglich

from machine import Pin
import neopixel, time

NUMBEROFLEDS = 10
PIN = 4
np = neopixel.NeoPixel(Pin(PIN, Pin.OUT), NUMBEROFLEDS)

def setColor(farbcode):
    for i in range(NUMBEROFLEDS):
        np[i] = farbcode
    np.write()

def colorMixingTest():
    print("\n🎨 Farbmischung-Test")
    farben = [(255,0,0), ...]
    for farbcode in farben:
        setColor(farbcode)
        time.sleep(1)

while True:
    colorMixingTest()

Jede Farbe wird als RGB-Tupel (255,0,0) definiert und über die Funktion setColor() ausgegeben.

Wir importieren die notwendigen Bibliotheken und definieren die Anzahl der LEDs auf dem LED-Streifen sowie die Pinnummer. Dann erzeugen wir ein Objekt um den LED-Streifen ansteuern zu können.

Die Funktion setColor wird der Farbcode als Tupel übergeben und mit einer Schleife schreiben wir diesen Farbcode auf jede LED. Die gepseicherten Werte werden anschließend mit np.write() ausgegeben.

In der Funktion colorMixingTest schreiben wir eine Liste mit verschiedenen Farben. Die verschiedenen Farbcodetupels speichern wir in einer Liste. Über eine for-each-Schleife senden wir all diese Farbcodes an die Funktion setColor zur Ausgabe und bauen noch eine Zeitverzögerung ein.

Helligkeit und Anzeige

BRIGHTNESS = 0.1

def setBrightness(farbe):
    r,g,b = farbe
    r = int(r * BRIGHTNESS)
    g = int(g * BRIGHTNESS)
    b = int(b * BRIGHTNESS)
    return(r,g,b)
    
def setColor(farbe):
    farbeskaliert = setBrightness(farbe)
    for i in range(NUMBEROFLEDS):
        np[i] = farbeskaliert
    np.write()

Wir ergänzen unser Programm um eine weitere Funktion setBrightness. Mit dieser können wir die Helligkeit der LEDs skalieren. Dies ist deshalb sinnvoll, da die Farbcodes in Farbpaletten in der Regel immer auf den Maximalwert 255 ausgelegt sind.

def colorMixingTest():
    print("\n🎨 Farbmischung-Test")
    farben = [((255,0,0),"Rot"), ...]
    for farbcode, farbname in farben:
        print(f" →{farbname}")
        setColor(farbcode)
        time.sleep(1)

Des weiteren Ergänzen wir die Farbliste noch mit dem Farbnamen. Um noch den Farbnamen mitzuspeichern erweitern wir jedes Tupel in der Liste zu ((255,0,0),"Rot"). Mit for farbcode, farbname in farben können wir uns so zusätzlich mit print(f" →{farbname}") die aktuell angezeigte Farbe ausgeben lassen.

Arbeitsauftrag 1

🎨 Farbmischung-Test

  1. Erstelle den Ordner RGB-LED.
  2. Erstelle die Datei rgb.py und programmiere die zwei Funktionen setColor und colorMixingTest.
  3. Binde alle notwendigen Libraries ein.
  4. Test die Funktionen einzeln auf korrekte Ausführung.

💡 Helligkeit skalieren

  1. Ergänze dein Programm mit der Funktiion setBrightness(farbe) zur Skalierung der Helligkeit.
  2. Ergänze in deiner Funktion colorMixingTest die Farbliste mit Angabe der Farbe farben = [((255,0,0),"Rot"),...] und gib die Farbe aus.
  3. Test die Ausgabe von Farbpaletten.
  4. Bewerte welche Farben gut und weniger gut dargestellt werden.

🎨 Farbverlauf Fadeeffekt

Für einen Farbverlauf oder Fadeeffekt müssen wir die LEDs zeitverzögert zu Ihrem Maximalwert hochzählen und dann wieder runterzählen. Wir definieren uns wieder eine Liste mit Farben und arbeiten diese in einer Schleife ab. Als erstes speichern wir uns die drei Maximalwerte der Farben rMax, gMax, bMax und legen die Anzahl der Schritte fest.

Damit wir nun jeden der drei Farbwerte bis zu seinem Maximalwert hochzählen multiplizieren wir den Maximalwert der Farbe r = int(rMax * i/steps) mit dem Index und teilen ihn gleichzeitig durch die Anzahl der Schritte.

       
def colorFadeEffect():
    print("\n🎨 Farbverlauf,")
    farben = [((255,0,0),"Rot"),((0,255,0),"Grün"),((0,0,255),"Blau")]
    for farbcode,farbname in farben:
        print(f" →{farbname}")
        rMax,gMax,bMax = farbcode
        steps = 100
        for i in range(steps+1):
            r = int(rMax * i/steps)
            g = int(gMax * i/steps)
            b = int(bMax * i/steps)
            setColor((r,g,b))
            time.sleep_ms(10)
        for i in range(steps,-1,-1):
            r = int(rMax * i/steps)
            g = int(gMax * i/steps)
            b = int(bMax * i/steps)
            setColor((r,g,b))
            time.sleep_ms(10)
        time.sleep_ms(100)

🎨 Farblauflicht

Zeitablaufdiagramm für ein Lauflicht mit sechs LEDs
Abb. 2 Ausschnitt aus einem Zeitablaufdiagramm für ein Lauflicht mit sechs LEDs.

Lauflichter werden typischerweise als Statusanzeige für den Batterieladestand oder eine Fortschrittsanzeige verwendet. Aber auch für Dekorations- und Beleuchtungszwecke lässt es sich einsetzten. Auch auf Baustellen wendet man sie an um die Verkehrsführung zu optimieren. Abb. 2 zeigt einen Ausschnitt aus einem Zeitablaufdiagramm für ein Lauflicht mit sechs LEDs.

In unserem Fall wollen wir ein einfaches LED-Lauflicht erzeugen bei dem wir aber den Farbton für jede LED aus einer Liste von Farben verändern. Dies können die Regenbogenfarben sein aber auch die Farben einer Farbpalette. Darüber hinaus kann man die Geschwindigkeit von LED zu LED erhöhen. So steigert man die Aufmerksamkeit.

Die verwendete Farbpalette wechselt von orange zu einem intensiverem rot. Das wird dadurch erreicht, dass grün reduziert wird und am Ende sogar die Intensität von rot auch reduziert wird.

Da wir nun die einzelnen LEDs ansteuern können wir nicht mehr auf unsere Funktion setColor zurückgreifen. Mit Hilfe einer for-Schleife mit Index for i,farbcode in enumerate(farben) können wir einerseits auf die verschiedenen Farbcodes zugreifen und anderseits die einzelnen LEDs durchschalten np[i] = (farbcode). Man beachte, dass durch np[i] = (0,0,0) die letzte LED wieder gelöscht wird.


def colorLoop():
    print("\n🎨 Farb-Lauflicht")
    farben = [(100,70,0),(100,55,0),(100,40,0),
              (100,25,0),(100,10,0),(85,0,0),
              (70,0,0),(55,0,0),(40,0,0),(25,0,0)]
    
    for i,farbcode in enumerate(farben):
        np[i] = (farbcode)
        np.write()
        time.sleep_ms(500)
        np[i]=(0,0,0)

Arbeitsauftrag 2

🎨 Farbverlauf

  1. Programmiere die Funktionen colorFadeEffect(). Die Funktion soll drei Farben in einer Liste nacheinander ausgeben. Dabei sollen sie die Farben langsam ein- und wieder ausgeschaltet werden.
  2. Teste verschiedene Zeitverzögerungen.
  3. Verkürze den Quelltext durch die Verwendung von List Comprehension.

🎨 Farblauflicht

  1. Ergänze dein Programm mit der Funktion colorLoop() für ein Lauflicht mit verschiedenen Farben.
  2. Erstelle eine eigene Farbpalette.
  3. Ändere die Funktion so ab, dass ein Lauflicht für eine Autobahnbaustelle entsteht. Die LEDs sollen zunehmend kürzer aufleuchten und bspw. am Ende alle kurz blinken.
  4. Vergleiche verschiedene verkehrsführende Lichter und vergleiche die Einsatzzwecke.

🌈 Regenbogen-Farbverlauf

RGB-LED an Pin 4
Abb. 3 Sinusgewichteter Farbverlauf einer RGB-LED.
Farbverlauf

Abb. 3 zeigt einen möglichen Farbverlauf der Regenbogenfarben. Auch wenn die Mischfarben magenta, gelb und cyan hier etwas untergewichtet sind bildet der zeitliche Verlauf eine solide Grundlage, da die drei Farben mit mathematischen Funktionen zu berechnen sind, ohne dass man eine Bedingung benötigt.

Wir machen uns die Sinusfunktion f(t) = sin(2π/360 ⋅ (t-t0)) zu Nutze. Mit Ihr können wir die notwendigen Werte berechnen. Um die negativen Werte abzuschneiden arbeiten wir zusaätzlich mit der Max-Funktion max(Wert1;Wert2). Diese gibt den größeren beider Werte aus. Da der eine Wert 0 ist, werden alle negativen Werte abgeschnitten.


from math import sin, pi

def rainbowLoop():
    print("\n🌈 Regenbogen-Farbverlauf")
    a = BRIGHTNESS * 255
    for t in range(361):
        for i in range(NUMBEROFLEDS):
            phase = 360 / NUMBEROFLEDS * i 
            r = max(0, round(a * sin(2*pi/360 * (t + phase))))
            g = max(0, round(a * sin(2*pi/360 * (t + phase - 120))))
            b = max(0, round(a * sin(2*pi/360 * (t + phase - 240))))

            np[i] = (r, g, b)
        np.write()
        time.sleep(0.01)

Vom Mathemodule importieren wir die Sinusfunktion und die Zahl Pi.a ist die Amplitude der Sinusfunktion, d.h. der Maximalwert, den wir skalieren.

Mit der ersten Schleife for t in range(361) zählen wir 360 Grad in 1er-Schritten. Danach wiederholt sich der Ablauf periodisch. Mit der zweiten Schleife for i in range(NUMBEROFLEDS) schreiben wir die Werte auf jede der zehn RGB-LEDs. Man beachte dass nach jedem Schreibvorgang der 10 LEDs die Werte ausgegeben werden np.write() und eine kurze Zeitverzögerung von 10 ms erzeugt wird.

Jede der drei Farben hat eine Phasenverschiebung von 120 Grad. Dazu addieren wir die Phase phase = 360 / NUMBEROFLEDS * i. Hierdurch erreichen wir, dass der Regenbogen wandert. D.h. wir haben ein Regenbogenlauflicht inklusive Farbverlauf erzeugt.

Arbeitsauftrag 3 🌈 rainbow loop

Rainbow loop

  1. Erstelle die Datei rainbowloop.py und programmiere zuerst die einzelnen Farben für den LED-Streifen mit Hilfe der Sinusfunktion.
  2. Ergänze das Programm so, dass der Regenbogen mit einem Farbverlauf wandert.

Gleichmäßige Gewichtung der Farben

  1. Erstelle ein Zeitablaufdiagramm in dem alle Farben rot, gelb, grün, cyan, blau und magenta gleich gewichtet sind.
  2. Überlege Dir in einem zweiten Schritt ob Du eine mathematische Funktion findest mit der Du den Zeitablauf programmieren kannst, oder ob du über Bedingung die einzelnen Werte begrenzen musst.
  3. Programmiere die Erweiterung.


🎯 Arbeitsauftrag 4 Lauflicht für einen Informationsstand

Situationsbeschreibung

Du sollst für einen kleinen Messe-Informationsstand ⓘ ein visuelles Lauflicht entwickeln. Ein ESP32 steuert dabei einen RGB-LED-Streifen mit 10 LEDs.

Das Licht soll nacheinander jede LED aufleuchten lassen, anschließend in die andere Richtung laufen und sich farblich anpassen.

Gegebenes Grundgerüst in Micropython:

from machine import Pin
import neopixel
import time

NUMBEROFLEDS = 10
PIN = 4
np = neopixel.NeoPixel(Pin(PIN, Pin.OUT), NUMBEROFLEDS)
				
Auftragsbearbeitung

4.1 Programmiere ein Lauflicht, das:

  • LED 0 bis LED 9 nacheinander (0,1 s) in Rot einschaltet.
  • Danach LED 9 bis LED 0 in Grün einschaltet.
  • Nach jedem Durchlauf sollen die LEDs ausgeschaltet werden.

Die Lösung sollte folgendermaßen aussehen:


def messeLauflicht():
	for i in range(10):
        np[i]=(255,0,0)
        np.write()
        time.sleep(0.1)

	...

4.2 Auf der Messe stellt Dir ein Besucher einige Fragen zu dem Programm, da er es selber nachbauen möchte.

4.2.1 Er fragt nach der notwendigen Bibliothek für die WS2812/NeoPixel-LEDs in Micropython. Wähle eine Antwort.

  1. import rgb
  2. import np.neopixel
  3. import neopixel
  4. np = neopixel.NeoPixel(...)


4.2.2 Erkläre ihm die Bedeutung von
np = neopixel.NeoPixel(Pin(4, Pin.OUT), 10). Wähle eine Antwort aus.

  1. Es wird eine Variable für 10 Farbwerte ohne Hardware erzeugt.
  2. Die Bibliothek für den RGB-Streifen wird importiert.
  3. Es wird ein Objekt für den LED-Streifen erzeugt.
  4. Es setzt alle LEDs zurück und schaltet sie ein.



4.2.3 Erkläre ihm, wie man eine einzelne LED auf Rot setzt. Wähle eine Antwort.

  1. np.set(0, 255,0,0)
  2. np[0] = (255,0,0)
  3. np.pixel(0,255)
  4. np[255,0,0] = 0


4.2.4 Zeige ihm, mit welcher Schleife die LEDs vorwärts laufen. Wähle eine Antwort.

  1. for i in range(0, 10):
  2. for i in range(9, -1, -1):
  3. for i in reverse(10):
  4. for i in farben:


4.3 Ein anderer Besucher hat noch grundlegende Fragen zu den Schleifen in Python. Kannst Du ihm helfen?

4.3.1 Quelltext:
for i in range(10,-1,0):
  print(i, end=" ")

Gib die Ausgabe an. Wähle eine Antwort.

  1. 10 9 8 7 6 5 4 3 2 1 0
  2. 9 8 7 6 5 4 3 2 1 0 -1
  3. -1 0 1 2 3 4 5 6 7 8 9
  4. 9 8 7 6 5 4 3 2 1 0


4.3.2 Quelltext
farben = ["rot", "gruen", (0,0,255)]
for farbe in farben:  print(farbe, end=" ")

Gib die Ausgabe an. Wähle eine Antwort.

  1. rot, gruen, blau
  2. 255,255,0
  3. rot gruen (0,0,255)
  4. rot, gruen, (0,0,255)

Wichtige Funktionen zum Ansteuern von Sensoren



from machine import Pin, I2C importieren der Klassen Pin und I2Caus dem Modul machine
i2c = I2C(0, scl=Pin(22), sda=Pin(21)) I2C-Objekt am Pin 21 und 22 erzeugen
print(f"H: {humidity:.2f} %") Formatierte Ausgabe eines Sensorwertes
x, y, z = lis.read() Funktionsaufruf mit drei Rückgabewerten
messwerte={"wert1": 20.1, "wert2": 36.2} Aufbau eines Dictionaries