Skip to main content
LeRobot’s async inference system enables you to run policy inference on a remote server (typically a GPU machine) while controlling your robot from a separate client (typically running on the robot’s embedded computer). This architecture minimizes latency and enables real-time robot control.

Architecture

The async inference system consists of two components:
  • Policy Server: Runs the neural network policy on a GPU machine
  • Robot Client: Controls the robot and communicates with the policy server
They communicate via gRPC, streaming observations from the robot to the server and receiving action chunks in return.

Starting the Policy Server

The policy server loads a pretrained model and waits for client connections:

Server Configuration

str
default:"localhost"
Server host address to bind to
int
default:"8080"
Server port number
int
default:"30"
Target frames per second for observation processing
float
default:"0.033"
Target inference latency in seconds (controls inference throttling)
float
default:"1.0"
Timeout for observation queue in seconds

Running the Robot Client

The robot client captures observations, sends them to the server, and executes received actions:

Client Configuration

RobotConfig
required
Robot configuration including type, port, and camera setup
str
Task instruction for the robot (e.g., “pick up the cup”)
str
default:"localhost:8080"
Address of the policy server
str
required
Type of policy to use (e.g., “act”, “pi0”, “diffusion”)
str
required
HuggingFace Hub model ID or local path to pretrained model
str
default:"cpu"
Device for policy inference on the server (e.g., “cuda”, “cuda:0”, “mps”)
str
default:"cpu"
Device to move actions to after receiving from server
int
required
Number of actions per chunk to request from the policy
float
default:"0.5"
Threshold for triggering new observations (0.0-1.0). When the action queue size drops below chunk_size_threshold * actions_per_chunk, a new observation is sent to the server.
str
default:"weighted_average"
Function to aggregate overlapping actions. Options:
  • weighted_average: 0.3 * old + 0.7 * new
  • latest_only: Always use new actions
  • average: 0.5 * old + 0.5 * new
  • conservative: 0.7 * old + 0.3 * new

Control Flow

The async inference system operates in two parallel threads on the client:

Thread 1: Control Loop

Runs at the robot’s control frequency (e.g., 30 Hz):
  1. Execute Action: If actions are available in the queue, pop and execute the next action
  2. Stream Observation: When queue size drops below threshold, capture and send observation to server

Thread 2: Action Receiver

Continuously receives action chunks from the server:

Action Queue Management

The client maintains an action queue and aggregates overlapping actions:

Must-Go Observations

The system uses a “must-go” flag to ensure observations are processed when the action queue is empty:
This prevents the robot from stalling when no actions are available.

Server-Side Processing

The policy server maintains an observation queue (size 1) and processes observations on demand:

Performance Optimization

Reduce Observation Sending

Adjust chunk_size_threshold to control how often observations are sent:

Custom Aggregation Functions

Define custom aggregation logic for your robot:

Device Placement

Move actions to GPU for downstream planners:

Debugging

Enable debug visualization to monitor action queue size:
This generates a plot showing action queue size over time after the session ends.

Example: SO-100 Robot

Complete example for running async inference on an SO-100 robot:

API Reference

RobotClient

See lerobot/async_inference/robot_client.py:83
() -> bool
Connect to the policy server and initialize the client
() -> None
Stop the client and disconnect from the server
(task: str) -> tuple[Observation, Action]
Main control loop that executes actions and streams observations

PolicyServer

See lerobot/async_inference/policy_server.py:66
(RemotePolicyConfig) -> Empty
Load the policy model based on client instructions
(TimedObservation) -> Empty
Receive observation from the robot client
() -> Actions
Generate and return action chunk based on latest observation