Measurement Precision versus Control Precision

Spent some time today chasing down a problem that’s probably obvious to experienced developers, but it wasn’t to me, and I’ll guess to other newcomers.  There’s obviously a limit to both the position and heading precision that can be obtained purely through odometry based on wheel encoders.  For distance traveled in a short delta of time, the precision is a function of the smallest fraction of wheel rotation you can measure and the wheel diameter.  For heading, it’s also a function of the wheelbase (the distance between the wheels on each side).  The heading precision tends to be much poorer than the distance.   For example, if I can measure 1/8th of a revolution of a 1″ diameter wheel, I can measure increments of 1/8 x pi x 1 = 0.39 inches.  If the wheelbase is 4 inches, and I’m using tank style steering, then the smallest heading increment I can measure is pi * ( 1/8 * 1) / 4 = 0.098 radians or about 5.6 degrees.  That lack of precision is one factor in the errors that can build up very quickly when making a number of turns.  (Slippage can also be a major contributor to the error).   [The Using Dead Reckoning section in Enabling Your Robot to Keep Track of It’s Position from Ridgesoft has a good explanation of this]

When trying to use dead reckoning to turn, you typically can’t get the measured heading to exactly match the desired heading due to these precision limits, so you have to set a window defining “close enough.”  So far, so good.  In my case, I’m using interrupts to count clicks on each of two wheel encoders, so I could be sure not to miss a unit.  All was working well.  In tests, I’d see 0 or 1 click of the encoder on each wheel each time my Arduino code executed the main loop and updated the position and heading.  I set my “close enough” threshold accordingly.  Then I added doubled the resolution on the encoders and added a lot of serial.print() commands when in debugging mode.  Suddenly my formally working robot, which now had more precise navigation, would go haywire.  It would often work fine, but at other times it would spin around in multiple circles when turning to the next waypoint or avoiding an obstacle.

It took a lot of debugging to figure out the problem. With interrupts now occurring with twice the frequency, and the execution loop slowing down due to numerous serial print statements, there were often 3-4 encoder clicks per update.   This meant that the robot was sometimes turning 4x more than the maximum precision of my measurements between execution of the appropriate code in the main loop.  Therefore it would sometimes, by luck, hit within the good enough window when turning, but other times it would be below the window on one pass and above it the next, and therefore keep turning and turning until by luck it hit within the window.  My control precision was only 1/4 of my measurement precision.

I’ve done three things to adjust:

  1. Ensure that don’t have the debugging serial.print() statements in except when doing a “bench test.”  (see the use of the #if preprocessor directive if you’re new to C or Arduino programming).  That speeds up loop execution.
  2. Slow down the turning speed of the robot.  By turning slower I can get the control precision to more closely match the measurement precision.
  3. Relax the window slightly, making control a bit sloppier, but ensuring I don’t miss the window if adjustments 1 and 2 weren’t sufficient.

Wheel Encoders

In order to estimate position and orientation using dead reckoning, you have to measure the rotation of your wheels (or the motor shaft or gear driving the wheels).   This means using some sort of shaft or wheel encoder.  The RP5 has a gear that rotates 4x for every wheel rotation, and a hole in it which they indicate can be used to count gear rotations using some sort of optical (infrared) encoder.

One can get much more precision by using more holes/slots or more markings, as discussed in this thread on homemade encoders.  Also, having two offset sets of marks allows one to do quadrature encoding and determine the direction of travel as well. For my first robot, I’m just using a rough encoder, with 4 counts per wheel revolution.

In looking in the chassis, there’s not a lot of room. As a result, I decided I’d use a small transmissive sensor, rather than a reflective sensor.  Both have an IR emitter and an IR photo detector.  For reflective units, they both face the same direction, and the detector measure IR reflected back to the sensor.  For a transmissive or interrupt sensor, the two units are separated by a gap, and the detector picks up IR passing through the gap. So far, so good.

I ended up using Vishay transmissive optical sensors (model TCST1202) I purchased from DigiKey.  I found a ciruch  and wiring them up based on the circuit posted by Aniss1001 in the “Homemade wheel encoder”  thread on the Arduino forum.

encoder circuit diagram

Encoder circuit diagram - for a different encoder, but it worked fine

I built the circuit on a prototyping breadboard for testing and got a surprise.  The circuit worked fine, but the gear is transparent to IR!  It turns out that nylon and most plastics used for inexpensive gears are pretty transparent to IR.  I first tried creating an opaque section with a black marker, but while that worked on paper, it didn’t adhere well enough to the gear.  I ended up using a piece of black tape.  Once that worked, I cut some small circuit boards down to size and built the encoders, practicing my soldering skills.

I just used hot glue to mount the encoders.  The encoder boards stick up above the chassis base, so I’m using standoffs to raise the plastic plate with the Romeo controller and other devices.  Here’s a picture of one of the encoders before mounting,, and then mounted on the chassis:

Homemade wheel encoder

Homemade wheel encoder

Mounted encoder

UPDATE: If you don’t want to build your own, I just discovered these pre-built transmissive encoder boards.