top of page
Writer's pictureRadim Petruška

Jak si vytisknut RGB LED Rocket Lamp pro děti na 3d tiskárně

Updated: Mar 15, 2021




Rocket Lamp je projekt jehož účelem je zábavnou cestou přiblížit dětem základy slaboproudých elektrických obvodů, tak aby ihned viděli výsledek a zůstalo jim něco užitečného, třeba lampička do pokojíku.

Ukážeme Vám jak si vytisknout a sestavit naši Rocket Lamp pro děti na 3d tiskárně. Máme připraveny 3 stupně obtížnosti.


Než začneme podívejte se na naše video návody rozdělené do 3 obtížností:


Všechny 3 obtížnosti se dají vzájemně kombinovat, proto si projděte všechny.


OBTÍŽNOST ZAČÁTEČNÍK

Budete potřebovat:

  1. Rocket Lamp 3d print data

  2. RGB LED chytrý pásek

Xiaomi Yeelight Lightstrip Plus
Xiaomi Yeelight Lightstrip Plus

Je nejjednodušší způsob jak vyrobit Vašim dětem tuto lampičku. Pokud nemáte čas, nebo chuť pájet a programovat, stačí když vytisknete Base_Universal.stl a koupíte si Smart RGB LED pásek. Tato základna (Base_Universal.stl) má obdélníkový prostup pro Smart RGB LED pásek s napájením. Jednoduše tento LED pásek protáhnete do základny lampičky, poté ze základny do věže, na kterou LED pásek osadíte, jak jde vidět ve videu Beginner Level. Většinu těchto chytrých LED pásků lze ovládat pomocí aplikace v telefonu.

V našem případě používáme pásek Yeelight LED Lightstrip Plus 1S.

Poté si vyberete design pláště (solid, wire nebo stars), vytisknete jej na 3D tiskárně a vše sesadíte dohromady.



OBTÍŽNOST POKROČILÝ


Je určen pro ty, které baví posouvat věci dále a něco se naučit. Pájení není nutné, ale doporučujeme jej.


Budete potřebovat:

  1. Rocket Lamp 3d print data

  2. DC konektor samice

  3. 5V-12V DC nápajecí adaptér

  4. 5V - 12V RGB LED pásek

  5. Wago svorka

  6. Chytrá zásuvka


Budete potřebovat DC konektor, DC 5V-12V nápájecí adaptér, a RBG LED pásek 5V-12V. Protože naše lampička nemá žádné viditelné tlačítko, doplnili jsme tuto verzi o Smart zásuvku, která jde opět ovládat telefonem a můžete lampičku na dálku dítěti vypnout až usne, aniž by jste ho vzbudili. V tomto případě jsme použili Smart zásuvku od firmy FIBARO. Výhodou je také možnost napojení této zásuvky na Amazon Alexu, pokud tento systém máte doma.

DC konektor osadíte do naší Base_DC.stl, která má otvor připravený pro běžně prodávané DC konektory. Pokud by byl větší něž je šířka stěn v základně, můžete plast oříznout nožem. Poté doporučujeme zafixovat pomocí tavné pistole. DC konektor jednoduše připájíte k LED pásku, nebo použijete wago svorky jak jde vidět ve videu Advanced Level. LED pásek poté protáhnete otvorem do věže a zafixujete.

Poté si vyberete design pláště (solid, wire nebo stars), vytisknete jej na 3D tiskárně a vše sesadíte dohromady.



OBTÍŽNOST MISTROVSKÁ

Teprve tady začíná opravdová zábava a naplňuje náš záměr. Rocket Lamp je projekt, který je primárně zamýšlen jako výukový KIT pro děti, tak aby se začali zábavnou cestou učit programování. Je však podmíněna vedením svého rodiče, který má s Arduinem zkušenosti. Tuto obtížnost doporučujeme těm, kteří již mají zkušenost s Arduino IDE. Je nutné nainstalovat si Arduino IDE a ovladače do Vašeho počítače. Pokud tuto zkušenost s Arduinem nemáte, nevadí. Pokud budete postupovat podle našeho videa Master Level, mělo by se Vám povést lampičku zprovoznit a měla by fungovat minimálně tak jak ukazujeme ve videu.


Budete potřebovat

Hardware:


Software:


Arduino IDE - download

Budete mi také muset doinstalovat ch340 ovladače, pokud je nemáte. Instalace ovladače převodníku USB na UART CH340, click here for Download link for ch340


Krok 1: Diagram

Vše se musí zapojit dle následujícího obrázku.


5V ----> NeoPixel VCC

G ----> NeoPixel GND & TTP223 GND

