Skip to main content
Integrating physical robots with cloud-hosted Vision-Language-Action (VLA) models requires reliable control rates, deterministic safety bounds, and low-latency network streaming. Servo connects model inputs and outputs directly to whatever your robot provides—Python callables, hardware camera handles, or ROS 2 topics—without requiring custom framework wrappers or brittle configuration files.
Preview. The servo.connect API is currently in developer preview and not yet shipped in general availability. Early feedback and testing are welcome. Code samples on this page import connect/camera/inspect/gym_step explicitly from servo.universal — they don’t yet resolve as servo.connect etc.

The Connection Pattern

Every VLA policy operates on a simple principle: it consumes observations (camera feeds, joint states) and outputs actions (target joint positions or velocities). servo.connect() binds these inputs and outputs in a few lines of Python:
Servo manages the background daemon (servo daemon), camera frame capture, hardware video encoding, and network transport automatically.

Discovering Model Contracts

Different VLA models expect different inputs and outputs. The exact contract is resolved for a hosted checkpoint and registered robot together: a model family can support several embodiments with different sensors. Servo’s built-in local development profile for allenai/MolmoAct2-BimanualYAM uses the top, left, right, and state observation slots. Before writing integration code, inspect the server-resolved contract in Python:

1. Python inspection (servo.inspect)

The contract is a property of the (model, robot) pairing, not the model alone, so robot is required — pass a registered robot name (same resolution as connect(robot=...)):
This current flat inspection projection reports model-prepared observation inputs. It does not yet preserve the full inference contract or expose action outputs; use robot.check(policy) to validate the complete live path.

2. Immediate preflight error detection

For the exact built-in MolmoAct2 development profile, servo.connect() checks the observed slot names immediately at startup. A missing slot or typo (such as "front" instead of "top") fails before a control loop starts:

3. Static type checking & IDE autocomplete

The Servo SDK provides TypedDict definitions so your IDE (VS Code, PyCharm) can autocomplete slot names and flag errors with static type checkers like mypy or pyright:
The explicit annotation is what enables slot-name checking and IDE completion; connect() does not infer a model-specific TypedDict from a string literal.

Supplying Observations (observe)

The observe argument accepts several flexible formats depending on your hardware and software stack:

Option A: Dedicated hardware camera handles

For USB and RealSense cameras, use servo.camera(serial="..."). Servo opens cameras using zero-copy DMA-BUF streaming directly into hardware video encoders:
The customer CLI does not expose automatic camera discovery yet. Generic V4L2 cameras can be opened by a verified device index. For a supported Intel RealSense installation, pass a known vendor serial and verify each role before starting a session.

Option B: Python callable functions

Pass any non-blocking callable returning a NumPy array or PyTorch tensor:
  • Images: (H, W, 3) uint8 RGB NumPy arrays. (If OpenCV outputs BGR, pass servo.camera(..., color_space="bgr") or convert with cv2.cvtColor).
  • Joint States: 1D vector (N,) float32 in radians for revolute joints, meters for prismatic joints.

Option C: Unified observation method (Simulators & existing environments)

If you already have a custom driver or simulation environment with an atomic observation function, pass that function directly:

Option D: ROS 2 topic strings

If your robot runs on ROS 2, pass your active node and topic names directly:
Servo automatically subscribes to standard ROS message types (sensor_msgs/Image, sensor_msgs/JointState) and publishes commands.

Commanding Motor Actuators (act)

On each control cycle (e.g. 30 Hz), Servo passes the target action array (e.g. (14,) float32) to your act callable:

Return semantics

Wrapping existing Gym environments

If wrapping a standard Gym env.step method, use servo.gym_step to cleanly handle step tuples:

Built-in Safety: Zero-velocity hold on fault

When controlling physical hardware, software errors must never cause runaway motor movements. If your act function raises an exception (such as motor overcurrent, joint limit reached, bus timeout, or E-stop trigger):
  1. Active Zero-Velocity Hold: Servo catches the exception immediately and commands actuators to lock position or hold zero velocity.
  2. Telemetry Preservation: All video frames, network round-trip traces, and joint timestamps leading up to the exact moment of failure are flushed and preserved.
  3. Structured Reporting: session.run() exits safely and returns a RunReport with report.status = "fault" and report.error = str(exception).

Running Episodes & Controlling Motion

Executing an episode (session.run)

session.run() executes a bounded autonomous rollout and returns a RunReport:
Current limitations: until=/on_step= are only implemented for mock=True sessions today — passing either to a real (non-mock) run raises rather than silently no-op’ing, since the real chunked control loop has no per-step hook or early-stop predicate yet (only a coarser on_chunk= via robot.run()). report.dataset_path is also always None on a real run today: a bare connect(model, robot=...) binding has no deployment to record episodes against, unlike deployment.policy()/fleet.policy() — see ROBOT_INTEGRATION_SPEC.md’s “Known limitation” note.

Non-blocking camera preview

To display a live camera feed in a local OpenCV window or web viewer without slowing down the 30 Hz control loop:

Pausing and resuming motion

If an obstacle appears or a human enters the workcell:

Direct Functional Control Loop (servo.Policy)

If your system already manages its own custom while loop (for custom safety filters, low-level trajectory smoothing, or custom step logging), use servo.Policy:
Each call to policy(...) returns the first row of the chunk the model returned. It does not buffer or prefetch — every call is one real network round trip — so call it no faster than your model’s round-trip allows, or add your own buffering for a tighter loop.

Remote Operations (session.listen)

In automated workcells and production lines, the robot script often runs continuously on the cell IPC while tasks are triggered remotely by a central scheduler, web console, or CI script:

Zero-Motion Preflight (servo check-rig)

Before powering on robot motors, run zero-motion preflight against your integration script:

How Servo Manages Streaming Under the Hood

Servo is designed to give you smooth, stutter-free 30 Hz control even when connecting to remote cloud GPUs over the internet:
  1. Local Background Daemon (servo daemon): Decouples your robot control loop from network traffic and video encoding. Video compression happens on hardware silicon without consuming CPU cycles needed by your motor drivers.
  2. Pipelined Action Prefetching: VLA models predict chunks of future actions (e.g. 30 steps ahead). While your robot executes step 15, Servo captures the next observation and prefetches the next action chunk from the cloud. When step 30 finishes, step 31 is already waiting—eliminating boundary pauses.
  3. Smooth Teleoperation Blending: When transitioning between autonomous policy control and human gamepad teleoperation, Servo applies a 50 ms velocity blend to eliminate sudden motion jolts and protect robot gearboxes.