Finished Cube glowing red


 

After reading about LED cubes with Arduino doing nothing else than just fading between colors, i decided to build my one, but instead of just fading colors, why not gather information from the surrounding environment ?

Using the Adafruit TSL2561 and some assumptions (more on that later) I build this cube !

Material

Keyes KY-009 3 color RGB SMD LED (It’s very bright and it’s cheap)  – You can find it here, at dx.com or at banggood.com

Adafruit TSL2561

Arduino UNO R3

3 x 220 ohms resistors

Colors

I’ve read about color temperatures and Illuminance (since the Adafruit sensor returns LUX values) and came up with a theory for the lightning, based in Astronomy and Star classification ! It’s crazy, but bare with me.

I thought about this because, according with some reading I’ve done, the blue color affects your sleep at night, so, lets start with red color for darker ambiance and the cube can stay in a bedroom.  And now, the Astronomy enters:

A hot  star shines blue and a cooler star shines red. Here’s the Wikipedia entry for stellar classification and One-Minute Astronomer explaining star colors. And, here’s the typical illuminance values for the time of day – Wikipedia entry.  So, why not relate both ?

When it’s mid day, a bluish-white color. As the day progresses, the illuminance is getting lower (the LUX values), so the LED color as to change accordingly – Why not use Stellar classification ? And, the blue light problem gets solved because you’ll have a red light at night !

So, my idea was to “CREATE” a relation between the LUX values and the Kelvin values for the effective temperature of the stars and display the related color in the LED according to the LUX return by the sensor during the day.

Here’s my idea

Effective Temperature K Illuminance LUX Surfaces illuminated by Conventional Color description (and LED color)
>= 30.000 32.000 – 100.000 Direct Sun Light Blue
10.000 – 30.000 10.000 – 25.000 Full daylight Blue white
7.500 – 10.000 1000 Overcast day white
6000 – 7.500 400 Sunrise or Sunset on a clear day yellow white
5.200 – 6.000 320 – 400 Office lightning yellow
3.700 – 5.200 100 Very dark overcast day orange
2.400 – 3.700 <100 hallway, full moon (.027 – 1 LUX) red

This is just an example why i’m using this scheme. If we have a very high value of LUX, it’s like a very bright start – lets show a blue light. If we have a very low LUX value, is like a smaller red star – lets show a red light. Just like this – THERE’S NO RELATION BETWEEN THEM, JUST IN MY MIND !

To fade the LEDs and display the colors we’ll be using, I’ll be using  some code for the example “ColorCrossFade” available at the Arduino Tutorials section. (Don’t know the author – If you’re the author, please let me know. Credit is to be given where credit is due )

The colors will be described as percentages of RGB, from 0 to 100 – Using the text from the ColorCrossFade example:

 

* DESCRIBING A COLOR:
 * A color is just an array of three percentages, 0-100,
 * controlling the red, green and blue LEDs
 *
 * Red is the red LED at full, blue and green off
 * int red = { 100, 0, 0 }
 * Dim white is all three LEDs at 30%
 * int dimWhite = {30, 30, 30}
 * etc.
Our colors will be:
    color = { R %, G %, B% }
    black = {0, 0, 0}
    blue = {0, 0, 100}
    blue_white = {72, 79, 100}
    yellow_white = {100,100, 92}
    yellow = {100, 100, 0}
    orange = {100, 59, 20}
    red={100, 0, 0}

This will be how the LED will fade between colors.

The Cube

The Cube I’ve made I took it from here – Twitter Mood Light – The World’s Mood in a Box – and here  – LED Cube Night Light

The differences are that my cube is white (my mistake with the supplier) and my measurements are (in metric system):

Bigger cube top (x1): 15cm x 15cm

bigger cube walls  (x4): 14,7cm x 14,7cm

smaller cube base (x1): 14,4cm x 14,4cm

smaller cube walls (x4): 14,1 cm (width) x 2,5cm (height) – a rectangule

smaller cube cover (x1): 14,4 cm x 14,4cm with a 6mm hole in the middle – This cover made of a mirror

The first photo is the smaller cube ( ignore the hole – that was a mistake) and the mirror top – the cover – goes here. The second photo is the bigger cube that goes on top of the smaller one – once more, ignore the hole – that was a mistake from the supplier

