Spinning Knobs: Custom Rotary Encoders

For this project, I wanted a device that wasn’t an absolute mapping of position to color amount. I didn’t want a strict teaching device, but more of a fun color exploratory toy, able to be spun like mad by kids.

Rotary encoders are used to measure rotational amount and direction. You can find them in “infinite rotation” knobs, computer mice, robots, and lots of other things. They’re a good solution for user interface input devices when you want to make relative adjustments to a value, rather than absolute positioning (where a pot would work well). Wikipedia’s “rotary encoder” entry is a pretty good explanation of the various types of encoders. Wikipedia mentions absolute positioning encoders, a much rarer and more expensive type. Most all rotary encoders you’ll encounter are the relative positioning type. There are two main classes of relative rotary encoder implementations: mechanical and optical. Both make electrical signals when the encoder is rotated. Mechanical uses tiny electrical wipers to produce them. An optical encoder uses an optical interrupter, consisting of a light beam and light sensor.

I experimented with mechanical encoders but they had a lot of friction and their pulses-per-revolution were fairly low (12-24). I wanted a low-friction, high-resolution encoder. For low-friction this meant an optical encoder, and for high-resolution this meant a large encoder disk (since I was using fairly large optical interrupters).

To sense the slots in the disk, standard H21A1 optical interrupters are used. These optical interrupters are simply an IR LED (”emitter”) and an IR phototransistor (”detector”) in a single package, pointing at each other. Breaking or unbreaking the beam creates a signal you can measure. If you hook them up, you can see the IR LED using a digital camera:


You can see the “E” and “D” markings for “emitter” and “detector” above.

A single interrupter can measure speed of rotation by counting pulses. It can’t measure direction of rotation. But by using two interrupters and “quadrature encoding” (two output signals offset by 90º), you can measure both. The spacing between the slots, the spacing between the interrupters, and the aperture width of the LED emitter are interrelated in order to get proper quadrature output. Hopefully I’ll have a subsequent blog post describing this in more detail. :) To decode quadrature encoding, pick one of the two signals (call them “A” and “B”): when A goes HIGH, measure B. The value of B gives the direction of rotation. By counting the number of times A goes HIGH, you know how much rotation is happening. In the diagram below, follow the two signals as rotation happens either clockwise (to the right in the diagram) or counterclockwise (to the left)

Building the Knobs

The knobs are constructed out of PVC drainage caps, laser cut acrylic for hubs & diffusers, rollerblade bearings to give a smooth spin, 5/16″ bolts to act as axles, hot glue to put it all together, and a plywood base. The black, slightly rubbery texture was from the spray-on form of PlastiDip.

My good friend Ben Franco helped prototype many iterations of the physical design of the knobs, until we came upon the final result. He was the one who recognized that the diameter of 5/16″ nuts was just perfect enough to grasp the inner ring of a rollerblade bearing. So a 5/16″ bolt through the center of the bearing becomes the axle and the outer ring of the bearing can be attached to a stationary base, giving a smoothly spinning knob.

Rotary encoder Arduino code

When reading rotary encoders, it’s useful to think of the two signals coming out of it as a “clock” and a “data” signal. It doesn’t matter which one you treat as which, as it’s the interrelationship between the two that matters. Usually you’d use interrupts to handle reading encoders because it makes it very simple: on interrupt of the “clock” signal, read the “data” signal, and its value gives you the rotation direction. On Arduino we’ve only got one interrupt and three knobs, so polling is easier. I started with the a really good Arduino playground rotary encoder polling example and then went from there.

The relevant parts of the BlinkMCylon code for dealing with rotary encoders is below. It’s almost encapsulated enough to be a library. The “knobs” data structure contains a list of “knob” data structures, which in turn is just a holder for which pins the knob is connected to, what the last value was of that knob’s clock pin, and its current rotation value.

The “knobs_init()” function sets up the pins correctly, and by calling “knobs_poll()” as fast as possible, you can read many knobs fairly accurately.

typedef struct _knob {
    uint8_t clkpin; uint8_t datpin; uint8_t clklast; uint8_t val;
} knob;
knob knobs[num_knobs] = {
    { 2,3, 0, 0},    // first knob on pins 2 & 3
    { 4,5, 0, 0},    // second knob on pins 4 & 5
    { 6,7, 0, 0},    // third knob on pins 6 & 7
};

