Calibration

Measuring the gyro bias and the flow scale, and taking both out of the estimate.

U3.4Odometry and driftUniversity30 min

Do this lesson in the simulator

Two numbers were doing most of the damage. Both can be measured, and once measured, subtracted.

Calibrating the gyro

Stand still, average the rate, and subtract that from every reading afterwards. Six seconds of standing still buys the whole run.

rates = [imu()[1] for _ in range(50) if wait(0.1) is None]
bias = sum(rates) / len(rates)
...
h += (imu()[1] - bias) * DT

Every inertial system on earth does this, from a phone to an airliner, and in more serious ones it is done continuously whenever the vehicle is known to be still. That is called zero velocity update, and it is the reason a pedestrian tracker in a shoe works at all: the foot is stationary once a step, every step, and each of those moments is a free calibration.

Forty turn-rate readings from a robot standing still, the zero line and their average01234-2-101time standing still, simu()[1], deg/sdots: one reading each tick. dotted: zero, what a still robot should read-0.17average
The robot is not turning, yet the readings scatter by about 0.7 deg/s either side, and no single one of them shows the bias. Their average does: -0.17 deg/s (the green line), within 0.02 of this gyro's real bias of -0.19. More readings would pin it down closer still.

Calibrating the flow scale

Drive a measured distance, compare it with the integral, take the ratio:

scale = true_distance / integrated_distance

and multiply every future reading by it. The catch is that a real robot needs a true distance from somewhere, which means a tape measure, a wall at a known place, or a landmark. Calibration always costs an external reference. There is no way to measure yourself using only yourself.

The order matters

Calibrate the gyro first and the flow second, because the flow calibration involves driving, and steering with an uncalibrated gyro curves the path, which corrupts the distance you were trying to measure. Fix the heading, then the distance.

Doing it in one program

from bugbot import *
import math
connect()

DT = 0.1

rates = []
for i in range(40):
    rates.append(imu()[1])
    wait(0.1)
bias = sum(rates) / len(rates)
print("gyro bias", round(bias, 2), "deg/s")

x = y = h = 0.0
for i in range(40):
    vx, vy = flow()
    rate = imu()[1] - bias                # calibrated
    a = math.radians(h + 0.5 * rate * DT)
    x += (vx * math.cos(a) + vy * math.sin(a)) * DT
    y += (-vx * math.sin(a) + vy * math.cos(a)) * DT
    h += rate * DT
    forward(70)
    wait(DT)
stop()
print("mine", (round(x, 1), round(y, 1)), "truth", position())
print("heading: mine", round(h, 1), "truth", round(heading(), 1))

Run this in the simulator

Heading added up over a minute of standing still, with and without the measured bias taken off0204060-12-8-404time after calibrating, sheading, degrees-10.9°-1.0°red: the raw rate added upgreen: with the bias taken off
The robot never moves, so the right answer is 0° all the way. Adding up the raw rate, the heading leans 10.9° in a minute and keeps going. Take off the -0.17 measured in the first four seconds and it is 1.0° out after the same minute: what is left is the noise and the few hundredths the average missed.

What calibration cannot fix

  • Drift in the bias itself. A real gyro's bias changes with temperature and with time, which is why a calibration made an hour ago is worth less than one made a minute ago. The simulated gyro's bias holds still for the whole run (it measured -0.17 deg/s here); what wanders in the simulator is the fused heading from imu()[0].
  • Slip. The mat moving under a robot that is not moving, or the other way round. It is not a constant, so there is nothing to subtract.
  • Anything unmodelled. Calibration removes the errors your model has a name for, and nothing else.

Calibration buys you time. Getting a fix from outside is what actually bounds the error, and that is the next lesson.

Task: a calibrated lap

Calibrate the gyro, then dead reckon at least 120 cm with turns in it. Print bias:, my x: and my y:. The position tolerance is tighter than the uncalibrated task, so the calibration has to be real.

from bugbot import *
import math
connect()

DT = 0.1
# stand still first and learn the bias

Challenges

  1. Run the same lap with and without the bias correction and report both errors.
  2. Calibrate the flow scale against a wall at a known distance, using distance().
  3. Recalibrate the gyro every time the robot stops. Does it help over a two minute run?