XY Matrix 16x16 matrix (256 pixels) driven by an Arduino Nano, plastic diffuser,

XY Matrix
16x16 matrix (256 pixels) driven by an Arduino Nano, plastic diffuser, and faux TV.

Here’s the complete code for this effect; the whole program is well under a hundred lines, and the ‘effect’ itself is just twenty lines. Compiled code size is 3,756 bytes.
(This same code also pasted here XY Matrix sample (draft) - Pastebin.com )

A more fully commented version of this XY example code will be included in the v2.1 release of the FastLED library.


#include <FastLED.h>

#define LED_PIN 5
#define COLOR_ORDER GRB
#define CHIPSET WS2811

#define BRIGHTNESS 32

const uint8_t kMatrixWidth = 16;
const uint8_t kMatrixHeight = 16;
const bool kMatrixSerpentineLayout = true;

#define NUM_LEDS (kMatrixWidth * kMatrixHeight)
CRGB leds[NUM_LEDS];

void setup() {
FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS);
FastLED.setBrightness( BRIGHTNESS );
}

void loop()
{
uint32_t ms = millis();
int32_t yHueDelta32 = ((int32_t)cos16( ms * 27 ) * (350 / kMatrixWidth));
int32_t xHueDelta32 = ((int32_t)cos16( ms * 39 ) * (310 / kMatrixHeight));
DrawOneFrame( ms / 65536, yHueDelta32 / 32768, xHueDelta32 / 32768);
FastLED.show();
}

void DrawOneFrame( byte startHue8, int8_t yHueDelta8, int8_t xHueDelta8)
{
byte lineStartHue = startHue8;
for( byte y = 0; y < kMatrixHeight; y++) {
lineStartHue += yHueDelta8;
byte pixelHue = lineStartHue;
for( byte x = 0; x < kMatrixWidth; x++) {
pixelHue += xHueDelta8;
leds[ XY(x, y)] = CHSV( pixelHue, 255, 255);
}
}
}

// Helper function that translates from x, y into an index into the LED array
// Handles both ‘row order’ and ‘serpentine’ pixel layouts.
uint16_t XY( uint8_t x, uint8_t y)
{
uint16_t i;

if( kMatrixSerpentineLayout == false) {
i = (y * kMatrixWidth) + x;
} else {
if( y & 0x01) {
// Odd rows run backwards
uint8_t reverseX = (kMatrixWidth - 1) - x;
i = (y * kMatrixWidth) + reverseX;
} else {
// Even rows run forwards
i = (y * kMatrixWidth) + x;
}
}

return i;
}

Looks great Mark! I’m definitely interested to see the code. :slight_smile:

Thanks! Part of what I like about this effect is that the code is incredibly small, and simple, but the effect is surprisingly interesting. Another bonus here is that if you look at the DrawOneFrame function, you’ll see that inside the inner loop all it’s doing aside from an HSV color conversion is… one simple addition. By keeping the innermost loop fast and light, even a standard ATmega328 (Arduino Nano) is able to drive these 256 pixels at a very snappy frame rate. If the inner loop required much more math or processing, the frame rate would lag a bit.

I originally developed this effect for the Rainbowduino and an 8x8 RGB LED pack. The Rainbowduino does’t drive intelligent pixels like the WS2811s here; the Rainbowduino uses the main Arduino’s CPU to multiplex and drive 64 ‘dumb’ RGB LEDs. It was exactly because the Arduino was so ‘busy’ driving the LEDs that I had to come up with an effect that was very light in its CPU demand.

This effect is interesting because it looks like there’s some kind of rotation, or scaling, or zooming, or warping going on, but as you can see from the code, all that’s really going on is that each row of pixels is painted with a hue gradient, and each successive row’s gradient is offset a bit from the previous row. That’s it; everything else you think you see is generated with CPU power borrowed from your brain and optic nerves.

In looking at your code, I understand what it’s doing, but every time I look at code like this, I always wonder how people come up with the values to use in the sin or cos functions. Do you have any tips or advice?

The value inside the cos16(…) here is ‘time’. I initially used just ‘ms’, but everything moved too slowly so I decided to multiply it for a faster pace. I experimented, but ultimately chose different time multipliers for X and Y, so that the effect varies at different speeds in each axis.

