When I first started this blog, I was just dipping my toes back into the world of C++. Before that, my experience with it was mostly academic, and after struggling through a course with a particularly poor professor I swore off it in favor of VB.NET. No, I never did forgive myself for that decision, but it ultimately helped me learn to appreciate the importance and relevance of C++. And after tinkering with systems that use C++ exclusively, I’ve come to appreciate it even more.
Note: I planned on adding screenshots and code samples, but I’m rebuilding my environment after a recent reformat. I may update this post later.
At the start of this blog, I set off to develop my own complete Arduino library. It was an excuse to learn not just how to use C++, but how to program in a low-power, low-memory environment. My yet-to-be-open-sourced library, which I call Pixel Maestro, has the totally unique and never before attempted ambition of being a full multi-color LED controller, providing simple APIs for displaying 2D animations on an LED grid. As I worked on Pixel Maestro and added features, I eventually realized I no longer had the hardware to support the features. For instance, I didn’t have enough physical LEDs to create multiple rows of lights (and I was cheap to buy a pixel grid). Faced with such overwhelming and insurmountable opposition, I decided the best decision would be to do away with the hardware completely and run Pixel Maestro entirely in software. I would create a desktop application that simulated an LED grid while allowing me to dynamically set the number of LEDs, their position and orientation, and the behavior of Pixel Maestro in real-time. The best part is I had the added satisfaction of knowing that this too had never been done before.
C++ on the Desktop
So how exactly does one take an Arduino library and run it on a typical computer? Pixel Maestro itself is a simple set of classes with some C++11 features. It doesn’t depend on any external libraries with the exception of stdlib, which I only need for abs() so I can find the absolute difference between two colors during an animation cycle. Piece of cake, right? Well, mostly. The easy part was running it; the hard part was getting any meaningful output from it. Being a Linux user, I was very familiar with running C++ applications on a command-line, but a terminal is hardly a good medium for playing animations (although it can be done). The only option was to add graphics.
Your computer may have dozens of uniquely designed applications on it. Each application could be made by a different developer, have different layouts, and offer different visual effects and animations. And yet many of them will share a fairly unified look and feel, as if they had the same core interface. This is because a lot of applications are built on top of a common graphical toolkit (or framework) that acts as sort of a graphics middleman between the application and the operating system. These toolkits provide many of the basic building blocks for creating graphical applications such as labels, buttons, textboxes, and menus. For example, many Windows programs use the Windows Presentation Foundation, and many Mac programs use Cocoa. There are many toolkits available for all operating systems. In my case, I use Fedora with the Gnome Desktop Environment. Gnome is built on the GIMP ToolKit, or GTK. As a result, I decided to use GTK as my toolkit of choice.
Each toolkit provides several wrappers (or bindings) for different languages. In the case of GTK, there are bindings for many languages including C, Python, PHP(!), and even Fortran. The official GTK binding for C++ is called gtkmm, and it provides a fairly straightforward object-oriented approach to creating and interacting with widgets on the screen. Even for a relative C++ newbie, it was very easy to wrap Pixel Maestro in a GTK wrapper. I gave my new application the very inspired name of Pixel Grid.
Turning LEDs into Graphics
Now I had a hypothetical canvas for my hypothetical LEDs. The question now was how do I display these LEDs in a way that makes sense? One solution – and I admit it’s not a good solution, but I’ll use it anyway – is to use text that looks kinda like an LED and simply change it’s color. I created a grid of labels that have a bullet character • as a stand-in LED. Gtkmm lets you format the font, size, and color of individual labels, meaning I could take an LED’s color values from Pixel Maestro and apply it to its corresponding label. What I ended up with is a perfectly uniform and scalable virtual LED matrix on a platform that offered way more flexibility and oomph than my flimsy hand-soldered, Arduino-powered light array could ever offer. The best part is that now I could design and test new animations without having to fiddle with wires, solder, or even get up from the couch.
No programming exercise is not without its troubles. In my case, the most difficult part of creating Pixel Grid was learning how to use a rather significant external library in my application. The standard method in C++ is to use a makefile, which defines a set of instructions for building an application such as what files to generate and what dependencies to pull in. Additionally, different IDEs have their own different interfaces and methods that supplement or outright replace makefiles. I used Code::Blocks to develop Pixel Grid, and in all fairness adding dependencies in Code::Blocks is a breeze, but in an ideal world I would have created a makefile that linked Pixel Grid, Pixel Maestro, and gtkmm for better portability.
My next problem was performance. The nature of an animation library is that it requires constant refreshing. A typical computer monitor in the US redraws 60 times a second – that means Pixel Grid has to iterate over each and every LED, calculate its current color based on the active animation, and update the label in 16.67 milliseconds (1/60th of a second). I was able to use a method called signal_timeout() (provided by GLib rather than gtkmm) to update Pixel Grid whenever a certain timeout was reached. This was set to the update speed of Pixel Maestro, which can be changed dynamically based on the current running animation. The hope was to keep the program from chewing up CPU time that it didn’t need: instead of chugging constantly, it would only update when the grid needed to send an update. Did it work? Well, it hovers around 18% utilization on a Core i7-4500, so there’s plenty of room for improvement. But it’s responsive, there’s no tearing, and there are no noticeable memory leaks, so I’m quite pleased for a newbie.
What’s next for Pixel Maestro and Pixel Grid? I’m in the process of adding functionality to trigger changes to Pixel Maestro at certain times. For example, you can create a transition that changes the speed of the animation, the type of animation, and the colors to use in the animation, and have it apply when the program has been running for 2 minutes. I’m also working on adding controls to Pixel Grid to allow users to manipulate Pixel Maestro from the GUI itself. My ultimate goal is to make this a platform for creating dynamic light shows in real-time, but that’s still a long way off.