SO-101 pick-and-place (MuJoCo)

Pick the orange cube off the table and place it inside the green target zone, on a calibrated SO-101 arm. A LeRobot EnvHub environment.

from lerobot.envs import make_env

envs = make_env(
    "namenu/so101-pick-place-env@<commit-sha>:env.py",
    n_envs=1,
    trust_remote_code=True,
)
env = envs["so101_pick_place"][0]
obs, info = env.reset(seed=0)

Pin a commit. @main works but tells you nothing about which scene produced a result.

Install the dependencies first

EnvHub does not install a repository's requirements.txt. Before loading:

pip install "gymnasium>=0.29" "mujoco>=3.2" "numpy>=1.26"

What a policy has to speak

observation pixels.up, pixels.side โ€” (480, 640, 3) uint8; agent_pos โ€” (6,) float32
action (6,) float32 โ€” joint position targets, degrees
control rate 20 Hz (sim_dt 0.002 s, 25 substeps)
episode length 200 steps
success cube centre within 4 cm of the target site, back near table height, gripper open
reward shaped: โˆ’โ€–cube_xy โˆ’ target_xyโ€–, +1 per step while lifted, +10 terminal on success

Observations follow LeRobot's gym convention, so preprocess_observation maps them onto observation.images.up / observation.images.side / observation.state with no remap layer. Joint units are degrees to match lerobot/svla_so101_pickplace, whose policies are trained on that convention; the MJCF actuators are in radians and the env converts at the boundary.

SO101PickBin-v0 โ€” one front camera at 30 Hz, box into a wire bin, approximating the namenu/pick-place-v1 real-hardware capture โ€” is also registered by the bundled package, though this entry point exposes pick-and-place.

An assisted grasp, stated plainly

The SO-101's moulded jaws do not reliably hold the cube under contact physics alone. When the gripper is commanded closed within 4.5 cm of the cube, the cube is kinematically attached to the tool frame until the gripper opens. Scripted experts and learned policies get the same rule, so train and eval stay consistent โ€” but a success rate here is not a claim about contact-rich grasping.

No baseline numbers are published with this environment. Nothing has been measured on it under a protocol worth citing yet.

Why env.py downloads the repository

EnvHub fetches only the file named in the ref. The bundled so101_envs package and 16 MB of robot meshes are not fetched with it, and their directory is never put on sys.path โ€” so env.py calls snapshot_download for its own repo on first load, recovering the repo id and commit from the cache path. A cloned checkout skips that entirely.

One trap if you copy the pattern: locate yourself with Path(__file__).absolute(), never .resolve(). The cache exposes snapshots/<commit>/ as symlinks into a flat blobs/ store, and resolving them discards both the repo name and the commit.

Worth knowing if you publish your own: an environment spanning more than one file does not work through make_env unless it bootstraps this way.

Provenance

The robot model โ€” assets/so101/mjcf/so101_new_calib.xml and the 13 STL meshes โ€” comes from TheRobotStudio/SO-ARM100 (Simulation/SO101/), Apache-2.0. The only change is the MJCF's meshdir attribute, repointed at this layout; geometry, joints, actuators, and calibration are untouched. See NOTICE.

The task scenes, the gym environments, and this entry point are original. The scene geometry is authored, not measured against a physical cell.

Downloads last month

-

Downloads are not tracked for this model. How to track
Video Preview
loading