Quickstart
Install menlo-sdk, log in to a robot, stand and walk — in five minutes.
Install
uv add --prerelease allow "menlo-sdk[livekit]" # or: pip install --pre "menlo-sdk[livekit]"Python 3.12 or newer. Releases are pre-releases for now, so the resolver needs to be told to
accept one. The core pulls in protobuf and asimov-protocol; the [livekit] extra adds
the camera, microphone and speaker lane. Without it the SDK drives a robot over UDP only.
Get a Credential and Log In
On the robot, mint an SDK credential: the manager's SDK page, or
asimovctl sdk-token create --name laptop --role controlA control credential may drive and talk; observe may only watch. Then, on your machine:
menlo login http://<robot-address> --credential <credential>login asks the robot's manager for a LiveKit token exactly as a script would, and saves the
manager URL and credential to ~/.menlo/robots.toml only when that works. Nothing prints the
credential back. menlo robots lists what is saved; menlo use <name> picks the default.
Connect and Read
from menlo.asimov import Robot
with Robot().connect() as robot: # the robot you logged in to
print(robot.info) # transport, joints, capabilities
s = robot.state
print(s.mode.name, s.upright, f"{s.age_s:.3f}s old")
print(s.joint("L_Knee").pos, "rad")connect returns once the robot has reported in and its protocol version matches. Otherwise
you get a ConnectError that says what to check. Robot() with no argument reads
MENLO_MANAGER_URL and MENLO_CREDENTIAL from the environment first, then the store.
Stand, Walk, Rest
from menlo.asimov import Robot, Mode
with Robot().connect() as robot:
if robot.state.mode is Mode.DAMP:
robot.stand()
robot.wait_for(Mode.STAND, timeout=15.0) # the FIRMWARE reports standing
robot.set_velocity(vx=0.25, duration=4.0, wait=True) # walks 4 s, sends the zero, returns
robot.wait_for(Mode.MOVE, timeout=5.0)
# Ends in MOVE at zero velocity, still balancing. That's where a walk should end.
print(robot.state.mode.name, robot.state.upright) # MOVE TrueDon't finish a walk with stand()
STAND has no balance loop — a free-standing robot asked to stiffen after walking tips over. Stay in MOVE at zero velocity instead. Safety explains why.
Waits read the robot's own report and raise when the answer can't come: RobotFaultedError if it fault-DAMPed, StateStaleError if it went quiet, WaitTimeoutError otherwise.
Stop
robot.stop() # zero velocity — the robot keeps its feet
robot.damp() # motors compliant now — a standing robot folds. The emergency verb.Leaving the with block calls close(): sends a zero if one is held, drops the link, never damps. A script that ends or crashes leaves the robot on its feet.
How is this guide?