30% off your first 3 months

Get the deal

Add wheel encoders and measure distance

by DuckyHelperNov 12, 20264 min read
Robotics

TL;DR:

  • An encoder turns wheel rotation into pulses. Count the pulses, multiply by the distance one pulse represents, and you know how far the wheel rolled.

  • For a 65 mm wheel with 20 pulses per turn, one pulse is about 10.2 mm, so one meter is about 98 pulses.

  • Measure the real distance once and correct the numbers. A small error in wheel size becomes a visible error in distance.

A robot that drives for two seconds does not drive a fixed distance. A fresh battery, a carpet, a slight slope: each changes how far two seconds takes it. If you want it to go exactly one meter, it has to count how far its wheels have turned, and an encoder is the part that does the counting.

What you will build

You will add one encoder to each drive wheel of a small two-wheel robot, count the pulses on a microcontroller, convert them to meters, and make the robot drive one meter and stop. Then you will measure what it really did and calibrate. The same counting idea sits underneath odometry, the way mobile robots estimate where they are.

Parts and tools

  • A two-wheel robot base with a microcontroller board such as an Arduino-compatible board, and a motor driver you already know how to use

  • Two encoders: either slotted-disc encoders (a plastic disc with slots that passes through a small optical sensor) or magnetic encoders built into geared motors

  • Jumper wires and a breadboard

  • A tape measure and masking tape for start and finish lines

  • A battery pack suited to your motors, with a switch

Wiring and assembly

A slotted-disc encoder has three pins: power, ground and signal. The signal goes from low to high each time a slot passes the sensor. Mount the disc on the wheel axle (or on the motor shaft, if you know the gear ratio) so it turns with the wheel, and make sure it passes through the sensor gap without rubbing.

Connect the signal pin to a pin that supports interrupts. On many Arduino-style boards that is a small set of specific pins, so check your board's pin chart. An interrupt lets the board count a pulse the instant it happens, even while the main loop is busy driving the motors.

Note: A single signal wire tells you how many pulses happened, not which way the wheel turned. For driving forward that is fine. If the robot will also reverse, either keep track of your own commanded direction or use a quadrature encoder, which has two signals offset from each other so the order of the edges gives the direction.

Worked example: from pulses to one meter

Say the wheel diameter is 65 mm and the disc has 20 slots, so you get 20 pulses per wheel turn. Work out how far one pulse represents.

  1. Circumference: π × 65 mm ≈ 204.2 mm.

  2. Distance per pulse: 204.2 mm ÷ 20 ≈ 10.21 mm.

  3. Pulses for one meter: 1000 mm ÷ 10.21 mm ≈ 97.9, so stop at 98 pulses.

Check it backwards: 98 × 10.21 mm = 1000.6 mm, which is within a millimeter of the target. One pulse is the finest step you can see, so the best you can do is about ±10 mm. Reading both edges of every slot would halve that step, at the cost of counting twice as fast.

The code, step by step

Keep the counting in a tiny interrupt routine and do everything else in the main loop. Variables shared with an interrupt must be marked volatile, otherwise the compiler may cache an old value.

volatile long ticks = 0;
const int ENC_PIN = 2;        // an interrupt-capable pin
const long TARGET = 98;       // pulses for 1 m

void onTick() { ticks++; }

void setup() {
  pinMode(ENC_PIN, INPUT);
  attachInterrupt(digitalPinToInterrupt(ENC_PIN), onTick, RISING);
  // start motors forward here, at a gentle speed
}

void loop() {
  noInterrupts();
  long t = ticks;      // copy safely
  interrupts();
  if (t >= TARGET) {
    // stop both motors here
  }
}

The copy inside noInterrupts() matters: a long is read in several steps on a small board, and an interrupt in the middle could hand you a half-updated number. Drive both wheels and compare their counts; the difference is also your first clue to why a robot curves.

Test, measure and fix

Put tape at the start and mark the front of the robot. Run the program three times and measure the stopping distance from the same point on the robot each time. Suppose all three runs end at about 1040 mm.

  1. The robot thought it traveled 1000 mm but really traveled 1040 mm.

  2. Correction factor: 1040 ÷ 1000 = 1.04.

  3. Effective distance per pulse: 1040 mm ÷ 98 ≈ 10.61 mm.

  4. Equivalent wheel diameter: 65 mm × 1.04 = 67.6 mm. Check: π × 67.6 ÷ 20 ≈ 10.62 mm, matching.

A real wheel is slightly larger than its bare plastic because of the tire, and it squashes under weight, so the effective diameter is usually not the number on the packaging. Put the measured 10.61 mm into your code and repeat the test. If the three runs agree with each other but not with the target, it is a calibration problem. If they disagree with each other, look for slipping wheels or a loose disc.

Make it better

  • Add a gentle speed ramp near the end so the robot does not overshoot when it stops.

  • Use both encoders and average them for distance.

  • Add a rule that stops the robot if the count has not changed for half a second, which means a wheel is stuck.

  • Turn on the spot by driving the wheels in opposite directions until a counted distance is reached.

Stay safe

Lift the robot so the wheels are off the table for your first power-up, so a bug does not send it off the edge. Keep fingers away from the wheels and any gears. Switch off the battery before you change wiring.

Frequently asked questions

Why does my count jump when the motors start?

Electrical noise from the motors can add false pulses. Keep encoder wires away from motor wires, add a small capacitor across the motor terminals, and make sure the grounds share one point.

Can I use the encoder count to know where the robot is?

For short runs, yes, with the caveat that wheel slip adds error that never goes away. Over a longer run you need another sensor to correct it.

Get started

DuckyHelper can
do more

It sees your screen and works in any app you use. Try it for 10 minutes, no card.

Get it for Mac, Windows or Linux

Share

Questions and jobs

Do anything

Ask it a question or hand it a job, in any app.

Doing jobs for you is in early access on Mac. Asking works on Mac, Windows and Linux.