static void knobs_init(void)
{
    for( int i=0; i<num_knobs ; i++ ) {
        pinMode( knobs[i].clkpin, INPUT );
        pinMode( knobs[i].datpin, INPUT );
        // turn on internal pullup resistors so we don't need external ones
	digitalWrite( knobs[i].clkpin, HIGH);
        digitalWrite( knobs[i].datpin, HIGH);
    }
}

// this function must be called as quickly and as regularly as possible
static void knobs_poll(void)
{
    byte c,d;  // holder for readings
    for( byte i=0; i<num_knobs; i++ ) {
	knob k = knobs[i];           // get a knob
	c = digitalRead( k.clkpin ); // read its pins
	d = digitalRead( k.datpin );
	if( c != k.clklast  ) {      // look for clk line transition
            d = c^d;                   // xor gives us direction
	    if( d ) k.val++;           // non-zero means clockwise rotation
	    else k.val--;              // zero means counter-clockwise rotation
	    k.clklast = c;             // save the clk pin's state
            knobs[i] = k;              // save our changes
	}
    }
}

Resources & Links

Other info:

Get on the BlinkM Bus with a BlinkM Cylon

BlinkMs are a lot of fun by themselves, but they’re also little network devices, each having its own address on an I2C network. Here’s where I think BlinkM can really shine since it makes controlling multiple RGB LEDs pretty easy. For Maker Faire, I wanted to show off this facet by having a single Arduino control a dozen or so BlinkMs on a single I2C bus. The result is shown in the little video below.

Read on for how this was put together.

Continue reading “Get on the BlinkM Bus with a BlinkM Cylon”

FunGizmo’s colorful tiny breadboards

I just received some colorful tiny mini-breadboards from FunGizmos.com. They are pretty great. Now quickie ideas prototyped with Arduino can be even smaller than the “1¢ Arduino under-shield”.

They appear to be the same quality as the other breadboards I have, just different color plastic. I can already tell the colors will help me differentiate projects, which all tend to look alike from 10 feet away. Normally when you buy these from Digikey or similar places, these little ones cost $7 a piece. FunGizmos has them for $5.40. And that’s cheap enough to get a few. Note that all these tiny breadboards don’t have the side power busses like the larger breadboards do. That’s the price you pay for tininess.

“WiiChuck” Wii Nunchuck Adapter Available

Want to hook up a Wii Nunchuck to an Arduino but don’t want to cut up the cord on your Nunchuck? Yeah me too. So I made some of these:

wiichuck_adapter1.jpg

wiichuck_adapter2.jpg

It’s a small PCB that adapts the Wii Nunchuck connector to standard 4-pin header. I call it the “wiichuck adapter”. It plugs directly into the Arduino, no wiring necessary. You can get one too for $4.

Available from the following wonderful shops:
FunGizmos.com. FREE DOMESTIC SHIPPING. International shipping for $1 more.
Little Bird Electronics (Australia)
SparkFun. Ships domestic & internationally. Be sure to order header pins too!
– and just about any SparkFun distributor

Continue reading ““WiiChuck” Wii Nunchuck Adapter Available”

Bezel for Sparkfun’s “Monome-like” Button Pad


sparkfun-buttonbezel1.jpg

This is a laser-cut acrylic bezel for Sparkfun’s Monome-like Button Pad PCB and Button Pad. These 4×4 Button Pads are great: big chunky buttons with a PCB that can take an RGB LED. JMG is making a “monomuino”, a Monome work-alike using this pad and an Arduino. And he’s extending the Monome functionality since his indicator lights can display 3 dimensions of data instead of the normal 1 of Monome.
Continue reading “Bezel for Sparkfun’s “Monome-like” Button Pad”

BlinkM Hello, Video Guides, Example Code

This is a BlinkM:

BlinkMs are “smart LEDs”, a type of smart interface component. A BlinkM consists of an ultrabirght RGB LED backed with a microcontroller with built-in knowledge about 24-bit color spaces, color fading, and color pattern generation. All in a package 0.6” wide. You talk to it over I2C, a serial protocol spoken by many different things. (Arduino speaks it, as do Basic Stamps, and your PC) And you can have over 100 BlinkMs on the same serial bus, each individually addressable. Here’s how they can hook up to an Arduino:

BlinkMs are available from SparkFun (US) and Little Bird Electronics (AU). It’s hard to show in just static pictures how fun and easy it is to play with BlinkMs, so here’s a few quick video guides.