The mirror cover will amplify the LED light (or it’s supposed to 😀 )

cubeBottomHalfcubeAllInside

Connections

Connections sensor

LED above the mirror

 

Here’s the schematic for the cube connections:

Connections for TSL

Every LED connection goes to a 220 Ohm resistor and then to Arduino PINs 9, 10 and 11 – These are PWM PINs that allow the fadding of the LED.

Coding

For the sensor to work, we need to download two libraries from Adafruit for the sensor.  The sensor TSL2561 itself and Adafruit’s sensor library.

You can find out more in Adafruit’s TSL2561 page.

Download the both and put them in your Arduino’s library folder.

The code is quite extensive, but many lines are just info

You can get the complete code from my Bitbucket account.

Include some libraries we need

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_TSL2561_U.h>

Initialize the sensor

Adafruit_TSL2561_Unified tsl = Adafruit_TSL2561_Unified(TSL2561_ADDR_FLOAT, 12345);

Display some info about the sensor

 

/**************************************************************************/
/*
 Displays some basic information on this sensor from the unified
 sensor API sensor_t type (see Adafruit_Sensor for more information)
*/
/**************************************************************************/
void displaySensorDetails(void) {
 sensor_t sensor;
 tsl.getSensor(&sensor);
 Serial.println("------------------------------------");
 Serial.print ("Sensor: "); Serial.println(sensor.name);
 Serial.print ("Driver Ver: "); Serial.println(sensor.version);
 Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id);
 Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" lux");
 Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" lux");
 Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" lux"); 
 Serial.println("------------------------------------");
 Serial.println("");
 delay(500);
}

In the next function, were going to configure the sensor gain and integration time. The sensor gain means light boost in dim or bright situations. Integration time is the time the sensors stays collecting light samples. The driver version 2 has also an option for auto-gain – witch is set. More information can be read in Adafruit’s use page for the TSL2561 sensor.

/**************************************************************************/
/*
 Configures the gain and integration time for the TSL2561
*/
/**************************************************************************/
void configureSensor(void) {
 /* You can also manually set the gain or enable auto-gain support */
 // tsl.setGain(TSL2561_GAIN_1X); /* No gain ... use in bright light to avoid sensor saturation */
 // tsl.setGain(TSL2561_GAIN_16X); /* 16x gain ... use in low light to boost sensitivity */
 tsl.enableAutoRange(true); /* Auto-gain ... switches automatically between 1x and 16x */
 
 /* Changing the integration time gives you better sensor resolution (402ms = 16-bit data) */
 tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_13MS); /* fast but low resolution */
 // tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_101MS); /* medium resolution and speed */
 // tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_402MS); /* 16-bit data but slowest conversions */

/* Update these values depending on what you've set above! */ 
 Serial.println("------------------------------------");
 Serial.print ("Gain: "); Serial.println("Auto");
 Serial.print ("Timing: "); Serial.println("13 ms");
 Serial.println("------------------------------------");
}

LED configuration

/* 
 Configure LED PINs
 IN LED smd, the PINs are switched
 green is R
 red is G
 blue is B
*/
int redPin = 10; // Red LED, connected to digital pin 9
int greenPin = 9; // Green LED, connected to digital pin 10
int bluePin = 11; // Blue LED, connected to digital pin 11

The color definitions using R G B notation in an array

// Color arrays
int black[3] = { 0, 0, 0 };
int blue[3] = { 0, 0, 100 };
int blue_white[3] = { 72, 79, 100 };
int white[3] = { 100, 100, 100 };
int yellow_white[3] = { 100, 100, 92 };
int yellow[3] = { 100, 100, 0 };
int red[3] = { 100, 0, 0 };
// Set initial color
int redVal = black[0];
int greenVal = black[1]; 
int blueVal = black[2];
// Initialize color variables
int prevR = redVal;
int prevG = greenVal;
int prevB = blueVal;
int wait = 10; // 10ms internal crossFade delay; increase for slower fades
int hold = 0; // Optional hold when a color is complete, before the next crossFade

Setup function for arduino

