教程 · 命令逐字照录
SONIC 数据采集:给 VLA 的 LeRobot 数据集
把遥操作演示录成 LeRobot 数据集,供 Isaac-GR00T 后训练使用。数据导出器与 SONIC 部署和 VR 遥操作栈并行运行,按可配置频率捕获机器人状态、SMPL 遥操作姿态与相机图像。所有命令逐字摘自官方 Data Collection 教程。
部署模型
前置要求:完成 Quick Start(sim2sim 循环,包括部署安装与模型 checkpoint 下载)、完成 VR Teleop Setup(PICO 硬件已标定、.venv_teleop 就绪),并让相机服务器在机器人上运行。仿真时,MuJoCo 仿真循环自动发布摄像头图像——无需相机服务器。
支持的相机
经过测试与支持的相机配置使用 Luxonis OAK 相机(OAK-D、OAK-1 等):一个头部/第一视角 OAK 相机,加可选的 OAK 腕部相机。其他相机驱动(RealSense、USB 摄像头)在代码库里,但最近没测过。头部/第一视角 OAK-D W 相机的 3D 打印支架在 hardware/camera_mount/ 下——README 覆盖打印设置、物料清单以及如何装到 G1 上。
一次性设置(工作站)
从仓库根目录运行安装脚本,创建带全部数据采集依赖(LeRobot、PyAV、OpenCV 等)的专用虚拟环境:
bash install_scripts/install_data_collection.sh 这会用 uv 基于 Python 3.10 创建 .venv_data_collection,安装 gear_sonic[data_collection](lerobot、av、opencv-python 等包)加上 espeak(系统包)用于录制时的语音反馈。这个环境与 .venv_teleop、.venv_sim 相互独立——数据导出器有遥操作和仿真用不到的更重的 ML 依赖。
相机服务器设置(机器人侧)
相机服务器是唯一运行在机器人计算机上(如 Jetson Orin)的组件。其他所有组件——C++ 部署、PICO 遥操作流式程序、数据导出器与相机查看器——都运行在你的工作站上。它从物理连接在机器人上的 OAK 相机捕获帧,并通过 ZMQ 发布。
git clone https://github.com/NVlabs/GR00T-WholeBodyControl.git
cd GR00T-WholeBodyControl bash install_scripts/install_camera_server.sh 脚本创建带 gear_sonic[camera](DepthAI、ZMQ、msgpack、OpenCV、tyro)的 .venv_camera,检测连接的 OAK 相机并列出它们的 MxID,逐个提示每个相机的位置(第一视角,可选左/右腕)与设备 ID,然后询问是否把相机服务器装成 systemd 服务(推荐)——回答 y 会自动生成 unit 文件、安装、启用并启动。验证:
sudo systemctl status composed_camera_server.service
journalctl -u composed_camera_server.service -f 手动替代:在 .venv_camera 里用 python -c "import depthai as dai; print(dai.Device.getAllAvailableDevices())" 找设备 ID,然后用 python -m gear_sonic.camera.composed_camera --ego-view-camera oak --ego-view-device-id <YOUR_MXID> --port 5555 启动服务器(腕部相机加 --left-wrist-camera / --right-wrist-camera 标志;--fps、--use-mjpeg、--mjpeg-quality 见 --help)。手动 systemd:编辑 systemd/composed_camera_server.service,复制到 /etc/systemd/system/,然后 daemon-reload + enable + start。G1 机器人的默认 IP 是 192.168.123.164。
ZMQ 消息格式
相机服务器每个帧周期发布一个包含所有相机图像的 msgpack 编码负载:
{
"timestamps": { "ego_view": 1712345678.123, "left_wrist": 1712345678.125 },
"images": { "ego_view": "<base64-jpeg>", "left_wrist": "<base64-jpeg>" }
} 图像经 JPEG 压缩(质量 80),以 base64 编码字符串或原始 JPEG 字节(启用 MJPEG 设备端编码时)传输。数据导出器的 ComposedCameraClientSensor 自动处理两种格式。
架构与 ZMQ 数据源
| 数据源 | 运行在 | ZMQ 话题 | 默认端口 | 提供 |
|---|---|---|---|---|
| C++ 部署 | 工作站 | g1_debug | 5557 | 关节位置、速度、IMU 四元数 |
| C++ 部署 | 工作站 | robot_config | 5557 | 启动时的一次性机器人配置 |
| PICO 遥操作流式程序 | 工作站 | pose | 5556 | SMPL 身体参数(遥操作目标姿态) |
| 相机服务器 | 机器人 | (原始 TCP) | 5555 | JPEG 压缩的相机图像(第一视角 + 可选腕部视角) |
数据导出器订阅全部三个 ZMQ 数据源——5557 端口的部署状态、5556 的 SMPL 遥操作姿态、5555 的相机图像——并写出 LeRobot 数据集(parquet + mp4)。
方案 A · 一体化 tmux 启动器(推荐)
启动器在单个 tmux 会话里启动全部组件,共四个窗格:C++ Deploy、PICO Teleop、Data Exporter、Camera Viewer(需要 tmux:sudo apt install tmux)。仿真(启动器会在单独的 tmux 窗口自动启动 run_sim_loop.py):
python gear_sonic/scripts/launch_data_collection.py --sim 真机(相机服务器运行在 192.168.123.164 的机器人上):
python gear_sonic/scripts/launch_data_collection.py \
--camera-host 192.168.123.164 \
--task-prompt "pick up the cup" 带腕部相机(录制第一视角 + 左/右腕流):
python gear_sonic/scripts/launch_data_collection.py \
--camera-host 192.168.123.164 \
--task-prompt "pick up the cup" \
--record-wrist-cameras 无需先激活虚拟环境——如果当前 Python 缺必要依赖,启动器会自动检测并使用 .venv_data_collection。常用标志:--task-prompt(默认 "demo")、--dataset-name(默认:时间戳)、--sim / --no-sim、--camera-host(默认 localhost)、--camera-port(5555)、--data-exporter-frequency(50)、--deploy-checkpoint、--deploy-obs-config、--deploy-planner、--deploy-motion-data、--record-wrist-cameras、--no-text-to-speech。会话管理:Ctrl+b 加方向键切换窗格,Ctrl+b 加 d 分离,tmux attach -t sonic_data_collection 重新接入,tmux kill-session -t sonic_data_collection 结束。
录制控制:PICO VR 手柄——Left Grip + A 切换录制(开始新 episode 或停止并保存),Left Grip + B 丢弃当前 episode(会存到磁盘,但在后处理时标记为移除)。键盘经 ZMQ(端口 5580):c 切换录制,x 丢弃该 episode。这些在任何 manager 模式(POSE、PLANNER 等)下都有效。
方案 B · 手动多终端设置
终端 1 —— MuJoCo 仿真器(真机跳过):
source .venv_sim/bin/activate
python gear_sonic/scripts/run_sim_loop.py \
--enable-image-publish --enable-offscreen --camera-port 5555 终端 2 —— C++ 部署(在 gear_sonic_deploy/ 里):
cd gear_sonic_deploy
source scripts/setup_env.sh
./deploy.sh --input-type zmq_manager sim
# Wait until you see "Init done" 终端 3 —— PICO 遥操作流式程序:
source .venv_teleop/bin/activate
python gear_sonic/scripts/pico_manager_thread_server.py --manager 终端 4 —— 数据导出器:
source .venv_data_collection/bin/activate
python gear_sonic/scripts/run_data_exporter.py --task-prompt "pick up the cup" 终端 5(可选)—— 相机查看器:在 .venv_data_collection 里运行 python gear_sonic/scripts/run_camera_viewer.py。数据集保存在 <root-output-dir>/<dataset-name>/(默认根目录 outputs);省略 --dataset-name 用自动时间戳,或复用名字来追加 episode。独立相机查看器还录制原始 MP4 参考视频(R 开始/停止,Q 退出)到 camera_recordings/rec_<timestamp>/。
录制的数据通道
| 特征 | 形状 | 描述 |
|---|---|---|
observation.state.joint_position | (N,) | 被驱动的关节位置(弧度) |
observation.state.joint_velocity | (N,) | 被驱动的关节速度(弧度/秒) |
observation.state.body_rotation_6d | (6,) | 基座朝向(6D 旋转) |
observation.state.projected_gravity | (3,) | body 系下的重力向量 |
observation.images.ego_view | (480, 640, 3) | 第一视角相机图像(存为 MP4 视频) |
observation.images.left_wrist | (480, 640, 3) | 左腕相机(仅 --record-wrist-cameras 时) |
observation.images.right_wrist | (480, 640, 3) | 右腕相机(仅 --record-wrist-cameras 时) |
action.joint_position | (N,) | 遥操作目标关节位置 |
action.body_rotation_6d | (6,) | 遥操作目标 body 朝向 |
annotation.human.action.task_description | string | 本帧的任务提示 |
数据集按 LeRobot v2.1 格式保存在 <root-output-dir>/<dataset-name>/:data/(parquet:关节状态、动作、标注)、videos/(每路相机流 H264 编码的 MP4)、meta/(info.json、modality.json、episodes.jsonl、tasks.jsonl)。
数据集后处理
所有命令在 .venv_data_collection 里运行。移除被丢弃的 episode(用 x 或 Left Grip + B 标记)——默认行为会移除它们,确保不进入微调;传 --no-remove-discarded 保留供检查:
# 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 移除过期 SMPL 帧——遥操作暂停或 ZMQ 丢帧会产生 teleop.smpl_pose 全为零的帧;脚本还会移除它们前面连续冻结(相同)的引入帧。可原地或非破坏处理:
# 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 teleop.smpl_pose 全是零,因为 VR_3PT 用原始 VR 位置/朝向而不是 SMPL 身体参数。你必须禁用 SMPL 清理,否则会丢光所有帧:
python gear_sonic/scripts/process_dataset.py \
--dataset-path outputs/my_dataset \
--output-path outputs/my_dataset_cleaned \
--no-remove-stale-smpl 合并多个数据集(会验证所有会话共享相同的 script_config 机器人配置):
# 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 清理在合并时默认生效——它会移除 SMPL 遥操作姿态卡在零的整帧(操作员暂停、ZMQ 丢包时段),外加进入零段前的连续冻结帧。加 --no-remove-stale-smpl 跳过清理只合并。输出数据集直接兼容 Isaac-GR00T 后训练管线——下一步是VLA 全流程。
BONES-SEED:离线动作语料
除了你自己的遥操作演示,训练数据栈还构建在 BONES-SEED 之上——一个开放数据集,包含 142,220 段带标注的人体动作动画(71,132 原始 + 71,088 镜像,120 fps 下约 288 小时),来自 522 位演员,带自然语言描述与时间分段,提供 SOMA 与 Unitree G1 两种格式。每段动作有三种格式:SOMA Proportional(BVH)、SOMA Uniform(BVH)与重定向到 G1 人形机器人的 Unitree G1(CSV)。下载:
# Using the Hugging Face CLI
pip install huggingface_hub
huggingface-cli download bones-studio/seed --repo-type dataset --local-dir ./bones-seed SONIC 训练时,G1 CSV 用 convert_soma_csv_to_motion_lib.py(--fps 30 --fps_source 120)转换、用 filter_and_copy_bones_data.py 过滤,然后通过 --training Hugging Face 下载消费 SMPL 数据——完整命令在训练页与 Training Data 文档里。