RGB-Polyeder

Vor einiger Zeit wurde ich durch einen Beitrag auf Instagram inspiriert, eine 3-dimensionale geometrische Figur (hier: Tetraeder bzw. Ikosaeder) mit LEDs zu bestücken, um daraus eine Art Kunstobjekt zu machen. Die Idee war, einen kleinen Mikrocontroller (Arduino bzw. ATtiny) zu verwenden, um LEDs vom Typ WS2812B anzusteuern, um somit das volle Farbspektrum auszuschöpfen.

Video: Test eines Tetraeders mit Polyeder-Modulen und einem Arduino Uno.

Verwendete Bauteile

Layout des Moduls

Um solch einen 3-dimensionalen Körper zu erstellen, habe ich mich dazu entschieden, ein Modul zu erstellen, welches jeweils eine Fläche des Objektes darstellen soll. Auf jeder dieser identischen Platinen (PCB) sitzt jeweils eine WS2812B-LED. Der Aufbau dieses Platinen-Moduls ist recht einfach, da die WS2812B außer einem Stützkondensator keine weiteren Komponenten verlangt.

Schaltplan des LED-Polyeder-Moduls
Abb.: Schaltplan des LED-Polyeder-Moduls

Da ich mich für geometrische Objekte mit gleichseitigen Dreiecken als Flächen entschieden hatte, musste die Platine ein entsprechendes Layout besitzen. Leider besitzt EasyEDA kein exaktes Werkzeug, um eine Platine in anderen Winkeln als 90° zu layouten, daher ist der folgende Aufbau nur näherungsweise möglich gewesen.

Platinenlayout des LED-Polyeder-Moduls in EasyEDA
Abb.: Platinenlayout des LED-Polyeder-Moduls in EasyEDA
EasyEDA-Platinenlayout für Polyeder-Modul [40kB]
Gerber-Dateien für Polyeder-Modul [10kB]

Das obige Layout übergab ich an JLCPCB, einem in China ansässigen Platinenhersteller, der mir nach recht kurzer Zeit 50 gefertige Platinen zugeschickt hat.

Bestückung und Aufbau

Aufbau und Beschaltung der WS2812B-LED

Der grundlegende Aufbau eines WS2812B-Moduls wurde ja schon in einem vorherigen Beitrag beschrieben, allerdings sind bei der hier verwendeten SMD-3535-Packung die Anschlüsse nicht beschriftet. Für die meisten Fälle sollten die folgenen Anschlüsse festgelegt sein:

Abb.: Anschlüsse (Pinout) eines WS2812B-Moduls (SMD 3535)
WS2812B-LED-Modul in SMD 3535 Bauweise
Abb.: WS2812B-LED-Modul in SMD 3535 Bauweise (Lieferzustand)
100nF Keramik-Kondensatoren in SMD 0603 Bauweise
Abb.: 100nF Keramik-Kondensatoren in SMD 0603 Bauweise (Lieferzustand)
100nF Keramik-Kondensatoren in SMD 0603 Bauweise
Abb.: 100nF Keramik-Kondensatoren in SMD 0603 Bauweise (Detail)

Aufbau und Test eines Moduls

Um zunächst die Funktionalität eines Moduls nach dessen Fertigung zu testen, habe ich folgende Schritt getan.

Gefertigte Polyeder-Modul-Platinen von JLCPCB
Abb.: Gefertigte Polyeder-Modul-Platinen von JLCPCB
Polyeder-Modul
Abb.: Polyeder-Modul
Pin-Header (Stiftleisten) zum Test des Moduls
Abb.: Für einen ersten Test des Moduls habe ich normale Stiftleisten (Pin-Header) an die Anschlüsse DI, VCC und GND gelötet, damit sie einfach in ein Breadboard zu montieren sind.
Stiftleiste wird in Platine gelötet
Abb.: Stiftleiste wird in Platine gelötet
100nF Keramik-Kondensator wird auf Platine gelötet
Abb.: 100nF Keramik-Kondensator wird auf Platine gelötet. Es empfiehlt sich, dafür ein USB-Mikroskop zu verwenden.
Vergrößerung eines WS2812B-LED-Moduls SMD 3535)
Abb.: Vergrößerung eines WS2812B-LED-Moduls SMD 3535)
Fertiges Polyeder-Modul wird gestestet
Abb.: Das fertige Polyeder-Modul wird auf ein Breadboard gesteckt, mit einem Arduino Uno verdrahtet und mit einem einfachen Sketch (s.u.) auf dessen Funktionalität gestest.

Sketch

Der folgende Sketch soll den bzw. die WS2812B-Module testen. Dabei wird im Sekundentakt jeweils eine der drei Hauptfarben aufleuchten. Wenn später mehrere Modul zusammengeschaltet getestet werden sollen, dann muss die Konstante LED_AMOUNT nur auf die entsprechende Anzahl an Platinen (=LED-Modulen) gesetzt werden. (Es wird hier die Library Adafruit_NeoPixel verwendet)

