NeoPixel Steuerung

NeoPixel Steuerung

Stand: 04/2016
Lesedauer: ca. 7 Minuten

Inhalt:

  • NeoPixel

  • Hardware

  • Ansteuerung

  • Konzept

  • Programmierung

  • Steuerung

  • Fazit

Ziel des Projekts war es programmierbare LED-Stripes (RGB) zur Beleuchtung einzusetzen. Hierbei lag der Fokus auf der Ansteuerungsmöglichkeit jeder einzelnen LED, der Möglichkeit beliebige Farben einzustellen sowie auf der einfachen Steuerung nach Projektabschluss.

NeoPixel

Um einzelne LEDs innerhalb eines LED-Stripes ansteuern zu können, wurden LED-Stripres mit NeoPixel von der Firma Adafruit verwendet. Diese haben den Vorteil, dass jeder Pixel aus drei einfarbigen LEDs (Rot, Grün, Blau) und einem Controller besteht. Über diesen Controller kann jede LED des Pixels in 256 Helligkeitsstufen eingestellt werden. Aufgrund der umfangreichen Abstufungen lassen sich beliebige Helligkeiten und Farbkominationen einfach einstellen.

Neben dem kompakten Aufbau der NeoPixel bietet der enthaltene Controller (WS2812) weitere wichtige Vorteile:

  • Eine Ansteuerung des Controllers wird ausschließlich für eine Änderung der aktuellen Helligkeitswerte benötigt. So behalten die Pixel ihre eingestellten Helligkeitswerte auch bei einer unterbrochenen Verbindung zum steuernden Controller bei.

  • Einzelne Pixel und Stripes können durch ein einfaches dreiadriges Kabel (+, - und Steuerleitung) in Reihe geschaltet und so die Anzahl der Pixel erweitert werden. Die Helligkeitswerte der einzelnen LEDs werden hierbei über die Steuerleitung von Pixel zu Pixel, wie in einem Schieberegister, weitergereicht.

  • Soll ein neuer Helligkeitswert eingestellt werden, so wird diese nicht vom Ausgangswert auf den Zielwert verändert, sondern erhält durch den Controller automatisch einen linearen Übergang.

Hardware

Folgenden Hardwarekomponenten wurden für die NeoPixel Steuerung verwendet:

  • 6x NeoPixel LED-Stripe: Ein Stripe beinhaltet 30 einzeln ansteuerbare NeoPixel, sowie ein Netzteil zur Stromversorgung des kompletten Stripes.

  • 1x RaspberryPi 3: Zum Betrieb des RaspberryPi wurde zusätzlich ein USB-Netzteil und eine Micro-SD Karte benötigt.

  • 1x FadeCandy: Ein USB-Controller von Adafruit zur Ansteuerung von bis zu 8 NeoPixel-Stripes mit maximal 64 Pixel pro Stripe.

  • Geschirmtes Twisted-Pair-Kabel zur Verbindung zwischen NeoPixel und USB-Controller.


Abbildung 1: Angeschlossener FadeCandy an den RaspberryPi und den Steuerleitungen


Abbildung 2: Die Steuerleitungen Enden beim RaspberryPi. Dort können die einzelnen Drähte gemappt werden. Jede Steuerleitung ist mit Klebeband an beiden Enden farblich markiert.

Ansteuerung

Die Ansteuerung der NeoPixel muss über einen permanenten WebSocket zur Controller-Software erfolgen. Über diese Verbindung können neue Helligkeitswerte für alle Pixel übertragen werden. Eine gezielte Ansteuerung einzelner Pixel ist aufgrund des Weiterreichens der aktuellen Helligkeitswerte an den jeweils nächsten Pixel nicht möglich. Soll nur ein einziger Pixel in der Helligkeit verändert werden, so müssen alle anderen Pixel mit den alten Werten neu gesetzt werden.

Über die bestehende WebSocket-Verbindung können keine Effekte oder dergleichen übertragen werden. Sollen die NeoPixel eingesetzt werden um Effekte darzustellen, so müssen die veränderten Werte jeweils in JavaScript berechnet und anschließend in einem sehr kurzen Abstand über die WebSocket-Verbindung übertragen werden.

Konzept

Für die Ansteuerung der NeoPixel soll nicht auf den RaspberryPi über eine Shell zugegriffen und anschließend einzelne Skripte aufgerufen werden müssen. Als Lösung wurde ein webbasiertes Konzept umgesetzt, welches eine einfach Webseite zur Verfügung stellt, über das die Helligkeitswerte eingestellt werden können. Hierbei stellt der RaspberryPi durch einen Lighttpd Webserver die Webseite innerhalb des lokalen Netzwerks zur Verfügung.

