DIY a Magic Light Box
Let's see what Magic Light Box (MLB) is!
MLB is a lighting box that can change the color upon the movment. It is based on Arduino Nano, using tri-axial accelerometer ADXL345 to collect the moving information. Besides, it can be charged by way of wireless charging.
Three Lighting Mode:
Shaking in X direction - White Color Mode
Shaking in Y direction - Auto-changing Color Mode
Shaking in Z direction - Changing upon Attitude Mode
Prepare the Materials
Tools
Iron solder
Hot melt glue gun
Tool for cutting the prototyping board
Materials
1 x Arduino Nano
1 x ADXL345
1 x Wirelss charging module
1 x DC-DC 5V boost module
2 x 3.7V lithium ion battery 952240
20 x Common anode mist RGB led
1 x Resistance of 5 ohms, 100 ohms each one
3 x NPN transistor 8050
N x DuPont line, sewing, fly line
1 x 5.5mm DC Power Interface
1 x 12VDC power adapter
Schmatics
R1 = 5ohm, R2 = 10ohm, the value depends on the number of RGB LED.
Connects the Modules
Connects the modules based on the schematic.
Testing the Circuit
Test the circuit to see if the driving part works or not.
Add the Glue to Protect the Circuit and Program
The Arduino Nano is then covered by the glue to avoid the possible short circuit.
Do the same for the other modules.
Then simply tied them with hot melt adhesive. Before that you can cut off some pins on the modules to save space, such as arduino Nano's ICSP pins. Once the work is completed, this Nano is impossible to use again, so, for those unused IO pins, cut them off!
Program to the Nano, and test the functions. Test the charging effect. After doing the above work, this stuff can be put aside.
Installing the RGB LEDs to Acrylic Board
The thickness of the acrylic board is 1.7mm. Cut the boards as the attached designs.
Install the RGB LED to the 5 boards with holes.
All 20 RGB LEDs are in prallel connection. Be careful the polarity of each LED.
I don't recommend using the colored line on the photo, as the soldering point is easy to disconnect.
The soft fly line is a good choice, as it is able to adapt to the process of enclosing acrylic to the cubic.
Note, the current of single line only allowed 47mA or less. So the part closer to the power should be connected more lines. The lines connected to anode pins should be more than the cathode pin.
Pay attention to confirm the fly line is not easy to fall off, and using a multimeter to verify before the final installation.
Yes, this step is very complicated.
Downloads
Test With the Electronic Controlling Part
Connect the controlling part made above, and test.
Install the Internal Cube
Connect the boards with hot melt glue to get the Internal LED cube done.
Install the LED Cube Onto the Acrylic Base Board
Install the LED cube on a white acrylic. Put the wireless charging receiving coil inside the center, self-locking switch to the right position.
Install the External Acrylic Cube Boards
Glue the acrylic boards into a big cube, and install the LED cube into it.
The main body of the MLB is done, and the size is 96x96x96mm
Make the Charging Base
It's very easy to make the charging base.
Put the DC connecter and the wireless charging module to the acrylic board.
Plug in the power adapter, and put the MLB onto the charging base, the work is finally done.
Thanks!
Made by Xie Linhong
Arduino Code Attached
#include //use timer lib
#include
#define Register_ID 0
#define Register_2D 0x2D
#define Register_X0 0x32
#define Register_X1 0x33
#define Register_Y0 0x34
#define Register_Y1 0x35
#define Register_Z0 0x36
#define Register_Z1 0x37
int ADXAddress = 0xA7 >> 1;
//variable to keep the info of accelerometer
int X0, X1, Xg;
int Y0, Y1, Yg;
int Z1, Z0, Zg;
//pins for three color
int ledx = 9;
int ledy = 5;
int ledz = 6;
//declare 7 counters
int counterX, counterY, counterZ, counterT, counterx, countery, counterz;
//3 variable to keep the state
int stateX, stateY, stateZ;
//breathing value
int valx = 60;
int valy = 130;
int valz = 195;
//breathing speed
int fadeAmount1 = 3;
int fadeAmount2 = 6;
int fadeAmount3 = 9;
void setup() {
// Serial.begin(9600); //use the serial port to debug
// initial
Wire.begin();
delay(10);
Wire.beginTransmission(ADXAddress);
Wire.write(Register_2D);
Wire.write(8);
Wire.endTransmission();
pinMode(ledx, OUTPUT);
pinMode(ledy, OUTPUT);
pinMode(ledz, OUTPUT);
counterY = 0;
counterX = 0;
counterT = 0;
//set the state of X,Y,Z in off state
stateX = 0;
stateY = 0;
stateZ = 0;
}
void loop() {
//all off
digitalWrite(ledx, 0);
digitalWrite(ledy, 0);
digitalWrite(ledz, 0);
//read the acc info of X,Y,Z
Wire.beginTransmission(ADXAddress);
Wire.write(Register_X0);
Wire.write(Register_X1);
Wire.endTransmission();
Wire.requestFrom(ADXAddress, 2);
if (Wire.available() <= 2);
{
X0 = Wire.read();
X1 = Wire.read();
X1 = X1 << 8;
Xg = X0 + X1;
}
Wire.beginTransmission(ADXAddress);
Wire.write(Register_Y0);
Wire.write(Register_Y1);
Wire.endTransmission();
Wire.requestFrom(ADXAddress, 2);
if (Wire.available() <= 2);
{
Y0 = Wire.read();
Y1 = Wire.read();
Y1 = Y1 << 8;
Yg = Y0 + Y1;
}
Wire.beginTransmission(ADXAddress);
Wire.write(Register_Z0);
Wire.write(Register_Z1);
Wire.endTransmission();
Wire.requestFrom(ADXAddress, 2);
if (Wire.available() <= 2);
{
Z0 = Wire.read();
Z1 = Wire.read();
Z1 = Z1 << 8;
Zg = Z0 + Z1;
}
//judge if acc value of X arrives the threshold, add the counter
if (Xg >= 500 || Xg <= -500) {
counterX++;
//when counter X starts, timer will start, and enter clear function after 0.5s
if (counterX == 1) {
MsTimer2::set(500, Clear);
MsTimer2::start();
}
}
//if the counterX is more than 16 before clearing, open X trig state(auto-changing color)
if (counterX >= 16) { //16 can be changed to other number, the smaller the more sensitive
stateX = !stateX;
while (stateX == 1) {
fading();
}
}
if (Yg >= 500 || Yg <= -500) {
// checking Y
counterY++;
if (counterY == 1) {
MsTimer2::set(500, Clear);
MsTimer2::start();
}
}
if (counterY >= 16) {
stateY = !stateY;
while (stateY == 1) {
following();
}
}
if (Zg >= 500 || Zg <= -500) {
// checking Z
counterZ++;
if (counterZ == 1) {
MsTimer2::set(500, Clear);
MsTimer2::start();
}
}
if (counterZ >= 14) {
stateZ = !stateZ;
while (stateZ == 1) {
white();
}
}
delay(6);
// Serial.print("X=");
// Serial.print(Xg);
// Serial.print(" Y=");
// Serial.print(Yg);
// Serial.print(" Z=");
// Serial.print(Zg);
// Serial.print(" CX=");
// Serial.print(counterX);
// Serial.print(" CY=");
// Serial.print(counterY);
// Serial.print(" CZ=");
// Serial.println(counterZ);
}
void Clear() {
//clear all counters
counterX = 0;
counterx = 0;
counterY = 0;
countery = 0;
counterZ = 0;
counterz = 0;
}
void white() {
//white color
digitalWrite(ledx, 1);
digitalWrite(ledy, 1);
digitalWrite(ledz, 1);
//read the acc of Z
Wire.beginTransmission(ADXAddress);
Wire.write(Register_Z0);
Wire.write(Register_Z1);
Wire.endTransmission();
Wire.requestFrom(ADXAddress, 2);
if (Wire.available() <= 2);
{
Z0 = Wire.read();
Z1 = Wire.read();
Z1 = Z1 << 8;
Zg = Z0 + Z1;
}
if (Zg >= 500 || Zg <= -500) {
counterz++;
if (counterz == 1) {
MsTimer2::set(500, Clear);
MsTimer2::start();
}
}
//if counterZ is more than 140, close the trig state of Z and go back to the main function
if (counterz >= 140) {
stateZ = !stateZ;
return;
}
// Serial.print("Z=");
// Serial.print(Zg);
// Serial.print(" CZ=");
// Serial.println(counterz);
}
void following() {
//跟随姿态变色的程序
int xfollow, yfollow, zfollow;
Wire.beginTransmission(ADXAddress);
Wire.write(Register_X0);
Wire.write(Register_X1);
Wire.endTransmission();
Wire.requestFrom(ADXAddress, 2);
if (Wire.available() <= 2);
{
X0 = Wire.read();
X1 = Wire.read();
X1 = X1 << 8;
Xg = X0 + X1;
}
Wire.beginTransmission(ADXAddress);
Wire.write(Register_Y0);
Wire.write(Register_Y1);
Wire.endTransmission();
Wire.requestFrom(ADXAddress, 2);
if (Wire.available() <= 2);
{
Y0 = Wire.read();
Y1 = Wire.read();
Y1 = Y1 << 8;
Yg = Y0 + Y1;
}
Wire.beginTransmission(ADXAddress);
Wire.write(Register_Z0);
Wire.write(Register_Z1);
Wire.endTransmission();
Wire.requestFrom(ADXAddress, 2);
if (Wire.available() <= 2);
{
Z0 = Wire.read();
Z1 = Wire.read();
Z1 = Z1 << 8;
Zg = Z0 + Z1;
}
//keep the color steady by contraining the value of X,Z. Y is used to exit
Xg = constrain(Xg, -272, 272);
// Yg = constrain(Yg, -272, 272);
Zg = constrain(Zg, -272, 272);
xfollow = map(Xg, -272, 272, 5, 250);
analogWrite(ledx, xfollow);
yfollow = map(Yg, -290, 290, 5, 250);
analogWrite(ledy, yfollow);
zfollow = map(Zg, -272, 272, 5, 250);
analogWrite(ledz, zfollow);
//keep the color steady by contraining the value
xfollow = constrain(xfollow, 1, 255);
yfollow = constrain(yfollow, 1, 255);
zfollow = constrain(zfollow, 1, 255);
if (Yg >= 500 || Yg <= -500) {
countery++;
if (countery == 1) {
MsTimer2::set(500, Clear);
MsTimer2::start();
}
}
if (countery >= 40 ) {
stateY = !stateY;
return;
}
// Serial.print("Y=");
// Serial.print(Yg);
// Serial.print(" CY=");
// Serial.println(countery);
}
void fading() {
//auto-chaning color
analogWrite(ledx, valx);
analogWrite(ledy, valy);
analogWrite(ledz, valz);
valx = valx + fadeAmount1;
valy = valy + fadeAmount2;
valz = valz + fadeAmount3;
if (valx <= 4 || valx >= 252) {
fadeAmount1 = -fadeAmount1 ;
}
if (valy <= 7 || valy >= 249) {
fadeAmount2 = -fadeAmount2 ;
}
if (valz <= 10 || valz >= 246) {
fadeAmount3 = -fadeAmount3 ;
}
delay(90);
Wire.beginTransmission(ADXAddress);
Wire.write(Register_X0);
Wire.write(Register_X1);
Wire.endTransmission();
Wire.requestFrom(ADXAddress, 2);
if (Wire.available() <= 2);
{
X0 = Wire.read();
X1 = Wire.read();
X1 = X1 << 8;
Xg = X0 + X1;
}
if (Xg >= 500 || Xg <= -500) {
counterx++;
if (counterx == 1) {
MsTimer2::set(500, Clear);
MsTimer2::start();
}
}
if (counterx >= 2) {
stateX = !stateX;
return;
}
// Serial.print("X=");
// Serial.print(Xg);
// Serial.print(" CX=");
// Serial.println(counterx);