The multiplies outside the cos16(…) are scaling the ‘stripey-ness’ of the pattern; bigger numbers make the stripes more dense, smaller numbers make the stripes wider. Again, I experimented and chose different values for X and Y, to keep things slightly off balance and syncopated.

Finally, I wanted the code to automatically scale to different matrix sizes; I’ve used 8x8, 5x8, 16x8, and 16x16 – as shown here. I already had the constants worked out for a stripe width that I liked, and I then added the math to automatically take matrix width and height into account.

I think maybe the short answer to your question is: experimentation. Play around and see what you like the look of.

I usually start with the range of numbers that I think I’m going to want (eg, 20-50), and then set up a cos() oscillator to swing between those. In floating point math, you’d say
output = (cos(something) * 15) + 35;
and that would swing between 35-15 (20) and 35+15 (50). Then I decide how fast I want it to swing that number, and adjust the parameter inside the cos() to suit.

This is a very helpful explanation Mark - thanks!! I’ve been going the experimentation route already, but I didn’t yet have a good idea of what to change to have the desired effect (it’s been a LONG time since I’ve done math :wink: ). This gives me a basic idea to work from. :slight_smile:

Often when you see cos or sin in this sort of pattern, it has nothing to do with trigonometry. It’s just a shorthand way of expressing that one value will oscillate within a certain range, at a certain frequency.

Using sin&cos just saves on typing. Plus, the oscillation is smooth ~~~~~, versus a pointy triangle wave up and down ////.

Originally when I wrote this code, the xHueDelta and yHueDelta did follow triangle waveforms. They incremented until they hit the upper bound and then decremented until they hit the lower bound, repeated. I found that by switching to cos16(…) the code got smaller and easier to tinker! it changed the shape of the pattern a little, but I still liked it, so here it is.

The FastLED library is great, and I’ve been having a lot of fun writing code for my 24 x 24 array. I have all kinds of patterns that look really nice. I’ve wanted to add more though, especially doing things like rolling color waves, changing brightness, and other things based on sin and cos, but it’s been frustrating for me not knowing exactly what effect each change will have.

As I see more posts and code samples like this, it’s finally starting to gel in my mind. Thanks again, and I am really excited to see what you and @Daniel_Garcia have in store for 2.1 and beyond. :slight_smile:

I have a spare matrix and some beat up acrylic that needs a good sanding that I can put to good use. I think the code will make a good addition to my front window lighting.

Hi! Kind of late to the party :slight_smile: I just got started working with LEDs. I made a board that consists of 480 WS2811 lights. I used this code with the Arduino I have driving the lights, but I’m trying to start writing my own. I figured out a formula to calculate which light I’m addressing, but it’s not very clean. Can you explain/link me to any sources that can explain how you pick which pixel to address?
Thanks!!

Hey Mark. I’m new to fastLED and am loving it so far, already have 5 strips of 300 LEDs up and running with some great effects. I want to take it a step further and apply some effects such as the one you’ve illustrated here in this 16x16 matrix. I’m effectively looking for a 5x300 matrix - the strips I have will be lined up next to each other. Any pointers? I’m not sure why the matrix examples are all only 16x16. Am I missing something :S Thanks!

They’re that size because there are pre-built matrices that size-- but any dimensions should work, assuming you have enough RAM and CPU power!

Brilliant work Mark, it works great on my 8x8 neopixel matrix and looks fantastic

Hey @Mark_Kriegsman , the video looks amazing. I copy/pasted this into my sketch but I’m getting a weird error:

Arduino: 1.6.5 (Windows 8.1), TD: 1.25, Board: “Adafruit Bluefruit Micro”

Test_Sketch:64: error: stray ‘’ in program
Test_Sketch:64: error: ‘ufeff’ does not name a type
stray ‘’ in program

This report would have more information with
“Show verbose output during compilation”
enabled in File > Preferences.

Any ideas?

Well… see where it suggests turning on Verbose output? Try that, recompile, paste the results into http://pastebin.com, and put a link to it here and we’ll see what it says!

Ok I think I got it: http://pastebin.com/jmJzk6Be

Could you also do the same pastebinning for the TestSketch source code too? It says line 63/64 has a snag…

And the code: http://pastebin.com/ycjR9UdY

Thanks. Ok uh I’m stumped. I’ll have to try it later when I have a real computer (just on my phone now).

Do other FastLED example sketches work ok?

Yeah I just tried the colorpallet example sketch and it works fine.