Skip to content
BetaDE
Lesson 7 of 8Robotics with LEGO SPIKE

Robotics with LEGO SPIKE · Lesson 7 · 30 minutes

Calibrating

What you'll learn

  • Understand why real robots never drive perfectly
  • Measure the distance with the distance sensor and the turn with the gyro
  • Recalculate wheel_diameter and axle_track correctly

The code in this lesson comes from the book “Python for Robots”, chapter 2.5, and runs unchanged in the simulator. German edition on Amazon ↗

No robot is perfect

The program says wheel_diameter=56 – but is your wheel really exactly 56 mm? Tyres get squashed, wear out, and every model is built a little differently. Just 2 mm of difference add up to several centimetres over one metre. In a competition, that decides between winning and losing.

That’s why good teams calibrate their robot: they measure how it really moves and adjust the numbers in the program.

In the simulator: On the workshop field the robot behaves like a real one – its wheels are different from what the program thinks. On all other fields it drives perfectly.

Measuring the distance

On a real table you use a ruler. Here – and in real life too, if there’s a wall in front of the robot – there’s a more elegant way with the distance sensor: distance before minus distance after = distance driven.

from pybricks.pupdevices import Motor, UltrasonicSensor
from pybricks.parameters import Port, Direction
from pybricks.robotics import DriveBase

left_motor = Motor(Port.A, positive_direction=Direction.COUNTERCLOCKWISE)
right_motor = Motor(Port.B, positive_direction=Direction.CLOCKWISE)
distance_sensor = UltrasonicSensor(Port.C)
drive_base = DriveBase(left_motor, right_motor, wheel_diameter=56, axle_track=114)

before = distance_sensor.distance()
drive_base.straight(500)
after = distance_sensor.distance()

print("Target: 500 mm")
print("Actual:", before - after, "mm")
print("The robot itself believes:", drive_base.distance(), "mm")

Interesting: the robot itself believes it drove 500 mm – after all, it only counts how often its wheels turned. Only the sensor shows the truth.

Calculating the wheel diameter

If the robot drives too short, the wheels are really smaller than in the program. The formula:

old_diameter = 56
target = 500
measured = 464

new_diameter = old_diameter * measured / target
print("New wheel_diameter:", round(new_diameter, 1))

Measuring the turn

For turns, the gyro sensor helps – it measures the real turn, no matter what the wheels are like:

from pybricks.hubs import PrimeHub
from pybricks.pupdevices import Motor
from pybricks.parameters import Port, Direction
from pybricks.robotics import DriveBase

hub = PrimeHub()
left_motor = Motor(Port.A, positive_direction=Direction.COUNTERCLOCKWISE)
right_motor = Motor(Port.B, positive_direction=Direction.CLOCKWISE)
drive_base = DriveBase(left_motor, right_motor, wheel_diameter=56, axle_track=114)

hub.imu.reset_heading(0)
for _ in range(4):
    drive_base.turn(90)
print("After 4 × 90 degrees:", round(hub.imu.heading()), "degrees")

Four times 90 degrees should make exactly one full turn – but the robot doesn’t manage it.

Calculating the axle track – careful, the other way round!

For axle_track the calculation is reversed. Think about the robot: if it believes its wheels are further apart than they really are, it runs them longer for a turn – and turns too far. So a smaller value means a weaker turn.

old_track = 114
target = 360
measured = 342

new_track = old_track * target / measured
print("New axle_track:", round(new_track, 1))

Order: Set the wheel diameter correctly first and then measure the turn again. The wheel diameter affects the turn too.

Calibration recipe

  1. Put the robot on a mark, drive straight(500), measure the real distance.
  2. wheel_diameter = old value × measured ÷ target
  3. Drive turn(360), measure the real turn with the gyro.
  4. axle_track = old value × target ÷ measured
  5. Drive everything again to check. Several turns (e.g. turn(1080)) make small errors easier to see.

Tip: With drive_base.use_gyro(True) the robot even corrects turns by itself using the gyro sensor. You still have to calibrate the distance – the gyro only measures turns.

Your task

Your turn

This robot in the workshop is like a real one: its wheels aren't exactly what the program says. Measure how far it really drives with drive_base.straight(500) and how far it really turns with drive_base.turn(360). Then recalculate wheel_diameter and axle_track and enter them until it drives exactly 500 mm (from tape strip to tape strip) and turns exactly once around. Tip: the wheel first, then measure again, then the axle.

from pybricks.hubs import PrimeHub
from pybricks.pupdevices import Motor, UltrasonicSensor
from pybricks.parameters import Port, Direction
from pybricks.robotics import DriveBase

hub = PrimeHub()
left_motor = Motor(Port.A, positive_direction=Direction.COUNTERCLOCKWISE)
right_motor = Motor(Port.B, positive_direction=Direction.CLOCKWISE)
distance_sensor = UltrasonicSensor(Port.C)

# You have to calibrate these two values:
drive_base = DriveBase(left_motor, right_motor, wheel_diameter=56, axle_track=114)

# Measurement 1: how far does it really drive?
before = distance_sensor.distance()
drive_base.straight(500)
driven = before - distance_sensor.distance()
print("Driven:", driven, "mm")

# Measurement 2: how far does it really turn?
hub.imu.reset_heading(0)
drive_base.turn(360)
print("Turned:", round(hub.imu.heading()), "degrees")

Solve it without hints to earn a ⭐ on your progress page.

Show solution

Try it yourself first – mistakes teach you the most. Here is one possible solution:

from pybricks.hubs import PrimeHub
from pybricks.pupdevices import Motor, UltrasonicSensor
from pybricks.parameters import Port, Direction
from pybricks.robotics import DriveBase

hub = PrimeHub()
left_motor = Motor(Port.A, positive_direction=Direction.COUNTERCLOCKWISE)
right_motor = Motor(Port.B, positive_direction=Direction.CLOCKWISE)
distance_sensor = UltrasonicSensor(Port.C)

# You have to calibrate these two values:
drive_base = DriveBase(left_motor, right_motor, wheel_diameter=52, axle_track=120)

# Measurement 1: how far does it really drive?
before = distance_sensor.distance()
drive_base.straight(500)
driven = before - distance_sensor.distance()
print("Driven:", driven, "mm")

# Measurement 2: how far does it really turn?
hub.imu.reset_heading(0)
drive_base.turn(360)
print("Turned:", round(hub.imu.heading()), "degrees")