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

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)

Run this in the simulator

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

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

  1. Hold 30 cm instead of 20. Where does it lose the leader?
  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.