Speed and precision

Coasting, overshoot, and why fast and accurate pull in different directions.

1.5DrivingRobot club15 min

Do this lesson in the simulator

Fast robots overshoot. Slow robots take forever. Every real robot, from a warehouse trolley to a Mars rover, lives with this trade. In this lesson you measure it, see how the robot deals with it, and learn the standard trick for getting both.

Coasting

Drive by time and stop, and see how far the robot slides after stop():

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

for speed in [30, 60, 100]:
    forward(speed)
    # pause 2 s (the robot keeps doing what it was told)
    wait(2)
    x, y_at_stop = position()
    # all motors off
    stop()
    # pause 1 s (the robot keeps doing what it was told)
    wait(1)
    x, y_at_rest = position()
    print(f"speed {speed}: slid {round(y_at_rest - y_at_stop, 1)} cm after stop()")
    backward(60, distance=y_at_rest)

Run this in the simulator

At full speed the robot slides about 4 cm after the motors switch off; at 30 it slides about 1 cm. Faster means more coasting, and it is not linear.

Why: momentum

When the motors stop, the robot is still moving, and the mat's friction takes a moment to stop it. The distance it slides depends on how fast it was going. Timing a drive can never be precise, because the timing does not know about the slide.

The robot allows for it

distance= is different. The robot measures how far it has gone, knows how fast it is moving, and switches the motors off early, by the amount it expects to slide:

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

for speed in [30, 60, 100]:
    forward(speed, distance=20)
    # where am I? (cm from where I started)
    x, y = position()
    print(f"speed {speed}: asked 20, got {y}")
    backward(60, distance=y)

Run this in the simulator

All three land close to 20. Look at the last decimal though: the fast one is usually the furthest off. The prediction of the slide is never perfect, and the faster you go the more there is to predict.

The trick: fast, then slow

When the last centimetre matters, do most of the distance fast and the last part slowly:

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

# fast for most of the way
forward(100, distance=15)
# slow for the last bit
forward(25, distance=5)
# where am I? (cm from where I started)
x, y = position()
print(f"asked 20, got {y}")

Run this in the simulator

Almost as quick as flat out, and the finish is at the slow speed's accuracy. Real robots do exactly this: a fast approach and a slow final approach.

Turning has the same problem

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

# turn 90 degrees clockwise at speed 100
turn_right(100, angle=90)
print("fast turn:", round(heading(), 1))
# turn 90 degrees anticlockwise at speed 100
turn_left(100, angle=90)
# turn 90 degrees clockwise at speed 20
turn_right(20, angle=90)
print("slow turn:", round(heading(), 1))

Run this in the simulator

Turning takes a speed as its first argument. A fast turn overshoots by about a degree; a slow one by a fraction of that. Over a long route those degrees add up.

Measure it yourself

Real engineering starts with measuring. This cell drives the same distance at several speeds and collects the errors in a list:

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

errors = []
for speed in [20, 40, 60, 80, 100]:
    forward(speed, distance=20)
    # where am I? (cm from where I started)
    x, y = position()
    errors.append(round(y - 20, 1))
    backward(50, distance=y)
print("errors by speed:", errors)

Run this in the simulator

Task: gentle stop

Stop with the robot's centre within 2 cm of the small square 50 cm ahead, having driven at least 40 cm. The starter times the drive; timing is never that accurate.

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

# drive forward at 100 (keeps going until the next command)
forward(100)
# pause 2.5 s (the robot keeps doing what it was told)
wait(2.5)
# all motors off
stop()

Challenges

  1. Get the gentle stop within 1 cm.
  2. Write precise_forward(cm) that does the fast-then-slow trick for any distance.
  3. Do the same for turns: precise_turn(deg).