Introduction: DNA Helix Lamp - Arduino Powered WS2812B LED Strip 3D Printed Fancy Desk Lamp

About: Have a nice day

I wanted to make a LED lamp which can be simple, minimalist and programmable. The power source should be simple and effectient like standard 5V USB Power Source that can be either mobile phone charger or a power bank.

I was curious with various LED Strip lamp and few Helical lamps. So I decided to do this DNA Helix Lamp.

The size of the lamp was restricted by the power consumption of the LED Strip. Each LED in the WS2812B Strip consumes 0.3 Watt power (60mA at 5V). Another consideration was the voltage drop. There will be voltage drop of 1V for every 15 LEDs. So I decided to limit the LED count within 15, as the total power needed will be 5V, 1A or 5W power source, which can be easily provided by 5V power out in Arduino.

There was problem in finding the 30 LED/m strips in my location. So I went with 60 LED/m strip for the lamp powered with arduino nano.

For controlling the lamp, I wanted it to be simple. So I went with a IR Receiver to control and operate it easily. Ofcourse using Bluetooth or WiFi is possible, but an overkill for this minimalist lamp.

Supplies

  1. Arduino Nano or Compatible
  2. WS2812B LED Strip (min length - 2 x 20-21 cm), count can be adjusted in code
  3. IR Receiving End VS1838B or Compatible
  4. Generic IR Remote
  5. Resistors 330 Ohms x 2
  6. USB Power Adapter or Power Bank with min 5V 2A rating or 10000 mAh
  7. Access to 3D Printer to create the lamp parts (around 75-80g of materials)
  8. Adhesive, rubber bands, soldering tools, wires, etc for making/fixing

Step 1: Print the Parts

The Lamp was designed in AutoCAD, as I am proficient in it. I made the Helix and extruded the arms of the lamp. Added the base and required openings.

Several iterations we done modeling and printing. Few worthy try are

  1. 2 Turn 80mm dia Helix with 210mm height (my 3D printer limit is 250mm) and 5mm thick arms (Arm length - 440mm)
  2. 1 Turn 90mm dia Helix with 200mm height and 4mm thick arms (Arm length - 320mm)
  3. 1 Turn 60mm dia Helix with 160mm height and 4mm thick arms (Arm length - 220mm)

The last one was small, firm and perfect.

All the required 3D models are here.

The base part of the model is incomplete right now. I will post an updated version soon.

Recommended print settings are there.

Step 2: Attach the LED Strips

With the 3D Models printed, start with the following

  1. Cut required length of LED Strip. It was 12 LEDs in my case.
  2. Solder the LED strip ends - check the direction before soldeing
  3. Fix the LED strips in the printed helix arms with adhesives. LED strip's own adhesive might not be sufficient.
  4. Make sure both the led strips are PARALLEL. Otherwise, fixing the strands will be hard and overall lamp will look weird.
  5. Once the strips are glued strong enough, start placing the strand pieces in between the arms along each LED. Glue them firmly. Attach rubber bands if needed.
  6. Once all the strands are fixed, test the strips if needed.

Step 3: The Circuit

The circuit is very simple. Once you have working Arduino Nano (ie having Boot loader installed), Connect the 5V and Ground to corresponding Vcc and Gnd of LED Strips and IR receiver. Connect D7, D8 with 330 Ohm resistor and either LED Strips serially. Connect D9 with IR Receiver Data pin. Voila. Put the circuit in the base and wrap it up.

You can use tapes to fix the IR Receiver aligning with hole in the base model.

Step 4: The Code

The code is fairly simple. I have used the latest Arduino IDE.

  1. Add FastLED and IRremote libraries in the Arduino Project
#include <FastLED.h>
#include <IRremote.hpp>
  1. Define and initialize required variables
// IR Remote
const int IR_RECEIVE_PIN = 9;

// WS2812 LED Strip
#define LED1_PIN 7
#define LED2_PIN 8
#define NUM_LEDS 12
CRGB leds1[NUM_LEDS];
CRGB leds2[NUM_LEDS];

// Color
int start = 0;
int rgbArray[NUM_LEDS][3] = {
{255, 0, 0}, {255, 127, 0}, {255, 255, 0}, {127, 255, 0},
{0, 255, 0}, {0, 255, 127}, {0, 255, 255}, {0, 127, 255},
{0, 0, 255}, {127, 0, 255}, {255, 0, 255}, {255, 0, 127}
};

// Light Control
int lightMode = 0;
bool lightOn = true;

