The AY-Robots policies page comparing the five trainable models by parameters, GPU tier, latency per action step and minimum episodes
ROS 2LeRobotIntegrationRobot LearningSO-100

ROS 2 and LeRobot Side by Side: What Each Stack Is For

AY-Robots ResearchAugust 23, 202618 min read

ROS 2 and LeRobot solve different problems and overlap in one small interface. What each is for, the bridges that exist in 2026, and how to connect them.

If you already run a robot on ROS 2, the first question about imitation learning is rarely "which model". It is "do I have to throw away my node graph". The answer is no. ROS 2 and the LeRobot stack solve different problems and touch each other along a narrow seam: joint states and camera frames in, joint commands out, at a fixed rate.

This describes ROS 2 Lyrical Luth, the LTS released 22 May 2026, and LeRobot 0.6.x (0.6.1 on PyPI from 3 August 2026, 0.6.2 on main). Both move fast, so every version and default below is dated on purpose. Platform numbers come from the policy catalog and the pricing page.

What you need to know

  • ROS 2 is distributed middleware plus an ecosystem: nodes, topics, services, actions, TF2, ros2_control, MoveIt 2, rosbag2. It has no opinion about machine learning.
  • LeRobot is a Python library for learning manipulation from demonstrations. Neither its dependency list nor any optional extra mentions ROS.
  • The overlap is one abstract base class with ten members, of which three carry the traffic. That is why a bridge is a mapping file, not a rewrite.
  • Two directions, and most people use both: expose the ROS 2 robot to LeRobot's CLI as a plugin, and run the trained policy back inside a ROS 2 node.
  • Rosetta, LeROS2, lerobot_robot_ros2_zenoh and sacovo/lerobot_ros were all pushed to in August 2026; LeRobot's docs list two of them.
  • Latency decides where the policy runs: 20 ms per action step for ACT, 485 ms for Pi0.5, before any network hop.

What each stack is actually for

Both projects use the word "robot". ROS 2 means a system of processes that has to keep running for years. LeRobot means an object that can be asked for an observation and handed an action.

ROS 2: a distributed system for a whole robot

ROS 2 is a communication layer plus a package ecosystem. Nodes are separate processes that find each other through distributed discovery with no central master, and exchange data over topics for continuous streams, services for request and response, and actions for long-running goals with feedback. The ROS on DDS article gives the reason for that choice: DDS already had distributed discovery and per-connection Quality of Service.

  • ros2_control: the real-time loop. controller_manager reads hardware state, updates controllers and writes commands at an update_rate that defaults to 100 Hz and is declared read-only.
  • Hardware components: System, Actuator and Sensor plugins exposing state and command interfaces. Your Feetech or Dynamixel driver lives here.
  • MoveIt 2: collision-aware motion planning, IK and trajectory execution against a URDF.
  • TF2: the transform tree, so "where is the gripper in the base frame" is a library call.
  • rosbag2: record and replay every topic. MCAP has been the default storage plugin since Iron Irwini; Humble still defaulted to sqlite3.
  • Tooling: ros2 topic hz, rqt, RViz, lifecycle nodes, launch files, parameter YAML.
Which ROS 2 are we talking about

ROS 2 releases every May, alternating LTS and non-LTS: five years for an LTS, eighteen months otherwise. Lyrical Luth (22 May 2026) is the current LTS, Tier 1 on Ubuntu 26.04 and Windows 11 until May 2031. Kilted Kaiju runs out in November 2026. Every bridge below is packaged against Jazzy Jalisco, so check its build before assuming your distro is covered.

LeRobot: a training pipeline that happens to touch hardware

LeRobot goes the other way. One Python package, Apache-2.0, Python 3.12 or newer, whose job is to get demonstrations off a real arm, into a dataset, through a training run, and back onto the arm as a policy. Everything is a console script. No message bus, no node graph, no discovery.

bash
pip install lerobot

# the console scripts a manipulation workflow touches (pyproject.toml on main, 0.6.2)
lerobot-find-port          # which serial device is the arm
lerobot-setup-motors       # write servo IDs to EEPROM
lerobot-calibrate          # record range of motion per joint
lerobot-teleoperate        # leader drives follower, --fps default 60
lerobot-record             # write a LeRobotDataset while teleoperating
lerobot-train              # train a policy on that dataset
lerobot-eval               # evaluate a checkpoint
lerobot-rollout            # run a trained policy on hardware
lerobot-dataset-viz        # look at what you recorded
Nine of the nineteen entry points declared in [project.scripts] on main.

