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:
- 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.
- Slow down the turning speed of the robot. By turning slower I can get the control precision to more closely match the measurement precision.
- 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.