Following a robot
Two controllers that never finish: chase a moving tag at a set distance.
Do this lesson in the simulatorDocking 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
Robot 101 drives a loop at a steady speed. Look at its tag 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
# camera: the tag detector
set_cv("apriltag")
# do this 16 times (i counts from 0)
for i in range(16):
tags = [t for t in apriltags() if t[0] == 101]
if tags:
print(f"{i}: {tags[0][3]} cm, bearing {round(bearing_of(tags[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 and the bearing swings as it drives away and turns. Standing still, you lose it in a few seconds.
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
# camera: the tag detector
set_cv("apriltag")
# do this 200 times (tick counts from 0)
for tick in range(200):
tags = [t for t in apriltags() if t[0] == 101]
if not tags:
# lost it: turn until it is back
turn_right(40)
else:
cx, dist = tags[0][1], tags[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. The robot settles into a steady chase about 20 cm behind.
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 robot 101 for the whole run, without touching it.
# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()
# camera: the tag detector
set_cv("apriltag")
# do this 390 times (tick counts from 0)
for tick in range(390):
tags = [t for t in apriltags() if t[0] == 101]
if tags:
# forward, sideways, rotation: -100 to 100 each, until the next command
drive(60, 0, (tags[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. Where does it lose the leader?
- 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.