Project in progress

Corolla Desk Light © GPL3+

Corolla is a lamp that can be adjusted to focus its light on a reading/working spot or to spread light around for ambient lighting.

  • 9,304 views
  • 3 comments
  • 24 respects

Components and supplies

Necessary tools and machines

Apps and online services

About this project

My plan is to build a lamp that can be adjusted to focus its light on a reading/working spot or to spread light around for ambient lighting.

LEDs are widely used these days to provide light in public places, workspaces or at home. Still, there are not many LED lamps which allow for users to adjust the light temperature (or color) or how/where this light is projected.

This project consists of a custom made lamp in the shape of a flower with six petals connected to a central hub. Each petal have two articulated parts and each half host a RGB LED.

Petals can change their angle relative to central hub and the tips of the petals can further change angle made with the root of the petal, this allowing the light produced by LEDs to be focused on a area or spread around.

The main roles of the Arduino 101 board are to control the motors or servos for petals position, to generate the PWM signals to control RGB LEDs and communicate with the user through bluetooth with the help of a mobile app or another bluetooth device.

With the help of the mobile app, user can control petals position, light color and intensity, create and store patterns for petals positions and LEDs working modes.

Commands can be given directly to lamp without a mobile app, with switches and potentiometers or by tapping the lamp base which hold Arduino board. These taps are detected with the help of Arduino's onboard accelerometer.

Being an Arduino powered device will have the possibility to be connected to a number of sensors like temperature sensor, PIR, RTC, humidity, etc and display their status in a visual way or react to parameters given by these sensors.

The build

After much thinking on how the lamp will look, I decided to try to build a lamp with a steampunk(ish) look.

This decision being made, I choose building materials as brass, brass beads, hinges, plywood, various nuts, bolts and wires, water based paint and various glues. On the electronics side, I used the kindly provided Genuino 101 and Grove Starter Kit for Arduino/Genuino101 plus four 10K potentiometers, a WS8212 RGB LEDs strip and 5 positions linear switch.

The petals were cut from 3mm pine plywood. The tip of the petal is attached with two hinges to the root of the petal which is also attached with a hinge to central hub.

After petals were completed I attached them to a central hub, a hexagonal piece made of plywood. This hub is attached to the mechanism which open or close petals.

Petals mechanism

The mechanism is based on a nut and bolt assembly, the bolt is coupled with the motor shaft and the nut assembly is connected to the petals command rods.

The stepper motor and controller used are the ones from Grove Starter Kit.

When the command rods are pulled towards motor, the petals lean forward closing the flower. When the command rods are pushed away from motor petals lean backward opening the flower.

To determine the position of the petals and the mechanism in order to avoid to damage the mechanics or the motor, I used a feedback potentiometer which is mechanically connected to the moving part of the mechanism. I determined by experiments the thresholds for open and close positions.

Electronics

As I wrote before, for this project I used the provided Genuino 101 and Grove Starter Kit for Arduino/Genuino101 plus four 10K potentiometers, a WS8212 RGB LEDs strip and 5 positions linear switch.

I wished to implement as many features as possible in this and I had in mind a number of parameters to control:

  • petals position
  • brightness
  • light color
  • independent control of LEDs R, G, B channels
  • independent control of LCDs R, G, B channels
  • bluetooth connection
  • different LEDs/colors patterns

I wanted to control many of these parameters with potentiometers, looks more intuitive to me, but Arduino have a small number (6) of analog inputs. One way was to multiplex a number of potentiometers on one analogic input or to group the actions/pots and select the group I want.

I choose the latter and I used a 5 way switch to choose between groups/ modes:

Position 1 - Mode 1 - potentiometers have these functions:

  • pot1 - petals position
  • pot2 - light intensity
  • pot3 - light color, warm or cold light

Position 2 - Mode 2 - potentiometers have these functions:

  • pot1 - change value for LEDs RED channel
  • pot2 - change value for LEDs GREEN channel
  • pot3 - change value for LEDs BLUE channel

This mode is used to tune the light color.

Position 3 - Mode 3 - potentiometers have these functions:

  • pot1 - change RED channel for display background
  • pot2 - change GREEN channel for display background
  • pot3 - change BLUE channel for display background

This mode is to tune the background color of the LCD display.

Position 4 - select bluetooth control.

Position 5 - predefined combinations of LEDs/colors patterns.

To date, Mode 1, 2 and 3 are implemented.

Using this type of 5 way switch was a first to me. I wanted a linear not rotary multi pole switch and the only one I could find was a guitar switch.

