Introduction: Interactive Color-wheel RGB Cube 8x8x8

Picture of Interactive Color-wheel RGB Cube 8x8x8

This is special version of RGB Led Cube 8x8x8, so called "Interactive Color-wheel RGB Cube 8x8x8". Let's see all attached videos to know how it works.

  • Interactive effect: whenever you move led cube in any axis, cube's color will be changed according to color-wheel rule. See DEMO version below.

  • Color-wheel effect: It looks more amazing if we do effects with color-wheel function. For my project, you can see on videos, there are a lot of effects that were collected from many sources, some of them were done by myself.

  • VU meter effect: Read music signal by MSGEQ7 through 3.5mm audio jack.

On the forum, I saw a lot of posts talking about led cube so I just briefly discussed how to do a RGB led cube in the simplest way.

Step 1: Bill of Material

Picture of Bill of Material

With RGB CUBE 8x8x8, we have 512 LED RED, 512 LED GREEN and 512 LED BLUE, so totally we have to control: 512x3 = 1,536 LEDs.

By 4-bit BAM method, we can create 4,096 separated colors (16 ^ 3) for each RGB LED.

For this project, we'll do a lot of soldering works. Let prepare masks, gloves and exhaust fan for health protection.

Step 2: Cube Template & Led Tester

Picture of Cube Template & Led Tester

Print this template drawing out paper, stick by glue to wood, and then drill with diameter 5mm (if using 5mm RGB LED) at the center of each circle. We will have a led cube wood template with 64 holes.

Note: The holes spacing of wood template and LED spacing of cube base printed circuit board is the same. Thus, we can put 3 pins of led into cube base PCB easily.

Make a Led tester with 9V battery, take note that resistor R470 ohm are connected in series between battery and Led.

Step 3: Cube Base PCB

Picture of Cube Base PCB

Distance between 2 LEDs in PCB is 20mm, same as wood template holes spacing.

With this distance, I didn't use any cooper wires or extra zinc wires to connect LED together. I just bend the Led pins and then soldered them easily.

Step 4: Shift Register Board

Picture of Shift Register Board
  • Schematic:

Schematic above is only for one color so we will have totally 3 sets of shift register board like that.

  • PCB:

As shown on shift register board PCBs, we have 3 blocks, each controlling 64 LEDs (R, G, B) -> 8 x 74HC595. These blocks are connected in series so that each time 24 bytes data is shifted out in the following order: BLUE --> GREEN --> RED.

Step 5: Layer Board

Picture of Layer Board

This layer circuit can be used in two options:

  • Select layers through 74HC595.
  • Select layers directly from 8 pins of Arduino Mega 2560.

I used the second option for faster response.

Step 6: Overall Schematic

Picture of Overall Schematic

RGB Led is common anode type, connected in series R100 for every single R, G, B led. Resistor R100 are included on shift register board PCB, located after ULN2803.

Arduino Mega 2560 control 24 x 74HC595 through SPI interface. And cube layer is collected directly from pin 26 ~ 33 of Arduino.

Step 7: Cube Box

Picture of Cube Box

I made a box containing 5V power supply, PCB boards, Arduino Mega 2560. Some switches, push buttons, jack 3.5mm, fan ... were mounted at cube's backside. You can refer to the internet how to make an beautiful acrylic cube.

In my design, I added one small fan & audio jack 3.5mm on the back of box to ventilate power PCB board and make it become VU meter as optional.

For VU meter, we can use MSGEQ7 with PCB design as picture, or, we can use FFT transformation to read audio analog data from 3.5mm jack.

Step 8: Main Program

Main program for RGB LED CUBE 8x8x8