Aufgrund der Tatsache, dass die Helligkeitswerte über den JavaScript WebSocket an die Software des Controllers gesendet werden und ein Endgerät (z. B. Tablet) beim Ausschalten des Displays diese Verbindung und die Ausführung des JavaScript-Codes stoppt, können so keine Effekte stabil auf die NeoPixel übertragen werden. Ebenfalls führte ein gleichzeitiger Aufruf der Steuerungsseite und dem Auswählen von Effekten auf mehreren Geräten zu einem unerwünschten Verhalten, indem Werte von beiden Endgeräten hintereinander angezeigt wurden.
Um die beiden genannten Probleme zu lösen, wurde die Ausführung des JavaScript-Codes vom Endgerät auf den RaspberryPi verschoben. Aufgrund der Verschiebung des JavaScript-Codes wird dieser nun durch die ausgelieferte Steuerungswebseite gesteuert. Dadurch ist es nun möglich von beliebigen Endgeräten die auszuführenden Effekte zu setzen, ohne dass dies zu einem unerwünschten Verhalten führt. Auch setzen die Endgeräte lediglich die anzuzeigenden Effekte und benötigen keine permanente Verbindung zum Controller. Durch das Verschieben des JavaScript-Codes vom Endgerät in den RaspberryPi, konnten die Verbindungen zwischen JavaScript und Controller-Software über eine interne Verbindung (localhost) geleitet und so die Reaktionszeiten zusätzlich verkürzt werden.

Um die Ausführungsgeschwindigkeit weiter zu erhöhen, läuft der JavaScript-Code auf dem RaspberryPi in einem eigenem vom Webserver unabhängigen Thread. Die Kommunikation zwischen beiden Komponenten erfolgt hierbei durch eine periodische Meldung des Status des JavaScript-Codes, sowie eines Abrufs des Status des Webservers, jeweils über AJAX. Hierdurch können Statusänderungen des Webservers durch eine Eingabe eines Benutzers erkannt, sowie der aktuelle Status des JavaScript-Codes mit aktuell ausgeführten Effekten über die Webseite an jedes Endgerät übertragen werden.
Für die Speicherung der Status aller Komponenten, sowie der Synchronisation verwendet der Webserver im RAM gespeicherte Dateien. Dies hat erstens den Vorteil die SD-Karte des RaspberryPi nicht durch ständige Statusupdates kaputt zu schreiben und zweitens sind Schreibe- und Lesezugriffe auf den RAM deutlich performanter als auf die SD-Karte.

Programmierung

Das komplette Projekt wurde eigenständig umgesetzt und zur besseren Verwaltung als Git-Projekt realisiert und versioniert. Die Serverseite verwendet ausschließlich PHP, läuft auf einen lighttpd-Webserver und benutzt zum Speichern der Status-Dateien, welche im RAM abgelegt werden.
Die Berechnung der Farbwerte, die Verbindung zur Controller-Software und das Erstellen der Daten wurden in JavaScript umgesetzt und läuft ebenfalls auf dem RaspberryPi und nicht auf einem Endgerät. Einzelne Effekte werden jeweils in einer eigenen JS-Datei gespeichert. Neue Dateien können beliebig hinzugefügt und bestehende beliebig verändert werden. Eine Änderung an den Dateien wird jeweils beim Starten oder Stoppen eines Effekts über ein beliebiges Endgerät auf dem Server erkannt. Für jeden Effekt können Geschwindigkeit und Helligkeit des Effekts, ohne einen Neustart des Effekts zu bewirken, jederzeit über einen Schieberegler frei verändert werden.

Um die Helligkeitswerte von NeoPixeln zu verändern muss ein neues Set an Daten mit Helligkeitswerten, für jede Farbe sowie für jedes NeoPixel in einem fest vorgeschriebenen Format (Uint8ClampedArray) komplett übertragen werden. Dies sind bei den verwendeten 180 NeoPixel 540 Dezimal-Werte zwischen 0 und 255.
Um das Setzen aller oder einzelner Pixel zu vereinfachen, wurden Hilfsfunktionen geschrieben, die die Erstellung des kompletten Datenblocks vereinfachen. Beispielsweise setzt die JS-Funktion "writeToAllPixel(red, green, blue)" alle 180 Pixel auf die angegebenen Helligkeitswerte. Die letzten/aktuellen Helligkeitswerte werden zu jederzeit gespeichert und können durch die "writeToSomePixel" Funktion wiederverwendet werden. Mit dieser Funktion ist es möglich beliebig viele einzelne Pixel direkt zu verändern. Alle nicht veränderten Pixel erhalten die gleichen Werte wie im vorherigen Paket. Mit diesen beiden Funktionen können Effekte mit allen oder einzelnen NeoPixel sehr einfach und schnell umgesetzt und zur Laufzeit in die Anwendung integriert werden.

Beispiel 1

Im Folgenden wird die Programmierung für einen blauen Puls-Effekt beispielhaft aufgezeigt:

// Animation parameters
var lastTime = 0;
var phase = 0;

// Animation loop
var animate = function() {
  if(status == 1) { // if the sequence should not run
    // Get time delta
    var thisTime = (new Date()).getTime();
    var dt = (thisTime - lastTime) * 0.001;
    lastTime = thisTime;

    // Update animation
    phase += frequency * 2 * Math.PI * dt;
    var f = Math.sin(phase);

    writeToAllPixel(
      color.r * (1 + contrast * f),
      color.g * (1 + contrast * f),
      color.b * (1 + contrast * f));
  }
  setTimeout(animate, 1 + speed);
};
animate();

