Python harness for Universal Robots UR5e simulation (Menagerie meshes) with a Robotiq 2F-85 adaptive gripper (tendon drive, 0–255 ctrl), RGB cameras, and a validation loop for task policies (e.g. grasp / lift).
The robot uses vendored MuJoCo Menagerie universal_robots_ur5e OBJ meshes under src/robot_manipulation_sim/mjcf/menagerie_ur5e/ (see NOTICE.txt and MENAGERIE_LICENSE there). The default scene is ur5e_two_finger_scene.xml.
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"Copy .env.example → .env and set GEMINI_API_KEY (used by scripts/validate_rollout.py and robot_manipulation_loop.py when present). Do not commit .env.
MuJoCo uses an OpenGL backend for offscreen RGB (mujoco.Renderer). On a normal desktop, the default (glfw / platform GL) is fine. In headless environments, install/configure OSMesa/EGL as described in the MuJoCo rendering docs or run with UR5GripperEnv(enable_rgb=False) for state-only observations.
from robot_manipulation_sim import UR5GripperEnv
env = UR5GripperEnv(enable_rgb=True) # False in CI / no GL
obs = env.reset()
obs = env.step(env._home) # 6 arm position actuators + Robotiq tendon command (ctrl 0–255)Observations include images (when enable_rgb=True), qpos, qvel, ctrl, box_height, time.
- Automated VLM loop (rollout → judge → optional Gemini policy rewrite until pass):
python scripts/robot_manipulation_loop.py examples/task/base_rotation.py --run-dir artifacts/base_rotation(if the script omits--run-dir, check its--helpfor the default; needspip install -e ".[vlm]"andGEMINI_API_KEY; put your intent / success criteria intask_spec.inlinein the task YAML—or keepVLM_TASKin the policy if the loop still expects it—and compare againstrollout.vlm.json; use--no-auto-fixfor a single VLM pass without editing the policy file) - Simulate a policy (writes
rollout.mp4with a 2×2 camera grid—overview RGB/depth include thin traced link COM paths unless--no-overview-traces—plusmetrics.txt,joints.csvunderrun_dir, or legacyvideosingle-file layout): defaults live inexamples/simulate_policy.example.yaml(auto-loaded when that file exists). Run e.g.python scripts/simulate_policy.py --config examples/simulate_policy.example.yaml, or override the policy path / any flag on the CLI (python scripts/simulate_policy.py examples/task/base_rotation.py --steps 400). With no default YAML, pass apolicy_filepositional plus any--run-dir/--videoyou need. - Rollout validation (YAML) (needs
pip install -e ".[vlm]"for Gemini analyzers): aftersimulate_policy.py … --run-dir DIR, runpython scripts/validate_rollout.py --config examples/validation.example.yaml. Withtask:set to a stem<task>, the loader readsexamples/task/<task>.yamlfortask_specandtask_analyzers, requiresexamples/task/<task>.py, mergesanalyzers_head+ task analyzers +analyzers_tail, and resolves rollout paths underartifacts/<task>/(relative tobase_dir) unlesssimulation.*overrides. Configs withouttaskkeep the legacy shape: top-leveltask_spec, singleanalyzerslist, explicitsimulationpaths. - Example task (
task: base_rotation): policy atexamples/task/base_rotation.py— slow base-axis rotation via small closed-loop steps onshoulder_pan_joint; other joints held at episode-start setpoints. Intent for validation lives inexamples/task/base_rotation.yaml.
Policies are plain Python files defining policy(obs, step, env) returning a length-env.nu control vector (joint / gripper targets in actuator units). For iteration workflows, keep success criteria in examples/task/<task>.yaml (task_spec.inline) or override from the main config; you can also use policy_module with TASK_SPEC / VLM_TASK so you (or an agent) can compare them to validate_rollout.py / vlm_observer output in rollout.vlm.json.
See .cursor/skills/robot-manipulation-task-loop/SKILL.md for the iterative spec → implement → validate in sim workflow tied to this repo.