#include
#define latch_pin 4
#define blank_pin 5
#define data_pin 51
#define clock_pin 52
#define layer1 26
#define layer2 27
#define layer3 28
#define layer4 29
#define layer5 30
#define layer6 31
#define layer7 32
#define layer8 33
int layerArray[8] = {layer1, layer2, layer3, layer4, layer5, layer6, layer7, layer8};
int lastAnode;
byte red[4][64];
byte blue[4][64];
byte green[4][64];
#define BAM_RESOLUTION 4
const byte Size_X = 8;
const byte Size_Y = 8;
const byte Size_Z = 8;
int level=0;
int anodeLevel=0;
int BAM_Bit, BAM_Counter=0;
void setup(){
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
SPI.setClockDivider(SPI_CLOCK_DIV2);
noInterrupts();
TCCR1A = B00000000;
TCCR1B = B00001011;
TIMSK1 = B00000010;
OCR1A=30;
pinMode (2, OUTPUT);
pinMode (3, OUTPUT);
pinMode(data_pin, OUTPUT);
pinMode(clock_pin, OUTPUT);
pinMode(layer1, OUTPUT);
pinMode(layer2, OUTPUT);
pinMode(layer3, OUTPUT);
pinMode(layer4, OUTPUT);
pinMode(layer5, OUTPUT);
pinMode(layer6, OUTPUT);
pinMode(layer7, OUTPUT);
pinMode(layer8, OUTPUT);
SPI.begin();
interrupts();
}
void loop()
{
clearfast();
LED(4, 5, 6, 3, 6, 13);
delay(5000);
clearfast();
LED(0,0,0,15,0,0);
delay(5000);
LED(7,0,0,0,15,0);
delay(5000);
LED(7,7,0,0,0,15);
delay(5000);
LED(0,7,0,15,15,0);
delay(5000);
LED(0,7,7,15,0,15);
delay(5000);
LED(7,0,7,0,15,15);
delay(5000);
LED(0,0,7,15,15,15);
delay(5000);
LED(7,7,7,15,9,0);
delay(5000);
}
void LED(int Z, int Y, int X, int R, int G, int B)
{
X = constrain(X, 0, Size_X - 1);
Y = constrain(Y, 0, Size_Y - 1);
Z = constrain(Z, 0, Size_Z - 1);
R = constrain(R, 0, (1 << BAM_RESOLUTION) - 1);
G = constrain(G, 0, (1 << BAM_RESOLUTION) - 1);
B = constrain(B, 0, (1 << BAM_RESOLUTION) - 1);
int WhichByte = int(((Z << 6) + (Y << 3) + X) >> 3);
int WhichBit = ((Z << 6) + (Y << 3) + X) - (WhichByte << 3) ;
for (byte BAM = 0; BAM < BAM_RESOLUTION; BAM++)
{
//*** RED ***
bitWrite(red[BAM][WhichByte], WhichBit, bitRead(R, BAM));
//*** GREEN ***
bitWrite(green[BAM][WhichByte], WhichBit, bitRead(G, BAM));
//*** BLUE ***
bitWrite(blue[BAM][WhichByte], WhichBit, bitRead(B, BAM));
}
}
ISR(TIMER1_COMPA_vect)
{
PORTE |= 1<
if(BAM_Counter==8)
BAM_Bit++;
else
if(BAM_Counter==24)
BAM_Bit++;
else
if(BAM_Counter==56)
BAM_Bit++;
BAM_Counter++;
switch (BAM_Bit)
{
case 0:
//Red
mySPI(red[0][level + 0]);
mySPI(red[0][level + 1]);
mySPI(red[0][level + 2]);
mySPI(red[0][level + 3]);
mySPI(red[0][level + 4]);
mySPI(red[0][level + 5]);
mySPI(red[0][level + 6]);
mySPI(red[0][level + 7]);
//Green
mySPI(green[0][level + 0]);
mySPI(green[0][level + 1]);
mySPI(green[0][level + 2]);
mySPI(green[0][level + 3]);
mySPI(green[0][level + 4]);
mySPI(green[0][level + 5]);
mySPI(green[0][level + 6]);
mySPI(green[0][level + 7]);
//Blue
mySPI(blue[0][level + 0]);
mySPI(blue[0][level + 1]);
mySPI(blue[0][level + 2]);
mySPI(blue[0][level + 3]);
mySPI(blue[0][level + 4]);
mySPI(blue[0][level + 5]);
mySPI(blue[0][level + 6]);
mySPI(blue[0][level + 7]);
break;
case 1:
//Red
mySPI(red[1][level + 0]);
mySPI(red[1][level + 1]);
mySPI(red[1][level + 2]);
mySPI(red[1][level + 3]);
mySPI(red[1][level + 4]);
mySPI(red[1][level + 5]);
mySPI(red[1][level + 6]);
mySPI(red[1][level + 7]);
//Green
mySPI(green[1][level + 0]);
mySPI(green[1][level + 1]);
mySPI(green[1][level + 2]);
mySPI(green[1][level + 3]);
mySPI(green[1][level + 4]);
mySPI(green[1][level + 5]);
mySPI(green[1][level + 6]);
mySPI(green[1][level + 7]);
//Blue
mySPI(blue[1][level + 0]);
mySPI(blue[1][level + 1]);
mySPI(blue[1][level + 2]);
mySPI(blue[1][level + 3]);
mySPI(blue[1][level + 4]);
mySPI(blue[1][level + 5]);
mySPI(blue[1][level + 6]);
mySPI(blue[1][level + 7]);
break;
case 2:
//Red
mySPI(red[2][level + 0]);
mySPI(red[2][level + 1]);
mySPI(red[2][level + 2]);
mySPI(red[2][level + 3]);
mySPI(red[2][level + 4]);
mySPI(red[2][level + 5]);
mySPI(red[2][level + 6]);
mySPI(red[2][level + 7]);
//Green
mySPI(green[2][level + 0]);
mySPI(green[2][level + 1]);
mySPI(green[2][level + 2]);
mySPI(green[2][level + 3]);
mySPI(green[2][level + 4]);
mySPI(green[2][level + 5]);
mySPI(green[2][level + 6]);
mySPI(green[2][level + 7]);
//Blue
mySPI(blue[2][level + 0]);
mySPI(blue[2][level + 1]);
mySPI(blue[2][level + 2]);
mySPI(blue[2][level + 3]);
mySPI(blue[2][level + 4]);
mySPI(blue[2][level + 5]);
mySPI(blue[2][level + 6]);
mySPI(blue[2][level + 7]);
break;
case 3:
//Red
mySPI(red[3][level + 0]);
mySPI(red[3][level + 1]);
mySPI(red[3][level + 2]);
mySPI(red[3][level + 3]);
mySPI(red[3][level + 4]);
mySPI(red[3][level + 5]);
mySPI(red[3][level + 6]);
mySPI(red[3][level + 7]);
//Green
mySPI(green[3][level + 0]);
mySPI(green[3][level + 1]);
mySPI(green[3][level + 2]);
mySPI(green[3][level + 3]);
mySPI(green[3][level + 4]);
mySPI(green[3][level + 5]);
mySPI(green[3][level + 6]);
mySPI(green[3][level + 7]);
//Blue
mySPI(blue[3][level + 0]);
mySPI(blue[3][level + 1]);
mySPI(blue[3][level + 2]);
mySPI(blue[3][level + 3]);
mySPI(blue[3][level + 4]);
mySPI(blue[3][level + 5]);
mySPI(blue[3][level + 6]);
mySPI(blue[3][level + 7]);
if(BAM_Counter==120)
{
BAM_Counter=0;
BAM_Bit=0;
}
break;
}
lastAnode = (anodeLevel-1);
if (anodeLevel == 0) { lastAnode = 7; }
digitalWrite(layerArray[lastAnode], LOW);
digitalWrite(layerArray[anodeLevel], HIGH);
PORTE |= 1<
PORTE &= ~(1<
delayMicroseconds(3);
PORTE &= ~(1<
//delayMicroseconds(3);
anodeLevel++;
level = level+8;
if(anodeLevel==8)
anodeLevel=0;
if(level==64)
level=0;
pinMode(blank_pin, OUTPUT);
}
void clearfast ()
{
for (unsigned char j=0; j<64; j++)
{
red[0][j] = 0;
red[1][j] = 0;
red[2][j] = 0;
red[3][j] = 0;
green[0][j] = 0;
green[1][j] = 0;
green[2][j] = 0;
green[3][j] = 0;
blue[0][j] = 0;
blue[1][j] = 0;
blue[2][j] = 0;
blue[3][j] = 0;
}
}
inline static uint8_t mySPI(uint8_t mydata){
SPDR = mydata;
asm volatile("nop");
asm volatile("nop");
}

    Step 9: Bit Angle Modulation

    Picture of Bit Angle Modulation

    About B.A.M, you can check my topic: https://www.instructables.com/id/BI-COLORS-MATRIX-...

    Or refer to two amazing websites:

    http://www.kevindarrah.com/?cat=99.

    http://www.batsocks.co.uk/readme/art_bcm_3.htm.

    Example with command LED(4, 5, 6, 3, 6, 13), we can see conversion from actual 3D dimension to program coordinates "Byte" & "Bit ", as well as, the mix colors on pictures.

    Step 10: Color-wheel and Interactive Program

    Picture of Color-wheel and Interactive Program

    Refer from Nick Schulze: http://www.hownottoengineer.com/projects/rgb-led-c..., I did some modifications on his color-wheel program to match with my color template as follows:

    • From:
    array[phase] = {red, green, blue};
    • To:
    RED[phase] = red;
    GREEN[phase] = green;
    BLUE[phase] = blue;
    
    • Get color from color-wheel function
    void get_colour(int16_t p, uint8_t *R_colorwheel, uint8_t *G_colorwheel, uint8_t *B_colorwheel){
      if (p >= COLOUR_WHEEL_LENGTH)
        p -= COLOUR_WHEEL_LENGTH;
      *R_colorwheel = RED[p];
      *G_colorwheel = GREEN[p];
      *B_colorwheel = BLUE[p];
    }

    For MPU-6050, you can refer to my previous project: https://www.instructables.com/id/2-Wheel-Self-Bala...

    In my demo video, I took three values yaw, pitch, roll from MPU-6050 and input them to color-wheel function to get red, green & blue color for Led. K1, K2, K3 is converted coefficients from yaw, pitch, roll to color-wheel position. Parameter "COLOUR_WHEEL_LENGTH", in my case, is 256.

    get_colour(K1*pitch + K2*roll + K3*yaw, &RED, &GREEN, &BLUE);
    fillCube(RED, GREEN, BLUE);
    void fillCube(byte R, byte G, byte B){
    for (byte z=0; z<8; z++){
        for (byte x=0; x<8; x++){
          for (byte y=0; y<8; y++){
            LED(z, y, x, R, G, B);}}}}

    Step 11: RGB Led Cube Pictures

    Picture of RGB Led Cube Pictures

    Some pictures for my cube project.

    Step 12: More RGB Led Cube Videos

    More videos for my led cube project:

    Finally, I would like to say a big thanks to Kevin Darrah, Nick Schulze, SuperTech-IT with the best references about RGB led cube.

    Comments

    nhutnhutnhut (author)2018-01-14

    Nice!

    JuddW1 (author)2018-01-12

    Would you be willing to make the pcb boards and sell to me to make onw led cube?

    tuenhidiy (author)JuddW12018-01-13

    I don't have time to do it right now. Whenever possible, I will contact you. Thanks for being interested in my project.

    NielsR2 (author)2018-01-13

    Happy that you got Kevin Darrah with in your THANKS

    tuenhidiy (author)NielsR22018-01-13

    I just did what I had to :-)

    4DIYers (author)2018-01-12

    That is really cool!

    tuenhidiy (author)4DIYers2018-01-12

    I’m glad you liked it!

    AZBDaniel365 (author)2018-01-11

    Do you have any more Details on how you etch the PCB board design?

    tuenhidiy (author)AZBDaniel3652018-01-11

    During etching these PCBs, I didn't take any photos. Generally, I used Toner Transfer Method with clothes iron & Ferrous Chloride. It is more difficult when we etch double sided - cooper clad boards. So after ironing one side of double-sided copper board (TOP), I drilled some holes then put some pins, like led pins or small wires... through PCB, to get the alignment of opposite side (BOTTOM).

    inconceivable1 (author)2018-01-08

    man led cubs are cool!

    tuenhidiy (author)inconceivable12018-01-09

    Thanks. Your projects are also awesome, too!

    inconceivable1 (author)tuenhidiy2018-01-09

    Not as cool as yours!

    nebloid (author)2018-01-08

    Brilliant job. Well done

    tuenhidiy (author)nebloid2018-01-08

    Thanks!

    About This Instructable

    6,895views

    123favorites

    License:

    Bio: PLC, Arduino - Do it yourself project
    More by tuenhidiy:Interactive Color-wheel RGB Cube 8x8x8BI-COLORS MATRIX 32x32 SHOWING 256 COLORS WITH GIF PICTURES2 Wheel Self Balancing Robot From Broken Toy Car
    Add instructable to: