feat(envs): add RoboTwin 2.0 benchmark integration

- RoboTwinEnvConfig with 4-camera setup (head/front/left_wrist/right_wrist)
- Docker image with SAPIEN, mplib, CuRobo, pytorch3d (Python 3.12)
- CI workflow: 1-episode smoke eval with pepijn223/smolvla_robotwin
- RoboTwinProcessorStep for state float32 casting
- Camera rename_map: head_camera/front_camera/left_wrist -> camera1/2/3

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Pepijn
2026-04-14 11:49:15 +02:00
parent cff4bcf4a0
commit 5558ea2207
7 changed files with 1364 additions and 0 deletions

View File

@@ -226,3 +226,29 @@ class IsaaclabArenaProcessorStep(ObservationProcessorStep):
def observation(self, observation):
return self._process_observation(observation)
@dataclass
@ProcessorStepRegistry.register(name="robotwin_processor")
class RoboTwinProcessorStep(ObservationProcessorStep):
"""Passthrough step for RoboTwin observations, casting state to float32.
RoboTwin observations already arrive in LeRobot format (observation.images.*
and observation.state), so this step mainly ensures state dtype is float32.
"""
def _process_observation(self, observation):
processed_obs = dict(observation)
if OBS_STATE in processed_obs:
state = processed_obs[OBS_STATE]
if hasattr(state, "dtype") and state.dtype != torch.float32:
processed_obs[OBS_STATE] = state.float()
return processed_obs
def transform_features(
self, features: dict[PipelineFeatureType, dict[str, PolicyFeature]]
) -> dict[PipelineFeatureType, dict[str, PolicyFeature]]:
return features
def observation(self, observation):
return self._process_observation(observation)