How to bring your own embodiment#

Isaac ROS Deploy uses ros2_control to interface with robot hardware. This guide shows how to create the required package skeletons, add the SystemInterface implementations for the real and simulated robot, and add the corresponding launch and configuration files.

Prerequisites#

Before you begin, make sure you have:

  • A URDF description of the robot

  • A simulator asset (USD or MJCF) for each simulation platform that you plan to support

  • A C++ robot SDK for the real hardware

Use the Unitree G1 integration as a working example while following the steps:

  • Source code available on GitHub.

    contains the robot descriptions and platform-specific ros2_control xacros.

  • Source code available on GitHub.

    contains the real-hardware SystemInterface plugin.

  • Source code available on GitHub.

    contains the controller configuration and launch files.

1. Create the package layout#

Create three packages for the new robot, following the G1 split:

<robot>_description

Owns URDF or xacro descriptions and simulator assets.

<robot>_ros2_control

Owns the real-hardware SystemInterface plugin.

<robot>_bringup

Owns controller configuration, policy groups, and launch files.

2. Define the ROS 2 Control interfaces#

Next, determine which ROS 2 Control state and command interfaces the new embodiment should expose. Use the same interfaces for the real and simulated SystemInterface implementations.

For each target platform, add a ros2_control xacro to the <robot>_description package. Each xacro must define:

  • The platform-specific hardware plugin and its parameters

  • The command and state interfaces for each joint

  • The state interfaces for each IMU or other sensor

The G1 integration provides an example for each platform:

3. Add each target platform#

Implement only the tabs needed by the new robot.

You don’t need to implement a new SystemInterface for MuJoCo. Reuse mujoco_ros2_control and its MujocoSystemInterface, and configure it with the robot’s MJCF model. Provide:

  1. A MuJoCo MJCF model.

  2. A mujoco_pid.yaml parameter file. Pass this file to the controller manager. When a controller claims the position, kp, and kd interfaces, MujocoSystemInterface uses the commanded gains instead of the values under pid_gains. The file can also configure optional MuJoCo plugins, such as a virtual gantry.

  3. A ros2_control xacro that selects MujocoSystemInterface and declares the shared interface contract from step 2.

The result is a robot description that the controller manager can load with the MuJoCo hardware plugin.

4. Configure controllers and policy groups#

Add two files to <robot>_bringup:

controller_manager.yaml

Declares controller plugins, joints, gains, and controller-specific parameters.

controller_groups.yaml

Groups the controllers that run together. A policy group identifies the LEAPP bundle, source-to-topic mappings, command-interface prefix and suffix, and controller activation order.

Use the G1 controller_manager.yaml and controller_groups.yaml files as a starting point. Remove G1-specific joints, controllers, and thresholds instead of carrying them into the new robot unchanged.

5. Validate one layer at a time#

Validate the integration in this order on every supported platform:

  1. The robot description expands without xacro or URDF errors.

  2. The controller manager loads the selected hardware plugin.

  3. State interfaces update with the expected joint and sensor names.

  4. A simple test controller can claim and write the expected command interfaces.

  5. The configured controller group loads with the LEAPP runtime selected for the policy.

Start with simulation. Move to real hardware only after the description, interface names, controller configuration, and policy tensor ordering match the simulation integration.