8x8x8 LED Cube
This is exactly what it sounds like, an awesome flashing cube of LED's. After seeing a 512 LED cube on hackaday I decided that I needed one for myself and went right to ebay to find some cheap LED's. Although 512 LED's seems like a daunting number it only took one weekend to make the control circuit and construct the cube, the code and animations though took a few weeks, maybe coding isn't my thing. I will go through some of the steps and theory here and you can see the results in the video at the end.
Control Circuit
Before I started this project I had never heard of multiplexing, its basically a nice way of breaking up the control of a large number of LED's and tricking the eyes into seeing it all happening simultaneously. In this case all you have to do is load an image onto the bottom layer hold it there for say 5-10 milliseconds, turn it off and load an image onto the next layer for 5-10 milliseconds etc etc, at this speed you will not be able to tell that each layer is being controlled separately. Multiplexing reduced the number of LED's that need controlling at a single time from 512 to 64 LED's + 8 layers, this is still more I/O's than most micro controllers so I found a nice chip that allows me to control as many LED's as a want with only 3 I/O's.The STP16CP LED sink driver receives a serial signal and can sink the cathode of 16 separate LED's to ground, the really nice thing about this chip is that you can run as many as you want in cascade to control say up to 64 LED's + 8 layers. I have included my schematic below, I used the suggested layout from the data sheet except I added a 10uF decoupling capacitor on the power inputs to keep them nice and quiet, the resistors are the current setting resistors I used some high wattage 1k resistors I had laying around. I have 4 chips to control the 64 LED's in each layer and another chip and 8 transistors to control the layers. These chips are designed to sink currents, not to supply them so you have to ensure that all the cathodes (negative leg) of the LED's in a column are connected and the anodes (positive legs) of all the LED's in each layer are joined together and supplied via the transistors.
I am currently using an old PC power supply to power my cube, I will probably never get around to making a more compact power supply but if you decide to make your own remember that this many LED's will draw a decent current, I measured the maximum current drawn from my cube and it was about 700mA that includes the power for the control circuit (this was with multiplexing so if you actually turned all the layers on at once it would be a lot more).
Control Circuit Schematic
Parts List
I have been receiving a lot of questions about parts so the parts I used are listed below. I get all my components from http://au.element14.com who offer next day delivery in Australia or from http://www.jaycar.com.au/, not delivered but usually keep a decent selection of passive and active components in stock. Now I'm not saying you need exactly these components, the capacitors for one are rather expensive and an electrolytic capacitor would do a similar job, but this is what I used and they obviously work.5 x 1k 2W resistors (2W is overkill but I already had them at home) [element14 part# 1417017]
5 x 10uF 35V Tantalum Capacitors (35 V is overkill but I already had a few) [element14 part# 1457591]
8 x BD136 pnp transistors (the BD438 in the schematic should work just fine) [element14 part# 9956263]
5 x STP16CPS05MTR LED sink Driver [element14 part# 1551227]
9 x 8 pin header [jaycar part# HM3418]
As for the board and schematic those who are wondering how you get them, well you make them. I'm not an electrical engineer so my electronics knowledge is limited by what datasheets can tell me, if you read through the STP16CPS05 datasheethttp://www.farnell.com/datasheets/28788.pdf you will see that it gives all the information you need to make the schematic above even a suggested circuit application. I use eagleCad http://www.cadsoftusa.com/ to draw my schematics and layout the boards. Its easy and they offer a free version which is nice, there are tutorials on YouTube but really the only way to get the hang of it is try it out. To make the boards I use the toner transfer method google will throw about a thousand tutorials at you if you type it in, here is a simple one http://www.instructables.com/id/Cheap-and-Easy-Toner-Transfer-for-PCB-Making/.PCB
I layed out the board using eagle, turns out I had to make it double sided to fit all the traces in, double sided boards are a bit tricky with the toner transfer method and I hate soldering vias but it didn't look too bad in the end, a few smudges on the top ground plane where the toner didn't stick and you can see a few wires on the bottom to fix a broken trace and a somehow floating block of my ground plane. If you want the eaglecad files I have uploaded them to my downloads section which you can access via the top menu, but remember these chips are tiny, although you may be able to get ones already soldered to breakout boards if you search hard enough.Control Board Top
Control Board Bottom
CUBE
I found the simplest part of the project constructing the cube, once I had a jig to hold each layer in position and got into a routine it all came together relatively quickly. The first picture is of the first complete later of 64 LED's, the second shows the anode layer in red and the 64 cathode legs in black which will be soldered to the next layer to form the cathode columns. Each layer is held together along one axis using the LED's positive leg and on along the other axis with 8 pieces of wire, the layers are then soldered to each other using each LED's negative legs, the final cube is surprisingly rigid.Once I finished the cube I wired it all up to do some testing before I made a timber box to hide all the wires and circuits, with a few coats of paint the final product came up looking pretty good I think, the most annoying part so far was getting all 64 of the slightly bent legs through the holes in the wooden box.
First Complete Layer
LED Cube
Finished Product
Control
The fist step in control is to figure out how to load data into the STP16CP chips, they have 3 inputs, clock (CLK), data (SDI) and latch (LE). Its pretty simple really you load the data on the data pin, keep the time with the clock pin and set the data which activates the outputs with the latch pin. I didnt find the timing diagrams provided in the data sheet completely obvious initially so ill try and explain it hopefully a bit clearer here. For example if you want to load the byte B11001110 = 0xCE into the first byte register in the first STP16 chip in the cascade the timing diagram below shows the required output for all 3 pins.STP16CP Timing Diagram
SEND BYTE CODE
void CUBE::send_data(char byte_to_send){
for(int i = 0; i < 8; i++){
if(byte_to_send & 0x01<<i){
digitalWrite(SDI, HIGH);
}
digitalWrite(CLK, HIGH);
digitalWrite(SDI,LOW);
digitalWrite(CLK,LOW);
}
}
LATCH CODE
void CUBE::latch(void){
digitalWrite(LE,HIGH);
digitalWrite(LE,LOW);
}
The cascade works by pushing the data to the next byte register each time data is loaded into the first register, this means that the first byte you load will end up in the last byte register. Normally because I have 5 chips, each that have 2 byte registers I would load 10 bytes into the cascade before sending the latch command. The first byte corresponds to the layer command so will only ever have one bit set, the second byte is just zeros because nothing is connected to those pins and the next eight correspond to the image desired on that layer. What I didn't think of when laying out the board was that every second 8-pin header actually needed to be flipped around. You could fix this by soldering the wires on in opposite directions but I still hadn't thought of it by that time so i fixed it by flipping every second byte with the following code. You can see that some basic understanding of binary can be useful for this project, there are plenty of tutes on the Internet for this sort of thing.
Flip Code
char CUBE::flip(char input){
char output = 0x00;
for(int i = 7; i >= 0; i--){
if(input & 0x01 << i){
output |= 0x01 << (7 - i);
}
}
return output;
}
Animations
To animate the cube I first write all the animations onto a 8x8x8 array in C++ on my PC, then I split up the array into 64 bytes (8 bytes per layer) and send the 64 bytes to my arduino which converts them and loads them onto the cube layer by layer. This might mean more computationally demanding code but it makes it a lot easier to visualise the animations as I write them, if I want to turn on the LED at (x,y,z) = (5,3,0) I just set cubeArray[5][3][0] = 1.As I was waiting for my LED's in the mail I started writing and plotting animations in matlab to try and get an idea of how I was going to animate this thing. Matlab is very handy for this sort of thing if a bit slow when it comes to plotting this way, you can see in the short video below that it can help visualise things when you don't have a physical platform.
Wave Animation Simulated in Matlab
Animations Using Functions
Probably the easiest to implement and maybe even the nicest look animations are those based on surface functions such as the wave function in the matlab simulation above. Here I will go through the animation of a 3D sine wave which looks pretty cool on the cube. I start with the function below which plots the surface shown in the figure, to get this onto my cube I need to map the function onto my cube and discretise the continuous function.3D Sine Function and Surface
Because my array representing my cube has a range from 0-7 in each axis you need to map the values of X and Y to a range centered at zero to get a symmetrical result which you can the map back onto the range 0-7 to get the Z position, the simple c++ function below will map a value in a range onto the desired range.
Map Code
double cube::map(double in, double inMin, double inMax, double outMin, double outMax){So to plot the function onto the 8x8x8 array I loop through all 64 X and Y positions, map these values to a range between -PI and PI, then calculate the Z position which will be somewhere in the range -1 to 1. Then I map the Z result back to the range 0-7 and round it off to get a discrete position and set the LED at [X,Y,Z] to on. I have included my code below where size = 8, there are probably other ways of getting the same result but this made sense to me. Of course this only plots one instance of the sine animation, to actually make it move I repeat this code clearing the array at each instance and continuously incrementing the phase between 0 and 2PI.
double out;
out = (in-inMin)/(inMax-inMin)*(outMax-outMin) + outMin;
return out;
}
Sine Code
for(int x = 0; x < size; x++){Here is a video of the 3D sine animation on the cube unfortunately I still haven't found a decent camera to film this with, so the quality is not excellent.
for(int y = 0; y < size; y++){
Z = sin(phase + sqrt(pow(map(x,0,size-1,-PI,PI),2) + pow(map(y,0,size-1,-PI,PI),2)));
Z = round(map(Z,-1,1,0,size-1));
cubeArray[x][y][(int)Z] = 1;
}
}
3D Sine Animation
Equation of a Spiral/Helix
3D waves Equation
Generate Bytes
So now that I have a 3D array filled with an instance of an animation it needs to be broken up into something to send to my arduino. 8 is such a nice number for this sort of thing because there are 8 bits in a byte, so I can separate the array into 64 bytes which makes 512 bits each representing an LED. The image below shows how I split up one layer of the cube, each byte is stored in an array cubeChars. The code I have written for this is also included below.A Layer of Bytes
Generate Chars Code
void cube::genChars(void){
int i = 0;
memset(cubeChars, 0x00, sizeof(cubeChars));
for(int z = 0; z < size; z++){
for(int y = 0; y < size; y++){
for(int x = 0; x << size; x++){
if(cubeArray[x][y][z] == 1){
cubeChars[i] |= 0x01<<((size-1)-x);
}
}
i++;
}
}
}
Aucun commentaire:
Enregistrer un commentaire