7. Moving to a certain position
Where the robot is, and how to send it somewhere
The problem. drive() and spin() are open-loop: they run the wheels for a time and never check where the robot ended up. On the floor, a wheel slips or a turn comes out at 85 degrees, and nothing corrects it, which is why your step 6 robot does not end exactly where the simulator’s did, and the challenge square does not quite close. goto() is closed-loop: the robot reads its own position all the way and keeps correcting until it is there.
Where am I: the frame
robot.position() gives where the robot is, as (x, y) in millimetres, measured by the lighthouse (step 2). The origin is the top-left corner of the map, x grows to the right and y grows down (Figure 1). So “300 mm up the map” is (x, y - 300).
y grows down, so going up the map takes y down.
Coordinates belong to the controller you talk to. Each controller places its map on a site. Your own simulator uses the default site, a 2 x 2 m field; the room’s real floor uses the instructor’s site, with a staging area along the top and other numbers. So:
- Relative moves work everywhere. A target computed from
robot.position(), like(x, y - 300), means the same thing in your simulator and on the floor. Every script on this page does that. - Absolute targets do not travel. A fixed
goto(1000, 1200)must be read off the map of the controller you are connected to (hover over the console map to see the coordinates), not off your simulator’s map.
Going there: goto() and arrived()
robot.goto(x, y)gives the robot a target. The robot drives there by itself and stops once it is withinthresholdmm of it (60 by default).goto()returns at once: the robot is still on its way.robot.arrived()isTrueonce it is there. Wait for it in a loop, instead of atime.sleep()that guesses how long the trip takes.academy.distance(a, b)is the distance in mm between two(x, y)points, to check how close it got.
goto() returns immediately: the robot drives there by itself. Use arrived() to wait.
Save example.py next to academy.py and run it against your simulator, python example.py.
example.py
import time
import academy
academy.connect("http://localhost:8000") # your simulator
robot = academy.bot("000000") # its first robot
x, y = robot.position() # in mm: x grows to the right, y grows DOWN the map
print("Start:", x, y)
for target in [(x, y - 300), (x + 300, y - 300), (x, y)]: # up, right, back
robot.led(0, 0, 255) # blue while it drives
robot.goto(*target)
while not robot.arrived():
time.sleep(0.5)
robot.led(0, 255, 0) # green: there
off = academy.distance(robot.position(), target)
print("At", robot.position(), f"{off:.0f} mm from {target}")You should see: robot 000000 goes up, right and back to where it started, blue while it drives and green at each target, and the terminal prints how many mm from each target it stopped.
Core there and back
Save exercise.py (below), fill in its two TODOs, and run it against your simulator. When it works there, run it on your real robot: change BASE_URL and LABEL as in step 6.
You should see: the robot turns red, drives 300 mm up the map, comes back and turns green.
exercise.py
"""Step 7: moving to a certain position.
Building on example.py: turn the robot red, send it 300 mm up the map, bring it
back and turn it green.
You should see: on the map, the robot turns red, drives up, comes back, turns green.
"""
import time
import academy
BASE_URL = "http://localhost:8000" # your simulator; or the instructor's controller, as in step 6
LABEL = "000000" # the simulator's first robot; or your real robot's label, as in step 6
academy.connect(BASE_URL)
robot = academy.bot(LABEL)
# 1. Turn it red this time.
# TODO
x, y = robot.position()
print("Start:", x, y)
# 2. Send it 300 mm up the map. Instead of a fixed sleep, wait until it is there.
robot.goto(x, y - 300)
while not robot.arrived():
time.sleep(0.5)
# 3. Bring it back to (x, y), wait the same way, then turn it green.
# TODO
print("Back at", robot.position())goto() only gives the robot its target, then returns at once. The while not robot.arrived() loop is what makes your script wait until the robot is there before it sends the next order.
cannot unpack non-iterable NoneType:position()returnedNone, so the lighthouse cannot see the robot. Call the instructor.- The robot never arrives: it is circling close to the target. Stop the script with Ctrl+C, check that the floor around the target is free, and run it again.
solution.py
"""Step 7: moving to a certain position.
Building on example.py: turn the robot red, send it 300 mm up the map, bring it
back and turn it green.
You should see: on the map, the robot turns red, drives up, comes back, turns green.
"""
import time
import academy
BASE_URL = "http://localhost:8000" # your simulator; or the instructor's controller, as in step 6
LABEL = "000000" # the simulator's first robot; or your real robot's label, as in step 6
academy.connect(BASE_URL)
robot = academy.bot(LABEL)
# 1. Turn it red this time.
robot.led(255, 0, 0)
x, y = robot.position()
print("Start:", x, y)
# 2. Send it 300 mm up the map. Instead of a fixed sleep, wait until it is there.
robot.goto(x, y - 300)
while not robot.arrived():
time.sleep(0.5)
# 3. Bring it back to (x, y), wait the same way, then turn it green.
robot.goto(x, y)
while not robot.arrived():
time.sleep(0.5)
robot.led(0, 255, 0)
print("Back at", robot.position())