The structural fact that matters: LeRobot's unconditional install pulls torch, torchvision, numpy, opencv-python-headless, Pillow, einops, draccus, huggingface-hub, requests, gymnasium, safetensors and five build helpers. That is the whole list. No rclpy, no DDS, no colcon, and no ROS package in any optional extra either. It is a pip package that talks to a serial port.

Side by side

ConcernROS 2 (Lyrical Luth, May 2026)LeRobot (0.6.x, Aug 2026)
Unit of compositionNode, a process found by distributed discoveryPython object subclassing Robot
TransportDDS/RTPS with per-connection QoS; https://github.com/ros2/rmw_zenoh">rmw_zenoh_cpp is an alternative RMW, branched Humble through LyricalIn-process calls; gRPC only in the optional async extra
Control loopcontroller_manager, update_rate default 100 HzA Python loop at --dataset.fps, default 30
Hardware abstractionhardware_interface plugins with state and command interfacesget_observation() and send_action() over named features
Kinematics and planningURDF, TF2, MoveIt 2, Nav2None. Policies emit joint targets directly
Recordingros2 bag record, MCAP by default since IronLeRobotDataset v3.0: Parquet and MP4 shards plus metadata
TrainingNothing in the corelerobot-train, checkpoints, Hub upload
Timing guaranteesReal-time capable executors, QoS deadlines, measurable overrunsBest effort. A slow camera read stretches the loop
What it is forShipping a robot system that keeps runningTeaching one arm one task from demonstrations

Read the last row twice. Most arguments about ROS 2 versus LeRobot are arguments about which job you are doing this week. A navigation stack, a safety controller and a fleet API mean ROS 2 is not optional. Fifty episodes of a gripper picking up a cube to fine-tune a vision-language-action model means ROS 2 is a lot of scaffolding around a serial port.

The overlap is one small interface

Bridging works because LeRobot asks very little of hardware. The base class in src/lerobot/robots/robot.py declares ten abstract members, and in a bridge only three carry traffic. The two feature properties are the entire schema negotiation, and their docstrings insist both stay callable whether or not the robot is connected.

python
# src/lerobot/robots/robot.py on main, abridged: docstrings removed
class Robot(abc.ABC):
    config_class: builtins.type[RobotConfig]
    name: str

    # schema, readable before connect()
    @property
    @abc.abstractmethod
    def observation_features(self) -> dict: ...   # {"shoulder.pos": float, "cam": (h, w, 3)}

    @property
    @abc.abstractmethod
    def action_features(self) -> dict: ...        # {"shoulder.pos": float, ...}

    # lifecycle
    @property
    @abc.abstractmethod
    def is_connected(self) -> bool: ...

    @abc.abstractmethod
    def connect(self, calibrate: bool = True) -> None: ...

    @property
    @abc.abstractmethod
    def is_calibrated(self) -> bool: ...

    @abc.abstractmethod
    def calibrate(self) -> None: ...

    @abc.abstractmethod
    def configure(self) -> None: ...

    @abc.abstractmethod
    def disconnect(self) -> None: ...

    # the loop
    @abc.abstractmethod
    def get_observation(self) -> RobotObservation: ...

    @abc.abstractmethod
    def send_action(self, action: RobotAction) -> RobotAction: ...
All ten abstract members. Skip one and the subclass will not instantiate, which is the usual first error when a bridge is written from a blog post instead of from the file.

A ROS 2 bridge fills these in the obvious way. get_observation() returns the latest message from each subscribed topic, named; send_action() publishes to the command topics; connect() brings up the node and waits for a first value on every stream. Once that class exists, every LeRobot tool works unchanged, including dataset recording and fine-tuning.

Plugin discovery is by package name

LeRobot auto-imports any installed package named lerobot_robot_*, lerobot_camera_* or lerobot_teleoperator_*. Three rules follow: the device class is named after its config class minus the Config suffix, it sits in that config's module or a submodule named after the device, and both are exported from __init__.py. Follow those four conventions from the Bring Your Own Hardware guide and --robot.type=your_name works with no fork.

The bridges that exist today

LeRobot's Third-Party Robots and Teleoperators page carries a "ROS 2 Bridges" heading, and as of August 2026 it lists exactly two entries. Two more projects do the same job at a different scope, and one is a complete arm stack rather than a plugin.

