Speed and precision
Coasting, overshoot, and why fast and accurate pull in different directions.
Do this lesson in the simulatorFast 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)
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)
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}")
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))
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)
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
- Get the gentle stop within 1 cm.
- Write
precise_forward(cm)that does the fast-then-slow trick for any distance. - Do the same for turns:
precise_turn(deg).