Von Erleuchtungen und Lichterketten

Der Pragmatische Architekt  –  5 Kommentare

Wer eBay nach Stichworten wie "NeoPixel" oder "WS2811" durchsucht, erhält eine schier endlose Liste von Angeboten.

"WS" steht für WorldSemi und bezeichnet den Hersteller der Chips WS2811, WS2812 und WS2812B. Der Baustein WS2811 dient dazu, RGB-LEDs zu kontrollieren. Die Kombination einer LED mit einem WS2811 ergibt einen WS2812B-Baustein bzw. in älteren Varianten einen WS2812-Baustein.

Ein WS2812x enthält neben der eigentlichen RGB-LED eine Kontrolllogik in Form des WS2811-Controllers (Bild: Adafruit)

Die angebotenen Produkte basieren in der Vielzahl auf LEDs in kleinen und kostengünstigen SMD-Versionen. Fast immer handelt es sich um eine 5050 LED mit 5 mm x 5 mm = 25 mm² Oberfläche. Deren Lichtstärke beträgt 16–22 Lumen. So ein Winzling kann je nach Lichtintensität bis zu 60 mA verbrauchen. Der meiste Verbrauch ergibt sich bei voller Intensität der Rot-, Grün- und Blau-LED, also bei intensivem Weiß. Eine Ansteuerung von Dutzenden Pixeln, die üblicherweise in Rudeln auftreten, benötigt daher ganz schnell einmal mehrere Ampere. Das übersteigt die Möglichkeiten jedes handelsüblichen Mikrocontroller-Boards.

Nur einmal als Beispielrechnung: Ein 5 Meter langer LED-Streifen mit nur 30 Pixeln pro Meter verlangt nach einem Netzteil mit 5 V Ausgangsspannung und bis zu 9 A Stromstärke.

Es gibt aber statt der SMD 5050 LEDs noch weitere SMD-Alternativen:

  • 3528: 3.5 mm x 2.8 mm = 9.8 mm², 6–8 Lumen, 20–30 mA.
  • 5630: 5.6 mm x 3.0 mm = 16.8 mm², 45–50 Lumen, 150 mA.

Zudem existieren Standard RGB-LEDs mit THT (Through-Hole-Technology), etwa die üblichen LEDs mit 5 mm Durchmesser.

Mittlerweile werden RGBW-Pixel als weitere Variante angeboten. Diese enthalten neben einer Rot-, Grün-, und Blaukomponente eine zusätzliche weiße LED. Dadurch kommt laut Herstellern ein augenfreundlicheres Licht zustande.

Ein Baustein des Typs WS2811 wirkt winzig, hat es aber in sich. Er vereinigt im Detail:

  • einen internen Taktgeber. Der ist notwendig, um das Timing zu überprüfen, und zum Beispiel zu ermitteln, ob ein ankommendes Signal eine 0 oder eine 1 darstellt.
  • Logik zur Signalmodellierung und -verstärkung. Jeder Pixel übernimmt ankommende Daten und lässt weitere Daten an die nachfolgenden Pixel weiter. Das ist auch als Kaskadierung bekannt.
  • einen digitalen Eingang (D0), der die Daten vom vorherigen Pixel übernimmt. Beim ersten Pixel in der Kette kommen die Daten von einem Mikrocontroller, in unserem Fall vom Arduino.
  • einen digitalen Ausgang (D1), um Daten an die nachfolgenden Pixel weiter zuleiten, sofern vorhanden.
  • 3-Kanalsteuerung der einzelnen Farb-LEDs um Lichtintensitäten zwischen 0 und 255 einzustellen.
  • Einen Datalatch, um empfangene Datenpakete zwischenzuspeichern. Es handelt sich hier um ein FIFO-Shiftregister.

Ein an einen WS2811 versandtes Datenpaket besteht aus 24 Bit, je 8 Bit für Rot, Grün, Blau. Bei Hintereinanderschaltung mehrerer Pixel fließen demzufolge Sequenzen von 24-Bit-Paketen über die Datenleitung. Zwischen solchen Übertragungen werden Pausen von 50 µsecs eingeschoben.

Auf LED-Streifen finden sich meistens Pfeile zwischen den Pixeln, die die Übertragungsrichtung der Daten anzeigen.