D4 ----> NeoPixel I/O

3V3 ----> TTP223 VCC

D8 ----> TTP223 I/O


Krok 2: Pájení

Napájíme si dráty na Adafruit NeoPixel, tlačítko TTP223 a WeMos D1 Mini. Tak jak jde vidět v našem video návodu Master Level, nebo na obrázcích níže.



Krok 3: Osazení do základny a věže

Nyní můžeme vše osadit do Base_Wemos_D1_Mini.STL základny.

Doporučujeme požít jakékoliv konektory, tak aby tlačítko i LED kroužek šli případně vyměnit.

Pokud chcete, můžete samozřejmě vše spájet dohromady "na tvrdo".



Krok 4: Nahrání kódu ARDUINO IDE

Celý postup nahrání a modifikace kódu je ukázán v Master Level od 3:00, ale pro jistotu zde zopakujeme nejdůležitější momenty.

a) První si nainstalujeme ovladače ch340 jako je vidět v tomto videu Install Serial Drivers for ESP32 (macOS, Windows, Linux) , nebo tady Instalace ovladače převodníku USB na UART CH340

Odkaz na stažení ovladačů ch340 je zde: Download, pokud již máte, můžete přeskočit.

b) Připojte WeMos D1 Mini pomocí micro USB k počítači.

c) Nainstalujte si Arduino IDE - download

d) Naistalujte si ESP8266 board v Master Level 3:05

e) Nainstalujte si Adafruit_Neopixel - Download v Master Level 3:45

f) Otevřete si Adafruit Neopixel buttoncycler.ino z ukázkových kódů v Master Level 4:03

g) Zmodifikujeme kód na:

#define BUTTON_PIN D8

#define PIXEL_PIN D4

#define PIXEL_COUNT 24

h) Uložíme si náš zmodifikovaný kód.

i) Vybereme Vaši desku v Master Level 4:28

j) Vybere COM port v Master Level 4:30, ten se může u každého lišit.

i) Nahrajeme kód do lampičky přes upload ikonu jako v Master Level 4:36



HOTOVO!


Zdroje:


Nainstalujte si Adafruit NeoPixel knihovnu ručně z tohoto odkazu, nebo přes Library manager jako v Master Level 3:45.


Stáhněte si RocketLamp.zip a otevřete si RocketLamp.ino soubor.


Nebo si zkopírujte následující kód a vložte do nového sketche a uložte:

// Simple demonstration on using an input device to trigger changes on your
// NeoPixels. Wire a momentary push button to connect from ground to a
// digital IO pin. When the button is pressed it will change to a new pixel
// animation. Initial state has all pixels off -- press the button once to
// start the first animation. As written, the button does not interrupt an
// animation in-progress, it works only when idle.

#include <Adafruit_NeoPixel.h>
//#ifdef __AVR__
//#include <avr/power.h> // Required for 16 MHz Adafruit Trinket
//#endif

// Digital IO pin connected to the button. This will be driven with a
// pull-up resistor so the switch pulls the pin to ground momentarily.
// On a high -> low transition the button press logic will execute.
#define BUTTON_PIN   D8   //Digital IO pin connected to the Touch Button.

#define PIXEL_PIN    D4  // Digital IO pin connected to the NeoPixels.

#define PIXEL_COUNT 24  // Number of NeoPixels
// Declare our NeoPixel strip object:
Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, NEO_GRB + NEO_KHZ800);
// Argument 1 = Number of pixels in NeoPixel strip
// Argument 2 = Arduino pin number (most are valid)
// Argument 3 = Pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
//   NEO_RGBW    Pixels are wired for RGBW bitstream (NeoPixel RGBW products)

boolean oldState = HIGH;
int     mode     = 0;    // Currently-active animation mode, 0-9

void setup() {
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  strip.begin(); // Initialize NeoPixel strip object (REQUIRED)
  strip.show();  // Initialize all pixels to 'off'

}

