Controlling speed
Speed from the remaining distance, the dead band, clamping.
Do this lesson in the simulatorPrint it: worksheet (PDF) · answers (PDF) · as a web page
Guide: PWM and motor control explained
So far the controller steered. It can just as well decide how fast to go. This lesson parks the robot at an exact distance from a wall by making the speed depend on how far there is still to go.
The bang-bang park
# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()
# as long as the thing ahead is further than 22 cm
while distance() > 22:
# drive forward at 60 (keeps going until the next command)
forward(60)
# pause 0.1 s (the robot keeps doing what it was told)
wait(0.1)
# all motors off
stop()
# pause 0.5 s (the robot keeps doing what it was told)
wait(0.5)
print("stopped", distance(), "cm from the wall")
Fast all the way and stop dead: the robot coasts past 22 and ends closer. Same problem as lesson 3.1, sideways.
Proportional speed
Speed in proportion to the remaining distance: 40 cm to go, drive fast; 4 cm to go, crawl.
# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()
target = 22
# do this 100 times (tick counts from 0)
for tick in range(100):
error = distance() - target
if abs(error) < 1:
# leave the loop
break
# gain 4, and never more than full speed
speed = min(100, error * 4)
forward(speed)
# pause 0.05 s (the robot keeps doing what it was told)
wait(0.05)
# all motors off
stop()
# pause 0.5 s (the robot keeps doing what it was told)
wait(0.5)
print("stopped", distance(), "cm from the wall, last speed asked for:", round(speed))
It gets close and then stalls short of the target: it stops at 25 cm, 3 cm short, asking for a speed of 12 that does nothing.
The dead band
The vibration motors do nothing below about 15. With 3 cm to go, the proportional controller asks for 12 over and over, and the robot just sits there. Real actuators all have a dead band like this, and the fix is to never ask for less than the minimum:
# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()
target = 22
# again and again, for ever
while True:
error = distance() - target
if abs(error) < 1:
# leave the loop
break
# never below 16, never above 60
speed = max(16, min(60, abs(error) * 4))
if error > 0:
forward(speed)
else:
backward(speed)
# pause 0.05 s (the robot keeps doing what it was told)
wait(0.05)
# all motors off
stop()
# pause 0.5 s (the robot keeps doing what it was told)
wait(0.5)
print("stopped", distance(), "cm from the wall")
max(16, min(60, value)) is called clamping: it keeps a number between two limits. You will write it a lot. And because the loop checks the sign, the robot backs up if it went too far.
The pattern
Every P controller in this module has the same shape. Learn it once:
error = target - measured
output = clamp(error * gain)
apply(output)
Steering: measured is the heading, apply is the rotation. Speed: measured is the distance, apply is forward or backward. Same loop, different sensor and motor.
Task: park at twenty
Stop with the front of the robot 20 to 24 cm from the wall, the green band, without touching the wall.
# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()
# as long as the thing ahead is further than 22 cm
while distance() > 22:
# drive forward at 60 (keeps going until the next command)
forward(60)
# pause 0.1 s (the robot keeps doing what it was told)
wait(0.1)
# all motors off
stop()
Challenges
- Park at 40 cm, then at 10 cm, with the same loop and a different
target. - Print the speed every tick and watch it fall as the robot approaches.
- Start the robot closer than the target (edit the loop to drive there first) and check it backs up.