Für die Zusammenschaltung von WS8212B-Komponenten ergeben sich mehrere mögliche Bauformen.

  • Matrizen: Eine häufige Konstellation sind 8x8-Matrizen. Durch Schaltung der einzelnen Pixel können Entwickler auch Symbole und Buchstaben darstellen.
Matrix mit 8 x 8 LEDs (Bild: Adafruit)
  • Sticks mit 4, 8 oder 16 Pixeln passen gut auf Breadboards stecken. Mit 16 Sticks à 4 Pixeln ist zum Beispiel ein einfacher 4x4x4-Kubus realisierbar.
Ein Pixel-Stick mit 8 Komponenten (Bild: Adafruit)
  • Ringe dienen zum Beispiel zur Befestigung an der Kleidung oder als Wohnaccessoires (Wearables).
Ring mit 16 LEDs (Bild: Adafruit)
  • Streifen: Die häufigste Form sind Streifen mit 0,5 bis 5 Meter Länge, die 30 Pixel pro Meter, 60 Pixel pro Meter oder sogar 144 Pixel pro Meter umfassen.
LED-Strip mit 60 Pixel / Meter (Bild: Adafruit)
  • Einzelne Pixel lassen sich individuell nutzen und kombinieren.
Einzelne Pixel (Bild: Adafruit)

Daten und Taktung erfolgen beim WS281xx über eine einzelne Leitung. Normalerweise liegt die Frequenz bei 800 KHz, was einer Taktperiode von 1.25 µsecs entspricht.

Die Übermittlung einzelner Bits an einen WS2811 kommt über Rechtecksignale zustande:

  • Zur Übertragung einer binären '1' muss für 0.85 µsecs ein HIGH-Signal anliegen und für 0.40 µsecs ein LOW-Signal.
  • Zur Übertragung einer binären '0' muss für 0.40 µsecs ein HIGH-Signal anliegen und für 0.85 µsecs ein LOW-Signal.
Sequenz zur Übertragung von 0 und 1

Nach jeder Bitübertragung wechselt die Leitung wieder auf HIGH. Daraus erkennt der Taktgeber eines Pixels den Takt. Das ist auch als NZR (Non Zero Return) bekannt.

Die Reihenfolge für das 24-Bit-Datenpaket an einen Pixel (8 Bits pro Farb-LED für Intensitäten von 0 bis 255) lautet dabei (R : Rot, G: Grün, B: Blau):

R7, R6, ..., R0, G7, G6, ..., G0, B7, B6, ..., B0

Im nachfolgenden Bild sendet ein Arduino Datenpakete à 24 Bit an alle LEDs. Der Kommunikation liegt die später beschriebene Kaskadierung zugrunde.

Paketübertragung bei hintereinander geschalteten WS2812x-Komponenten

Alle Datenpakete werden sequenziell über die Leitung geschickt.

  • IC1 nimmt Paket A entgegen, B und C werden an die nachfolgenden Pixel IC2 und IC3 weitergeschickt.
  • IC2 nimmt Paket B entgegen, C wird an IC3 weiter geschickt.

Sobald alle LEDs ihre Daten entgegengenommen haben, erfolgt eine Pause von mindestens 50 µsecs. Dadurch werden die Pakete in den jeweiligen Datalatches der ICs gespeichert, und die LEDs gemäß Intensitätsanteilen für Rot, Grün, Blau eingeschaltet. Das wiederholt sich in den darauf folgenden Zyklen, etwa für den in der Abbildung anschließenden zweiten Zyklus.

Anhand eines Fritzing-Schaltungsdiagramms betrachten wir eine Schaltung, um einen LED-Streifen anzusteuern.

Schaltung zur Ansteuerung eines LED-Streifens aus WS2812B-Pixel

Konkret sehen Sie auf dem Schaltungsdiagramm folgende Komponenten und Verbindungen:

  • GND der Pixel verbinden wir mit GND des Netzteils.
  • Zur 5-V-Spannungsversorgung der verketteten Pixel verbinden wir den Spannungseingang der Pixel mit Vout des Netzteils.
  • Arduino und Netzteil legen wir an einen gemeinsamen GND.
  • Zur Steuerung schließen wir einen beliebigen Arduino-Digital-Ausgang an den Dateneingang des ersten Pixels. Viele Beispiele verwenden dafür Digital-Pin 6.

