Following a robot

Two controllers that never finish: chase a moving tag at a set distance.

6.5Seeing moreRobot club20 min

Do this lesson in the simulator

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)

Run this in the simulator

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())

Run this in the simulator

(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.

The follower's speed against the gap to the leader: nothing up to 20 cm, then rising, capped at 7001020304050020406080gap to the leader, cmspeed asked for44: fast enough to keep upso the gapsettles at 31 cm20 cm or closer: 0capped at 70
The speed controller asks for nothing at 20 cm or closer, and 4 more for every cm further away. This robot needs about 44 to keep up with the leader, and it only asks for that when the gap is 31 cm, so that is where it sits.

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.

From above: the leader's loop and the follower's path, which stays inside it, with the gap at three moments31 cm20 cm10 cmthe leader'sloopfollower starts
The leader drives the grey loop and the follower's path is green. Each dashed line joins where the two were at the same moment. On the first straight the gap is about 31 cm. At the corners the follower turns to face the leader and cuts across the inside, so the gap closes to about 20 cm, and to 10 cm at the last one.

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

  1. 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?
  2. Print your distance to the leader every second and see how steady it is.
  3. Make the LED green while you can see the leader and red when you cannot.