void loop() {
  // Get current button state.
  boolean newState = digitalRead(BUTTON_PIN);
  ButtonPressed();
  // Check if state changed from high to low (button press).
  if((newState == LOW) && (oldState == HIGH)) {
    // Short delay to debounce button.
    delay(20);
    // Check if button is still low after debounce.
    newState = digitalRead(BUTTON_PIN);
    if(newState == LOW) {      // Yes, still low
      if(++mode > 11) mode = 2; // Advance to next mode, wrap around after #8
      switch(mode) {           // Start the new animation...
          
        case 0:
          colorWipe(strip.Color(  0,   0,   0), 50);    // Black/off
        //  break;
        case 1:
          colorWipe(strip.Color(255,   0,   0), 50);    // Red
        //  break;
        case 2:
          colorWipe(strip.Color(  255, 255,   255), 50);    // Green
         break;
        case 3:
          colorWipe(strip.Color(  0,   0, 255), 50);    // Blue
        //  break;
        case 4:
          theaterChase(strip.Color(127, 127, 127), 50); // White
        //  break;
        case 5:
          theaterChase(strip.Color(127,   0,   0), 50); // Red
        //  break;
        case 6:
          theaterChase(strip.Color(  0,   0, 127), 50); // Blue
        //  break;
        case 7:
          rainbow(5);
        //  break;
        case 8:
          theaterChaseRainbow(5);
        //  break;
        case 9:
           byte colors[3][3] = {{255, 0, 0}, 
                                {0, 255, 0}, 
                                {0, 0  , 255}};

           BouncingColoredBalls(3, colors);
             //  break; 
   //      case 10:
         theaterLine(strip.Color(  0,   0, 127), 50);
        
      }   
      }
    }
  

  // Set the last-read button state to the old state.
  oldState = newState;
}

// Fill strip pixels one after another with a color. Strip is NOT cleared
// first; anything there will be covered pixel by pixel. Pass in color
// (as a single 'packed' 32-bit value, which you can get by calling
// strip.Color(red, green, blue) as shown in the loop() function above),
// and a delay time (in milliseconds) between pixels.
void colorWipe(uint32_t color, int wait) {
  for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
    strip.setPixelColor(i, color);         //  Set pixel's color (in RAM)
    strip.show();                          //  Update strip to match
    delay(wait);                           //  Pause for a moment
  }
}

// Theater-marquee-style chasing lights. Pass in a color (32-bit value,
// a la strip.Color(r,g,b) as mentioned above), and a delay time (in ms)
// between frames.
void theaterChase(uint32_t color, int wait) {
  for(int a=0; a<10; a++) {  // Repeat 10 times...
    for(int b=0; b<3; b++) { //  'b' counts from 0 to 2...
      strip.clear();         //   Set all pixels in RAM to 0 (off)
      // 'c' counts up from 'b' to end of strip in steps of 3...
      for(int c=b; c<strip.numPixels(); c += 3) {
        strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
      }
      strip.show(); // Update strip with new contents
      delay(wait);  // Pause for a moment
    }
  }
}

void theaterLine(uint32_t color, int wait) {
  for(int a=0; a<10; a++) {  // Repeat 10 times...
    //  'b' counts from 0 to 2...
      strip.clear();         //   Set all pixels in RAM to 0 (off)
      // 'c' counts up from 'b' to end of strip in steps of 3...
      for(int c=a; c<strip.numPixels(); c += 3) {
        strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
      }
      strip.show(); // Update strip with new contents
      delay(wait);  // Pause for a moment
    }
  }


// Rainbow cycle along whole strip. Pass delay time (in ms) between frames.
void rainbow(int wait) {
  // Hue of first pixel runs 3 complete loops through the color wheel.
  // Color wheel has a range of 65536 but it's OK if we roll over, so
  // just count from 0 to 3*65536. Adding 256 to firstPixelHue each time
  // means we'll make 3*65536/256 = 768 passes through this outer loop:
  for(long firstPixelHue = 0; firstPixelHue < 3*65536; firstPixelHue += 256) {
    for(int i=0; i<strip.numPixels(); i++) { // For each pixel in strip...
      // Offset pixel hue by an amount to make one full revolution of the
      // color wheel (range of 65536) along the length of the strip
      // (strip.numPixels() steps):
      int pixelHue = firstPixelHue + (i * 65536L / strip.numPixels());
      // strip.ColorHSV() can take 1 or 3 arguments: a hue (0 to 65535) or
      // optionally add saturation and value (brightness) (each 0 to 255).
      // Here we're using just the single-argument hue variant. The result
      // is passed through strip.gamma32() to provide 'truer' colors
      // before assigning to each pixel:
      ButtonPressed();
      strip.setPixelColor(i, strip.gamma32(strip.ColorHSV(pixelHue)));
    }
    strip.show(); // Update strip with new contents
    delay(wait);  // Pause for a moment
  }
}

