|
Download GR00T-WholeBodyControl/docs/source/tutorials/data_collection.md from Timsty/groot_deployment: direct link, hf CLI and curl.
- Browser
- Download file 23.6 kB
-
https://huggingface.co/Timsty/groot_deployment/resolve/main/GR00T-WholeBodyControl/docs/source/tutorials/data_collection.md
- Command line
-
hf download hf://Timsty/groot_deployment/GR00T-WholeBodyControl/docs/source/tutorials/data_collection.md
-
curl -L -o data_collection.md https://huggingface.co/Timsty/groot_deployment/resolve/main/GR00T-WholeBodyControl/docs/source/tutorials/data_collection.md
23.6 kB
| # Data Collection for VLA | |
| Record teleop demonstrations as [LeRobot](https://github.com/huggingface/lerobot) datasets for post-training with [Isaac-GR00T](https://github.com/NVIDIA/Isaac-GR00T). The data exporter runs alongside the SONIC deployment and VR teleop stack, capturing robot state, SMPL teleop poses, and camera images at a configurable frequency. | |
| ```{admonition} Deployment model | |
| :class: important | |
| Everything runs **offboard on your workstation** except the **camera server**, which runs **onboard the robot computer** (e.g., Jetson Orin) where the physical cameras are connected. The camera server publishes JPEG frames over ZMQ to the workstation. | |
| ``` | |
| ```{admonition} Supported cameras | |
| :class: note | |
| The tested and supported camera setup uses **Luxonis OAK cameras** (OAK-D, OAK-1, etc.). This includes a head/ego-view OAK camera and optional OAK wrist cameras. Other camera drivers (RealSense, USB webcam) are included in the codebase but have not been tested recently. | |
| A 3D-printable mount for the head/ego-view **OAK-D W** camera is available under [`hardware/camera_mount/`](https://github.com/NVlabs/GR00T-WholeBodyControl/blob/main/hardware/camera_mount/README.md) β see its README for print settings, the bill of materials, and how it mounts on the G1. | |
| ``` | |
| ```{admonition} Prerequisites | |
| :class: note | |
| 1. **Completed the [Quick Start](../getting_started/quickstart.md)** β you can run the sim2sim loop (includes [installing the deployment](../getting_started/installation_deploy.md) and [downloading model checkpoints](../getting_started/download_models.md)). | |
| 2. **Completed the [VR Teleop Setup](../getting_started/vr_teleop_setup.md)** β PICO hardware is calibrated and `.venv_teleop` is ready. | |
| 3. **Camera server running on the robot** β see [Camera Server Setup](#camera-server-setup-on-robot) below. For simulation, the MuJoCo sim loop publishes camera images automatically β no camera server needed. | |
| ``` | |
| --- | |
| ## One-Time Setup (Workstation) | |
| On your **workstation** (where you run the C++ deployment, teleop, and data exporter), run the install script from the repo root to create a dedicated virtual environment with all data collection dependencies (LeRobot, PyAV, OpenCV, etc.): | |
| ```sh | |
| bash install_scripts/install_data_collection.sh | |
| ``` | |
| This creates `.venv_data_collection` using Python 3.10 via `uv`. It installs `gear_sonic[data_collection]` which includes `lerobot`, `av`, `opencv-python`, and other required packages. It also installs `espeak` (system package) for voice feedback during recording. | |
| ```{tip} | |
| This environment is separate from `.venv_teleop` and `.venv_sim` β the data exporter has heavier ML dependencies that are not needed for teleop or simulation. | |
| ``` | |
| --- | |
| ## Camera Server Setup (On-Robot) | |
| The camera server is the **only component that runs on the robot computer** (e.g., Jetson Orin). Everything else β the C++ deployment, PICO teleop streamer, data exporter, and camera viewer β runs on your workstation. | |
| The camera server captures frames from the OAK cameras physically connected to the robot and publishes them over ZMQ to the workstation. | |
| ### Step 1: Clone the repo on the robot | |
| SSH into your robot computer and clone this repository: | |
| ```sh | |
| git clone https://github.com/NVlabs/GR00T-WholeBodyControl.git | |
| cd GR00T-WholeBodyControl | |
| ``` | |
| ### Step 2: Run the install script | |
| The install script handles everything: creates the virtual environment, installs all | |
| dependencies (including the DepthAI SDK for OAK cameras), detects connected cameras, | |
| and optionally installs a systemd service so the camera server starts automatically | |
| on boot. | |
| ```sh | |
| bash install_scripts/install_camera_server.sh | |
| ``` | |
| The script will: | |
| 1. Create `.venv_camera` with `gear_sonic[camera]` (DepthAI, ZMQ, msgpack, OpenCV, tyro). | |
| 2. Detect connected OAK cameras and list their MxIDs. | |
| 3. Prompt you for each camera position (ego view, and optionally left/right wrist) and its device ID. | |
| 4. Ask whether to install the camera server as a **systemd service** (recommended). If you answer **y**, it generates the unit file, installs, enables, and starts the service automatically. | |
| After the script finishes, verify the service is running: | |
| ```sh | |
| sudo systemctl status composed_camera_server.service | |
| journalctl -u composed_camera_server.service -f | |
| ``` | |
| ```{note} | |
| Other camera drivers (RealSense, USB webcam) are included in the codebase but have not been tested recently for data collection. If you need RealSense, install `pyrealsense2` into the venv after setup. See the driver files in `gear_sonic/camera/drivers/` for details. | |
| ``` | |
| ### Manual setup (alternative) | |
| If you prefer not to use the install script, or need to reconfigure: | |
| **Finding camera device IDs:** | |
| Each OAK camera has a unique MxID. List all connected OAK devices: | |
| ```sh | |
| source .venv_camera/bin/activate | |
| python -c "import depthai as dai; print(dai.Device.getAllAvailableDevices())" | |
| ``` | |
| Example output: | |
| ```text | |
| [XLinkDeviceState.X_LINK_BOOTED, MxId: 18443010E1ABC12300, ...] | |
| ``` | |
| **Starting the camera server manually:** | |
| ```sh | |
| source .venv_camera/bin/activate | |
| # Single camera (ego view only) | |
| python -m gear_sonic.camera.composed_camera \ | |
| --ego-view-camera oak \ | |
| --ego-view-device-id <YOUR_MXID> \ | |
| --port 5555 | |
| # Multiple cameras (ego view + wrist cameras) | |
| python -m gear_sonic.camera.composed_camera \ | |
| --ego-view-camera oak --ego-view-device-id <EGO_MXID> \ | |
| --left-wrist-camera oak --left-wrist-device-id <LEFT_WRIST_MXID> \ | |
| --right-wrist-camera oak --right-wrist-device-id <RIGHT_WRIST_MXID> \ | |
| --port 5555 | |
| ``` | |
| Run `python -m gear_sonic.camera.composed_camera --help` for all options including `--fps`, `--use-mjpeg`, and `--mjpeg-quality`. | |
| **Manual systemd setup:** | |
| ```sh | |
| # 1. Edit the service file to match your camera setup | |
| nano systemd/composed_camera_server.service | |
| # 2. Copy to systemd, enable, and start | |
| sudo cp systemd/composed_camera_server.service /etc/systemd/system/ | |
| sudo systemctl daemon-reload | |
| sudo systemctl enable composed_camera_server.service | |
| sudo systemctl start composed_camera_server.service | |
| ``` | |
| Once the systemd service is running, the camera server starts automatically whenever the robot boots β no manual intervention needed. | |
| ### Connecting from the workstation | |
| On your workstation, the data exporter and camera viewer connect to the robot's camera server over the network. Pass the robot's IP address (the G1 robot's default IP is `192.168.123.164`): | |
| ```sh | |
| # Data exporter | |
| python gear_sonic/scripts/run_data_exporter.py \ | |
| --task-prompt "pick up the cup" \ | |
| --camera-host 192.168.123.164 --camera-port 5555 | |
| # Camera viewer (to verify the feed) | |
| python gear_sonic/scripts/run_camera_viewer.py \ | |
| --camera-host 192.168.123.164 --camera-port 5555 | |
| ``` | |
| The tmux launcher also accepts `--camera-host`: | |
| ```sh | |
| python gear_sonic/scripts/launch_data_collection.py \ | |
| --camera-host 192.168.123.164 \ | |
| --task-prompt "pick up the cup" | |
| ``` | |
| ### ZMQ message format | |
| The camera server publishes a single msgpack-encoded payload per frame cycle containing all camera images: | |
| ```python | |
| { | |
| "timestamps": {"ego_view": 1712345678.123, "left_wrist": 1712345678.125}, | |
| "images": {"ego_view": "<base64-jpeg>", "left_wrist": "<base64-jpeg>"} | |
| } | |
| ``` | |
| Images are JPEG-compressed (quality 80) and either base64-encoded strings or raw JPEG bytes (when MJPEG on-device encoding is enabled). The data exporter's `ComposedCameraClientSensor` handles both formats automatically. | |
| --- | |
| ## Architecture | |
| The data exporter receives data from three ZMQ sources. The C++ deployment, PICO teleop, and data exporter all run **offboard on the workstation**. The camera server runs **onboard the robot** and streams frames to the workstation over the network. | |
| ```text | |
| Workstation (offboard) Robot (onboard) | |
| ββββββββββββββββββββββββ ββββββββββββββββββββββββ βββββββββββββββββ | |
| β C++ deploy β β pico_manager β β Camera β | |
| β (zmq_output_handler)β β _thread_server.py β β server β | |
| β β β β β (OAK cameras)β | |
| β port 5557 β β port 5556 β β port 5555 β | |
| β topics: g1_debug, β β topic: pose β β (JPEG/ZMQ) β | |
| β robot_configβ β (SMPL body params) β β β | |
| ββββββββββββ¬ββββββββββββ ββββββββββββ¬βββββββββββββ ββββββββ¬βββββββββ | |
| β β β | |
| ββββββββββββββ¬βββββββββββββββββββββββββββββββββββββ | |
| β (network) | |
| ββββββββββΌβββββββββ | |
| β run_data_ β | |
| β exporter.py β | |
| β (workstation) β | |
| β β | |
| β LeRobot datasetβ | |
| β (parquet + mp4)β | |
| βββββββββββββββββββ | |
| ``` | |
| | Source | Runs on | ZMQ Topic | Default Port | Provides | | |
| |---|---|---|---|---| | |
| | C++ deployment | Workstation | `g1_debug` | 5557 | Joint positions, velocities, IMU quaternion | | |
| | C++ deployment | Workstation | `robot_config` | 5557 | One-shot robot configuration at startup | | |
| | PICO teleop streamer | Workstation | `pose` | 5556 | SMPL body parameters (teleop target poses) | | |
| | Camera server | Robot | *(raw TCP)* | 5555 | JPEG-compressed camera images (ego view + optional wrist views) | | |
| --- | |
| ## Running Data Collection | |
| There are two ways to run the data collection stack: an **all-in-one tmux launcher** (recommended) or **manual multi-terminal setup**. | |
| ### Option A: All-in-One Tmux Launch (Recommended) | |
| The launcher starts all components in a single tmux session with four panes: | |
| ```text | |
| βββββββββββββββββββββββββ¬ββββββββββββββββββββββββ | |
| β Pane 0: C++ Deploy β Pane 2: Data Exporter β | |
| β (gear_sonic_deploy) β (.venv_data_collection)β | |
| βββββββββββββββββββββββββΌββββββββββββββββββββββββ€ | |
| β Pane 1: PICO Teleop β Pane 3: Camera Viewer β | |
| β (.venv_teleop) β (.venv_data_collection)β | |
| βββββββββββββββββββββββββ΄ββββββββββββββββββββββββ | |
| ``` | |
| ```{note} | |
| Requires `tmux` to be installed (`sudo apt install tmux`). | |
| ``` | |
| **For simulation** (the launcher starts `run_sim_loop.py` in a separate tmux window automatically): | |
| ```bash | |
| python gear_sonic/scripts/launch_data_collection.py --sim | |
| ``` | |
| **For real robot** (camera server running on robot at `192.168.123.164`): | |
| ```bash | |
| python gear_sonic/scripts/launch_data_collection.py \ | |
| --camera-host 192.168.123.164 \ | |
| --task-prompt "pick up the cup" | |
| ``` | |
| **With wrist cameras** (records ego view + left/right wrist camera streams): | |
| ```bash | |
| python gear_sonic/scripts/launch_data_collection.py \ | |
| --camera-host 192.168.123.164 \ | |
| --task-prompt "pick up the cup" \ | |
| --record-wrist-cameras | |
| ``` | |
| ```{tip} | |
| No need to activate a virtual environment first β the launcher automatically detects and uses `.venv_data_collection` if the required dependencies are not in the current Python. | |
| ``` | |
| The launcher auto-attaches to the tmux session. Use `Ctrl+b` then arrow keys to switch between panes. | |
| Common options: | |
| | Flag | Default | Description | | |
| |---|---|---| | |
| | `--task-prompt` | `"demo"` | Language task description (e.g., `"pick up the cup"`) | | |
| | `--dataset-name` | *(auto: timestamp)* | Dataset name; omit to auto-generate | | |
| | `--sim / --no-sim` | `False` | Run deploy.sh in sim mode (also starts the sim loop) | | |
| | `--camera-host` | `localhost` | Camera server host (e.g., `192.168.123.164` for real robot) | | |
| | `--camera-port` | `5555` | Camera server port | | |
| | `--no-camera-viewer` | *(viewer on)* | Disable the camera viewer pane | | |
| | `--data-exporter-frequency` | `50` | Recording frequency (Hz) | | |
| | `--deploy-checkpoint` | *(default)* | Custom checkpoint path for deploy.sh | | |
| | `--deploy-obs-config` | *(default)* | Custom observation config for deploy.sh | | |
| | `--deploy-planner` | *(default)* | Custom planner model path for deploy.sh | | |
| | `--deploy-motion-data` | *(default)* | Custom motion data path for deploy.sh | | |
| | `--record-wrist-cameras` | `False` | Record left/right wrist camera streams in the dataset | | |
| | `--no-text-to-speech` | *(on)* | Disable voice feedback via espeak | | |
| Run `python gear_sonic/scripts/launch_data_collection.py --help` for all options. | |
| ```{tip} | |
| The launcher automatically enables **mouse support** in the tmux session β click to select panes, scroll with the mouse wheel, and drag to resize pane borders. | |
| ``` | |
| **Session management:** | |
| | Action | Command | | |
| |---|---| | |
| | Switch panes | `Ctrl+b`, then arrow keys | | |
| | Detach (keep running) | `Ctrl+b`, then `d` | | |
| | Reattach | `tmux attach -t sonic_data_collection` | | |
| | Kill session | `Ctrl+\` in any pane, or `tmux kill-session -t sonic_data_collection` | | |
| ### Option B: Manual Multi-Terminal Setup | |
| If you prefer individual control over each process, run them in separate terminals: | |
| **Terminal 1 β MuJoCo Simulator** *(skip for real robot)*: | |
| ```bash | |
| source .venv_sim/bin/activate | |
| python gear_sonic/scripts/run_sim_loop.py \ | |
| --enable-image-publish --enable-offscreen --camera-port 5555 | |
| ``` | |
| The `--enable-image-publish` and `--enable-offscreen` flags are required so the | |
| sim renders camera images and streams them over ZMQ on the specified port. | |
| The data exporter subscribes to this port the same way it subscribes to a | |
| physical camera server. | |
| For real robot deployment, skip this terminal and see [VR Whole-Body Teleop](vr_wholebody_teleop.md) instead. | |
| **Terminal 2 β C++ Deployment** (from `gear_sonic_deploy/`): | |
| ```bash | |
| cd gear_sonic_deploy | |
| source scripts/setup_env.sh | |
| ./deploy.sh --input-type zmq_manager sim | |
| # Wait until you see "Init done" | |
| ``` | |
| **Terminal 3 β PICO Teleop Streamer:** | |
| ```bash | |
| source .venv_teleop/bin/activate | |
| python gear_sonic/scripts/pico_manager_thread_server.py --manager | |
| ``` | |
| **Terminal 4 β Data Exporter:** | |
| ```bash | |
| source .venv_data_collection/bin/activate | |
| python gear_sonic/scripts/run_data_exporter.py --task-prompt "pick up the cup" | |
| ``` | |
| **Terminal 5 (optional) β Camera Viewer:** | |
| ```bash | |
| source .venv_data_collection/bin/activate | |
| python gear_sonic/scripts/run_camera_viewer.py | |
| ``` | |
| All options are provided via CLI flags β no interactive prompts. Key flags: | |
| | Flag | Default | Description | | |
| |---|---|---| | |
| | `--task-prompt` | `"demo"` | Language task description for this session | | |
| | `--dataset-name` | *(auto: timestamp)* | Dataset name. Omit to create a new one, or pass an existing name to append episodes | | |
| | `--data-collection-frequency` | `50` | Recording frequency (Hz) | | |
| | `--root-output-dir` | `outputs` | Parent directory for saved datasets | | |
| ```{tip} | |
| Datasets are saved under `<root-output-dir>/<dataset-name>/`. If `--dataset-name` | |
| is not specified, a timestamped name is generated automatically. | |
| ``` | |
| ### Recording Controls | |
| There are two ways to control recording: **PICO VR controllers** (recommended during teleop) or **keyboard over ZMQ**. | |
| **PICO VR Controllers (via `manager_state` topic):** | |
| | Input | Action | | |
| |---|---| | |
| | **Left Grip + A** | **Toggle** recording β starts a new episode, or stops and saves the current one | | |
| | **Left Grip + B** | **Discard** the current episode (saved to disk but flagged for removal during post-processing) | | |
| These buttons work in any manager mode (POSE, PLANNER, etc.) and are independent of the mode-switching controls. | |
| **Keyboard over ZMQ:** | |
| | Key | Action | | |
| |---|---| | |
| | `c` | **Toggle** recording (same as Left Grip + A) | | |
| | `x` | **Discard** episode (same as Left Grip + B β flagged for removal) | | |
| ```{note} | |
| Keyboard commands are sent via a separate ZMQ publisher (default port `5580`). The data exporter subscribes to this channel automatically. You can send keys from any ZMQ publisher on that port, or integrate with the C++ deployment's keyboard handler. | |
| ``` | |
| --- | |
| ## Camera Viewer | |
| A standalone camera viewer is available for monitoring camera feeds and recording raw video independently of the data exporter. | |
| ```bash | |
| source .venv_data_collection/bin/activate | |
| python gear_sonic/scripts/run_camera_viewer.py --camera-host localhost --camera-port 5555 | |
| ``` | |
| The viewer connects to the same ZMQ camera server used by the data exporter and displays all detected camera streams in a tiled OpenCV window. | |
| **Controls** (OpenCV window must be focused): | |
| | Key | Action | | |
| |---|---| | |
| | `R` | Start/stop video recording | | |
| | `Q` | Quit | | |
| Recordings are saved to `camera_recordings/rec_<timestamp>/` with one MP4 per camera stream. This is useful for: | |
| - Verifying camera placement and image quality before starting data collection | |
| - Recording reference videos alongside the LeRobot dataset | |
| - Debugging camera server connectivity | |
| Run `python gear_sonic/scripts/run_camera_viewer.py --help` for all options. | |
| --- | |
| ## CLI Options | |
| All options can be viewed with `--help`: | |
| ```bash | |
| python gear_sonic/scripts/run_data_exporter.py --help | |
| ``` | |
| Key options: | |
| | Flag | Default | Description | | |
| |---|---|---| | |
| | `--task-prompt` | `"demo"` | Language task description for annotation | | |
| | `--dataset-name` | *(auto: timestamp)* | Dataset name; omit to auto-generate, or reuse an existing name to append | | |
| | `--data-collection-frequency` | `50` | Recording frequency in Hz | | |
| | `--camera-host` | `localhost` | Camera server hostname | | |
| | `--camera-port` | `5555` | Camera server port | | |
| | `--sonic-zmq-host` | `localhost` | SMPL pose publisher host | | |
| | `--sonic-zmq-port` | `5556` | SMPL pose publisher port | | |
| | `--state-zmq-host` | `localhost` | Robot state publisher host | | |
| | `--state-zmq-port` | `5557` | Robot state publisher port | | |
| | `--root-output-dir` | `outputs` | Root directory for saved datasets | | |
| | `--text-to-speech / --no-text-to-speech` | `True` | Voice feedback via espeak | | |
| --- | |
| ## Output Format | |
| Datasets are saved in the [LeRobot v2.1](https://github.com/huggingface/lerobot) format under `<root-output-dir>/<dataset-name>/`: | |
| ```text | |
| outputs/2026-04-03-14-30-00-G1-robot01/ | |
| βββ data/ | |
| β βββ train-00000.parquet # Tabular data (joint states, actions, annotations) | |
| β βββ ... | |
| βββ videos/ | |
| β βββ observation.images.ego_view/ | |
| β β βββ episode_000000.mp4 # H264-encoded ego camera video | |
| β β βββ ... | |
| β βββ observation.images.left_wrist/ # (only with --record-wrist-cameras) | |
| β βββ observation.images.right_wrist/ # (only with --record-wrist-cameras) | |
| βββ meta/ | |
| βββ info.json # Dataset metadata (fps, features, sizes) | |
| βββ modality.json # GR00T modality configuration | |
| βββ episodes.jsonl # Per-episode metadata | |
| βββ tasks.jsonl # Task prompt definitions | |
| ``` | |
| ### Recorded Data Channels | |
| Each frame contains: | |
| | Feature | Shape | Description | | |
| |---|---|---| | |
| | `observation.state.joint_position` | `(N,)` | Actuated joint positions (rad) | | |
| | `observation.state.joint_velocity` | `(N,)` | Actuated joint velocities (rad/s) | | |
| | `observation.state.body_rotation_6d` | `(6,)` | Base orientation (6D rotation) | | |
| | `observation.state.projected_gravity` | `(3,)` | Gravity vector in body frame | | |
| | `observation.images.ego_view` | `(480, 640, 3)` | Ego camera image (saved as MP4 video) | | |
| | `observation.images.left_wrist` | `(480, 640, 3)` | Left wrist camera (only with `--record-wrist-cameras`) | | |
| | `observation.images.right_wrist` | `(480, 640, 3)` | Right wrist camera (only with `--record-wrist-cameras`) | | |
| | `action.joint_position` | `(N,)` | Teleop target joint positions | | |
| | `action.body_rotation_6d` | `(6,)` | Teleop target body rotation | | |
| | `annotation.human.action.task_description` | string | Task prompt for this frame | | |
| --- | |
| ## Post-Processing Datasets | |
| After recording, you can clean and merge datasets using the processing script. | |
| All commands below run in the **data collection virtual environment**: | |
| ```bash | |
| source .venv_data_collection/bin/activate | |
| ``` | |
| ### Remove Discarded Episodes | |
| Episodes discarded during collection (`x` key or Left Grip + B) are saved to disk | |
| but flagged in `meta/info.json`. By default, the processing script removes these | |
| flagged episodes so they are excluded from fine-tuning: | |
| ```bash | |
| # Clean a single dataset (removes discarded episodes + stale SMPL frames) | |
| python gear_sonic/scripts/process_dataset.py \ | |
| --dataset-path outputs/my_dataset \ | |
| --output-path outputs/my_dataset_cleaned | |
| ``` | |
| To keep discarded episodes (e.g., for inspection), pass `--no-remove-discarded`. | |
| ### Remove Stale SMPL Frames | |
| Teleop pauses or ZMQ frame drops create frames where `teleop.smpl_pose` is all | |
| zeros. The processing script detects these and also removes consecutive | |
| frozen (identical) lead-in frames that precede them: | |
| ```bash | |
| # Clean a single dataset in-place | |
| python gear_sonic/scripts/process_dataset.py \ | |
| --dataset-path outputs/my_dataset | |
| # Clean and write to a new directory (non-destructive) | |
| python gear_sonic/scripts/process_dataset.py \ | |
| --dataset-path outputs/my_dataset \ | |
| --output-path outputs/my_dataset_cleaned | |
| ``` | |
| ```{warning} | |
| If you collected data using **VR 3-point tracking mode** (VR_3PT), the | |
| `teleop.smpl_pose` column will be all zeros because VR_3PT uses raw VR | |
| positions/orientations instead of SMPL body parameters. In this case, you | |
| **must** disable SMPL cleaning to avoid dropping all frames: | |
| python gear_sonic/scripts/process_dataset.py \ | |
| --dataset-path outputs/my_dataset \ | |
| --output-path outputs/my_dataset_cleaned \ | |
| --no-remove-stale-smpl | |
| ``` | |
| ### Merge Multiple Datasets | |
| Combine several recording sessions into a single dataset. The script | |
| validates that all sessions share the same `script_config` (robot | |
| configuration) before merging: | |
| ```bash | |
| # Merge by listing datasets on the command line | |
| python gear_sonic/scripts/process_dataset.py \ | |
| --dataset-path outputs/session1 outputs/session2 outputs/session3 \ | |
| --output-path outputs/merged_dataset | |
| # Or use a text file (one dataset path per line, # for comments) | |
| python gear_sonic/scripts/process_dataset.py \ | |
| --dataset-list datasets.txt \ | |
| --output-path outputs/merged_dataset | |
| ``` | |
| SMPL cleaning is applied by default during merging. When enabled, the script | |
| removes entire frames where the SMPL teleop pose is stuck at zeros β this | |
| happens during operator pauses or ZMQ packet-drop periods where the SMPL | |
| stream stops updating. Consecutive frozen (identical) frames that lead into | |
| a zero block are also removed, since they represent stale data right before | |
| the dropout. To skip this cleaning and merge only, add `--no-remove-stale-smpl`. | |
| --- | |
| ## Next Steps: Fine-tune and Deploy | |
| The output dataset is directly compatible with the [Isaac-GR00T](https://github.com/NVIDIA/Isaac-GR00T) post-training pipeline. To fine-tune a VLA model on your collected data and deploy it for autonomous inference, see the [VLA Workflow tutorial](vla_workflow.md). | |