Losing the line

Gaps: carry on, then search with a state machine.

6.3Seeing moreRobot club20 min

Do this lesson in the simulator

Lines have gaps: a join in the tape, a scuff, a junction. A follower that stops the moment line() is empty is stuck at the first one. This lesson is what to do when the line is gone.

Keep going first

Most gaps are short. The cheapest fix is to carry straight on for a while before deciding the line has really gone:

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

def follow_step(speed=60, gain=0.4):
    # [cx, angle] of the line ahead, or [] if none
    seen = line()
    if not seen:
        return False
    cx, angle = seen
    # forward, sideways, rotation: -100 to 100 each, until the next command
    drive(speed, 0, (cx - 160) * gain)
    return True

# camera: the line detector
set_cv("line")
lost = 0
# do this 120 times (tick counts from 0)
for tick in range(120):
    if follow_step():
        lost = 0
    else:
        lost += 1
        # drive forward at 40 (keeps going until the next command)
        forward(40)
    # pause 0.1 s (the robot keeps doing what it was told)
    wait(0.1)
# all motors off
stop()
print("at", position(), "ticks without a line at the end:", lost)

Run this in the simulator

On this mat the line restarts 8 cm to the right after the gap, so carrying straight on misses it. The counter tells you how long it has been gone.

Then search

After enough ticks without a line, switch to a search: creep forward while sweeping side to side, and go back to following the moment the line reappears. That is a state machine from Module 5:

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

def follow_step(speed=60, gain=0.4):
    # [cx, angle] of the line ahead, or [] if none
    seen = line()
    if not seen:
        return False
    cx, angle = seen
    # forward, sideways, rotation: -100 to 100 each, until the next command
    drive(speed, 0, (cx - 160) * gain)
    return True

# camera: the line detector
set_cv("line")
lost = 0
state = "follow"
while position()[1] < 85:
    if state == "follow":
        if follow_step(60, 0.4):
            lost = 0
        else:
            lost += 1
            # drive forward at 40 (keeps going until the next command)
            forward(40)
            if lost > 8:
                state = "search"
                sweep = 0
                print("lost the line at", position())
    elif state == "search":
        if line():
            state = "follow"
            print("found it at", position())
        else:
            sweep += 1
            # creep forward, sliding right then left
            drive(25, 40 if (sweep // 15) % 2 == 0 else -40, 0)
    # pause 0.1 s (the robot keeps doing what it was told)
    wait(0.1)
# all motors off
stop()

Run this in the simulator

The sweep slides right for 15 ticks, left for 15, and so on, while still creeping forward. Because the robot strafes instead of turning, it keeps its heading, so when the line is found again it is already pointing the right way.

Choosing the first direction

Sweeping right first is a guess. A better guess is the last angle you saw: a line that was heading right when it vanished probably continues to the right. Store it before it is gone.

Task: find the line again

Follow the line through the gap to the green zone.

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

def follow_step(speed=60, gain=0.4):
    # [cx, angle] of the line ahead, or [] if none
    seen = line()
    if not seen:
        return False
    cx, angle = seen
    # forward, sideways, rotation: -100 to 100 each, until the next command
    drive(speed, 0, (cx - 160) * gain)
    return True

# camera: the line detector
set_cv("line")
while position()[1] < 85:
    if not follow_step(60, 0.4):
        # leave the loop
        break
    # pause 0.1 s (the robot keeps doing what it was told)
    wait(0.1)
# all motors off
stop()

Challenges

  1. Sweep in the direction of the last angle you saw.
  2. Count how many ticks the search took and print it.
  3. Make the sweep widen each time: 10 ticks, then 20, then 30.