float lightBrightness = 1.0f;
float lightBrightnessStep = 0.1f;

int lightSleep = 250;
int lightSleepStep = 50;
int lightSleepMin = 50;
int lightSleepMax = 1000;

// char buffer for Serial PrintF
char printBuffer[40];
  1. In setup() section
void setup() {

// Init Serial
Serial.begin(115200);

// Setup LED Strip
FastLED.addLeds<WS2812, LED1_PIN, GRB>(leds1, NUM_LEDS);
FastLED.addLeds<WS2812, LED2_PIN, GRB>(leds2, NUM_LEDS);

// Setup IR Remote
IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);
}
  1. In loop() section
void loop() {

processIrRemote();
updateLight();
delay(lightSleep);
}
  1. Function to process IR interrupts
void processIrRemote() {
if (IrReceiver.decode()) {
// Serial.println(IrReceiver.decodedIRData.decodedRawData, HEX); // Print "old" raw data
// IrReceiver.printIRResultShort(&Serial); // Print complete received data in one line
// IrReceiver.printIRSendUsage(&Serial); // Print the statement required to send this data

// USE THIS DEBUG INFO TO MAP REMOTE KEYS
snprintf(printBuffer, sizeof printBuffer, "ir Command:%x\n", IrReceiver.decodedIRData.command);
Serial.print(printBuffer);

switch (IrReceiver.decodedIRData.command) {
case 0x8: // left
lightSleep -= lightSleepStep;
if (lightSleep < lightSleepMin) lightSleep = lightSleepMin;
break;
case 0x5a: // right
lightSleep += lightSleepStep;
if (lightSleep > lightSleepMax) lightSleep = lightSleepMax;
break;
case 0x18: // up
lightBrightness += lightBrightnessStep;
if (lightBrightness > 1.0f) lightBrightness = 1.0f;
break;
case 0x52: // down
lightBrightness -= lightBrightnessStep;
if (lightBrightness < 0.0f) lightBrightness = 0.0f;
break;
case 0x1c: // Ok
lightOn = !lightOn;
break;
case 0x19: // 0
lightMode = 0;
break;
case 0x45: // 1
lightMode = 1;
break;
case 0x46: // 2
lightMode = 2;
break;
case 0x47: // 3
lightMode = 3;
break;
case 0x44: // 4
lightMode = 4;
break;
case 0x40: // 5
lightMode = 5;
break;
case 0x43: // 6
lightMode = 6;
break;
case 0x07: // 7
lightMode = 7;
break;
case 0x15: // 8
lightMode = 8;
break;
case 0x09: // 9
lightMode = 9;
break;
case 0x16: // *
lightMode--;
if (lightMode < 0) lightMode = 9;
break;
case 0xd: // #
lightMode++;
if (lightMode > 9) lightMode = 0;
break;
default:
break;
}

IrReceiver.resume(); // Enable receiving of the next value
}
}
  1. Functions to update LED lights
void updateLight() {

if (lightOn == false) {
FastLED.clear();
FastLED.show();
return;
};

for (int i = 0; i < NUM_LEDS; i++) {
int c = start + i;
if (c >= NUM_LEDS) c -= NUM_LEDS;
leds1[i] = getColor(c, lightBrightness);
leds2[i] = getColor(c, lightBrightness);

// snprintf(printBuffer, sizeof printBuffer, "i:%d, Angle %d,RGB - %d, %d, %d\n", i, angle + i * step, r, g, b);
// Serial.print(printBuffer);
}
FastLED.show();

start += 1;
if (start >= NUM_LEDS) start = 0;

}

CRGB getColor(int index, float brightness) {
switch (lightMode) {
case 0:
return CRGB(rgbArray[index][0] * brightness, rgbArray[index][1] * brightness, rgbArray[index][2] * brightness); // mode 0 - RGB
case 1:
return CRGB(rgbArray[index][0] * brightness, 0, 0); // mode 1 Red
case 2:
return CRGB(0, rgbArray[index][1] * brightness, 0); // mode 2 Blue
case 3:
return CRGB(0, 0, rgbArray[index][2] * brightness); // mode 3 Green
case 4:
return CRGB(rgbArray[index][0] * brightness, rgbArray[index][0] * brightness, rgbArray[index][0] * brightness); // mode 4 White
case 5:
case 6:
case 7:
case 8:
case 9:
default:
return CRGB(rgbArray[index][0] * brightness, rgbArray[index][1] * brightness, rgbArray[index][2] * brightness); // mode 5-9 TODO
}
}

The sample .ino code is attached below.