Intro: Self-Contained 7x7x7 LED Cube
LED cubes are true 3D displays that work by lighting up points in a 3D lattice of LEDs.
On the 3D display you can produce some truly mesmerizing animations. This Instructable will walk you through creating an LED cube for yourself that is completely self-contained and powered by an Arduino Mega. Once you have it programmed, all you have to do is plug it into the wall and it will display whatever you tell it to! This cube avoids the complication of multiplexers and instead uses an Arduino Mega to directly control transistor circuits.
Without further ado, here's a video of the cube in action:
(Although there are limitations to taking a 2D video of a 3D display)
We'll start by making the physical cube and then turn to programming it.
Besides being for fun, this project is an entry for the Make-to-Learn, Lighting, and Epilog Challenge V Contests. I would really appreciate your vote!
**Please click on the orange vote ribbon in the upper right-hand corner of this page if you enjoy this Instructable.**
What would you do if you were to win the Epilog Zing Laser?
My high school got an Epilog Laser this year, and on it I had my first experience using a laser cutter. I was immediately struck by how effective it was at turning designs into reality.
I first used it last December to cut ornate snowflake Christmas ornaments out of acrylic and wood, some of which are pictured in photo 2 on step 12. Not only did it inspire me to teach myself Illustrator, but the results were delightful, and I hope to share the process in a future Instructable. I went on to use the laser cutter to slice Stanford's logo out of sticky felt to decorate the top of my graduation cap, as well as to make acrylic coasters, place mats and the LED layer template the box for this project.
Unfortunately, since I have now graduated, I have lost access to the laser cutter. Laser cutters have the precision to make things that would be essentially impossible to fabricate otherwise, such as the radially symmetric lines on the snowflake ornaments or the pinpoint holes that allow the legs of the LED cube to rest through the lid of the box. If I were to win the Epilog Laser, I would continue to use it to fabricate neat items too delicate and too complex to be made otherwise. In short, I'd love to win the laser to continue my adventure of learning how to create objects with computer controlled machinery.
Below are my answers to the contest Make-to-Learn Youth Contest questions:
What did you make?
I built and programmed a 7x7x7 LED cube from scratch. The description above and the rest of the Instructable tell the story much better than is possible in the short answer to a question. Therefore, please refer to the rest of the Instructable for a more complete answer to this question.
How did you make it?
I was originally inspired by chr's Instructable (here), which first introduced me to LED cubes and how neat they are. I wanted to make a LED cube that was self-contained--that you could just plug into the wall and have run--rather than one that requires input from a computer.
I co-opted the idea of using the legs of the LEDs to form the framework of the lattice that most other LED cubes use, but I came up with the rest of the physical and circuitry design on my own. I built and assembled the whole cube from scratch. Several of the routines that the cube runs were inspired by chr's, but I wrote the code myself or in conjunction with teaching my cousin to program.
The only major change of plans I had while building the cube was to use an Arduino Mega instead of a Due. The Due has the advantage of a higher clock speed, but I realized that I needed 5V for the digital out pins to be able to fully switch the transistors in my circuit. Otherwise, the voltage drop across the LEDs would have been capped at 2.6V rather than the 3.3V they were rated to.
Where did you make it?
I did the majority of the work on this project in the lab and shop at my high school, as this was my second semester project for my Applied Science Research Class. We have a laser cutter in our school lab, which I used to cut out the acrylic box.
I did some of the soldering at home as well.
What did you learn?
A lot! I learned how to used Adobe Illustrator to create things with the laser cutter. In terms of electronics, I came to really understand how transistors work while working on this project, and it was by far the largest and most complex circuit I have ever designed. On the programming side, I learned how to use pointers and memory management to write the C++ code that controls the cube. It was neat to see a real-world application of polymorphism and to learn about the virtual keyword in C++.
More generally, this project taught me the value of building a smaller-scale prototype and the power of digital circuits coupled with a microprocessor.
My cousin was with me while I was programming the cube. He had no programming experience, but I taught him enough that with some help he was able to write two of the eight routines that are displayed on the cube. More on that in the programming section!
Step 1: Skills Required
The skills required for this project are actually pretty minimal; most can be learned along the way, especially given that you have plans to work off of.
That being said, you should really have some experience with basic electronics and also with soldering, since this project requires a lot of that.
My programs should work for you out of the box, but if you want to write your own display routines, some experience with object-oriented programming in C++ (Arduino) would be helpful.
Step 2: How It Works!
In its simplest form, an LED cube is a three dimensional array of lights in space, with each light either on or off at any given moment in time. To achieve complete control over those lights, each LED needs to appear to be controlled individually.
Doing this directly, however, is not feasible. If x is the number of LEDs on each side of the LED cube, we'd need x3 digital output ports to control each LED individually. This might work for smaller cubes, but for larger values of x, this quickly exceeds the number of ports directly available on any standard microcontroller. For this 7x7x7 cube, 343 ports would be needed.
This problem is commonly resolved by flickering through the layers of the LED cube quickly enough to create the illusion of being able to control every LED independently. Let's look at how this would reduce the number of ports needed:
In each colored layer in the photo above, the cathode (to ground) leg of each LED is connected. The anode (voltage in) legs of all the LEDs in each column are also connected. Without going into details yet, assume that the microcontroller can connect and disconnect each column from power and each layer from ground.
To display something on the cube, we would first ground the red layer and apply voltage to the columns we want to turn on. Then we would disconnect everything and repeat the process for the orange layer, this time applying voltage only to the columns of the LEDs we want to light up in that layer.
By quickly flickering through the layers, every layer will appear to be lit at once. The flicker fusion threshold, the rate above which flickering lights appear constant, in humans is about 60Hz, so the cube needs to cycle through every layer at least 60 times per second.
Switching the LEDs in layers and columns makes larger cubes feasible. A total of x2 + x digital outputs are needed to control such a cube: x2 for the columns and x for the layers. Therefore, to build a 7x7x7 cube, 56 ports are needed, rather than 343. The Arduino Mega has 70 pins that can be used as digital I/O ports, leaving 14 ports open for external push button switches to switch the pattern being displayed on the cube.
Step 3: Tools
- Good soldering iron
- Wire stripper
- 2 Pairs of needle-nose pliers
- Eye protection, etc.
Alligator clips and a power supply are handy, as is an ohmmeter for checking connections.
I used a laser cutter to build my acrylic box and to make the template I used for soldering. I'm sure an inventive person could get by without, but the laser cutter was tremendously helpful.
Calipers are also helpful but not necessary.
As always, make sure you know how to safely use a tool before using it.
Step 4: Materials
You'll need the following for this project:
1x Arduino Mega
--The brains of our project
1000x 3mm diffused blue LEDs
**Buy these off of eBay and make sure to get the diffused variety. They'll be
much cheaper that way (~$25), and diffused LEDs have a much better
view angle than normal LEDs.
1x 5V Wall Wart power supply
--This will supply power to the project.
**eBay is a great place to get these. I got a 2A one, but 1A should work just
1x DC female power jack
--Get power from the wall wart
**Make sure the jack size matches the size of the jack on the power supply
you bought. Like here.
8x Momentary pushbutton switches
--User input to switch programs
**I got mine at RadioShack here.
1x Switch rated to at least 1A that mounts through a hole
**I used a DPDT switch, but other kinds would work just fine.
2x Prototype Board
**Get the ones that have some holes already connected. It will save you a
ton of time. I got mine here.
~ Header pins
--For connecting PCBs and for connecting ribbon cable to the Arduino.
**Get a bunch of the male ones and some smaller sockets like those on
6ft 7+ conductor ribbon cable
3ft 35+ conductor ribbon cable
1pkg Adhesive velcro
--Secure boards down inside box
53x 100Ω resistor
53x 560Ω resistor
9x 4.7kΩ resistor
8x 10kΩ resistor
9x TIP31C NPN power transistor
--For switching layers
53x 2N3904 NPN transistor
--For switching columns
~3ft 24 and 22 gauge insulated wire
1x Acrylic Sheet
4x 3" by 1/8" Stainless steel screws with acorn caps
1x 1/8" Particle board
--For soldering template
1 ton Solder
1x Tube of epoxy
2x Male jumper wires
**Could substitute wire and header pins
The total cost should be somewhere around $150.
Step 5: Make a Prototype
It is really worth making a miniature prototype to make sure everything will work as expected.
I built a 2x2x2 cube out of 8 green LEDs that were lying around at school and got it to light up in a spiral pattern. I'm not going to go into detail here, since the methods used to build the prototype are the same as for the main cube.
At the very least, build the prototype to see what you are getting yourself into.
Step 6: Wiring Diagrams
The electrical circuit needs to accomplish three tasks: Providing a stable DC supply, allowing the current-sensitive, digital output pins on the Arduino Mega to switch the relatively high currents needed for the LEDs, and allowing the Arduino to detect when the routine switching buttons are pressed. The circuit diagrams below are broken up to reflect these three different tasks.
For the DC supply itself, I made use of a 5V, 2A wall wart power supply to convert the AC from the wall outlet. When plugged into the wall, it actually provides 5.4V, but the Arduino’s internal voltage regulator is able to bring that voltage down to the 5V it requires. Tests with a variable voltage power supply found that the Arduino Mega continued to function even when only 3.9V was supplied.
The wall wart’s jack plugs into a power port through a hole in the acrylic enclosure. As shown in the second diagram, the leads on the port run to a double pole, double throw switch which allows power to be easy switched off from the outside of the cube without needing to remove the power jack. The power and ground lines then go to power the circuits controlling the LEDs and to the unregulated voltage input and ground pins on the Arduino.
Before discussing the second circuit, it is necessary to explain the choice of LEDs for the cube. I chose 3mm diffused blue LEDs because they are bright, give the appearance of a point light source and have better view angles than non-diffused LEDs. The variety I purchased are designed to drop 3.3V and have a current of 20mA, giving them an effective resistance of 165 Ω.
The transistor circuit that allows the Arduino pins to switch the columns and layers of the cube is significantly more complex. An abbreviated diagram is shown in the first image above. The 5V line from the power circuit provides runs into this circuit. The following circuit is repeated for each column. The 5V first goes through a 100Ω resistor to drop the voltage enough for the LED and to bring it to a low enough level that it can be controlled by the 5V Arduino pin. The current then flows into an NPN transistor, the base of which is controlled by an Arduino output pin protected by a 560Ω resistor.
Current then flows from the emitter of the transistor out to the anodes of the LEDs in that column.
Another NPN transistor controls the grounding of each of the layers. The current flows out of the collective cathode for that layer into the collector of a power NPN transistor. The current through this transistor could equal 20mA*49 = 0.98A, so a power transistor is needed. A 4.7kΩ resistor protects the Arduino pin that controls this transistor. The emitter of the transistor is connected straight to ground.
The final circuit is used for detecting when the pushbutton switches on the exterior of the acrylic case are pressed. The circuit is diagrammed in the last image. When the push button is open, the digital input port is grounded through the resistor. If the pushbutton is pressed, however, the digital input will be at the 5V coming from the Arduino’s voltage regulator. This allows the microcontroller to detect the button being pushed so that it knows when to switch to a different display mode.
Step 7: Laser Cut the Soldering Template
Let's start with the LED lattice.
To solder each layer of the LED lattice, we'll need a 2D template. Measure the shorter leg of your LEDs with a pair of calipers, or failing that, a ruler.
You then want to make a grid of holes spaced exactly that distance from center to center. The holes should hold the LEDs snugly. I used Illustrator and a laser cutter to create the template out of 1/8" particle board, but you could probably do it with a drill press.
Make sure that the holes go all the way through the material to make removing the LEDs easier.
Step 8: Solder Layers
For each layer of the cube, you want to make a perfect 7x7 array of LEDs with their cathodes connected.
I began by inserting LEDs into the template in an L with the cathode leg bent flat against the neighboring LED. The cathodes were then soldered together, and more rows of LEDs were added to begin to form a comb, as starts to be shown in the second picture.
I then added more wires to strengthen the "comb" as shown in the second picture. I used 24 gauge wire to best match the legs of the LEDs. To straighten the wire, simply pull from both ends with pliers and smooth out any imperfections with your fingers. The extra supporting wires were added at the end and center of the comb (not pictured). Be sure not to have any shorts to the anodes of the LEDs.
Finally, carefully poke each LED out from the template by pushing from below with a blunt object.
Repeat this process for all 7 layers.
After you have soldered a layer, it is worth checking it because once it is soldered into the cube, there will be no way of fixing it. Just set your power supply to 5 volts, connect the cathodes to ground through a 100Ω resistor and connect each anode to 5V in turn.
Step 9: Assemble the Cube
The first step in putting the layers together is bending the tips of the anode legs of each LED in the lower layers to hook around the LED above them. Then, wooden spacers were used to prop the next layer in place as the bent anodes were soldered to the base of the anodes on the LEDs above them. The layers were then slid slightly to ensure that each layer was perfectly above the one below it. Repeating this process seven times yielded the 7x7x7 LED lattice.
Trim any protrusions beside the bottom legs of the cube and congratulate yourself on a job well soldered.
Step 10: Solder Ribbon Cable to the Layers
Each layer will eventually need to be wired to the PCB, and ribbon cable is the neatest way to do that. Solder a strip of ribbon cable to the back left corner of the cube with one wire going to each layer, as shown.
The picture was taken from the back of the cube.
Step 11: Solder Circuit Boards
The transistor circuits switching the columns and layers and the resistors for the pushbutton-detection circuits need to be soldered to the circuit boards.
I put 35 of the column circuits on the lower board and 14 on the upper board. 7 transistor circuits for the layers are on the upper board, as are the resistors for the pushbuttons.
Then, solder header pins and sockets to connect ground and power between the boards.
Step 12: Acrylic Box
Now to laser cut the acrylic box!
If you don't have access to a laser cutter, that's okay. It's possible there is one locally, at a TechShop, for example, and online services to order laser cut parts exist. Otherwise, you can likely modify a pre-built enclosure to fit your needs.
Either way, the enclosure will need to have:
--49 Holes for the legs of the LEDs
--Holes to mount the switch
--A hole for the Arduino USB port
--A hole for the power port
--A slot to admit the ribbon cable that grounds the layers
--Holes to bolt the whole thing together
I've attached the Illustrator files I used when I cut the box from 1/8" acrylic. The bottom of the box was identical to the top, but without any of the holes in the center. The laser beam was fine enough that the kerf does not have to be corrected for. You may have to adjust hole sizes if your components were different sizes from mine.
Once the box is ready, carefully coax the legs of the cube into the top of the box. It helps to start with one side and use a pencil to poke the legs into place.
Carefully epoxy the power port where shown in the image.
Step 13: Wire Everything Together
All the circuits now need to be connected with ribbon cable.
I started by connecting all of the transistor circuits to the Arduino, making sure that the transistors were connected to the Arduino pins in a consistent way. I chose to do it top to bottom, left to right. Then I connected the circuits for the pushbuttons on the circuit board to the Arduino.
The hardest part is soldering the ribbon cable to the header pins going into the Arduino. By far the easiest way to do this is to part the strands of each wire around the top of the header pin and then twist them on the other side, clamping the pin between them.
Then, screw all the switches through the acrylic and solder one side of all the pushbutton switches together. Solder one half of a male jumper wire to that. This wire will plug into a 5V pin on the Arduino to supply power to the pushbutton circuits. Solder each other lead of the pushbuttons to a wire in a strip of ribbon cable.
Next, solder ribbon cable to each leg of the LED lattice underneath the top of the acrylic box. This holds the lattice in place. I soldered across in rows left to right, front to back, for reasons that will become clear later. You can see those cables in image #3.
Things get messy soldering the cube to the circuit boards. Just do it carefully, matching the first transistor circuit you soldered to the first column you soldered, and it will turn out all right. Then, solder the ribbon cable coming from the pushbuttons into the pushbutton circuits on the circuit board.
You're getting close! Finally, solder the leads from the power port to the power switch. Run wire from the switch to power the circuit board and solder half jumper wires so the power can go into the Arduino.
Then, Velcro down the boards inside the box, push all the header pins and jumper wires into their sockets, and screw the box closed. The hardware is done!
Step 14: Software Intro
Now that the hardware is done, let's make the cube come alive!
I've attached a zip file of my whole program. For those who just want to run it, drag the contents of the libraries folder into your Arduino libraries folder, and drag the LED_Cube folder into your Arduino folder. Compile it and run.
You need the latest version of Arduino (1.0.4) to run my program. Otherwise you will get errors that the new and delete operators are not defined.
When you press a button the whole cube will light up, and when you release, a display routine will begin. This might be a firework simulation, or a bouncing ball.
If one or more lights doesn't work on the cube, don't panic. For me, a solder join on the lattice had cracked. Just find the break with an ohmmeter and repair it with the soldering iron.
Step 15: Program Overview
For this program, I tried to loosely follow the Model-View-Controller paradigm. All that means is that I keep the information about the model--information about what the state should be and updating it--separate from the view, which displays that information on the cube. The main Arduino sketch acts as the controller, passing information from the model to the view to be displayed.
We'll be writing a lot of classes to make a clean object-oriented program. Arduino deals with these classes as libraries. Before we get to the main program, I'll talk about a couple of those libraries.
A PushButton deals with getting input from the pushbutton switches on the front of the cube. You tell it what pin the pushbutton circuit is connected to, and then you can ask it whether it has been pressed or released since you last checked it.
A routine object is responsible for calculating what the cube should be displaying each turn. It is repeatedly told to update its state based on the amount of time that has passed since it was last told to update. We can extend Routine and override the update method to make new routines for the cube. Routines also hold a 3D array of booleans that represents the current state of the cube. The routine does not do the actual displaying of the array on the cube. That falls to the CubeView.
A CubeView handles displaying a 3D array of booleans (from the Routine) on the cube. It does this one layer at a time, shifting to the next layer every time you tell it to display.
Now for a high level view of the main program:
The main program keeps around a pointer to the Routine we are currently running. In the loop() we repeatedly tell the current routine to update, copy the new frame the routine has generated into a local variable, and then check to see if there has been any input on the buttons. If any buttons have been pressed, we delete the old routine and replace it with a new one that lights up the whole cube. If a button is released, we delete the old routine and replace it with a new routine that corresponds to that button.
This code is repeatedly interrupted (420 times per second with the current settings) to display the next layer on the cube. Here, we simply pass the last frame we've fully calculated to the CubeView to be displayed. More information about interrupts can be found here. Having the display method interrupt the other code keeps the refresh rate independent of calculation time and prevents flickering.
If you want to take videos of a cube you've built, simply change the #define REFRESH_RATE to something like 240. That will make the cube flash so fast that the camera doesn't pick it up.
More on routines in the next step:
Step 16: Coordinate System
Before we turn to making new extensions of Routine, we need to define a coordinate system. I chose the one pictured above, because it kept the standard, 2D X-Y plane for the column switching, which made thinking about the grid of columns easier for me.
To access the boolean corresponding to the LED at (x,y,z) in a 3D array, we would use cubeModel[x][y][z].
Step 17: AllOn
Just put your .cpp and .h files in a folder in libraries and you can call on them from the main program.
The simplest extension of routine is to turn all the lights on rather than having them all off by default. For this we just set all the coordinates in our cubeModel to true in the constructor.
Step 18: CornerToCorner
The program starts by randomly choosing a vertex of the cube. Every step, the lights advance out from their starting vertex toward the opposing corner. When the light has filled the whole cube, it retreats away from the corner where it started. The routine then repeats with a new random corner.
A simple rule tells the program to light a pixel: If the sum of the x, y and z distances is below a certain threshold, the pixel is lit. All other pixels remain off. The threshold is upped by one each step, and then the process is repeated in reverse to darken the cube.
Step 19: CubeFrame
Again, a relatively simple rule allows us to decide whether a point is on the wire frame cube or not. At least two of the x, y, or z distances from the corner of must either be the current size or the cube or zero. The remaining distance must be less than the size of the cube.
Step 20: Fade
Step 21: Ripple
Step 22: Wave
Step 23: PouringRain
An unlit LED at the top of the cube is randomly chosen to become a drop. This drop then falls until it either hits the bottom of the cube or piles on top of a previously fallen drop. This process is repeated until the cube is full, at which point the routine repeats.
Step 24: BouncingBall
To make this easier, I defined a particle class that simulates physics within some bounds. You initialize the particle with some radius, position, and velocity and tell it whether or not it should bounce. You can also apply acceleration and air resistance to the particle.
This routine just creates a particle with radius 2 at a random position with random velocity, and takes snapshots of its position as it bounces about.
Step 25: Firework
A particle is sent up in the center of the cube. When it gets to z=4, the particle is replaced with a random number of other particles. The particles are sent out with large, random velocities but are subject to a large amount of drag, just like in a real firework.
These particles slide down the sides of the cube, disappearing just before they reach the ground.
Then the process repeats with another firework.
It's neat that you can run something this complicated just off an Arduino.
Step 26: Emission Spectrum
That's it for the actual construction and programming of the cube. You now have a fully functioning and self-contained LED cube that can be powered from a wall outlet!
Out of interest, I performed one test on the LEDs in the cube. Using an emission spectrometer, I measured the intensity of the light being emitted by the blue LEDs at different wavelengths in an otherwise darkened room. The above is the graph of that data. The peak of 468 nm is a function of the bandgap of the LED and is consistant with zinc selenide, indium gallium nitride, and other common blue LED semiconductor materials.
We've confirmed that the LEDs are indeed blue!
Seriously, though, I hope you enjoyed reading about my cube and might be inspired to build one of your own. The 3D visual effects are even more amazing when not confined to to a 2D video.
Again, I would really appreciate your vote for the contests I've entered. If you enjoyed reading, please click on the orange ribbon in the upper right-hand corner.