ProjectWhat it doesConfigNotes
https://github.com/iblnkn/rosetta">iblnkn/rosettaBoth directions: recorder node, bag converter, policy runner, plus a lerobot_robot_rosetta pluginOne YAML contract, reused at record and deploy timeApache-2.0, 91 stars, pushed 5 Aug 2026. Its workspace installs ROS 2 Jazzy
https://github.com/ngres/leros2">ngres/leros2Both directions, with end-effector pose and wrench as well as joint positionsYAML topic-to-feature mapApache-2.0, listed in LeRobot's docs. Ships leros2-convert, pinned to lerobot 0.6.x
https://github.com/ROBOTIS-GIT/lerobot_robot_ros2_zenoh">ROBOTIS lerobot_robot_ros2_zenohROS 2 robot appears as a LeRobot robot over a Zenoh router; the LeRobot side needs no ROS 2 installPython dataclassAlpha by its own README, listed in LeRobot's docs. Needs an editable lerobot install plus zenoh_ros2_sdk, not on PyPI
https://github.com/sacovo/lerobot_ros">sacovo/lerobot_rosRecorder, replay and a policy controller behind a /run_policy action, gated on an operator heartbeatTOML, topics tagged observation or actionMIT, pushed 14 Aug 2026, built against Jazzy
https://github.com/legalaspro/so101-ros-physical-ai">legalaspro/so101-ros-physical-aiA whole SO-101 stack: ros2_control Feetech driver, teleop, MoveIt 2, recorder, conversion, inferenceROS 2 params plus conversion YAMLApache-2.0, 120 stars, Ubuntu 24.04 and Jazzy. The closest thing to a reference
The AY-Robots download page for the desktop client that records LeRobot-format datasets from a teleoperation session
No ROS 2 stack yet? The desktop client on /download records the same LeRobotDataset format from a teleop session.

Three ways to connect the two

Path A: make the ROS 2 robot look like a LeRobot robot

The cleanest option when your ROS 2 side is already healthy. Map topics to features, install the plugin, and every LeRobot command works against the real arm. Here is the Rosetta contract format, quoted from its README.

yaml
robot_type: my_robot
robot_interface: ros2
fps: 30

observations:
  observation.state:
    channel: {topic: /joint_states, type: sensor_msgs/msg/JointState}
    align: {strategy: hold, timeline: header}
    select: [position.j1, position.j2]

  observation.images.cam:
    channel: {topic: /camera/image_raw/compressed,
              type: sensor_msgs/msg/CompressedImage}
    align: {strategy: hold, timeline: header}
    apply: [resize: [480, 640]]

actions:
  action:
    channel: {topic: /cmd, type: sensor_msgs/msg/JointState}
    align: {strategy: hold, timeline: header}
    select: [position.j1, position.j2]
Recorder, converter and deployed policy all read this file, and the converter copies it into the dataset as meta/rosetta_contract.yaml so it travels with the data.
bash
# with lerobot_robot_rosetta installed, LeRobot sees --robot.type=rosetta
lerobot-record --robot.type=rosetta --robot.config_path=contract.yaml
lerobot-teleoperate --robot.type=rosetta --robot.config_path=contract.yaml
The plugin adds no options of its own; the contract is the whole configuration.

Two details from that plugin's README save a midnight debugging session. It hosts a ROS 2 lifecycle node itself, so ROS 2 must be installed on the machine running the LeRobot CLI even though the command looks like plain Python. And while connected a watchdog applies the contract's per-channel safety behaviour, zeros, hold or none, whenever no action arrives for two frame periods.

Path B: record rosbags, then convert offline

Path A puts the recording loop inside Python, and that costs something. The LeROS2 README is blunt: driving the follower from the LeRobot record loop "can introduce additional latency". Its recommendation is to wire leader-follower teleoperation natively in ROS 2, record a bag, and convert afterwards. Bags also keep native topic rates and full image resolution, so you can requantise later without re-recording.

bash
# 1. record at native rates, MCAP by default since Iron
ros2 bag record -o episode_001 /joint_states /cmd \
    /wrist/color/image_raw/compressed /base/color/image_raw/compressed

# 2a. Rosetta: bags -> LeRobotDataset, using the same contract
rosetta_port \
    --raw-dir ./datasets/bags \
    --contract my_contract.yaml \
    --repo-id my-org/my-dataset \
    --root ./datasets/lerobot

# 2b. LeROS2: same job, quantised by fps or by a clock topic
leros2-convert \
    --config_path=./my-config.yaml \
    --dataset.repo_id=my-org/my-dataset \
    --dataset.fps=30 \
    --input_bag='./recordings/episodes/*/*.mcap'
