Saturday, January 19, 2008

My first project: Full-colour RGB monome clone (Trinome?)


Here it is, the first project that I designed and executed on my own. I'm thinking of calling it the Trinome, but that's still up in the air. Here it is running a simple demo program:



The monome is a gorgeous, minimalist, open-source light-and-button pad used primarily by musicians as a controller. The folks over at SparkFun Electronics, inspired by the monome, released their own button pads and circuit boards, only they designed theirs to be able to hold RGB LEDs. They made this nifty Tetris game with their parts. Looking at it, though, I noticed something: they only seemed to use a limited palette, in particular, they only appeared to have red, green, blue, cyan, magenta, yellow, and white, corresponding to channels being fully on or fully off. I wanted to see if I could get colour mixing, wherein channels were on partially in order to blend colours smoothly.

Read on for more details, videos, and instructions on how to build one.


The Design
A common way to control many LEDs is multiplexing, wherein only some of the LEDs are on at any given time. They are cycled through at a rate fast enough that the human eye can't detect it, and hence all appear to be on at the same time. In this case, having one row on at a time is the natural way to go. A similar method can be used to determine which keys are pressed; diodes are necessary to prevent "ghosting" and "masking" of buttons, as explained in this article.

Analog output, used to control LED brightness, is usually achieved via pulse-width modulation (PWM). While it may be possible to combine PWM with a multiplexed display, it would require very fast refresh rates in order to not appear to flicker. Furthermore, that would require 12 pins on the microcontroller be dedicated to controlling the brightness of the LEDs (3 colour channels x 4 LEDs on at a time). That eats up an unacceptable number of microcontroller outputs. Another solution had to be found.

Another way to adjust the brightness of an LED is using a resistor; in particular, if you want the brightness to be adjustable, a variable resistor. Fortunately, there exist digital potentiometers whose resistance can be set. I was introduced to one such digital pot in this tutorial on the Arduino website, written by Heather Dewey-Hagborg. The chip in the tutorial, the AD5206, has six independent potentiometers on board. As I mentioned above, this project needs to control 12 channels at once, so two AD5206s should do the trick nicely.


The Parts
4x4 Button pad ($10, Sparkfun)
Button pad breakout board ($15, Sparkfun)
Arduino ($33, Adafruit)
16 common cathode RGB LEDs (I used RL5-RGB-D) (~$1.50ea, Superbrightleds.com)
2 AD5206 digital potentiometers ($3.66, Digikey)
16 1N4148 diodes (Pennies, any electronics parts store)
4 2N2222 transistors (Pennies, any electronics parts store)
Various resistors (LED current limiting and pull-down) (Pennies, any electronics parts store)

The Build
I'm too inexperienced with Eagle (and, let's face it, too lazy) to draw up a proper schematic. If enough people want it, I suppose I'll put one together. Still, the build itself is pretty easy. The button pad assembly is straightforward: solder in the LEDs and the diodes according to the silkscreen on the board. Actually, the LEDs held in tightly even without soldering, and since I'm a bit paranoid, I did all of my testing with the LEDs held in place by tension alone. I soldered in wires for each of the input and ground lines, 24 wires in all, making it all quite a mess to work with. If I continue with this, I'll replace them with proper connections of some sort, but I didn't have anything handy, so wires it was.

The AD5206 gets wired up just like in the datasheet, or in this tutorial from the Arduino site. To add the second digital pot, you wire it up exactly the same, and share the same Serial In and Clock lines with the first chip, with a separate Chip Select line. Each of the twelve outputs gets wired to one channel of one column of LEDs, with a series resistor in between to protect the LED from too much current and to set the colour balance. (You might be able to get away without this resistor, but it will probably shorten the lifespan of your LEDs.) The zero setting of the AD5206 has a resistance of about 40 Ohms. In all the RGB LEDs that I've seen the red channel has a much lower forward voltage than the blue and green, something to consider when picking your resistor values.

