wholebody-vlaGR00TSONICPICOLeRobotVLAZMQUnitree G1teleoperationhumanoid

Teleop PICO và dữ liệu LeRobot cho VLA

Hướng dẫn luồng PICO teleop, zmq_manager, data exporter và LeRobot v2.1 cho VLA trên SONIC.

Nguyễn Anh Tuấn13 tháng 6, 202615 phút đọc
Teleop PICO và dữ liệu LeRobot cho VLA

Trong bài 4, chúng ta đã đi qua lớp C++ deployment: ONNX, TensorRT, ZMQ output và vòng điều khiển thời gian thực. Bài 5 nối lớp đó với phần rất quan trọng cho VLA: teleoperation bằng PICO VR và pipeline ghi dữ liệu LeRobot. Nếu bài 4 trả lời câu hỏi "policy chạy trên robot như thế nào?", bài này trả lời câu hỏi "ta thu demo người điều khiển như thế nào để sau đó fine-tune VLA?".

Điểm hay của SONIC là VLA không cần học trực tiếp toàn bộ low-level joint control từ đầu. Tài liệu VLA workflow của NVlabs mô tả cách VLA dự đoán latent motion token 64 chiều cùng 7 khớp tay trái và 7 khớp tay phải, còn SONIC decoder xử lý điều khiển toàn thân ở 50 Hz. Vì vậy, dữ liệu teleop không chỉ là video và joint state. Nó còn là cầu nối giữa ngôn ngữ task, camera ego-view, trạng thái robot, motion token, SMPL pose, planner command và action tay.

Nguồn kỹ thuật nên mở song song:

Nguồn Dùng để kiểm tra gì
Data Collection for VLA Lệnh tmux/manual, cổng 5555/5556/5557, camera viewer, output LeRobot
VLA Workflow Cách dữ liệu teleop đi tới fine-tune Isaac-GR00T N1.7 và latent action interface
install_pico.sh Cài .venv_teleop, Python 3.10, gear_sonic[teleop], XRoboToolkit
pico_manager_thread_server.py POSE/PLANNER/VR_3PT, combo PICO, ZMQ port 5556/5557
launch_data_collection.py Launcher tmux dùng --input-type zmq_manager
run_data_exporter.py Ghi frame, nhận camera, SMPL pose, robot state và tạo dataset
GR00T LeRobot v2 data format Layout data/, videos/, meta/info.json, modality.json, tasks.jsonl

Nếu bạn mới đọc series, nên quay lại bài 1 về kiến trúc SONIC để hiểu encoder-decoder-token, rồi đọc bài 3 về dữ liệu và training để thấy vì sao SMPL, motion library và token state cùng xuất hiện trong pipeline này. Ngoài series, hai bài LeRobot cho humanoid G1fine-tune VLA hai tay là bối cảnh tốt cho phần dataset.

Demo PICO VR teleoperation walking trên humanoid - nguồn: repo NVlabs/GR00T-WholeBodyControl
Demo PICO VR teleoperation walking trên humanoid - nguồn: repo NVlabs/GR00T-WholeBodyControl

1. Bức tranh tổng thể: teleop không chỉ là remote control

Với robot công nghiệp truyền thống, "teleop" thường có nghĩa là người điều khiển gửi vận tốc hoặc pose target trực tiếp. Với SONIC, teleop có thêm một mục tiêu: tạo ra demonstration có thể học được. Một phiên thu dữ liệu tốt phải đồng bộ ít nhất bốn dòng dữ liệu:

Dòng dữ liệu Nguồn Đi vào dataset để làm gì
Camera ego-view Camera server hoặc MuJoCo image publisher, port 5555 Observation hình ảnh cho VLA
PICO/SMPL/VR pose pico_manager_thread_server.py, port 5556 Action intent, SMPL pose, wrist/hand target, stream mode
Robot state C++ deploy g1_debug, port 5557 Proprioception, action WBC, root orientation, token state
Task prompt CLI --task-prompt Annotation ngôn ngữ trong tasks.jsonl và parquet

Điểm quan trọng là PICO không điều khiển motor trực tiếp. PICO gửi pose, planner command hoặc VR 3-point target qua ZMQ. C++ deploy chạy với --input-type zmq_manager, nhận command đó, đưa qua SONIC policy/planner và phát motor command. Song song, data exporter cũng subscribe các topic ZMQ để ghi lại cùng một thời điểm robot nhìn gì, robot đang ở trạng thái nào, người đang ra lệnh gì và SONIC đang tạo action gì.

Một sơ đồ tối giản:

PICO headset + controllers
        |
        v
