X-VLA SimplerEnv Guide#
Before running xvla + SimplerEnv evaluation, execute the check in the Patch requirement check section below and confirm the absolute EE controller is present. Skipping this usually surfaces as a 0% success run after hundreds of steps.
Impact boundary#
The patches only (a) register one new controller entry and (b) change the dead non-delta branch of
PDEEPoseController.compute_target_pose(use_delta=False, unreachable on stock upstream).Delta control modes (
arm_pd_ee_target_delta_pose_align2_*, used by pi05 and GR00T) are unaffected; models on the delta path can share the same environment.Written against
ManiSkill2_real2sim@54ae2e0e(the official 255isWhite fork pin). Option 2 strictly follows that fork; apply on the same base version or verify the surrounding code first.
Background#
The official X-VLA SIMPLER evaluation (evaluation/simpler) does not use upstream
simpler-env/SimplerEnv. It uses the official fork
255isWhite/SimplerEnv (including the ManiSkill2_real2sim
submodule pinned at commit 54ae2e0e). From the official README:
The evaluation follows SimplerEnv, with minor environment modifications to support absolute end-effector (EE) control.
Reason: X-VLA emits absolute EE poses (target position + Euler orientation in the base frame), while upstream SimplerEnv WidowX only provides delta control modes. Mismatch leads to two failure modes:
Environment state |
Symptom |
|---|---|
Upstream + config |
|
Upstream + fallback delta mode (e.g. |
Runs, but absolute actions are applied as deltas; arm flies out on the first step; success rate stays 0 |
Measured on 2026-07-21: before the patch, stack_cube failed for all steps through 120/300; after the patch and switching to absolute control, episode 0 succeeded in 55 steps.
Patch requirement check#
Run (replace python and paths):
python -c "
import sys
sys.path.insert(0, '/path/to/SimplerEnv')
sys.path.insert(0, '/path/to/SimplerEnv/ManiSkill2_real2sim')
from mani_skill2_real2sim.agents.configs.widowx.defaults import WidowXDefaultConfig
print('arm_pd_ee_target_base_pose_gripper_pd_joint_pos' in WidowXDefaultConfig().controllers)
"
Prints
True: nothing to do (official fork or already patched).Prints
False: apply one of the two options below.
Option 1: use the official fork#
This is the recommended path.
git clone https://github.com/255isWhite/SimplerEnv.git --recurse-submodules
cd SimplerEnv/ManiSkill2_real2sim && pip install -e .
cd .. && pip install -e .
Point env.simplerenv_root in the eval YAML at that directory.
Option 2: apply manual patches#
These changes strictly follow the official fork (simpler-env/ManiSkill2_real2sim@54ae2e0e). Delta control modes are unchanged (pi0.5 and other models on the delta path are unaffected).
Patch 1: register absolute EE pose controller#
File: mani_skill2_real2sim/agents/configs/widowx/defaults.py
Add a controller config in WidowXDefaultConfig.controllers and insert it into _C["arm"]:
# 255isWhite/SimplerEnv fork (X-VLA): absolute EE pose control in base frame
arm_pd_ee_target_base_pose = PDEEPoseControllerConfig(
*arm_common_args, frame="base", use_target=True, use_delta=False, **arm_common_kwargs
)
_C["arm"] = dict(
..., # keep existing entries
arm_pd_ee_target_base_pose=arm_pd_ee_target_base_pose,
)
The combined control mode used by the eval YAML is arm_pd_ee_target_base_pose_gripper_pd_joint_pos.
Patch 2: parse rotation as Euler xyz on the non-delta branch#
File: mani_skill2_real2sim/agents/controllers/pd_ee_pose.py
In PDEEPoseController.compute_target_pose, on the use_delta=False branch, parse rotation as Euler xyz instead of rotvec (axis-angle):
else:
assert self.config.frame == "base", self.config.frame
target_pos, target_rot = action[0:3], action[3:6]
# 255isWhite/SimplerEnv fork (X-VLA): absolute action rotation is Euler xyz
target_quat = Rotation.from_euler("xyz", target_rot).as_quat()[[3, 0, 1, 2]]
target_pose = sapien.Pose(target_pos, target_quat)
Why this is required: the X-VLA client protocol outputs Euler xyz (rot6d → euler, then add bias [0, π/2, 0]; see post-processor ee6d_to_simpler_abs_euler). Upstream dead code used from_rotvec on the same three numbers, which yields a totally different orientation — position may look roughly right while the gripper is twisted, IK fails often, and grasps fail.
Note: on stock upstream, no control mode reaches this non-delta branch (dead code), so the edit does not change any existing upstream behavior.
Eval config#
See examples/embodied/xvla/eval/configs/simplerenv/widowx_stack_cube_smoke.yaml:
benchmark:
control_mode: arm_pd_ee_target_base_pose_gripper_pd_joint_pos # needs patch 1
max_steps: 1200 # official horizon
robot_init_x: 0.147
robot_init_y: 0.028
model:
model_type: xvla
state_encoding: ee6d_widowx # WidowX proprio (closed-loop backfill)
action_encoding: ee6d # decoder auto-composed → ee6d_to_simpler_abs_euler
domain_id: 0 # WidowX (Bridge)
Rollback#
Patches are not committed to git; inspect or restore with:
git -C /path/to/SimplerEnv/ManiSkill2_real2sim diff # inspect
git -C /path/to/SimplerEnv/ManiSkill2_real2sim checkout -- . # restore
References#
Official eval client: evaluation/simpler/WidowX/client_blocks.py
Official fork controller: ManiSkill2_real2sim@54ae2e0e defaults.py
Official numbers (WidowX Visual Matching): Spoon 100 / Carrot 91.7 / Blocks 95.8 / Eggplant 95.8, Avg 95.8