Following a robot
Two controllers that never finish: chase a moving tag at a set distance.
Do this lesson in the simulatorPrint it: worksheet (PDF) · answers (PDF) · as a web page
Docking at a marker in Module 4 aimed at something that stayed still. Following a robot aims at something that keeps moving, so the loop never finishes: the target's distance and bearing are new every tick, and the two controllers from lesson 4.3 just run forever.
Watch it go
The leader drives a loop at a steady speed with its dome lit green. Look at it every half second:
# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()
def bearing_of(cx):
return (cx - 160) * 120 / 320
# do this 16 times (i counts from 0)
for i in range(16):
seen = [r for r in robots() if r[0] == "green"]
if seen:
print(f"{i}: {seen[0][3]} cm, bearing {round(bearing_of(seen[0][1]), 1)}")
else:
print(f"{i}: out of view")
# pause 0.5 s (the robot keeps doing what it was told)
wait(0.5)
The distance grows by 4 cm every half second, from 25 cm to 57 cm, as it drives straight away. Then it turns, the bearing starts to swing, and by the last read it is 73 cm off to the right. Standing still, you are losing it: a dome that far away is only a few pixels across, and the next corner takes it out of view altogether.
Two controllers, forever
Rotation from the bearing, speed from the distance, every tick:
# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()
def bearing_of(cx):
return (cx - 160) * 120 / 320
# do this 200 times (tick counts from 0)
for tick in range(200):
seen = [r for r in robots() if r[0] == "green"]
if not seen:
# lost it: turn until it is back
turn_right(40)
else:
cx, dist = seen[0][1], seen[0][3]
# hold about 20 cm behind
speed = max(0, min(70, (dist - 20) * 4))
# forward, sideways, rotation: -100 to 100 each, until the next command
drive(speed, 0, bearing_of(cx) * 3)
# pause 0.1 s (the robot keeps doing what it was told)
wait(0.1)
# all motors off
stop()
print("ended", position())
(dist - 20) * 4 is the speed controller from lesson 3.4 with a target of 20 cm: further away, faster; at 20 cm, stop; closer than that, the clamp holds it at zero rather than reversing. On the first straight the gap settles at about 30 cm, not 20: to keep up with the leader the follower needs a speed of about 44, and the controller only asks for that when the gap is 31 cm. That is the steady error of a P controller again. On the corners the follower cuts inside the leader's path and the gap closes to about 20 cm, and to 10 cm at the last one.
Corners
Watch the corners. The leader turns, its bearing jumps, and the follower cuts the corner to catch up. That is fine here. In a convoy on a line you would follow the line instead and use the leader only for speed.
Losing it
A follower loses its leader behind an obstacle or round a sharp turn. turn_right(40) is the simplest recovery. A better one remembers the last bearing and turns that way, and a better one still remembers the last few positions and heads for where the leader is likely to be. That is lesson 6.7.
Task: follow the leader
Stay 12 to 35 cm behind the green robot for at least 80% of the run, without touching it.
# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()
# do this 390 times (tick counts from 0)
for tick in range(390):
seen = [r for r in robots() if r[0] == "green"]
if seen:
# forward, sideways, rotation: -100 to 100 each, until the next command
drive(60, 0, (seen[0][1] - 160) * 120 / 320 * 3)
# pause 0.1 s (the robot keeps doing what it was told)
wait(0.1)
# all motors off
stop()
The starter drives at the leader at a fixed speed and rams it. Add the distance controller.
Challenges
- Hold 30 cm instead of 20. How far behind does it sit on the straight now, and does it still stay inside 12 to 35 cm?
- Print your distance to the leader every second and see how steady it is.
- Make the LED green while you can see the leader and red when you cannot.