Als Vorsichtsmaßnahmen hat die Schaltung noch zwei zusätzliche Bauteile hinzugefügt:

  • Einen 1000 µF Elektrolytkondensator zwischen Vout und GND des Netzteils, um anfängliche Spannungsspitzen zu unterbinden. Und auch dazu, um ein Energiereservoir aufzubauen, das den variierenden Energieverbrauch des WS8212B kurzfristig kompensieren kann.
  • Einen 470-Ohm-Widerstand zwischen Digital-Pin des Arduino und dem Dateneingang der geschalteten Pixel, um Signal-Fluktuationen zu vermeiden.

Mittlerweile gibt es mehrere Bibliotheken, um WS2812B-Produkte anzusteuern. Verbreitet sind z.B.

Lassen Sie sich nicht davon irritieren, dass viele Bibliotheken von Herstellern von WS2812x-Produkten stammen. Das bedeutet mitnichten, dass die Bibliotheken nicht für andere Produkte funktionieren. Solange es sich um WS2812x-Bausteine handelt und die Bibliothek nicht auf ein bestimmtes Mikrocontroller-Board zugeschnitten ist, können Sie in der Regel eine solche Bibliothek nutzen.

Dort finden Sie auch relativ komplexen, maschinennahen Inline-Code mit zahlreichen Tricks, um das Timing exakt zu realisieren. Für die verschiedenen Varianten von WS281xx bieten die Bibliotheken ebenso Unterstützung wie für unterschiedliche Mikrocontroller-Boards. Es lohnt die Mühe nicht, eine weitere Selbstbau-Bibliothek zu implementieren.

In dieser Folge beschränke ich mich auf die Adafruit-Neopixel-Bibliothek zur Programmierung eines Leuchtstreifens. Es ist allerdings unerheblich, ob tatsächlich ein Leuchtstreifen vorliegt, solange die Pixel hintereinander geschaltet sind.

Am Anfang eines Sketches ist die Bibliothek zu importieren:

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif

Der digitale Ausgang des Arduino sei Pin 6 und der Leuchtstreifen bestehe aus 30 Pixeln.

#define PIN             6
#define NUMPIXELS 30

Ich gehe davon aus, dass Sie ein Standard-Arduino-Board nutzen, sodass als Taktfrequenz 800 KHz zum Einsatz kommen. Des Weiteren gehe ich davon aus, dass Sie einen Neopixel-Streifen neueren Datums besitzen, dessen LEDs als GRB (Green, Red, Blue) konfiguriert sind. Daher lautet der Konstruktaufruf wie folgt:

Adafruit_NeoPixel pixels = 
Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

Bei anderer Konstellation entnehmen Sie der Bibliothek alternative Konfigurationsoptionen:

  • NEO_KHZ800 800 KHz Bitstream für die meisten Produkte mit WS2812 LEDs
  • NEO_KHZ400 400 KHz (Adafruit V1 Flora Pixel, WS2811 Treiber)
  • NEO_GRB Pixels sind als GRB Bitstream verdrahtet (gilt für viele Produkte)
  • NEO_RGB Pixels sind als RGB Bitstream verdrahtet (ältere Produkte wie V1 FLORA Pixel)
  • NEO_RGBW Pixels sind als RGBW Bitstream verdrahtet (RGBW Produkte)

Im setup() initialisieren Sie den Streifen (begin()), um ihn dann zu zeigen (show()). Anfangs ist allerdings noch nichts zu sehen, da die LEDs noch keine Leuchtintensität zugeordnet bekommen haben.

void setup() {
strip.begin();
strip.show();
}

In der loop()-Methode können die Farbenspiele beginnen.

Zum Beispiel könnten wir Pixel nach Pixel mit einer gewünschten Farbe zum Leuchten bringen:

for(uint16_t pixno = 0; pixno < strip.numPixels(); pixno++) {
uint32_t color = strip.Color(127,0,0); // Rot
strip.setPixelColor(pixno, color);
strip.show();
delay(50);
}

Beliebt ist auch das Chasing, also ein Lauflicht wie im Theater. Wir wiederholen die Animation zehnmal (cycle). In jedem Durchlauf werden zunächst alle LEDs mit Pixel-Nummer mod 3 == 0 schrittweise aktiviert (ein- und ausgeschaltet), danach alle LEDs mit Pixel-Nummer mod 3 == 1 und schlussendlich alle LEDs mit Pixel-Nummer mod 3 == 2. Als Farbe wählen wir ein kräftiges Blau.

