Learning · Robot club · about 20 min
The simplest classifier, in a dozen lines.
[1 mark]What does this program print?
def difference(a, b):
return sum((p - q) ** 2 for p, q in zip(a, b))
print(difference([10, 20, 30], [12, 20, 27]))[1 mark]What does this program print?
def nearest(sample, data):
best_label, best_d = None, 1e18
for feats, label in data:
d = sum((a - b) ** 2 for a, b in zip(feats, sample))
if d < best_d:
best_label, best_d = label, d
return best_label
DATA = [([50, 50, 50], "open"), ([16, 16, 16], "wall-ahead"), ([45, 45, 16], "gap-left")]
print(nearest([40, 42, 20], DATA))[1 mark]Why are the differences squared before adding them up?
[1 mark]Around 30 cm from the wall, the classifier says gap-left when the truth is a wall ahead. What is the cure?
nearest function[1 mark]The dataset has no sample labelled corner. The robot drives into a corner. What can nearest neighbour say?
[1 mark]A student tests nearest by classifying each sample in DATA and gets every one right. What does that show?
[1 mark]Two views of 16 readings differ by exactly 1 cm in every column. What is their difference, using the sum of squared differences?
Drive to (0, 15), (0, 40), (-38, 40) and (38, 40) in turn, and print spot <n>: <label> at each, using nearest against DATA.
# 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():
# rows 2 and 3: the 16 readings that look straight ahead
return tof_grid()[16:32]
def nearest(sample, data):
# the label of the recorded sample most like this one (smallest sum of squared differences)
best_label, best_d = None, 1e18
for feats, label in data:
d = sum((a - b) ** 2 for a, b in zip(feats, sample))
if d < best_d:
best_label, best_d = label, d
return best_label
DATA = [
([54, 52, 51, 51, 51, 51, 52, 54, 54, 52, 51, 51, 51, 51, 52, 54], 'open'),
([16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16], 'wall-ahead'),
([36, 47, 46, 46, 46, 16, 16, 16, 36, 47, 46, 46, 46, 16, 16, 16], 'gap-left'),
([16, 16, 16, 46, 46, 46, 47, 36, 16, 16, 16, 46, 46, 46, 47, 36], 'gap-right'),
]
drive_to(0, 15)
print('spot 1:', nearest(level_rows(), DATA))Plan your program here, then type it in and press Run.
nearest also return the smallest difference, and print unsure when it is above 2000.