Tutorials‎ > ‎

Rotary Encoders

posted Dec 30, 2013, 10:46 PM by Sean M. Messenger   [ updated Apr 6, 2014, 3:57 PM ]

Background

I recently worked with encoders for the umpteenth time on a project and decided it was high time to write up a reference for future use. The basic principle of encoders are simple, and I give several diagrams that make their functionality more straight forward. 

The below image shows a case where I needed to measure the speed a motor had a shaft spinning at, since the shaft won't necessarily turn at 60 RPM given a signal that we would expect to correlate to 60 RPM. This could be because our correlation between signal and speed is off or there is some outside factor affecting it (i.e., torque). We want to measure the speed of rotation, which can be done using an encoder.

Block diagram of encoder implementation in Filament Winder Project.

An encoder tracks the change in (angular) position of a shaft, and this change in position can be used to find the (angular) velocity. Velocity is change in position over time. I will be ignore the "angular" distinction, as all positions and velocities we are concerned with are, in fact, angular.

There are many different kinds of encoders, but I keep finding myself come back to optical quadrature rotary encoders because of their low cost, relatively high accuracy, and ease of use. There are Hall-effect rotary encoders, absolute encoders, binary encoders, et cetera.

Functionality

Rotary encoders track the change in position by looking at slits on a disk. There are variations on this, but for our consideration there are evenly spaced slits on a disk attached to the shaft in question. 

Quadrature encoder (6 P/R) showing two 90 degree out-of-phase rings.[2]

The image shows a simple encoder disk. You can see the rings are 90 degrees out of phase, and this allows the determination of direction. This is a 6 Pulse per Revolution (P/R) encoder. Two sensors read these disks and output as Channel A and Channel B. If a black region is in front of the sensor, the signal goes low (and vice versa).

Phase transition diagram.[1]

The phase transition diagram shows that if both A and B are low, the sensors are both over black/opaque regions. You can tell that if A goes high, then the disk is rotating in one direction whereas if B goes high it rotates in the other direction. This is a benefit of quadrature encoders -- they let you determine direction of rotation without tracking absolute position.

Finite State Machine for encoder state transitions.

The encoder can be modelled as a finite state machine, where these transitions change what state the encoder is in. A transition between any two states is called an encoder tick. Positive would be, say, clockwise whereas negative would be counterclockwise. If the state machine jumps from state S1 to S2 by having A go high and then back to state S1 by A going low, it makes since that there has been no total rotation. The increment in encoder tick is offset by an immediately following decrement. By tracking these encoder ticks, one can determine the relative change in position of the shaft.

Encoder Module - Considerations

As discussed, quadrature rotary encoders output on two channels -- A and B. A module can take these as input along with a clock signal to provide an output encoderTick. This counter can be used in whatever application and for any further analysis, such as determination of velocity. 

Encoder black box module showing inputs and outputs.

There are many ways to calculate the encoderTick output. A simple one without error handling is presented here. This is sufficient under two conditions:
  1. A state transition is not missed
  2. The signal is debounced or debouncing is not necessary
The first condition is satisfied when the clock speed is significantly faster than the encoder transitions. A reasonable encoder to consider is a 1024 P/R quadrature optical encoder. This means there are 1024 pulses per revolution or 4096 unique states per rotation. This gives a resolution of 360 degrees/4096 = 0.1 degrees. In order for the module to not miss a state transition, you need to be able to check the states at least as fast as a state transition would happen. So, the minimum clock frequency f to handle a rotation speed of X revolutions per second is,

f = (X rev/s)  *  (4096 transitions / rev) = (4096 X) Hz

We can consider a reasonable 10 MHz clock cycle such 

X = (10 MHz) / (4096 Hz) = 2400

At this clock speed, we could handle up to 2400 revolutions per second or 144,000 RPM. For some perspective, the fastest motors I have dealt with run at 14,000 RPM and much more reasonably would be hundreds RPM. Most clock speeds are also faster than 10 MHz, but we can see that the state transitions should accurately be tracked with current hardware.

For the second condition, we are satisfied with optical encoders not requiring debouncing. As a topic for another discussion or further research, mechanical encoders require it whereas optical ones don't. Optical encoders are much more popular and readily available, but this is something to be aware of.

Encoder Module - Implementation

Our applications are typically not pushing the limits of the hardware and we have considered clock frequency. To simplify the logic, we can reduce the state machine down to a basic transition counter. We will continuously sample on the clock frequency as opposed to the rising or falling edge of either input channel logic. When the state increases, add one to the encoderTick. When it decreases, subtract one. We know that the signals should never jump a state, as the clock is fast enough to handle this. Our implementation did not have error handling. Here is SystemVerilog code that increments and decrements appropriately, inspired by Joshua Vasquez[3]:

module Counter(input logic A, B, clk, reset,
               output logic [13:0] count);
               
  // Parameterization of possible states: equivalent to {A,B}.
  localparam S1 = 2'b00, 
             S4 = 2'b01, 
             S2 = 2'b10, 
             S3 = 2'b11;
  // Registers to store state values.
  logic [1:0] currState, prevState;
  // State register.
  always_ff@(posedge clk) begin
    prevState <= currState;
    currState <= {A,B};
  end
  // Output logic.
  // Compute on negative edge to avoid metastability.
  always@(negedge clk) begin
    if (reset)
      count <= 14'b0;
    else
      case ({prevState, currState})
        {S1, S4}:  count <= count + 1; 
        {S2, S1}:  count <= count + 1;
        {S3, S2}:  count <= count + 1;
        {S4, S3}:  count <= count + 1;
        {S1, S2}:  count <= count - 1; 
        {S2, S3}:  count <= count - 1;
        {S3, S4}:  count <= count - 1;
        {S4, S1}:  count <= count - 1;
        default:   count <= count;
      endcase
  end
          
endmodule

And that's it. Since the logic is so simple, skipping the state machine altogether is entirely possible. Note that the output encoderTick will still have rollover issues, which must be handled by whatever uses the encoder ticks.

Funding for this project was provided by Harvey Mudd College's Fab Studio and Harvey Mudd College's Engineering Department.

References
[1] Wikipedia, https://en.wikipedia.org/wiki/Rotary_encoder
https://github.com/Poofjunior/SynchronousQuadratureEncoder