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.

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 driving 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

What calibration cannot fix

  • Drift in the bias itself. A gyro's bias changes with temperature and with time. Yours wanders slowly, which is why a calibration made an hour ago is worth less than one made a minute ago.
  • 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?