Video Quick Start Guide

A video version of the BlinkM Quick Start Guide.

Playing with BlinkMTester

A demonstration of one of the example Arduino sketches “BlinkMTester”, which lets you exercise a BlinkM by typing simple commands to the Arduino.

Exampe Code

There are a couple of examples of how to talk to BlinkMs all zipped up in BlinkM_Examples.zip. You can also peruse them unzipped if you like. The examples are predominately for Arduino currently, but any I2C master will work. Some of the examples so far:

  • BlinkMCommunicator
    A simple serial-to-i2c gateway for PC controlling of BlinkM (for instance via Processing or the BlinkM Sequencer)
  • BlinkMTester
    A general tool to play with a single BlinkM
  • BlinkMMulti
    An example showing how to communicate with multiple BlinkMs
  • BlinkMScriptWriter
    A demonstration of how to write BlinkM light scripts with Arduino
  • BlinkMChuck
    Control the hue & brightness of a BlinkM with a Wii Nunchuck

More examples will be added periodically.

For the Arduino examples, a convenience library called BlinkM_funcs.h has been created. Just drop this .h file into your sketch folder and call the functions to start playing with BlinkM.

The complete list of functions is below, though you’ll probably only use a few of them for a particular project.

BlinkM_begin();
BlinkM_beginWithPowerPins(byte pwrpin, byte gndpin);
BlinkM_beginWithPower();
BlinkM_sendCmd(byte addr, byte* cmd, int cmdlen);
BlinkM_setAddress(byte newaddress);

BlinkM_setFadeSpeed(byte addr, byte fadespeed);
BlinkM_setTimeAdj(byte addr, byte timeadj);

BlinkM_fadeToRGB(byte addr, byte red, byte grn, byte blu);
BlinkM_fadeToHSB(byte addr, byte hue, byte saturation, byte brightness);
BlinkM_setRGB(byte addr, byte red, byte grn, byte blu);

BlinkM_fadeToRandomRGB(byte addr, byte rrnd, byte grnd, byte brnd);
BlinkM_fadeToRandomHSB(byte addr, byte hrnd, byte srnd, byte brnd);

BlinkM_getRGBColor(byte addr, byte* r, byte* g, byte* b);

BlinkM_playScript(byte addr, byte script_id, byte reps, byte pos);
BlinkM_stopScript(byte addr);
BlinkM_setScriptLengthReps(byte addr, byte script_id, byte len, byte reps);
BlinkM_writeScriptLine(byte addr, byte script_id, byte pos, byte dur,
                                byte cmd, byte arg1, byte arg2, byte arg3);
BlinkM_writeScript(byte addr, byte script_id, 
                          byte len, byte reps,   blinkm_script_line* lines);

And More

For more information, including a datasheet, example code and sequencer application for Mac/Windows/Linux visit blinkm.thingm.com.

If you want to talk about BlinkM, leave a comment or participate in discussions on ThingM’s Satisfaction page.

WineM lights, a BlinkM predecessor

With BlinkMs available for purchase soon, I figured it would be neat to show what a large collection of them can do. BlinkMs were created from my desire to have a “smart LED” that did its own tri-color PWM. I didn’t want to build a real-time system to control the PWM of several hundred RGB LEDs. And existing LED controllers didn’t meet my needs. I wanted something that knew a bit about color and color patterns and could be networked together into clusters. Thus BlinkM. A single BlinkM is fun, but the real utility is seen when you have several of them on the same I2C network.

Below are two movies of the lighting system in WineM, our smart RFID winerack. Each place a bottle goes contains a essentially BlinkM and RFID reader controlled via an I2C master.

WineM prototype at NextFest


This video shows WineM in use. A handheld web device allows one to select and display different facets of the wine collection. In the video, first all wines are shown, colored by varietal, then Cabernet wines are selected. Within the Cabernets, color them by year. Select 2002 as the year and only the 2002 Cabernets are shown. Then color those by price. Finally, select the 2002 cabernets that are between $20-$30. You’re left with the perfect wine for tonight’s meal. Also shown is the visual indication when bottles are added or removed.

WineM prototype light tests


This is just a light show using the WineM lights. It was taken right after I had assembled and installed everything in the rack. Apologies for the exposure fluctuations.

For a bit more detail on the WineM prototype hardware, see this post.