Behaviours · Robot club · about 20 min
A plan as a state variable, transitions, drawing the machine.
[1 mark]In a state machine, what is the state?
state = "up" is all it is. Each tick does the right thing for that state and checks whether to change it.[1 mark]What does this program print?
import math
route = {"up": (0, 60), "right": (60, 60)}
state = "up"
for p in [(0, 20), (0, 57), (30, 60), (57, 61)]:
tx, ty = route[state]
if math.hypot(tx - p[0], ty - p[1]) < 6:
if state == "right":
print("done")
break
state = "right"
print(p, state)(0, 20) up (0, 57) right (30, 60) right done
At (0, 57) the robot is within 6 cm of the end of the up leg, so the state changes to right. At (57, 61) it is near the end of the right leg, so it is done.
[1 mark]In the "up" branch of a patrol, the transition is if near(0, 60): state = "up". The robot reaches (0, 60) and just sits there. Why?
"up", so it never leaves that statenear needs a cm argumentgo_to cannot drive to (0, 60)wait(0.1)"right". Setting it to the state you are already in is a machine stuck in one state.[1 mark]target = route[state] gives a pair like (60, 60). What does near(*target) do?
near(60, 60)x gets 60 and y gets 60.[1 mark]The task's patrol goes round the box and back. Put its states in order.
Number the lines 1 to 4 to put them in the right order.
uprightdownleftup right left down
Up and right take the robot to B. Left and down bring it back the same way, along the top of the box and down its left side.
[1 mark]You draw a state machine before writing it. Which belong in the drawing?
Tick every answer that is true.
[1 mark]Why does the patrol keep the corners in a dictionary, route, instead of writing a separate driving block for each state?
go_to only accepts a dictionaryifFrom A to B and back, round the box: up, right, then left, down. Without touching the box.
# 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=70):
# 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=6):
# where am I?
px, py = position()
return math.hypot(x - px, y - py) < cm
# do this 100 times (tick counts from 0)
for tick in range(100):
if near(0, 60):
# leave the loop
break
go_to(0, 60)
# pause 0.1 s (the robot keeps doing what it was told)
wait(0.1)
# all motors off
stop()The hint students can ask for: Go from A to B and back again, round the box: up, right, then left, down. One state per leg, and a transition when the leg is done.
from bugbot import *
connect()
def wrapped(h):
return (h + 180) % 360 - 180
import math
def go_to(x, y, speed=70):
# one tick of sliding straight towards (x, y) (relative to the start) while holding heading 0
px, py = position()
a = math.radians(wrapped(math.degrees(math.atan2(x - px, y - py)) - heading()))
drive(speed * math.cos(a), speed * math.sin(a), wrapped(0 - heading()) * 3)
def near(x, y, cm=6):
px, py = position()
return math.hypot(x - px, y - py) < cm
# positions are relative to the start (20, 20): B is at (60, 60) relative
route = {"up": (0, 60), "right": (60, 60), "left": (0, 60), "down": (0, 0)}
order = ["up", "right", "left", "down"]
state = "up"
for tick in range(390):
target = route[state]
if near(*target):
if state == "down":
break
state = order[order.index(state) + 1]
print("now:", state)
else:
go_to(*target)
wait(0.1)
stop()
Any program that meets the task's checks is marked correct in the simulator; this is one way, not the only way.