Menlo
Python SDK

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 control

A 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 True

Don'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.

Next: Connect for the LAN lane and the other ways in, then Safety before you let go of the robot.

How is this guide?

On this page