Menlo
Asimov API

Protocols

Command and telemetry field reference for the Asimov robot API.

All commands and telemetry use Protocol Buffers, sent over LiveKit DataChannels and DataTracks.

Commands

Commands are sent from your application to the robot on the commands data channel.

CloudCommand

Every command is wrapped in a CloudCommand envelope with a timestamp and sequence number.

FieldTypeDescription
timestamp_usuint64Timestamp in microseconds
sequenceuint32Monotonic sequence number
velocityVelocityCommandWalk command (one of)
trajectoryTrajectoryRequestDirect joint control (one of)
modeModeCommandMode switch (one of)

Only one of velocity, trajectory, or mode should be set per command.


VelocityCommand

Make the robot walk with the given velocity. Automatically enters MOVE/POLICY mode.

FieldTypeRangeUnitDescription
vxfloat-2.0 to 2.0m/sForward / backward velocity
vyfloat-1.0 to 1.0m/sLeft / right lateral velocity
vyawfloat-2.0 to 2.0rad/sYaw rotation rate

Example (Python)

import asyncio
import time
from livekit import rtc
from edge.generated.edge_cloud_pb2 import CloudCommand, VelocityCommand


async def main():
    room = rtc.Room()
    await room.connect(livekit_url, token)

    # Send velocity command
    cmd = CloudCommand(
        timestamp_us=int(time.time() * 1e6),
        sequence=1,
        velocity=VelocityCommand(vx=0.3, vy=0.0, vyaw=0.0)
    )
    await room.local_participant.publish_data(
        cmd.SerializeToString(), topic="commands", reliable=True
    )

    await asyncio.sleep(1)


if __name__ == "__main__":
    asyncio.run(main())

TrajectoryRequest

Command a direct joint trajectory. Positions use firmware order (25 joints) — see Joint Order.

FieldTypeDescription
fullFullTrajectoryCustom joint trajectory

FullTrajectory

A sequence of joint position targets with timing.

FieldTypeDescription
segmentsJointSegment[]Ordered list of target poses

JointSegment

FieldCountRangeUnitDescription
positions25motor-specificradiansTarget joint positions in firmware order. Every entry drives its motor — no skip sentinel.
kp250 – 500Position gain per joint (optional — edge fills defaults if omitted)
kd250 – 5.0Velocity damping gain per joint (optional — edge fills defaults if omitted)

Each JointSegment is applied as an instantaneous PD target. There is no in-firmware interpolation between segments — clients are responsible for any smoothing.


ModeCommand

Switch the robot's control mode.

FieldTypeValuesDescription
modeMode enumMODE_STAND=0, MODE_DAMP=1Target mode

Watch out: The command enum (Mode) and the telemetry enum (FirmwareMode) use different numbering for the same modes:

DAMPSTAND
Commands (Mode)10
Telemetry (FirmwareMode)01

Don't compare them numerically — use the named constants.

See Robot Control for mode transitions.


Telemetry

Sent from the robot at 10 Hz on the telemetry DataTrack (lossy — dropped packets are acceptable since the next update arrives in 100ms).

FieldTypeCountDescription
timestamp_usuint641Edge clock (microseconds)
fw_timestamp_usuint641Firmware clock (microseconds)
sequenceuint321Monotonic counter
fw_modeFirmwareMode1FW_MODE_DAMP=0, FW_MODE_STAND=1, FW_MODE_MOVE=2
joint_posfloat25Joint positions (radians)
joint_velfloat25Joint velocities (rad/s)
joint_currentfloat25Motor current (amps)
joint_tempfloat25Motor temperature (celsius)
imu_quatfloat4Orientation quaternion [w, x, y, z]
imu_gyrofloat3Angular velocity [x, y, z] (rad/s)
imu_gravityfloat3Projected gravity vector [x, y, z]
error_flagsuint321Active errors bitfield
active_alertsFirmwareAlertrepeatedCurrent hardware alerts — see below
fw_age_msuint321Staleness of firmware data when forwarded (ms)
last_video_timestamp_usuint641Most recent video frame timestamp (for media sync)
last_audio_timestamp_usuint641Most recent audio frame timestamp (for media sync)

FirmwareAlert

Hardware alerts forwarded from the firmware safety layer. Present in EdgeTelemetry.active_alerts whenever an alert condition is active. Clears automatically when the condition resolves (e.g. motor cools below threshold).

FieldTypeDescription
iduint32Alert type identifier
severityuint32Severity level (see table below)
valueuint32Measured value that triggered the alert
thresholduint32Threshold that was exceeded
first_set_usuint64Firmware timestamp when alert first fired
source_iduint32Source (e.g. motor index)

Severity values:

ValueMeaning
0Critical
1Warning
2Info

Common alerts: motor overtemperature (trips at 80°C, clears at 70°C), fall detection, CAN bus faults.

Example (Python)

import asyncio
from livekit import rtc
from edge.generated.edge_cloud_pb2 import EdgeTelemetry


async def read_telemetry(track):
    stream = track.subscribe()
    async for frame in stream:
        t = EdgeTelemetry.FromString(frame.payload)
        print(f"Mode: {t.fw_mode}")
        print(f"Joint positions: {list(t.joint_pos)}")
        print(f"IMU quaternion: {list(t.imu_quat)}")


async def main():
    room = rtc.Room()
    await room.connect(livekit_url, token)

    # Telemetry arrives on a DataTrack, not a DataChannel
    @room.on("data_track_published")
    def on_data_track(track):
        asyncio.create_task(read_telemetry(track))

    await asyncio.sleep(10)


if __name__ == "__main__":
    asyncio.run(main())

System Events

Sent from the robot on the system data channel (reliable — these must not be lost).

EdgeEvent

FieldTypeDescription
timestamp_usuint64Timestamp in microseconds
sequenceuint32Monotonic counter
errorEdgeErrorError report (one of) — emitted on error
diagnosticsEdgeDiagnosticsStatus snapshot (one of) — emitted every ~1s
controllerControllerEventControl source change (one of) — emitted on change

EdgeError

FieldTypeDescription
subsystemSubsystemSource subsystem (see enum below)
codestringe.g. "CAMERA_OPEN_FAILED", "FW_LINK_TIMEOUT"
messagestringHuman-readable detail

Subsystem enum: SUBSYSTEM_FW_LINK=0, SUBSYSTEM_CAMERA=1, SUBSYSTEM_MIC=2, SUBSYSTEM_SPEAKER=3, SUBSYSTEM_BLE=4, SUBSYSTEM_CLOUD=5, SUBSYSTEM_FIRMWARE=6

EdgeDiagnostics

Emitted every ~1 second on the system channel. Provides a snapshot of edge and firmware health.

FieldTypeDescription
can_healthCanBusHealth[]Per-bus CAN statistics (frames sent/received, errors, bus-offs)
onnx_avg_msfloatAverage ONNX inference time (ms)
onnx_max_msfloatMax ONNX inference time (ms)
onnx_countuint64Total inference count
controllerstringActive controller: "ble", "cloud", or ""
provisionedboolRobot setup complete
cloud_connectedboolLiveKit connection active
ble_connectedboolPhone connected via BLE
camera_activeboolCamera capturing
mic_activeboolMicrophone active

ControllerEvent

Fired when the active control source changes.

FieldTypeDescription
previousstringPrevious controller
currentstringNew controller
reasonstring"acquired", "override", "timeout", "disconnect"

How is this guide?

On this page