Commit Graph

1939 Commits

Author SHA1 Message Date
Pepijn 0fe31bfae1 fix pi052 runtime and training safety 2026-07-15 18:17:23 +02:00
Liang Su 3cec067795 perf(pi052): optimize flow and full-training paths (#3974)
* perf(pi052): optimize equivalent training paths

* fix(pi052): guard FlexAttention backend selection
2026-07-15 17:26:55 +02:00
Pepijn d304d75ad7 chore: trim training comments and obsolete rerun test 2026-07-15 16:25:25 +02:00
Pepijn 6795b22b1e refactor(factory): remove PI052 processor overrides 2026-07-15 16:07:14 +02:00
Pepijn eddf75616e fix(processor): serialize FAST token mapping 2026-07-15 16:04:26 +02:00
Pepijn a09715121e refactor(runtime): reuse shared rerun visualization 2026-07-15 15:59:13 +02:00
Pepijn ad885c098d refactor(runtime): remove gibberish filtering 2026-07-15 15:55:26 +02:00
Pepijn f76e6b0841 refactor(pi052): use standard processor loading 2026-07-15 15:52:28 +02:00
Pepijn 696e68869c feat(pi0-fast): support automatic tokenizer fitting 2026-07-15 15:46:04 +02:00
Pepijn 2749cf7767 refactor(pi052): remove debug prediction dumps 2026-07-15 15:35:08 +02:00
Pepijn ca42fa2f92 docs: explain hierarchical policy adapters 2026-07-15 15:27:38 +02:00
Pepijn 2f64b85f00 revert(datasets): drop unrelated version error change 2026-07-15 15:24:38 +02:00
Pepijn 9cd8efc5c8 docs: compact language runtime comments 2026-07-15 15:19:52 +02:00
Pepijn d3ad24d9dd revert(datasets): use main package exports 2026-07-15 15:12:17 +02:00
Pepijn ca5be5b482 revert(config): drop train config comment change 2026-07-15 15:09:07 +02:00
Pepijn ffdd87fdac docs(recipes): compact language recipe comments 2026-07-15 15:08:20 +02:00
Pepijn 2e43ca0d54 docs(pi052): describe merged training optimizations 2026-07-15 15:07:01 +02:00
Pepijn 5242e9195c fix(pi052): use base learning rate for lm head 2026-07-15 15:06:22 +02:00
Pepijn 6a89c7be45 fix(pi052): default flow loss weight to ten 2026-07-15 15:05:13 +02:00
Pepijn 0a7b21cdd0 refactor(train): remove wandb example tables 2026-07-15 14:05:50 +02:00
Pepijn 07e75d94be refactor(runtime): remove compatibility aliases 2026-07-15 14:04:12 +02:00
Pepijn 6094058203 docs: add PI052 training and inference guide 2026-07-15 13:58:32 +02:00
Pepijn 7c125c0028 style: compact comments in language runtime 2026-07-15 13:52:52 +02:00
Pepijn 1eed8df1c4 style: add missing license headers 2026-07-15 13:42:45 +02:00
Pepijn 87585195e6 style(wandb): move training example imports to module scope 2026-07-15 13:41:39 +02:00
Pepijn 94dc85b443 refactor(runtime): remove dataset replay mode 2026-07-15 13:39:54 +02:00
Pepijn 8593ff081b refactor(runtime): reuse rollout context and remove dead code 2026-07-15 13:31:24 +02:00
Pepijn 1f00078cc7 fix(robocasa): render overlay text once 2026-07-15 12:07:23 +02:00
Pepijn dbb7f5b769 feat(rollout): integrate language runtime 2026-07-15 11:31:19 +02:00
pepijn223 dca4c2f8cc feat(runtime): add --policy.device to override checkpoint device
Some checkpoints ship config.device=cpu (e.g. MolmoAct2 SO100/101). The
language runtime had no device override, so it always ran on the config
device. --policy.device=cuda (or cpu) now overrides cfg.device at load.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-13 19:11:29 +02:00
Pepijn cb971cc12b feat(runtime): allow autonomous robot mode without --dataset.repo_id
Load normalization stats from the checkpoint (norm_tag) and derive the
observation/action feature schema from the connected robot when no dataset
is given, mirroring lerobot-rollout. A dataset is still honoured when
supplied and its stats take precedence.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-13 18:15:03 +02:00
pepijn223 7632922fb3 feat(runtime): MolmoAct2 language-runtime adapter (direct-subtask)
Enable running MolmoAct2 policies (e.g. on an SO101) in the interactive
language runtime with direct-subtask prompting.

- policies/molmoact2/molmoact2_adapter.py: MolmoAct2PolicyAdapter — flat VLA
  bridge; select_action predicts an action chunk from the packed observation,
  generate_text is a no-op (no text head; use --direct_subtask).
- runtime/registry.py: register "molmoact2" -> MolmoAct2PolicyAdapter.
- runtime/cli.py:
  - Preserve model-input keys emitted outside observation.* (MolmoAct2 packs
    the prompt+images into input_ids/pixel_values/...) through the robot
    observation filter; no-op for PI0-family policies.
  - Robot observation provider now reads the live task/subtask each frame via a
    get_task callback, so a typed command re-packs the instruction (also fixes
    stale-task for other flat VLAs). Bound to runtime state after creation.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-13 16:46:20 +02:00
pepijn223 9f0e4dfb53 fix(pi052): accept use_flex_attention config field for checkpoint compat
Newer PI052 training runs serialize use_flex_attention into config.json.
This branch's attention path is SDPA/eager (mathematically equivalent), so
the field is accepted as an inert no-op (mirrors the existing use_hf_kernels
compat field) — otherwise loading those checkpoints raises DecodingError.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-13 16:46:10 +02:00
pepijn223 33f0414733 feat(runtime): add --fp8 flag to enable PI052 FlashRT FP8 MLPs
Wire the existing (but previously unreachable from the runtime) PI052
FlashRT FP8 MLP swap into the language runtime. --fp8 sets
config.use_flashrt_fp8_mlp before load; the policy calibrates and swaps
every Gemma + SigLIP MLP to fused FP8 on its first predict_action_chunk.
Ignored with a warning for policies without the flag (PI052 only).

Measured ~1.12x faster action-chunk inference (124 -> 111 ms) on an
RTX 5090; needs the `kernels` package (pin <0.13 for transformers) and
CUDA SM>=8.9, else it degrades to BF16.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-09 13:36:48 +02:00
pepijn223 1e94a4f62d feat(runtime): real-robot interactive mode + rerun live camera view
Add physical-robot support to the language runtime, plus a live rerun viewer.

- runtime/rerun_viz.py: headless rerun gRPC + web viewer; logs camera frames
  (every control tick) and joint state. Prints an auto-connect ?url= view URL.
- runtime/cli.py:
  - _run_robot_interactive: real-time control loop (background thread) with a
    clean chat prompt — a typed command switches task/subtask immediately and
    regenerates. Starts running as soon as a task is set (via --task or the
    picker); otherwise paused until the first command. No flag needed.
  - --rerun (+ --rerun.web_port / --rerun.grpc_port): live camera view; the
    robot obs provider and action executor log frames to rerun.
  - --direct_subtask (general, sim or robot): the typed text is the subtask fed
    to the action expert; the LM subtask generator is disabled.
  - Inference overrides: force compile_model=False and gradient_checkpointing
    =False (torch.compile recompiled on every prompt-length change -> >1min per
    chunk; grad checkpointing only slows the forward pass).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-09 11:52:09 +02:00
pepijn223 cd15a66286 feat(runtime): RoboCasa sim backend + interactive controls
Drive a persistent RoboCasa kitchen with open-ended prompts and watch it live.

- runtime/sim_robocasa.py: single-scene RoboCasa backend (n_envs=2 for stable
  EGL rendering — single-worker rendering is broken), high-res multi-view
  compositing incl. wrist cam, annotated MP4 + rolling latest.png + MJPEG live
  viewer, and /reset scene re-roll.
- runtime/cli.py: --sim mode with a main-thread control loop (background-thread
  rendering corrupts EGL), clean chat-style prompt (a new command switches the
  task and regenerates the subtask immediately), plus --sim.render_size,
  --sim.views, --sim.stream_port, --sim.direct_subtask and --disable_memory.
- runtime/adapter.py: GenerationConfig.enable_memory / enable_subtask toggles.
- runtime/registry.py + policies/pi05/pi05_adapter.py: register pi05 (flat VLA,
  direct task-text conditioning; no subtask/memory head).
- policies/pi052/inference/pi052_adapter.py: condition the action expert on
  "{subtask}, State: {..}" to match eval/training.
- envs/robocasa.py + envs/configs.py: terminate_on_success + horizon options so
  the interactive kitchen persists across tasks (defaults preserve eval).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-08 17:28:40 +02:00
pepijn 147b8f248d refactor(train): remove EMA support from training pipeline
Drop the opt-in EMA-shadow feature entirely: EMAConfig, the `ema` field on
TrainPipelineConfig, all EMA logic in lerobot_train.py (setup/resume, per-step
update, W&B observability, checkpoint save, EMA-model eval, and the sibling
`<repo_id>-ema` hub push), and the ema-pytorch dependency.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-08 11:15:33 +00:00
pepijn c80ddfe22c Merge remote-tracking branch 'origin/main' into feat/smolvla-on-steerable
Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	src/lerobot/configs/train.py
#	src/lerobot/datasets/__init__.py
#	src/lerobot/policies/factory.py
#	src/lerobot/policies/groot/groot_n1.py
#	src/lerobot/scripts/lerobot_eval.py
#	src/lerobot/scripts/lerobot_train.py
#	uv.lock
2026-07-08 10:31:40 +00:00
pepijn 18ddf98ab5 feat(pi052): add subtask-only (no-memory) recipe
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-08 10:21:05 +00:00
Mishig 3e538352ca Make doc builds faster (#3958)
* Update doc build workflow: light installs, drop custom container

* Keep the pin comment dependabot-compatible
2026-07-08 07:31:10 +02:00
pepijn cae4a2de43 perf(pi052): gate per-step .item() CUDA syncs to logging steps
Keep PI052Policy.forward's loss components as detached tensors and only
materialize loss/grad_norm/update_s to python floats on logging steps
(1-in-log_freq) via a new update_policy(log_metrics=...) gate. Also dedupe
the predict_actions .any().item() control-flow sync (2 -> 1 per step).

Keeps the training step fully async on non-logging steps so the next batch's
dataloading/enqueue overlaps GPU compute instead of stalling on a per-step
CUDA sync.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-07 07:00:42 +00:00
Steven Palma 8a74e0ac6d chore(dependencies): Bump lerobot to 0.6.1 (#3957) 2026-07-06 12:52:39 +02:00
Steven Palma 30da8e687a chore(dependencies): Bump lerobot to 0.6.0 (#3956) v0.6.0 2026-07-06 12:06:51 +02:00
Steven Palma 93257e3468 chore(dependencies): update uv.lock (#3928) 2026-07-06 11:21:38 +02:00
Caroline Pascal b895ed0fe4 docs(prettier): making video encoding parameters docs prettier (#3911)
* docs(prettier): making video encoding parameters docs prettier

* chore(format): formatting code

* chore(contrast): removing poor contrast elements
2026-07-05 23:39:05 +02:00
Caroline Pascal 293a8d9a77 feat(examples): add Isaac Teleop → SO-101 teleoperation and dataset recording example (#3927)
* Add Isaac Teleop SO-101 leader-arm teleoperator

Add the NVIDIA Isaac Teleop teleoperator scaffolding and its first device:
SO101LeaderArm, a back-drivable SO-101 leader arm on Isaac Teleop's generic
joint-space device path. It reads the leader's joints from the so101_leader
plugin via JointStateSource and emits follower-ready {joint}.pos (rad2deg arm,
gripper -> RANGE_0_100) for direct 1:1 joint drive.

- IsaacTeleopTeleoperator base + IsaacTeleopConfig (shared session/CloudXR config)
- SO101LeaderArm / SO101LeaderArmConfig and leader_joints_to_robot_action
- examples/isaac_teleop_to_so101/teleoperate_leader.py example
- pure-numpy conversion tests
- isaac-teleop optional extra + NVIDIA PyPI index in pyproject

* Add Isaac Teleop XR controller teleoperator for SO-101

Add end-to-end XR (VR) controller teleoperation of an SO-101 follower arm via
the NVIDIA Isaac Teleop stack, layered on the Isaac Teleop scaffolding.

Teleoperator (src/lerobot/teleoperators/isaac_teleop/):
- XRController / XRControllerConfig: connect to the CloudXR runtime, auto-launch
  the Isaac Teleop session, and expose get_action() emitting the raw base-frame
  grip pose, squeeze, and trigger.
- MapXRControllerActionToRobotAction: stateless per-frame mapper from the XR
  action to the IK input contract (absolute ee.x/y/z, ee.gripper_pos, wrist_roll).
- OverwriteWristRollFromAngle: post-IK step writing the operator wrist-roll [rad]
  onto wrist_roll.pos [deg], recovering the under-determined roll DOF.

Example (examples/isaac_teleop_to_so101/):
- teleoperate.py: thin absolute-pose IK pipeline with an in-loop clutch (engage
  latch + 1:1 delta rebase of position and orientation), EEBoundsAndSafety, and
  InverseKinematicsEEToJoints; slews to a recorded home on startup.
- record_reset_pose.py / download_assets.py / webxr.env / .gitignore.

Also:
- Extend robot_kinematic_processor.py with EEBoundsAndSafety and
  InverseKinematicsEEToJoints.
- Add XRControllerConfig + base_T_anchor to the Isaac Teleop config.
- Add docs/source/isaac_teleop.mdx and the _toctree entry.
- Add unit tests for the CloudXR launcher and the XR controller processor.

* Unify Isaac Teleop SO-101 scripts behind a mandatory device selector

Merge teleoperate.py (XR controller: clutch + soft-orientation IK) and
teleoperate_leader.py (SO-101 leader arm: 1:1 joint mirror) into a single
teleoperate.py driven by a `lerobot-teleoperate`-style draccus CLI: a follower
`--robot.*` and an input `--teleop.*`, where `--teleop.type` (xr_controller |
so101_leader) selects the Isaac device.

Uses a "dispatch, don't merge" shape: per-device setup_xr/setup_leader build a
Device bundle (compute / startup / cleanup / command); a shared slew() takes a
per-step target callable (XR a fixed reset pose, leader a live re-read so the
1:1 handoff stays continuous); one device-branchless outer loop runs both, with
compute() -> None meaning "hold at the measured pose" (XR disengaged or leader
stale). The entrypoint is @parser.wrap()'d over a TeleoperateConfig dataclass and
dispatches on the parsed config type; device knobs ride on --teleop.* (the leader
serial port is --teleop.port, forwarded to the plugin) and loop/launch knobs are
top-level (--launch_plugin=<path> collapses the old --launch-plugin/--plugin-bin
pair; --reset_to_origin/--align/--dry_run).

To let the Isaac devices claim the natural --teleop.type names without colliding
with the serial so101_leader of lerobot-teleoperate, give IsaacTeleopConfig its
own draccus choice registry (own _choice_registry, decoupled from the global
TeleoperatorConfig one) and register XRControllerConfig as "xr_controller" and
SO101LeaderArmConfig as "so101_leader" there; the example types its teleop field
as IsaacTeleopConfig so the choices resolve against that scoped registry. These
devices drive the bespoke clutch/IK/align loop and are not routed through
make_teleoperator_from_config, so dropping them from the global registry is inert.

YAGNI sweep of the commit train: delete the orphaned OverwriteWristRollFromAngle
(wrist_roll_processor.py) plus its export and tests -- no producer emits
wrist_roll; the live XR path uses orientation-weight IK on the 5-DOF arm by
design. Kept the load-bearing knobs (orientation_weight, raise_on_jump,
base_T_anchor) and the optional reset-pose recorder. Updated isaac_teleop.mdx
for the unified entrypoint and excised the stale roll-retargeter prose.

Net LOC down (two scripts 714 lines -> one), in-loop device branches reduced to
zero. Planned and reviewed via a 6-persona multi-agent panel (3-round planning
convergence + 2-round review). Verification (isaacteleop/placo not installable
here, so the device classes cannot connect, but their config dataclasses and the
script import fine via deferred imports): the teleoperators test suite passes
(45 passed, 2 skipped), draccus parsing of both target command lines yields the
right config subclass with scoped --teleop.type, --help renders the scoped
choices, the serial so101_leader stays in the global registry, and ruff
check/format are green.

Signed-off-by: Jiwen Cai <jiwenc@nvidia.com>

* Add Isaac Teleop SO-101 dataset recording script

record.py records a LeRobot dataset while driving the SO-101 follower
with either Isaac Teleop device (--teleop.type=xr_controller |
so101_leader), mirroring teleoperate.py's device dispatch.

* Extract shared Isaac Teleop SO-101 example infra into common.py

teleoperate.py and record.py both built the per-device pipeline and ran the
same read -> compute -> hold-when-idle -> sleep loop, with record.py importing
internals from teleoperate.py. Move the shared device/loop infrastructure
(Device, slew, Clutch, setup_xr/setup_leader + leader helpers, reset infra and
constants) into a new common.py, and add build_device() + hold_action() to
collapse the connect/dispatch/startup and idle-hold glue duplicated in both
entry points. The setup functions now type their config against a LoopConfig
Protocol, so common.py is decoupled from either CLI; both import from it.

Also rename record_reset_pose.py -> override_reset_pose.py so it is not confused
with record.py, and update the doc references.

* Add stdin keyboard backend so recording shortcuts work over SSH/headless

lerobot's init_keyboard_listener() uses pynput, which hooks GLOBAL key events
from the display server. Over SSH, under Wayland, or on a headless box with only a
TTY, keystrokes go to the terminal's stdin instead, so the listener never fires and
the Right/Left/Esc recording shortcuts silently do nothing.

Add a stdin (termios) keyboard backend to the example's common.py and an
init_keyboard_listener() that prefers it whenever stdin is an interactive TTY
(works over SSH / Wayland / headless-with-tty), falling back to lerobot's
pynput/headless listener for GUI launches with no controlling terminal. Selectable
via LEROBOT_KEYBOARD_BACKEND={auto,stdin,pynput,none}. The backend keeps ISIG so
Ctrl-C still works and always restores the terminal (on stop() and via atexit).
record.py now sources init_keyboard_listener from common; the Right/Left/Esc -> flag
mapping and the (listener, events) contract are unchanged.

Also convert record.py's loop_kwargs to a dict literal (ruff C408).

* Wait for the XR headset to connect before driving the arm

On the xr_controller path the example connected CloudXR and immediately ran the
reset slew + control loop, even if no headset was connected — the arm moved before
the operator was in VR, and get_action() just returned zeros so the clutch never
engaged.

Add an is_tracking property to XRController (set from the controller stream's
optional group, mirroring SO101LeaderArm) and a _wait_for_xr_controller() helper in
common.py that prints connection instructions (CloudXR web client URL + this
workstation's candidate IPv4s, with loopback/link-local and virtual/bridge/USB-gadget
interfaces filtered out) and polls until the controllers stream (indefinite, 15s
reminder, Ctrl-C to abort). setup_xr.startup() now connects, waits for the headset,
THEN runs the reset slew and seeds the clutch — so the arm only moves once the
operator is connected and watching. Mirrors the leader path's _wait_for_leader; both
record.py and teleoperate.py inherit it via the shared setup_xr.

* Address review feedback on the Isaac Teleop -> SO-101 example

Review-response and CI fixes for the Isaac Teleop -> SO-101 example.

- Move the XR Clutch into src/lerobot/teleoperators/isaac_teleop/clutch.py
  (pure numpy + Rotation, no isaacteleop import), export it, and add
  tests/teleoperators/test_clutch.py.
- Drop the vendored stdin keyboard listener; record.py uses a small terminal-
  first wrapper over upstream's TerminalKeyListener (works over SSH even with a
  local X display), falling back to upstream init_keyboard_listener otherwise.
- record.py: pass rgb_encoder/depth_encoder to LeRobotDataset create()/resume()
  (upstream removed camera_encoder), fixing the AttributeError at record time.
- build_device: derive motor names from robot.action_features instead of
  robot.bus (supports non-bus robots), and disconnect the follower if any step
  after connect() fails so a failed setup never leaks the connection.
- Read leader joints by the group's declared names (_joints_group_to_rad)
  instead of positionally, so a layout mismatch can't silently mirror the wrong
  DOF onto the follower; add tests including a reversed-layout group.
- base.py: hoist `from pathlib import Path` to module scope; only the
  isaacteleop CloudXRLauncher import stays lazy (optional dep).
- Trim the common.py module docstring and point to docs/source/isaac_teleop.mdx.
- default.env: correct the NV_DEVICE_PROFILE comment (auto-webrtc is the default;
  this file overrides to Quest3, which works for both Quest 3 and Pico 4).
- download_assets.py: correct the RAW_BASE comment (tracks main, not pinned) and
  add `# nosec B310` next to the existing `# noqa: S310` for the bandit hook.
- uv.lock: add the isaac-teleop extra's deps so `uv sync --locked` matches
  pyproject; regenerated with uv 0.8.0 to keep lockfile revision 2 (CI's uv).
- isaac_teleop.mdx: prettier formatting.

* fix(.gitignore): removing .gitignore and using lerobot cache folder instead to store local user files

* chore(docstrings): reducing docstrings in default.env

* feat(URDF): cleaning up and simplifying the URDF download procedure

* feat(robot guard): adding a guard in case an unsupported robot type is provided (so-arms only)

* fix(imports): enforcing a python module structure to simplify imports

* feat(safe read): extending the motor bus safe read rationale to reset pose setting

* chore(trim): trimming lenghty comments and docstrings

* fix(deps): use isaacteleop [retargeters-lite] extra to unblock aarch64 (DGX Spark) (#3933)

* fix(deps): drop isaacteleop [retargeters] extra to unblock aarch64

The [retargeters] extra pulls dex-retargeting (pins numpy<2.0, conflicting
with lerobot's numpy>=2.0) and nlopt>=2.8 (no aarch64 wheels), making
lerobot[isaac-teleop] unresolvable on ARM (DGX Spark, Jetson Thor, GH200)
and over-constrained on numpy everywhere else.

The LeRobot teleoperators only import isaacteleop.retargeting_engine,
isaacteleop.cloudxr and isaacteleop.teleop_session_manager, all shipped in
the base wheel (requires only numpy>=1.23), so the extra is unused.

Verified on DGX Spark (aarch64, Python 3.12): resolves and installs with
isaacteleop 1.3.131 + numpy 2.2.6; all imported symbols load.

* fix(deps): use isaacteleop [retargeters-lite] extra for aarch64 support

Pin to isaacteleop ~=1.3.131 (the release that added ARM64/aarch64 support)
and swap the full [retargeters] extra for the new [retargeters-lite] one
(scipy-only). The full extra drags in dex-retargeting (pins numpy<2,
conflicting with lerobot's numpy>=2.0) and nlopt>=2.8 (no aarch64 wheels),
making lerobot[isaac-teleop] unresolvable on ARM hosts (DGX Spark, Jetson
Thor, GH200) and over-constrained on numpy everywhere else.

The LeRobot teleoperators only import isaacteleop.retargeting_engine,
isaacteleop.cloudxr and isaacteleop.teleop_session_manager — all covered
by the base wheel + retargeters-lite.

Verified on DGX Spark (aarch64, Python 3.12/3.13): resolves and installs
with isaacteleop 1.3.131 + numpy 2.2.6 + scipy 1.18.

* feat(deps): re-add full [retargeters] extra gated to x86_64

Keep the dex-retargeting/nlopt-based retargeters available on x86_64 (where
their wheels exist) via an environment marker, while ARM hosts (DGX Spark,
Jetson Thor, GH200) resolve with base + [retargeters-lite] only.

Verified: uv lock resolves on both platforms; on aarch64 the compile
excludes nlopt/dex-retargeting, on x86_64 they are included.

---------

Co-authored-by: Johnny Nunez <22727137+johnnynunez@users.noreply.github.com>

* chore(docstrings): trimming latest docstrings

* chore(teleop): move isaac-teleop to examples + update docs + add readme with installation notes

* chore(deps): restore uv.lock

* fix(example: isaac teleop parsing config

* fix(examples): isaac atomic-gripper controller

* feat(Examples): isaac-teleop holdlatch

* chore(examples): some other minor improvements for isaac-teleop

* chore(examples): top-level imports isaac-teleop

* chore(Examples): address ai review isaac-teleop

---------

Signed-off-by: Jiwen Cai <jiwenc@nvidia.com>
Co-authored-by: Jiwen Cai <jiwenc@nvidia.com>
Co-authored-by: Johnny <johnnync13@gmail.com>
Co-authored-by: Johnny Nunez <22727137+johnnynunez@users.noreply.github.com>
Co-authored-by: Steven Palma <steven.palma@huggingface.co>
Co-authored-by: Steven Palma <imstevenpmwork@ieee.org>
2026-07-05 20:56:26 +02:00
Steven Palma 7957d4e2dc chore(docs): update readme + gr00t libero results (#3941)
* chore(docs): update readme + gr00t libero results

* chore(docs): update template and in-tree policy steps
2026-07-05 15:11:46 +02:00
Steven Palma 192a0b9282 chore(dependencies): update uv.lock (#3816) 2026-07-04 10:18:01 +02:00
Steven Palma 0530dd9b97 chore(infra): remove requirements files (#3925) 2026-07-03 22:42:50 +02:00
Steven Palma 698d2a0e77 feat(policies): add EVO1 policy (#3908)
* feat(policies): add EVO1 policy

* fix(evo1): infer batch size after normalizing image dims

`_collect_image_batches` read `batch_size = batch[camera_keys[0]].shape[0]`
before normalizing per-camera tensors to `(B, C, H, W)`. For an unbatched
`(C, H, W)` input (which the function tries to support via the `image.dim() == 3`
branch), this picked up the channel count `C` instead of the real batch size,
making the subsequent per-sample loop iterate `C` times and indexing go
out of bounds.

Normalize each camera tensor up-front, then read `batch_size` from the
normalized batch dim. Adds `test_collect_image_batches_handles_unbatched_chw`
covering the regression.

Reported by Copilot review on huggingface/lerobot#3545.

* chore(lock): regenerate uv.lock for evo1 extra

Adds the `evo1` entry to `[package.metadata.requires-dist]` and the
`provides-extras` list so that `uv sync --locked --extra test` (used by
fast_tests.yml) no longer reports the lockfile as stale.

Generated with `uv 0.8.0` (matching `UV_VERSION` in fast_tests.yml).
The non-evo1 marker tweaks are produced by `uv lock` re-resolving the
existing dep graph and are not introduced by this PR.

* chore(evo1): align with policy contribution guide conventions

- Add `src/lerobot/policies/evo1/README.md` symlink into `docs/source/evo1.mdx`
  to match the in-tree README convention (mirroring the EO-1 layout).
- Convert `transformers` import in `internvl3_embedder.py` to the standard
  `TYPE_CHECKING + _transformers_available` two-step gating used by other
  optional-backbone policies (e.g. diffusion). The previous lazy-in-`__init__`
  import was functionally equivalent for runtime gating but didn't expose the
  real symbols to type checkers.
- Add `lerobot[evo1]` to the `all` extra in `pyproject.toml` so
  `pip install 'lerobot[all]'` keeps installing every optional policy.

Per the guidance in https://moon-ci-docs.huggingface.co/docs/lerobot/pr_3534/en/contributing_a_policy.

* fix(evo1): finalize policy guide alignment

* docs(evo1): format results table

* Fix EVO1 LIBERO rollout processors

* Fix EVO1 LIBERO eval action postprocessing

* Fix eval action conversion for bf16 policies

* fix(evo1): move LIBERO padding into policy processors

* refactor(evo1): use native HF InternVL3-1B-hf, drop trust_remote_code

- Switch from OpenGVLab/InternVL3-1B (requires trust_remote_code=True)
  to OpenGVLab/InternVL3-1B-hf (native transformers implementation).
- Replace manual _extract_feature + _prepare_and_fuse_embeddings with
  a single model.forward() call — verified bit-for-bit identical output.
- Remove ~170 lines of manual ViT/pixel-shuffle/projection logic.
- Symlink README.md to docs/source/ following repo convention.

Weights are byte-identical between both model variants; only the module
naming differs. All 12 existing unit tests pass. Local training (10 steps)
on maximellerbach/omx_pickandplace confirmed working.

* refactor(policy): evo1 GPU-batched preprocessing +  vectorized attention masking + remove dead code

* fix(style): pre-commit

oops

* chore(evo1): delete added test + reduce diff

* refactor(policies): use config for evo1 + local imports

* refactor(policies): multiple improvements

* chore: update docs + remove legacy codepaths

* feat(policies): implement RTC to EVO1

---------

Co-authored-by: javadcc_mac <javadcc1@sjtu.edu.cn>
Co-authored-by: Yiming Wang <145452074+JAVAdcc@users.noreply.github.com>
Co-authored-by: Martino Russi <nopyeps@gmail.com>
2026-07-03 22:17:15 +02:00