Mục tiêu của bài này
Trong bài 1 của series, chúng ta thiết kế ca pilot 2 người cho dữ liệu humanoid VLA: ai điều khiển, ai giám sát dữ liệu, cần camera/state/action nào, và khi nào nên save hoặc discard episode. Bài này đi vào quyết định rất thực tế trước khi bật record: chọn teleoperation stack nào.
Với humanoid, "teleop" không chỉ là một tay cầm điều khiển. Nó là toàn bộ đường đi từ ý định của con người đến action mà model sẽ học: keyboard hoặc SpaceMouse tạo delta SE(3), OpenXR hand tracking tạo wrist pose và finger joints, motion controller tạo pose kèm trigger, còn GR00T WholeBodyControl chia control loop, teleop loop và policy loop cho cả thân, tay, locomotion và hand. Nếu chọn sai stack, bạn vẫn có thể thu được video đẹp, nhưng action trong dataset sẽ khó học, trễ, không ổn định, hoặc nguy hiểm khi replay.
Sau bài này, bạn sẽ biết khi nào nên dùng Isaac Lab teleop_se3_agent.py với --teleop_device keyboard, spacemouse, hoặc handtracking; khi nào nên dùng OpenXR retargeters như g1_upper_body_retargeter.py; và khi nào nên chuyển sang GR00T WBC BaseConfig với body_control_device, hand_control_device, teleop_frequency=20, control_frequency=50. Nếu bạn đang chuẩn bị bước tiếp theo về ROS 2, MCAP và đồng bộ dữ liệu, quyết định teleop hôm nay sẽ quyết định schema data ngày mai.
Bảng chọn nhanh
| Nhu cầu thu dữ liệu | Stack nên bắt đầu | Action thu được | Điểm mạnh | Rủi ro chính |
|---|---|---|---|---|
| Beginner, chỉ test pipeline, pick/place đơn giản trong sim | Isaac Lab keyboard | Delta SE(3), gripper binary | Rẻ, dễ debug, deterministic | Motion gãy khúc, demo kém tự nhiên |
| Pick/place cần trajectory mượt, không cần finger dexterity | Isaac Lab SpaceMouse | Delta SE(3), gripper binary | Mượt hơn keyboard, điều khiển 6-DoF tự nhiên hơn | Cần thiết bị đúng model, vẫn không thu được ngón tay |
| Bimanual hoặc upper-body pose cần wrist tracking | Isaac Lab OpenXR handtracking | Absolute hand/wrist pose, pinch/grip, hand joints qua retargeter | Tự nhiên, phù hợp imitation | Latency và calibration khó hơn |
| G1 loco-manipulation, cần thân dưới ổn định và tay phối hợp | GR00T WBC / Decoupled WBC | Navigate command, body/hand teleop, WBC action, state/action stream | Gần robot thật, có control loop rõ | Safety phức tạp, phải có operator kỷ luật |
| Thu dữ liệu VLA production cho humanoid | GR00T WBC + data exporter + camera sync | Episode đủ camera, proprio, eef, action, teleop command, prompt | Có đường mở rộng sang train/eval | Tốn thời gian chuẩn hóa schema và QA |
Quy tắc thực dụng: keyboard để debug, SpaceMouse để thu demo SE(3) sạch, hand tracking để thu chuyển động tay tự nhiên, WBC để thu whole-body humanoid data. Đừng nhảy thẳng vào VR nếu bạn chưa replay được 10 episode keyboard. Đừng dùng keyboard để thu dữ liệu ngón tay nếu mục tiêu cuối là dexterous manipulation.
Ba lớp trong một teleop stack
Một beginner thường nghĩ teleop là "thiết bị điều khiển robot". Với humanoid VLA, nên tách thành ba lớp:
| Lớp | Câu hỏi cần trả lời | Ví dụ |
|---|---|---|
| Input device | Con người dùng gì để ra lệnh? | Keyboard, SpaceMouse, OpenXR hand tracking, PICO controller, Vive, Joy-Con |
| Retargeting | Tín hiệu người được map sang robot như thế nào? | SE(3) delta, absolute wrist pose, gripper pinch, G1 upper-body retargeter |
| Control loop | Robot nhận action ở tần số nào và kiểm soát ổn định ra sao? | Isaac Lab env step, GR00T WBC control_frequency=50, teleop loop 20 Hz |
Khi debug, hãy log từng lớp riêng. Nếu robot giật, lỗi có thể đến từ input noisy, retargeter scale sai, frame coordinate sai, hoặc control loop nhận command quá thưa. Nếu dataset xấu, lỗi có thể không nằm ở camera mà ở action representation: model nhìn một chuyển động mượt trong video nhưng action lại là chuỗi delta khó học.
Isaac Lab teleop_se3_agent.py: tốt nhất cho SE(3) demo
Isaac Lab cung cấp script scripts/environments/teleoperation/teleop_se3_agent.py để chạy teleoperation cho các environment manipulation. Trong tài liệu chính thức, SE(3) teleoperation trả về vector 6 chiều đại diện cho thay đổi pose; keyboard và SpaceMouse được dùng với các task Franka IK, còn hand tracking dùng qua XR/CloudXR cho task absolute.
Ví dụ debug bằng keyboard:
./isaaclab.sh -p scripts/environments/teleoperation/teleop_se3_agent.py \
--task Isaac-Stack-Cube-Franka-IK-Rel-v0 \
--num_envs 1 \
--teleop_device keyboard
Ví dụ dùng SpaceMouse:
./isaaclab.sh -p scripts/environments/teleoperation/teleop_se3_agent.py \
--task Isaac-Stack-Cube-Franka-IK-Rel-v0 \
--num_envs 1 \
--teleop_device spacemouse
Ví dụ dùng hand tracking với task absolute:
./isaaclab.sh -p scripts/environments/teleoperation/teleop_se3_agent.py \
--task Isaac-Stack-Cube-Franka-IK-Abs-v0 \
--teleop_device handtracking \
--device cpu
Keyboard phù hợp nhất cho giai đoạn đầu vì bạn có thể nhìn từng command. Với keyboard, các phím thường map sang di chuyển theo trục x/y/z, xoay quanh x/y/z, reset và toggle gripper. Đây là lựa chọn tốt để kiểm tra env, reset, reward, termination và recording. Nhược điểm là trajectory thường có đoạn thẳng, góc cua cứng, tốc độ không tự nhiên. Nếu bạn train imitation từ demo keyboard quá nhiều, policy dễ học kiểu chuyển động "bậc thang".
SpaceMouse là bước nâng cấp rõ ràng cho pick/place hoặc insertion đơn giản. Nó cho điều khiển 6-DoF liên tục: nghiêng để đi x/y, đẩy/kéo để đi z, vặn để rotate. Isaac Lab khuyến nghị SpaceMouse cho vận hành mượt và off-axis tốt hơn, vì demo mượt giúp policy clone hành vi dễ hơn. Lưu ý thực tế: Isaac Lab chỉ nêu tương thích với SpaceMouse Wireless và SpaceMouse Compact của 3Dconnexion; trong container, bạn có thể phải mount /dev/hidraw vào container và cấp quyền thiết bị.
Hand tracking trong Isaac Lab phù hợp khi action bạn muốn thu là absolute hand pose hoặc pinch-based interaction. Tài liệu Isaac Lab nói OpenXR dùng hand tracking của index/thumb tip để drive target pose, còn gripping dựa trên pinching. Khi dùng hand tracking, nên ưu tiên task absolute như Isaac-Stack-Cube-Franka-IK-Abs-v0, vì tay người trong XR là pose tuyệt đối trong không gian, không phải chuỗi delta keyboard.
Điểm quan trọng cho data center: teleop_se3_agent.py là công cụ tốt để tạo demo SE(3) sạch, nhưng nó không tự động giải quyết toàn bộ bài toán humanoid. Nó không nói cho bạn cách đồng bộ nhiều camera, cách lưu prompt, cách chống mode switch nguy hiểm, hay cách chia thân dưới/thân trên. Nó là lớp input và env-control, không phải production data pipeline.
OpenXR retargeters: khi cần map tay người sang G1
OpenXR trong Isaac Lab mở ra cách teleop tự nhiên hơn: lấy tracking data từ XR device, rồi dùng retargeter để biến hand pose, wrist pose hoặc motion controller thành command robot. Trong API Isaac Lab, device interface có thể nhận danh sách retargeters; khi advance() được gọi, raw device data được retarget thành tensor command. Các retargeter có thể map hand joint data sang end-effector pose, gripper state hoặc joint command.
Với Unitree G1 trong môi trường locomanipulation, config Isaac Lab hiện có hai nhóm device đáng chú ý:
teleop_devices:
handtracking:
- G1TriHandUpperBodyRetargeterCfg
- G1LowerBodyStandingRetargeterCfg
motion_controllers:
- G1TriHandUpperBodyMotionControllerRetargeterCfg
- G1LowerBodyStandingMotionControllerRetargeterCfg
Ý nghĩa thực tế:
| Device key | Dùng khi | Tín hiệu chính | Ghi chú |
|---|---|---|---|
handtracking |
Muốn bắt chuyển động bàn tay/ngón tay tự nhiên | OpenXR hand joints, wrist pose, pinch | Config G1 dùng 2 * 26 OpenXR hand joints cho hai tay |
motion_controllers |
Muốn điều khiển ổn định hơn bằng controller vật lý | Controller pose, button, trigger | Ít nhiễu ngón tay hơn, dễ training operator hơn |
g1_upper_body_retargeter.py thuộc nhóm retargeter này: nó biến tín hiệu người thành target upper-body/hand cho G1. Trong config locomanipulation G1, retargeter upper body đi cùng lower-body standing retargeter, nghĩa là robot không chỉ có tay; nó còn cần trạng thái thân dưới ổn định trong lúc tay làm việc. Config cũng đặt XR anchor vào pelvis của robot, cố định height và dùng chế độ rotation theo pelvis yaw có smoothing. Đây là chi tiết nhỏ nhưng quan trọng: nếu anchor bị trôi hoặc xoay sai, người điều khiển cảm thấy tay "không ở cùng thế giới" với robot.
Beginner nên hiểu retargeting bằng một ví dụ đơn giản. Tay người và tay robot không cùng chiều dài, joint limit, palm frame hoặc finger topology. Nếu bạn copy trực tiếp joint người sang joint robot, robot có thể tự đâm vào thân, vượt joint limit hoặc tạo pose không IK được. Retargeter là nơi bạn nói: wrist người map sang left_wrist_yaw_link, pinch map sang gripper close, ngón tay người map sang joint hand robot qua scale và clamp, lower body giữ standing policy.
Checklist trước khi dùng OpenXR retargeter:
| Kiểm tra | Cách nghĩ đúng |
|---|---|
| Coordinate frame | Wrist pose đang ở OpenXR frame, USD/world frame hay robot pelvis frame? |
| Anchor | Người điều khiển đứng ở đâu so với robot? Anchor có follow pelvis không? |
| Calibration | Pose neutral của người có khớp pose neutral robot không? |
| Joint limits | Retargeter có clamp target vào range an toàn không? |
| Visualization | Có bật target pose/joint visualization trước khi chạy real-time không? |
| Data schema | Dataset lưu raw hand tracking, retargeted action, hay cả hai? |
Với data VLA, tôi khuyến nghị lưu cả hai mức nếu storage cho phép: raw-ish teleop signal để debug, và action thật gửi vào robot để train/replay. Khi episode hỏng, bạn cần biết lỗi đến từ người, tracker, retargeter hay controller.
GR00T WBC BaseConfig: khi nhiệm vụ là whole-body
GR00T WholeBodyControl không chỉ là một input device. Nó là stack whole-body control cho humanoid, có tài liệu Decoupled WBC cho Unitree G1, control loop, teleoperation stack và data exporter. Tài liệu GR00T WBC mô tả stack hỗ trợ policy whole-body, teleop và exporter; phần Decoupled WBC chạy run_g1_control_loop.py, sau đó terminal khác chạy run_teleop_policy_loop.py với --hand_control_device và --body_control_device. Tài liệu cũng cho ví dụ PICO controller cho hand/body coordinated control, cùng data collection helper tạo tmux session cho control, camera forwarder, viewer và exporter.
Trong source BaseConfig, các field quan trọng là:
control_frequency = 50
body_control_device = "dummy"
hand_control_device = "dummy"
teleop_frequency = 20
data_collection_frequency = 20
Và khi chạy teleop/data collection, bạn thường override bằng CLI:
python decoupled_wbc/control/main/teleop/run_teleop_policy_loop.py \
--hand_control_device=pico \
--body_control_device=pico
Hoặc trong data collection:
python decoupled_wbc/scripts/deploy_g1.py \
--interface sim \
--simulator robocasa \
--image-publish \
--hand_control_device=pico \
--body_control_device=pico
Tại sao teleop_frequency=20 nhưng control_frequency=50? Vì teleop input của con người không cần cập nhật nhanh như vòng điều khiển robot. Người điều khiển tạo command ở khoảng 20 Hz là đủ cho intent và pose target; controller cần chạy nhanh hơn để giữ ổn định, interpolate, xử lý state và gửi action đều. Nếu bạn cố đẩy teleop lên quá cao qua WiFi hoặc XR stream không ổn định, bạn có thể tăng jitter. Nếu control loop quá thấp, robot phản ứng chậm và mất ổn định. Tách hai tần số là thiết kế hợp lý.
GR00T WBC phù hợp khi action bạn muốn thu không còn là "dịch end-effector 3 cm sang trái". Với humanoid, action có thể gồm:
| Action cần học | Stack phù hợp |
|---|---|
| Navigate command: tiến/lùi/trái/phải/yaw | GR00T WBC planner hoặc controller joystick |
| Upper-body reach trong khi thân dưới giữ thăng bằng | GR00T WBC hoặc Isaac Lab G1 OpenXR retargeter |
| Hand grasp đơn giản bằng trigger | PICO/controller hoặc SpaceMouse gripper |
| Finger dexterity chi tiết | OpenXR hand tracking, Manus/LeapMotion nếu stack hỗ trợ |
| Whole-body pose/motion | PICO full-body teleop hoặc SONIC/GR00T WBC mode |
Tài liệu PICO VR Whole-body Teleop của GR00T WBC đặc biệt nhấn mạnh safety. Có các mode như POSE, PLANNER, PLANNER_FROZEN_UPPER và VR_3PT; có calibration full và calibration khi switch vào VR_3PT; emergency stop có thể qua PICO controller hoặc phím O ở C++ terminal. Điểm beginner cần nhớ: mode switch là lúc nguy hiểm nhất. Nếu người điều khiển đứng lệch pose robot rồi bật POSE hoặc VR_3PT, robot có thể snap sang pose người và tạo chuyển động mạnh.
Chọn theo latency
Latency không chỉ là số millisecond. Với data collection, latency ảnh hưởng cả safety lẫn chất lượng action.
| Stack | Latency cảm nhận | Vì sao | Khi chấp nhận được |
|---|---|---|---|
| Keyboard | Thấp, dễ đoán | Event rời rạc, ít sensor | Debug, scripted reset, thao tác đơn giản |
| SpaceMouse | Thấp đến trung bình | HID liên tục, ít xử lý retarget | SE(3) manipulation mượt |
| OpenXR handtracking | Trung bình, có jitter | Tracking, streaming, retargeting, render | Upper-body/hand natural demo trong sim |
| GR00T WBC PICO/VR | Trung bình đến cao nếu mạng yếu | XR stream, teleop loop, policy/control loop | Whole-body data khi đã có safety operator |
Đừng chỉ hỏi "stack nào nhanh nhất?". Hãy hỏi "latency này có ổn định không?". Latency 80 ms nhưng ổn định có thể dễ điều khiển hơn latency 30-150 ms dao động. Với hand tracking, jitter nhỏ ở ngón tay có thể tạo action hand noisy. Với locomotion, command trễ có thể làm operator overcorrect: robot đi quá target, operator kéo ngược, dataset có nhiều dao động.
Một log tối thiểu nên có:
timing:
input_timestamp: 1718000000.100
retarget_timestamp: 1718000000.118
action_publish_timestamp: 1718000000.122
robot_state_timestamp: 1718000000.140
camera_timestamp: 1718000000.151
episode_frame_index: 42
Bài 3 về ROS 2/MCAP sẽ đi sâu hơn, nhưng ngay từ bài này hãy đặt tên timestamp rõ. Nếu không, khi train lỗi, bạn sẽ không biết model học từ action đúng thời điểm hay action bị lệch 2-3 frame.
Chọn theo an toàn
Safety của humanoid khác robot arm. Robot arm có thể dừng ở joint target; humanoid còn balance, foot contact, base drift và mode switch.
Checklist an toàn theo stack:
| Stack | Gate tối thiểu |
|---|---|
| Keyboard/SpaceMouse trong sim | Reset environment bằng R, giới hạn workspace, termination khi object/robot rơi |
| Hand tracking trong sim | Teleop inactive mặc định, chỉ START khi operator đã nhìn visualization |
| G1 OpenXR retargeting | Anchor/calibration check, joint limit, target visualization, lower-body standing state |
| GR00T WBC sim | Operator phải biết stop policy, reset sim, discard trajectory |
| GR00T WBC real robot | Safety operator riêng, vùng trống, emergency stop đã test, không switch mode khi pose lệch |
Trong teleop_se3_agent.py, hand tracking được xử lý thận trọng hơn: khi XR được bật, teleoperation có thể bắt đầu ở trạng thái inactive, rồi START mới apply command. Đây là pattern nên copy sang stack của bạn. Input device có thể luôn stream, nhưng robot chỉ nên apply action khi gate đúng: robot ở trạng thái sẵn sàng, operator nhìn thấy scene, calibration pass, và data captain đã bật record.
Chọn theo loại hành động cần thu
Nếu chỉ thu pick/place trên bàn, bạn không cần whole-body VR. Nếu thu "đi đến bàn, cúi người, nhấc hộp, đặt lên kệ", keyboard SE(3) không đủ. Chọn stack bằng cách viết action schema trước:
action_schema:
base:
type: velocity_command
fields: [vx, vy, yaw_rate]
upper_body:
type: eef_pose_or_delta
fields: [left_wrist, right_wrist]
hand:
type: gripper_or_joint
fields: [left_hand, right_hand]
safety:
type: mode_state
fields: [teleop_active, planner_mode, emergency_stop]
Sau đó map schema sang device:
| Nếu schema cần | Đừng dùng | Nên dùng |
|---|---|---|
eef_delta đơn giản |
Full VR ngay từ đầu | Keyboard/SpaceMouse |
eef_absolute_pose |
Keyboard-only | OpenXR handtracking hoặc motion controller |
hand_joint |
SpaceMouse gripper binary | Hand tracking, Manus, LeapMotion nếu đã ổn định |
base velocity |
Pure arm teleop | WBC planner, joystick/controller |
whole-body pose |
SE(3) arm-only | PICO/VR whole-body teleop + WBC |
Một lỗi phổ biến là thu data bằng stack dễ nhất, rồi hy vọng model học được task khó hơn. Nếu dataset không có hand joints, model không tự học dexterity. Nếu dataset không có base command, model không học navigation. Nếu dataset không có mode state, model không biết lúc nào robot đang planner, pose hoặc frozen-upper mode.
Khuyến nghị triển khai cho data center nhỏ
Với một team 2-4 người mới bắt đầu humanoid VLA data, tôi sẽ đi theo bốn nấc:
- Keyboard trong Isaac Lab: thu 10 episode, replay được, kiểm tra state/action shape, xác nhận save/discard.
- SpaceMouse trong Isaac Lab: thu 30-50 episode mượt hơn, đo thời gian reset và tỷ lệ success.
- OpenXR handtracking hoặc motion controller trong sim: bật visualization, log raw input + retargeted action, kiểm tra calibration.
- GR00T WBC sim trước real: chạy control loop 50 Hz, teleop 20 Hz, data collection 20 Hz, có data captain và safety operator.
Đến khi chuyển sang real G1, đừng thay cả thiết bị, task, camera và exporter cùng lúc. Giữ task đơn giản, giữ object ít, chạy sim trước, rồi chỉ đổi interface sang real khi emergency stop đã được diễn tập. Nếu cần đọc thêm về dữ liệu G1 và GR00T N1 theo hướng fine-tune, xem bài GR00T N1 + G1: thu data trong Isaac Lab và xr_teleoperate. Nếu muốn nhìn rộng hơn các repo VLA/WBC đang dùng trong hệ sinh thái humanoid, xem VLA + WBC repos cho humanoid.
Nguồn kỹ thuật
- Isaac Lab: Teleoperation and Imitation Learning
- Isaac Lab devices API: keyboard, SpaceMouse, OpenXR and retargeters
- Isaac Lab
teleop_se3_agent.py - Isaac Lab G1 locomanipulation OpenXR retargeter config
- GR00T WholeBodyControl documentation
- GR00T WBC Decoupled WBC guide
- GR00T WBC PICO VR Whole-body Teleop