Training guide · verbatim from the official docs

SONIC on a new robot: seven files, one mapping

SONIC's training pipeline is designed around the Unitree G1 (29 DOF) but can be extended to other humanoids. The official guide walks through every file you need to touch, using the Unitree H2 (31 DOF) as the concrete example — everything here is transcribed from the Training on New Embodiments doc.

Files you need to add or modify

FileActionPurpose
gear_sonic/data/assets/robot_description/urdf/<robot>/AddURDF + mesh files for Isaac Lab simulation
gear_sonic/data/assets/robot_description/mjcf/<robot>.xmlAddMuJoCo XML for motion library forward kinematics
gear_sonic/envs/manager_env/robots/<robot>.pyAddRobot config: joints, actuators, mappings, action scales
gear_sonic/envs/manager_env/robots/__init__.pyModifyImport your new robot module
gear_sonic/envs/manager_env/modular_tracking_env_cfg.pyModifyAdd robot to robot_mapping dict (~line 998)
gear_sonic/trl/utils/order_converter.pyModifyAdd converter class for joint/body reordering
gear_sonic/config/exp/manager/universal_token/all_modes/sonic_<robot>.yamlAddExperiment config
Config YAMLs (terminations, rewards, commands)CheckBody names must exist on your robot

The full H2 support ships in the repo as a reference implementation: robot config, URDF + meshes, MJCF, experiment config, H2Converter, and the robot_mapping entry all exist — copy them for your own robot.

Step 1 · Robot model files

