Project: a shape in the world
Drive a square in world coordinates while the robot spins, which only a holonomic drive can do.
Do this lesson in the simulatorA square is easy when the robot faces the way it is going. Drive, turn, drive, turn. Now do it while the robot spins the whole time.
This is the exercise that separates the two frames for good. The path is in the world. The commands are in the body. The heading is changing continuously, so the relationship between them changes every tick, and any line of code that assumed forward means north will show it immediately.
The structure
for each corner of the square:
until close to that corner:
vector to the corner, in the world
speed proportional to the gap, capped
inverse kinematics with the heading you have NOW
plus a rotation term, all the way
The rotation term never stops. The robot turns continuously; the translation is computed afresh each tick against the new heading. That is the whole trick, and it is why the heading has to be read inside the loop rather than once at the top.
from bugbot import *
import math
connect()
V_MAX, V_LAT = 20.0, 15.0
def world_drive(wx, wy, spin=0.0):
a = math.radians(heading())
vx = wx * math.cos(a) - wy * math.sin(a)
vy = wx * math.sin(a) + wy * math.cos(a)
drive(100 * vy / V_MAX, 100 * vx / V_LAT, spin)
for tick in range(40):
world_drive(10, 0, 25) # due east, spinning
wait(0.1)
stop()
print("ended", position(), "facing", round(heading()))
Run it and watch: the robot spins, and travels in a straight line east while it does. If the line bends, the heading is being read in the wrong place.
Task: a square while spinning
Visit the four corner zones in order, east then north then west then home, with a rotation term running all the way round.
from bugbot import *
import math
connect()
V_MAX, V_LAT = 20.0, 15.0
# the corners, in cm from where the robot started
CORNERS = [(40, 0), (40, 60), (-20, 60), (-20, 0)]
Challenges
- Plot the world path by printing x and y each tick, and check the corners are square.
- Make the robot face the corner it is heading for, instead of spinning. Which is easier to write, and which is easier to watch?
- Do the whole square with
odometry()instead ofposition(). How square is it by the fourth corner?
What comes next
U3 takes that last challenge seriously. Dead reckoning is the only thing a robot has when nothing is watching it, and the module is about how it fails, how fast, and what it costs.