Searching

Spin until it is in view; find and approach as functions; list comprehensions.

4.5VisionRobot club20 min

Do this lesson in the simulator

The camera sees 120 degrees. The world is 360. Most of the time the thing you want is not in the picture, and a robot that only reacts to what it sees just sits there. This lesson is about looking for things.

Nothing in view

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

# camera: the tag detector
set_cv("apriltag")
print(apriltags())

Run this in the simulator

An empty list. Marker 5 is somewhere on the mat, but not in the 120 degrees in front of the robot.

Spin until you see it

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

# camera: the tag detector
set_cv("apriltag")
# until a tag is in view
while not apriltags():
    # 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)
# every tag in view: [id, cx, cy, distance], nearest first
tags = apriltags()
print("found", tags[0][0], "after turning to", round(heading()))

Run this in the simulator

while not apriltags() reads as "while the list is empty". Each time round, spin a little and look again. The moment the tag enters the picture the loop ends. Then settle, because the robot coasts and the tag may have slid to the edge of the view, or out of it.

Spin the right way

Spinning always to the right takes up to a full turn. If you have a clue, use it: the last place you saw it, or the side the distance grid says is open. A search that uses clues is called heuristic. Without a clue, right is as good as left.

Find, then approach

Searching and servoing are two functions, and every camera program in this course is those two in a row:

# 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:
            # lost it: turn slowly until it is back
            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(5)
print("found 5")
approach(5, 14)
print("at", position(), "facing", round(heading()))

Run this in the simulator

Two new things. [t for t in apriltags() if t[0] == tag_id] keeps only the tags with the id you want: a list comprehension, and one of the most useful lines in Python. And approach handles losing the tag by turning slowly instead of stopping.

Task: hide and seek

Find marker 5, print found 5, then drive up and stop about 14 cm in front of it.

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()

# camera: the tag detector
set_cv("apriltag")
print(apriltags())

Challenges

  1. Search left instead of right. Which is quicker for this marker?
  2. Print how many degrees the search turned through.
  3. Make find give up and return False after a full turn with nothing seen, and print a message instead of spinning forever.