After some talk, we decided to present a LED cube controlled by a calculator on this year's Maker Faire. The idea is to send the LED data through the link port as serial data and decode it with a pair of shift registers. This enables a wide range of possibilities, such as a simple GUI for users to control the LED cube with the calculator, pre-programmed animations and potentially more. Any brainstorming on the subject is welcome.
The current plan is that Kerm will assemble (or already assembled?) a LED cube, and will post the hardware specifications here. If I can replicate it with the hardware I have on hand and feel like I am up to the challenge, I will then build a similar cube for testing, and use the Axe Parser to implement an interactive demonstration program for visitors to try out at our booth.
I already have an Arduino program to display animations in a relatively simple-to-input format, which I believe I can mostly port to Axe.
The animation format is as follows:
Every animation is in a separate header file. This is probably not strictly necessary, but I found it to be useful fro readability. The animation data files are #include'd in the main program. A sample animation file with two frames:
Code:
Here we go for the actual code and animations:
LED_Cube.ino (main file)
Code:
Cube_Driver.ino (the implementation of the "framework")
Code:
A1_RotateY.h (animation 1)
Code:
A2_RotateX.h (animation 2)
Code:
A3_MiddleLayer.h (animation 3)
Code:
A4_Jump.h (animation 4)
Code:
A5_MakeLine.h (animation 5)
Code:
A6_DrawLayers.h (animation 6)
Code:
A7_MoveToMiddleLayer.h (animation 7)
Code:
The current plan is that Kerm will assemble (or already assembled?) a LED cube, and will post the hardware specifications here. If I can replicate it with the hardware I have on hand and feel like I am up to the challenge, I will then build a similar cube for testing, and use the Axe Parser to implement an interactive demonstration program for visitors to try out at our booth.
I already have an Arduino program to display animations in a relatively simple-to-input format, which I believe I can mostly port to Axe.
The animation format is as follows:
Every animation is in a separate header file. This is probably not strictly necessary, but I found it to be useful fro readability. The animation data files are #include'd in the main program. A sample animation file with two frames:
Code:
// the file contains a byte with the number of frames an array with the duration for every frame (in ms) and an array with the animation data itself
// the array lengths must match the specified size
// I chose to name the variables as size1/duration1/animation1, size2/duration2/animation2, ...
extern const byte size1 = 2;
// 2 frames
extern const int duration1 = {
200, // 0
100, // 1
}
// this array would show frame 0 for 200 ms and frame 1 for 100 ms
// the animation data itself is an array of 2D arrays
// every 2D array represents a frame, and they are shown in order
extern const byte animation1[][9][3] = {
{ // 0
{1, 1, 1}, {0, 1, 0}, {0, 0, 0},
{1, 1, 1}, {1, 1, 1}, {0, 1, 0},
{1, 1, 1}, {0, 1, 0}, {0, 0, 0}
},
{ // 1
{0, 0, 0}, {0, 1, 0}, {0, 0, 0},
{0, 1, 0}, {1, 1, 1}, {0, 1, 0},
{0, 0, 0}, {0, 1, 0}, {0, 0, 0}
},
}
// with this combination of whitespace, the frames form three squares
// the left square corresponds with the bottom layer, the middle one with the middle layer and the right one with the top layer
// a 0 means the LED is off, a 1 means the LED is on
// this animation would show a pyramid for 200 ms and a diamond for 100 ms before ending
Here we go for the actual code and animations:
LED_Cube.ino (main file)
Code:
// all animation files must be included
#include "A1_RotateY.h"
#include "A2_RotateX.h"
#include "A3_HideMiddleLayer.h"
#include "A4_Jump.h"
#include "A5_MakeLine.h"
#include "A6_DrawLayers.h"
#include "A7_MoveToMiddleLayer.h"
void setup() {
// initialization "hidden" in function
setupPins();
}
void loop() {
// play all animations in order, loop when done
// RotateY
// rotates a plane along the Y axis
dispAnimation(animation1, duration1, 10, size1);
// show middle layer for some extra time for smooth transition between animations
// frame is already present in animation, extracted individually to save memory
dispFrame(animation1[0], 500);
// RotateX
// rotates a plane along the X axis
dispAnimation(animation2, duration2, 10, size2);
// HideMiddleLayer
// transition animation - smoothly turns off LEDs in middle layer
dispAnimation(animation3, duration3, 1, size3);
// Jump
// "jumps" single lit LED around
dispAnimation(animation4, duration4, 5, size4);
// MakeLine
// transition animation - creates a line from single lit LED
dispAnimation(animation5, duration5, 1, size5);
// DrawLayers
// gradually lights up various layers
dispAnimation(animation6, duration6, 5, size6);
// MoveToMiddleLayer
// transition animation - moves layer from the bottom to the middle
dispAnimation(animation7, duration7, 1, size7);
}
Cube_Driver.ino (the implementation of the "framework")
Code:
// Wiring:
// 3 LEDs linked at the anodes make up a column, 9 in total
// 9 LEDs linked at the cathodes make up a layer, 3 in total
// column anodes are connected to digital pins 2 - 10 and set HIGH to turn on the column
// layer cathodes are connected to GND through transistors as low side switches
// the transistor bases are connected to digital pins 11 - 13 and set to HIGH to turn on the layer
// single use initialization function
void setupPins() {
for (int i = 2; i <= 13; i++) {
pinMode(i, OUTPUT);
digitalWrite(i, LOW);
}
}
// play an animation given an array of frames, durations, the number of times to play the animation and the number of frames
void dispAnimation(byte animationData[][9][3], int aDuration[], byte aCount[], byte aSize) {
// for loop repeats animation for the specified number of times
for (byte count = 0; count < aCount; count++) {
// for loop shows every frame in the data array
for (byte i = 0; i < aSize; i++) {
dispFrame(animationData[i], aDuration[i]);
}
}
}
// display frame given array of LED states and duration in ms
// displaying a frame once takes 1 ms, duration directly translates to number of times frame is displayed
void dispFrame(byte frame[9][3], int count) {
// map 0, 1 and 2 to the pins for the transistor bases
// they were not connected in order
const byte layPins[3] = {12, 13, 11};
// for loop repeats frame for the specified time
for (int i = 0; i < count; i++) {
// LEDs are wired as a matrix -> not every LED can be accessed individually
// show frame layer by layer to light up any combination of LEDs
for (byte lay = 0; lay < 3; lay++) {
// cache layer pin, probably redundant
byte layPin = layPins[lay];
// activate layer
digitalWrite(layPin, HIGH);
// extract LED states from frame data array, activate/deactivate columns accordingly
digitalWrite( 4, frame[0 + lay][0]); // pin 4 = col 0
digitalWrite( 3, frame[0 + lay][1]); // pin 3 = col 1
digitalWrite( 2, frame[0 + lay][2]); // pin 2 = col 2
digitalWrite( 9, frame[3 + lay][0]); // pin 9 = col 3
digitalWrite(10, frame[3 + lay][1]); // pin 10 = col 4
digitalWrite( 5, frame[3 + lay][2]); // pin 5 = col 5
digitalWrite( 6, frame[6 + lay][0]); // pin 6 = col 6
digitalWrite( 7, frame[6 + lay][1]); // pin 7 = col 7
digitalWrite( 8, frame[6 + lay][2]); // pin 8 = col 8
// 3 layers, 1 ms per frame = 1/3 m/s per frame and layer
delayMicroseconds(333);
// deactivate layer after done displaying
digitalWrite(layPin, LOW);
}
}
}
A1_RotateY.h (animation 1)
Code:
// number of frames
extern const byte size1 = 8;
// duration for every frame
extern const int duration1[] = {
100, // 0
100, // 1
100, // 2
100, // 3
100, // 4
100, // 5
100, // 6
100, // 7
};
// array of frames
extern const byte animation1[][9][3] = {
{ // 0
{0, 0, 0}, {1, 1, 1}, {0, 0, 0},
{0, 0, 0}, {1, 1, 1}, {0, 0, 0},
{0, 0, 0}, {1, 1, 1}, {0, 0, 0}
},
{ // 1
{1, 0, 0}, {0, 1, 0}, {0, 0, 1},
{1, 0, 0}, {0, 1, 0}, {0, 0, 1},
{1, 0, 0}, {0, 1, 0}, {0, 0, 1}
},
{ // 2
{0, 1, 0}, {0, 1, 0}, {0, 1, 0},
{0, 1, 0}, {0, 1, 0}, {0, 1, 0},
{0, 1, 0}, {0, 1, 0}, {0, 1, 0}
},
{ // 3
{0, 0, 1}, {0, 1, 0}, {1, 0, 0},
{0, 0, 1}, {0, 1, 0}, {1, 0, 0},
{0, 0, 1}, {0, 1, 0}, {1, 0, 0}
},
{ // 4
{0, 0, 0}, {1, 1, 1}, {0, 0, 0},
{0, 0, 0}, {1, 1, 1}, {0, 0, 0},
{0, 0, 0}, {1, 1, 1}, {0, 0, 0}
},
{ // 5
{1, 0, 0}, {0, 1, 0}, {0, 0, 1},
{1, 0, 0}, {0, 1, 0}, {0, 0, 1},
{1, 0, 0}, {0, 1, 0}, {0, 0, 1}
},
{ // 6
{0, 1, 0}, {0, 1, 0}, {0, 1, 0},
{0, 1, 0}, {0, 1, 0}, {0, 1, 0},
{0, 1, 0}, {0, 1, 0}, {0, 1, 0}
},
{ // 7
{0, 0, 1}, {0, 1, 0}, {1, 0, 0},
{0, 0, 1}, {0, 1, 0}, {1, 0, 0},
{0, 0, 1}, {0, 1, 0}, {1, 0, 0}
},
};
A2_RotateX.h (animation 2)
Code:
// number of frames
extern const byte size2 = 8;
// duration for every frame
extern const int duration2[] = {
100, // 0
100, // 1
100, // 2
100, // 3
100, // 4
100, // 5
100, // 6
100, // 7
};
// array of frames
extern const byte animation2[][9][3] = {
{ // 0
{0, 0, 0}, {1, 1, 1}, {0, 0, 0},
{0, 0, 0}, {1, 1, 1}, {0, 0, 0},
{0, 0, 0}, {1, 1, 1}, {0, 0, 0}
},
{ // 1
{1, 1, 1}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {1, 1, 1}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {1, 1, 1}
},
{ // 2
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{1, 1, 1}, {1, 1, 1}, {1, 1, 1},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}
},
{ // 3
{0, 0, 0}, {0, 0, 0}, {1, 1, 1},
{0, 0, 0}, {1, 1, 1}, {0, 0, 0},
{1, 1, 1}, {0, 0, 0}, {0, 0, 0}
},
{ // 4
{0, 0, 0}, {1, 1, 1}, {0, 0, 0},
{0, 0, 0}, {1, 1, 1}, {0, 0, 0},
{0, 0, 0}, {1, 1, 1}, {0, 0, 0}
},
{ // 5
{1, 1, 1}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {1, 1, 1}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {1, 1, 1}
},
{ // 6
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{1, 1, 1}, {1, 1, 1}, {1, 1, 1},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}
},
{ // 7
{0, 0, 0}, {0, 0, 0}, {1, 1, 1},
{0, 0, 0}, {1, 1, 1}, {0, 0, 0},
{1, 1, 1}, {0, 0, 0}, {0, 0, 0}
},
};
A3_MiddleLayer.h (animation 3)
Code:
// number of frames
extern const byte size3 = 6;
// duration for every frame
extern const int duration3[] = {
500, // 0
100, // 1
100, // 2
100, // 3
100, // 4
500, // 5
};
// array of frames
extern const byte animation3[][9][3] = {
{ // 0
{0, 0, 0}, {1, 1, 1}, {0, 0, 0},
{0, 0, 0}, {1, 1, 1}, {0, 0, 0},
{0, 0, 0}, {1, 1, 1}, {0, 0, 0}
},
{ // 1
{0, 0, 0}, {0, 1, 1}, {0, 0, 0},
{0, 0, 0}, {1, 1, 1}, {0, 0, 0},
{0, 0, 0}, {1, 1, 0}, {0, 0, 0}
},
{ // 2
{0, 0, 0}, {0, 0, 1}, {0, 0, 0},
{0, 0, 0}, {1, 1, 1}, {0, 0, 0},
{0, 0, 0}, {1, 0, 0}, {0, 0, 0}
},
{ // 3
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {1, 1, 1}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}
},
{ // 4
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 1, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}
},
{ // 5
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}
},
};
A4_Jump.h (animation 4)
Code:
// number of frames
extern const byte size4 = 15;
// duration for every frame
extern const int duration4[] = {
200, // 0
100, // 1
300, // 2
100, // 3
300, // 4
100, // 5
300, // 6
100, // 7
300, // 8
100, // 9
300, // 10
100, // 11
300, // 12
100, // 13
100, // 14
};
// array of frames
extern const byte animation4[][9][3] = {
{ // 0
{1, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}
},
{ // 1
{0, 1, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}
},
{ // 2
{0, 0, 1}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}
},
{ // 3
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 1, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}
},
{ // 4
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {1, 0, 0}
},
{ // 5
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {1, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}
},
{ // 6
{0, 0, 0}, {0, 0, 0}, {1, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}
},
{ // 7
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 1, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}
},
{ // 8
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 1}
},
{ // 9
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{1, 0, 0}, {0, 1, 0}, {0, 0, 0}
},
{ // 10
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{1, 0, 0}, {0, 0, 0}, {0, 0, 0}
},
{ // 11
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 1, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}
},
{ // 12
{0, 0, 0}, {0, 0, 0}, {0, 0, 1},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}
},
{ // 13
{0, 0, 0}, {0, 1, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}
},
{ // 14
{1, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}
},
};
A5_MakeLine.h (animation 5)
Code:
// number of frames
extern const byte size5 = 4;
// duration for every frame
extern const int duration5[] = {
500, // 0
100, // 1
100, // 2
500, // 3
};
// array of frames
extern const byte animation5[][9][3] = {
{ // 0
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}
},
{ // 1
{1, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}
},
{ // 2
{1, 0, 0}, {0, 0, 0}, {0, 0, 0},
{1, 0, 0}, {0, 0, 0}, {0, 0, 0},
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}
},
{ // 3
{1, 0, 0}, {0, 0, 0}, {0, 0, 0},
{1, 0, 0}, {0, 0, 0}, {0, 0, 0},
{1, 0, 0}, {0, 0, 0}, {0, 0, 0}
},
};
A6_DrawLayers.h (animation 6)
Code:
// number of frames
extern const byte size6 = 16;
// duration for every frame
extern const int duration6[] = {
100, // 0
500, // 1
100, // 2
500, // 3
100, // 4
500, // 5
100, // 6
500, // 7
100, // 8
500, // 9
100, // 10
500, // 11
100, // 12
500, // 13
100, // 14
500, // 15
};
// array of frames
extern const byte animation6[][9][3] = {
{ // 0
{1, 0, 0}, {1, 0, 0}, {0, 0, 0},
{1, 0, 0}, {1, 0, 0}, {0, 0, 0},
{1, 0, 0}, {1, 0, 0}, {0, 0, 0}
},
{ // 1
{1, 0, 0}, {1, 0, 0}, {1, 0, 0},
{1, 0, 0}, {1, 0, 0}, {1, 0, 0},
{1, 0, 0}, {1, 0, 0}, {1, 0, 0}
},
{ // 2
{0, 0, 0}, {1, 0, 0}, {1, 0, 0},
{0, 0, 0}, {1, 0, 0}, {1, 0, 0},
{0, 0, 0}, {1, 0, 0}, {1, 0, 0}
},
{ // 3
{0, 0, 0}, {0, 0, 0}, {1, 0, 0},
{0, 0, 0}, {0, 0, 0}, {1, 0, 0},
{0, 0, 0}, {0, 0, 0}, {1, 0, 0}
},
{ // 4
{0, 0, 0}, {0, 0, 0}, {1, 1, 0},
{0, 0, 0}, {0, 0, 0}, {1, 1, 0},
{0, 0, 0}, {0, 0, 0}, {1, 1, 0}
},
{ // 5
{0, 0, 0}, {0, 0, 0}, {1, 1, 1},
{0, 0, 0}, {0, 0, 0}, {1, 1, 1},
{0, 0, 0}, {0, 0, 0}, {1, 1, 1}
},
{ // 6
{0, 0, 0}, {0, 0, 0}, {0, 1, 1},
{0, 0, 0}, {0, 0, 0}, {0, 1, 1},
{0, 0, 0}, {0, 0, 0}, {0, 1, 1}
},
{ // 7
{0, 0, 0}, {0, 0, 0}, {0, 0, 1},
{0, 0, 0}, {0, 0, 0}, {0, 0, 1},
{0, 0, 0}, {0, 0, 0}, {0, 0, 1}
},
{ // 8
{0, 0, 0}, {0, 0, 1}, {0, 0, 1},
{0, 0, 0}, {0, 0, 1}, {0, 0, 1},
{0, 0, 0}, {0, 0, 1}, {0, 0, 1}
},
{ // 9
{0, 0, 1}, {0, 0, 1}, {0, 0, 1},
{0, 0, 1}, {0, 0, 1}, {0, 0, 1},
{0, 0, 1}, {0, 0, 1}, {0, 0, 1}
},
{ // 10
{0, 0, 1}, {0, 0, 1}, {0, 0, 0},
{0, 0, 1}, {0, 0, 1}, {0, 0, 0},
{0, 0, 1}, {0, 0, 1}, {0, 0, 0}
},
{ // 11
{0, 0, 1}, {0, 0, 0}, {0, 0, 0},
{0, 0, 1}, {0, 0, 0}, {0, 0, 0},
{0, 0, 1}, {0, 0, 0}, {0, 0, 0}
},
{ // 12
{0, 1, 1}, {0, 0, 0}, {0, 0, 0},
{0, 1, 1}, {0, 0, 0}, {0, 0, 0},
{0, 1, 1}, {0, 0, 0}, {0, 0, 0}
},
{ // 13
{1, 1, 1}, {0, 0, 0}, {0, 0, 0},
{1, 1, 1}, {0, 0, 0}, {0, 0, 0},
{1, 1, 1}, {0, 0, 0}, {0, 0, 0}
},
{ // 14
{1, 1, 0}, {0, 0, 0}, {0, 0, 0},
{1, 1, 0}, {0, 0, 0}, {0, 0, 0},
{1, 1, 0}, {0, 0, 0}, {0, 0, 0}
},
{ // 15
{1, 0, 0}, {0, 0, 0}, {0, 0, 0},
{1, 0, 0}, {0, 0, 0}, {0, 0, 0},
{1, 0, 0}, {0, 0, 0}, {0, 0, 0}
},
};
A7_MoveToMiddleLayer.h (animation 7)
Code:
// number of frames
extern const byte size7 = 8;
// duration for every frame
extern const int duration7[] = {
100, // 0
100, // 1
500, // 2
100, // 3
100, // 4
100, // 5
100, // 6
500, // 7
};
// array of frames
extern const byte animation7[][9][3] = {
{ // 0
{1, 1, 0}, {0, 0, 0}, {0, 0, 0},
{1, 1, 0}, {0, 0, 0}, {0, 0, 0},
{1, 0, 0}, {0, 0, 0}, {0, 0, 0}
},
{ // 1
{1, 1, 1}, {0, 0, 0}, {0, 0, 0},
{1, 1, 1}, {0, 0, 0}, {0, 0, 0},
{1, 0, 0}, {0, 0, 0}, {0, 0, 0}
},
{ // 2
{1, 1, 1}, {0, 0, 0}, {0, 0, 0},
{1, 1, 1}, {0, 0, 0}, {0, 0, 0},
{1, 1, 1}, {0, 0, 0}, {0, 0, 0}
},
{ // 3
{0, 1, 1}, {1, 0, 0}, {0, 0, 0},
{1, 1, 1}, {0, 0, 0}, {0, 0, 0},
{1, 1, 1}, {0, 0, 0}, {0, 0, 0}
},
{ // 4
{0, 0, 1}, {1, 1, 0}, {0, 0, 0},
{0, 1, 1}, {1, 0, 0}, {0, 0, 0},
{1, 1, 1}, {0, 0, 0}, {0, 0, 0}
},
{ // 5
{0, 0, 0}, {1, 1, 1}, {0, 0, 0},
{0, 0, 1}, {1, 1, 0}, {0, 0, 0},
{0, 1, 1}, {1, 0, 0}, {0, 0, 0}
},
{ // 6
{0, 0, 0}, {1, 1, 1}, {0, 0, 0},
{0, 0, 0}, {1, 1, 1}, {0, 0, 0},
{0, 0, 1}, {1, 1, 0}, {0, 0, 0}
},
{ // 7
{0, 0, 0}, {1, 1, 1}, {0, 0, 0},
{0, 0, 0}, {1, 1, 1}, {0, 0, 0},
{0, 0, 0}, {1, 1, 1}, {0, 0, 0}
},
};