Project: the marker trail

Visit three tag cubes in order.

4.6VisionRobot club25 min

Do this lesson in the simulator

Three tags on cubes around the mat, numbered 1, 2 and 3. Visit them in order: find each one, drive up to it, move on. A treasure hunt for a robot, and the shape of every "go to A, then B, then C" job a real robot does.

Cubes, not cards

The tags in earlier lessons were printed on cards and could only be read from the front. These are on cubes, with a tag on every side, so they can be read from anywhere. Run this and turn slowly:

# 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 8 times (step counts from 0)
for step in range(8):
    print(round(heading()), "->", [t[0] for t in apriltags()])
    # turn 45 degrees clockwise, then stop
    turn_right(30, angle=45)

Run this in the simulator

[t[0] for t in apriltags()] is just the ids: a list comprehension again.

The two functions

find and approach from lesson 4.5, unchanged:

# 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

def find(tag_id):
    # again and again, for ever
    while True:
        tags = [t for t in apriltags() if t[0] == tag_id]
        if tags:
            # leave the loop
            break
        # spin clockwise on the spot at 40
        turn_right(40)
        # pause 0.1 s (the robot keeps doing what it was told)
        wait(0.1)
    # all motors off
    stop()
    # pause 0.3 s (the robot keeps doing what it was told)
    wait(0.3)

def approach(tag_id, stop_at):
    # again and again, for ever
    while True:
        tags = [t for t in apriltags() if t[0] == tag_id]
        if not tags:
            # spin clockwise on the spot at 30
            turn_right(30)
            # pause 0.1 s (the robot keeps doing what it was told)
            wait(0.1)
            # back to the top of the loop
            continue
        cx, dist = tags[0][1], tags[0][3]
        if dist <= stop_at:
            # leave the loop
            break
        speed = max(20, min(70, (dist - stop_at) * 3))
        # 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()

# camera: the tag detector
set_cv("apriltag")
find(1)
approach(1, 10)
print("at marker 1:", position())

Run this in the simulator

The trail is a loop

With the two functions written, the project is three lines:

for tag_id in [1, 2, 3]:
    find(tag_id)
    approach(tag_id, 10)

That is why functions matter. The hard part was written once and tested once; the plan on top of it is trivial to read and trivial to change.

Task: the marker trail

Visit markers 1, 2 and 3 in order, stopping close to each. Sixty seconds.

# 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

def find(tag_id):
    # again and again, for ever
    while True:
        tags = [t for t in apriltags() if t[0] == tag_id]
        if tags:
            # leave the loop
            break
        # spin clockwise on the spot at 40
        turn_right(40)
        # pause 0.1 s (the robot keeps doing what it was told)
        wait(0.1)
    # all motors off
    stop()
    # pause 0.3 s (the robot keeps doing what it was told)
    wait(0.3)

def approach(tag_id, stop_at):
    # again and again, for ever
    while True:
        tags = [t for t in apriltags() if t[0] == tag_id]
        if not tags:
            # spin clockwise on the spot at 30
            turn_right(30)
            # pause 0.1 s (the robot keeps doing what it was told)
            wait(0.1)
            # back to the top of the loop
            continue
        cx, dist = tags[0][1], tags[0][3]
        if dist <= stop_at:
            # leave the loop
            break
        speed = max(20, min(70, (dist - stop_at) * 3))
        # 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()

# camera: the tag detector
set_cv("apriltag")
find(1)
approach(1, 10)

Where next

In the Capture the marker competition, a tag keeps moving and four robots look for it. Module 5 is about behaviours: programs that decide what to do next, not just how to do it.

Challenges

  1. Visit them in the order 3, 1, 2. Which order is fastest?
  2. Print the time when you reach each marker, using a variable that counts your wait calls or the t from the telemetry.
  3. Make find remember which way it turned to find the last tag and search that way first.