Two converters, same problem: ROS 2 messages arrive at different rates, so something must decide what one dataset frame means.
The trap that eats a day: frame alignment

ROS 2 topics are asynchronous by design. A 30 fps camera, a 100 Hz joint state and a 20 Hz command topic share no clock, and the dataset needs one row per frame with all three filled in. Every converter answers this with an alignment strategy: Rosetta with align: {strategy: hold, timeline: header} per channel, LeROS2 with --dataset.fps for a fixed grid or --clock_topic to emit a frame whenever a chosen topic publishes. Get it wrong and the policy trains on images that lag the action by a frame or two, which looks exactly like a model that almost works. Inspect an episode with lerobot-dataset-viz before spending GPU hours, and check the dataset docs.

Path C: run the policy as a ROS 2 node

Deployment is the mirror image. A ROS 2 node loads the checkpoint, subscribes to the observation topics and publishes actions. Both mature bridges expose it as an action server, so the policy is startable and cancellable like any other ROS 2 behaviour.

bash
# terminal 1: load the checkpoint into a ROS 2 node
ros2 launch rosetta policy_runner_launch.py \
    contract_path:=my_contract.yaml \
    pretrained_name_or_path:=outputs/train/my_policy/checkpoints/last/pretrained_model

# terminal 2: send it a task
ros2 action send_goal /run_policy \
    rosetta_interfaces/action/RunPolicy "{prompt: 'pick up the red block'}"
Use the prompt you recorded with. Cancelling the goal stops the arm, which is what you want when a language-conditioned model does something unexpected.
  • Rosetta: rosetta_interfaces/action/RunPolicy, goal field prompt. One contract, one checkpoint per launch.
  • sacovo/lerobot_ros: lerobot_interfaces/action/RunPolicy, goal fields policy_name and task. Several policies live in one TOML file, and the available names are published on a latched policy_control/status topic.
  • That second project refuses to actuate without a fresh policy_control/heartbeat from the operator, and clamps or rounds policy output per topic, which stops a continuous gripper prediction landing between the only two values your controller accepts.

End to end on an SO-100 class arm

On an SO-100 or SO-101 with a leader arm and two cameras, the whole path looks like this. The commands are the SO-101 ROS 2 stack's own; substitute your package and topic names.

  1. 1
    Set up the servos with LeRobot first, not ROS

    Motor IDs and calibration live in servo EEPROM. The SO-101 stack is explicit: complete LeRobot motor setup and calibration for both arms before you teleoperate, plan or command them from ROS. The other order gives an arm that moves to the wrong angles for no visible reason.

    bash
    lerobot-find-port
    lerobot-setup-motors --robot.type=so101_follower --robot.port=/dev/ttyACM0
    lerobot-calibrate --robot.type=so101_follower --robot.port=/dev/ttyACM0 --robot.id=follower_1
  2. 2
    Bring up the ROS 2 side and check the rates

    A ros2_control hardware component drives the servo bus, a controller publishes /joint_states, camera nodes publish compressed images. A camera that silently drops to 5 fps is the most common cause of a dataset that trains to a low loss and does nothing on hardware.

    bash
    ros2 launch so101_bringup teleop.launch.py
    ros2 topic hz /joint_states
    ros2 topic hz /wrist/color/image_raw/compressed
  3. 3
    Record episodes as bags

    Teleoperate through ROS 2 and record each demonstration as its own bag. Aim past the platform minimum: 30 episodes for SmolVLA, 50 for ACT, GR00T N1.7, GR00T N1.5 and Pi0.5. Vary object placement or you train a confident single-position policy.

    bash
    ros2 launch so101_bringup recording_session.launch.py \
      experiment_name:=pick_and_place \
      task:="Pick up the cube and place it in the container." \
      use_rerun:=true
    
    # second terminal: r start, s save, d discard, q quit
    ros2 run episode_recorder teleop_episode_keyboard
  4. 4
    Convert the bags to a LeRobotDataset

    Here the alignment strategy from the warning above gets applied. The SO-101 stack ships its own converter in a second Pixi environment and writes v3.0 directly; rosetta_port and leros2-convert are the generic alternatives. In v3.0 many episodes share Parquet and MP4 shards, with boundaries in meta/episodes/ rather than filenames.

    bash
    pixi run -e lerobot convert -- \
      --input-dir ~/.ros/so101_episodes/pick_and_place \
      --config    rosbag_to_lerobot/config/so101.yaml \
      --repo-id   local/so101_pick_place
    
    # look at it before you rent a GPU
    lerobot-dataset-viz --repo-id local/so101_pick_place --episode-index 0
  5. 5
    Train

    Locally for ACT or SmolVLA on a 24 GB card, on rented hardware otherwise. Format version matters: the GR00T loader crashes on a v3.0 dataset and needs it converted down to v2.1 first.

    bash
    lerobot-train \
      --dataset.repo_id=local/so101_pick_place \
      --policy.type=act \
      --output_dir=outputs/train/so101_pick_place
  6. 6
    Deploy back into the graph

    Either as a policy runner node, or through LeRobot's async inference pair, which decouples prediction from execution so the arm keeps running the current chunk while the next is computed. The client wraps a Robot instance, so it takes the same --robot.type your bridge registers.

    bash
    pip install "lerobot[async]"
    
    # on the GPU box
    python -m lerobot.async_inference.policy_server --host=127.0.0.1 --port=8080
    
    # on the robot
    python -m lerobot.async_inference.robot_client \
      --server_address=gpu-box:8080 \
      --robot.type=rosetta \
      --robot.config_path=contract.yaml \
      --task="pick up the cube" \
      --policy_type=act \
      --pretrained_name_or_path=my-org/so101-pick-place-act \
      --actions_per_chunk=50 \
      --chunk_size_threshold=0.5