The input and output lines from the buttons go into Arduino pins, with the output having pull-down resistors. The ground lines from the common cathodes of the LEDs go to the collectors of the transistors, with the emitters going to ground, and the base pins attached to the Arduino (through appropriate resistors). Using the transistors ensures the Arduino pins don't sink too much current.

One final word about the build: make sure that, when soldered, your LEDs don't stick up too high, otherwise you might not be able to get the buttons to make a good contact. I found this out the hard way.


The Code
The basic outline of the code is:

Looping through the rows, bring each row of buttons high in turn, in order to scan that row for button presses.
Looping through the columns, check if each button-press state has changed. If it has, run the appropriate on_press or on_release routines. If it hasn't, run the appropriate while_pressed or while_released routine.
Still inside both loops, write the potentiometer value for that button entry.
End the column loop.
Bring the row of buttons low.
Bring the LEDs for the row high, wait a little bit so it's visible, and then bring it low.
End the row loop.


I wanted to include real code here, but I have yet to figure out how to properly format it in the Blogger tags. If people really want to see it, I'll figure out how to add it in here. (Update: I've posted some code in the Arduino forum for now.)


The Catch
Or, rather, the catches. Basically, this is a lousy a pretty lousy method to accomplish the colour blending. First of all, the digital potentiometers are voltage dividers; they limit current (and therefore brightness) by limiting voltage. That means that, once the supply voltage drops below the LED's forward voltage, the LED turns off. For the blue and green channels, this happens less than halfway through the pot's 8-bit range, severely limiting the range of colours you can get. I could use the digital potentiometers as rheostats, limiting only current, but then the 10kOhms maximum isn't enough to get them anywhere close to off, so I'd either need a high-resistance pot (with correspondingly low resolution), or additional circuitry to turn the LEDs off. Both bad choices. Furthermore, because of the LEDs' nonlinear current-brightness curve, the number of visible changes within that limited range is further cut. So, the resolution in colour space is much less than I'd like.

The other catch is brightness. Though the videos look really bright, it doesn't look anywhere near that good in person. Don't get me wrong, it looks alright, but not as good as it could look. Because of the multiplexing, the LEDs are on at a maximum a quarter of the time. In reality, it's probably more like a fifth or less because of overhead. Comparing a full-on LED to one at the duty cycle on the board really makes me want to come up with a non-multiplexed solution.

