I wanted to attach a knob to my Raspberry Pi to act as a volume control for my MPD based jukebox. Traditionally volume control devices are implemented with potentiometers acting as inputs for amplifiers. A potentiometer is a hardware device with a knob or a slider that, in a word allows for a variable voltage input into a circuit. 1 The problem here is that this is a very hardware oriented method of setting volume, when what I really wanted to do was set the software volume setting on the Raspberry Pi. I wanted to be able to change the volume from the operating system (a la alsamixer) or through the MPD client, and still be able change it up or down by physically turning the knob on the device. Essentially, I wanted the ALSA PCM element volume to increase as I turned the knob clockwise, and decrease as I turned the knob counterclockwise, I wanted to actual volume to be independent of the position of the knob and because a potentiometer is an absolute input device which returns it’s position and cannot be turned indefinitely there was no way to make one work for what I needed.
What I needed was a rotary encoder. A rotary encoder, is in essence a pair of switches which change as a shaft is turned, and by reading those switches, one can tell whether and in which direction the shaft is turning. A rotary encoder cannot tell absolute position, but it doesn’t need to, plus it can spin infinitely.2 This, of course, was exactly what I needed. Unfortunately there isn’t a lot of information on getting a rotary encoder working with a Raspberry Pi.
I did some research and found a number of articles about getting a rotary encoder to work with an Arduino. This code could be adapted to the Raspberry Pi, but it’s important to note that an Arduino has a real-time operating system (that is, it has almost no operating system) so programs can execute without the unpredictable delays of time-sharing/multitasking, buffering, or garbage collection. The Raspberry Pi is a Linux machine, which is a time-sharing system, so it can’t make guarantees to the millisecond about performance the same way an Arduino can. This can be a problem because to properly read a rotary encoder, a program needs to track every change of the switches, else one could get backward or confused readings.
Fortunately this is a solvable problem. The Raspberry Pi has interrupts, which allows us to trigger functions upon switch reading changes, and the wiringPi library makes it easy to use them. So, here’s what I ultimately did:
Connecting a rotary encoder couldn’t be much simpler. Rotary encoders only have three pins.3 The middle pin is ground and the others are connected to the switches and produce the A signal and B signal respectively. You can connect these pins to the Raspberry Pi directly. Rotary Encoder pins:
And how to connect it to the Raspberry Pi:
Using the built in pull-up resistors on the Raspberry Pi for the pins connected to A and B means that when the respective switches are closed, the pins will read low (0) and when the switches are open, the same pins will read high (1). There’s no need for any additional resistors or capacitors. As the encoder shaft is turned, the switches will alternatively open and close so that they progress through a series of states known as Gray Code. These states are as follows:
00, 01, 11, 10
By reading any two successive states, one can tell which direction the encoder is turning. 00->01 might be clockwise while 00->10 might be counter-clockwise. Using interrupts, we can get the Pi to record each change of a pin and to record the direction the encoder is turning.