Still tinkering with the XBees. Progress is slow and I'm feeling more stupid than usual. I do have the excuse of an ongoing show in one town and a load-in in another town.
Yesterday was typical, though. Wasn't able to get the XBee to respond to my desktop, thought I had another Java issue, in the process of re-installing Java realized I really needed to do a round of file back-ups and general cleaning on three different machines...and after several hours of that, more driver installs, and change back to the previous version of Processing...realized it was a bad USB cable all along.
I've been trying to interpret the signals from the XBee, which are sent as strings of different lengths. I'm trying to parse them using Processing's string functions and it is NOT going well. Whether it is due to Processing considering string handling beneath it (the manual gives short shrift to the subject), the difficult-to-decipher documentation on the XBee, or that my own brain is not quite running right this week...
The easiest way to use XBees is as a transparent serial link. With two XBees in the factory defaults, and serial-to-USB connections to them (via say the XBee Explorer USB, which uses the perennial FTDI chip to produce a virtual COM port on the USB hub -- don't forget to install the FTDI drivers!) you can type into a terminal application on one computer and the text will appear on the other.
After struggling with the broken Java implementation of MIDI on OSX 10.4 through 10.5, I was able to get a proof-of-concept working via a nice little piece of freeware called the Hairless MIDI to Serial Bridge. For whatever weird reason, Processing uses -128 to 128 as the range of values for the Byte data format, so to get something like 144 (the decimal value of the "NoteOn" command) I had to do some odd tinkering.
But it all worked well enough. I ran a Processing sketch on my laptop that would spit out a serial string on command, and Hairless was on the slave computer, hooked up as a virtual MIDI input to QLab. And the actual serial connection between the two machines was via XBee modules plugged into the USB ports. Using just Series 1 modules with chip antennas I was able to fire off a sound cue even with the sound computer at the back of the house (in the lighting booth) and my laptop all the way upstage behind the scenery.
And this will...work. It means intelligence on the sending end. My preference was that the transmitter would be "dumb," merely reporting on the status of the sensors or other inputs connected to it, and that the massaging of the data and creation of a MIDI or DMX signal would happen on software running on the receiving computer. But to get this working either requires I learn how to program on CoreAudio itself (bypassing Java entirely) or wait until I am working on machines running 10.6 and above.
I can hack it now, though, by having an AVR do the listening to the sensors and conditioning of them, and constructing a viable serial string. The advantage to having intelligence at the sensor end is you can add battery status and other diagnostic and self-reporting functions. The downside is that trimming the sensor or otherwise changing the response means re-programming a micro. Or adding more hardware to the transmitter so you can interact with it directly (aka display, buttons, etc.)
The next show has a potential "Jeopardy" type button. Basically, that means sticking an XBee into the "Easy" button we are using right now to run QLab. I think a wireless "Easy" button is far too useful not to have around. I do want to build it with some sort of self-diagnostics, though, and of course I need the ability to change out the battery easily.
Probably the nicest solution is a custom fabbed board with an AVR, LED drivers, and perhaps a MAX power monitor chip on it. At the moment, I'd just waste an Arduino in order to get it up and functioning -- if there was room for an Arduino and shield inside the button. I'm not quite comfortable with serial I/O on a "naked" AVR yet.
Or move the intelligence. The XBee modules have several I/O ports that can be configured as digital inputs, ADCs, digital outs, or even PWMs. That was the big progress for this week; I finally got an XBee set up to where it would stand in idle mode without doing anything, but transmit a short burst whenever the status of a "sensor" (aka a button) on one pin changed.
The XBees are very much designed for remote monitoring applications and thus also have a variety of sleep modes, including sleep-until-pin and wake-every-n-seconds. In my current arrangement, I'm not sleeping the module at all; it is remaining in active state. It just isn't transmitting unless it has something to say.
I've already been working up a control surface for use with QLab -- several large buttons (maybe even arcade buttons) on a box that is powered from the USB connector and shows up (via the ATmel family of USB-compliant chips) as a MIDI device.
It is much easier to hook up the AT-USB chips as HID -- to make them emulate mice and keyboards. But there are a growing number of MIDI libraries for them now and I'm pretty sure I can get that working in a couple more weeks.
So in this format, the XBee is a dumb terminal; it sits around, reporting what it sees on its inputs. The micro sitting inside the control surface up in the sound booth interprets the sensor readings, adds them to the button inputs, and spits out MIDI-over-USB which is interpreted by QLab.
And, yes, using Max/MSP as a go-between, and upgrading to OSC (or just sending serial to Max and letting it deal with it) is a smarter solution. I'm just used to MIDI, I don't need to pay for it, and it will work with any host -- like the typical "someone supplied a laptop to run sound effects but they need it back after the show." Same for the XBee, really -- you can get cheaper radio links, but the cost on the XBees is as low as 17 bucks each and they handle all the error correction and multiple transmit tries and so forth for you.
Of course it doesn't stop there. The XBee has those outputs, after all. You can quite easily have them controlling relays or servos. But there is another trick that, again, leverages the insane intelligence available these days in very small packages.
For instance, by hooking it to a BlinkM. According to my reading, A BlinkM can be run off an unregulated 6v supply. The typical breakout for the XBee includes a 3.3V regulator. The UARTs on both devices are tolerant enough to operate across a range of voltages.
The end result would be a high-power RGB LED running a pre-programmed sequence that can change behavior (change sequences) by remote command.
I don't know how many shows I've had a candle or lantern on stage. The difficulties are both getting them bright enough to read against stage lighting, and being able to turn them on and off. On a production of "Lulu" some time back the solution was to glue a servo and radio (from an RC model car) to the shaft of a potentiometer inside the lamp. Thus, by using the RC controller you could dial the light up or down.
In this case, once you are in digital domain like this, the control impetus can come from anywhere...from the lighting board, for instance. So a lantern hanging in the barn will go up automatically with the lights, go out at the blackout, and flicker in a pleasing manner during the scene.
Or turn red and blue or flash like a police car, if you wanted it to. It's all right there in the remote controls.
In the upcoming show, I also have some electric collars. Mention was made during the production meeting of the light-up collars in the old Star Trek episode "The Gamesters of Triskellion." It is totally do-able with this sort of hardware. With lithium coin cells you could even make it self-contained (but an external battery pack would be nicer). Under direct control from the booth the collars could be radio controlled to light up and change color.
Waaaay too useful a tool not to try to put together.
Argh. The BlinkM is designed to take I2C. You can bitbang with an XBee to talk to a I2C device, but it is a complicated, slow, and power-hungry process. You could use the two PWM outputs of the XBee for a light controller (via some Darlington drivers) but this has several disadvantages; it wouldn't be a full RGB, you have to transmit constantly, and the only way to access these pins anyhow is via "echo mode" -- where one XBee is fed an analog value on several pins and the other mimics it out the corresponding pins.
You could include any of the family of AVR or Arduino clones to act as a translator from XBee to BlinkM, but that is adding to the cost, complexity, and size of the device, and is a bit silly besides; the BlinkM already HAS an AVR.
As it turns out, you can hack the BlinkM. You can even burn an Arduino-style bootloader and run it via the Arduino IDE, if you happen to have an ISP handy (which I do). At which point, you could write your own open version of the BlinkM software. Opening up the BlinkM also opens up the available I/O pins -- unfortunately it does not include the UART but you can use one of the soft serial libraries.
So, in short, it is still a plausible idea; to connect XBee to BlinkM, add a battery, and make an over-the-air programmable RGB light. It just requires a lot more work on the software side.
As I describe in a later post, once you've added the BlinkM to the list of compatible boards in the Arduino IDE, you can write modified Arduino code to it. And since one analog in port is uncovered (aka broken out to a pin), a trim pot or resistor ladder can be used as a multi-position switch. Presumably you could also use the PWM output of an XBee for this. My proof of concept, though, involved a digital output from the XBee and two resistors to toggle the BlinkM between two programmed states.
Of course, you could do soft serial. Or even write your own asynchronous unidirectional protocol; three "clicks" from the XBee means go to the blinking red program, four clicks means turn the LED off, etc. (Or, even more clever...an asynchronous PWM comparator; count the time from leading edge to falling edge and compare to the time from falling edge to leading edge. Then use the comparison as an analog value.)