isaac_ros_unitree_g1_recorder#
Source code available on GitHub.
Overview#
Records synchronized teleoperation demonstrations from the Unitree G1 into MCAP rosbags that are compatible with the GR00T training pipeline. Supports bulk data collection via keyboard-driven session management (start/stop/cancel per episode) and launches an H.264 encoder per episode so each bag embeds its own SPS/PPS headers.
For a narrative walk-through of recording episodes end to end, see Record Demonstrations.
Tutorial: Record Demonstrations#
This tutorial walks through recording synchronized teleoperation demonstrations from the Unitree G1 into MCAP rosbags ready for the GR00T training pipeline.
Prerequisites#
The teleoperation stack is already running in a first terminal, either in MuJoCo simulation or on real hardware. Follow isaac_ros_unitree_g1_teleop_bringup through the Run CloudXR Server and Launch the application steps before continuing here.
An Intel RealSense D435 must be connected to the host (Thor) via USB 3 and publishing frames — the recorder writes the H.264 camera stream into every episode bag, and a missing camera will leave the recorded session unusable for fine-tuning.
Set Up Development Environment#
Set up your development environment by following the instructions in getting started.
(Optional) Install dependencies for any sensors you want to use by following the sensor-specific guides.
Note
We strongly recommend installing all sensor dependencies before starting any quickstarts. Some sensor dependencies require restarting the development environment during installation, which will interrupt the quickstart process.
Build isaac_ros_unitree_g1_recorder#
If your container was built with the gr00t_workflow Docker layer, you can skip step 1
Install and build
isaac_ros_unitree_g1_recorder:Activate the Isaac ROS environment:
isaac-ros activateInstall the prebuilt Debian package:
sudo apt-get update
sudo apt-get install -y ros-jazzy-isaac-ros-unitree-g1-recorder source /opt/ros/jazzy/setup.bash
Install Git LFS:
sudo apt-get install -y git-lfs && git lfs install
Clone this repository under
${ISAAC_ROS_WS}/src:cd ${ISAAC_ROS_WS}/src && \ git clone -b release-4.5 https://github.com/NVIDIA-ISAAC-ROS/isaac_ros_physical_ai.git isaac_ros_physical_ai
Activate the Isaac ROS environment:
isaac-ros activateUse
rosdepto install the package’s dependencies:sudo apt-get update
rosdep update && rosdep install --from-paths ${ISAAC_ROS_WS}/src/isaac_ros_physical_ai/isaac_ros_unitree_g1_recorder --ignore-src -y
Build the package from source:
cd ${ISAAC_ROS_WS}/ && \ colcon build --symlink-install --packages-up-to isaac_ros_unitree_g1_recorder --base-paths ${ISAAC_ROS_WS}/src/isaac_ros_physical_ai/isaac_ros_unitree_g1_recorder
Source the ROS workspace:
Note
Make sure to repeat this step in every terminal created inside the Isaac ROS environment. Because this package was built from source, the enclosing workspace must be sourced for ROS to be able to find the package’s contents.
source install/setup.bash
Verify the Camera View#
Before recording, confirm that the robot’s ego-view camera sees the work area you intend to demonstrate. In a new terminal inside the Isaac ROS environment:
rviz2
In RViz, click Add (bottom-left) → By topic →
/realsense_d435_rgb/color/image_raw/Image → OK. Confirm the live
camera frame shows the workspace. Adjust the camera mount or scene if not.
Run the Recorder#
Open a second terminal (the teleop stack must keep running in the first). Activate the Isaac ROS environment and source the workspace:
isaac-ros activate source install/setup.bash
Launch the recorder:
ros2 run isaac_ros_unitree_g1_recorder record -- \ task_description:="move the apple to the plate"
The
--separatesros2 runarguments from the keyboard-controller arguments. A keyboard UI appears in this terminal:Task: move the apple to the plate Episode: 0 saved | Status: IDLE ──────────────────────────────── [Space] Start [t] Change Task [q] Quit
The recorder starts in the IDLE state. The UI prints the host path to the new session directory.
Record Episodes#
Key |
IDLE |
RECORDING |
|---|---|---|
Space |
Start recording |
Stop & save |
|
— |
Cancel & discard |
|
Change task description |
— |
|
Quit |
— (prevents accidental data loss) |
Bulk-collection loop:
Press Space to start recording an episode.
Perform the teleoperation demonstration.
Press Space to save the episode, or c to discard if the demo was bad.
Repeat.
Each session creates a directory under output_dir (default
/workspaces/isaac_ros-dev/recordings/). The task description is also
written to <episode_dir>/task.txt.
API#
Usage#
Run from a second terminal while the teleop bringup is running:
ros2 run isaac_ros_unitree_g1_recorder record -- \
task_description:="move the apple to the plate"
The -- separates ros2 run arguments from recorder launch arguments.
Launch Arguments#
Launch Argument |
Type |
Default |
Description |
|---|---|---|---|
|
|
(required) |
Initial task description for the session; written to each
|
|
|
|
Session base directory. Keep inside the workspace mount for host persistence. |
|
|
|
|
|
|
|
H.264 camera topic (encoder output). |
|
|
|
Raw image topic (encoder input). |
|
|
|
Camera intrinsics topic. |
|
|
|
Camera width in pixels. |
|
|
|
Camera height in pixels. |
|
|
|
IMU topic. |
Recorded Topics#
Each episode bag contains:
Topic |
Type |
Purpose |
|---|---|---|
|
|
43-DOF robot observation (200 Hz) |
|
|
Safety-blended applied joint commands (action, 200 Hz) |
|
|
Per-frame sync timestamps (30 Hz) |
|
|
H.264 ego-view video (30 Hz) |
|
|
Camera intrinsics + distortion (30 Hz) |
|
|
Locomotion |
|
|
Locomotion |
|
|
Headset EE pose targets (pre-IK) |
|
|
Headset finger joint targets (pre-controller) |
|
|
Body orientation / angular velocity |
|
|
Dynamic transforms |
|
|
Static transforms (latched) |
|
|
Task string (latched, one message per episode) |
|
|
URDF (latched, one message per episode) |
Note
On the real robot, /joint_states and /applied_joint_commands are
recorded at the full 200 Hz controller rate. In MuJoCo simulation these
topics may instead show a sustained ~165 Hz average rate with intermittent
inter-message gaps. This is an aliasing artifact between the 200 Hz
controller and MuJoCo’s internal simulation timestep, not a recording
defect. MuJoCo is intended for validating the teleop setup; record full
datasets on real hardware to obtain the expected 200 Hz sampling.
ROS Services#
Exposed by the recorder node for programmatic control:
Service |
Type |
Purpose |
|---|---|---|
|
|
Begin recording an episode. |
|
|
Stop and save the current episode. |
|
|
Stop and discard the current episode. |
ROS Parameters#
Parameter |
Node |
Type |
Default |
Description |
|---|---|---|---|---|
|
|
|
(from launch arg) |
Task description for upcoming episodes. Update with
|
Status Topic#
The recorder publishes session status on /g1_recorder/status as a JSON
string containing state, task, episode count, and episode duration.
Keyboard Controls#
Key |
IDLE |
RECORDING |
|---|---|---|
Space |
Start recording |
Stop & save |
|
— |
Cancel & discard |
|
Change task description |
— |
|
Quit |
— (prevents accidental data loss) |
Troubleshooting#
Recorded Bags Show a Frozen Robot (Real Hardware)#
If /applied_joint_commands in the recorded bag does not reflect your
teleop motion, the AGILE safety controller was almost certainly still at
blend_ratio=0.0 when you recorded. Raise the ratio before recording:
ros2 param set /safety_controller blend_ratio 1.0
In MuJoCo simulation blend_ratio defaults to 1.0 and no action is
needed.