Move the Robot
Walk, strafe and turn with one verb: set_velocity.
One verb drives the robot: set_velocity. Forward,
sideways and turning are three arguments of it, not three commands.
from menlo.asimov import Mode, Robot
with Robot().connect() as robot:
if robot.state.mode is Mode.DAMP:
robot.stand()
robot.wait_for(Mode.STAND, timeout=20.0)
robot.set_velocity(vx=0.3, duration=2.0, wait=True) # forward, 2 s
robot.set_velocity(vx=-0.3, duration=2.0, wait=True) # backward
robot.set_velocity(vyaw=0.8, duration=5.0, wait=True) # turn on the spot
robot.stop() # zero: stand still, still balancingWake It First
A robot at rest sits in DAMP, and velocity alone will not wake it — the command is
dropped before it reaches the firmware. Call stand() first, every time.
See the ladder.
Holding, and Letting Go
set_velocity is held: the SDK re-sends it at 10 Hz so a dropped packet doesn't stop the
robot mid-stride, and so your script can spend most of a second on vision between calls. It
stops when you supersede it, when duration expires, or when the link dies.
set_velocity returns at once, duration or not. The hold runs in the background; the
next verb, or the end of the with block, cuts it short. Either sleep for the duration or pass
wait=True to block until the hold ended and its zero went out.
| You want | Do this |
|---|---|
| walk until I say otherwise | set_velocity(vx=0.3) |
| walk for exactly 2 s, then continue the script | set_velocity(vx=0.3, duration=2.0, wait=True) |
| walk for 2 s while doing something else | set_velocity(vx=0.3, duration=2.0) then your work |
| stop, keep balancing | stop() |
| stop, go limp | damp() |
Zero velocity is how it stands still
stop() sends zero on every axis. The robot stays in MOVE and the walking policy keeps
balancing it — that is what standing still looks like for a free biped.
Ending a Walk
End a walk at zero velocity. Do not call stand() to finish — it stiffens rather than
balances, and tips a free-standing robot over. See
Safety.
robot.set_velocity(vx=0.3, duration=4.0, wait=True)
robot.stop() # correct ending
# robot.stand() # tips a free-standing robot overTurning by Heading
state.yaw is the IMU heading, counter-clockwise, relative to wherever the firmware booted.
Only differences mean anything, and they wrap:
import math
before = robot.state.yaw
robot.set_velocity(vyaw=0.9, duration=math.pi / 0.9, wait=True) # half a turn, open loop
after = robot.wait_until(lambda s: s.age_s < 0.2, timeout=2.0).yaw
turned = math.remainder(after - before, math.tau) # in (-π, π]What Actually Went Out
Every verb returns a Sent describing the command that
reached the wire, already clamped:
sent = robot.set_velocity(vx=2.0)
sent.command # Velocity(vx=0.6, vy=0.0, vyaw=0.0)
sent.clamped # True — 2.0 was above the limitDefaults are 0.6 m/s forward, 0.6 m/s sideways, 1.5 rad/s turning. Read them from
robot.info.limits, or pass your own limits= to Robot(...). The clamp is there so a
typo'd vx=20 is a visibly clamped command rather than a lunge; the robot clamps again on
its own side.
Next
- Control Joints Directly — when a gait won't do
- Read State and React — waiting on the robot's own report
How is this guide?