uint32_t color = strip.Color(0, 0, 255); // Blau
for (int cycle=0;  cycle<10; cycle++) {  // 10 Durchläufe
for (int step=0; step<3; step++) {
for (uint16_t pixno=0; pixno<strip.numPixels(); pixno += 3) {
strip.setPixelColor(pixno+step, color); // jedes 3. Pixel an
}
strip.show();

delay(10);

for (uint16_t pixno=0; pixno<strip.numPixels(); pixno += 3) {
strip.setPixelColor(pixno+step, 0); // jedes 3. Pixel wieder aus
}
}
}
}

Spektraleffekte sind ein beliebtes Animationsmittel für Lichteffekte. Wer sich damit beschäftigt, könnte annehmen, nichts wäre leichter als die Spektralfarben des Regenbogens zu erzeugen. Leider ist das physikalisch alles andere als trivial. Letztendlich geht es darum, Wellenlängen (Maßeinheit Nanometer) in RGB-Werte (Rot/Grün/Blau-Werte) umzuwandeln.

Um Ihnen die Aufgabe zu erleichtern, habe ich im nachfolgenden Code einen physikalischen Algorithmus von Bruton verwendet. Ich habe meine englischen Kommentare nicht nach Deutsch übersetzt.


//////////////////////////////////////////////////////////////////
//
// (c) 2016, Prof. Dr. Michael Stal
// Purpose: Conversion of wavelengths (in nanometers) to
// RGB-Value (each color ranges from 0 .. 255 intensity)
// This way it is possible to draw a color spectrum
// such as the sequence of colors found in rainbows
//
// Source of Pascal- Solution:
// http://www.efg2.com/Lab/ScienceAndEngineering/Spectra.htm
// Original solution is written in FORTRAN
// Wavelength = 400 nm --------- Magenta
// Wavelength = 450 nm --------- Blue
// Wavelength = 500 nm --------- Green
// Wavelength = 550 nm --------- Light Green
// Wavelength = 600 nm --------- Orange
// Wavelength = 650 nm --------- Light Red
// Wavelength = 700 nm --------- Medium Red
// Wavelength = 750 nm --------- Darker Red
//
// Dedicated to the Public Domain
// Have fun!
//
//////////////////////////////////////////////////////////////////

#include <math.h> // math required

//////////////////////////////////////////////////////////////////
// waveLengthInInterval
// Purpose: checks containment for intervals of type [left, right[
//////////////////////////////////////////////////////////////////

#define wavelengthInInterval(VAL, LEFT, RIGHT)
((LEFT) <= (VAL)) && ((VAL) < (RIGHT))

//////////////////////////////////////////////////////////////////
// calculate RGB - values from wavelengths in nanometers
//
// Result: contains blue, green, and red values
// with red = byte 2, green = byte 1, blue = byte 0
// Parameter: wavelength in nanometers
// wavelength should be within interval [380, 780]
//////////////////////////////////////////////////////////////////


uint32_t wavelengthToRGB(uint32_t wavelength) {
double blue; // blue value
double green; // green value
double red; // red value
double factor;// factor to adjust for boundaries
const double gamma = 0.45; // according to Poynton
// const double gamma = 0.80; // according to Bruton
const double maxIntensity = 255.0;
// calculations depend on wavelength
if (wavelengthInInterval(wavelength, 380, 440)) {
red = -1.0 * (wavelength - 440.0) / (440.0 - 380.0);
green = 0.0;
blue = 1.0;
} else
if (wavelengthInInterval(wavelength, 440, 490)) {
red = 0.0;
green = (wavelength - 440.0) / (490.0 - 440.0);
blue = 1.0;
} else
if (wavelengthInInterval(wavelength, 490, 510)) {
red = 0.0;
green = 1.0;
blue = -1.0 * (wavelength - 510.0) / (510.0 - 490.0);
} else
if (wavelengthInInterval(wavelength, 510, 580)) {
red = (wavelength - 510.0) / (580.0 - 510.0);
green = 1.0;
blue = 0.0;
} else
if (wavelengthInInterval(wavelength, 580, 645)) {
red = 1.0;
green = -1.0 * (wavelength - 645.0) / (645.0 - 580.0);
blue = 0.0;
} else {
red = 1.0;
green = 0.0;
blue = 0.0;
}

// Adjust for the boundaries of the visible spectrum
if (wavelengthInInterval(wavelength, 380, 420)) { // lower spectrum
factor = 0.3 + 0.7 * (wavelength - 380.0) / (420.0 - 380.0);
} else
if (wavelengthInInterval(wavelength, 700, 780)) { // higher spectrum
factor = 0.3 + 0.7 * (780.0 - wavelength) / (780.0 - 700.0);
} else { // main spectrum
factor = 1.0;
}

// re-calculate values of red, green, blue accordingly
red = pow(factor * red, gamma);
green = pow(factor * green, gamma);
blue = pow(factor * blue, gamma);

// we place Red/Green/Blue - values
// into different bytes of the 32 Bit
// RGB result.
// byte 0 => Blue
// byte 1 => Green
// byte 2 => Red


uint32_t word32 = 0;
uint8_t *bytes = (uint8_t *) &word32;
bytes[0] = (uint8_t)(blue * maxIntensity);
bytes[1] = (uint8_t)(green * maxIntensity);
bytes[2] = (uint8_t)(red * maxIntensity);
bytes[3] = 0;
return word32;
}