I saw the middle pins connected together and I assumed that each lever position connect each of the pins to center. I was wrong... Each lever position trigger a combination of one, two or three pins if pins 4 and 5 are not bind together or up to five pins if pins 4 and 5 are bind. I choose to unbind them and in this way I got five positions using only three digital pins.

Unused digital and analog pins will be used for additional sensors and modules.

The lamp base is made from two identical plywood boxed mounted face to face and hold together with four screws mounted in corners.

The base box holds Genuino board + shield, potentiometers used to adjust lamp parameters, the 5 positions switch, voltage regulator and the Grove display.

The lamp pole is made from 10mm brass tube and hold the cables for motor and LEDs.

RGB LEDs are 36 pieces of 5V WS2812 leds, grouped three on each petal part. These LEDs are controlled with the help of Adafruit Neopixel library.

Power

At the beginning, for test/programming purposes, I powered everything (Arduino + stepper + Leds) from the USB cable, but I was expecting when set the LEDs to higher brightness the current draw to be too high and the Arduino board reset, which was happened. When USB powered the voltage at 5V pin was around 4.8 - 4.9 Volts.

The obvious choice was to power the Arduino board from power jack, but to my surprise LEDs did not light up...

WS2812 LEDs are not just simple RGB LEDs, they have an integrated driver inside, powered at 5V, which control the Red, Green and Blue LEDs.

When my Arduino board is powered from power jack, the output of 5V pin is about 5.25V which seems fine for Arduino but is not tolerated by the WS LEDs...

So the next option was to use an external voltage regulator with an output voltage closer to 5V, to supply the required power to Arduino + stepper + Leds.

I choose for this task a 5V/5A step-down power regulator, D24V50F5 made by Pololu. 5 Amps might look overkill but 36 WS8212 ICs at about 60 mA/IC (20mA on each color) at full brightness result in 2160 mA current draw and I wanted to have some reserve for future use.

Besides, the output voltage of D24V50F5 is 4.95V which is fine for all devices involved. I sourced this voltage directly to 5V pin and so far everything looks good.

Finally, a couple of videos with Corolla in action. Watching them require some patience because the movement of the petals is quite slow.

Mechanics demo

Mechanics and lights demo

Custom parts and enclosures

corolla1
Sketchup drawing
corolla1_8wxZ0uze0B.skp
corolla2
Sketchup drawing
corolla2_MP9MkEL5Sn.skp
corolla3
Sketchup drawing
corolla3_8efV902ZsY.skp

Schematics

Corolla schematic
Electrical schematic
corolla_C53Sv4GEIY.fzz
5 way switch
5 positions switch connection
Switch pea76hptex

Code

CorollaArduino
Code for stepper, LEDs and display
#include <Stepper.h>
#include <Adafruit_NeoPixel.h>
#include <Wire.h>
#include "rgb_lcd.h"

#define oneMotorTurn 32 //number of steps required to turn motor one complete turn
#define oneOutputTurn 32 * 64 //number of steps required to turn output shaft of the reductor one turn
#define halfOutputTurn 32 * 32 //number of steps required to turn output shaft of the reductor a half turn
#define myledPin 3

rgb_lcd lcd;
String lcdString;
Stepper motor_stepper(oneMotorTurn, 8, 10, 9, 11);// define stepper control pins
Adafruit_NeoPixel strip = Adafruit_NeoPixel(36, myledPin, NEO_RGB + NEO_KHZ800); //define RGB LEDs strip

//int petalPos;
int brightness;// light intensity
int maxbrightness = 42;//maximum brightness allowed to met condition maxbrightness * maxRatio <=255. I put 42 as start value to match the start values for red, green and ratios.
int maxRatio;//biggest color ratio - used to calculate maxbrightness
int colorTemp;//color intensity used to change light color
int red_ratio = 6;
int green_ratio = 5;
int blue_ratio = 1;
int red_led=1;// value for RED of RGB LED
int green_led=1;// value for GREEN of RGB LED
int blue_led=1;// value for BLUE of RGB LED
int red_lcd=110;// value for RED of RGB LED - I choose these default value for a pale orange backlight color
int green_lcd=90;// value for GREEN of RGB LED
int blue_lcd=10;// value for BLUE of RGB LED

int pot1Pin = A2;//first control potentiometer
int pot2Pin = A1;//second control potentiometer
int pot3Pin = A0;//third control potentiometer
int feedbackpotPin = A3;//feedback potentiometer, used to determine petals position

int switch1Pin1 = 2;//pins from linear switch
int switch1Pin2 = 4;
int switch1Pin3 = 5;
int switch1val1 = 0;
int switch1val2 = 0;
int switch1val3 = 0;
int selectedMode = 1;

