Thursday, March 6, 2014

Rotary encoders are commonly used for measuring angular position or motion sensing. An optical encoder has a disc with a pattern of cutouts. As the disc rotated, an LED light that shines on photo detector is turned on and off accordingly to produce a digital waveform.

An optical encoder produced by VEX Robotics Design System

Gray code is normally used in encoders instead of ordinary binary code to prevent glitches. In Gray code, the number of changing bits between successive numbers is only 1. The following table shows 2 bit Gray code from 0 to 3.

Gray code
Number 2-bit Gray Code
0 00
1 01
2 11
3 10

Encoders typically have two outputs called A and B. When it is turned clockwise, the waveform as shown in the following figure is produced. Its phase increases from 0 to 3. When it is turned counter-clockwise, the output phases are produced in reverse order.

I have found several example programs in the Internet to read an encoder from a microcontroller. But I think, those programs are long and inefficient. The program presented here is simple, short and efficient. The resulting resolution of the program is 4 times the pulses per revolution of the encoder.

I use the state machine design. I define the output phases of the encoder 0, 1, 2 ,and 3 as states - s0, s1, s2, and s2 respectively. Then, the counting of the encoder states is shown in the following table.

Counting encoder states
Next state Present state Count
s0 s0 No change
s0 s1 Down
s0 s3 Up
s0 s2 Don't care
s1 s0 Up
s1 s1 No change
s1 s3 Don't care
s1 s2 Down
s3 s0 Down
s3 s1 Don't care
s3 s3 No change
s3 s2 Up
s2 s0 Don't care
s2 s1 Up
s2 s3 Down
s2 s2 No change

When the states are replaced by the corresponding binary bits, the following truth table is obtained.

Truth table
Decimal number Next state - Present state Up Down
0 00 00 0 0
1 00 01 0 1
2 00 10 1 0
3 00 11 0 0
4 01 00 1 0
5 01 01 0 0
6 01 10 0 0
7 01 11 0 1
8 10 00 0 1
9 10 01 0 0
10 10 10 0 0
11 10 11 1 0
12 11 00 0 0
13 11 01 1 0
14 11 10 0 1
15 11 11 0 0

By considering next state and present state in the truth table as binary code, it is counting up at 2, 4, 11, and 13. Similarly, it is counting down at 1, 7,8, and 14. An array can be declared to represent the truth table as follows.
 int En_TruthTable[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};


Arduino UNO single board microcontroller and an optical shaft encoder from VEX Robotics Design System are used in this example.

In our circuit, pin 9 of the microcontroller is connected to channel A of the encoder and pin 10 is connected to channel B. The code to get the next state (NS) from the bitwise reading of channel A and channel B is shown below.
  NS = (digitalRead(pinA)<<1) | digitalRead(pinB);


As we turn the shaft, the encoder produces a series of digital pulses and the microcontroller has to constantly check and update the position everytime the next state (NS) is different from the present state (PS). If c is a variable to keep track of the encoder position, its values should reach back to zero when the encoder has been turned a complete revolution. The number of state changes for one revolution (SPR) is four times the pulses per revolution (PPR) of the encoder (SPR = 4 . PPR) .
c=(c+En_TruthTable[(NS<<2)|PS]+SPR)%SPR;

The angle (a) that corresponds to c in degree ( 0 ≤ a < 360 ) is calculated as follows.
a =  c * 360.0  / SPR

Similarly, the angle (b) n degree ( -180 ≤ a < 180 ) can be calculated from the angle (a).
b =  a - floor(a/180)*360.


An example program is available at Rotary Encoder using Arduino to get absolute value (on GitHub).

Arduino software (IDE) is available for free and I found it very easy to use. In my case, after I have chosen the correct board and correct COM port in the "Tools" menu, it worked without any problem.