Skip to main content
Run Policy and DAgger collection can drive the arms with your own model, in any framework. It can be a JAX model, a different PyTorch version, a VLA served elsewhere or a hand-written controller.
  1. Wrap the model in a small server with the almond_axol.policy SDK.
  2. Start Run Policy or DAgger collection with --policy_type custom.
The robot sends your server the arm state and camera frames, and runs the action chunks it returns. The robot never loads the model. Your server handles preprocessing, inference, instructions, postprocessing and any blending between chunks. While the server works on a new plan, the robot keeps running the current one. When the new plan arrives, the robot switches to it at the row that is due, so a slow network doesn’t stall the arms. See Timing and continuity for details.

Write the policy

Install almond-axol wherever the model runs. The base install is enough. LeRobot and PyTorch aren’t needed. Subclass Policy and start it with serve():
infer returns T future targets, one row per control tick, in spec.action_names order. See Action chunks for the accepted shapes and State and action names for the layout. If you trained on a dataset from Data Collection, the names match its observation.state and action features. The robot runs each chunk as sent and switches to a new one at the row that is due when it arrives. To keep that switch smooth, do one of these:
  • Continue the motion in progress. Condition on obs.plan, or at least start near obs.plan[0].
  • Ensemble on the server. Use serve(..., ensemble=0.01) for an ACT-style chunked policy trained with temporal ensembling.
serve() handles the rest of the interface. It confirms the session settings, keeps the plans it sent so obs.plan works, clears them on reset, and shows your exceptions to the operator. To write the server in another language, follow the interface reference. Your policy chooses the model, checkpoint and instruction. On the robot, --task only labels recorded episodes, and --policy_path is not used.

Check it without the robot

With the server running, play the robot’s side of a session against it:
policy.check runs the robot’s scheduler on a simulated clock, here with 3 ticks of reply delay. It reports:
  • replies that arrive too late,
  • the server’s round-trip time, and
  • the largest jumps where one plan hands over to the next.
Match --cameras, --cartesian and the chunk settings to your robot. check_policy() does the same from Python, for unit tests.

Run on the robot host

Replace the endpoint address and camera serial with your configuration:
The command connects to your server. It doesn’t start one. Without --server_host, it connects to 127.0.0.1. An episode can start only when the robot and the server agree on the cameras, state and actions. To run it from the control panel:
  1. Start your serve() process. The panel doesn’t start it.
  2. Assign the cameras.
  3. Select Run policy and choose policy type custom.
  4. Enter the task label and leave the policy path blank.
  5. Set the server’s host and port under Settings → Inference. A blank host means this computer, on port 8765 by default.
  6. Press Start.
The usual episode controls and recording options work. See run-policy for the controls and settings. Two settings control timing for custom policies:
  • plan_config.request_interval (default 5) sets how many actions run between requests.
  • plan_config.max_adoption_offset_steps (default 6) sets how late a reply may arrive.
The LeRobot chunk settings (aggregate_fn, chunk_size_threshold, temporal ensembling and chunk alignment) don’t change a custom policy’s plans. Do any blending on your server. The robot still limits joint speed and acceleration.

Collect corrections with DAgger

  • Hold either grip to drive that arm.
  • Release both grips to hand back. The robot holds your last command until the policy’s new plan arrives, then blends into it.
  • The policy can keep predicting while you drive, but its predictions never move the arms.
  • Taking over and handing back stay within the same episode, and your frames are labeled as interventions.
DAgger has separate server settings. It reads its shared settings from data collection, not from the Inference settings that Run Policy uses. See collect-dagger for settings, recording, startup homing and shutdown.

Failure behavior

  • A malformed reply, a mismatch in cameras, state or actions, or a lost connection stops the policy.
  • When the plan runs out, plan_config.late_policy decides what happens. The default holds the arms and requests a new plan. abort ends the session.
  • The robot never stretches an old plan to fill a gap.
  • The robot doesn’t reconnect automatically to resume motion.
See Lifecycle and failure for details.