This week, Bre Pettis teams up with Mitch Altman and George Shammas to make a little 3x3x3 cube made of little LED lights that you can program with any kind of animation you like! – Subscribe Link
Update: in the podcast I say you need a yellow purple brown colored resistor (470 Ohm). I need to get my glasses checked because actually you need a yellow purple black (47 Ohm) resistor!
Update 2: It has come to our knowledge that James Clar is the initial creator of the 3D LED Cube. He is a lighting designer that has done many things with technology lighting and his works can be seen at: www.JamesClar.com You can view his patent for the 3D Cube with the wiring schematic at the USPTO patent # 7190328
60 thoughts on “Make a pocket LED cube – Weekend Projects Podcast”
Comments are closed.
ADVERTISEMENT
Join Make: Community Today
Erm…isn’t yellow-purple-brown 470 ohms? Also, the voice-over edit in post was funny. :-)
Still, the thing looks cool. A definite argument for having lots of LEDs lying around…
Neat project but dude, you guys need to switch to decaf. As if the blinky-blinky lights weren’t sufficient to give me a seizure to begin with…
I agree – I like the information, but Bre’s pulsing waving hands and energy can be a little distracting at times..
Love ya, Bre! Keep em’ coming! The projects are great!
neat project,can be used in discos
Quick note, the pdf also specifies a 470 ohm resistor in the “What you’ll need” list.
A very cool project which im planning to make.
I just wonder if its possible to make a bigger matrix than a 3x3x3 one with the miniPOV kit.
Or can i make a matrix with a PIC programmer i buy here (in the netherlands) Because the shipping costs are a bit high for the miniPOV kit to get here.
Sorry if i post this at the wrong place but i couldnt find a forum for this.
I’m glad somebody finally said something about how annoying Bre can be, now I know I’m not crazy. He seems like a great guy but his face in macro gets old :)
I didn’t want to complain about the over-enthusiasm, but the on-camera personalities sometimes make these podcasts seem overly juvenile and a little embarrassing to watch.
I agree with the other comments: good material, sub-optimal presentation.
Is there a fourm for this project? I have a few questions on some of the details that seem to be missing on how to do this project
Nonsense. I *love* the energy level of podcasts. Bre, don’t ever change!
I like Bre and his spasmatic mannerisms. I wonder if he has a hairy chest.
But as was asked before, do we need the mini pov kit?
You can use any microcontroller you have laying around, as long as you can use 12 I/Os on it. I build mine on a 8051 eval board from silicon labs.
I’m going to build this as soon as I can get the minipov kit. Looks like a good place to start.
I want to build a 10×10 like the ones I’ve seen around the net, but no one has posted a good how to complete with schematics, parts list, and code.
Once I have mastered the 3×3, does anyone know how to step this up to a 8×8 or 10×10?
Thanks
I don’t have a POV kit laying around, but I do have an Ardunio. I assembled the cube but I’m trying to work out how to wire it to the board. I’m pretty sure I know how to provide 9 +V to the columns, but I’m sketchy on how to get 3 -V connections out of the board. Any suggestions?
I feel like an idiot asking this, but I don’t understand the wiring. I need 9 positive voltage ports to address each of the 9 LEDs on a layer. And then I need 3 grounds? How do I turn off two ground ports? (I’m using an Arduino.) Do I set them HIGH so there’s no voltage across?
As I type this, I’m thinking the answer is yes.
How are the grounds connected? =/ I know they are common to each layer, but how are the layers connected?
Noob questions from a noob.
The last picture in the PDF shows four wires–one with the 47 ohm resistor–coming out of the processor socket.
What do they connect to? I assume they go to the cathodes. But
(a) Does the one with the resistor connect to somewhere special?
(b) How do I decide which cathodes (or whatever) they connect to?
(c) If I choose which cathodes to connect, can anyone recommend a few to start with?
(d) And why four wires?
Thanks!
Finally figured some things out after searching this sight and some others on this project.
there are 3 grounds.. on the bottom side of the board
from the left most side in pic
left top layer ground
middle left is middle layer ground
right is bottom layer ground
right most wire with resistor is the anode for the 9th column of lights.. there are only 8 connections available topside of board.. Took a while to locate the info but after some searching on this site and others and instructables on this project I found there are a few pics which show this detail with pics and hand drawings.
Would have been nice to have had included in the main pdf for this project.. it would have saved me a few moments of insanity.
Good Luck
Bought the Pov kit, bought some leds.. Made my jig and soldered the 3×3 (9) led sections together.. But before I solder 3 layers together I have a question. there will be (9) connection points at the base of the cube when it is done, there will be 1-2 common ground connections.. With all the anodes connected together(9 columns of 3) and all the cathodes connected together, how do you manage to light up any single led?? Not sure what im missing here.. found some answer in the pdf file, just having a hard time visualizing how it all flows..
taking Noob to a whole new level… :)
ok another IOC (Item of Concern)
the pdf shows 4 connections on the bottom side of the circuit board of the pov kit.. But, it does not say what they are and where they terminate on the other end…..
So…..?
/*
LEDcube
Firmware
for use with ATtiny2313
27-August-07
Distributed under Creative Commons 2.5 — Attib & Share Alike
*/
/*
This test firmware lights up each LED for 1/2 second, starting with the top-front-left corner LED,
and going to the bottom-rear-right corner LED.
*/
/*
to program the ATtiny2313, execute the following two commands:
make ledcube.hex
make program-ledcube
*/
#include // this contains all the IO port definitions // definitions for interrupts // definitions for power-down modes // definitions or keeping constants in program memory
#include
#include
#include
/*
The hardware for this project is as follows:
ATtiny2313 has 20 pins:
pin 1 connects to serial port programming circuitry
pin 2 PD0 – ground for top plane of 3×3 LEDs
pin 3 PD1 – ground for middle plane of 3×3 LEDs
pin 6 PD2 – ground for bottom plane of 3×3 LEDs
pin 7 PD3 – +V for lower-left LED of each plane
pin 10 ground
pin 12 PB0 – +V for upper-right LED of each plane
pin 13 PB1 – +V for upper-middle LED of each plane
pin 14 PB2 – +V for upper-right LED of each plane
pin 15 PB3 – +V for middle-right LED of each plane
pin 16 PB4 – +V for midle-middle LED of each plane
pin 17 PB5 – +V for middle-right LED of each plane — also connects to serial port programming circuitry
pin 18 PB6 – +V for lower-right LED of each plane — also connects to serial port programming circuitry
pin 19 PB7 – +V for lower-middle LED of each plane — also connects to serial port programming circuitry
pin 20 +3v
All other pins are unused
This firmware requires that the clock frequency of the ATtiny
is the default that it is shipped with: 8.0MHz internal oscillator
*/
/*
The C compiler creates code that will transfer all constants into RAM when the microcontroller
resets. Since this firmware has a table (brainwaveTab) that is too large to transfer into RAM,
the C compiler needs to be told to keep it in program memory space. This is accomplished by
the macro PROGMEM (this is used, below, in the definition for the brainwaveTab). Since the
C compiler assumes that constants are in RAM, rather than in program memory, when accessing
the brainwaveTab, we need to use the pgm_read_byte() and pgm_read_dword() macros, and we need
to use the brainwveTab as an address, i.e., precede it with “&”. For example, to access
imageTab[3].topRow0, which is a byte, this is how to do it:
pgm_read_byte( &imageTab[3].topRow0 );
And to access imageTab[3].imageDuration, which is a double-word, this is how to do it:
pgm_read_dword( &imageTab[3].imageDuration );
*/
// table of values for 3x3x3 LEDs
// 0 is off, 1 is on for each LED
// last element must have 0 duration
struct imageElement {
unsigned char topRow0;
unsigned char midRow0;
unsigned char botRow0;
unsigned char topRow1;
unsigned char midRow1;
unsigned char botRow1;
unsigned char topRow2;
unsigned char midRow2;
unsigned char botRow2;
unsigned long int imageDuration; // Duration for this element to be displayed before going to next element (divide by 10,000 to get seconds)
} const imageTab[] PROGMEM = {
// flash cube on and off
{ 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 15000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },
{ 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 15000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },
{ 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 15000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },
// four corners
{ 0b101, 0b000, 0b101, 0b000, 0b010, 0b000, 0b101, 0b000, 0b101, 25000 },
{ 0b000, 0b000, 0b000, 0b000, 0b010, 0b000, 0b000, 0b000, 0b000, 25000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 25000 },
{ 0b101, 0b000, 0b101, 0b000, 0b010, 0b000, 0b101, 0b000, 0b101, 25000 },
{ 0b000, 0b000, 0b000, 0b000, 0b010, 0b000, 0b000, 0b000, 0b000, 25000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 25000 },
// makezine code
{ 0b000, 0b000, 0b000, 0b000, 0b010, 0b000, 0b000, 0b000, 0b000, 25000 },
{ 0b000, 0b000, 0b000, 0b000, 0b110, 0b110, 0b000, 0b110, 0b110, 15000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 50000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b100, 30000 },
{ 0b000, 0b000, 0b000, 0b000, 0b110, 0b110, 0b000, 0b110, 0b110, 30000 },
{ 0b111, 0b111, 0b111, 0b111, 0b101, 0b111, 0b111, 0b111, 0b111, 30000 },
{ 0b000, 0b000, 0b000, 0b000, 0b110, 0b110, 0b000, 0b110, 0b110, 30000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b100, 30000 },
{ 0b000, 0b000, 0b000, 0b000, 0b110, 0b110, 0b000, 0b110, 0b110, 20000 },
{ 0b111, 0b111, 0b111, 0b111, 0b101, 0b111, 0b111, 0b111, 0b111, 20000 },
{ 0b000, 0b000, 0b000, 0b000, 0b110, 0b110, 0b000, 0b110, 0b110, 20000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b100, 20000 },
{ 0b000, 0b000, 0b000, 0b000, 0b110, 0b110, 0b000, 0b110, 0b110, 20000 },
{ 0b111, 0b111, 0b111, 0b111, 0b101, 0b111, 0b111, 0b111, 0b111, 10000 },
{ 0b000, 0b000, 0b000, 0b000, 0b110, 0b110, 0b000, 0b110, 0b110, 10000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b100, 10000 },
{ 0b000, 0b000, 0b000, 0b000, 0b110, 0b110, 0b000, 0b110, 0b110, 10000 },
{ 0b111, 0b111, 0b111, 0b111, 0b101, 0b111, 0b111, 0b111, 0b111, 10000 },
{ 0b000, 0b000, 0b000, 0b000, 0b110, 0b110, 0b000, 0b110, 0b110, 25000 },
// diamond
{ 0b010, 0b101, 0b010, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },
{ 0b000, 0b000, 0b000, 0b101, 0b000, 0b101, 0b000, 0b000, 0b000, 15000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b010, 0b101, 0b010, 15000 },
{ 0b000, 0b000, 0b000, 0b010, 0b101, 0b010, 0b000, 0b000, 0b000, 15000 },
{ 0b010, 0b101, 0b010, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },
{ 0b000, 0b000, 0b000, 0b101, 0b000, 0b101, 0b000, 0b000, 0b000, 15000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b010, 0b101, 0b010, 15000 },
{ 0b000, 0b000, 0b000, 0b010, 0b101, 0b010, 0b000, 0b000, 0b000, 15000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },
// light up the layers in succession
{ 0b111, 0b111, 0b111, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },
{ 0b000, 0b000, 0b000, 0b111, 0b111, 0b111, 0b000, 0b000, 0b000, 15000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b111, 0b111, 0b111, 15000 },
{ 0b000, 0b000, 0b000, 0b111, 0b111, 0b111, 0b000, 0b000, 0b000, 15000 },
{ 0b111, 0b111, 0b111, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },
{ 0b111, 0b111, 0b111, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },
{ 0b000, 0b000, 0b000, 0b111, 0b111, 0b111, 0b000, 0b000, 0b000, 15000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b111, 0b111, 0b111, 15000 },
{ 0b000, 0b000, 0b000, 0b111, 0b111, 0b111, 0b000, 0b000, 0b000, 15000 },
{ 0b111, 0b111, 0b111, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },
{ 0b111, 0b111, 0b111, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },
{ 0b000, 0b000, 0b000, 0b111, 0b111, 0b111, 0b000, 0b000, 0b000, 15000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b111, 0b111, 0b111, 15000 },
{ 0b000, 0b000, 0b000, 0b111, 0b111, 0b111, 0b000, 0b000, 0b000, 15000 },
{ 0b111, 0b111, 0b111, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 15000 },
{ 0b000, 0b000, 0b111, 0b000, 0b000, 0b111, 0b000, 0b000, 0b111, 15000 },
{ 0b000, 0b111, 0b000, 0b000, 0b111, 0b000, 0b000, 0b111, 0b000, 15000 },
{ 0b111, 0b000, 0b000, 0b111, 0b000, 0b000, 0b111, 0b000, 0b000, 15000 },
{ 0b000, 0b111, 0b000, 0b000, 0b111, 0b000, 0b000, 0b111, 0b000, 15000 },
{ 0b000, 0b000, 0b111, 0b000, 0b000, 0b111, 0b000, 0b000, 0b111, 15000 },
// spin cross plane 1
{ 0b000, 0b010, 0b000, 0b000, 0b111, 0b000, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b100, 0b010, 0b001, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b010, 0b010, 0b010, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b001, 0b010, 0b100, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b000, 0b111, 0b000, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b100, 0b010, 0b001, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b010, 0b010, 0b010, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b001, 0b010, 0b100, 0b000, 0b010, 0b000, 10000 },
// spin cross plane 2
{ 0b000, 0b010, 0b000, 0b000, 0b111, 0b000, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b100, 0b010, 0b001, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b010, 0b010, 0b010, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b001, 0b010, 0b100, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b000, 0b111, 0b000, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b100, 0b010, 0b001, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b010, 0b010, 0b010, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b001, 0b010, 0b100, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b010, 0b010, 0b010, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b100, 0b000, 0b010, 0b010, 0b010, 0b000, 0b001, 0b000, 10000 },
{ 0b000, 0b000, 0b000, 0b010, 0b111, 0b010, 0b000, 0b000, 0b000, 10000 },
{ 0b000, 0b001, 0b000, 0b010, 0b010, 0b010, 0b000, 0b110, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b010, 0b010, 0b010, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b010, 0b010, 0b010, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b100, 0b000, 0b010, 0b010, 0b010, 0b000, 0b001, 0b000, 10000 },
{ 0b000, 0b000, 0b000, 0b010, 0b111, 0b010, 0b000, 0b000, 0b000, 10000 },
{ 0b000, 0b001, 0b000, 0b010, 0b010, 0b010, 0b000, 0b110, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b010, 0b010, 0b010, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b010, 0b010, 0b010, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b100, 0b000, 0b010, 0b010, 0b010, 0b000, 0b001, 0b000, 10000 },
{ 0b000, 0b000, 0b000, 0b010, 0b111, 0b010, 0b000, 0b000, 0b000, 10000 },
{ 0b000, 0b001, 0b000, 0b010, 0b010, 0b010, 0b000, 0b110, 0b000, 10000 },
{ 0b000, 0b010, 0b000, 0b010, 0b010, 0b010, 0b000, 0b010, 0b000, 10000 },
{ 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0b000, 0 }, // this is a dummy element for end of table (duration=0)
};
// This function delays the specified number of 1/10 milliseconds
void delay_one_tenth_ms(unsigned long int ms) {
unsigned long int timer;
const unsigned long int DelayCount=87; // this value was determined by trial and error
while (ms != 0) {
// Toggling PD6 is done here to force the compiler to do this loop, rather than optimize it away
for (timer=0; timer <= DelayCount; timer++) {PIND |= 0b01000000;}; ms--; } } // This function displays a 3x3x3 image by multiplexing through the images for the 3 planes. // The multiplex rate is about 111Hz. // This function also acts as a delay for the Duration specified. void displayImage(int index) { unsigned long int duration = pgm_read_dword( &imageTab[index].imageDuration ); for (int i=0; i<(duration/(90*3*2)); i++) { PORTB |= pgm_read_byte( &imageTab[index].topRow0 ) | (pgm_read_byte( &imageTab[index].midRow0 )<<3 ) | (pgm_read_byte( &imageTab[index].botRow0 )<<6 ); PORTD |= ( ( pgm_read_byte( &imageTab[index].botRow0 ) & 0b100 ) ) << 1; PORTD &= ~(1<
Also found out when I was coding my own animations, that there is definitely a limit or so it seems on how many lines you can enter into the image table.. In order to enter all of my code into the table, I was able to enter some initially, but found after numerous errors that I had to delete some lines of the original image table in order to complete my own.
looks like this:
{ 0b000, 0b000, 0b111, 0b000, 0b000, 0b111, 0b000, 0b000, 0b111, 15000 },
I am wondering if it is possible to write in some for/next loops to repeat certain sections of the image table without having to repeat with all the lines.. might save coding space for additional animations.
You can just copy and paste the above text in the previous post and save it as ledcube.c, and load it to your own cube.
The
is it possible to name my own animation or version of it to something I would like.. The two files given for the cube are ledcube.c and ledcubetest.c..
Is it possible for me to name it mycube.c?
I have modified the original code (image table and added loop) only and saved it as the original file.. Tried to name it to mycube.c, it created the mycube.hex and mycube.c, but recieved an error when trying to run make program-mycube.. I get an error-1 that the file cannot be found. any ideas?
I also created an excel file to copy the image tables into.
I created some headers which helped me to keep track of the columns 1-9.. also created a drawing which showed which leds were connected to which layer and column.. made it so much easier to code the animations because you can see it visually.
Now someone needs to create a point and click coder for this project where all you do is look at a image of the cube and click on the leds you want to light up or turn off for each line in the table and the program generates the table in the correct format… that would be so nice .. if only i could write that program..:) Hint hint…
what would it take to upgrade this to a 4x4x4 cube? Is there
a way to add memory in order to write larger more complex image tables?
And lastly, the image table it self, can the values be named something other than just 0b000? Can it be relevant to the position of the led in the cube so that all the data. I had noticed that when I was making my animations that the last 3 zero’s in 0b000 seem to be in a backwards order.. ex. in order for me to light up a specific led on a layer i noticed that each 0b000 corresponds to 3 specific leds on a given layer, and that the location of the 0b000 in the data entry also corresponds to led layer and location..
So in order to light up just one led i had to count out the leds and try to find its location in the data line and that its location in that bit of data always seemed to be backwards (here is how I had to map it out
0b000, 0b000, 0b111, 0b000, 0b000, 0b111, 0b000, 0b000, 0b111, 15000..
Lets take the first entry in the line: 0b000 (ob(you would think the first zero corresponds to led 1 and second to led 2 and third to led 3 on layer 1), but I found the opposite I found it to be mapped out as 0b321.
0b321, 0b654, 0b987, 0b121110, 0b151413, 0b181716, 0b212019, 0b242322,
0b272625
, 15000
so each one of those maps to a corresponding led and you would just put a 1 in place of the led you want to turn on.
0b321, 0b654, 0b987, are layer 1,
0b121110, 0b151413, 0b181716 are layer 2
0b212019, 0b242322, 0b272625 are layer 3
it would be nice if each entry was like 0b123 instead of 0b321..
is it possible to either loop a line or for/next a line to repeat a given line in image table x number of times before moving to next image line?? what would the entry look like? I am thinking this would definitely conserve table size and allow more variations or animations
Your method of telling everything in this piece of writing is genuinely good, all be capable of without
difficulty be aware of it, Thanks a lot.
You can definitely see уour enthusiasm in the article yoou write.
The sector hopes for even more passionte writers such aas you who аre
not afraid to mention how they believe. At all times folllω уour heart.
Hello! I just wanted to ask if you ever have any trouble with hackers?
My last blog (wordpress) was hacked and I ended up losing a few months of hard
work due to no back up. Do you have any solutions to prevent hackers?
Individuals who are introverts find it more comfortable
to get involved in classroom discussions. And you will not
have to interrupt your work schedule and you can still
have a family life. They join organizations, meet others, and go on dates.