//////////////////////////////////////////////////////////////////
// printRGBToSerial
// Purpose: diagnostic output of RGB values on serial line
//////////////////////////////////////////////////////////////////

void printRGBToSerial(uint32_t color)
{
uint8_t *bytes = (uint8_t *)& color;
Serial.print("(");
Serial.print(bytes[2], DEC); // Red
Serial.print(", ");
Serial.print(bytes[1], DEC); // Green
Serial.print(", ");
Serial.print(bytes[0], DEC); // Blue
Serial.print(")");
}

Genutzt wird das Ganze wie folgt:

uint32_t color = wavelengthToRGB(550); // RGB Wert holen ...
printRGBToSerial(color); // ... und über seriellen Monitor ausgeben

Für das Beispiel ergibt sich als RGB-Wert: (113, 0, 255)

Natürlich habe ich mir die Mühe mit dem obigen Algorithmus nicht gemacht, um sie mit Physikkenntnissen zu beeindrucken. Stattdessen wollen wir das Ganze in der Praxis für eigene Erleuchtungen anwenden.

Hier eine Methode rainbowWipe(), die wavelengthToRGB(wavelength) verwendet, um die Pixel auf einem LED-Strip das Lichtspektrum des Regenbogens abdecken zu lassen.

Die benötigte Initialisierung der Adafruit-Neopixel-Bibliothek und weitere Vorarbeiten im Sketch hatte ich bereits weiter oben erläutert ( Abschnitt Beispielscode).

//////////////////////////////////////////////////////////////////
// rainbowWipe(wait)
//
// Zweck: Pixel für Pixel beginnend mit Violett und mit
// Rot endend in Regenbogenfarben erleuchten.
//
//
// Parameter: wait = Wartezeit zwischen Pixeln
//
// Hinweis: Je mehr Pixel, desto feinere Übergänge möglich!
//
//////////////////////////////////////////////////////////////////

void rainbowWipe(uint8_t wait) {
// Wir wollen in delta-Schritten den Bereich sichtbaren
// Lichts in den Pixeln abbilden.

uint32_t delta = (780.0-380.0) / (strip.numPixels());
uint32_t wavelength;

// Alle vorhandenen Pixel durchlaufen:
for(uint16_t pixno=0; pixno<strip.numPixels(); pixno++) {
// Wellenlänge in etwa zwischen 380 nm und 780 nm:
wavelength = 380 + pixno * delta;

// RGB-Pixelfarbe aus Wellenlänge berechnen:
strip.setPixelColor(pixno, wavelengthToRGB(wavelength));
// Licht an:
strip.show();
delay(wait); // Gegebene Zeit warten
}
}

Allgemein ist festzustellen, dass wir für jedes Pixel ca 3 Byte Daten im SRAM-Speicher des Arduino benötigen. Boards wie Leonardo oder Uno mit ihren 2K RAM kommen damit schnell an die Speichergrenze. Speziell dann, wenn wir größere LED-Streifen ansteuern wollen.

Eine mögliche Lösung besteht darin, konstante Daten im Programmspeicher statt im SRAM zu speichern. Dafür gibt es das Attribut PROGMEM. Nähere Information findet sich dazu in der Arduino-Dokumentation.

Das Ganze funktioniert ausschließlich für alle in pgmspace.h definierten Datentypen. Am folgenden Beispiel sehen Sie das Vorgehen exemplarisch für Zeichenketten. Für andere Datentypen verweise ich Sie auf die Dokumentation. Der vorliegende Sketch funktioniert auch ab Arduino IDE Version 1.6. Das gilt für andere, im Web verbreitete Beispiele unter Umständen nicht. Eine ganz gute Übersicht liefert der folgende Artikel.