int pot1RawValue1, pot1RawValue2, pot1RawValue3;  //variables to store the values coming from the potentiometers
int pot2RawValue1, pot2RawValue2, pot2RawValue3;
int pot3RawValue1, pot3RawValue2, pot3RawValue3;
int ledPot1Value = 0;//variables to store the values coming from the potentiometers mapped on different ranges
int ledPot2Value = 0;
int ledPot3Value = 0;
int lcdPot1Value = 0;//variables to store the values coming from the potentiometers mapped on different ranges
int lcdPot2Value = 0;
int lcdPot3Value = 0;
int feedbackpotValue = 0;
int stepper_turn = 0;

void setup() {
  pinMode(myledPin, OUTPUT);
  pinMode(pot1Pin, INPUT);
  pinMode(pot2Pin, INPUT);
  pinMode(pot3Pin, INPUT);
  pinMode(feedbackpotPin, INPUT);
  pinMode(switch1Pin1, INPUT);
  pinMode(switch1Pin2, INPUT);
  pinMode(switch1Pin3, INPUT);
  strip.begin();//start RGB LEDs
  strip.show();
  lcd.begin(16, 2);
  lcd.setRGB(red_lcd, green_lcd, blue_lcd);
  Serial.begin(9600);
}

// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
  for(uint16_t i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, c);
      strip.show();
      delay(wait);
  }
}

