Collecting data

Readings with labels, and why bad data makes bad robots.

8.2LearningRobot club20 min

Do this lesson in the simulator

A model learns from examples. An example is a view plus a word for what the view means: a sample with a label. This lesson collects the samples the rest of the module uses.

Four situations

The mat has one wall across it, with a gap at each end. Four things can be in front of the robot: open space, the wall, the gap at the wall's left end, the gap at its right end. Those are the labels: open, wall-ahead, gap-left, gap-right. The green squares mark a spot for each.

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

def level_rows():
    return tof_grid()[16:32]

sample = (level_rows(), "open")
print(sample)

Run this in the simulator

A sample is a pair: the 16 readings, and the label. The label is your judgement, not the robot's. If you get it wrong, the model learns your mistake.

Getting to the spots

drive_to from Module 5 slides the robot to a point, holding its heading, and stops there. The spots, relative to the start, are (0, 10), (0, 45), (-38, 45) and (38, 45).

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

# maths: atan2, hypot, sin, cos, radians
import math

def wrapped(h):
    return (h + 180) % 360 - 180

def go_to(x, y, speed=60):
    # where am I?
    px, py = position()
    a = math.radians(wrapped(math.degrees(math.atan2(x - px, y - py)) - heading()))
    # forward, sideways, rotation: -100 to 100 each, until the next command
    drive(speed * math.cos(a), speed * math.sin(a), wrapped(0 - heading()) * 3)

def near(x, y, cm=4):
    # where am I?
    px, py = position()
    return math.hypot(x - px, y - py) < cm

def drive_to(x, y):
    while not near(x, y):
        go_to(x, y)
        # pause 0.1 s (the robot keeps doing what it was told)
        wait(0.1)
    # all motors off
    stop()
    # pause 0.4 s (the robot keeps doing what it was told)
    wait(0.4)

def level_rows():
    return tof_grid()[16:32]

data = []
drive_to(0, 10)
data.append((level_rows(), "open"))
print("recorded open:", data[-1][0][:8])
drive_to(0, 45)
data.append((level_rows(), "wall-ahead"))
print("recorded wall-ahead:", data[-1][0][:8])
print(len(data), "samples")

Run this in the simulator

The wait(0.4) at the end of drive_to matters: the readings are taken after the robot has settled, not while it is still sliding.

Bad data makes bad robots

Three ways to collect data that produce a robot that does the wrong thing with total confidence:

  • Wrong labels. Record the wall as open once and the model will happily drive into walls that look like that one.
  • One place only. Record open only at the start, and the model has never seen open space from anywhere else. Lesson 8.1 showed how much the numbers change with a small turn.
  • Labels that mean where, not what. The label must describe what the robot sees. gap-left means "the wall ends on my left", wherever the robot happens to be when it sees that.

The fix for all three is the same: look at what you recorded, and record more, from more places.

Task: collect data

Visit the four spots in order, record the level rows at each with its label, and print recorded <label> each time.

# the two lines every program starts with: the commands, then the robot
from bugbot import *
connect()
# maths: atan2, hypot, sin, cos, radians
import math

def wrapped(h):
    return (h + 180) % 360 - 180

def go_to(x, y, speed=60):
    # where am I?
    px, py = position()
    a = math.radians(wrapped(math.degrees(math.atan2(x - px, y - py)) - heading()))
    # forward, sideways, rotation: -100 to 100 each, until the next command
    drive(speed * math.cos(a), speed * math.sin(a), wrapped(0 - heading()) * 3)

def near(x, y, cm=4):
    # where am I?
    px, py = position()
    return math.hypot(x - px, y - py) < cm

def drive_to(x, y):
    while not near(x, y):
        go_to(x, y)
        # pause 0.1 s (the robot keeps doing what it was told)
        wait(0.1)
    # all motors off
    stop()
    # pause 0.4 s (the robot keeps doing what it was told)
    wait(0.4)
drive_to(0, 10)
print('recorded', 'open')

Challenges

  1. Record three samples at each spot: facing 10 degrees left, straight, and 10 degrees right.
  2. Print data at the end. That text is your dataset; lesson 8.7 shows how to keep it.
  3. Add a fifth label, corner, recorded in a corner of the mat. What does the robot see there?