Abbildung 3: Die LED-Stripes wurden meist auf den Abschlussleisten aufgebracht.


Abbildung 4: Durch das Anbringen auf den Abschlussleisten können die Wände der Wohnung in Szene gesetzt werden.

Beispiel 2

Im Folgenden wird die Programmierung für ein Lauflicht, welches bei jeder Runde eine zufällige Farbe auswählt, aufzeigt:

var counter = 181;
var color;

// Animation loop
var animate = function() {
  if(status == 1) { // if the sequence should run

    var arr = new Array();

    if(counter >= 180) {
      counter = 1;

      var rand = Math.round(Math.random()*5);
      if(rand == 0)
        color = hexToRgb('#FF0000');
      else if(rand == 1)
        color = hexToRgb('#00FF00');
      else if(rand == 2)
        color = hexToRgb('#0000FF');
      else if(rand == 3)
        color = hexToRgb('#FFFF00');
      else if(rand == 4)
        color = hexToRgb('#00FFFF');
      else if(rand == 5)
        color = hexToRgb('#FF00FF');
    }

    for(var i=0; i<3; ++i)
      arr[i] = new Array(counter+i, color.r, color.g, color.b);

    writeToSomePixel(false, arr);
    counter++;
  }
  window.setTimeout(animate, 5 + speed);
};
animate();

Abbildung 5: Lauflicht 1. Durchgang


Abbildung 6: Lauflicht 1. Durchgang


Abbildung 7: Lauflicht 1. Durchgang


Abbildung 8: Lauflicht 2. Durchgang


Abbildung 9: Lauflicht 2. Durchgang

Steuerung

Zur Steuerung der NeoPixel wird lediglich ein Webbrowser, sowie eine Verbindung zum Webserver auf dem RaspberryPi im lokalen Netzwerk benötigt. Nach dem Aufrufen der Webseite hat der Besucher folgende Auswahlmöglichkeiten:

  • Setzen einer Farbe über die Farbauswahl sowie der Helligkeit über einen Schieberegler, für alle NeoPixel (180 Pixel).

  • Setzen einer Farbe über die Farbauswahl sowie der Helligkeit über einen Schieberegler, pro NeoPixel-Stripe (30 Pixel).

  • Starten eines der vorprogrammierten Effekte zur periodischen Ansteuerung der NeoPixel

    • Blau Pulsierend: Alle NeoPixel pulsieren in blauer Farbe. (Siehe Beispiel 1)

    • Grün Pulsierend: Alle NeoPixel pulsieren in grüner Farbe.

    • Rot Pulsierend: Alle NeoPixel pulsieren in roter Farbe.

    • Lauflicht: Lauflicht in zufälliger Farbe (immer ein NeoPixel aktiv) über alle 180 NeoPixel. Die Laufrichtung ist hierbei von rechts nach links. (Beispiel 2)

    • Lauflicht 2: Lauflicht in zufälliger Farbe (immer ein NeoPixel aktiv) über alle 180 NeoPixel. Die Laufrichtung ist hierbei von rechts nach links und wieder zurück.

    • Regenbogen: Alle NeoPixel durchlaufen hier die Farben des Regenbogens. Rot -> Rot+Grün -> Grün -> Grün+Blau -> Blau -> Blau+Rot

    • Random: Alle NeoPixel werden auf einen zufälligen Farbwert eingestellt.

    • Radnom 2: 20 zufällige NeoPixel der 180 verfügbaren erhalten eine zufällige Farbe. Alle anderen NeoPixel werden ausgeschaltet.

    • Radnom 3: Alle NeoPixel eines Stripes werden auf einen zufälligen Farbwert eingestellt. Alle anderen NeoPixel werden ausgeschaltet.

    • Random 4: Alle NeoPixel eines Stripes werden auf einen zufälligen Farbwert eingestellt. Alle anderen NeoPixel behalten ihre vorherige Farbe.

Fazit

Das Projekt zur NeoPixel Steuerung war ein voller Erfolg. Es wurden 6 NeoPixel-Stripes mit jeweils 30 Pixel verbaut und über den RaspberryPi angesteuert. Aufgrund der einfachen Ansteuerung der Pixel und der anschließenden Abstraktion können feste Farben, als auch beliebige Effekte sehr einfach und mit wenigen Zeilen JavaScritp-Code programmiert werden. Ein großer Vorteil der umgesetzten Steuerung ist, dass zur Steuerung beliebige Endgeräte (Webbrowser und Netzwerkverbindung benötigt) verwendet werden können. Sogar die gleichzeitige Nutzung beliebig vieler Endgeräte ist möglich. Aufgrund der kompletten Ausführung auf dem RaspberryPi können Endgeräte mit beliebiger Performance verwendet werden.