Quickstart
Install menlo-sdk, save the robot, check it, then stand, balance, walk for 3 s and damp from Python.
By the end of this page the robot stands up from DAMP, balances on its own, walks forward for 3 s and rests again, from five short scripts.
Before the first walk
For a first run, hang the robot from its gantry hook with both feet on the floor and 2 m of clear floor ahead. Keep Asimov Manager open at the E-Stop, or be ready to cut power at the battery unit: nothing in the SDK is an emergency stop. Work through Before You Run a Script and Standing and Balancing first.
Install
Python 3.12 or newer.
pip install menlo-sdkor, in a project managed by uv, uv add menlo-sdk. One package drives every connection
mode; there are no extras.
Get the Examples
The scripts on this page are in the examples directory of the
menlo-sdk repository on GitHub.
Clone it and run them from there:
git clone https://github.com/menloresearch/menlo-sdk
cd menlo-sdk/examplesEach code block below shows the main part of a script. The full script also imports the
SDK, sets its constants and connects with with Robot().connect() as robot:, which waits
for the robot's first state.
Get an SDK Credential
The hybrid and livekit connection modes join the robot's LiveKit room with an SDK
credential from Asimov Manager; livekit also carries commands through it. Skip this step
for udp, which needs no credential.
-
In Asimov Manager, open Developer in the sidebar. Under How a script connects, note the Manager URL: it is the address the SDK uses to reach the robot.
You do not need the LiveKit URL or the Room. The SDK asks the robot for both each time it connects, and when the LiveKit URL reads
localhost, the SDK uses the robot's address instead. -
Under Issue a credential, enter a Name for the computer that will use it, such as
my-laptop. Issue one per computer, so you can revoke one without cutting off the others. -
Under What it may do, choose Control to drive the robot from your computer. Observe watches the camera and listens to the microphone only; the robot drops its commands.
-
Select Issue credential, then copy the credential with the copy button next to it. It is shown only this once: the robot keeps the credential's ID, not the credential, so it cannot show it again. If you lose it, revoke it and issue another.
-
The credential appears under Issued credentials with its role and ID. To take it back, select Revoke next to it; the computer holding it can no longer connect, and a session that is already running keeps working until its LiveKit token expires, at most 12 hours.
Save the Robot
menlo setupThe wizard asks for a name, a connection mode, and what the mode needs: the robot's
address for udp, the Manager URL and the credential for livekit, both for hybrid. It
checks each field against the robot before it saves, and every script below then finds the
robot with Robot() and no arguments.
udp and hybrid carry commands and state on the robot's network, and the robot sends
UDP state to one computer. In Asimov Manager, open Advanced Settings and, under
Asimov Edge, set udp-control to on and udp-state-host to your computer's address,
then select Save & Restart Asimov Edge. Without a saved robot, export MENLO_UDP_HOST=<robot address> points the SDK at the robot for one shell. To build the
connection in code, see Connection Modes.
Check
check.py connects, prints what stands in the way of a stand, a walk and a trajectory,
and sends nothing. Run it before anything that moves the robot:
# The SDK counts the 0.5 s a robot in STAND must be upright to arm from its own samples.
time.sleep(0.6)
print(f"robot mode {robot.get_state().mode.name}, armed {robot.armed}")
for action in ("stand", "move", "trajectory"):
print(robot.preflight(action)) # "ready to move", or "not ready to move:" and whypython check.pyEvery problem has a stable code and a one-line message; the codes and what clears each one
are in Check Before You Move. stand(),
balance() in STAND, set_velocity(), set_joints() and trajectory() run the same check before they send
anything, so the scripts below do not repeat it.
Stand
With the robot in DAMP, hanging from its gantry hook with both feet on the floor:
try:
# Checks the robot first. Returns once it reports STAND and has been upright for
# 0.5 s (armed): the firmware accepts MOVE only after that.
robot.stand()
except (NotReadyError, WaitTimeoutError) as exc:
print(exc) # what is wrong and what fixes it
sys.exit(1)
print(f"robot mode {robot.get_state().mode.name}, armed {robot.armed}")python stand.pyThe actuators hold a standing pose and stand() returns once the robot is armed: STAND
held upright for 0.5 s. It sends nothing else. When the robot is not ready, stand() raises
NotReadyError with nothing sent, and the script prints why; when the robot does not arm
within 10 s, it raises WaitTimeoutError. Call stand() only from DAMP, never after a
walk: STAND has no balance loop.
Balance
With the robot armed and still on its gantry hook:
try:
# Checks the robot first when it is in STAND. Returns once it reports MOVE.
robot.balance()
except (NotReadyError, WaitTimeoutError) as exc:
print(exc) # what is wrong and what fixes it
sys.exit(1)
print(f"robot mode {robot.get_state().mode.name}, balancing in place")python balance.pybalance() sends zero velocity, which puts an armed robot in MOVE: the walking policy
balances it in place, and this is the only robot mode in which it stands free. It returns
once the robot reports MOVE, or raises WaitTimeoutError after 5 s. Once it has returned,
slacken the gantry gradually until the robot carries its own weight.
Walk
With the robot balancing in MOVE:
try:
# Checks the robot first: it must be in MOVE. Held and re-sent at 10 Hz for
# DURATION_S, then zero velocity; returns after that.
sent = robot.set_velocity(vx=VX, vy=VY, vyaw=VYAW, duration=DURATION_S)
except NotReadyError as exc: # nothing was sent, or (RobotFaultedError) a fault ended it
print(exc)
sys.exit(1)
if sent.clamped:
print("the SDK reduced the speed to the robot's limits:", sent.command)
print(f"robot mode {robot.get_state().mode.name}, balancing in place")python walk.pyWhat each line does:
| Line | Effect |
|---|---|
set_velocity(vx=VX, vy=VY, vyaw=VYAW, duration=DURATION_S) | Checks that the robot is in MOVE and ready to walk, then walks at the set velocity for the duration; the SDK re-sends the velocity while it is held, sends zero velocity when the duration ends, and returns after that |
except NotReadyError | The check failed and nothing was sent, or a fault ended the walk (a RobotFaultedError with .sent set); the message says what is wrong and what fixes it |
sent.clamped | True when the SDK reduced the speed to the robot's limits; sent.command is what went out |
After the walk the robot stays in MOVE, balancing in place. The velocity and duration are
constants at the top of the file. Leaving the with block closes the connection; a held
velocity gets a zero first. The script never changes the robot mode: on a robot in STAND it
prints not ready to move: the robot is in STAND; balance() it first (wrong_mode) and
exits.
Put the Robot Down
damp() makes every actuator compliant. A standing robot folds, so support it first: take
up the gantry's slack, or seat the robot on a bench.
# damp() is never refused, so there is no check here, only the question.
if not YES:
mode = robot.get_state().mode.name
question = f"Robot mode {mode}. Is the robot supported? Damp now? [y/N] "
if input(question).strip().lower() not in ("y", "yes"):
print("nothing sent")
sys.exit(0)
try:
robot.damp() # returns once the robot reports DAMP
except WaitTimeoutError as exc: # sent, but DAMP was not reported: the message says what next
print(exc)
sys.exit(1)
print(f"robot mode {robot.get_state().mode.name}")python damp.pyThe script asks for confirmation unless YES is set to True at the top of the file.
damp() is not an emergency stop; for that, use the E-Stop in Asimov Manager, or cut power
at the battery unit (Stopping the Robot).
What Ready Means
A command that moves the robot checks it first and raises NotReadyError instead of
guessing. The message names each blocking problem, its code and what fixes it, and the
exception carries the problems. Read it before you retry:
from menlo.asimov import NotReadyError, Robot
with Robot().connect() as robot:
try:
robot.set_velocity(vx=0.3, duration=3.0)
except NotReadyError as e:
print(e) # not ready to move: the robot is in DAMP; stand() it first (wrong_mode)
print(e.preflight) # one line per problem, blocking ones firstA problem that clears on its own, such as a robot that is in STAND but has not held it
upright for 0.5 s, is waited out for up to timeout seconds (5 s by default) before the
command raises. balance() in MOVE and damp() are never refused. The full picture is in
Check Before You Move.
Next Steps
- Move the Robot: turning, holding a velocity, limits
- Safety: what the SDK does and does not do for you
- Examples: every script in the repository, including
keyboard.pyfor driving from the keyboard - Command Line:
menlo setupto save a robot,menlo status --watchwhile you develop
Related
- Drive from Python: the same path with the robot's settings, video and sound
- Stand Up and Walk: the same sequence from the Cockpit
How is this guide?