7.4 V, not 12 V

The SO-100, the SO-101 and the LeKiwi arm use Feetech STS3215 bus servos on a 7.4 V rail. Feeding them 12 V destroys them. LeKiwi is the easy one to get wrong, because its base runs on 12 V and its arm does not. Koch v1.1 is different again: Dynamixel XL330 and XL430 on separate 5 V and 12 V rails. Check the brick before first power-up, and see servo not responding if a joint has already gone quiet.

Bridging ROS 2 into LeRobot
Advantages
  • You keep the drivers, safety layer, URDF and tooling you already trust. Learning is one more node.
  • Bags keep native rates and full resolution, so you can requantise into a different dataset without re-recording.
  • Any sensor on the graph is one block of YAML from being a policy input, wrench and force-torque included.
  • The same contract is used at record and deploy time, removing the classic train-serve preprocessing mismatch.
  • MoveIt 2 can still own the approach and retreat while the policy owns the contact-rich part.
Trade-offs
  • One more link in the failure chain. When the gripper does nothing, rule out a QoS mismatch as well as a bad checkpoint.
  • These are community projects, not vendor products. Read the last commit date first.
  • All of them are packaged against Jazzy. Lyrical Luth is a fresh LTS and nothing here advertises support for it yet.
  • LeRobot's live path expects one numeric observation key and one action key, because it collapses numeric features into a single observation.state and action. A richer contract records and trains, then is rejected at connect().
  • Recording through the LeRobot Python loop adds latency compared with native ROS 2 teleoperation.

Latency decides where the policy runs

Inference latency is not a benchmark number, it is a budget. Every action step costs the model time, and whatever you add on top comes out of the same budget.

PolicyParamsPer action stepGPU tierMin episodesDataset format
ACT~80 M20 msRTX 4090 or any 24 GB card50LeRobot v3.0
GR00T N1.7~3 B, ~40 M trained during fine-tuning152 msA100 80 GB or H100 80 GB50LeRobot v2.0 or v2.1
GR00T N1.5~3 B165 msA100 80 GB or H100 80 GB50LeRobot v2.0 or v2.1
SmolVLA~450 M245 msRTX 4090 or any 24 GB card30LeRobot v3.0
Pi0.5~3 B, PaliGemma backbone485 msA100 80 GB or H100 80 GB50LeRobot v3.0

ACT at 20 ms leaves room for a network hop. Pi0.5 at 485 ms does not: the model alone dominates a reactive loop, and a public-internet round trip on top turns a working policy into a hesitant one. Remote inference is viable for slow pick-and-place, not fast reactive motion. That is the argument for putting the policy node on the robot's own compute, and for action chunking: with async inference the arm executes the chunk it has while the next is computed, and chunk_size_threshold decides how early the client asks for it.

The AY-Robots CLI page showing the install command and the run commands for training and inference from a terminal
The /cli page: the same operations the web UI exposes, as terminal commands you can drop into a launch file.

Doing it yourself versus doing it here