// Rainbow-enhanced theater marquee. Pass delay time (in ms) between frames.
void theaterChaseRainbow(int wait) {
  int firstPixelHue = 0;     // First pixel starts at red (hue 0)
  for(int a=0; a<30; a++) {  // Repeat 30 times...
    for(int b=0; b<3; b++) { //  'b' counts from 0 to 2...
      strip.clear();         //   Set all pixels in RAM to 0 (off)
      // 'c' counts up from 'b' to end of strip in increments of 3...
      for(int c=b; c<strip.numPixels(); c += 3) {
        // hue of pixel 'c' is offset by an amount to make one full
        // revolution of the color wheel (range 65536) along the length
        // of the strip (strip.numPixels() steps):
        int      hue   = firstPixelHue + c * 65536L / strip.numPixels();
        uint32_t color = strip.gamma32(strip.ColorHSV(hue)); // hue -> RGB
        strip.setPixelColor(c, color); // Set pixel 'c' to value 'color'
      }
      strip.show();                // Update strip with new contents
      delay(wait);                 // Pause for a moment
      firstPixelHue += 65536 / 90; // One cycle of color wheel over 90 frames
    }
  }
}

void BouncingColoredBalls(int BallCount, byte colors[][3]) {
  float Gravity = -9.81;
  int StartHeight = 1;
  
  float Height[BallCount];
  float ImpactVelocityStart = sqrt( -2 * Gravity * StartHeight );
  float ImpactVelocity[BallCount];
  float TimeSinceLastBounce[BallCount];
  int   Position[BallCount];
  long  ClockTimeSinceLastBounce[BallCount];
  float Dampening[BallCount];
  
  for (int i = 0 ; i < BallCount ; i++) {   
    ClockTimeSinceLastBounce[i] = millis();
    Height[i] = StartHeight;
    Position[i] = 0; 
    ImpactVelocity[i] = ImpactVelocityStart;
    TimeSinceLastBounce[i] = 0;
    Dampening[i] = 0.90 - float(i)/pow(BallCount,2); 
  }

  while (true) {
    for (int i = 0 ; i < BallCount ; i++) {
      TimeSinceLastBounce[i] =  millis() - ClockTimeSinceLastBounce[i];
      Height[i] = 0.5 * Gravity * pow( TimeSinceLastBounce[i]/1000 , 2.0 ) + ImpactVelocity[i] * TimeSinceLastBounce[i]/1000;
  
      if ( Height[i] < 0 ) {                      
        Height[i] = 0;
        ImpactVelocity[i] = Dampening[i] * ImpactVelocity[i];
        ClockTimeSinceLastBounce[i] = millis();
  
        if ( ImpactVelocity[i] < 0.01 ) {
          ImpactVelocity[i] = ImpactVelocityStart;
        }
      }
      Position[i] = round( Height[i] * (PIXEL_COUNT - 1) / StartHeight);
    }
  
    for (int i = 0 ; i < BallCount ; i++) {
      setPixel(Position[i],colors[i][0],colors[i][1],colors[i][2]);
    }
    
    showStrip();
    setAll(0,0,0);
  }
}

void setPixel(int Pixel, byte red, byte green, byte blue) {
 #ifdef ADAFRUIT_NEOPIXEL_H 
   // NeoPixel
   strip.setPixelColor(Pixel, strip.Color(red, green, blue));
 #endif
 #ifndef ADAFRUIT_NEOPIXEL_H 
   // FastLED
   leds[Pixel].r = red;
   leds[Pixel].g = green;
   leds[Pixel].b = blue;
 #endif
}

void setAll(byte red, byte green, byte blue) {
  for(int i = 0; i < PIXEL_COUNT; i++ ) {
    setPixel(i, red, green, blue); 
  }
  showStrip();
}

void showStrip() {
 #ifdef ADAFRUIT_NEOPIXEL_H 
   // NeoPixel
   strip.show();
 #endif
 #ifndef ADAFRUIT_NEOPIXEL_H
   // FastLED
   FastLED.show();
 #endif
}



void ButtonPressed(void){
  boolean newState = digitalRead(BUTTON_PIN);
  while(newState == HIGH)  {
    // Short delay to debounce button.
    colorWipe(strip.Color(255,   0,   0), 10);    // Red
    colorWipe(strip.Color(255,   255,   255), 10); 
    // Check if button is still low after debounce.
    newState = digitalRead(BUTTON_PIN);
     strip.clear(); 
    }
    if(newState == LOW) {
    }
  }

Materiál pro další experimenty:


Můžete si samozřejmě vybrat i jiné knihovny, například FastLED.

Krásný video návod na použití knihovny je zde: Satisfying LED Mood Lamp - 3D Printing and Arduino DIY

Skvělý článek pro další experimentování s programováním je například tento:

Napojení WeMos na mobilní aplikaci je třeba v tomto návodu pomocí Blynk aplikace - WS2812B Neopixel RGB LED Strip control via Blynk & NodeMCU ESP8266


Přejeme Vám příjemnou zábavu, Printednest


Comments


bottom of page