The Future
The good news is, I think I have come up with a solution that will work for non-multiplexing the LEDs. The bad news is, it will eat a lot of current (so I'm looking in to power supply options), and it will require me to make my own circuit board (which I've never done before, but I'm going to have to learn sometime, so why not now?). The really bad news is that the free version of Eagle CAD has a size limit per board that is smaller than the 4x4 buttons. I'm not sure I'm ready yet to invest $125 in the non-profit license, so we'll have to see what happens. I'll get a breadboard prototype working first.

As for this version, I think it should easily expand to a 4x8 pad by adding two more AD5206s. It might require some fancy work, or even a demultiplexer IC, to read all 8 buttons in a row, but I think it should work. An 8x8 layout might also be attainable, but in order to keep the brightness up I would set it up as two 4x8's being driven off the same master controller. I think anything higher than 8x8, at least with this design, will require multiple microcontrollers for different segments with a master controller coordinating it.

One other possibility using this design, which is more in tune with the minimalist philosophy of the original, would be to use single colour LEDs and fade them, ideas of which are shown in the following couple of videos:


Finally, if I were to continue pursuing this design, I would want to eventually put it on a board that could function as a "backpack" to the Sparkfun breakout board, similar to their serial interface for their RGB pixel boards, or the idea behind the Arduino shields. The idea would be a board with headers that lined up with those of the breakout board, which can be attached directly to it to extend it's functionality.


The Challenge
Wow! If you've read this far you must be really interested. I'm flattered!

Here's the deal: so far, all the demos I've written are running directly on the Arduino, so the whole setup is standalone. One of the coolest things about the monome, though, is that it's interfacing with something (namely, the computer). Implementing a serial protocol on the button pad is pretty trivial. However, you need something to interface with. I haven't had time to write any software that would talk to the button pad via the serial port and do something cool; I'm too caught up in the microcontroller side of things. However, if someone were to write software to talk to the button pad, I would definitely set it up to work and post a video of it in action.

Here are the requirements: it needs to run on OS X, and I need to be able to see the source. A Processing sketch would be ideal. You can set the communications protocol up any way you like, as long as you explain it; it should be easy, all you need to send are coordinates and RGB data, and received a 16-bit binary string indicating whether buttons are pressed or not. Post something in the comments, maybe a link to the code, and we'll see if we can get it working.

I'll be honest, I don't really expect anyone to respond to this, but man, it'd be cool if someone did!

4 comments:

Anonymous said...

Awesome! I live in Stockholm, so getting these parts is a bit hard and could potentially be disastrously expensive. But Im going to follow your progress. I want to build a minimal interface like this myself. At least 8x8. Multicolor would definetly not be a negtive thing! This kit from Sparkfun, seems to be able to serial link the boards into potentially huge interfaces..

And hopefully this scene is just in birth. Maybe in a somewhat near future, we will be able to download different programs to use with our interfaces, easily installable and customizable.

Nice!

Jonathan said...

Neat hack! A few observations...

If your PWM cycle period is 1/60 sec or faster, you should notice minimal or no flicker, and you can probably get away with a slower cycle still depending on ambient lighting.

Those digital pots are designed for no more than 20mA wiper current. Multiplex operation of LEDs requires higher current to provide a satisfactory brightness level, but take care that you don't draw too much current for too long through the LEDs or from your power supply, especially during power-on reset or serial communications.

The 74HC164 shift register with some driver transistors may be a good solution to the low I/O row selector. It's an 8-out 1-in shift register that can be cascaded as wide as you like and can also be connected as an SPI peripheral. Assuming you run with 8 columns and a 4x4 RGB matrix, you would need to provide six independent output pulses with 2ms / brightness_levels precision (125us for 4 bits per channel).

If you can't get that level of precision in timing with your MCU/language of choice, you might consider scanning as fast as you consistently can with full-on or full-off and doing the PWM in software like LCD controllers; e.g. 33% brightness turns the LED on every third scan time, 66% turns the LED on two out of three scan times, etc.

If your MCU can't do PWM fast enough or if you're really married to those digital pots, there's another way to improve the linearity and consistency of the brightness curve. You can use a couple of op amps to generate a sawtooth or triangle wave of 10kHz or higher (see almost any op amp datasheet for an example circuit) and place comparators on each analog output that compare the DAC output with the "carrier" wave and double as a high-current open-collector output. Higher bit depths demand a faster oscillator and faster comparators.

Hope this inspires!

-jhp

JMG said...

anonymous - I'm glad you enjoy it. If you're looking for community and posted programs, please check out monome, the inspiration for this project. They have a very well developed product with an active community that has already done exactly the sort of thing you're talking about.

jhp - I've taken care to ensure that the pots are receiving considerably less than 20mA peak current, and all is safe. The brightness level is OK, but, of course, in this sort of thing the brighter the better, right? That's why I'm working on a revised design that will not be multiplexed at all.
I don't have any 74HC164s, but I initially tried doing a PWM setup with a 74HC595, and wasn't happy with the results. That said, my programming has improved a lot since then, so I might be able to get it to work. I doubt I'll bother, though, because a non-multiplexed design inherently offers higher brightness possibilities than a multiplexed one. I'm willing to deal with the downside, which is the increased power consumption.
Your op-amp suggestions are very interesting, and a topic I know nothing about. That is something I will definitely look into.

Easy said...

I am very interested in building a hardware platform like this myself. Taking your comments about the LED brightness into consideration, I think my design will end up using eight of those AD5206 pots so that each 3-channel LED can get a constant voltage. I want to implement the keypad as a door lock like the one here:
RGB Combination Door Lock
but also have it be self-contained enough to do things like the monome. I may need to put an MCU on-board just to bring all the necessary SPI and button lines together for easier USB control with Processing or something similar.