#include <avr/pgmspace.h>
const char board0[] PROGMEM = "Arduino Uno";
const char board1[] PROGMEM = "Arduino Mega";
const char board2[] PROGMEM = "Arduino Pro Mini";
const char board3[] PROGMEM = "Arduino Yun";

// Tabelle mit Zeigern auf Zeichenketten:

const char *const myBoards[] PROGMEM =
{
board0,
board1,
board2,
board3
};

char puffer[30]; // muss für größte Zeichenkette reichen

void setup() // Übertragung mit 9600 Baud
{
Serial.begin(9600);
}


void loop()
{
/* Wir brauchen Spezialfunktionen um die Daten abzurufen.
strcpy_P kopiert eine Zeichenkette vom Programmspeicher
zur Variablen puffer */


for (int i = 0; i < 4; i++)
{
strcpy_P(puffer, (char *)pgm_read_word(&myBoards[i]));
Serial.println(puffer);
delay( 100);
}
}

Oben war bereits von RGBW-Pixels die Rede, die zusätzlich weiße LEDs beherbergen. Dadurch sind weitere Übergänge und Effekte möglich. Neben den 3x8 = 24 Bit für Rot, Grün, und Blau erwartet der WS2812B-Controller für eine RGBW zusätzlich die gewünschte 8-Bit-Intensität des Weißlichts.

Der UCS2912 (siehe Datasheet). definiert einen zum WS2812B alternativen Controller und kann speziell RGBW-Pixel ansteuern. Als Besonderheit gegenüber seinem Cousin kontrolliert ein UCS2912 drei Pixel statt eines einzigen. Lassen sich LED-Streifen mit WS2812Bs in einzelne Pixel zerschneiden, so ist das für UCS2912-basierte LED-Streifen demzufolge nicht möglich.

Weil jeder UCS2912 drei Pixel steuert, braucht er 12 Kanäle, also 4 pro Pixel. Datenpakete an einen UCS2912 sind dementsprechend 96-Bits groß. Der Datenstransfer beträgt wie schon beim WS2812B 800 kb/sec.

Funktioniert die Adafruit Neopixel Library auch für LED-Streifen mit UCS2912? Die Antwort lautet "ja, aber". Ausführlicher formuliert, lässt sich die Bibliothek grundätzlich für den Controller nutzen. Nur für die Farbansteuerung sind Anpassungen nötig. Dementsprechende Beispielssketche hat @MegaFan auf dem Arduino-Forum bereitgestellt.

Die Welt ist bekanntlich kompliziert, auch wenn alle Wege nach Rom führen. Daher existiert eine weitere Alternative zum WS2812B. Willkommen an Board, SK8612! Dieser Controller ist weitgehend kompatibel zum WS2812, enthält sogar einen WS2811-Controller.

Funktioniert die Adafruit Neopixel Library auch für LED-Streifen mit dem SK6812? Die Antwort lautet "ja, aber". Ausführlicher formuliert, lässt sich die Bibliothek grundätzlich für den Controller nutzen. Nur für die Farbansteuerung sind Anpassungen nötig. Auch für den SK6812 hat @MegaFan die entsprechenden Adaptionen veröffentlicht.

In dieser Folge haben wir das Potenzial der Kombination einer LED mit WS2811-Controller kennengelernt, auch bekannt als WS2812B. Diese LEDs bieten eine sehr preisgünstige Möglichkeit, ausgefeilte Lichteffekte mit Hilfe eines Mikrocontrollers wie dem Arduino zu erzeugen. Allerdings ist der Stromverbrauch nicht zu unterschätzen, der mit einigen Ampere zu Buche schlagen kann.

Die Vielzahl der Bauformen, etwa Streifen, Matrizen oder einzelne Pixel bietet dem Entwickler einen bunten Strauß kreativer Möglichkeiten. Dank der Bibliotheken wie beispielsweise Adafruit's Neopixel Library brauchen Maker sich nicht mit den diffizilen programmatischen Details herumzuschlagen, speziell was das Timing betrifft. Sie können sich stattdessen auf das eigentlich Kreative eines Projekts konzentrieren.

Die nächste Ausgabe wird sich solchen konkreten Projekten widmen.