diff --git a/docs/source/_toctree.yml b/docs/source/_toctree.yml
index 765f669..2f9715c 100644
--- a/docs/source/_toctree.yml
+++ b/docs/source/_toctree.yml
@@ -47,8 +47,8 @@
- sections:
- local: envhub
title: Environments from the Hub
- - local: il_sim
- title: Imitation Learning in Sim
+ - local: envhub_leisaac
+ title: Control & Train Robots in Sim (LeIsaac)
- local: libero
title: Using Libero
- local: metaworld
diff --git a/docs/source/envhub_leisaac.mdx b/docs/source/envhub_leisaac.mdx
new file mode 100644
index 0000000..5c951b5
--- /dev/null
+++ b/docs/source/envhub_leisaac.mdx
@@ -0,0 +1,301 @@
+# LeIsaac × LeRobot EnvHub
+
+LeRobot EnvHub now supports **imitation learning in simulation** with LeIsaac.
+Spin up everyday manipulation tasks, teleoperate the robot, collect demos, push them to the Hub, and train policies in LeRobot — all in one loop.
+
+[LeIsaac](https://github.com/LightwheelAI/leisaac) integrates with IsaacLab and the SO101 Leader/Follower setup to provide:
+
+- 🕹️ **Teleoperation-first workflows** for data collection
+- 📦 **Built-in data conversion** ready for LeRobot training
+- 🤖 **Everyday skills** like picking oranges, lifting cubes, cleaning tables, and folding cloth
+- ☁️ **Ongoing upgrades** from [LightWheel](https://lightwheel.ai/): cloud simulation, EnvHub support, Sim2Real tooling, and more
+
+Below you’ll find the currently supported LeIsaac tasks exposed through LeRobot EnvHub.
+
+# Available Environments
+
+The following table lists all available tasks and environments in LeIsaac x LeRobot Envhub. You can also get the latest list of environments by running the following command:
+
+```bash
+python scripts/environments/list_envs.py
+```
+
+| Task | Environment ID | Task Description | Related Robot |
+| :-------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------- |
+| | [LeIsaac-SO101-PickOrange-v0](https://github.com/LightwheelAI/leisaac/blob/main/source/leisaac/leisaac/tasks/pick_orange/pick_orange_env_cfg.py)
[LeIsaac-SO101-PickOrange-Direct-v0](https://github.com/LightwheelAI/leisaac/blob/main/source/leisaac/leisaac/tasks/pick_orange/direct/pick_orange_env.py) | Pick three oranges and put them into the plate, then reset the arm to rest state. | Single-Arm SO101 Follower |
+| | [LeIsaac-SO101-LiftCube-v0](https://github.com/LightwheelAI/leisaac/blob/main/source/leisaac/leisaac/tasks/lift_cube/lift_cube_env_cfg.py)
[LeIsaac-SO101-LiftCube-Direct-v0](https://github.com/LightwheelAI/leisaac/blob/main/source/leisaac/leisaac/tasks/lift_cube/direct/lift_cube_env.py) | Lift the red cube up. | Single-Arm SO101 Follower |
+| | [LeIsaac-SO101-CleanToyTable-v0](https://github.com/LightwheelAI/leisaac/blob/main/source/leisaac/leisaac/tasks/clean_toy_table/clean_toy_table_env_cfg.py)
[LeIsaac-SO101-CleanToyTable-BiArm-v0](https://github.com/LightwheelAI/leisaac/blob/main/source/leisaac/leisaac/tasks/clean_toy_table/clean_toy_table_bi_arm_env_cfg.py)
[LeIsaac-SO101-CleanToyTable-BiArm-Direct-v0](https://github.com/LightwheelAI/leisaac/blob/main/source/leisaac/leisaac/tasks/clean_toy_table/direct/clean_toy_table_bi_arm_env.py) | Pick two letter e objects into the box, and reset the arm to rest state. | Single-Arm SO101 Follower
Bi-Arm SO101 Follower |
+| | [LeIsaac-SO101-FoldCloth-BiArm-v0](https://github.com/LightwheelAI/leisaac/blob/main/source/leisaac/leisaac/tasks/fold_cloth/fold_cloth_bi_arm_env_cfg.py)
[LeIsaac-SO101-FoldCloth-BiArm-Direct-v0](https://github.com/LightwheelAI/leisaac/blob/main/source/leisaac/leisaac/tasks/fold_cloth/direct/fold_cloth_bi_arm_env.py) | Fold the cloth, and reset the arm to rest state.
_Note: Only the DirectEnv support check_success in this task._ | Bi-Arm SO101 Follower |
+
+# Load LeIsaac directly in LeRobot with one line of code
+
+> EnvHub: Share LeIsaac environments through HuggingFace
+
+[EnvHub](https://huggingface.co/docs/lerobot/envhub) is our reproducible environment hub, spin up a packaged simulation with one line, experiment immediately, and publish your own tasks for the community.
+
+LeIsaac offers EnvHub support so you can consume or share tasks with only a few commands.
+
+
+
+## How to get started, environment Setup
+
+Run the following commands to setup your code environments:
+
+```bash
+# Refer to Getting Started/Installation to install leisaac firstly
+conda create -n leisaac_envhub python=3.11
+conda activate leisaac_envhub
+
+conda install -c "nvidia/label/cuda-12.8.1" cuda-toolkit
+pip install -U torch==2.7.0 torchvision==0.22.0 --index-url https://download.pytorch.org/whl/cu128
+pip install 'leisaac[isaaclab] @ git+https://github.com/LightwheelAI/leisaac.git#subdirectory=source/leisaac' --extra-index-url https://pypi.nvidia.com
+
+# Install lerobot
+pip install lerobot==0.4.1
+
+# Fix numpy version
+pip install numpy==1.26.0
+```
+
+## Usage Example
+
+EnvHub exposes every LeIsaac-supported task in a uniform interface. The examples below load `so101_pick_orange` and demonstrate a random-action rollout and an interactive teleoperation.
+
+### Random Action
+
+Click to expand code example
+
+```python
+# envhub_random_action.py
+
+import torch
+from lerobot.envs.factory import make_env
+
+# Load from the hub
+envs_dict = make_env("LightwheelAI/leisaac_env:envs/so101_pick_orange.py", n_envs=1, trust_remote_code=True)
+
+# Access the environment
+suite_name = next(iter(envs_dict))
+sync_vector_env = envs_dict[suite_name][0]
+# retrieve the isaac environment from the sync vector env
+env = sync_vector_env.envs[0].unwrapped
+
+# Use it like any gym environment
+obs, info = env.reset()
+
+while True:
+ action = torch.tensor(env.action_space.sample())
+ obs, reward, terminated, truncated, info = env.step(action)
+ if terminated or truncated:
+ obs, info = env.reset()
+
+env.close()
+```
+
+Click to expand code example
+
+```python
+# envhub_teleop_example.py
+
+import logging
+import time
+import gymnasium as gym
+
+from dataclasses import asdict, dataclass
+from pprint import pformat
+
+from lerobot.teleoperators import ( # noqa: F401
+ Teleoperator,
+ TeleoperatorConfig,
+ make_teleoperator_from_config,
+ so101_leader,
+)
+from lerobot.utils.robot_utils import busy_wait
+from lerobot.utils.utils import init_logging
+from lerobot.envs.factory import make_env
+
+
+@dataclass
+class TeleoperateConfig:
+ teleop: TeleoperatorConfig
+ env_name: str = "so101_pick_orange"
+ fps: int = 60
+
+
+@dataclass
+class EnvWrap:
+ env: gym.Env
+
+
+def make_env_from_leisaac(env_name: str = "so101_pick_orange"):
+ envs_dict = make_env(
+ f'LightwheelAI/leisaac_env:envs/{env_name}.py',
+ n_envs=1,
+ trust_remote_code=True
+ )
+ suite_name = next(iter(envs_dict))
+ sync_vector_env = envs_dict[suite_name][0]
+ env = sync_vector_env.envs[0].unwrapped
+
+ return env
+
+
+def teleop_loop(teleop: Teleoperator, env: gym.Env, fps: int):
+ from leisaac.devices.action_process import preprocess_device_action
+ from leisaac.assets.robots.lerobot import SO101_FOLLOWER_MOTOR_LIMITS
+ from leisaac.utils.env_utils import dynamic_reset_gripper_effort_limit_sim
+
+ env_wrap = EnvWrap(env=env)
+
+ obs, info = env.reset()
+ while True:
+ loop_start = time.perf_counter()
+ if env.cfg.dynamic_reset_gripper_effort_limit:
+ dynamic_reset_gripper_effort_limit_sim(env, 'so101leader')
+
+ raw_action = teleop.get_action()
+ processed_action = preprocess_device_action(
+ dict(
+ so101_leader=True,
+ joint_state={
+ k.removesuffix(".pos"): v for k, v in raw_action.items()},
+ motor_limits=SO101_FOLLOWER_MOTOR_LIMITS),
+ env_wrap
+ )
+ obs, reward, terminated, truncated, info = env.step(processed_action)
+ if terminated or truncated:
+ obs, info = env.reset()
+
+ dt_s = time.perf_counter() - loop_start
+ busy_wait(1 / fps - dt_s)
+ loop_s = time.perf_counter() - loop_start
+ print(f"\ntime: {loop_s * 1e3:.2f}ms ({1 / loop_s:.0f} Hz)")
+
+
+def teleoperate(cfg: TeleoperateConfig):
+ init_logging()
+ logging.info(pformat(asdict(cfg)))
+
+ teleop = make_teleoperator_from_config(cfg.teleop)
+ env = make_env_from_leisaac(cfg.env_name)
+
+ teleop.connect()
+ if hasattr(env, 'initialize'):
+ env.initialize()
+ try:
+ teleop_loop(teleop=teleop, env=env, fps=cfg.fps)
+ except KeyboardInterrupt:
+ pass
+ finally:
+ teleop.disconnect()
+ env.close()
+
+
+def main():
+ teleoperate(TeleoperateConfig(
+ teleop=so101_leader.SO101LeaderConfig(
+ port="/dev/ttyACM0",
+ id='leader',
+ use_degrees=False,
+ ),
+ env_name="so101_pick_orange",
+ fps=60,
+ ))
+
+
+if __name__ == "__main__":
+ main()
+
+```
+
+Click to expand code example
+
+```python
+import torch
+from lerobot.envs.factory import make_env
+
+# Load from the hub
+envs_dict = make_env("LightwheelAI/leisaac_env:envs/bi_so101_fold_cloth.py", n_envs=1, trust_remote_code=True)
+
+# Access the environment
+suite_name = next(iter(envs_dict))
+sync_vector_env = envs_dict[suite_name][0]
+# retrieve the isaac environment from the sync vector env
+env = sync_vector_env.envs[0].unwrapped
+
+# NOTE: initialize() first
+env.initialize()
+
+# other operation with env...
+```
+
+
-
-
- Gamepad button mapping for robot control and episode management -
- -**Keyboard controls** - -For keyboard controls use the `spacebar` to enable control and the following keys to move the robot: - -```bash - Arrow keys: Move in X-Y plane - Shift and Shift_R: Move in Z axis - Right Ctrl and Left Ctrl: Open and close gripper - ESC: Exit -``` - -## Visualize a dataset - -If you uploaded your dataset to the hub you can [visualize your dataset online](https://huggingface.co/spaces/lerobot/visualize_dataset) by copy pasting your repo id. - -
-
-
- Dataset visualizer -
- -## Train a policy - -To train a policy to control your robot, use the [`lerobot-train`](https://github.com/huggingface/lerobot/blob/main/src/lerobot/scripts/train.py) script. A few arguments are required. Here is an example command: - -```bash -lerobot-train \ - --dataset.repo_id=${HF_USER}/il_gym \ - --policy.type=act \ - --output_dir=outputs/train/il_sim_test \ - --job_name=il_sim_test \ - --policy.device=cuda \ - --wandb.enable=true -``` - -Let's explain the command: - -1. We provided the dataset as argument with `--dataset.repo_id=${HF_USER}/il_gym`. -2. We provided the policy with `policy.type=act`. This loads configurations from [`configuration_act.py`](https://github.com/huggingface/lerobot/blob/main/src/lerobot/policies/act/configuration_act.py). Importantly, this policy will automatically adapt to the number of motor states, motor actions and cameras of your robot (e.g. `laptop` and `phone`) which have been saved in your dataset. -3. We provided `policy.device=cuda` since we are training on a Nvidia GPU, but you could use `policy.device=mps` to train on Apple silicon. -4. We provided `wandb.enable=true` to use [Weights and Biases](https://docs.wandb.ai/quickstart) for visualizing training plots. This is optional but if you use it, make sure you are logged in by running `wandb login`. - -Training should take several hours, 100k steps (which is the default) will take about 1h on Nvidia A100. You will find checkpoints in `outputs/train/il_sim_test/checkpoints`. - -#### Train using Collab - -If your local computer doesn't have a powerful GPU you could utilize Google Collab to train your model by following the [ACT training notebook](./notebooks#training-act). - -#### Upload policy checkpoints - -Once training is done, upload the latest checkpoint with: - -```bash -huggingface-cli upload ${HF_USER}/il_sim_test \ - outputs/train/il_sim_test/checkpoints/last/pretrained_model -``` - -You can also upload intermediate checkpoints with: - -```bash -CKPT=010000 -huggingface-cli upload ${HF_USER}/il_sim_test${CKPT} \ - outputs/train/il_sim_test/checkpoints/${CKPT}/pretrained_model -``` - -## Evaluate your policy in Sim - -To evaluate your policy we have to use a configuration file. An example can be found [here](https://huggingface.co/datasets/lerobot/config_examples/resolve/main/sim_il/eval_config.json). - -Here's an example evaluation configuration: - -```json -{ - "env": { - "type": "gym_manipulator", - "name": "gym_hil", - "task": "PandaPickCubeGamepad-v0", - "fps": 10 - }, - "dataset": { - "repo_id": "your_username/il_sim_dataset", - "dataset_root": null, - "task": "pick_cube" - }, - "pretrained_policy_name_or_path": "your_username/il_sim_model", - "device": "cuda" -} -``` - -Make sure to replace: - -- `repo_id` with the dataset you trained on (e.g., `your_username/il_sim_dataset`) -- `pretrained_policy_name_or_path` with your model ID (e.g., `your_username/il_sim_model`) - -Then you can run this command to visualize your trained policy - -