Asking
A question and a reply, with a timeout; going where you are told.
Do this lesson in the simulatorLesson 9.3 asked for instructions. This one asks for information: where another robot is, then goes there. The Scout on this mat answers where are you? with at <x>,<y>.
The same map
A position is only useful if both robots measure it the same way. The Scout reports positions the way your position() does: from your starting point, x to the right, y forward. Agreeing a shared origin is the first thing any group of robots has to do, and on this mat it is done for you. In the games every robot uses the mat's corner.
# 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 ask(question, seconds=1.0):
# send a question and return the first reply that arrives within `seconds`, or None
send(question)
for tick in range(int(seconds * 10)):
# pause 0.1 s (the robot keeps doing what it was told)
wait(0.1)
for sender, text in messages():
return text
return None
def numbers_in(text):
# every number in a message, as floats: "at 25,55" -> [25.0, 55.0]
out = []
for word in text.replace(",", " ").split():
try:
out.append(float(word))
except ValueError:
pass
return out
reply = ask("where are you?")
print("scout says:", reply)
sx, sy = numbers_in(reply)
# where am I? (cm from where I started)
x, y = position()
print(f"the scout is {math.hypot(sx - x, sy - y):.0f} cm away")
numbers_in pulls every number out of a message, whatever else is in it: at 25,55 becomes [25.0, 55.0]. Forgiving in.
Going there
go_to from Module 5 slides the robot to a point. Aim a robot's length short of the Scout, or you will drive into it:
# 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 ask(question, seconds=1.0):
# send a question and return the first reply that arrives within `seconds`, or None
send(question)
for tick in range(int(seconds * 10)):
# pause 0.1 s (the robot keeps doing what it was told)
wait(0.1)
for sender, text in messages():
return text
return None
def numbers_in(text):
# every number in a message, as floats: "at 25,55" -> [25.0, 55.0]
out = []
for word in text.replace(",", " ").split():
try:
out.append(float(word))
except ValueError:
pass
return out
sx, sy = numbers_in(ask("where are you?"))
while not near(sx, sy - 13):
go_to(sx, sy - 13)
# pause 0.1 s (the robot keeps doing what it was told)
wait(0.1)
# all motors off
stop()
print("stopped at", position(), "facing the scout at", (sx, sy))
Ask again
The answer was true when it was sent. A robot that moves needs asking again. In the games, me.others gives every robot's position for free, but a real team of robots gets that only by asking each other, over and over.
Task: meet the scout
Ask the Scout where it is and stop in the green square, 13 cm in front of it, without touching it.
# 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 ask(question, seconds=1.0):
# send a question and return the first reply that arrives within `seconds`, or None
send(question)
for tick in range(int(seconds * 10)):
# pause 0.1 s (the robot keeps doing what it was told)
wait(0.1)
for sender, text in messages():
return text
return None
def numbers_in(text):
# every number in a message, as floats: "at 25,55" -> [25.0, 55.0]
out = []
for word in text.replace(",", " ").split():
try:
out.append(float(word))
except ValueError:
pass
return out
reply = ask('where are you?')
print('scout says:', reply)
Challenges
- Ask again once you arrive and print how far off the first answer was.
- End facing the Scout: turn to the bearing of (sx, sy) from where you stopped.
- Print
no answerand stay put if the Scout does not reply within a second.