void loop() {
  
  switch1val1 = digitalRead(switch1Pin1);// read the value from the switch
  switch1val2 = digitalRead(switch1Pin2);
  switch1val3 = digitalRead(switch1Pin3);
  Serial.print("pot1RawValue1 = ");
  Serial.println(pot1RawValue1);
  Serial.print("pot1RawValue2 = ");
  Serial.println(pot1RawValue2);
  Serial.print("pot1RawValue3 = ");
  Serial.println(pot1RawValue3);
  Serial.print("Selected mode = ");
  Serial.println(selectedMode);

   //each switch position corespond to a combination of one, two or three pins, so is required to check all three pins at once
  if ((switch1val1 == 0)&&(switch1val2 == 0)&&(switch1val3 == 1))//start switch1 position1 - change petals position, brightness and light temperature
    {
      pot1RawValue1 = analogRead(pot1Pin);// read the value from the potentiometers
      pot2RawValue1 = analogRead(pot2Pin);
      pot3RawValue1 = analogRead(pot3Pin);
      feedbackpotValue = analogRead(feedbackpotPin);
      Serial.print("Feedbackpot = ");
      Serial.println(feedbackpotValue);
      lcd.clear();
      lcd.setCursor(5,0);//coordinates are (column, row) - 0,0 is upper left
      lcd.write("Mode 1");
      if (selectedMode == 2)
          {
            if ((pot1RawValue1 < pot1RawValue2-20) || (pot1RawValue1 > pot1RawValue2+20) || (pot2RawValue1 < pot2RawValue2-20) || (pot2RawValue1 > pot2RawValue2+20) || (pot3RawValue1 < pot3RawValue2-20) || (pot3RawValue1 > pot3RawValue2+20))//I put this condition to not change the Mode parameters when switch from other Mode
              {
                selectedMode = 1;
              }
          }
       if (selectedMode == 3)
          {
            if ((pot1RawValue1 < pot1RawValue3-20) || (pot1RawValue1 > pot1RawValue3+20) || (pot2RawValue1 < pot2RawValue3-20) || (pot2RawValue1 > pot2RawValue3+20) || (pot3RawValue1 < pot3RawValue3-20) || (pot3RawValue1 > pot3RawValue3+20))//I put this condition to not change the Mode parameters when switch from other Mode
              {
                selectedMode = 1;
              }
          }
        if (selectedMode == 1)
          {
            brightness = map(pot2RawValue1, 0, 1023, 0, maxbrightness);
            colorTemp = map(pot3RawValue1, 0, 1023, 0, 15);
            
            Serial.print("brightness = ");
            Serial.println(brightness);
            Serial.print("colorTemp = ");
            Serial.println(colorTemp);
          
            if (pot1RawValue1 < 300)//if the value read from the first potentiometer, pot1, is below this value, petals are closing
              {
                stepper_turn = - halfOutputTurn;
                Serial.println("Close");
              }
            if ((pot1RawValue1 < 300) && (feedbackpotValue < 690))//if the value read from the feedback potentiometer, is below this value (690 in this case), stepper is stopped to not damage the mechanics and/or motor
              {
                stepper_turn = 0;
                Serial.println("Close stopped");
              }
        
            if (pot1RawValue1 > 600)//if the value read from the first potentiometer, pot1, is above this value, petals are opening
              {
                stepper_turn = halfOutputTurn;
                Serial.println("Open");
              }
            if ((pot1RawValue1 > 600) && (feedbackpotValue > 780))//if the value read from the feedback potentiometer, is above this value (750 in this case), stepper is stopped to not damage the mechanics and/or motor
              {
                stepper_turn = 0;
                Serial.println("Open stopped");
              }
        
            if ((pot1RawValue1 > 300) && (pot1RawValue1 < 600))
             {
                stepper_turn = 0;
                Serial.println("Stepper stop");
             }
        
            motor_stepper.setSpeed(500);   
            motor_stepper.step(stepper_turn);
      
            red_led = (brightness * red_ratio) - colorTemp;
            green_led = (brightness * green_ratio) - colorTemp;
            blue_led = (brightness * blue_ratio) + colorTemp;
            colorWipe(strip.Color(green_led, red_led, blue_led), 30);
        }
     delay(300);//this delay is needed for LCD display. Without delay the display is very dim
    }//end switch1 position1

  if ((switch1val1 == 0)&&(switch1val2 == 1)&&(switch1val3 == 1))//start switch1 position 2 - change LEDs colors
    {
      pot1RawValue2 = analogRead(pot1Pin);// read the value from the potentiometers
      pot2RawValue2 = analogRead(pot2Pin);
      pot3RawValue2 = analogRead(pot3Pin);
      lcd.clear();
      lcd.setCursor(5,0);//coordinates are (column, row) - 0,0 is upper left
      lcd.write("Mode 2");
      
      if (selectedMode == 1)
          {
            if ((pot1RawValue2 < pot1RawValue1-20) || (pot1RawValue2 > pot1RawValue1+20) || (pot2RawValue2 < pot2RawValue1-20) || (pot2RawValue2 > pot2RawValue1+20) || (pot3RawValue2 < pot3RawValue1-20) || (pot3RawValue2 > pot3RawValue1+20))
              {
                selectedMode = 2;
              }
          }
       if (selectedMode == 3)
          {
            if ((pot1RawValue2 < pot1RawValue3-20) || (pot1RawValue2 > pot1RawValue3+20) || (pot2RawValue2 < pot2RawValue3-20) || (pot2RawValue2 > pot2RawValue3+20) || (pot3RawValue2 < pot3RawValue3-20) || (pot3RawValue2 > pot3RawValue3+20))
              {
                selectedMode = 2;
              }
          }
        if (selectedMode == 2)
          {
            ledPot1Value = map(pot1RawValue2, 0, 1023, 1, 252);
            ledPot2Value = map(pot2RawValue2, 0, 1023, 1, 252);
            ledPot3Value = map(pot3RawValue2, 0, 1023, 1, 252);
          /*Serial.print("Pot1 = ");
          Serial.println(pot1Value);
          Serial.print("Pot2 = ");
          Serial.println(pot2Value);
          Serial.print("Pot3 = ");
          Serial.println(pot3Value);*/
            red_led = ledPot1Value;
            green_led = ledPot2Value;
            blue_led = ledPot3Value;
    
            lcdString = "R" + String(red_led) + " G " + String(green_led) + " B " + String(blue_led);
            lcd.setCursor(0,1);
            lcd.print(lcdString);
          
            colorWipe(strip.Color(green_led, red_led, blue_led), 30);
            
          // start calculate the colors ratios
             if (ledPot1Value > ledPot2Value)
                  {
                    if (ledPot2Value > ledPot3Value)
                              {
                                red_ratio = ledPot1Value / ledPot3Value;
                                green_ratio = ledPot2Value / ledPot3Value;
                                blue_ratio = 1;
                              }
                    if (ledPot2Value < ledPot3Value)
                              {
                                red_ratio = ledPot1Value / ledPot2Value;
                                green_ratio = 1;
                                blue_ratio = ledPot3Value / ledPot2Value;
                                
                              }
                    if (ledPot1Value < ledPot3Value)
                        {
                          red_ratio = ledPot1Value / ledPot2Value;
                          green_ratio = 1;
                          blue_ratio = ledPot3Value / ledPot2Value;
                        }
                  }
              if (ledPot2Value > ledPot1Value)
                  {
                    if (ledPot1Value > ledPot3Value)
                        {
                          red_ratio = ledPot1Value / ledPot3Value;
                          green_ratio = ledPot2Value / ledPot3Value;
                          blue_ratio = 1;
                        }
                    if (ledPot1Value < ledPot3Value)
                        {
                          red_ratio = 1;
                          green_ratio = ledPot2Value / ledPot1Value;
                          blue_ratio = ledPot3Value / ledPot1Value;
                        }
                    if (ledPot2Value < ledPot3Value)
                        {
                          red_ratio = 1;
                          green_ratio = ledPot2Value / ledPot1Value;
                          blue_ratio = ledPot3Value / ledPot1Value;
                        }
                  }
             // end calculate the colors ratios
          maxRatio = max(red_ratio, green_ratio);
          maxRatio = max(maxRatio, blue_ratio);//calculate the biggest ratio
          maxbrightness = 255/maxRatio;//calculate the maximum brightness
          /*Serial.print("Red_ratio = ");
          Serial.println(red_ratio);
          Serial.print("green_ratio = ");
          Serial.println(green_ratio);
          Serial.print("Blue_ratio = ");
          Serial.println(blue_ratio);
          Serial.print("Max ratio = ");
          Serial.println(maxRatio);
          Serial.print("Max brightness = ");
          Serial.println(maxbrightness);*/
         }
      delay(300);
    }//end switch1 position2

  if ((switch1val1 == 0)&&(switch1val2 == 1)&&(switch1val3 == 0))//start switch1 position 3 - change LCD display background color
    {
      pot1RawValue3 = analogRead(pot1Pin);// read the value from the potentiometers
      pot2RawValue3 = analogRead(pot2Pin);
      pot3RawValue3 = analogRead(pot3Pin);
      lcd.clear();
      lcd.setCursor(5,0);//column, row - 0,0 is upper left
      lcd.write("Mode 3");
      lcdString = "R" + String(red_lcd) + " G " + String(green_lcd) + " B " + String(blue_lcd);
      lcd.setCursor(0,1);
      lcd.print(lcdString);

      if (selectedMode == 1)
          {
            if ((pot1RawValue3 < pot1RawValue1-20) || (pot1RawValue3 > pot1RawValue1+20) || (pot2RawValue3 < pot2RawValue1-20) || (pot2RawValue3 > pot2RawValue1+20) || (pot3RawValue3 < pot3RawValue1-20) || (pot3RawValue3 > pot3RawValue1+20))
              {
                selectedMode = 3;
              }
          }
      if (selectedMode == 2)
          {
            if ((pot1RawValue3 < pot1RawValue2-20) || (pot1RawValue3 > pot1RawValue2+20) || (pot2RawValue3 < pot2RawValue2-20) || (pot2RawValue3 > pot2RawValue2+20) || (pot3RawValue3 < pot3RawValue2-20) || (pot3RawValue3 > pot3RawValue2+20))
              {
                selectedMode = 3;
              }
          }
      if (selectedMode == 3)
          {       
                Serial.println("Mode 3 selected");
                red_lcd = map(pot1RawValue3, 0, 1023, 1, 252);
                green_lcd = map(pot2RawValue3, 0, 1023, 1, 252);
                blue_lcd = map(pot3RawValue3, 0, 1023, 1, 252);
                Serial.print("Red LCD = ");
                Serial.println(red_lcd);
                Serial.print("Green LCD = ");
                Serial.println(green_lcd);
                Serial.print("Blue LCD = ");
                Serial.println(blue_lcd);
                lcd.setRGB(red_lcd, green_lcd, blue_lcd);
                delay(500);
                selectedMode = 3;
             }
      delay(300);
    }//end switch1 position 3

  if ((switch1val1 == 1)&&(switch1val2 == 1)&&(switch1val3 == 0))//start switch1 position 4
    {
      Serial.println("Mode 4 selected");
      delay(500);
    }//end switch1 position 4

  if ((switch1val1 == 1)&&(switch1val2 == 0)&&(switch1val3 == 0))//start switch1 position 5
    {
      Serial.println("Mode 5 selected");
      delay(500);
    }//end switch1 position 5
    
}//end loop

Comments

Similar projects you might like

Sigfox Forest Fire Detector

Project tutorial by Louis Moreau

  • 1,861 views
  • 2 comments
  • 12 respects

TV Tee Shirt

Project showcase by Maddy

  • 3,479 views
  • 1 comment
  • 11 respects

Race Car Dashboard (Online Connectivity)

Project showcase by Team Jatayu

  • 1,866 views
  • 4 comments
  • 5 respects

Arduino Live WiFi Web Scoreboard

Project tutorial by Oli Norwell

  • 2,105 views
  • 0 comments
  • 4 respects
Add projectSign up / Login