pico_manager_thread_server.py  -- PUB tcp://*:5556
        |                         topics: pose, planner, manager_state
        +---------------------> C++ deploy --input-type zmq_manager
        |                         publishes g1_debug + robot_config on 5557
        v
run_data_exporter.py <--------- camera server on 5555
        |
        v
LeRobot v2.1 dataset: parquet + MP4 + meta/*.json

Trong workflow này, --input-type zmq_manager là lựa chọn đúng cho thu dữ liệu VLA vì nó nói với C++ deployment rằng input không đến từ keyboard hay gamepad cục bộ, mà đến từ một "manager" ZMQ biết chuyển mode giữa POSE, PLANNER và VR_3PT. Nếu bạn chạy sai input type, PICO streamer có thể vẫn publish dữ liệu, exporter vẫn ghi được một số tín hiệu, nhưng policy không nhận command đúng đường.

2. install_pico.sh: môi trường teleop riêng cho PICO

Script install_scripts/install_pico.sh không chỉ pip install một package. Nó dựng một môi trường riêng .venv_teleop để PICO teleop có đúng Python, native SDK và dependency. Luồng chính của script là:

  1. Phát hiện kiến trúc bằng uname -m, ví dụ x86_64 trên workstation hoặc aarch64 trên Jetson Orin.
  2. Cài uv nếu máy chưa có.
  3. Cài Python 3.10 do uv quản lý, có development headers.
  4. Xóa .venv_teleop cũ, tạo venv mới với prompt gear_sonic_teleop.
  5. Cài gear_sonic[teleop].
  6. Cài cmake, pybind11, setuptools, rồi cài XRoboToolkit SDK.
  7. Nếu chạy trên aarch64 và thiếu native library, script build PXREARobotSDK từ branch orin.
  8. Trên desktop hoặc máy không phải onboard Jetson user unitree, script cài thêm gear_sonic[sim]unitree_sdk2_python để hỗ trợ sim bridge.

Đây là một chi tiết beginner hay bỏ qua: PICO teleop cần XRoboToolkit native SDK, không chỉ Python wheel. Nếu bạn thấy lỗi import xrobotoolkit_sdk, hoặc PICO không có body data, hãy kiểm tra lại script cài teleop trước khi debug policy. Lệnh chuẩn từ repo root là:

bash install_scripts/install_pico.sh
source .venv_teleop/bin/activate
python gear_sonic/scripts/pico_manager_thread_server.py --manager

Trên robot thật, PICO, workstation và G1 thường phải ở cùng mạng ổn định. Tài liệu data collection nhắc đến IP mặc định của G1 là 192.168.123.164 khi workstation kết nối camera server trên robot. Với teleop, độ trễ mạng không chỉ làm video chậm; nó còn làm command pose và dataset mất đồng bộ.

3. Ba cổng ZMQ cần nhớ: 5555, 5556, 5557

Trong stack này, ba port mặc định có vai trò rất rõ:

Port Producer Consumer Nội dung
5555 Camera server hoặc run_sim_loop.py --enable-image-publish run_data_exporter.py, run_camera_viewer.py Frame camera, thường có ego_view, có thể thêm wrist camera
5556 pico_manager_thread_server.py C++ deploy và data exporter Topic pose, planner, manager_state
5557 C++ deploy zmq_output_handler data exporter, PICO planner feedback Topic g1_debug, robot_config

run_data_exporter.py ghi rõ nó không phụ thuộc ROS 2: robot state đến từ topic g1_debug trên port 5557, SMPL pose đến từ topic pose trên port 5556, và camera đến qua ComposedCameraClientSensor. Robot config được đọc từ topic robot_config trên cùng socket state. Nếu exporter không nhận được robot_config, nó không biết cấu hình robot đủ chắc để ghi metadata đúng.

Trong simulation, docs dùng:

python gear_sonic/scripts/run_sim_loop.py \
  --enable-image-publish --enable-offscreen --camera-port 5555

Trong deployment, pane C++ thường chạy:

cd gear_sonic_deploy
./deploy.sh --input-type zmq_manager sim

Với robot thật và camera server trên G1:

python gear_sonic/scripts/run_data_exporter.py \
  --task-prompt "pick up the cup" \
  --camera-host 192.168.123.164 \
  --camera-port 5555

Nếu chỉ muốn xem camera trước khi record, dùng:

python gear_sonic/scripts/run_camera_viewer.py \
  --camera-host localhost \
  --camera-port 5555

Camera viewer không ghi dataset LeRobot. Nó hiển thị các stream camera trong một cửa sổ OpenCV, phím R để start/stop record MP4 thô và Q để thoát. Đây là bước rất nên làm trước khi thu demo thật: kiểm tra exposure, góc nhìn ego-view, độ rung, frame drop và việc wrist camera có thực sự xuất hiện hay không.

4. PICO manager: POSE, PLANNER và VR_3PT

Trong pico_manager_thread_server.py, StreamMode có các giá trị:

Mode Giá trị Ý nghĩa thực tế
OFF 0 Không stream command điều khiển policy
POSE 1 Stream full SMPL/body pose từ PICO để SONIC tracking
PLANNER 2 Dùng joystick/controller để điều khiển locomotion planner
PLANNER_FROZEN_UPPER_BODY 3 Planner di chuyển thân dưới, giữ mục tiêu upper body đã chốt
POSE_PAUSE 4 Tạm pause pose khi giữ left menu, thả ra quay lại POSE
PLANNER_VR_3PT 5 Planner cho locomotion, VR 3 điểm cho upper body

Tên user thường gọi "VR_3PT" thực chất là PLANNER_VR_3PT: robot vẫn cần planner để đi, còn upper body nhận ba keypoint VR. Code _process_3pt_pose() lấy Root/Pelvis, Left Wrist, Right Wrist và Neck từ SMPL joints, chuyển từ Unity frame sang robot frame, áp offset rotation, rồi trả về ba keypoint không tính root. Ghi chú trong code nói Neck được dùng thay Head vì ổn định hơn cho hướng thân trên.

Các combo PICO quan trọng:

Combo Tác dụng
A+B+X+Y Khi đang OFF, start policy vào PLANNER; khi đang chạy, emergency stop về OFF
A+X Toggle giữa POSEPLANNER theo chain chính
B+Y Toggle giữa POSEPLANNER_FROZEN_UPPER_BODY
Left axis click Vào hoặc thoát PLANNER_VR_3PT từ mode planner hiện tại
Left menu hold Trong POSE, chuyển sang POSE_PAUSE; thả ra quay lại POSE
Left Grip + A Toggle recording episode
Left Grip + B Đánh dấu abort/discard episode

Trong planner loop còn có combo A+B để tăng locomotion mode và X+Y để giảm locomotion mode. Danh sách mode gồm IDLE, SLOW_WALK, WALK, RUN, các tư thế kneel/lie/crawl, boxing, hook, jump, stealth walk và injured walk. Joystick điều khiển hướng, vận tốc, facing và height. Từ góc nhìn operator, đây là cách tách việc: controller PICO vừa là công tắc mode, vừa là nguồn pose, vừa là remote locomotion.

Tổng quan SONIC: nhiều nguồn motion và VLA đi qua universal token interface - nguồn: project page NVlabs GEAR-SONIC
Tổng quan SONIC: nhiều nguồn motion và VLA đi qua universal token interface - nguồn: project page NVlabs GEAR-SONIC

5. Thu dữ liệu bằng launcher tmux

launch_data_collection.py là script tiện nhất khi bạn muốn chạy cả stack trong một session tmux. Config mặc định của nó rất đáng chú ý: deploy_input_typezmq_manager, pico_manager bật, camera_viewer bật và camera_port5555. Với simulation:

python gear_sonic/scripts/launch_data_collection.py --sim

Launcher sẽ tạo session sonic_data_collection, mở pane cho C++ deploy, PICO manager, data exporter, camera viewer, và nếu --sim được truyền thì thêm window MuJoCo simulator. Tài liệu chính thức cũng nhắc rằng launcher tự dùng .venv_data_collection khi dependency chưa có trong Python hiện tại, nên bạn không nhất thiết phải activate venv trước.

Với robot thật:

python gear_sonic/scripts/launch_data_collection.py \
  --camera-host 192.168.123.164 \
  --task-prompt "pick up the cup"

Nếu có wrist camera:

python gear_sonic/scripts/launch_data_collection.py \
  --camera-host 192.168.123.164 \
  --task-prompt "pick up the cup" \
  --record-wrist-cameras

Một điều thực tế: C++ deploy pane có thể chờ xác nhận trước khi robot bắt đầu control. Đừng record ngay khi tmux vừa mở. Hãy đợi C++ báo init xong, kiểm tra camera viewer có frame, PICO manager thấy body data, rồi mới dùng Left Grip + A để mở episode. Nếu cần detach session, dùng Ctrl+b rồi d; reattach bằng tmux attach -t sonic_data_collection.

VR 3-point teleoperation cho thao tác đồ vật - nguồn: project page NVlabs GEAR-SONIC

6. run_data_exporter.py: một frame LeRobot gồm những gì?

Exporter chạy ở --data-collection-frequency 50 Hz mặc định. Mỗi vòng, nó poll state ZMQ, poll PICO ZMQ, kiểm tra recording command, đọc camera và thêm một frame vào Gr00tDataExporter.

Các field quan trọng:

Field Nguồn Ý nghĩa
observation.images.ego_view Camera Ảnh chính cho VLA
observation.state Robot model + g1_debug Cấu hình toàn robot, gồm body và hands
observation.eef_state Forward kinematics Pose hai wrist, mỗi bên position + quaternion
action.wbc Last action từ SONIC/C++ Action toàn thân sau WBC
action.motion_token token_state nếu có Latent motion token 64 chiều
teleop.smpl_joints PICO pose mode 24 joints x 3, flatten thành 72
teleop.smpl_pose PICO pose mode SMPL body pose 63 chiều
teleop.stream_mode manager_state Biết frame thuộc POSE, PLANNER hay VR_3PT
teleop.left_hand_joints, teleop.right_hand_joints PICO trigger/grip hoặc planner message Action tay 7 chiều mỗi bên
teleop.vr_3pt_position, teleop.vr_3pt_orientation VR_3PT Ba keypoint và orientation cho upper body

Exporter chỉ dùng SMPL pose khi stream mode là POSE hoặc POSE_PAUSE và message chưa stale. Code có ngưỡng khoảng 100 ms cho SMPL pose; nếu quá cũ, nó ghi zeros để tránh đưa pose lỗi vào dataset. Với PLANNER_VR_3PT, exporter dùng planner message và có ngưỡng khoảng 200 ms. Đây là lý do sau khi thu xong cần chạy process_dataset.py: frame stale hoặc episode bị abort vẫn có thể nằm trên đĩa.

Recording có hai lớp điều khiển. Từ PICO, Left Grip + A toggle record; Left Grip + B đánh dấu discard. Từ keyboard ZMQ, key c toggle recording và key x discard episode qua port 5580. Trong thực tế, PICO combo tiện hơn vì operator không cần rời tay khỏi controller.

7. Output LeRobot v2.1: parquet, MP4 và metadata

Tài liệu data collection nói dataset được lưu dưới <root-output-dir>/<dataset-name>/, mặc định là outputs/<timestamp>/. Layout thực tế theo LeRobot v2.1/GR00T LeRobot gồm dữ liệu bảng, video và metadata:

outputs/my_dataset/
├── data/
│   └── chunk-000/
│       ├── episode_000000.parquet
│       └── episode_000001.parquet
├── videos/
│   └── chunk-000/
│       └── observation.images.ego_view/
│           ├── episode_000000.mp4
│           └── episode_000001.mp4
└── meta/
    ├── info.json
    ├── modality.json
    ├── episodes.jsonl
    └── tasks.jsonl

Một số docs của exporter cũ có thể hiển thị dạng data/train-00000.parquet, nhưng tài liệu GR00T LeRobot v2 và code process_dataset.py đều xử lý pattern chunked data/chunk-{episode_chunk:03d}/episode_{episode_index:06d}.parquet và video videos/.../episode_*.mp4. Khi đọc dataset, hãy tin meta/info.json vì nó chứa path pattern và feature schema.

Ý nghĩa từng file:

File Vai trò
episode_*.parquet Mỗi row là một frame: state, action, timestamp, episode index, task index, annotation
episode_*.mp4 Video camera đã encode, thường H264/MP4 cho ego view và optional wrist cameras
meta/info.json FPS, feature schema, tổng frame/episode, path template, script_config, có thể có discarded_episode_indices
meta/modality.json Metadata GR00T-specific để tách các mảng state/action thành field có nghĩa
meta/tasks.jsonl Mapping task_index sang mô tả ngôn ngữ, ví dụ "pick up the cup"
meta/episodes.jsonl Metadata từng episode: độ dài, task, index

modality.json đặc biệt quan trọng với GR00T. Trong LeRobot chuẩn, state/action có thể là mảng nối. GR00T cần biết đoạn nào là left leg, right leg, wrist pose, root orientation, motion token, SMPL pose, planner movement, VR 3-point orientation. File features_sonic_vla.py tạo modality config này từ RobotModel, không hardcode mọi thứ bằng tay. Nếu bạn copy parquet mà quên meta/modality.json, training có thể load file nhưng hiểu sai ý nghĩa từng dimension.

8. process_dataset.py: dọn trước khi fine-tune

Sau khi thu demo, đừng đưa ngay vào fine-tune. process_dataset.py làm ba việc chính:

  1. Xóa episode bị đánh dấu discard trong meta/info.json.
  2. Xóa frame có teleop.smpl_pose toàn zeros và các frame "đứng hình" ngay trước đó.
  3. Gộp nhiều session thành một dataset, nếu script_config khớp.

Lệnh dọn một dataset và ghi ra thư mục mới:

python gear_sonic/scripts/process_dataset.py \
  --dataset-path outputs/my_dataset \
  --output-path outputs/my_dataset_cleaned

Nếu muốn xử lý tại chỗ:

python gear_sonic/scripts/process_dataset.py \
  --dataset-path outputs/my_dataset

Nếu thu bằng VR_3PT, cần chú ý cảnh báo trong docs: teleop.smpl_pose sẽ toàn zeros vì VR_3PT dùng raw VR positions/orientations thay vì SMPL body parameters. Nếu vẫn bật stale SMPL cleaning, script có thể drop toàn bộ frame. Khi đó dùng:

python gear_sonic/scripts/process_dataset.py \
  --dataset-path outputs/my_dataset \
  --output-path outputs/my_dataset_cleaned \
  --no-remove-stale-smpl

Để merge nhiều session:

python gear_sonic/scripts/process_dataset.py \
  --dataset-path outputs/session1 outputs/session2 outputs/session3 \
  --output-path outputs/merged_dataset

Script kiểm tra script_config để tránh merge dữ liệu thu bằng cấu hình robot khác nhau. Đây là guard quan trọng: VLA rất dễ học sai nếu cùng một observation.state dimension nhưng ý nghĩa robot, camera hoặc wrist setup thay đổi.

9. Checklist cho một buổi thu demo sạch

Trước khi bấm record, hãy đi theo checklist này:

Bước Kiểm tra
Cài teleop install_pico.sh chạy xong, .venv_teleop import được xrobotoolkit_sdk
Camera run_camera_viewer.py thấy frame trên port 5555, không tối, không lệch góc
Deployment deploy.sh --input-type zmq_manager init xong, C++ publish robot_config
PICO pico_manager_thread_server.py --manager thấy body data, combo mode hoạt động
Prompt --task-prompt mô tả đúng task, không dùng "demo" cho dữ liệu thật
Recording Left Grip + A start/stop, Left Grip + B discard khi fail
Post-process Chạy process_dataset.py, chú ý --no-remove-stale-smpl với VR_3PT

Với beginner, lỗi phổ biến nhất không phải model kém mà là dataset lệch đồng bộ: camera ghi từ máy khác, PICO publish được nhưng C++ không chạy zmq_manager, exporter thiếu robot_config, hoặc task prompt dùng sai cho nhiều task khác nhau. Hãy coi mỗi episode như một sample supervised learning: input, action và annotation phải cùng kể một câu chuyện.

Kết luận

Bài 5 biến SONIC từ một controller thành một pipeline dữ liệu VLA hoàn chỉnh. install_pico.sh dựng môi trường teleop; pico_manager_thread_server.py biến PICO thành manager nhiều mode; launch_data_collection.py ghép C++ deploy, PICO, exporter và camera viewer trong tmux; run_data_exporter.py đồng bộ camera, robot state và teleop signal; process_dataset.py dọn dataset trước fine-tune.

Nếu nhớ một câu, hãy nhớ câu này: --input-type zmq_manager là cổng vào cho PICO manager, còn LeRobot v2.1 là hợp đồng đầu ra cho VLA. Khi cả hai đầu hợp đồng đúng, bạn có thể thu dữ liệu thao tác toàn thân để VLA học "làm gì", trong khi SONIC tiếp tục chịu trách nhiệm "di chuyển cơ thể như thế nào".

Trong bài cuối, chúng ta sẽ rời pipeline teleop-data và nhìn sang MotionBricks: lớp latent generative motion bổ sung cho hệ sinh thái SONIC.

Bài viết liên quan

NT

Nguyễn Anh Tuấn

Robotics & AI Engineer. Building VnRobo — sharing knowledge about robot learning, VLA models, and automation.

Khám phá VnRobo

Bài viết liên quan

Triển khai C++: TensorRT, ZMQ, ONNX
wholebody-vla

Triển khai C++: TensorRT, ZMQ, ONNX

13/6/202615 phút đọc
NT
Kiến trúc SONIC cho WBC humanoid
wholebody-vla

Kiến trúc SONIC cho WBC humanoid

13/6/202614 phút đọc
NT
Dữ liệu BONES-SEED và huấn luyện SONIC
wholebody-vla

Dữ liệu BONES-SEED và huấn luyện SONIC

13/6/202614 phút đọc
NT