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:
- Converting/preparing robot model (URDF/MJCF)
- Configuring default settings
- Setting up collision geometry
- Adding trace and tracking sites
- Configuring actuators
- 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:
<!-- Add this snippet to your URDF before conversion -->
<mujoco>
<compiler meshdir="assets" balanceinertia="true" discardvisual="false"/>
</mujoco>Then use MuJoCo's compiler:
# 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:
<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 stiffnessdampratio="1.0": Critical dampingarmature="1.0": Joint inertia
Step 3: Add Assets
Include textures and materials:
<asset>
<!-- Skybox texture -->
<texture type="skybox" builtin="gradient"
rgb1="0.3 0.5 0.7" rgb2="0 0 0"
width="512" height="3072" />
<!-- Ground plane texture -->
<texture type="2d" name="left_groundplane" builtin="checker"
mark="edge" rgb1="0.2 0.3 0.4" rgb2="0.1 0.2 0.3"
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:
<!-- 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):
<!-- 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>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:
<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:leftorrightfinger:thumb,index,middle,ring,pinky,palmpart: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:
<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 Tracking Sites
Add tracking sites for end-effector control:
<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)

Step 9: Add Actuators
Define position actuators for all joints:
<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
kpfrom<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:
<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:
<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
<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):
<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
<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
<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:
<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
<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>Important
Actuator order must match joint order in the model definition!
Step 8: Setup Scene
Add white background and tracking camera:
<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="1 1 1"
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
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:
# 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=100Step 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
simulatetool - Remove incompatible URDF attributes
Issue 2: Unstable Simulation
Symptoms: Robot falls through floor, explodes
Solutions:
<!-- 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
kpvalues 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.pngRegister Robot
Add robot to SPIDER's config:
# 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:
- Test thoroughly with multiple tasks
- Document robot-specific parameters
- Tune IK and optimization parameters
- Share your robot configuration (PR welcome!)
