Behaviours · Robot club · about 20 min
Avoid beats seek: behaviours that take over and run to completion.
[1 mark]With behaviours ordered by priority, who controls the robot each tick?
[1 mark]Put these layers in order, highest priority first.
Number the lines 1 to 3 to put them in the right order.
Seek: head for the goalEmergency: the battery is low, so stopAvoid: something is close ahead, so back off and slideEmergency: the battery is low, so stop Avoid: something is close ahead, so back off and slide Seek: head for the goal
Safety beats not hitting things, and not hitting things beats getting to the goal. The actual job is the lowest layer.
[1 mark]Once avoid takes over, it runs for ten ticks whatever the sensor says. Why?
[1 mark]What does this program print?
def choose(battery, dist, avoiding):
if battery < 20:
return "stop"
elif avoiding or dist < 22:
return "avoid"
else:
return "seek"
print(choose(80, 50, False))
print(choose(80, 15, False))
print(choose(10, 15, True))
print(choose(80, 60, True))seek avoid stop avoid
The first true test wins. A low battery beats everything, and an avoid that is still running carries on even when the way looks clear.
[1 mark]What does this program print?
state = "seek"
avoid_ticks = 0
for d in [50, 20, 18, 30, 15, 60]:
if state == "seek" and d < 22:
state = "avoid"
avoid_ticks = 0
if state == "avoid":
avoid_ticks += 1
if avoid_ticks >= 3:
state = "seek"
print(d, state)50 seek 20 avoid 18 avoid 30 seek 15 avoid 60 avoid
Avoid lasts three ticks. On the third, it hands back to seek, and the next close reading, 15, starts it again.
[1 mark]Does steer_to, the seek behaviour, need to know that avoid exists?
[1 mark]Why does steer_to only drive forward once the robot is facing within 25 degrees of the goal?
drive ignores speed while turningReach the green zone at (82, 82) without touching either wall.
# 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 steer_to(x, y, speed=60):
# where am I?
px, py = position()
bearing = math.degrees(math.atan2(x - px, y - py))
error = wrapped(bearing - heading())
# forward, sideways, rotation: -100 to 100 each, until the next command
drive(speed if abs(error) < 25 else 0, 0, max(-60, min(60, error * 3)))
def near(x, y, cm=6):
# where am I?
px, py = position()
return math.hypot(x - px, y - py) < cm
goal = (82 - 15, 82 - 15)
# do this 390 times (tick counts from 0)
for tick in range(390):
if near(*goal, cm=5):
# leave the loop
break
steer_to(*goal, speed=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: Head for the green zone at (82, 82), but avoiding things comes first: when the distance sensor sees something close, deal with that before seeking again.
from bugbot import *
connect()
def wrapped(h):
return (h + 180) % 360 - 180
import math
def steer_to(x, y, speed=60):
# one tick of driving towards (x, y), relative to the start: turn to face it, go when roughly facing it
px, py = position()
bearing = math.degrees(math.atan2(x - px, y - py))
error = wrapped(bearing - heading())
drive(speed if abs(error) < 25 else 0, 0, max(-60, min(60, error * 3)))
def near(x, y, cm=6):
px, py = position()
return math.hypot(x - px, y - py) < cm
goal = (82 - 15, 82 - 15) # relative to the start
state = "seek"
avoid_ticks = 0
for tick in range(390):
if near(*goal, cm=5):
break
if state == "seek" and distance() < 22:
state = "avoid" # avoiding takes over completely...
avoid_ticks = 0
if state == "avoid":
drive(-10, 60, 0) # ...back a touch and slide right
avoid_ticks += 1
if avoid_ticks >= 10:
state = "seek" # ...then seeking gets the robot back
else:
steer_to(*goal, speed=60)
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.