#define PIN_LED 9
#define LED_AMOUNT 1

#include <Adafruit_NeoPixel.h>

Adafruit_NeoPixel led = Adafruit_NeoPixel(LED_AMOUNT, PIN_LED, NEO_GRB + NEO_KHZ800);

void setup()
{
    led.begin();
}

void loop()
{
    showAllColor(led.Color(50,  0,  0));
    delay(1000);

    showAllColor(led.Color( 0, 50,  0));
    delay(1000);

    showAllColor(led.Color( 0,  0, 50));
    delay(1000);
}

void showAllColor(uint32_t color)
{
    for(byte i=0; i<LED_AMOUNT; i++) {
        led.setPixelColor(0, color);
    }
    led.show();
}

Tetraeder

Die geometrische Figur des Tetraeders besteht definitionsgemäß aus vier dreieckigen Seitenflächen, und daher müssen vier der oben genannten Polyeder-Modul mit den Komponenten verlötet werden.
Der exakte Winkel zwischen jeweils benachbarten Flächen beträgt: 70° 31' 44".
Dies errechnet sich aus arccos(1/3)

Zwei Polyeder-Module werden mit Drähten verbunden
Abb.: Zwei vorbereitete Polyeder-Module werden mit kurzen Drahtstücken (z.B. Reste abgezwickter LED-Pins) miteinander verbunden. Darauf achten, dass der Datenweg immer in einer Richtung gehen kann, d.h. immer von DI zu DO.
Zusammengefügte Polyeder-Module
Abb.: Zusammengefügte Polyeder-Module (überstehende Drähte müssen noch entfernt werden)
Zusammengefügte Polyeder-Module
Abb.: Zusammengefügte Polyeder-Module (alternative Ansicht)
Zusammengefügter Tetraeder aus vier Polyeder-Modulen
Abb.: Zusammengefügter Tetraeder aus vier Polyeder-Modulen (durch die Dicke der Platine bzw. die nicht 100% exakte Fertigung gibt es leichte Überstände an den Kanten)
Tetraeder Mit Arduino verkabelt
Abb.: Der fertige Tetraeder wird mit einem Arduino Uno verkabelt, um einen ersten Test durchzuführen.

Sketch

Der folgende Sketch zeigt eine kleine Leucht-Demonstration, wobei zunächst helle Lichtblitze zufällig auf den Flächen des Tetraeders entstehen und nach kurzer Zeit ein regenbogenartiger Farbwechsel. Der Teil des Codes mit dem Farbübergang wurde von rainbow-pixels abgleitet.

#define LED_PIN 9
#define LED_AMOUNT 4

#include <Adafruit_NeoPixel.h>

Adafruit_NeoPixel led = Adafruit_NeoPixel(LED_AMOUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

void setup()
{
    led.begin();
    randomSeed(analogRead(0));
    resetLeds();
}

void loop()
{
    strobeLeds(led.Color(0, 50, 50));
    rainbowLeds(50);
}

void resetLeds()
{
    for (byte i = 0; i < LED_AMOUNT; i++) {
        led.setPixelColor(i, led.Color(0, 0, 0));
    }
    led.show();
}

void rainbowLeds(byte cycleDelay)
{
    byte rgb[3] = {255, 0, 0};

    for (byte dC = 0; dC < 3; dC++ ) {
        byte iC = dC == 2 ? 0 : dC + 1;
        for (byte i = 0; i < 255; i++ ) {
            rgb[dC]--;
            rgb[iC]++;

            for (byte a = 0; a < LED_AMOUNT; a++ ) {
                led.setPixelColor(a, rgb[0], rgb[1], rgb[2]);
            }
            led.show();
            delay(cycleDelay);
        }
    }
}

void strobeLeds(uint32_t color)
{
    for (byte iter = 0; iter < 200; iter++) {
        for (byte i = 0; i < LED_AMOUNT; i++) {
            led.setPixelColor(i, led.Color(0, 0, 0));
            if (random(0, 33) == 0) {
                showColor(i, color, 25);
                showColor(i, led.Color(0, 0, 0), 1);
            }
            delay(5);
        }
    }
}

void showColor(byte ledIndex, uint32_t color, byte showDelay)
{
    led.setPixelColor(ledIndex, color);
    led.show();
    delay(showDelay);
}

Ikosaeder

Animation eines Ikosaeders
Abb.: Animation eines Ikosaeders (Quelle: Peter Steinberg/Wikimedia Commons)

Ein größerer geometrischer Körper, der aus 20 gleichseitigen, dreieckigen Seitenflächen besteht, ist der Ikosaeder. Hier müssen also 20 der oben genannten Polyeder-Modul mit den Komponenten verlötet werden.
Der exakte Winkel zwischen jeweils benachbarten Flächen eines Ikosaeders beträgt: 138° 11' 23".
Dies errechnet sich aus arccos(-sqrt(5)/3)

zurück