top of page

How to make 3D printed RGB LED Rocket Lamp for kids

Updated: Mar 17, 2021




Rocket Lamp is a project whose purpose is to introduce children to the basics of low-current electrical circuits so that they can immediately see the result and have something useful left, such as a lamp for a children's room.

We will show you how to 3d print and assemble our Rocket Lamp for children on a 3D printer. We have prepared 3 levels of difficulty.


Before we begin, take a look at our video tutorials divided into 3 levels of difficulty:


All 3 levels of difficulty can be combined with each other, so go through them all.


BEGINNER LEVEL

You will need:

  1. Yeelight LED Lightstrip Plus 1S - Aliexpress or Amazon

  2. Or cheaper alternative - Govee Smart LED Strip Lights

It is the easiest way to make this lamp for your children. If you don't have the time or the desire to solder and program, all you have to do is print Base_Universal.stl and buy a Smart RGB LED strip. This base (Base_Universal.stl) has a rectangular passage for Smart RGB LED strips with power supply. Simply pass this LED strip into the base of the lamp, then from the base to the tower, on which you attach the LED strip, as you can see in the video Beginner Level. Most of these smart LED strips can be controlled using an application on the phone. In our case we use Yeelight LED Lightstrip Plus 1S.

Then you choose the design of the casing (solid, wire or stars), print it on a 3D printer, and put everything together.



ADVANCED LEVEL



It is designed for those who enjoy moving things further and learning something. Soldering is not necessary, but we recommend it.


You will need:

  1. DC female connector - Aliexpress or Amazon

  2. 5V-12V DC power adapter - Aliexpress or Amazon

  3. 5V-12V LED strip tape - Aliexpress or Amazon

  4. Wago electrical connectors - Aliexpress or Amazon

  5. Smart Wifi Plug Socket Outlet - Amazon Alexa - Aliexpress or Amazon (check if HUB is required)


You will need a DC connector, a DC 5V-12V power adapter, and an RBG LED strip 5V-12V. Because our lamp has no visible button, we have added a Smart socket to this version, which can be controlled by the phone again, and you can remotely turn off the lamp when the child falls asleep without waking him up. In this case, we used a Smart socket from FIBARO. The advantage is also the possibility of connecting this socket to Amazon Alexa, if you have this system at home.

You can install the DC connector in our Base_DC.stl, which has a hole prepared for commonly sold DC connectors. If it is larger than the width of the walls in the base, you can cut the plastic with a knife. Then we recommend fixing with a hot glue gun. You simply solder the DC connector to the LED strip, or use wago connectors as you can see in the video Advanced Level. Then pass the LED strip through the hole in the tower and fix it.

Then you choose the design of the casing (solid, wire or stars), print it on a 3D printer and put everything together.



MASTER LEVEL


Here does real fun begin and fulfill our purpose. Rocket Lamp is a project that is primarily intended as an educational KIT for children to start learning programming in a fun way. However, she is conditioned by the guidance of her parent, who has experience with Arduino. We recommend this difficulty to those who already have experience with the Arduino IDE. You need to install Arduino IDE and drivers on your computer. If you don't have this experience with Arduino, it doesn't matter. If you follow our video Master Level, you should be able to put the lamp into operation and it should work at least as we show in the video.


You will need

Hardware:

  1. WeMos D1 Mini ESP8266 WiFi modul

  2. NeoPixel Ring - 24 x 5050 RGB LED

  3. TTP223 Capacitive Touch Switch Button

  4. Micro USB kabel

  5. Wires


Software:


Arduino IDE - download

You will also need to install the ch340 drivers if you do not have them. How to Install CH340 Drivers


Step 1: Diagram

Everything must be connected as shown in the following figure.


5V ----> NeoPixel VCC

G ----> NeoPixel GND & TTP223 GND

D4 ----> NeoPixel I/O

3V3 ----> TTP223 VCC

D8 ----> TTP223 I/O


Step 2: Soldering

Solder the wires to the Adafruit NeoPixel, the TTP223 button and the WeMos D1 Mini. As you can see in our video tutorial Master Level, or in the pictures below.



Step 3: Installation in the base and tower

Now we can put everything in Base_Wemos_D1_Mini.STL base.

We recommend using any connectors so that the button and LED ring can be replaced if necessary.

If you want, you can, of course, solder everything together.



Step 4: Upload the ARDUINO IDE code

The entire procedure of uploading and modifying code is shown in Master Level from 3:00, but for sure we will repeat the most important moments here.

a) We will first install the ch340 drivers as seen in this video Install Serial Drivers for ESP32 (macOS, Windows, Linux) , or here Instalace ovladače převodníku USB na UART CH340

The link to download the ch340 drivers is here: Download, if you already have, you can skip.

b) Connect WeMos D1 Mini using micro USB to computer.

c) Install Arduino IDE - download

d) Install ESP8266 board as in Master Level 3:05

e) Install Adafruit_Neopixel - Download as in Master Level 3:45

f) Open Adafruit Neopixel buttoncycler.ino from example codes as in Master Level 4:03

g) We will modify the code to:

#define BUTTON_PIN D8

#define PIXEL_PIN D4

#define PIXEL_COUNT 24

h) We'll save our modified code.

i) We will select your board as in Master Level 4:28

j) We will choose COM port as in Master Level 4:30, it can be different for everyone.

i) Upload the code to the lamp via the upload icon as in Master Level 4:36



DONE!


Sources:


Install Adafruit NeoPixel library manually from this link, or via the Library manager as in Master Level 3:45.


Download RocketLamp.zip and open RocketLamp.ino file.

RocketLamp
.zip
Download ZIP • 5KB

Or copy the following code and paste it into a new sketch and save:

// 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) {
    }
  }

Source for further experiments:


You can also choose other libraries, such as FastLED, of course.

Beautiful video instructions for using the library are here: Satisfying LED Mood Lamp - 3D Printing and Arduino DIY

Another project with ESP8266 - Home automation over WiFi using WeMos ESP8266

A great article for further experimentation with programming is this:

Connecting WeMos to a mobile application via Blynk application is in this guide - WS2812B Neopixel RGB LED Strip control via Blynk & NodeMCU ESP8266


Have fun, Printednest


bottom of page