gear_sonic/data/assets/robot_description/
|-- urdf/h2/
|   |-- h2.urdf
|   `-- meshes/          # STL/OBJ mesh files
`-- mjcf/
    `-- h2.xml           # MuJoCo XML

The URDF is loaded by Isaac Lab for physics simulation. The MJCF is used by the motion library to compute forward kinematics on reference motion data. Both must represent the same robot with consistent joint names and tree structure. Make sure your URDF mesh paths are correct — relative paths like meshes/pelvis.stl work best; if your URDF uses package:// paths, update them to match the directory layout.

Step 2 · Robot configuration

Create gear_sonic/envs/manager_env/robots/<robot>.py — the most important file; it defines how your robot integrates with the training pipeline. The articulation config uses Isaac Lab's ArticulationCfg with UrdfFileCfg spawn, init_state, and one ImplicitActuatorCfg group per motor type (legs, arms, waist, feet, etc.). Two init_state notes from the docs:

  • pos z-value is the spawn height — set it so the robot starts standing with feet slightly above ground. Too low = feet clip through ground on first frame.
  • joint_pos should be a stable standing pose, from your robot's real default calibration pose or a MuJoCo keyframe.

Joint and body ordering — the critical part

Isaac Lab and MuJoCo traverse the kinematic tree in different orders. You must define bidirectional index mappings. Get these by loading your URDF in Isaac Lab and your MJCF in MuJoCo, printing the joint/body lists, and computing the reorder indices.

# All bodies in IsaacLab traversal order (including root "pelvis")
H2_ISAACLAB_JOINTS = [
    "pelvis",
    "left_hip_pitch_link",
    "right_hip_pitch_link",
    # ... all 32 bodies for H2
]

# Index arrays: position i in the output = position mapping[i] in the input
H2_ISAACLAB_TO_MUJOCO_DOF = [...]   # len = num_dof (31 for H2)
H2_MUJOCO_TO_ISAACLAB_DOF = [...]
H2_ISAACLAB_TO_MUJOCO_BODY = [...]  # len = num_bodies (32 for H2)
H2_MUJOCO_TO_ISAACLAB_BODY = [...]

H2_ISAACLAB_TO_MUJOCO_MAPPING = {
    "isaaclab_joints": H2_ISAACLAB_JOINTS,
    "isaaclab_to_mujoco_dof": H2_ISAACLAB_TO_MUJOCO_DOF,
    "mujoco_to_isaaclab_dof": H2_MUJOCO_TO_ISAACLAB_DOF,
    "isaaclab_to_mujoco_body": H2_ISAACLAB_TO_MUJOCO_BODY,
    "mujoco_to_isaaclab_body": H2_MUJOCO_TO_ISAACLAB_BODY,
}
Getting the mappings right is critical. If they are wrong, the policy will receive scrambled observations and produce scrambled actions. Verify by loading a known pose in both simulators and checking that joint values match after reordering.

Actuator parameters (KP/KD tuning)

The actuator stiffness (KP) and damping (KD) are critical for sim-to-real transfer and training stability. SONIC uses implicit PD actuators in Isaac Lab.

# Derive from motor specs — these need tuning for your robot
NATURAL_FREQ = 10 * 2.0 * 3.1415926535  # 10Hz natural frequency
DAMPING_RATIO = 2.0                      # Overdamped for stability

# Per-motor stiffness: KP = armature * omega^2
STIFFNESS_5020 = ARMATURE_5020 * NATURAL_FREQ**2
# Per-motor damping: KD = 2 * zeta * armature * omega
DAMPING_5020 = 2.0 * DAMPING_RATIO * ARMATURE_5020 * NATURAL_FREQ

Tuning guidance (verbatim):

  • Start with the real motor's armature (rotor inertia) from the datasheet.
  • The natural frequency controls responsiveness. 10 Hz is a good starting point for humanoids. Increase for stiffer/faster tracking, decrease for compliance.
  • The damping ratio should be >= 1.0 (critically damped or overdamped) to avoid oscillation. 2.0 works well for SONIC.
  • Different joint groups need different gains. Hip/knee motors are much stronger than wrist motors. Group joints by motor type (see G1/H2 configs for examples).
  • If training is unstable (robot explodes or falls immediately), your KP/KD values are likely wrong — try reducing KP or increasing KD.
  • The effort limits (max torque) per joint should match the real motor specs.

Action scale

Action scale maps normalized policy outputs to joint position targets. Compute it from effort limit and stiffness:

{
H2_ACTION_SCALE = }
for joint_name in joint_names:
    H2_ACTION_SCALE[joint_name] = effort_limit[joint_name] / stiffness[joint_name]

Larger action scale = larger joint movements per policy output. If the robot moves too aggressively, reduce the action scale. Then register the module in robots/__init__.py and add the robot to the robot_mapping dict in modular_tracking_env_cfg.py (around line 998); the string key (e.g. "h2") is what you use as robot.type in the experiment config.

Step 3 · Order converter + body name compatibility

In gear_sonic/trl/utils/order_converter.py, add a converter class (e.g. H2Converter(IsaacLabMuJoCoConverter)) used by the evaluation and export pipeline, wiring the same DOF and body mappings plus the VR tracking and foot contact body names (VR_3POINTS_BODY_NAMES, FOOT_BODY_NAMES). Use lazy imports (inside __init__) to avoid circular dependencies.

Body name compatibility is a common source of errors. The training configs reference specific body names that must exist on your robot — check all of them:

  • Command config (config/manager_env/commands/terms/motion.yaml): anchor_body, vr_3point_body, reward_point_body, and the 14 tracked body_names.
  • Termination configs: ee_body_pos_adaptive.yaml (ankle + wrist links), foot_pos_xyz.yaml (ankle links).
  • Reward configs: undesired_contacts.yaml (regex excluding ankle/wrist links from contact penalty), anti_shake_ang_vel.yaml (wrist links + head_link).

If names differ (H2 has head_yaw_link where G1 has head_link), either override the specific fields in your experiment config (recommended) or copy the affected term YAMLs into robot-specific variants. Tip from the docs: run training with num_envs=1 first — Isaac Lab raises a clear error naming the missing body.

Step 4 · Motion data (PKL format)

SONIC expects retargeted motion data as PKL files (joblib format). Each file contains a dict keyed by motion name:

{
    "motion_name": {
        "root_trans_offset": np.ndarray,  # (T, 3) — root translation
        "pose_aa": np.ndarray,            # (T, num_bodies, 3) — axis-angle per body
        "dof": np.ndarray,                # (T, num_dof) — joint positions in MuJoCo order
        "root_rot": np.ndarray,           # (T, 4) — root quaternion (wxyz)
        "smpl_joints": np.ndarray,        # (T, 24, 3) — SMPL joint positions (optional)
        "fps": int,                       # Frame rate (typically 30)
    }
}

Important data format notes: num_bodies and num_dof must match your robot (e.g. 32 bodies / 31 DOF for H2); dof values must be in MuJoCo joint order, not IsaacLab order; pose_aa must be in MuJoCo body order; mirrored variants (filename ending in _M.pkl) double your effective dataset size and improve symmetry; smpl_joints is used by the SMPL encoder — set it to zeros if you don't have SMPL data. The motion library loads PKL files recursively from a directory (data/h2_motions/session_01/…).

Step 5 · Source motion data and retargeting

The recommended source is Bones-SEED — a large-scale human motion dataset (142K+ motions, ~288 hours) providing raw BVH files (full-body human motion capture) and G1 retargeted CSVs (already retargeted to the Unitree G1, 29 DOF). For a new robot you need to retarget the raw human motions to your robot's skeleton — the most labor-intensive step. Details and the download commands: data collection page and the Training Data doc.

Retargeting options:

  1. SOMA Retargeter (recommended) — NVIDIA's BVH-to-humanoid motion retargeting library built with Newton and NVIDIA Warp. Supports any humanoid robot via JSON configuration, includes a viewer for inspecting source and retargeted motions side by side. This is the same tool used to produce the Bones-SEED G1 retargeted data.
  2. GMR (General Motion Retargeting) — retargets human motions to arbitrary humanoid robots in real time on CPU. Supports any URDF. A lighter-weight alternative.
  3. This repo's data processing (gear_sonic/data_process/) — converts retargeted CSVs/BVHs into the PKL format SONIC expects, as the final step after retargeting:
    # Convert retargeted CSVs to motion library PKLs
    python gear_sonic/data_process/convert_soma_csv_to_motion_lib.py \
        --input /path/to/retargeted_csvs/ \
        --output data/my_robot_motions/robot \
        --fps 30 --fps_source 120 --individual --num_workers 16
    
    # Filter out motions that are physically impossible for your robot
    python gear_sonic/data_process/filter_and_copy_bones_data.py \
        --source data/my_robot_motions/robot \
        --dest data/my_robot_motions/robot_filtered

For SMPL data: pre-computed SMPL for Bones-SEED motions is on Hugging Face (python download_from_hf.py --training); for custom motions extract SMPL joints from BVH with gear_sonic/data_process/extract_soma_joints_from_bvh.py; or set smpl_motion_file: dummy.

Step 6 · Experiment config

Create gear_sonic/config/exp/manager/universal_token/all_modes/sonic_<robot>.yaml — start by copying sonic_release.yaml and modify. Fields to review and potentially override:

  • robot.type — must match the key in robot_mapping
  • motion_lib_cfg.asset.assetFileName — your MJCF file
  • reward_point_body / reward_point_body_offset — key bodies for reward computation
  • vr_3point_body / vr_3point_body_offset — if doing VR teleoperation
  • upper_body_augment_prefixes — remove if your motion data uses different naming
  • Body names in reward/termination overrides — see the body compatibility section

Step 7 · Train

python gear_sonic/train_agent_trl.py \
    +exp=manager/universal_token/all_modes/sonic_h2 \
    num_envs=16 headless=False \
    ++manager_env.commands.motion.motion_lib_cfg.motion_file=<path/to/h2_motions>

Start with num_envs=16 headless=False to visually verify the robot loads and motions play correctly, then scale up to num_envs=4096 headless=True for full training. A full training checklist (mappings verified, KP/KD per motor group, mirrored variants, SMPL data) is in the official doc — the full SONIC training flow (installation, finetune from checkpoint, evaluation) is on the training page.

New embodiments FAQ

Which files do I touch to train SONIC on a new robot?
Seven items: URDF + meshes under gear_sonic/data/assets/robot_description/urdf/<robot>/, an MJCF at mjcf/<robot>.xml, the robot config gear_sonic/envs/manager_env/robots/<robot>.py, an import in robots/__init__.py, an entry in the robot_mapping dict in modular_tracking_env_cfg.py, a converter class in trl/utils/order_converter.py, and the experiment config sonic_<robot>.yaml. Plus a check pass over body names in the termination, reward, and command YAMLs.
What is the Isaac Lab ↔ MuJoCo index mapping and why does it matter?
Isaac Lab and MuJoCo traverse the kinematic tree in different orders, so the pipeline needs bidirectional index arrays (isaaclab_to_mujoco_dof, mujoco_to_isaaclab_dof, and the body equivalents). The official docs call getting them right critical: if they are wrong, the policy will receive scrambled observations and produce scrambled actions. Verify by loading a known pose in both simulators and checking joint values after reordering.
What KP/KD values should I start with for a new robot?
Start from the real motor's armature (rotor inertia) from the datasheet. Natural frequency 10 Hz is a good starting point for humanoids — increase for stiffer/faster tracking, decrease for compliance. The damping ratio should be >= 1.0 (critically damped or overdamped) to avoid oscillation; 2.0 works well for SONIC. Group joints by motor type — hip/knee motors are much stronger than wrist motors.
Do I need SMPL data to train SONIC on a new robot?
No. The smpl_joints field in the PKL files is used by the SMPL encoder and can be zeros if you have no SMPL data. If you have no SMPL data at all, set smpl_motion_file: dummy in the config — the pipeline generates minimal placeholder SMPL data from the robot motions; it works but produces weaker SMPL encoder performance.