Before we start...

This tutorial is not aimed to help you build and set up the electronics for the LED-Cube as there are a lot of these tutorials out there already. Instead we are going to focus on the software and see how Quadrum can be implemented on your cube.

There are two ways to get an animation from the Quadrum editor to the LED-Cube, and as a result this tutorial will be divided into two parts. Since some of the concepts introduced in one section are used in the other, it is recommended to read both the Streaming Animations and Uploading Animations parts even if you are planning on only using one of them.

Download the Quadrum library and editor here. The library's .zip file will have to be imported into the Arduino IDE, if you are unsure of how to do so check this out. The animation editor is not a library and installs like a regular desktop application.

Limitations

The serial library sends each frame in a compressed format when possible at the Arduino's fastest speed setting (115200 bits per second). However this may still not be fast enough for some settings the library allows you to make (for example having RGB enabled with 8 bit resolution on each channel on a 8x8x8 cube). If you are experiencing problems this guide can help you determine if the issues are caused by the serial bandwidth. In general: the smaller the cube size, the smaller the resolution of each color channel and the fewer color channels you have enabled, the faster the serial data will be streamed to the cube.

On top of giving problems with the serial bandwidth, a big cube size combined with large amounts of data for each LED can take up more memory on the Arduino than it can handle. Make sure that you don't exceed the memory limits of the Arduino!

Keep in mind that some Arduino models may not be suitable for very large cube sizes since they are too slow. If the Arduino spends too much time in the loop function it will slow down the frame-rate and make the cube appear to flicker (if you are multiplexing it), to solve this issue the speed at which the loop function is called can be increased - however this will decrease the time data can be sent from the computer to the Arduino (if this time is too small the cube will stop displaying any frames).

Streaming Animations

The QuadrumSerial library starts by getting set up with some information about the cube such as its size, number of colors each LED has (for example RGB or just one color), etc. Once this is done it will start waiting for a serial connection to be established, and start calling the loop function repeatedly each time with new data to be displayed on the cube.

#include <QuadrumSerial.h>

/* first argument specifies cube side (in this case it is a 4x4x4 cube),
second the number of channels (colors for each LED)
third the resolution of each color (in this case 1 is just on/off)
last argument sets the speed at which the loop function is called

for debugging reasons the last argument is set to 256, a quite low setting, increase
it as much as possible while still being able to stream frames to the cube */
QuadrumSerial qs(4, 1, 1, 256);

void setup() {
    qs.start(); // must be the last call inside setup function
    // nothing below qs.start() will be executed
}

int y = 0;
void loop() {
    // this is just an example, implement getVoxelState in the way that fits your LED cube
    for(int x = 0; x < 4; x++) {
        for(int z = 0; z < 4; z++) {
            qs.getVoxelState(x, y, z); // returns true if voxel at x, y and z is on, otherwise returns false
        }
    }

    y++;
    if(y >= 4)
        y = 0;
}

The example code above shows how QuadrumSerial is set up and what call you can do (inside the loop function!) to get a particular LED's state. Keep in mind that it is up to you to take the data returned from the function getVoxelState and do something with it.

Important: Do not put a delay call inside the loop function, rather adjust the last argument in the QuadrumSerial constructor (that is 256 in the example above). QuadrumSerial will by itself wait in between each call to the loop function (and use this time to get new animation data from the computer).

For help on how to connect the Quadrum editor to your Arduino, visit this page.

More than just on and off?

Since getVoxelState only returns true or false at a given LED in the cube, this function cannot be used when you have multiple brightness levels (for example letting one LED stay dimmer and other ones brighter).

getVoxelBrightness(x, y, z); // returns uint8_t (value between 0 and 255) to give brightness of voxel

The function above will return a value between 0 and 255 that represents the brightness of an LED at x, y and z. Remember to adjust the third argument in the QuadrumSerial constructor to something greater than 1, accepted arguments here are 1, 2, 4 and 8. A larger value will give a greater number of steps (between 0 and 255) for an LED's brigness level but will also result in a longer streaming time for each frame.

Multiple colors (channels)

Neither of the functions explained above have the ability to return multiple values for each LED (for example red, green and blue in the case of RGB cubes).

getChannelState(channel, x, y, z); // returns true if channel at x, y and z is on, otherwise returns false

The function above will (similarly to getVoxelState) return true or false, however this time it requires an extra first argument that specifies the channel of the LED at x, y, and z. If you have QuadrumSerial setup for RGB: 0 will represent red, 1 green and 2 blue; when using 2 channels: 0 represents red and 1 represents green. To select how many channels QuadrumSerial should be set up for you can change the second argument in the QuadrumSerial constructor call, accepted values here are 1 (single color), 2 (red and green) and 3 (RGB).

Both multiple colors and brightness levels

The last function to cover is:

getChannelBrightness(channel, x, y, z); // returns uint8_t (value between 0 and 255) to give brightness of channel at x, y and z

This is a combination of getVoxelBrightness and getChannelState that will similarly to getVoxelBrightness return a value between 0 and 255, but on top of that wants an extra first argument that specifies what channel to read from. To select the number of channels and steps between 0 and 255 that can be reached you can change the second and third argument in the constructor call (as we have done previously).

Uploading Animations

When creating animations in Quadrum you can choose to upload them to the Arduino with your sketch, by doing so you will eliminate the need of a computer constantly streaming data to the cube. This will require the QuadrumCode library which you can implement in the following way:

#include <QuadrumCode.h>

const uint8_t animation[29] = {0x04,0x01,0x01,0x02,0x00,0x00,0x00,0x7A,0x44,0x11,0x11,0x22,0x22,0x44,0x44,0x88,0x88,0x00,0x00,0x7A,0x44,0x88,0x88,0x44,0x44,0x22,0x22,0x11,0x11};

/* first argument retreives the animation uint8_t array generated by the Quadrum editor,
last argument sets the speed at which the loop function is called */
QuadrumCode qc(animation, 256);

void setup() {
    qc.start(); // must be the last call inside setup function
    // nothing below qc.start() will be executed
}

int y = 0;
void loop() {
    // this is just an example, implement getVoxelState in the way that fits your LED cube
    for(int x = 0; x < 4; x++) {
        for(int z = 0; z < 4; z++) {
            qc.getVoxelState(x, y, z); // returns true if voxel at x, y and z is on, otherwise returns false
        }
    }

    y++;
    if(y >= 4)
        y = 0;
}

The uint8_t array animation is generated under the Code tab to the left in the Quadrum editor. By selecting the appropriate settings (channel count and channel resolution) and clicking on Generate you can copy-paste this array into the arduino sketch so that it can be uploaded to the cube. The code above holds an example animation, it can be replaced with your animation of choice. If you are unsure of how to generate the animation uint8_t array you can find help here.

As described in the section Streaming Animations in QuadrumSerial, the functions getChannelBrightness, getVoxelBrightness, getChannelState and getVoxelState are used in exactly the same way here.