Posts Tagged ‘hack’

Wiimote: Robust IR filters on the cheap

Friday, May 15th, 2009

One thing I learned from Perceptron was that interactive art is a lot like engineering: it’s all about coping when plans fall through.  For instance, one of my goals was to have a neat IR-based camera system in the final product.  It didn’t gel by our first installation, and has kind of fallen by the wayside for Perceptron Mk II (I’ve also mostly bowed out, in favor of another project or two).  However, I’m still rather interested in IR sensing in general.  There’s just something about having cameras that can see something humans can’t that makes me smile.

The goal wasn’t to see heat, but instead to see people.  Perceptron uses a video feed to detect people and their movement.  This is then fed into something that generates video, which we wanted to project onto a wall behind the person.  Now, most people-detection algorithms use motion detection as part of their process.  If you’re projecting a moving image up, then trying to find a person moving on top of that… it’s going to get really confused.  To get around this, I wanted to use an IR camera and flood the video display surface with IR light.

Getting the IR light is easy: remote controls use IR, so there are a lot of IR LEDs on the market.  A quick email to the noisebridge mailing list (“High-output IR LEDs?“), and I had a few suggestions for IR LEDs from Mitch Altman, the guy behind TV-B-Gone.  A quick mouser order and the IR light part was done, but where to get an IR camera?

Thankfully, most cheap webcams are actually sensitive to IR!  The technology they use to collect light for an image (charge-coupled devices, CCDs) is actually pretty sensitive to everything from IR to just above the visible spectrum.  If you don’t believe me, get out a digital camera, point a remote control at it and hit some buttons.  You should see a pink-ish flash from the LED on the front on the screen of the camera: that’s IR getting into the red-sensing bit of the camera.

So, we can use cheap webcams: great!  I have four of them just lying around, and between us, we had something like a dozen of them.  But allowing IR into a camera is problematic: it blows out the reds, so they put a filter in to stop it.  On nicer webcams, you can get in and remove that filter, but on the cheapest ones, it’s basically part of the sensor itself.  Did I mention that I had four cheap webcams?  To get four, they’re going to be real cheap.  So cheap that the filter is on the sensor itself.  They still see IR, but not very well: it gets drowned out by the visible light.  Admittedly, this is what most people want, but I found it rather frustrating.  To overcome this, you can put in a visible light filter, which blocks visible light, rendering the camera nearly blind.  You can use lots of things for this: exposed 35mm film, floppy disk material, etc, but they’re all a little hacky and fragile.  I wanted a proper filter, but real filters are damned expensive (and still a bit fragile, not something you want in a project that might wind up at Burning Man).

A week after the showing, Jean emailed me a link detailing how to use the Wii controller’s IR sensor to track IR points.  It isn’t quite what we want, but it made me realize something: the Wiimote is a great source of cheap, robust IR filters.  I have a couple Wiimotes lying around at home, so I ordered a tri-wing screwdriver from DealExtreme (85¢US, shipped, par avion, from Hong Kong) and tonight, popped open my second Wiimote.  The IR filter works stunningly, and now I have a dedicated “data acquisition device” Wiimote.  3-axis accelerometer, lots of buttons, and a light-source tracker that works in visible and IR now: this thing is quite great!

(The SICKmods Wiimote disassembly tutorial has good pictures of the disassembly process.  In particular, you’ll want to be careful with the two tabs at the top of the device.  I used my vinyl pry tools, part of the kit to change an original iPod battery… As for getting accelerometer, on linux, I’m using CWiid, but will just be using wmdemo to pipe data out for now.  There’s a gotcha with building it in its current state, documented in a bug report: hci_remote_name should be hci_read_remote_name.  The change described there worked for me.)

Hack of the day: LED HSV wheel

Thursday, May 14th, 2009

I recently worked on an art project called Perceptron, an interactive dance floor (it’s cool, check it out).  The kind folks at Langton Labs hosted our build process for a while, and it was there that I met the lamp of my dreams.

It was a sphere made out of pipette covers, which are a nice milky, translucent plastic, and diffuse light wonderfully.  In the center was an array of RGB LEDs, which would cycle through colors.  There were these gorgeous blues and reds in there that you just don’t see very often: they’re probably beyond what LCD technologies can produce, so it’s a redder red and a bluer blue than you’re used to seeing.

Tonight, while killing time waiting for something, I swung by my neighborhood Radio Shack and picked up an RGB LED.  When I got home, I plugged it into my arduino and got to hacking.  I now have a one-LED version of that lamp, which makes me really happy.  It’s a gorgeous thing to behold, and involves a fun little bit of code and math.  So, of course, I’m going to share it with you.

Color-wheel arduino video

To get the color transitions to be smooth, you can’t just ramp through levels of red, green, and blue: it winds up being a bunch of peaks and valleys.  Instead, you really want to go around the HSV color wheel, changing the hue as you go.  It generates a really smooth transition, which is most pleasant.  Unfortunately, due to how crappily I’m driving the LED, it’s not as smooth as it could be: the arduino has only so much resolution in how finely it can control the level of these LEDs.  This makes for a few little jerky transitions in the blue to red return.

Here’s the code, in full:

// This assumes you're using a RadioShack #276-0028 RGB LED
// 2011-05-12: Note!  The anode is the really long pin.
// You'll need to bend it to get it into Digital8.
//
//          ||  ||  ||  ||
//          ||  ||  ||  ||
//          ||  ||  ||  ||
//          G   B   ||  ||
//                  ||  R
//                   A
//         D11 D10 D08 D09 

int common_anode = 8;
int red_pin = 9;
int blue_pin = 10;
int green_pin = 11;

int red_min = 150;
int red_max = 255;

int blue_min = 185;
int blue_max = 255;

int green_min = 195;
int green_max = 255;

void hsv_to_rgb(float h, float s, float v, unsigned char *rc, unsigned char *gc, unsigned char *bc) {
int h_i = ((int)(h/60)) % 6;

float f = (h/60) - (int)(h/60);

float r,g,b;

float p = v * (1.0 - s);
float q = v * (1.0 - f*s);
float t = (1.0 - (1.0 - f)*s);

switch(h_i) {
case 0:  r = v; g = t; b = p; break;
case 1:  r = q; g = v; b = p; break;
case 2:  r = p; g = v; b = t; break;
case 3:  r = p; g = q; b = v; break;
case 4:  r = t; g = p; b = v; break;
case 5:  r = v; g = p; b = q; break;
}

*rc = red_max - (char)((red_max - red_min)*r);
*gc = green_max - (char)((green_max - green_min)*g);
*bc = blue_max - (char)((blue_max - blue_min)*b);
}

void setup() {
pinMode(common_anode, OUTPUT);
digitalWrite(common_anode, HIGH);

pinMode(red_pin, OUTPUT);
digitalWrite(red_pin, HIGH);

pinMode(green_pin, OUTPUT);
digitalWrite(green_pin, HIGH);

pinMode(blue_pin, OUTPUT);
digitalWrite(blue_pin, HIGH);

Serial.begin(9600);
}

float h = 0.0;
float s = 1.0;
float v = 0.8;

void loop() {

unsigned char r,g,b;

h += 1;
if (h > 360.0)  h -= 360.0;

hsv_to_rgb(h,s,v, &r,&g,&b);
analogWrite(red_pin, r);
analogWrite(green_pin, g);
analogWrite(blue_pin, b);

delay(100);
}