void setup(void) {
 Serial.begin(9600);
 Serial.println("Light Sensor Test"); Serial.println("");
 
 /* Display some basic information on this sensor */
 
 //displaySensorDetails();
 
 /* Setup the sensor gain and integration time */
 configureSensor();
 
 //configure the PINs
 pinMode(redPin, OUTPUT); // sets the pins as output
 pinMode(greenPin, OUTPUT); 
 pinMode(bluePin, OUTPUT);
 
 //start with all off
 digitalWrite (redPin, LOW);
 digitalWrite (greenPin, LOW);
 digitalWrite (bluePin, LOW);
 
}

The rest of the code is well commented

void loop(void) { 
 /* Get a new sensor event */ 
 sensors_event_t event;
 tsl.getEvent(&event);
 
 /* Display the results (light is measured in lux) */
 if (event.light) {
     Serial.print(event.light); Serial.println(" lux");
     fadeColor (event.light);
 }
 else {
     //we dont have any info, lets fade to black
     /* If event.light = 0 lux the sensor is probably saturated
        and no reliable data could be generated! */
     crossFade(red); //red is default color
     //Serial.println("Sensor overload");
 }
 delay(250);
}

The next function is responsible for defining which color is next in the LED based on the LUX measurement

void fadeColor (int luxval) {
 
 if (luxval >= 10000.00 and luxval <= 17000.00) {
     Serial.print ("fading to blue :");
     Serial.println (luxval);
     crossFade (blue);
 } else if (luxval >= 400 and luxval < 10000.00) {
     Serial.print ("fading to blue white :");
     Serial.println (luxval);
     crossFade (blue_white);
 } else if (luxval >= 320 and luxval < 400.00) {
     Serial.print ("fading to white :");
     Serial.println (luxval);
     crossFade (white);
 } else if (luxval >= 100 and luxval < 320) {
     Serial.print ("fading to yellow white :");
     Serial.println (luxval);
     crossFade (yellow_white);
 } else if (luxval >= 80 and luxval < 100) {
     Serial.print ("fading to yellow :");
     Serial.println (luxval);
     crossFade (yellow);
 } else if (luxval < 100) {
     Serial.print ("fading to red :");
     Serial.println (luxval);
     crossFade (red);
 }
 
}

// Functions used from CrossColorFade

// http://www.arduino.cc/en/Tutorial/ColorCrossfader
int calculateStep(int prevValue, int endValue) {
 int step = endValue - prevValue; // What's the overall gap?
 if (step) { // If its non-zero, 
 step = 1020/step; // divide by 1020
 } 
 return step;
}
/* The next function is calculateVal. When the loop value, i,
* reaches the step size appropriate for one of the
* colors, it increases or decreases the value of that color by 1. 
* (R, G, and B are each calculated separately.)
*/
int calculateVal(int step, int val, int i) {
 if ((step) && i % step == 0) { // If step is non-zero and its time to change a value,
 if (step > 0) { // increment the value if step is positive...
 val += 1; 
 } 
 else if (step < 0) { // ...or decrement it if step is negative
 val -= 1;
 } 
 }
 // Defensive driving: make sure val stays in the range 0-255
 if (val > 255) {
 val = 255;
 } 
 else if (val < 0) {
 val = 0;
 }
 return val;
}
/* crossFade() converts the percentage colors to a 
* 0-255 range, then loops 1020 times, checking to see if 
* the value needs to be updated each time, then writing
* the color values to the correct pins.
*/
void crossFade(int color[3]) {
 // Convert to 0-255
 int R = (color[0] * 255) / 100;
 int G = (color[1] * 255) / 100;
 int B = (color[2] * 255) / 100;
 int stepR = calculateStep(prevR, R);
 int stepG = calculateStep(prevG, G); 
 int stepB = calculateStep(prevB, B);
 for (int i = 0; i <= 1020; i++) {
 redVal = calculateVal(stepR, redVal, i);
 greenVal = calculateVal(stepG, greenVal, i);
 blueVal = calculateVal(stepB, blueVal, i);
 analogWrite(redPin, redVal); // Write current values to LED pins
 analogWrite(greenPin, greenVal); 
 analogWrite(bluePin, blueVal);
 delay(wait); // Pause for 'wait' milliseconds before resuming the loop
 }
 // Update current values for next loop
 prevR = redVal; 
 prevG = greenVal; 
 prevB = blueVal;
 delay(hold); // Pause for optional 'wait' milliseconds before resuming the loop
}