A rotary encoder converts angular position to an analog or digital code.

This page will deal a specific type of incremental rotary encoder - an optical quadrature encoder, which is very popular tool for determining how much a wheel has rotated and thus how far something, such as a robot, has moved.

An optical encoder consists of a disc with alternating areas of reflection and non-reflection. An emitter and receiver such as an LED and photodiode read the resulting optical pattern from the position of the optical encoder.

An incremental encoder has no knowledge of its absolute position and is simply able to count pulses which can be used to update a position in external electronics.

For the rest of this page, the phrase "quadrature encoder" will be used to mean "optical quadrature encoder".

Quadrature Encoder

A quadrature encoder consists of a disc with two tracks, containing alternating areas of reflection and non reflection, 90 degrees out of phase.


As it rotates in front of an emitter/receiver pair for each track (which we will call channel A, and channel B), it will produce the following results.


There are four distinct states that can be achieved with this disc, which are gray codes. Each time there is a valid state change, the pulse count is incremented, or decremented depending on the direction. A state change is only valid if only one of the tracks has changed. If both tracks change at the same time the state change is invalid.

Clockwise rotations

PhaseChannel AChannel B

Counter clockwise rotations

PhaseChannel AChannel B


The QEI library uses X2 encoding by default, which looks at the state every time a rising or falling edge occurs on channel A. It can also use X4 encoding which looks at the state every time a rising or falling edge occurs on channel A or channel B. After each rising or falling edge the pulse count is updated appropriately, depending on the direction of rotation.

Channel A and channel B are used as InterruptIn pins to ensure as few pulses as possible are missed that might cause invalid state readings or an incorrect count, which could be the case if polling was used.

An optional index channel is available which is essentially a third track on the disc which has one pulse per revolution. Thus it can keep track of the number of revolutions of the disc.

After creation of a QEI object, any change in the position of the encoder wheel will cause an update of the internal pulse count. The library methods can be used to find out what the current pulse count is (which with supporting code can be used to determine absolute position) and reset the pulse and revolution count.

The current state of the encoder can also be queried, but it is there purely for convenience - most, if not all users will not require this method.

It should be noted that the internal revolution count is only updated by the index channel. If no index channel is used, it is still easy to work out the current revolution count by dividing the pulse count by number of pulses per revolution for the disc, but this must be done in external code.

Interrupt Latency

As this library uses to interrupts to determine the pulse count, there is an upper limit on the number of pulses per second it can detect, which is dependent on the time it takes to service the interrupt.

The interrupt handler takes 2 microseconds to service, which means the library can deal with edges on the InterruptIn pins at frequencies of up to 500kHz, which equates to 500,000 pulses per second.

Hello World!

Import program

00001 #include "QEI.h"
00003 Serial pc(USBTX, USBRX);
00004 //Use X4 encoding.
00005 //QEI wheel(p29, p30, NC, 624, QEI::X4_ENCODING);
00006 //Use X2 encoding by default.
00007 QEI wheel (p29, p30, NC, 624);
00009 int main() {
00011     while(1){
00012         wait(0.1);
00013         pc.printf("Pulses is: %i\n", wheel.getPulses());
00014     }
00016 }


Import library

Public Member Functions

  QEI (PinName channelA, PinName channelB, PinName index, int pulsesPerRev, Encoding encoding=X2_ENCODING)
void  reset (void)
  Reset the encoder.
int  getCurrentState (void)
  Read the state of the encoder.
int  getPulses (void)
  Read the number of pulses recorded by the encoder.
int  getRevolutions (void)
  Read the number of revolutions recorded by the encoder on the index channel.


Although this page has dealt primarily with optical quadrature encoders, the interface will deal with any encoder that provides quadrature outputs. These include the Pololu Encoder and this DC Gearhead Robot Motor which has a built in quadrature encoder.

Alternatively you can make your own with a pair of QRD1114 IR sensors, and an encoder disc which you can generate and then print using this useful online tool.

By lining each QRD1114 up with each track of the encoder disc, you have a very cheap and reliable quadrature encoder which can be used to accurately determine the position [from a set starting point] of a wheeled object.


Import libraryQEI

Quadrature encoder interface library.