You own the whole chain. The right choice when the robot is not an SO-100 class arm, when the sensors are unusual, or when the policy has to live inside an existing ROS 2 product.

  1. Install ROS 2 and build a ros2_control hardware component for your servo bus.
  2. Pick a bridge and write the topic-to-feature contract.
  3. Record demonstrations as bags, convert, inspect with lerobot-dataset-viz.
  4. Rent or own a GPU: ACT and SmolVLA fit on 24 GB, GR00T and Pi0.5 want 80 GB.
  5. Run lerobot-train, watch the loss curve, keep checkpoints.
  6. Wrap the checkpoint in a policy node and handle deployment latency yourself.
Realistic effort

The bridge itself is a day if your topics are already clean. The GPU plumbing, the dataset debugging and the deployment loop are where the weeks go. Budget for one full re-record after you discover a camera was misaligned.

Where this platform does not help

The honest boundaries are more useful than the feature list.

  • There is no ROS 2 bridge built into AY-Robots. If your robot lives on a ROS 2 graph you adopt one of the community bridges above; the platform meets you at the dataset.
  • No motion planning, no collision checking, no navigation. Those stay in MoveIt 2 and Nav2.
  • GR00T N1.7, GR00T N1.5 and Pi0.5 are cloud-only here. Only SmolVLA and ACT also run locally.
  • GR00T's fine-tuning entry point is a tyro CLI that exposes no seed, so GR00T runs are not bit-for-bit reproducible. lerobot's default seed is 1000.
  • The gradient accumulation field is real for GR00T N1.7 and N1.5 and inert for Pi0.5 and SmolVLA, because lerobot 0.5.1 had no such flag.
The AY-Robots MCP server page listing the platform operations exposed as tools for AI agents
The /mcp page: the same operations as the CLI, addressed by an agent instead of a shell.

The pragmatic split: ROS 2 owns the robot, LeRobot owns the learning, the bridge is a YAML file, and this platform owns the GPU-shaped hole in the middle. The VLA overview explains why the policies behave as they do, the data collection guide covers what to record, and the SO-100 complete guide covers the hardware. If a run is already failing, the failure-mode index is faster.

Turn your converted bags into a trained policy

Point the training form at the dataset your converter wrote, pick one of the five models and your arm, and the backend rents the GPU by required VRAM. A 24 GB run costs about 1 to 3 USD.

Open the training matrix

Frequently asked questions

Do I need ROS 2 to use LeRobot?

No. LeRobot's install pulls torch, torchvision, numpy, opencv, Pillow, einops, draccus, huggingface-hub, requests, gymnasium, safetensors and a few build helpers. No ROS package appears there or in any optional extra; it talks to Feetech and Dynamixel servos over serial. You need ROS 2 only if your robot already runs on it, or if you want planning, TF and a distributed process model.

Can I train a LeRobot policy on data I already have in rosbags?

Yes, and it is the most common entry point. Rosetta ships rosetta_port, LeROS2 ships leros2-convert, and the SO-101 stack ships its own converter; all three read bags and write a LeRobotDataset. The work is not the conversion, it is deciding how asynchronous topics become one dataset frame: a fixed fps or a clock topic, then confirming the images line up with the actions.

Which ROS 2 distribution should I use for this?

Lyrical Luth, released 22 May 2026, is the current LTS, Tier 1 on Ubuntu 26.04 and Windows 11 until May 2031. But every bridge in this article is packaged against Jazzy Jalisco, so Jazzy is the lower-friction choice if you want community packages to build unpatched today. Kilted Kaiju is non-LTS and runs out in November 2026.

Should the policy run on the robot or on a server?

On the robot for anything reactive. Per action step this platform measures 20 ms for ACT up to 485 ms for Pi0.5, and a public-internet round trip is added on top of that, not hidden inside it. Remote inference works for slow pick-and-place; for fast reactive motion it does not, and the symptom is a policy that hesitates rather than one that fails cleanly.

Can I keep MoveIt 2 and still use a learned policy?

Yes, and it is often the better design. Let MoveIt 2 plan the free-space approach and retreat, where collision checking earns its keep, and hand control to the policy for the contact-rich segment. Rosetta's policy runner and sacovo/lerobot_ros both expose the policy as a ROS 2 action server, so switching between planner and policy is a goal handoff, not a rewrite.

Why does my GR00T run reject the dataset I just recorded?

Because LeRobot writes v3.0 by default and the GR00T loader crashes on it. GR00T N1.7 and N1.5 need v2.0 or v2.1, so it has to be converted down; ACT, SmolVLA and Pi0.5 take v3.0. The dataset rejected page has the error and the conversion path.

Ready for high-quality robotics data?

AY-Robots connects your robots to skilled operators worldwide.

Get Started