Initial snapshot: hand motion pipeline (Dyn-HaMR + dex-retargeting + SPIDER)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+173
@@ -0,0 +1,173 @@
|
||||
# Add New Dataset
|
||||
|
||||
This guide explains how to add a new dataset to SPIDER for retargeting human motion data to robots.
|
||||
|
||||
## Overview
|
||||
|
||||
Adding a new dataset involves:
|
||||
1. Preparing raw data in standardized format
|
||||
2. Creating a dataset processor script
|
||||
3. Extracting hand kinematics and object poses
|
||||
4. Converting meshes to MuJoCo-compatible format
|
||||
5. Testing the integration
|
||||
|
||||
## Dataset Requirements
|
||||
|
||||
Your dataset should include:
|
||||
- **Hand motion data**: Either MANO parameters or joint angles
|
||||
- **Object information**: 3D meshes and 6D poses (position + orientation)
|
||||
- **Temporal alignment**: Synchronized hand and object trajectories
|
||||
|
||||
Supported formats:
|
||||
- MANO parameters (shape, pose)
|
||||
- Direct joint angles
|
||||
- Wrist poses (position + rotation)
|
||||
- Object 6D poses
|
||||
|
||||
## Data File Structure
|
||||
|
||||
SPIDER uses a standardized directory structure:
|
||||
|
||||
```
|
||||
example_datasets/
|
||||
├── raw/ # Raw data from original dataset
|
||||
│ └── my_dataset/
|
||||
│ ├── task_name_01.pkl # Raw motion capture data
|
||||
│ ├── task_name_02.pkl
|
||||
│ └── meshes/ # Object meshes
|
||||
│ ├── cup.obj
|
||||
│ └── spoon.obj
|
||||
│
|
||||
└── processed/ # Processed data for SPIDER
|
||||
└── my_dataset/
|
||||
├── dataset_summary.json # Dataset metadata
|
||||
├── assets/ # Shared assets
|
||||
│ ├── objects/ # Object meshes
|
||||
│ │ └── cup/
|
||||
│ │ ├── convex/ # Convex decomposition
|
||||
│ │ │ ├── 0.obj
|
||||
│ │ │ ├── 1.obj
|
||||
│ │ │ └── ...
|
||||
│ │ └── visual.obj
|
||||
│ └── robots/ # Robot models
|
||||
│ └── allegro/
|
||||
│ ├── left.xml
|
||||
│ └── right.xml
|
||||
└── mano/ # Processed MANO data
|
||||
└── bimanual/
|
||||
└── task_name/
|
||||
└── 0/
|
||||
├── trajectory_keypoint.npz
|
||||
└── info.json
|
||||
```
|
||||
|
||||
## Step 1: Prepare Raw Data
|
||||
|
||||
Place your raw data in the appropriate directory:
|
||||
|
||||
```bash
|
||||
mkdir -p example_datasets/raw/my_dataset
|
||||
# Copy your raw data files here
|
||||
```
|
||||
|
||||
### Raw Data Format
|
||||
|
||||
Your raw data file (`.pkl` or `.npz`) should contain:
|
||||
|
||||
```python
|
||||
{
|
||||
# Hand data (one of the following):
|
||||
'mano_pose': [...], # [T, 48] MANO pose parameters
|
||||
'mano_shape': [...], # [10] or [T, 10] MANO shape parameters
|
||||
# OR
|
||||
'qpos_finger_left': [...], # [T, n_joints] Left finger joints
|
||||
'qpos_finger_right': [...], # [T, n_joints] Right finger joints
|
||||
'qpos_wrist_left': [...], # [T, 7] Left wrist pose (xyz + quat)
|
||||
'qpos_wrist_right': [...], # [T, 7] Right wrist pose (xyz + quat)
|
||||
|
||||
# Object data:
|
||||
'object_pose_left': [...], # [T, 7] Object pose (xyz + quat) for left hand
|
||||
'object_pose_right': [...], # [T, 7] Object pose (xyz + quat) for right hand
|
||||
'object_name_left': 'cup', # Object identifier
|
||||
'object_name_right': 'spoon',
|
||||
|
||||
# Metadata:
|
||||
'fps': 30.0, # Frame rate
|
||||
'task_name': 'pick_cup', # Task identifier
|
||||
}
|
||||
```
|
||||
|
||||
## Step 2: Create Dataset Processor
|
||||
|
||||
Create a processor script at `spider/process_datasets/my_dataset.py`:
|
||||
|
||||
## Step 3: Handle Object Meshes
|
||||
|
||||
Convert Meshes to OBJ Format
|
||||
|
||||
Ensure meshes are in MuJoCo-compatible OBJ format:
|
||||
|
||||
```python
|
||||
def convert_mesh_to_obj(input_mesh: str, output_mesh: str):
|
||||
"""
|
||||
Convert mesh to MuJoCo-compatible OBJ format.
|
||||
|
||||
Supports various input formats (STL, PLY, glb, etc.)
|
||||
"""
|
||||
import trimesh
|
||||
|
||||
# Load mesh
|
||||
mesh = trimesh.load(input_mesh)
|
||||
|
||||
# Ensure single mesh (merge if needed)
|
||||
if isinstance(mesh, trimesh.Scene):
|
||||
mesh = mesh.dump(concatenate=True)
|
||||
|
||||
# Export as OBJ
|
||||
mesh.export(output_mesh)
|
||||
|
||||
print(f"Converted {input_mesh} to {output_mesh}")
|
||||
```
|
||||
|
||||
Place Meshes in Assets
|
||||
|
||||
Place meshes in assets folder, for example, for cup:
|
||||
|
||||
```bash
|
||||
mkdir -p example_datasets/processed/my_dataset/assets/objects/cup
|
||||
cp example_datasets/raw/my_dataset/meshes/cup.obj example_datasets/processed/my_dataset/assets/objects/cup/visual.obj
|
||||
```
|
||||
|
||||
## Step 4: Test Your Dataset Processor
|
||||
|
||||
Run Processor
|
||||
|
||||
```bash
|
||||
# Process a single sample
|
||||
uv run spider/process_datasets/my_dataset.py \
|
||||
--task=pick_cup \
|
||||
--embodiment-type=bimanual \
|
||||
--data-id=0
|
||||
```
|
||||
|
||||
### Verify Output
|
||||
|
||||
Check that the output files exist and have correct format.
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
|
||||
# Load processed data
|
||||
data = np.load('example_datasets/processed/my_dataset/mano/bimanual/pick_cup/0/trajectory_keypoint.npz')
|
||||
|
||||
print("Keys:", list(data.keys()))
|
||||
print("qpos_finger shape:", data['qpos_finger'].shape)
|
||||
print("qpos_wrist shape:", data['qpos_wrist'].shape)
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- [OakInk Dataset](https://oakink.net/)
|
||||
- [GigaHand Dataset](https://gigahands.github.io/)
|
||||
- [Hot3D Dataset](https://github.com/facebookresearch/hot3d)
|
||||
- [MANO Hand Model](https://mano.is.tue.mpg.de/)
|
||||
+678
@@ -0,0 +1,678 @@
|
||||
# Add New Robot
|
||||
|
||||
This guide explains how to add a new robot to SPIDER, covering both dexterous hands and humanoid robots.
|
||||
|
||||
## Overview
|
||||
|
||||
Adding a new robot involves:
|
||||
1. Converting/preparing robot model (URDF/MJCF)
|
||||
2. Configuring default settings
|
||||
3. Setting up collision geometry
|
||||
4. Adding trace and tracking sites
|
||||
5. Configuring actuators
|
||||
6. Testing the integration
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Robot URDF or MJCF model
|
||||
- Basic understanding of MuJoCo XML format
|
||||
- Robot specifications (joint limits, actuator parameters)
|
||||
|
||||
## Add Dexterous Hand
|
||||
|
||||
### Step 1: Convert URDF to MJCF (Optional)
|
||||
|
||||
If you have a URDF file, convert it to MuJoCo XML:
|
||||
|
||||
```xml
|
||||
<!-- Add this snippet to your URDF before conversion -->
|
||||
<mujoco>
|
||||
<compiler meshdir="assets" balanceinertia="true" discardvisual="false"/>
|
||||
</mujoco>
|
||||
```
|
||||
|
||||
Then use MuJoCo's compiler:
|
||||
|
||||
```bash
|
||||
# Using MuJoCo command-line tool
|
||||
python -c "import mujoco; mujoco.MjModel.from_xml_path('robot.urdf').save('robot.xml')"
|
||||
```
|
||||
|
||||
### Step 2: Add Default Settings
|
||||
|
||||
Add default simulation parameters to your XML:
|
||||
|
||||
```xml
|
||||
<default>
|
||||
<!-- Disable all contacts by default, use explicit collision pairs -->
|
||||
<geom density="800" condim="1" contype="0" conaffinity="0" />
|
||||
|
||||
<!-- Position controller settings (response time ~1s) -->
|
||||
<position kp="300" dampratio="1.0" inheritrange="1" />
|
||||
|
||||
<!-- Joint dynamics -->
|
||||
<joint damping="0.0" armature="1.0" frictionloss="0.0" />
|
||||
|
||||
<!-- Trace sites for visualization -->
|
||||
<site size="0.01" type="sphere" rgba="1 0 0 1" group="3" />
|
||||
</default>
|
||||
```
|
||||
|
||||
**Parameter explanations:**
|
||||
- `density="800"`: Material density (kg/m³)
|
||||
- `kp="300"`: Position controller stiffness
|
||||
- `dampratio="1.0"`: Critical damping
|
||||
- `armature="1.0"`: Joint inertia
|
||||
|
||||
### Step 3: Add Assets
|
||||
|
||||
Include textures and materials:
|
||||
|
||||
```xml
|
||||
<asset>
|
||||
<!-- Skybox texture -->
|
||||
<texture type="skybox" builtin="gradient"
|
||||
rgb1="1 1 1" rgb2="0 0 0"
|
||||
width="512" height="3072" />
|
||||
|
||||
<!-- Ground plane texture -->
|
||||
<texture type="2d" name="left_groundplane" builtin="checker"
|
||||
mark="edge" rgb1="1 1 1" rgb2="1 1 1"
|
||||
markrgb="0.8 0.8 0.8" width="300" height="300" />
|
||||
|
||||
<!-- Ground material -->
|
||||
<material name="left_groundplane" texture="left_groundplane"
|
||||
texuniform="true" texrepeat="5 5" reflectance="0.2" />
|
||||
</asset>
|
||||
|
||||
<!-- Camera for tracking -->
|
||||
<camera name="left_track" pos="0.868 -0.348 -0.175"
|
||||
xyaxes="0.037 0.999 -0.000 0.011 -0.000 1.000" />
|
||||
```
|
||||
|
||||
### Step 4: Clean Up Joint Properties
|
||||
|
||||
Remove incompatible joint properties from the URDF-converted file:
|
||||
|
||||
```xml
|
||||
<!-- Remove these attributes from joints: -->
|
||||
<!-- actuatorfrcrange, damping, frictionloss, armature, etc. -->
|
||||
|
||||
<!-- Before: -->
|
||||
<joint name="finger_joint" damping="0.1" armature="0.01" ... />
|
||||
|
||||
<!-- After: -->
|
||||
<joint name="finger_joint" ... />
|
||||
<!-- Dynamics are now inherited from <default> section -->
|
||||
```
|
||||
|
||||
### Step 5: Rename Bodies and Geoms
|
||||
|
||||
Change mesh names to avoid conflicts (especially for bimanual setups):
|
||||
|
||||
```xml
|
||||
<!-- Left hand bodies should start with "left_" -->
|
||||
<body name="left_palm">
|
||||
<geom name="left_palm_visual" type="mesh" mesh="left_palm_mesh" />
|
||||
</body>
|
||||
|
||||
<!-- Right hand bodies should start with "right_" -->
|
||||
<body name="right_palm">
|
||||
<geom name="right_palm_visual" type="mesh" mesh="right_palm_mesh" />
|
||||
</body>
|
||||
```
|
||||
|
||||
::: tip Naming Convention
|
||||
- Bodies: `{side}_{finger}_{part}` (e.g., `left_index_proximal`)
|
||||
- Visual geoms: `{side}_{name}_visual`
|
||||
- Collision geoms: `collision_hand_{side}_{finger}_{part}`
|
||||
:::
|
||||
|
||||
### Step 6: Add Collision Geometry
|
||||
|
||||
Create simplified collision geometry using primitives:
|
||||
|
||||
For each finger, in different parts, the collision index start from 0 and increase in each new body.
|
||||
|
||||
```xml
|
||||
<body name="left_index_tip">
|
||||
<!-- Visual mesh -->
|
||||
<geom name="left_index_tip_visual" type="mesh" mesh="index_tip"
|
||||
contype="0" conaffinity="0" group="0" />
|
||||
|
||||
<!-- Collision geometry (capsule primitive) -->
|
||||
<geom name="collision_hand_left_index_0" type="capsule"
|
||||
size="0.008 0.015" pos="0.015 0 0" quat="0.707 0 0.707 0"
|
||||
contype="1" conaffinity="1" group="3" rgba="0 1 0 1" />
|
||||
</body>
|
||||
```
|
||||
|
||||
**Naming convention for collision geoms:**
|
||||
```
|
||||
collision_hand_{side}_{finger}_{part}
|
||||
```
|
||||
|
||||
Where:
|
||||
- `side`: `left` or `right`
|
||||
- `finger`: `thumb`, `index`, `middle`, `ring`, `pinky`, `palm`
|
||||
- `part`: `0`, `1`, `2`, `3`, ... (from tip to base)
|
||||
|
||||
**Collision geom guidelines:**
|
||||
- Use primitives (`box`, `sphere`, `cylinder`, `capsule`) instead of meshes
|
||||
- Set `group="3"` for collision geoms
|
||||
- Set `rgba="0 1 0 1"` (green) for visibility
|
||||
- Keep collision geoms simple for performance
|
||||
|
||||
### Step 7: Add Trace Sites
|
||||
|
||||
Add trace sites for fingertip visualization:
|
||||
|
||||
```xml
|
||||
<body name="left_thumb_tip">
|
||||
<!-- Trace site (for trajectory recording) -->
|
||||
<site name="trace_hand_left_thumb_tip" pos="0.02 0 0"
|
||||
size="0.005" type="sphere" rgba="1 0 0 1" group="3" />
|
||||
</body>
|
||||
|
||||
<body name="left_index_tip">
|
||||
<site name="trace_hand_left_index_tip" pos="0.02 0 0"
|
||||
size="0.005" type="sphere" rgba="1 0 0 1" group="3" />
|
||||
</body>
|
||||
|
||||
<!-- Repeat for middle, ring, pinky -->
|
||||
```
|
||||
|
||||
**Naming convention:** `trace_hand_{side}_{finger}_tip`
|
||||
|
||||
### Step 8: Add IK Tracking Sites
|
||||
|
||||
Add tracking sites for end-effector control:
|
||||
|
||||
```xml
|
||||
<body name="left_palm">
|
||||
<site name="left_palm" pos="0 0 0"
|
||||
euler="0 0 0" size="0.01" type="sphere" rgba="1 1 0 1" group="3" />
|
||||
</body>
|
||||
|
||||
<body name="left_thumb_tip">
|
||||
<site name="left_thumb_tip" pos="0.02 0 0"
|
||||
size="0.01" type="sphere" rgba="0 1 1 1" group="3" />
|
||||
</body>
|
||||
|
||||
<!-- Repeat for all fingertips -->
|
||||
```
|
||||
|
||||
**Required sites:**
|
||||
- `{side}_palm`: Palm center with proper orientation
|
||||
- `{side}_thumb_tip`, `{side}_index_tip`, `{side}_middle_tip`
|
||||
- `{side}_ring_tip`, `{side}_pinky_tip`
|
||||
|
||||
**Palm site orientation:**
|
||||
- Z-axis: pointing forward (finger direction)
|
||||
- X-axis: pointing down (toward ground)
|
||||
|
||||

|
||||
|
||||
Optional: Add contact tracking sites for contact tracking.
|
||||
|
||||
```xml
|
||||
<body name="left_thumb_tip">
|
||||
<site name="track_hand_left_thumb_tip" pos="0.02 0 0"
|
||||
size="0.01" type="sphere" rgba="0 1 1 1" group="3" />
|
||||
</body>
|
||||
|
||||
<!-- Repeat for all fingertips -->
|
||||
```
|
||||
|
||||
### Step 9: Add Actuators
|
||||
|
||||
Define position actuators for all joints:
|
||||
|
||||
```xml
|
||||
<actuator>
|
||||
<!-- Base DOFs (for free-floating hand) -->
|
||||
<position name="left_pos_x_position" joint="left_pos_x" kp="1000" />
|
||||
<position name="left_pos_y_position" joint="left_pos_y" kp="1000" />
|
||||
<position name="left_pos_z_position" joint="left_pos_z" kp="1000" />
|
||||
<position name="left_rot_x_position" joint="left_rot_x" kp="1000" />
|
||||
<position name="left_rot_y_position" joint="left_rot_y" kp="1000" />
|
||||
<position name="left_rot_z_position" joint="left_rot_z" kp="1000" />
|
||||
|
||||
<!-- Thumb joints -->
|
||||
<position name="left_thumb_proximal_yaw_position"
|
||||
joint="left_thumb_proximal_yaw_joint" />
|
||||
<position name="left_thumb_proximal_pitch_position"
|
||||
joint="left_thumb_proximal_pitch_joint" />
|
||||
<position name="left_thumb_intermediate_position"
|
||||
joint="left_thumb_intermediate_joint" />
|
||||
<position name="left_thumb_distal_position"
|
||||
joint="left_thumb_distal_joint" />
|
||||
|
||||
<!-- Index finger joints -->
|
||||
<position name="left_index_proximal_position"
|
||||
joint="left_index_proximal_joint" />
|
||||
<position name="left_index_intermediate_position"
|
||||
joint="left_index_intermediate_joint" />
|
||||
|
||||
<!-- Repeat for middle, ring, pinky -->
|
||||
</actuator>
|
||||
```
|
||||
|
||||
**Important notes:**
|
||||
- Base DOFs use higher `kp` (e.g., 1000) for stability
|
||||
- Finger joints inherit `kp` from `<default>` section
|
||||
- **Actuator order must match joint order** (SPIDER uses joint positions as control)
|
||||
|
||||
### Step 10: Example Complete Hand XML
|
||||
|
||||
Here's a minimal example structure:
|
||||
|
||||
```xml
|
||||
<mujoco model="my_hand">
|
||||
<compiler angle="radian" meshdir="assets" autolimits="true"/>
|
||||
|
||||
<option timestep="0.01" iterations="6" solver="CG" jacobian="auto">
|
||||
<flag eulerdamp="disable" />
|
||||
</option>
|
||||
|
||||
<default>
|
||||
<geom density="800" condim="1" contype="0" conaffinity="0" />
|
||||
<position kp="300" dampratio="1.0" inheritrange="1" />
|
||||
<joint damping="0.0" armature="1.0" frictionloss="0.0" />
|
||||
<site size="0.01" type="sphere" rgba="1 0 0 1" group="3" />
|
||||
</default>
|
||||
|
||||
<asset>
|
||||
<!-- Textures and materials -->
|
||||
<texture type="skybox" builtin="gradient" rgb1="0.3 0.5 0.7" rgb2="0 0 0" width="512" height="3072" />
|
||||
<material name="metal" rgba="0.7 0.7 0.7 1" />
|
||||
|
||||
<!-- Meshes -->
|
||||
<mesh name="left_palm_mesh" file="meshes/palm.obj" />
|
||||
<mesh name="left_thumb_tip_mesh" file="meshes/thumb_tip.obj" />
|
||||
<!-- ... more meshes -->
|
||||
</asset>
|
||||
|
||||
<worldbody>
|
||||
<geom name="floor" type="plane" size="0 0 0.05" material="groundplane"/>
|
||||
<light pos="0 0 3" dir="0 0 -1" directional="true"/>
|
||||
|
||||
<!-- Hand body -->
|
||||
<body name="left_hand" pos="0 0 0.2">
|
||||
<!-- Base free joint for 6-DOF -->
|
||||
<freejoint name="left_base_joint"/>
|
||||
|
||||
<!-- Palm -->
|
||||
<body name="left_palm">
|
||||
<geom name="left_palm_visual" type="mesh" mesh="left_palm_mesh" />
|
||||
<geom name="collision_hand_left_palm_0" type="box" size="0.04 0.03 0.01" />
|
||||
<site name="left_palm" pos="0 0 0" euler="0 0 0"/>
|
||||
|
||||
<!-- Thumb -->
|
||||
<body name="left_thumb_proximal">
|
||||
<joint name="left_thumb_proximal_yaw_joint" axis="0 0 1" range="-0.5 0.5"/>
|
||||
<joint name="left_thumb_proximal_pitch_joint" axis="0 1 0" range="-0.2 1.0"/>
|
||||
<!-- ... thumb links ... -->
|
||||
<body name="left_thumb_tip">
|
||||
<site name="left_thumb_tip" pos="0.02 0 0"/>
|
||||
<site name="trace_hand_left_thumb_tip" pos="0.02 0 0"/>
|
||||
</body>
|
||||
</body>
|
||||
|
||||
<!-- Index, middle, ring, pinky similar structure -->
|
||||
</body>
|
||||
</body>
|
||||
</worldbody>
|
||||
|
||||
<actuator>
|
||||
<position name="left_pos_x_position" joint="left_pos_x" kp="1000"/>
|
||||
<!-- ... all actuators ... -->
|
||||
</actuator>
|
||||
|
||||
<contact>
|
||||
<!-- Define collision pairs if needed -->
|
||||
</contact>
|
||||
</mujoco>
|
||||
```
|
||||
|
||||
## Add Humanoid Robot
|
||||
|
||||
Humanoid robots have similar requirements but with additional considerations.
|
||||
|
||||
### Step 1: Performance Optimization
|
||||
|
||||
Reduce solver iterations for faster simulation:
|
||||
|
||||
```xml
|
||||
<option timestep="0.02" iterations="2" ls_iterations="10">
|
||||
<flag eulerdamp="disable" />
|
||||
</option>
|
||||
|
||||
<visual>
|
||||
<global azimuth="135" elevation="-25" offwidth="1920" offheight="1080" />
|
||||
<quality shadowsize="8192" />
|
||||
<headlight ambient="0.3 0.3 0.3" diffuse="0.6 0.6 0.6" specular="0 0 0" />
|
||||
<scale forcewidth="0.25" contactwidth="0.4" contactheight="0.15"
|
||||
framelength="5" framewidth="0.3" />
|
||||
<rgba haze="0.15 0.25 0.35 1" force="1 0 0 1" />
|
||||
</visual>
|
||||
|
||||
<custom>
|
||||
<numeric data="15" name="max_contact_points" />
|
||||
<numeric data="15" name="max_geom_pairs" />
|
||||
</custom>
|
||||
```
|
||||
|
||||
### Step 2: Default Settings
|
||||
|
||||
```xml
|
||||
<default>
|
||||
<!-- Disable all contacts by default -->
|
||||
<geom contype="0" conaffinity="0" />
|
||||
|
||||
<!-- Position controller (stronger for humanoid) -->
|
||||
<position kp="500" dampratio="1" inheritrange="1" />
|
||||
|
||||
<!-- Joint dynamics -->
|
||||
<joint damping="0.0" armature="1.0" frictionloss="0.0" />
|
||||
</default>
|
||||
```
|
||||
|
||||
### Step 3: Add Collision Geoms for Feet
|
||||
|
||||
Add collision spheres to feet (4 contact points per foot):
|
||||
|
||||
```xml
|
||||
<body name="left_foot">
|
||||
<!-- Visual mesh -->
|
||||
<geom name="left_foot_visual" type="mesh" mesh="left_foot_mesh"
|
||||
contype="0" conaffinity="0"/>
|
||||
|
||||
<!-- Collision spheres -->
|
||||
<geom name="lf0" type="sphere" size="0.02" pos="-0.05 0.025 -0.03"
|
||||
priority="1" friction="2.0" condim="3" />
|
||||
<geom name="lf1" type="sphere" size="0.02" pos="-0.05 -0.025 -0.03"
|
||||
priority="1" friction="2.0" condim="3" />
|
||||
<geom name="lf2" type="sphere" size="0.02" pos="0.12 0.03 -0.03"
|
||||
priority="1" friction="2.0" condim="3" />
|
||||
<geom name="lf3" type="sphere" size="0.02" pos="0.12 -0.03 -0.03"
|
||||
priority="1" friction="2.0" condim="3" />
|
||||
</body>
|
||||
|
||||
<!-- Similar for right foot: rf0, rf1, rf2, rf3 -->
|
||||
```
|
||||
|
||||
### Step 4: Add Collision Geoms for Hands
|
||||
|
||||
```xml
|
||||
<body name="left_hand">
|
||||
<!-- Visual mesh -->
|
||||
<geom name="left_hand_visual" type="mesh" mesh="left_hand_mesh"
|
||||
contype="0" conaffinity="0"/>
|
||||
|
||||
<!-- Collision sphere -->
|
||||
<geom name="lh" type="sphere" size="0.05" pos="0.1 0.0 0.0" />
|
||||
</body>
|
||||
|
||||
<!-- Similar for right hand: rh -->
|
||||
```
|
||||
|
||||
### Step 5: Add Trace Sites
|
||||
|
||||
```xml
|
||||
<body name="pelvis">
|
||||
<site name="trace_pelvis" size="0.01" pos="0 0 0" />
|
||||
</body>
|
||||
|
||||
<body name="left_foot">
|
||||
<site name="trace_left_foot" size="0.01" pos="0 0 0" />
|
||||
</body>
|
||||
|
||||
<body name="right_foot">
|
||||
<site name="trace_right_foot" size="0.01" pos="0 0 0" />
|
||||
</body>
|
||||
|
||||
<body name="left_hand">
|
||||
<site name="trace_left_hand" size="0.01" pos="0 0 0" />
|
||||
</body>
|
||||
|
||||
<body name="right_hand">
|
||||
<site name="trace_right_hand" size="0.01" pos="0 0 0" />
|
||||
</body>
|
||||
```
|
||||
|
||||
### Step 6: Add Contact Pairs
|
||||
|
||||
Define explicit contact pairs:
|
||||
|
||||
```xml
|
||||
<contact>
|
||||
<!-- Left foot contacts -->
|
||||
<pair name="left_foot_floor0" geom1="lf0" geom2="floor"
|
||||
solref="0.008 1" friction="1 1" condim="3" />
|
||||
<pair name="left_foot_floor1" geom1="lf1" geom2="floor"
|
||||
solref="0.008 1" friction="1 1" condim="3" />
|
||||
<pair name="left_foot_floor2" geom1="lf2" geom2="floor"
|
||||
solref="0.008 1" friction="1 1" condim="3" />
|
||||
<pair name="left_foot_floor3" geom1="lf3" geom2="floor"
|
||||
solref="0.008 1" friction="1 1" condim="3" />
|
||||
|
||||
<!-- Right foot contacts -->
|
||||
<pair name="right_foot_floor0" geom1="rf0" geom2="floor"
|
||||
solref="0.008 1" friction="1 1" condim="3" />
|
||||
<pair name="right_foot_floor1" geom1="rf1" geom2="floor"
|
||||
solref="0.008 1" friction="1 1" condim="3" />
|
||||
<pair name="right_foot_floor2" geom1="rf2" geom2="floor"
|
||||
solref="0.008 1" friction="1 1" condim="3" />
|
||||
<pair name="right_foot_floor3" geom1="rf3" geom2="floor"
|
||||
solref="0.008 1" friction="1 1" condim="3" />
|
||||
|
||||
<!-- Hand contacts -->
|
||||
<pair name="left_hand_floor" geom1="lh" geom2="floor"
|
||||
solref="0.008 1" friction="1 1" condim="3" />
|
||||
<pair name="right_hand_floor" geom1="rh" geom2="floor"
|
||||
solref="0.008 1" friction="1 1" condim="3" />
|
||||
</contact>
|
||||
```
|
||||
|
||||
### Step 7: Use Position Actuators
|
||||
|
||||
```xml
|
||||
<actuator>
|
||||
<!-- Legs -->
|
||||
<position name="left_hip_pitch" joint="left_hip_pitch_joint" />
|
||||
<position name="left_hip_roll" joint="left_hip_roll_joint" />
|
||||
<position name="left_hip_yaw" joint="left_hip_yaw_joint" />
|
||||
<position name="left_knee" joint="left_knee_joint" />
|
||||
<position name="left_ankle_pitch" joint="left_ankle_pitch_joint" />
|
||||
<position name="left_ankle_roll" joint="left_ankle_roll_joint" />
|
||||
|
||||
<!-- Arms -->
|
||||
<position name="left_shoulder_pitch" joint="left_shoulder_pitch_joint" />
|
||||
<position name="left_shoulder_roll" joint="left_shoulder_roll_joint" />
|
||||
<position name="left_elbow" joint="left_elbow_joint" />
|
||||
<!-- ... -->
|
||||
|
||||
<!-- Repeat for right side -->
|
||||
</actuator>
|
||||
```
|
||||
|
||||
::: warning Important
|
||||
Actuator order must match joint order in the model definition!
|
||||
:::
|
||||
|
||||
### Step 8: Setup Scene
|
||||
|
||||
Add white background and tracking camera:
|
||||
|
||||
```xml
|
||||
<statistic center="1.0 0.7 1.0" extent="0.8"/>
|
||||
|
||||
<asset>
|
||||
<!-- White skybox -->
|
||||
<texture type="skybox" builtin="flat" rgb1="1 1 1" rgb2="1 1 1"
|
||||
width="800" height="800"/>
|
||||
|
||||
<!-- White groundplane -->
|
||||
<texture type="2d" name="groundplane" builtin="checker" mark="edge"
|
||||
rgb1="1 1 1" rgb2="1 1 1" markrgb="0 0 0"
|
||||
width="300" height="300"/>
|
||||
<material name="groundplane" texture="groundplane" texuniform="true"
|
||||
texrepeat="5 5" reflectance="0"/>
|
||||
</asset>
|
||||
|
||||
<worldbody>
|
||||
<!-- Floor -->
|
||||
<geom name="floor" size="0 0 0.01" type="plane" material="groundplane"
|
||||
contype="1" conaffinity="0" priority="1" friction="0.6" condim="3"/>
|
||||
|
||||
<!-- Directional light -->
|
||||
<light pos="0 0 5" dir="0 0 -1" type="directional"/>
|
||||
|
||||
<!-- Tracking camera -->
|
||||
<camera name="track" pos="1.734 -1.135 .35"
|
||||
xyaxes="0.552 0.834 -0.000 -0.170 0.112 0.979"
|
||||
mode="trackcom"/>
|
||||
</worldbody>
|
||||
```
|
||||
|
||||
## Testing Your Robot
|
||||
|
||||
### Step 1: Visualize in MuJoCo
|
||||
|
||||
```python
|
||||
import mujoco
|
||||
import mujoco.viewer
|
||||
|
||||
# Load model
|
||||
model = mujoco.MjModel.from_xml_path('my_robot.xml')
|
||||
data = mujoco.MjData(model)
|
||||
|
||||
# Launch viewer
|
||||
mujoco.viewer.launch(model, data)
|
||||
```
|
||||
|
||||
Check:
|
||||
- [ ] Model loads without errors
|
||||
- [ ] All joints move freely
|
||||
- [ ] Collision geometry looks correct (green geoms)
|
||||
- [ ] Trace sites are visible
|
||||
- [ ] Tracking sites are positioned correctly
|
||||
|
||||
### Step 2: Test with SPIDER
|
||||
|
||||
Create a simple test scene:
|
||||
|
||||
```bash
|
||||
# Test IK (for hands)
|
||||
uv run spider/preprocess/ik.py \
|
||||
--robot-type=my_hand \
|
||||
--task=test_task \
|
||||
--dataset-name=test \
|
||||
--data-id=0 \
|
||||
--embodiment-type=right
|
||||
|
||||
# Test physics optimization
|
||||
uv run examples/run_mjwp.py \
|
||||
robot_type=my_hand \
|
||||
task=test_task \
|
||||
max_sim_steps=100
|
||||
```
|
||||
|
||||
### Step 3: Verify Output
|
||||
|
||||
Check that:
|
||||
- [ ] Trajectory is saved successfully
|
||||
- [ ] Joint positions are within limits
|
||||
- [ ] No collision warnings
|
||||
- [ ] Video renders correctly
|
||||
|
||||
## Common Issues
|
||||
|
||||
### Issue 1: Model Doesn't Load
|
||||
|
||||
**Error:** `XML parse error`
|
||||
|
||||
**Solutions:**
|
||||
- Check XML syntax
|
||||
- Validate with MuJoCo's `simulate` tool
|
||||
- Remove incompatible URDF attributes
|
||||
|
||||
### Issue 2: Unstable Simulation
|
||||
|
||||
**Symptoms:** Robot falls through floor, explodes
|
||||
|
||||
**Solutions:**
|
||||
```xml
|
||||
<!-- Increase solver iterations -->
|
||||
<option iterations="10" ls_iterations="20"/>
|
||||
|
||||
<!-- Add more collision points -->
|
||||
<!-- Adjust contact parameters -->
|
||||
<pair solref="0.01 1" friction="2 2"/>
|
||||
|
||||
<!-- Check mass distribution -->
|
||||
<!-- Ensure reasonable inertia values -->
|
||||
```
|
||||
|
||||
### Issue 3: Actuators Don't Work
|
||||
|
||||
**Symptoms:** Robot doesn't move
|
||||
|
||||
**Solutions:**
|
||||
- Check actuator names match joint names
|
||||
- Verify `kp` values are reasonable (100-1000)
|
||||
- Ensure joints have proper ranges
|
||||
- Check actuator order matches joint order
|
||||
|
||||
### Issue 4: Poor IK Results
|
||||
|
||||
**Symptoms:** IK fails or produces bad poses
|
||||
|
||||
**Solutions:**
|
||||
- Check tracking site orientations (especially palm)
|
||||
- Verify joint limits are correct
|
||||
- Add more trace sites for debugging
|
||||
- Tune IK weights in config
|
||||
|
||||
## Robot Configuration Files
|
||||
|
||||
### Directory Structure
|
||||
|
||||
```
|
||||
spider/assets/robots/
|
||||
├── my_hand/
|
||||
│ ├── left.xml # Left hand only
|
||||
│ ├── right.xml # Right hand only
|
||||
│ ├── bimanual.xml # Both hands
|
||||
│ ├── meshes/
|
||||
│ │ ├── palm.obj
|
||||
│ │ ├── thumb_tip.obj
|
||||
│ │ └── ...
|
||||
│ └── textures/
|
||||
│ └── hand_texture.png
|
||||
```
|
||||
|
||||
### Register Robot
|
||||
|
||||
Add robot to SPIDER's config:
|
||||
|
||||
```python
|
||||
# In spider/config.py or appropriate config file
|
||||
|
||||
ROBOT_TYPES = {
|
||||
"allegro": "spider/assets/robots/allegro",
|
||||
"inspire": "spider/assets/robots/inspire",
|
||||
"my_hand": "spider/assets/robots/my_hand", # Add your robot
|
||||
# ...
|
||||
}
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
After adding your robot:
|
||||
|
||||
1. **Test thoroughly** with multiple tasks
|
||||
2. **Document** robot-specific parameters
|
||||
3. **Tune** IK and optimization parameters
|
||||
4. **Share** your robot configuration (PR welcome!)
|
||||
@@ -0,0 +1,337 @@
|
||||
# Add New Simulator / Environment
|
||||
|
||||
This guide explains how to integrate a new physics simulator with SPIDER, enabling physics-based retargeting with different simulation backends.
|
||||
|
||||
## Overview
|
||||
|
||||
SPIDER is designed to work with any simulator out of the box. The modular architecture allows you to port new simulators by implementing a standard interface.
|
||||
|
||||
**Current simulators:**
|
||||
- **MJWP**: MuJoCo + Warp (default)
|
||||
- **DexMachina**: Genesis simulator
|
||||
- **HDMI**: MjLab (MuJoCo fork)
|
||||
|
||||
**This guide covers:**
|
||||
- Required interface functions
|
||||
- Implementation steps
|
||||
- Configuration setup
|
||||
- Testing and debugging
|
||||
|
||||
## Architecture
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
A[SPIDER Optimizer] --> B[Simulator Interface]
|
||||
B --> C[MuJoCo Warp]
|
||||
B --> D[Genesis]
|
||||
B --> E[MjLab]
|
||||
B --> F[Your Simulator]
|
||||
```
|
||||
|
||||
The simulator interface provides a standardized API that SPIDER's optimizer uses, regardless of the underlying physics engine.
|
||||
|
||||
## Required Interface
|
||||
|
||||
### Core Functions (Required)
|
||||
|
||||
These functions are essential for SPIDER optimization:
|
||||
|
||||
#### 1. `setup_env(config, ref_data)`
|
||||
|
||||
Initialize and return the environment instance.
|
||||
|
||||
```python
|
||||
def setup_env(config: Config, ref_data: tuple | None) -> Any:
|
||||
"""
|
||||
Setup simulation environment.
|
||||
|
||||
Args:
|
||||
config: SPIDER configuration
|
||||
ref_data: Reference trajectory data (qpos, qvel, ctrl, contact, contact_pos)
|
||||
or None if environment provides its own reference
|
||||
|
||||
Returns:
|
||||
Environment instance (simulator-specific type)
|
||||
"""
|
||||
# Initialize your simulator
|
||||
env = YourSimulator(
|
||||
num_envs=config.num_samples,
|
||||
device=config.device,
|
||||
dt=config.sim_dt,
|
||||
)
|
||||
|
||||
# Load scene/model
|
||||
env.load_scene(config.model_path)
|
||||
|
||||
# Set initial state
|
||||
if ref_data is not None:
|
||||
qpos_ref, qvel_ref, _, _, _ = ref_data
|
||||
env.set_state(qpos_ref[0], qvel_ref[0])
|
||||
|
||||
return env
|
||||
```
|
||||
|
||||
#### 2. `step_env(config, env, ctrl)`
|
||||
|
||||
Step the simulator with control inputs.
|
||||
|
||||
```python
|
||||
def step_env(config: Config, env: Any, ctrl: torch.Tensor) -> None:
|
||||
"""
|
||||
Step simulation forward with controls.
|
||||
|
||||
Args:
|
||||
config: SPIDER configuration
|
||||
env: Environment instance
|
||||
ctrl: Control inputs [num_samples, nu]
|
||||
"""
|
||||
# Apply controls
|
||||
env.set_action(ctrl)
|
||||
|
||||
# Step physics
|
||||
env.step()
|
||||
```
|
||||
|
||||
#### 3. `save_state(env)`
|
||||
|
||||
Save the current state of all parallel environments.
|
||||
|
||||
```python
|
||||
def save_state(env: Any) -> dict:
|
||||
"""
|
||||
Save current simulation state.
|
||||
|
||||
Args:
|
||||
env: Environment instance
|
||||
|
||||
Returns:
|
||||
State dictionary (simulator-specific format)
|
||||
"""
|
||||
return {
|
||||
'qpos': env.get_qpos().clone(),
|
||||
'qvel': env.get_qvel().clone(),
|
||||
# Add any other state needed for perfect restoration
|
||||
'time': env.time,
|
||||
}
|
||||
```
|
||||
|
||||
#### 4. `load_state(env, state)`
|
||||
|
||||
Load a saved state back into the environments.
|
||||
|
||||
```python
|
||||
def load_state(env: Any, state: dict) -> None:
|
||||
"""
|
||||
Restore simulation state.
|
||||
|
||||
Args:
|
||||
env: Environment instance
|
||||
state: State dictionary from save_state()
|
||||
"""
|
||||
env.set_qpos(state['qpos'])
|
||||
env.set_qvel(state['qvel'])
|
||||
env.time = state['time']
|
||||
```
|
||||
|
||||
#### 5. `get_reward(config, env, ref)`
|
||||
|
||||
Compute reward for current state.
|
||||
|
||||
```python
|
||||
def get_reward(config: Config, env: Any, ref: tuple) -> torch.Tensor:
|
||||
"""
|
||||
Compute reward for current state.
|
||||
|
||||
Args:
|
||||
config: SPIDER configuration
|
||||
env: Environment instance
|
||||
ref: Reference data (qpos_ref, qvel_ref, ctrl_ref, contact, contact_pos)
|
||||
|
||||
Returns:
|
||||
Rewards [num_samples]
|
||||
"""
|
||||
qpos_ref, qvel_ref, ctrl_ref, contact, contact_pos = ref
|
||||
qpos = env.get_qpos()
|
||||
qvel = env.get_qvel()
|
||||
|
||||
# Tracking reward
|
||||
pos_error = torch.norm(qpos - qpos_ref, dim=-1)
|
||||
vel_error = torch.norm(qvel - qvel_ref, dim=-1)
|
||||
|
||||
reward = -pos_error * config.joint_rew_scale
|
||||
reward += -vel_error * config.vel_rew_scale
|
||||
|
||||
return reward
|
||||
```
|
||||
|
||||
#### 6. `get_terminal_reward(config, env, ref_slice)`
|
||||
|
||||
Compute terminal reward with scaling.
|
||||
|
||||
```python
|
||||
def get_terminal_reward(
|
||||
config: Config,
|
||||
env: Any,
|
||||
ref_slice: tuple
|
||||
) -> torch.Tensor:
|
||||
"""
|
||||
Compute terminal (final state) reward.
|
||||
|
||||
Args:
|
||||
config: SPIDER configuration
|
||||
env: Environment instance
|
||||
ref_slice: Reference slice for horizon
|
||||
|
||||
Returns:
|
||||
Terminal rewards [num_samples]
|
||||
"""
|
||||
# Often just scaled version of regular reward
|
||||
reward = get_reward(config, env, ref_slice[-1])
|
||||
return reward * config.terminal_rew_scale
|
||||
```
|
||||
|
||||
### Helper Functions (Required for Optimizer)
|
||||
|
||||
#### 7. `get_trace(config, env)`
|
||||
|
||||
Return visualization trace points.
|
||||
|
||||
```python
|
||||
def get_trace(config: Config, env: Any) -> torch.Tensor:
|
||||
"""
|
||||
Get trace points for visualization.
|
||||
|
||||
Args:
|
||||
config: SPIDER configuration
|
||||
env: Environment instance
|
||||
|
||||
Returns:
|
||||
Trace positions [num_samples, num_traces, 3]
|
||||
"""
|
||||
# Get positions of trace sites (hands, feet, objects, etc.)
|
||||
traces = []
|
||||
|
||||
for site_id in config.trace_site_ids:
|
||||
site_pos = env.get_site_position(site_id)
|
||||
traces.append(site_pos)
|
||||
|
||||
return torch.stack(traces, dim=1) # [num_samples, num_traces, 3]
|
||||
```
|
||||
|
||||
#### 8. `save_env_params(config, env)`
|
||||
|
||||
Save environment parameters for domain randomization.
|
||||
|
||||
```python
|
||||
def save_env_params(config: Config, env: Any) -> dict:
|
||||
"""
|
||||
Save environment parameters (for domain randomization).
|
||||
|
||||
Args:
|
||||
config: SPIDER configuration
|
||||
env: Environment instance
|
||||
|
||||
Returns:
|
||||
Parameters dictionary
|
||||
"""
|
||||
return {
|
||||
'object_pos': env.get_object_position().clone(),
|
||||
'object_mass': env.get_object_mass().clone(),
|
||||
'friction': env.get_friction().clone(),
|
||||
# Add any randomized parameters
|
||||
}
|
||||
```
|
||||
|
||||
#### 9. `load_env_params(config, env, env_param)`
|
||||
|
||||
Load environment parameters.
|
||||
|
||||
```python
|
||||
def load_env_params(config: Config, env: Any, env_param: dict) -> None:
|
||||
"""
|
||||
Load environment parameters.
|
||||
|
||||
Args:
|
||||
config: SPIDER configuration
|
||||
env: Environment instance
|
||||
env_param: Parameters from save_env_params()
|
||||
"""
|
||||
env.set_object_position(env_param['object_pos'])
|
||||
env.set_object_mass(env_param['object_mass'])
|
||||
env.set_friction(env_param['friction'])
|
||||
```
|
||||
|
||||
#### 10. `sync_env(config, env)`
|
||||
|
||||
Synchronize state across parallel environments.
|
||||
|
||||
```python
|
||||
def sync_env(config: Config, env: Any) -> None:
|
||||
"""
|
||||
Synchronize state across parallel environments.
|
||||
Typically broadcasts first environment to all others.
|
||||
|
||||
Args:
|
||||
config: SPIDER configuration
|
||||
env: Environment instance
|
||||
"""
|
||||
# Get state from first environment
|
||||
qpos = env.get_qpos()
|
||||
qvel = env.get_qvel()
|
||||
|
||||
# Broadcast to all environments
|
||||
qpos_sync = qpos[0:1].repeat(config.num_samples, 1)
|
||||
qvel_sync = qvel[0:1].repeat(config.num_samples, 1)
|
||||
|
||||
env.set_qpos(qpos_sync)
|
||||
env.set_qvel(qvel_sync)
|
||||
```
|
||||
|
||||
### Optional Functions
|
||||
|
||||
#### `copy_sample_state(state, sample_idx)`
|
||||
|
||||
Copy state from specific sample (for best trajectory selection).
|
||||
|
||||
```python
|
||||
def copy_sample_state(state: dict, sample_idx: int) -> dict:
|
||||
"""
|
||||
Copy state from specific parallel environment.
|
||||
|
||||
Args:
|
||||
state: Full state dictionary
|
||||
sample_idx: Index of sample to copy
|
||||
|
||||
Returns:
|
||||
State dictionary for single sample
|
||||
"""
|
||||
return {
|
||||
'qpos': state['qpos'][sample_idx:sample_idx+1].clone(),
|
||||
'qvel': state['qvel'][sample_idx:sample_idx+1].clone(),
|
||||
'time': state['time'],
|
||||
}
|
||||
```
|
||||
|
||||
#### `get_terminate(config, env, ref)`
|
||||
|
||||
Early termination check (optional optimization).
|
||||
|
||||
```python
|
||||
def get_terminate(config: Config, env: Any, ref: tuple) -> torch.Tensor:
|
||||
"""
|
||||
Check if rollout should terminate early.
|
||||
|
||||
Args:
|
||||
config: SPIDER configuration
|
||||
env: Environment instance
|
||||
ref: Reference data
|
||||
|
||||
Returns:
|
||||
Boolean mask [num_samples]
|
||||
"""
|
||||
# Example: terminate if object falls
|
||||
object_height = env.get_object_position()[:, 2]
|
||||
terminate = object_height < 0.1
|
||||
|
||||
return terminate
|
||||
```
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
# Installation
|
||||
|
||||
This guide walks you through installing SPIDER and its dependencies.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- **Python**: 3.12 or higher
|
||||
- **CUDA**: 11.8 or higher (for GPU acceleration)
|
||||
- **Git**: For cloning repositories
|
||||
- **Git LFS**: For large file storage (datasets)
|
||||
|
||||
## Option 1: Using uv (Recommended)
|
||||
|
||||
[uv](https://github.com/astral-sh/uv) is a fast Python package installer that we recommend for development.
|
||||
|
||||
### Install uv
|
||||
|
||||
```bash
|
||||
# Linux/macOS
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
|
||||
# Windows
|
||||
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
|
||||
```
|
||||
|
||||
### Install SPIDER
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://github.com/facebookresearch/spider.git
|
||||
cd spider
|
||||
|
||||
uv sync
|
||||
```
|
||||
|
||||
### Clone Example Datasets
|
||||
|
||||
```bash
|
||||
# Install git-lfs
|
||||
sudo apt install git-lfs # Ubuntu/Debian
|
||||
# brew install git-lfs # macOS
|
||||
|
||||
git lfs install
|
||||
git clone https://huggingface.co/datasets/retarget/retarget_example example_datasets
|
||||
```
|
||||
|
||||
## Option 2: Using Conda
|
||||
|
||||
If you prefer conda for environment management:
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone https://github.com/facebookresearch/spider.git
|
||||
cd spider
|
||||
|
||||
# Create conda environment
|
||||
conda create -n spider python=3.12
|
||||
conda activate spider
|
||||
|
||||
# Install dependencies
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install -r requirements.txt
|
||||
python -m pip install --no-deps -e .
|
||||
```
|
||||
|
||||
## Verify Installation
|
||||
|
||||
Test your installation by running a simple example:
|
||||
|
||||
```bash
|
||||
# With uv
|
||||
uv run examples/run_mjwp.py
|
||||
|
||||
# With conda
|
||||
python examples/run_mjwp.py
|
||||
```
|
||||
|
||||
If everything is installed correctly, you should see the MuJoCo viewer open with a retargeting simulation.
|
||||
|
||||
## Optional: Install Additional Backends
|
||||
|
||||
### DexMachina (Genesis Simulator)
|
||||
|
||||
For RL training with Genesis simulator:
|
||||
|
||||
```bash
|
||||
# Follow DexMachina installation instructions
|
||||
# https://mandizhao.github.io/dexmachina-docs/0_install.html
|
||||
|
||||
conda activate dexmachina
|
||||
pip install --ignore-requires-python --no-deps -e .
|
||||
```
|
||||
|
||||
### HDMI (Humanoid RL)
|
||||
|
||||
For humanoid robot RL training:
|
||||
|
||||
```bash
|
||||
# Clone and install HDMI
|
||||
git clone https://github.com/lecar-lab/hdmi.git
|
||||
cd hdmi
|
||||
|
||||
# Install SPIDER in HDMI environment
|
||||
uv pip install --no-deps -e ../spider
|
||||
```
|
||||
|
||||
### IDE Setup
|
||||
|
||||
For VSCode, recommended extensions:
|
||||
- Python
|
||||
- Pylance
|
||||
- Ruff
|
||||
|
||||
You can load the `.vscode/settings.json` file to your VSCode to get the recommended settings.
|
||||
+281
@@ -0,0 +1,281 @@
|
||||
# Quick Start
|
||||
|
||||
This guide will help you run your first SPIDER retargeting example in minutes.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Make sure you have completed the [installation](/guide/installation) and cloned the example datasets.
|
||||
|
||||
## Run Preprocessed Example
|
||||
|
||||
The quickest way to see SPIDER in action is to run a preprocessed example:
|
||||
|
||||
```bash
|
||||
# Run with default config (Xhand bimanual, OakInk dataset)
|
||||
uv run examples/run_mjwp.py
|
||||
```
|
||||
|
||||
This will:
|
||||
1. Load preprocessed kinematic trajectory
|
||||
2. Optimize trajectory with physics constraints
|
||||
3. Display real-time visualization in MuJoCo viewer
|
||||
4. Save optimized trajectory and video
|
||||
|
||||
## Full Workflow Example For Dexterous Hand
|
||||
|
||||
To process a task from scratch, follow these steps:
|
||||
|
||||
### 1. Set Task Parameters
|
||||
|
||||
```bash
|
||||
export TASK=p36-tea
|
||||
export HAND_TYPE=bimanual
|
||||
export DATA_ID=10
|
||||
export ROBOT_TYPE=xhand
|
||||
export DATASET_NAME=gigahand
|
||||
```
|
||||
|
||||
### 2. Process Dataset
|
||||
|
||||
Convert raw human motion data to standardized format:
|
||||
|
||||
```bash
|
||||
uv run spider/process_datasets/${DATASET_NAME}.py \
|
||||
--task=${TASK} \
|
||||
--embodiment-type=${HAND_TYPE} \
|
||||
--data-id=${DATA_ID}
|
||||
```
|
||||
|
||||
### 3. Decompose Object Mesh
|
||||
|
||||
Create convex decomposition for physics simulation:
|
||||
|
||||
```bash
|
||||
uv run spider/preprocess/decompose_fast.py \
|
||||
--task=${TASK} \
|
||||
--dataset-name=${DATASET_NAME} \
|
||||
--data-id=${DATA_ID} \
|
||||
--embodiment-type=${HAND_TYPE}
|
||||
```
|
||||
|
||||
### 4. Detect Contacts (Optional)
|
||||
|
||||
Identify hand-object contact points:
|
||||
|
||||
```bash
|
||||
uv run spider/preprocess/detect_contact.py \
|
||||
--task=${TASK} \
|
||||
--dataset-name=${DATASET_NAME} \
|
||||
--data-id=${DATA_ID} \
|
||||
--embodiment-type=${HAND_TYPE}
|
||||
```
|
||||
|
||||
### 5. Generate Scene
|
||||
|
||||
Create MuJoCo scene XML:
|
||||
|
||||
```bash
|
||||
uv run spider/preprocess/generate_xml.py \
|
||||
--task=${TASK} \
|
||||
--dataset-name=${DATASET_NAME} \
|
||||
--data-id=${DATA_ID} \
|
||||
--embodiment-type=${HAND_TYPE} \
|
||||
--robot-type=${ROBOT_TYPE}
|
||||
```
|
||||
|
||||
### 6. Run Inverse Kinematics
|
||||
|
||||
Convert human poses to robot joint angles:
|
||||
|
||||
```bash
|
||||
uv run spider/preprocess/ik.py \
|
||||
--task=${TASK} \
|
||||
--dataset-name=${DATASET_NAME} \
|
||||
--data-id=${DATA_ID} \
|
||||
--embodiment-type=${HAND_TYPE} \
|
||||
--robot-type=${ROBOT_TYPE} \
|
||||
--open-hand
|
||||
```
|
||||
|
||||
### 7. Physics-Based Retargeting
|
||||
|
||||
Optimize trajectory with physics constraints:
|
||||
|
||||
```bash
|
||||
uv run examples/run_mjwp.py \
|
||||
task=${TASK} \
|
||||
dataset_name=${DATASET_NAME} \
|
||||
data_id=${DATA_ID} \
|
||||
robot_type=${ROBOT_TYPE} \
|
||||
embodiment_type=${HAND_TYPE}
|
||||
```
|
||||
|
||||
## Full Workflow Example For Humanoid Robot
|
||||
|
||||
Set environment variables:
|
||||
|
||||
```bash
|
||||
# humanoid only
|
||||
export TASK=dance
|
||||
export HAND_TYPE=humanoid
|
||||
export DATA_ID=0
|
||||
export ROBOT_TYPE=unitree_g1
|
||||
export DATASET_NAME=lafan
|
||||
|
||||
# humanoid + object
|
||||
export TASK=move_largebox
|
||||
export HAND_TYPE=humanoid_object
|
||||
export DATA_ID=0
|
||||
export ROBOT_TYPE=unitree_g1
|
||||
export DATASET_NAME=omomo
|
||||
```
|
||||
|
||||
### Run IK
|
||||
|
||||
```bash
|
||||
# with GMR (remember to generate GMR data trajectoru_gmr.pkl first with their official code. )
|
||||
uv run spider/process_datasets/gmr.py \
|
||||
--task=${TASK} \
|
||||
--dataset-name=${DATASET_NAME} \
|
||||
--data-id=${DATA_ID} \
|
||||
--robot-type=${ROBOT_TYPE} \
|
||||
--embodiment-type=${HAND_TYPE} \
|
||||
--contact-detection-mode=one
|
||||
|
||||
# with locomujoco
|
||||
uv run spider/process_datasets/locomujoco.py \
|
||||
--task=${TASK} \
|
||||
--dataset-name=${DATASET_NAME} \
|
||||
--data-id=${DATA_ID} \
|
||||
--robot-type=${ROBOT_TYPE} \
|
||||
--embodiment-type=${HAND_TYPE}
|
||||
|
||||
# for humanoid + object, we don't have a pipeline yet
|
||||
# you can directly download data from omniretarget
|
||||
# https://huggingface.co/datasets/omniretarget/OmniRetarget_Dataset
|
||||
```
|
||||
|
||||
### Run Physics-Based Retargeting
|
||||
|
||||
```bash
|
||||
# for humanoid only
|
||||
uv run examples/run_mjwp.py \
|
||||
+override=humanoid \
|
||||
dataset_name=${DATASET_NAME} \
|
||||
task=${TASK} \
|
||||
data_id=${DATA_ID} \
|
||||
robot_type=${ROBOT_TYPE} \
|
||||
embodiment_type=${HAND_TYPE}
|
||||
|
||||
# for humanoid + object, we don't have a pipeline yet
|
||||
uv run examples/run_mjwp.py \
|
||||
+override=humanoid_object \
|
||||
dataset_name=${DATASET_NAME} \
|
||||
task=${TASK} \
|
||||
data_id=${DATA_ID} \
|
||||
robot_type=${ROBOT_TYPE} \
|
||||
embodiment_type=${HAND_TYPE}
|
||||
```
|
||||
|
||||
## Understanding the Output
|
||||
|
||||
After running, you'll find these files in the output directory:
|
||||
|
||||
```
|
||||
example_datasets/processed/oakink/allegro/bimanual/pick_spoon_bowl/0/
|
||||
├── trajectory_kinematic.npz # IK result
|
||||
├── trajectory_mjwp.npz # Optimized trajectory
|
||||
├── visualization_mjwp.mp4 # Video output
|
||||
└── metrics.json # Success metrics
|
||||
```
|
||||
|
||||
### Trajectory Data Format
|
||||
|
||||
The NPZ files contain:
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
|
||||
data = np.load('trajectory_mjwp.npz')
|
||||
|
||||
# Available keys:
|
||||
# - qpos: [T, nq] joint positions
|
||||
# - qvel: [T, nv] joint velocities
|
||||
# - ctrl: [T, nu] control commands
|
||||
# - time: [T] timestamps
|
||||
```
|
||||
|
||||
## Customize Parameters
|
||||
|
||||
Override configuration parameters from command line:
|
||||
|
||||
```bash
|
||||
# Increase optimization samples
|
||||
uv run examples/run_mjwp.py num_samples=2048
|
||||
|
||||
# Change planning horizon
|
||||
uv run examples/run_mjwp.py horizon=2.0
|
||||
|
||||
# Use different viewer
|
||||
uv run examples/run_mjwp.py viewer=rerun
|
||||
|
||||
# Combine multiple overrides
|
||||
uv run examples/run_mjwp.py \
|
||||
robot_type=inspire \
|
||||
num_samples=2048 \
|
||||
horizon=2.0 \
|
||||
viewer=mujoco-rerun
|
||||
```
|
||||
|
||||
## Remote Development
|
||||
|
||||
For headless servers, use Rerun viewer:
|
||||
|
||||
```bash
|
||||
# On remote server, start Rerun server
|
||||
uv run rerun --serve-web --port 9876
|
||||
|
||||
# Run SPIDER with Rerun viewer
|
||||
uv run examples/run_mjwp.py viewer=rerun
|
||||
|
||||
# On local machine, open browser to:
|
||||
# http://your-server:9876
|
||||
```
|
||||
|
||||
## Common Tasks
|
||||
|
||||
### Run Different Robot
|
||||
|
||||
```bash
|
||||
# Allegro hand
|
||||
uv run examples/run_mjwp.py robot_type=allegro
|
||||
|
||||
# Inspire hand
|
||||
uv run examples/run_mjwp.py robot_type=inspire
|
||||
|
||||
# Xhand
|
||||
uv run examples/run_mjwp.py robot_type=xhand
|
||||
```
|
||||
|
||||
### Run Different Dataset
|
||||
|
||||
```bash
|
||||
# GigaHand
|
||||
uv run examples/run_mjwp.py +override=gigahand
|
||||
|
||||
# Hot3D
|
||||
uv run examples/run_mjwp.py +override=hot3d
|
||||
|
||||
# Humanoid task
|
||||
uv run examples/run_mjwp.py +override=humanoid
|
||||
```
|
||||
|
||||
### Single Hand Configuration
|
||||
|
||||
```bash
|
||||
# Right hand only
|
||||
uv run examples/run_mjwp.py embodiment_type=right
|
||||
|
||||
# Left hand only
|
||||
uv run examples/run_mjwp.py embodiment_type=left
|
||||
```
|
||||
Vendored
+49
@@ -0,0 +1,49 @@
|
||||
---
|
||||
layout: home
|
||||
|
||||
hero:
|
||||
name: "SPIDER"
|
||||
text: "Scalable Physics-Informed DExterous Retargeting"
|
||||
tagline: A general framework for physics-based retargeting from human to diverse robot embodiments
|
||||
image:
|
||||
src: /figs/teaser.png
|
||||
alt: SPIDER
|
||||
actions:
|
||||
- theme: brand
|
||||
text: Get Started
|
||||
link: /guide/quick-start
|
||||
- theme: alt
|
||||
text: View on GitHub
|
||||
link: https://github.com/facebookresearch/spider
|
||||
|
||||
features:
|
||||
- icon: 🔬
|
||||
title: Physics-Based
|
||||
details: First general physics-based retargeting pipeline for both dexterous hand and humanoid robot manipulation
|
||||
|
||||
- icon: ⚡
|
||||
title: Fast Simulation
|
||||
details: GPU-accelerated batched simulation with MuJoCo Warp achieving 10-20x speedup over sequential execution
|
||||
|
||||
- icon: 📊
|
||||
title: Rich Datasets, Robots and Simulators
|
||||
details: Works with 6+ datasets out of the box including GigaHand, Hot3D, OakInk, and more. Supports 9+ robot embodiments including dexterous hands (Allegro, Inspire, Xhand) and humanoid robots (G1, H1, T1). Supports multiple simulators including MuJoCo Warp, Genesis, and HDMI.
|
||||
|
||||
- icon: 🔄
|
||||
title: Sim2Real Ready
|
||||
details: Optimized trajectories can be directly deployed to real-world robots with minimal adjustments
|
||||
---
|
||||
|
||||
## Quick Example
|
||||
|
||||
```bash
|
||||
# Clone example datasets
|
||||
git clone https://huggingface.co/datasets/retarget/retarget_example example_datasets
|
||||
|
||||
# Install with uv
|
||||
uv sync --python 3.12
|
||||
pip install --ignore-requires-python --no-deps -e .
|
||||
|
||||
# Run retargeting
|
||||
uv run examples/run_mjwp.py
|
||||
```
|
||||
+2379
File diff suppressed because it is too large
Load Diff
Vendored
+18
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "spider-docs",
|
||||
"version": "1.0.0",
|
||||
"description": "SPIDER Documentation",
|
||||
"scripts": {
|
||||
"docs:dev": "vitepress dev",
|
||||
"docs:build": "vitepress build",
|
||||
"docs:preview": "vitepress preview"
|
||||
},
|
||||
"overrides": {
|
||||
"esbuild": "0.27.1",
|
||||
"mdast-util-to-hast": "13.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vitepress": "^1.6.4",
|
||||
"vue": "^3.5.24"
|
||||
}
|
||||
}
|
||||
+389
@@ -0,0 +1,389 @@
|
||||
# Data Structure
|
||||
|
||||
SPIDER uses a structured file organization to handle multiple datasets, robots, and tasks efficiently.
|
||||
|
||||
## Directory Layout
|
||||
|
||||
```
|
||||
example_datasets/
|
||||
├── raw/ # Raw human motion data
|
||||
│ └── {dataset_name}/
|
||||
│ ├── {data_id}.pkl
|
||||
│ └── meshes/
|
||||
│
|
||||
└── processed/ # Processed robot trajectories
|
||||
└── {dataset_name}/
|
||||
├── dataset_summary.json # High-level metadata
|
||||
├── assets/ # Shared assets (avoid duplication)
|
||||
│ ├── objects/
|
||||
│ └── robots/
|
||||
├── mano/ # Extracted human hand data
|
||||
│ └── {embodiment_type}/
|
||||
│ └── {task}/
|
||||
│ └── {data_id}/
|
||||
│ ├── trajectory_keypoint.npz
|
||||
│ └── info.json
|
||||
└── {robot_type}/ # Robot-specific data
|
||||
└── {embodiment_type}/
|
||||
└── {task}/
|
||||
└── {data_id}/
|
||||
├── scene.xml
|
||||
├── trajectory_kinematic.npz
|
||||
├── trajectory_mjwp.npz
|
||||
├── visualization_mjwp.mp4
|
||||
└── metrics.json
|
||||
```
|
||||
|
||||
## Path Resolution
|
||||
|
||||
SPIDER automatically resolves paths based on task parameters:
|
||||
|
||||
```python
|
||||
from spider.io import get_processed_data_dir
|
||||
|
||||
# Resolve processed directory
|
||||
processed_dir = get_processed_data_dir(
|
||||
dataset_dir="/path/to/datasets",
|
||||
dataset_name="oakink",
|
||||
robot_type="allegro",
|
||||
embodiment_type="bimanual",
|
||||
task="pick_spoon_bowl",
|
||||
data_id=0
|
||||
)
|
||||
# Returns: /path/to/datasets/processed/oakink/allegro/bimanual/pick_spoon_bowl/0/
|
||||
```
|
||||
|
||||
## File Formats
|
||||
|
||||
### Raw Data (`raw/{dataset_name}/{data_id}.pkl`)
|
||||
|
||||
Raw human motion data from dataset processing:
|
||||
|
||||
```python
|
||||
{
|
||||
'qpos_wrist_right': np.ndarray, # [T, 7] position + quaternion
|
||||
'qpos_finger_right': np.ndarray, # [T, n_joints] joint angles
|
||||
'qpos_wrist_left': np.ndarray, # [T, 7]
|
||||
'qpos_finger_left': np.ndarray, # [T, n_joints]
|
||||
'qpos_obj_right': np.ndarray, # [T, 7] object pose
|
||||
'qpos_obj_left': np.ndarray, # [T, 7]
|
||||
'contact': np.ndarray, # [T, ncon] contact indicators
|
||||
'contact_pos': np.ndarray # [T, ncon, 3] contact positions
|
||||
}
|
||||
```
|
||||
|
||||
### Trajectory Files (`.npz`)
|
||||
|
||||
#### `trajectory_keypoint.npz`
|
||||
|
||||
Human hand keypoints (from dataset processor):
|
||||
|
||||
```python
|
||||
{
|
||||
'qpos_wrist_right': [T, 7],
|
||||
'qpos_finger_right': [T, 15],
|
||||
'qpos_obj_right': [T, 7],
|
||||
# ... left hand equivalents
|
||||
}
|
||||
```
|
||||
|
||||
#### `trajectory_kinematic.npz`
|
||||
|
||||
Kinematic retargeting result (from IK):
|
||||
|
||||
```python
|
||||
{
|
||||
'qpos': [T, nq], # Full robot configuration
|
||||
'qvel': [T, nv], # Velocities
|
||||
'ctrl': [T, nu], # Control targets
|
||||
'contact': [T, ncon], # Contact indicators
|
||||
'contact_pos': [T, ncon, 3] # Contact positions
|
||||
}
|
||||
```
|
||||
|
||||
#### `trajectory_mjwp.npz`
|
||||
|
||||
Physics-optimized trajectory (from MJWP):
|
||||
|
||||
```python
|
||||
{
|
||||
'qpos': [N_steps, ctrl_steps, nq], # Per-step configs
|
||||
'qvel': [N_steps, ctrl_steps, nv], # Velocities
|
||||
'ctrl': [N_steps, ctrl_steps, nu], # Control commands
|
||||
'time': [N_steps, ctrl_steps], # Timestamps
|
||||
'opt_steps': [N_steps], # Iterations per step
|
||||
'improvement': [N_steps], # Convergence metric
|
||||
'rewards': [N_steps, num_samples], # Per-sample rewards
|
||||
}
|
||||
```
|
||||
|
||||
### Scene Files
|
||||
|
||||
#### `scene.xml`
|
||||
|
||||
MuJoCo scene definition:
|
||||
|
||||
```xml
|
||||
<mujoco model="scene">
|
||||
<!-- Solver settings -->
|
||||
<option timestep="0.01" iterations="20" ...>
|
||||
|
||||
<!-- Robot model -->
|
||||
<include file="../../assets/robots/allegro/bimanual.xml"/>
|
||||
|
||||
<!-- Object geometries -->
|
||||
<body name="object_right" pos="0 0 0">
|
||||
<freejoint/>
|
||||
<geom type="mesh" mesh="obj_visual"/>
|
||||
<geom type="mesh" mesh="obj_collision_0" .../>
|
||||
...
|
||||
</body>
|
||||
|
||||
<!-- Contact pairs -->
|
||||
<contact>
|
||||
<pair geom1="finger_tip" geom2="obj_collision_0"/>
|
||||
...
|
||||
</contact>
|
||||
</mujoco>
|
||||
```
|
||||
|
||||
#### `scene_eq.xml`
|
||||
|
||||
Scene with equality constraints (for `num_dyn > 1`):
|
||||
|
||||
Includes additional `<equality>` elements for virtual contact constraints used in annealing.
|
||||
|
||||
### Metadata Files
|
||||
|
||||
#### `task_info.json`
|
||||
|
||||
Task-level metadata:
|
||||
|
||||
```json
|
||||
{
|
||||
"dataset_name": "oakink",
|
||||
"task": "pick_spoon_bowl",
|
||||
"embodiment_type": "bimanual",
|
||||
"ref_dt": 0.02,
|
||||
"object_names": ["spoon", "bowl"],
|
||||
"num_frames": 250
|
||||
}
|
||||
```
|
||||
|
||||
#### `info.json`
|
||||
|
||||
Trial-level metadata:
|
||||
|
||||
```json
|
||||
{
|
||||
"robot_type": "allegro",
|
||||
"data_id": 0,
|
||||
"timestamp": "2025-01-15T10:30:00",
|
||||
"object_asset_paths": {
|
||||
"spoon": "../../../../assets/objects/spoon/visual.obj",
|
||||
"bowl": "../../../../assets/objects/bowl/visual.obj"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### `metrics.json`
|
||||
|
||||
Performance metrics:
|
||||
|
||||
```json
|
||||
{
|
||||
"success_rate": 0.95,
|
||||
"avg_position_error": 0.012,
|
||||
"avg_rotation_error": 0.08,
|
||||
"avg_optimization_time": 0.234,
|
||||
"total_simulation_steps": 300
|
||||
}
|
||||
```
|
||||
|
||||
## Asset Organization
|
||||
|
||||
### Object Assets
|
||||
|
||||
Shared object meshes to avoid duplication:
|
||||
|
||||
```
|
||||
assets/objects/{object_name}/
|
||||
├── visual.obj # High-res visual mesh
|
||||
└── convex/ # Convex decomposition
|
||||
├── 0.obj
|
||||
├── 1.obj
|
||||
├── 2.obj
|
||||
└── ...
|
||||
```
|
||||
|
||||
### Robot Assets
|
||||
|
||||
Robot MJCF files:
|
||||
|
||||
```
|
||||
assets/robots/{robot_type}/
|
||||
├── left.xml # Left hand only
|
||||
├── right.xml # Right hand only
|
||||
└── bimanual.xml # Both hands
|
||||
```
|
||||
|
||||
## Loading Data
|
||||
|
||||
### In Python
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
from spider.io import load_data
|
||||
from spider.config import Config, process_config
|
||||
|
||||
# Create and process config
|
||||
config = Config(
|
||||
dataset_name="oakink",
|
||||
robot_type="allegro",
|
||||
embodiment_type="bimanual",
|
||||
task="pick_spoon_bowl",
|
||||
data_id=0
|
||||
)
|
||||
config = process_config(config)
|
||||
|
||||
# Load trajectory
|
||||
qpos, qvel, ctrl, contact, contact_pos = load_data(
|
||||
config,
|
||||
config.data_path
|
||||
)
|
||||
|
||||
print(f"Trajectory length: {qpos.shape[0]}")
|
||||
print(f"DOF: {qpos.shape[1]}")
|
||||
```
|
||||
|
||||
### Manual Loading
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
|
||||
# Load trajectory
|
||||
data = np.load('trajectory_mjwp.npz')
|
||||
|
||||
# Access arrays
|
||||
qpos = data['qpos'] # [T, nq]
|
||||
qvel = data['qvel'] # [T, nv]
|
||||
ctrl = data['ctrl'] # [T, nu]
|
||||
|
||||
# Reshape if needed (MJWP saves per-step)
|
||||
if qpos.ndim == 3:
|
||||
qpos = qpos.reshape(-1, qpos.shape[-1])
|
||||
```
|
||||
|
||||
## Data Flow Through Pipeline
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Raw Data<br/>raw/dataset/data.pkl] --> B[Dataset Processor]
|
||||
B --> C[Keypoints<br/>mano/.../trajectory_keypoint.npz]
|
||||
C --> D[Preprocessing Pipeline]
|
||||
D --> E[Object Decomposition<br/>assets/objects/*/convex/*.obj]
|
||||
D --> F[Scene XML<br/>robot/.../scene.xml]
|
||||
D --> G[Kinematic Trajectory<br/>robot/.../trajectory_kinematic.npz]
|
||||
G --> H[Physics Optimization]
|
||||
H --> I[Optimized Trajectory<br/>robot/.../trajectory_mjwp.npz]
|
||||
H --> J[Video<br/>robot/.../visualization_mjwp.mp4]
|
||||
|
||||
style C fill:#e1f5ff
|
||||
style G fill:#fff4e1
|
||||
style I fill:#ffe1e1
|
||||
```
|
||||
|
||||
## Configuration Paths
|
||||
|
||||
Paths in `Config` are automatically resolved:
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class Config:
|
||||
dataset_dir: str = "example_datasets" # Base directory
|
||||
dataset_name: str = "oakink"
|
||||
robot_type: str = "allegro"
|
||||
embodiment_type: str = "bimanual"
|
||||
task: str = "pick_spoon_bowl"
|
||||
data_id: int = 0
|
||||
|
||||
# Auto-set by process_config():
|
||||
model_path: str = "" # Path to scene.xml
|
||||
data_path: str = "" # Path to trajectory_kinematic.npz
|
||||
output_dir: str = "" # Where to save results
|
||||
```
|
||||
|
||||
After `process_config()`:
|
||||
|
||||
```python
|
||||
config.model_path = "{dataset_dir}/processed/{dataset_name}/{embodiment_type}/{task}/{data_id}/scene.xml"
|
||||
config.data_path = "{...}/{robot_type}/{embodiment_type}/{task}/{data_id}/trajectory_kinematic.npz"
|
||||
config.output_dir = "{...}/{robot_type}/{embodiment_type}/{task}/{data_id}/"
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Organization
|
||||
|
||||
1. **Keep raw data separate**: Never modify `raw/` directory
|
||||
2. **Share assets**: Use `assets/` for common objects/robots
|
||||
3. **One trial per directory**: Each `{data_id}` is self-contained
|
||||
4. **Relative paths in JSON**: Use relative paths for portability
|
||||
|
||||
### Naming Conventions
|
||||
|
||||
- **Tasks**: Use descriptive names (e.g., `pick_cup`, `open_jar`)
|
||||
- **Objects**: Match names across datasets
|
||||
- **Robots**: Use official model names (e.g., `allegro`, `inspire`)
|
||||
|
||||
### Cleanup
|
||||
|
||||
Remove intermediate files after successful optimization:
|
||||
|
||||
```bash
|
||||
# Keep only final results
|
||||
rm trajectory_kinematic.npz
|
||||
rm scene.xml # If not needed for replay
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Path Not Found
|
||||
|
||||
Check that all path components match:
|
||||
|
||||
```bash
|
||||
# Verify structure
|
||||
ls example_datasets/processed/oakink/allegro/bimanual/pick_spoon_bowl/0/
|
||||
|
||||
# Check config values
|
||||
python -c "from spider.config import Config, process_config; \
|
||||
c = process_config(Config()); print(c.output_dir)"
|
||||
```
|
||||
|
||||
### Missing Assets
|
||||
|
||||
Ensure assets are in shared location:
|
||||
|
||||
```bash
|
||||
# Check object assets
|
||||
ls example_datasets/processed/oakink/assets/objects/
|
||||
|
||||
# Check robot assets
|
||||
ls example_datasets/processed/oakink/assets/robots/
|
||||
```
|
||||
|
||||
### Corrupted NPZ Files
|
||||
|
||||
Validate NPZ integrity:
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
|
||||
try:
|
||||
data = np.load('trajectory.npz')
|
||||
print("Keys:", list(data.keys()))
|
||||
print("Shapes:", {k: v.shape for k, v in data.items()})
|
||||
except Exception as e:
|
||||
print(f"Error loading: {e}")
|
||||
```
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
# Deployment to Real Robots
|
||||
|
||||
This guide covers deploying SPIDER-optimized trajectories to real-world robots, including coordinate system transformations and practical deployment considerations.
|
||||
|
||||
## Overview
|
||||
|
||||
SPIDER saves all trajectories in a **minimum coordinate system** defined in the corresponding scene XML file. While joint positions can be used directly, it's important to convert the robot base position and orientation to the world coordinate system for correct execution on real robots.
|
||||
|
||||
Please refer to `spider/postprocess/read_to_robot.py` for the conversion code. It is recommended to read from a site from the robot to get wrist orientation that align with your real world setup.
|
||||
|
||||

|
||||
+266
@@ -0,0 +1,266 @@
|
||||
# Parameter Tuning
|
||||
|
||||
This guide helps you tune SPIDER parameters for optimal performance on your tasks.
|
||||
|
||||
## Overview
|
||||
|
||||
Like reinforcement learning, different motion characteristics require different parameter settings. Start with defaults and iteratively refine based on results.
|
||||
|
||||
## Control Parameters
|
||||
|
||||
### Simulation Timestep (`sim_dt`)
|
||||
|
||||
**Default**: `0.01` (100 Hz)
|
||||
|
||||
The fundamental simulation timestep. Smaller values increase accuracy but slow down simulation. Start from a smaller one and gradually increase for faster simulation.
|
||||
|
||||
::: warning
|
||||
All other timing parameters must be divisible by `sim_dt`
|
||||
:::
|
||||
|
||||
### Control Interval (`ctrl_dt`)
|
||||
|
||||
**Default**: `0.4s` (2.5 Hz)
|
||||
|
||||
How frequently the controller updates. Affects:
|
||||
- Optimization speed (larger = fewer optimizations)
|
||||
- Responsiveness (smaller = more reactive)
|
||||
|
||||
**Tuning guidelines:**
|
||||
- **Agile motions**: `0.05-0.2s`
|
||||
- **Smooth motions**: `0.2-0.4s`
|
||||
|
||||
### Planning Horizon (`horizon`)
|
||||
|
||||
**Default**: `1.6s`
|
||||
|
||||
**Most important parameter**. How far ahead the optimizer looks.
|
||||
|
||||
**Impact:**
|
||||
- ✅ Larger horizon: Better global plan, handles complex motions
|
||||
- ❌ Larger horizon: Slower optimization, requires more samples
|
||||
- ✅ Smaller horizon: Faster optimization
|
||||
- ❌ Smaller horizon: Myopic behavior, may fail on complex tasks
|
||||
|
||||
**Tuning strategy:**
|
||||
1. Start large (2.0s) for complex/unknown tasks
|
||||
2. Gradually decrease until performance degrades
|
||||
3. Monitor planned trajectories in Rerun viewer
|
||||
|
||||
```bash
|
||||
# Complex manipulation
|
||||
uv run examples/run_mjwp.py horizon=2.0
|
||||
|
||||
# Simple tracking
|
||||
uv run examples/run_mjwp.py horizon=1.0
|
||||
```
|
||||
|
||||
::: tip Visual Debugging
|
||||
Use Rerun viewer to see the planned trajectory (blue/red traces). If the plan looks good but execution fails, the horizon might be too short.
|
||||
:::
|
||||
|
||||
### Knot Spacing (`knot_dt`)
|
||||
|
||||
**Default**: `0.4s`
|
||||
|
||||
Temporal resolution of control parameterization. Actions are interpolated between knot points.
|
||||
|
||||
**Purpose**: Reduces search space by smoothing actions.
|
||||
|
||||
**Guidelines:**
|
||||
- **Agile motions** (jumping, quick grasps): `0.1-0.2s`
|
||||
- **Smooth motions** (walking, pouring): `0.2-0.4s`
|
||||
|
||||
```bash
|
||||
# Fine control for agile task
|
||||
uv run examples/run_mjwp.py knot_dt=0.1
|
||||
|
||||
# Smooth interpolation
|
||||
uv run examples/run_mjwp.py knot_dt=0.3
|
||||
```
|
||||
|
||||
## Sampling Parameters
|
||||
|
||||
### Number of Samples (`num_samples`)
|
||||
|
||||
**Default**: `1024`
|
||||
|
||||
Number of parallel trajectories to evaluate.
|
||||
|
||||
**Impact:**
|
||||
- ✅ More samples: Better exploration, more robust
|
||||
- ❌ More samples: Higher memory usage, slower per-iteration
|
||||
- Scales linearly with GPU memory and compute
|
||||
|
||||
**Tuning:** try it out on your GPU and pick up the largest number that doesn't cause significant slow down.
|
||||
|
||||
### Temperature (`temperature`)
|
||||
|
||||
**Default**: `0.1`
|
||||
|
||||
Softmax temperature for sample weighting.
|
||||
|
||||
**Impact:**
|
||||
- **Lower** (0.01-0.05): Sharper distribution, more optimal but can be unstable
|
||||
- **Higher** (0.2-0.5): Smoother distribution, more stable but less optimal
|
||||
|
||||
**Tuning strategy:**
|
||||
1. Start at `0.1`
|
||||
2. If motion is shaky/unstable, increase to `0.15-0.2`
|
||||
3. If motion is stable, decrease to `0.05-0.08` for better quality
|
||||
|
||||
Generally, this parameter is less important.
|
||||
|
||||
```bash
|
||||
# Stable but less optimal
|
||||
uv run examples/run_mjwp.py temperature=0.2
|
||||
|
||||
# Optimal but may be shaky
|
||||
uv run examples/run_mjwp.py temperature=0.05
|
||||
```
|
||||
|
||||
::: tip Monitoring
|
||||
Check the `ctrl` panel in rerun viewer. If the action is shaky, increase the temperature.
|
||||
:::
|
||||
|
||||
### Max Iterations (`max_num_iterations`)
|
||||
|
||||
**Default**: `32`
|
||||
|
||||
Maximum optimization iterations per control step.
|
||||
|
||||
**Tuning:**
|
||||
1. Run with default and monitor `improvement` in Rerun
|
||||
2. If `improvement` plateaus early (< 10 iters), decrease
|
||||
3. If `improvement` is still high at end, increase
|
||||
|
||||
```bash
|
||||
# Quick convergence
|
||||
uv run examples/run_mjwp.py max_num_iterations=8
|
||||
|
||||
# Thorough optimization
|
||||
uv run examples/run_mjwp.py max_num_iterations=64
|
||||
```
|
||||
|
||||
### Early Stopping (`improvement_threshold`)
|
||||
|
||||
**Default**: `0.01`
|
||||
|
||||
Stop optimization if improvement falls below threshold.
|
||||
|
||||
**Usage:**
|
||||
- Start at `0` (disabled) to see full convergence
|
||||
- Gradually increase for speed: `0.01` → `0.02` → `0.05`
|
||||
|
||||
```bash
|
||||
# No early stopping
|
||||
uv run examples/run_mjwp.py improvement_threshold=0.0
|
||||
|
||||
# Aggressive early stopping
|
||||
uv run examples/run_mjwp.py improvement_threshold=0.05
|
||||
```
|
||||
|
||||
## Noise Scheduling
|
||||
|
||||
### Control Noise Scales
|
||||
|
||||
These control exploration throughout the horizon:
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `first_ctrl_noise_scale` | `0.5` | Noise at start of horizon |
|
||||
| `last_ctrl_noise_scale` | `1.0` | Noise at end of horizon |
|
||||
| `final_noise_scale` | `0.1` | Global annealing factor |
|
||||
|
||||
**Tuning:**
|
||||
- Motion is stable? Decrease `first_ctrl_noise_scale` to `0.01-0.1`
|
||||
- Need more exploration? Increase `last_ctrl_noise_scale` to `0.1-1.0`
|
||||
- High precision task? Decrease `final_noise_scale` to `0.05`
|
||||
|
||||
### Component-Specific Scales
|
||||
|
||||
For dexterous hands, noise is applied differently to each component:
|
||||
|
||||
| Parameter | Default | Purpose |
|
||||
|-----------|---------|---------|
|
||||
| `joint_noise_scale` | `0.3` | Robot joint angles |
|
||||
| `pos_noise_scale` | `0.01` | Hand base position |
|
||||
| `rot_noise_scale` | `0.03` | Hand base rotation |
|
||||
|
||||
**Tuning guidelines:**
|
||||
- Base is stable? Decrease `pos_noise_scale` and `rot_noise_scale`
|
||||
- Finger control needs more exploration? Increase `joint_noise_scale`
|
||||
|
||||
```bash
|
||||
# Stable base, explore fingers
|
||||
uv run examples/run_mjwp.py \
|
||||
pos_noise_scale=0.005 \
|
||||
rot_noise_scale=0.01 \
|
||||
joint_noise_scale=0.5
|
||||
```
|
||||
|
||||
## Reward Scaling
|
||||
|
||||
Balance different tracking objectives:
|
||||
|
||||
### Position vs Rotation
|
||||
|
||||
```yaml
|
||||
pos_rew_scale: 1.0 # End-effector position
|
||||
rot_rew_scale: 0.3 # End-effector rotation
|
||||
```
|
||||
|
||||
**Tuning:**
|
||||
- Task requires precise orientation (e.g., key insertion)? Increase `rot_rew_scale`
|
||||
- Position more important? Keep `rot_rew_scale` low
|
||||
|
||||
### Joint Tracking
|
||||
|
||||
```yaml
|
||||
joint_rew_scale: 0.003
|
||||
```
|
||||
|
||||
Lower weight since joint tracking is less critical than end-effector pose.
|
||||
|
||||
**Tuning:**
|
||||
- Specific joint configuration needed? Increase to `0.01-0.03`
|
||||
- Only care about end-effector? Keep very low (`0.001-0.003`)
|
||||
|
||||
### Velocity Regularization
|
||||
|
||||
```yaml
|
||||
vel_rew_scale: 0.0001
|
||||
```
|
||||
|
||||
Penalizes large velocities to smooth motion.
|
||||
|
||||
**Best practices:**
|
||||
- ✅ Adding velocity tracking helps reduce latency
|
||||
- ❌ Don't make it too large (causes sluggish motion)
|
||||
|
||||
```bash
|
||||
# Reduce tracking latency
|
||||
uv run examples/run_mjwp.py vel_rew_scale=0.001
|
||||
|
||||
# Disable velocity penalty
|
||||
uv run examples/run_mjwp.py vel_rew_scale=0.0
|
||||
```
|
||||
|
||||
## Common Issues
|
||||
|
||||
### Motion is Unstable/Shaky
|
||||
|
||||
**Symptoms**: Robot vibrates, erratic movements, or fails to complete the task
|
||||
|
||||
**Solutions:**
|
||||
1. Iecrease `num_samples` (most effective)
|
||||
2. Check if `horizon` is too short
|
||||
3. Increase `knot_dt` for smoother actions or decrease it for more reactive motion
|
||||
|
||||
### Optimization Too Slow
|
||||
|
||||
**Symptoms**: RTR (realtime rate) < 0.1
|
||||
|
||||
**Solutions:**
|
||||
1. Reduce `horizon` (most effective)
|
||||
2. Increase `ctrl_dt` (also effective, make sure it doesn't cause instability)
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
# Viewers
|
||||
|
||||
SPIDER supports multiple viewer backends for visualization during retargeting. This guide covers setting up and using different viewers, including remote development workflows.
|
||||
|
||||
## Available Viewers
|
||||
|
||||
SPIDER supports the following viewer configurations:
|
||||
|
||||
| Viewer | Description | Use Case |
|
||||
|--------|-------------|----------|
|
||||
| `mujoco` | Native MuJoCo viewer | Fast local visualization |
|
||||
| `rerun` | Rerun.io viewer | Remote development, rich logging |
|
||||
| `viser` | Viser web viewer | Lightweight remote visualization |
|
||||
|
||||
To enable both, try `mujoco-rerun` or `mujoco-viser` viewer.
|
||||
|
||||
## Viser Viewer
|
||||
|
||||
[Viser](https://github.com/nerfstudio-project/viser) provides a lightweight web-based viewer for 3D scenes.
|
||||
|
||||
### Local Usage
|
||||
|
||||
```bash
|
||||
uv run examples/run_mjwp.py viewer=viser
|
||||
```
|
||||
|
||||
This will:
|
||||
1. Start a Viser server
|
||||
2. Log simulation data in real-time
|
||||
3. Print a URL to open in your browser
|
||||
|
||||
::: warning
|
||||
If you run headless (no X display), you may need to set a display before launching:
|
||||
|
||||
```bash
|
||||
export DISPLAY=:1
|
||||
# or
|
||||
export MUJOCO_GL=egl
|
||||
```
|
||||
:::
|
||||
|
||||
::: info
|
||||
If you see an import error, install the dependency:
|
||||
|
||||
```bash
|
||||
pip install viser
|
||||
```
|
||||
:::
|
||||
|
||||
## Rerun Viewer
|
||||
|
||||
[Rerun](https://rerun.io/) provides a powerful logging and visualization system with time-travel capabilities, perfect for remote development.
|
||||
|
||||
### Local Usage
|
||||
|
||||
```bash
|
||||
uv run examples/run_mjwp.py viewer=rerun
|
||||
```
|
||||
|
||||
This will:
|
||||
1. Automatically spawn a Rerun viewer
|
||||
2. Log simulation data in real-time
|
||||
3. Display 3D visualization and metrics
|
||||
|
||||
### Remote Development
|
||||
|
||||
For headless servers, use Rerun's web viewer:
|
||||
|
||||
#### Step 1: Start Rerun Server
|
||||
|
||||
On your remote server:
|
||||
|
||||
```bash
|
||||
# Start Rerun web server
|
||||
uv run rerun --serve-web --port 9876
|
||||
|
||||
# Or use rerun datapoints for more features
|
||||
uv run rerun datapoints --serve-web --port 9876
|
||||
```
|
||||
|
||||
#### Step 2: Run SPIDER
|
||||
|
||||
In another terminal on the remote server:
|
||||
|
||||
```bash
|
||||
uv run examples/run_mjwp.py viewer=rerun
|
||||
```
|
||||
|
||||
#### Step 3: Connect from Local Machine
|
||||
|
||||
Open your local browser to:
|
||||
|
||||
```
|
||||
http://your-server:9876
|
||||
```
|
||||
|
||||
Or connect via the Rerun client:
|
||||
|
||||
```bash
|
||||
# On local machine
|
||||
rerun --connect rerun+http://your-server:9876/proxy
|
||||
```
|
||||
|
||||
::: warning
|
||||
Make sure port 9876 is accessible through your firewall. You may need to configure SSH port forwarding:
|
||||
|
||||
```bash
|
||||
ssh -L 9876:localhost:9876 user@remote-server
|
||||
```
|
||||
:::
|
||||
|
||||
### Logged Data
|
||||
|
||||
SPIDER logs the following data to Rerun:
|
||||
|
||||
- 3D scene visualization (robot and objects)
|
||||
- Joint positions and velocities
|
||||
- Optimization metrics (improvement, reward)
|
||||
- Contact forces and positions
|
||||
- Trace trajectories
|
||||
@@ -0,0 +1,175 @@
|
||||
# Workflow: DexMachina (Genesis)
|
||||
|
||||
The DexMachina workflow integrates SPIDER with [Genesis](https://genesis.github.io/) simulator and [DexMachina](https://github.com/MandiZhao/dexmachina) framework for dexterous manipulation with downstream RL training.
|
||||
|
||||
## Quick Start (Reproducible Setup)
|
||||
|
||||
### 1. Download Data
|
||||
|
||||
All required data is hosted on HuggingFace. Download it into the spider directory:
|
||||
|
||||
```bash
|
||||
sudo apt install git-lfs
|
||||
git lfs install
|
||||
cd /path/to/spider
|
||||
git clone https://huggingface.co/datasets/retarget/retarget_example example_datasets
|
||||
```
|
||||
|
||||
### 2. Install DexMachina Environment
|
||||
|
||||
```bash
|
||||
# Create conda environment
|
||||
conda create -n dexmachina python=3.10
|
||||
conda activate dexmachina
|
||||
|
||||
# Install PyTorch
|
||||
pip install torch==2.5.1
|
||||
|
||||
# Clone and install the Genesis fork (use the 'older' branch for API compatibility)
|
||||
git clone https://github.com/MandiZhao/Genesis.git
|
||||
cd Genesis
|
||||
git checkout older
|
||||
pip install -e .
|
||||
pip install libigl==2.5.1 # Required: fixes igl.signed_distance API mismatch
|
||||
cd ..
|
||||
|
||||
# Clone and install rl_games fork
|
||||
git clone https://github.com/MandiZhao/rl_games.git
|
||||
cd rl_games
|
||||
pip install -e .
|
||||
cd ..
|
||||
|
||||
# Clone and install dexmachina
|
||||
git clone https://github.com/MandiZhao/dexmachina.git
|
||||
cd dexmachina
|
||||
pip install -e .
|
||||
cd ..
|
||||
|
||||
# Install additional packages for video export and RL training
|
||||
pip install moviepy==1.0.3 gymnasium ray seaborn
|
||||
```
|
||||
|
||||
### 3. Install SPIDER (Minimal)
|
||||
|
||||
Install SPIDER without MuJoCo Warp (only need optimization components):
|
||||
|
||||
```bash
|
||||
cd /path/to/spider
|
||||
conda activate dexmachina
|
||||
|
||||
# Install SPIDER without dependencies (DexMachina has its own)
|
||||
pip install --ignore-requires-python --no-deps -e .
|
||||
# Install other dependencies
|
||||
pip install loguru tyro hydra-core rerun-sdk==0.26.2
|
||||
```
|
||||
|
||||
### 4. Copy Pre-Generated Data to DexMachina Assets
|
||||
|
||||
Pre-generated inspire_hand data (7 clips) is stored in the HuggingFace dataset so you don't need to re-run the retargeting pipeline.
|
||||
|
||||
```
|
||||
example_datasets/raw/dexmachina/
|
||||
contact_retarget/inspire_hand/s01/ # contact mapping (.npy) + videos (.mp4)
|
||||
retargeted/inspire_hand/s01/ # retargeted kinematics (.pt)
|
||||
retargeter_results/inspire_hand/s01/ # retargeter results (.npy)
|
||||
```
|
||||
|
||||
Clips: `box_use_01`, `ketchup_use_01`, `ketchup_use_02`, `laptop_use_01`, `mixer_use_01`, `notebook_use_01`, `waffleiron_use_01`
|
||||
|
||||
After installing DexMachina, copy the data into its assets directory:
|
||||
|
||||
```bash
|
||||
DEXMACHINA_ASSETS=$(python -c "from dexmachina.asset_utils import get_asset_path; print(get_asset_path(''))")
|
||||
SPIDER_DATA=/path/to/spider/example_datasets/raw/dexmachina
|
||||
|
||||
cp -r $SPIDER_DATA/retargeted/inspire_hand/ $DEXMACHINA_ASSETS/retargeted/inspire_hand/
|
||||
cp -r $SPIDER_DATA/contact_retarget/inspire_hand/ $DEXMACHINA_ASSETS/contact_retarget/inspire_hand/
|
||||
cp -r $SPIDER_DATA/retargeter_results/inspire_hand/ $DEXMACHINA_ASSETS/retargeter_results/inspire_hand/
|
||||
```
|
||||
|
||||
If the data is missing at runtime, the error message will print the exact copy commands for your paths.
|
||||
|
||||
### 5. Run SPIDER
|
||||
|
||||
```bash
|
||||
conda activate dexmachina
|
||||
cd /path/to/spider
|
||||
|
||||
# Run with default config (inspire hand, box-30-230 task)
|
||||
python examples/run_dexmachina.py
|
||||
```
|
||||
|
||||
This will:
|
||||
1. Initialize Genesis environment with DexMachina task
|
||||
2. Load reference motion from task
|
||||
3. Optimize trajectory with Sampling
|
||||
4. Save optimized trajectory and video
|
||||
|
||||
Output is saved to `example_datasets/processed/arctic/inspire_hand/bimanual/{task}/{data_id}/`:
|
||||
- `trajectory_dexmachina.npz` --- trajectory data
|
||||
- `trajectory_dexmachina.mp4` --- video
|
||||
|
||||
## Evaluate Trajectories
|
||||
|
||||
After running `run_dexmachina.py`, evaluate object tracking metrics (position, rotation, articulation distances) with:
|
||||
|
||||
```bash
|
||||
conda activate dexmachina
|
||||
cd /path/to/spider
|
||||
|
||||
# Evaluate all tasks under the default data directory
|
||||
python spider/postprocess/evaluate_dexmachina.py
|
||||
|
||||
# Evaluate specific tasks
|
||||
python spider/postprocess/evaluate_dexmachina.py --tasks box-30-230 laptop-30-230
|
||||
|
||||
# Use a different dataset/robot configuration
|
||||
python spider/postprocess/evaluate_dexmachina.py --dataset_name arctic --robot_type inspire_hand --embodiment_type bimanual
|
||||
```
|
||||
|
||||
The script uses the same dataset path resolution as `config.py` (`dataset_dir/processed/{dataset_name}/{robot_type}/{embodiment_type}/{task}/{data_id}/`). You can also pass `--data_dir` to override with an explicit path.
|
||||
|
||||
## Compare SPIDER vs RL (Multi-Seed)
|
||||
|
||||
To compare SPIDER (MPC) against RL rollouts across multiple seeds, use `--compare` mode. This loads both `trajectory_dexmachina.npz` (SPIDER) and `rollout_rl.npz` (RL) from each `{task}/{seed}/` directory and prints mean +/- std tables.
|
||||
|
||||
```bash
|
||||
# Compare across seeds 0-4 (default), print Markdown tables
|
||||
python spider/postprocess/evaluate_dexmachina.py --compare
|
||||
|
||||
# Compare with LaTeX tables and per-seed detail
|
||||
python spider/postprocess/evaluate_dexmachina.py --compare --latex --detail
|
||||
|
||||
# Compare specific tasks / seeds
|
||||
python spider/postprocess/evaluate_dexmachina.py --compare --tasks box-30-230 laptop-30-230 --seeds 0 1 2
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Key parameters in `examples/config/dexmachina.yaml`:
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `task` | `box-30-230` | Object task (format: `object_name-start_frame-end_frame`) |
|
||||
| `robot_type` | `inspire_hand` | Dexterous hand model |
|
||||
| `embodiment_type` | `bimanual` | Hand configuration |
|
||||
| `num_samples` | `1024` | Parallel CEM samples (Genesis envs) |
|
||||
| `max_num_iterations` | `32` | CEM iterations per MPC step |
|
||||
| `horizon` | `0.40` | Planning horizon (seconds) |
|
||||
| `ctrl_dt` | `0.20` | Control timestep |
|
||||
|
||||
## Common Issues
|
||||
|
||||
1. **Missing DexMachina data**: Copy pre-generated data from `example_datasets/raw/dexmachina/` into the DexMachina assets directory (see "Copy Pre-Generated Data" section above).
|
||||
|
||||
2. **Genesis branch compatibility**: You must use the `older` branch of the Genesis fork (`git checkout older`). The `main` and `0122` branches have upstream merges that break API compatibility with DexMachina (e.g., `set_dofs_kp` input shape broadcasting, `inertial_quat` None handling).
|
||||
|
||||
3. **`igl.signed_distance` unpacking error** (`ValueError: too many values to unpack`): Install `libigl==2.5.1` explicitly. Newer versions of libigl change the return signature.
|
||||
|
||||
4. **`moviepy.editor` not found**: Install `moviepy==1.0.3` (not the newer 2.x which removed `moviepy.editor`). This is needed for video export.
|
||||
|
||||
5. **torch weights loading error**: If failed to load trajectory from dexmachina, ensure the data is loaded with `torch.load(data_fname, weights_only=False)`.
|
||||
|
||||
6. **numpy version**: Use `numpy==1.26.4` to avoid compatibility issues with Genesis and taichi.
|
||||
|
||||
7. **First run is slow**: The first run compiles taichi kernels (JIT) which can appear to hang for several minutes with no output. Subsequent runs use cached kernels and are faster.
|
||||
@@ -0,0 +1,46 @@
|
||||
# Workflow: HDMI (Humanoid-Object Interaction)
|
||||
|
||||
The HDMI workflow integrates SPIDER with [HDMI (Humanoid Manipulation)](https://github.com/lecar-lab/hdmi) framework for humanoid robot manipulation with downstream sim2real RL training.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Install HDMI Environment
|
||||
|
||||
Follow the [official HDMI installation guide](https://github.com/lecar-lab/hdmi):
|
||||
|
||||
```bash
|
||||
# Clone HDMI repository
|
||||
git clone https://github.com/lecar-lab/hdmi.git
|
||||
cd hdmi
|
||||
|
||||
# Install with uv (recommended)
|
||||
uv sync
|
||||
|
||||
# Install SPIDER into HDMI environment
|
||||
uv pip install --no-deps -e /path/to/spider
|
||||
```
|
||||
|
||||
## Running HDMI Workflow
|
||||
|
||||
### Basic Example
|
||||
|
||||
```bash
|
||||
cd /path/to/spider
|
||||
|
||||
# Run with default config (G1 humanoid, suitcase task)
|
||||
python examples/run_hdmi.py
|
||||
# OR refer to
|
||||
./examples/run_hdmi.sh
|
||||
```
|
||||
|
||||
### Configuration Options
|
||||
|
||||
You can enable `mjlab` native viewer by setting `viewer` to `hdmi`.
|
||||
|
||||
## Train RL
|
||||
|
||||
Write the motion as one HDMI reference motion by running the following command:
|
||||
|
||||
```bash
|
||||
python examples/postprocess/read_to_hdmi.py
|
||||
```
|
||||
@@ -0,0 +1,227 @@
|
||||
# Workflow: ManipTrans (IsaacGym)
|
||||
|
||||
SPIDER MPC for dexterous hand-object manipulation using [IsaacGym](https://developer.nvidia.com/isaac-gym) and [HO-Tracker-Baseline](https://github.com/KailinLi/HO-Tracker-Baseline) (ManipTrans).
|
||||
|
||||
## Quick Start (Reproducible Setup)
|
||||
|
||||
### 1. Download Data
|
||||
|
||||
All required data is hosted on HuggingFace. Download it into the spider directory:
|
||||
|
||||
```bash
|
||||
sudo apt install git-lfs
|
||||
git lfs install
|
||||
cd /path/to/spider
|
||||
git clone https://huggingface.co/datasets/retarget/retarget_example example_datasets
|
||||
```
|
||||
|
||||
This downloads `example_datasets/` containing:
|
||||
- `raw/maniptrans/HO-Tracker/` --- 16 trajectory demos (8 left-hand, 8 right-hand)
|
||||
- `raw/maniptrans/assets/` --- pre-trained base imitator checkpoints
|
||||
- `raw/maniptrans/rl_runs/` --- 16 trained RL baseline checkpoints
|
||||
- `raw/maniptrans/retargeting/` --- optional retargeting initialization
|
||||
- `processed/maniptrans/` --- pre-computed rollouts, videos, and metrics (160 runs)
|
||||
|
||||
### 2. Create Data Symlink
|
||||
|
||||
ManipTrans uses relative paths (`data/HO-Tracker/...`). Create a symlink:
|
||||
|
||||
```bash
|
||||
cd /path/to/spider
|
||||
ln -sf example_datasets/raw/maniptrans data
|
||||
```
|
||||
|
||||
### 3. Install Dependencies
|
||||
|
||||
Requires Python 3.8 + PyTorch 1.13.1 + IsaacGym (older than SPIDER's default Python 3.12+):
|
||||
|
||||
```bash
|
||||
# Create conda environment
|
||||
conda create -n maniptrans python=3.8
|
||||
conda activate maniptrans
|
||||
|
||||
# Install PyTorch 1.13.1 with CUDA 11.7
|
||||
pip install torch==1.13.1+cu117 torchvision==0.14.1+cu117 --extra-index-url https://download.pytorch.org/whl/cu117
|
||||
|
||||
# Install IsaacGym (requires NVIDIA GPU)
|
||||
cd /path/to/isaacgym/python && pip install -e .
|
||||
|
||||
# Install pytorch3d (prebuilt wheel for py38 + cu117 + pytorch 1.13.1)
|
||||
pip install pytorch3d==0.7.3 -f https://dl.fbaipublicfiles.com/pytorch3d/packaging/wheels/py38_cu117_pyt1131/download.html
|
||||
|
||||
# Install additional dependencies
|
||||
pip install git+https://github.com/otaheri/chamfer_distance.git
|
||||
pip install git+https://github.com/otaheri/bps_torch.git
|
||||
pip install git+https://github.com/lixiny/manotorch.git
|
||||
pip install numpy==1.23.5 gym==0.23.1 opencv-python-headless scikit-learn smplx trimesh
|
||||
|
||||
# Clone and install HO-Tracker-Baseline
|
||||
cd /path/to
|
||||
git clone https://github.com/KailinLi/HO-Tracker-Baseline.git
|
||||
cd HO-Tracker-Baseline
|
||||
touch requirements.txt # Create empty file (prevents pip install error)
|
||||
pip install -e .
|
||||
|
||||
# Install SPIDER (minimal, no-deps to avoid conflicts)
|
||||
cd /path/to/spider
|
||||
pip install --ignore-requires-python --no-deps -e .
|
||||
pip install loguru mujoco hydra-core omegaconf imageio[ffmpeg]
|
||||
```
|
||||
|
||||
### 4. Set Up HO-Tracker-Baseline Data
|
||||
|
||||
HO-Tracker-Baseline also needs access to the trajectory data and imitator checkpoints. Point its data paths to spider's `example_datasets/`:
|
||||
|
||||
```bash
|
||||
# Link HO-Tracker data
|
||||
cd /path/to/HO-Tracker-Baseline
|
||||
rm -f data/HO-Tracker
|
||||
ln -sf /path/to/spider/example_datasets/raw/maniptrans/HO-Tracker data/HO-Tracker
|
||||
|
||||
# Link retargeting data
|
||||
rm -rf data/retargeting/HO-Tracker
|
||||
ln -sf /path/to/spider/example_datasets/raw/maniptrans/retargeting/HO-Tracker data/retargeting/HO-Tracker
|
||||
|
||||
# Copy imitator checkpoints
|
||||
cp /path/to/spider/example_datasets/raw/maniptrans/assets/imitator_*.pth assets/
|
||||
```
|
||||
|
||||
### 5. Patch HO-Tracker-Baseline for Compatibility
|
||||
|
||||
The `dexhandimitator` module may fail to import in some environments. Patch `maniptrans_envs/lib/envs/tasks/__init__.py` to make it optional:
|
||||
|
||||
```python
|
||||
# Replace:
|
||||
from .dexhandimitator import DexHandImitatorRHEnv, DexHandImitatorLHEnv
|
||||
|
||||
# With:
|
||||
try:
|
||||
from .dexhandimitator import DexHandImitatorRHEnv, DexHandImitatorLHEnv
|
||||
except ImportError:
|
||||
DexHandImitatorRHEnv = None
|
||||
DexHandImitatorLHEnv = None
|
||||
```
|
||||
|
||||
### 6. Run SPIDER
|
||||
|
||||
```bash
|
||||
conda activate maniptrans
|
||||
cd /path/to/spider
|
||||
export LD_LIBRARY_PATH="/path/to/miniconda3/envs/maniptrans/lib:${LD_LIBRARY_PATH:-}"
|
||||
|
||||
# Default: 0f900@0, inspire hand, left hand
|
||||
python examples/run_maniptrans.py
|
||||
|
||||
# Different trajectory:
|
||||
python examples/run_maniptrans.py task=81a95@5
|
||||
|
||||
# Right hand:
|
||||
python examples/run_maniptrans.py task=07bb1@1 embodiment_type=right
|
||||
|
||||
# Fewer iterations (faster):
|
||||
python examples/run_maniptrans.py max_num_iterations=16
|
||||
```
|
||||
|
||||
Output is saved to `example_datasets/processed/maniptrans/inspire/{side}/{task}/{data_id}/`:
|
||||
- `rollout_isaac.npz` --- trajectory data
|
||||
- `rollout_isaac.mp4` --- video (when `save_video=true`)
|
||||
- `metrics_isaac.json` --- evaluation metrics
|
||||
|
||||
## Available Trajectories
|
||||
|
||||
16 trajectories from HO-Tracker dataset (8 per hand):
|
||||
|
||||
| Side | Task IDs |
|
||||
|------|----------|
|
||||
| Left | `0f900@0`, `81a95@5`, `0f4a7@1`, `70ca2@0`, `39e5e@5`, `380c7@0`, `2ddc8@2`, `0b3a0@6` |
|
||||
| Right | `07bb1@1`, `235ac@0`, `07301@0`, `49793@0`, `01857@10`, `031b7@0`, `03ac9@0`, `155cb@0` |
|
||||
|
||||
## Configuration
|
||||
|
||||
Key parameters in `examples/config/maniptrans.yaml`:
|
||||
|
||||
| Parameter | Default | Description |
|
||||
|-----------|---------|-------------|
|
||||
| `task` | `0f900@0` | HO-Tracker data sequence |
|
||||
| `embodiment_type` | `left` | `left` or `right` |
|
||||
| `num_samples` | `1024` | Parallel CEM samples (IsaacGym envs) |
|
||||
| `max_num_iterations` | `32` | CEM iterations per MPC step |
|
||||
| `horizon` | `0.6` | Planning horizon (seconds) |
|
||||
| `ctrl_dt` | `0.2` | Control timestep |
|
||||
| `seed` | `0` | Random seed |
|
||||
| `data_id` | `0` | Output subdirectory index |
|
||||
|
||||
## RL Baseline Evaluation
|
||||
|
||||
Trained RL checkpoints are included for all 16 trajectories. To evaluate:
|
||||
|
||||
```bash
|
||||
cd /path/to/HO-Tracker-Baseline
|
||||
|
||||
# Example: evaluate left-hand trajectory
|
||||
python main/rl/train.py \
|
||||
task=ResDexHand dexhand=inspire side=lh \
|
||||
headless=true num_envs=256 test=true \
|
||||
+forceFullLength=true seed=0 \
|
||||
rolloutStateInit=false randomStateInit=false \
|
||||
"dataIndices=[0f900@0]" \
|
||||
checkpoint=/path/to/spider/example_datasets/raw/maniptrans/rl_runs/baseline_0f900@0_inspire_lh/nn/baseline_0f900@0.pth \
|
||||
actionsMovingAverage=0.4 \
|
||||
rh_base_model_checkpoint=assets/imitator_rh_inspire.pth \
|
||||
lh_base_model_checkpoint=assets/imitator_lh_inspire.pth
|
||||
```
|
||||
|
||||
Side tags: `lh` for left-hand trajectories, `rh` for right-hand trajectories.
|
||||
|
||||
## Evaluation Metrics
|
||||
|
||||
Four metrics computed against ground-truth demo data:
|
||||
|
||||
| Metric | Description |
|
||||
|--------|-------------|
|
||||
| `e_t` | Object translation error (cm) |
|
||||
| `e_r` | Object rotation error (degrees, geodesic) |
|
||||
| `e_j` | Joint position error (cm) |
|
||||
| `e_ft` | Fingertip position error (cm) |
|
||||
|
||||
Run evaluation across all trajectories:
|
||||
|
||||
```bash
|
||||
# Single-seed evaluation (data_id=0 only)
|
||||
python spider/postprocess/evaluate_maniptrans.py
|
||||
|
||||
# Multi-seed evaluation (all data_ids, mean +/- std)
|
||||
python spider/postprocess/evaluate_maniptrans.py --multiseed
|
||||
```
|
||||
|
||||
## Common Issues
|
||||
|
||||
1. **DexHandFactory registration failure** (`KeyError: 'inspire_rh'`): This is a circular import issue. SPIDER includes a fix in `spider/simulators/maniptrans.py` that lazily triggers hand auto-registration. Ensure you are using the latest SPIDER code.
|
||||
|
||||
2. **`dexhandimitator` import error**: Apply the patch in step 5 above to make this import optional.
|
||||
|
||||
3. **pytorch3d installation**: Use the prebuilt wheel for your PyTorch/CUDA combination. Building from source requires matching CUDA toolkit version (not just driver) and compatible GCC. The command in step 3 uses prebuilt wheels for py38 + cu117 + pytorch 1.13.1.
|
||||
|
||||
4. **`np.float` deprecation** (`AttributeError: module 'numpy' has no attribute 'float'`): Install `numpy==1.23.5` which still supports the deprecated aliases.
|
||||
|
||||
5. **Missing `requirements.txt` in HO-Tracker-Baseline**: Run `touch requirements.txt` in the HO-Tracker-Baseline root before `pip install -e .`.
|
||||
|
||||
6. **`imageio[ffmpeg]` required for video**: Install with `pip install imageio[ffmpeg]` for video recording support.
|
||||
|
||||
7. **`LD_LIBRARY_PATH` must include conda env lib**: Without this, IsaacGym may fail to find shared libraries. Set `export LD_LIBRARY_PATH="/path/to/miniconda3/envs/maniptrans/lib:${LD_LIBRARY_PATH:-}"`.
|
||||
|
||||
## Important Notes
|
||||
|
||||
### Python 3.8 Compatibility
|
||||
|
||||
ManipTrans requires Python 3.8 + PyTorch 1.13.1 + IsaacGym. SPIDER handles this via:
|
||||
- `from __future__ import annotations` in `spider/config.py` (for `tuple[float, float]` syntax)
|
||||
- `hasattr(torch, "compile")` guards in `spider/optimizers/sampling.py`
|
||||
|
||||
### Action Space
|
||||
|
||||
SPIDER optimizes 18-dim residual actions (6 wrist force/torque + 12 DOF positions). The base imitator provides nominal tracking actions. These combine in the env's `pre_physics_step` to produce 36-dim actions for the full base+residual architecture.
|
||||
|
||||
### ManipTrans Config Fields
|
||||
|
||||
ManipTrans-specific fields (e.g., `maniptrans_episode_length`) are **not** part of the SPIDER `Config` dataclass. In `examples/run_maniptrans.py`, they are extracted from the Hydra config and attached as attributes after `Config` construction.
|
||||
+317
@@ -0,0 +1,317 @@
|
||||
# Workflow: MuJoCo Warp (MJWP)
|
||||
|
||||
The MuJoCo Warp (MJWP) workflow is SPIDER's default and most versatile pipeline, supporting both dexterous hand and humanoid robot retargeting with high-performance physics simulation.
|
||||
|
||||
## Overview
|
||||
|
||||
The MJWP workflow uses MuJoCo with Warp backend for GPU-accelerated physics simulation. It provides the complete pipeline from raw human motion data to physics-based optimized robot trajectories.
|
||||
|
||||
**Supported Embodiments:**
|
||||
- Dexterous hands (Allegro, Inspire, Shadow, Xhand, etc.)
|
||||
- Humanoid robots (G1, H1, T1, etc.)
|
||||
- Bimanual configurations
|
||||
|
||||
|
||||
## Workflow Steps
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A[Raw Data] --> B[Process Dataset]
|
||||
B --> C[Decompose Mesh]
|
||||
C --> D[Detect Contact]
|
||||
D --> E[Generate Scene]
|
||||
E --> F[IK Retargeting]
|
||||
F --> G[Physics Optimization]
|
||||
G --> H[Output Trajectory]
|
||||
```
|
||||
|
||||
### Step 1: Setup Environment Variables
|
||||
|
||||
Define task parameters:
|
||||
|
||||
```bash
|
||||
export TASK=pick_spoon_bowl
|
||||
export HAND_TYPE=bimanual
|
||||
export DATA_ID=0
|
||||
export ROBOT_TYPE=allegro
|
||||
export DATASET_NAME=oakink
|
||||
```
|
||||
|
||||
### Step 2: Process Dataset
|
||||
|
||||
Convert raw human motion data to standardized format:
|
||||
|
||||
```bash
|
||||
uv run spider/process_datasets/oakink.py \
|
||||
--task=${TASK} \
|
||||
--embodiment-type=${HAND_TYPE} \
|
||||
--data-id=${DATA_ID}
|
||||
```
|
||||
|
||||
**What it does:**
|
||||
- Reads raw motion capture data (MANO poses, object poses)
|
||||
- Extracts hand kinematics (joint positions, wrist poses)
|
||||
- Saves processed data in standardized format
|
||||
|
||||
**Output:**
|
||||
```
|
||||
example_datasets/processed/oakink/mano/bimanual/pick_spoon_bowl/0/
|
||||
├── trajectory_keypoint.npz
|
||||
└── info.json
|
||||
```
|
||||
|
||||
::: tip Dataset-Specific Processors
|
||||
Replace `oakink.py` with the appropriate processor for your dataset:
|
||||
- `gigahand.py` - GigaHand dataset
|
||||
- `hot3d.py` - Hot3D dataset
|
||||
- `fair_fre.py` - FAIR FRE dataset
|
||||
:::
|
||||
|
||||
### Step 3: Decompose Object Mesh
|
||||
|
||||
Create convex decomposition for efficient collision detection:
|
||||
|
||||
```bash
|
||||
uv run spider/preprocess/decompose_fast.py \
|
||||
--task=${TASK} \
|
||||
--dataset-name=${DATASET_NAME} \
|
||||
--data-id=${DATA_ID} \
|
||||
--embodiment-type=${HAND_TYPE}
|
||||
```
|
||||
|
||||
If you want higher quality convex decomposition, you can use the following command:
|
||||
```bash
|
||||
uv run spider/preprocess/decompose.py \
|
||||
--task=${TASK} \
|
||||
--dataset-name=${DATASET_NAME} \
|
||||
--data-id=${DATA_ID} \
|
||||
--embodiment-type=${HAND_TYPE}
|
||||
```
|
||||
|
||||
**What it does:**
|
||||
- Loads object mesh from dataset
|
||||
- Performs convex decomposition using V-HACD or CoACD
|
||||
- Saves decomposed mesh components
|
||||
|
||||
**Output:**
|
||||
```
|
||||
example_datasets/processed/oakink/assets/objects/spoon/convex/
|
||||
├── 0.obj
|
||||
├── 1.obj
|
||||
├── 2.obj
|
||||
└── visual.obj
|
||||
```
|
||||
|
||||
::: warning
|
||||
Convex decomposition quality significantly affects simulation accuracy. Complex objects may need manual tuning of decomposition parameters.
|
||||
:::
|
||||
|
||||
### Step 4: Detect Contact (Optional)
|
||||
|
||||
Identify hand-object contact points for contact-aware retargeting:
|
||||
|
||||
```bash
|
||||
uv run spider/preprocess/detect_contact.py \
|
||||
--task=${TASK} \
|
||||
--dataset-name=${DATASET_NAME} \
|
||||
--data-id=${DATA_ID} \
|
||||
--embodiment-type=${HAND_TYPE}
|
||||
```
|
||||
|
||||
**What it does:**
|
||||
- Analyzes hand-object proximity throughout trajectory
|
||||
- Identifies contact points on hand surface
|
||||
- Saves contact information for trajectory optimization
|
||||
|
||||
**Output:**
|
||||
- Updates `trajectory_keypoint.npz` with contact data
|
||||
|
||||
::: tip
|
||||
Contact detection helps maintain grasp stability during retargeting, especially for manipulation tasks.
|
||||
:::
|
||||
|
||||
### Step 5: Generate Scene
|
||||
|
||||
Create MuJoCo scene XML with robot and objects:
|
||||
|
||||
```bash
|
||||
uv run spider/preprocess/generate_xml.py \
|
||||
--task=${TASK} \
|
||||
--dataset-name=${DATASET_NAME} \
|
||||
--data-id=${DATA_ID} \
|
||||
--embodiment-type=${HAND_TYPE} \
|
||||
--robot-type=${ROBOT_TYPE}
|
||||
```
|
||||
|
||||
**What it does:**
|
||||
- Loads robot URDF/XML configuration
|
||||
- Creates scene with objects from dataset
|
||||
- Sets up collision pairs and contact parameters
|
||||
- Configures camera and lighting
|
||||
|
||||
**Output:**
|
||||
```
|
||||
example_datasets/processed/oakink/allegro/bimanual/pick_spoon_bowl/0/
|
||||
└── scene.xml
|
||||
```
|
||||
|
||||
**Scene structure:**
|
||||
```xml
|
||||
<mujoco>
|
||||
<compiler angle="radian" meshdir="assets"/>
|
||||
<option timestep="0.01"/>
|
||||
|
||||
<!-- Robot -->
|
||||
<worldbody>
|
||||
<body name="left_hand">...</body>
|
||||
<body name="right_hand">...</body>
|
||||
|
||||
<!-- Objects -->
|
||||
<body name="spoon">...</body>
|
||||
<body name="bowl">...</body>
|
||||
</worldbody>
|
||||
|
||||
<!-- Contact pairs -->
|
||||
<contact>
|
||||
<pair geom1="left_index_tip" geom2="spoon"/>
|
||||
...
|
||||
</contact>
|
||||
</mujoco>
|
||||
```
|
||||
|
||||
### Step 6: Inverse Kinematics (IK)
|
||||
|
||||
A minimum IK scripts based on mink can be used by:
|
||||
|
||||
```bash
|
||||
uv run spider/preprocess/ik_fast.py \
|
||||
--task=${TASK} \
|
||||
--dataset-name=${DATASET_NAME} \
|
||||
--data-id=${DATA_ID} \
|
||||
--embodiment-type=${HAND_TYPE} \
|
||||
--robot-type=${ROBOT_TYPE}
|
||||
```
|
||||
|
||||
You can also use the original IK script with mujoco by:
|
||||
|
||||
```bash
|
||||
uv run spider/preprocess/ik.py \
|
||||
--task=${TASK} \
|
||||
--dataset-name=${DATASET_NAME} \
|
||||
--data-id=${DATA_ID} \
|
||||
--embodiment-type=${HAND_TYPE} \
|
||||
--robot-type=${ROBOT_TYPE} \
|
||||
--open-hand
|
||||
```
|
||||
|
||||
**What it does:**
|
||||
- Loads MANO hand poses
|
||||
- Solves inverse kinematics for robot joints
|
||||
- Retargets hand poses to robot configuration
|
||||
- Initializes with open hand pose (`--open-hand`)
|
||||
|
||||
**Output:**
|
||||
```
|
||||
example_datasets/processed/oakink/allegro/bimanual/pick_spoon_bowl/0/
|
||||
└── trajectory_kinematic.npz
|
||||
```
|
||||
|
||||
**Data format:**
|
||||
```python
|
||||
# trajectory_kinematic.npz contains:
|
||||
qpos: [T, nq] # Joint positions
|
||||
qvel: [T, nv] # Joint velocities (zero for kinematic)
|
||||
ctrl: [T, nu] # Control targets (same as qpos)
|
||||
time: [T] # Timestamps
|
||||
```
|
||||
|
||||
::: tip IK Options
|
||||
- `--open-hand`: Start IK from open hand pose (recommended)
|
||||
- `--use-contacts`: Use detected contacts in IK optimization
|
||||
- `--smooth-qvel`: Add velocity smoothness term
|
||||
:::
|
||||
|
||||
### Step 7: Physics-Based Optimization
|
||||
|
||||
Optimize trajectory with physics constraints using DIAL-MPC:
|
||||
|
||||
```bash
|
||||
uv run examples/run_mjwp.py \
|
||||
+override=${DATASET_NAME} \
|
||||
task=${TASK} \
|
||||
data_id=${DATA_ID} \
|
||||
robot_type=${ROBOT_TYPE} \
|
||||
embodiment_type=${HAND_TYPE}
|
||||
```
|
||||
|
||||
**What it does:**
|
||||
- Loads kinematic trajectory as reference
|
||||
- Sets up parallel physics simulation (GPU)
|
||||
- Runs sampling-based optimization (DIAL-MPC)
|
||||
- Tracks reference while maintaining physics feasibility
|
||||
|
||||
**Real-time visualization** shows:
|
||||
- Current robot state
|
||||
- Reference trajectory (transparent)
|
||||
- Optimization metrics
|
||||
- Contact forces
|
||||
|
||||
**Output:**
|
||||
```
|
||||
example_datasets/processed/oakink/allegro/bimanual/pick_spoon_bowl/0/
|
||||
├── trajectory_mjwp.npz # Optimized trajectory
|
||||
├── visualization_mjwp.mp4 # Rendered video
|
||||
└── metrics.json # Success metrics
|
||||
```
|
||||
|
||||
## Augmentation Methods
|
||||
|
||||
The original `mjwp_eq` pipeline is no longer supported due to latest mujoco warp release make it unstable.
|
||||
The newer guidance methods are supported by the `mjwp_act` (e.g. `configs/override/oakink_act.yaml`) configuration instead. You will also need to add the `--act-scene` flag when running the `generate_xml.py` and `ik.py` scripts to ensure the necessary assets and logic are generated properly. This approach will provide the fair comparison you are looking for. Related assets is also available in our huggingface repo.
|
||||
|
||||
## Dataset-Specific Examples
|
||||
|
||||
### OakInk Dataset
|
||||
|
||||
```bash
|
||||
export TASK=pick_spoon_bowl
|
||||
export DATASET_NAME=oakink
|
||||
export DATA_ID=0
|
||||
|
||||
# Full workflow
|
||||
uv run spider/process_datasets/oakink.py --task=${TASK} --embodiment-type=bimanual --data-id=${DATA_ID}
|
||||
uv run spider/preprocess/decompose_fast.py --task=${TASK} --dataset-name=${DATASET_NAME} --data-id=${DATA_ID} --embodiment-type=bimanual
|
||||
uv run spider/preprocess/generate_xml.py --task=${TASK} --dataset-name=${DATASET_NAME} --data-id=${DATA_ID} --embodiment-type=bimanual --robot-type=allegro
|
||||
uv run spider/preprocess/ik.py --task=${TASK} --dataset-name=${DATASET_NAME} --data-id=${DATA_ID} --embodiment-type=bimanual --robot-type=allegro --open-hand
|
||||
uv run examples/run_mjwp.py +override=oakink task=${TASK} data_id=${DATA_ID} robot_type=allegro embodiment_type=bimanual
|
||||
```
|
||||
|
||||
### GigaHand Dataset
|
||||
|
||||
```bash
|
||||
export TASK=p36-tea
|
||||
export DATASET_NAME=gigahand
|
||||
export DATA_ID=10
|
||||
|
||||
# Full workflow
|
||||
uv run spider/process_datasets/gigahand.py --task=${TASK} --embodiment-type=bimanual --data-id=${DATA_ID}
|
||||
uv run spider/preprocess/decompose_fast.py --task=${TASK} --dataset-name=${DATASET_NAME} --data-id=${DATA_ID} --embodiment-type=bimanual
|
||||
uv run spider/preprocess/generate_xml.py --task=${TASK} --dataset-name=${DATASET_NAME} --data-id=${DATA_ID} --embodiment-type=bimanual --robot-type=xhand
|
||||
uv run spider/preprocess/ik.py --task=${TASK} --dataset-name=${DATASET_NAME} --data-id=${DATA_ID} --embodiment-type=bimanual --robot-type=xhand --open-hand
|
||||
uv run examples/run_mjwp.py +override=gigahand task=${TASK} data_id=${DATA_ID} robot_type=xhand embodiment_type=bimanual
|
||||
```
|
||||
|
||||
### Hot3D Dataset
|
||||
|
||||
```bash
|
||||
export TASK=P0001_4bf4e21a-obj96945373046044
|
||||
export DATASET_NAME=hot3d
|
||||
export DATA_ID=0
|
||||
|
||||
# Full workflow
|
||||
uv run spider/process_datasets/hot3d.py --task=${TASK} --embodiment-type=right --data-id=${DATA_ID}
|
||||
uv run spider/preprocess/decompose_fast.py --task=${TASK} --dataset-name=${DATASET_NAME} --data-id=${DATA_ID} --embodiment-type=right
|
||||
uv run spider/preprocess/generate_xml.py --task=${TASK} --dataset-name=${DATASET_NAME} --data-id=${DATA_ID} --embodiment-type=right --robot-type=xhand
|
||||
uv run spider/preprocess/ik.py --task=${TASK} --dataset-name=${DATASET_NAME} --data-id=${DATA_ID} --embodiment-type=right --robot-type=xhand --open-hand
|
||||
uv run examples/run_mjwp.py +override=hot3d task=${TASK} data_id=${DATA_ID} robot_type=xhand embodiment_type=right
|
||||
```
|
||||
Reference in New Issue
Block a user