BADASS Display: Coding Conundrums
Happy Monday (or whatever day it happens to be when you read this)! I just spend a jolly happy weekend programming some new test-pattern lighting effects into my Bodacious Acoustic Diagnostic Astoundingly Superior Spectromatic (BADASS) Display.
Note: If you're planning on attending ESC Boston, which will take place May 6-7, 2015, then I'll be happy to chat about my BADASS Display in excruciating detail to anyone who doesn't manage to get out of the way fast enough (LOL).
As I mentioned in my previous column on this topic -- BADASS Display: It's alive! It's alive! -- my chum Duane Benson has taken the circuit for my original spectrum analyzer breadboard prototype and replicated it as a custom shield. I'm currently waiting for this little rascal to come back from the board shop. In the meantime, as you can see in This Video, I'm having a lot of fun just playing around with different effects.
I have a couple of ideas for additional algorithms that might look rather tasty. For example, I'm thinking of a "raindrops" effect where we pick a column at random and a short trail of white dots falls from top to bottom ending in a "splash." We could have several of these falling at the same time. We could even tie it to the Internet such that this effect automatically comes on whenever it's raining outside.
Another idea is a "fireworks" effect. In this case, we'd pick a column at random and a short trail of white dots would rise from the bottom to some random height, at which point there would be an "explosion" of colored pixels radiating out in different directions. The color and size of each explosion could also be random.
And yet another idea is to have one or more snake-like creatures meandering their way around the pixel array. Ooh! Ooh! Now I come to think about it, what about implementing a version of Conway's Game of Life? Do you have any ideas for additional effects? If so, it would be great if you could post them in the comments below.
Now, I must admit to being quite proud of myself because I'm a hardware design engineer by trade -- when it comes to programming, I pretty much make things up as I go along; which leads me to the fact that I wouldn’t mind a bit of help in the form of someone who actually knows what they are doing taking a look at my code and offering some advice on how I can make it leaner, meaner, and more efficient.
If you Click Here, you'll be presented with an ASCII text file containing the program running in the video above (in fact there are three "rainbow" effects in this code -- vertical (column-by-column), horizontal (row-by-row), and diagonal -- but I only activated the diagonal version in the video).
Now, I'm using NeoPixel Strips from Adafruit to power my display. In fact, I have 16 strips, each boasting 16 NeoPixel elements, thereby giving me an array of 256 pixels.
On the off-chance you haven't used these little scamps yourself; it might be a good idea for me to explain a couple of things before you start dissecting my code. First we use the following #include statement to access Adafruit's NeoPixel library.
Next, we might a statement like the following to declare (instantiate? I'm not sure what the right word is here) a NeoPixel strip called "strip":
Adafruit_NeoPixel strip = Adafruit_NeoPixel(16, 25,...
The first parameter -- 16 in this example -- specifies the number of NeoPixel elements in the strip. The second parameter -- 25 in this example -- specifies the number of the Arduino's digital output pin we intend to use to drive the strip. We don’t need to worry about any remaining parameters here.
The important thing to note at this stage is that the act of instantiating a NeoPixel strip automatically creates an array in memory. This array has the same number of elements as the number of NeoPixels in our strip -- 16 in our example -- numbered from 0 to 15. Each of these elements has three byte-sized sub-elements, which are used to store that pixel's red, green, and blue (RGB) values. Now consider the following command:
strip.setPixelColor ( 6, 255, 127, 63);
This loads the seventh element of our array in the Arduino's memory with RGB values of 255, 127, and 63, respectively. but it doesn't actually change the values that are currently being displayed. This means that we can happily take our time deciding what values we wish to display and loading them into our array using a series of "strip.setPixelColor()" commands. When we are ready to actually display these values, we use the following command:
This causes the Arduino to stream the RGB values associated with all 16 pixel elements out of the associated pin (the neoPixels forming the strip are daisy-chained together).
OK, returning to My Code, you will see that I've instantiated 16 NeoPixel strips called strip0, strip1, strip2... strip15 as follows:
Adafruit_NeoPixel strip0 = Adafruit_NeoPixel(16, pinsStrips…
Adafruit_NeoPixel strip1 = Adafruit_NeoPixel(16, pinsStrips...
Adafruit_NeoPixel strip2 = Adafruit_NeoPixel(16, pinsStrips...
Adafruit_NeoPixel strip15 = Adafruit_NeoPixel(16, pinsStrips...
As you'll see, this makes my lowest-level functions look a tad ungainly, because I have to do things like the following:
What I would prefer is to declare my strips in such a way that I could re-write the above code snippet as follows:
for (int i = 0, i < 16; i++)
The problem is that I don't have a clue how to do this. Furthermore, although it seems to me that this new version should end up occupying less space in the Arduino's memory, I do wonder if it might be slower than my current incarnation. Do you have any thoughts on this?
Another big one for me is my diagonal rainbow effect. My pixels are numbered [0,0] in the lower left-hand corner to [15,15] in the upper right-hand corner. My 16 x 16 array has 31 diagonal "slices" -- the first has just one element at [0,0]; the second has two elements at [0,1] and [1,0]; the third has three elements at [0,2], [1,1], and [2,0]; and so forth. As you'll see in my code, I created a three-dimensional array called "xyDiagCells" to hold these values as global variables.
The problem here is that this has sucked up a lot of my available global variable space. Ideally, I'd like to be able to generate the XY coordinates of the cells forming each diagonal algorithmically, but I'm finding it difficult to wrap my brain around the way in which I might achieve this.
I could go on and on, but I think you get the drift. If you have a moment and you are up for a challenge, I'd love for you to take a look at My Code and offer any advice on how you would improve on it so as to consume less memory and fewer clock cycles. Any suggestions will be very gratefully received.
Join over 2,000 technical professionals and embedded systems hardware, software, and firmware developers at ESC Boston May 6-7, 2015, and learn about the latest techniques and tips for reducing time, cost, and complexity in the development process.
Passes for the ESC Boston 2015 Technical Conference are available at the conference's official site, with discounted advance pricing until May 1, 2015. Make sure to follow updates about ESC Boston's talks, programs, and announcements via the Destination ESC blog on Embedded.com and social media accounts Twitter, Facebook, LinkedIn, and Google+.
The Embedded Systems Conference, EE Times, and Embedded.com are owned by UBM Canon.