Mục tiêu của bài này
Nếu bạn muốn xây một "trung tâm dữ liệu" cho humanoid VLA, đừng bắt đầu bằng việc thuê 10 operator, mua thêm robot, hoặc viết dashboard phức tạp. Hãy bắt đầu bằng một ca pilot 2 người trong 2-3 giờ, có checklist rõ ràng, có quy ước episode, có replay để kiểm chứng dữ liệu, và có số throughput đủ tin cậy để quyết định có nên mở rộng hay không.
Bài 1 của series này thiết kế ca thu dữ liệu đầu tiên dựa trên hai pipeline thực tế: LeRobot với các bước teleoperate.py, record.py, replay.py, evaluate.py (trên bản hiện tại thường được expose qua CLI lerobot-teleoperate, lerobot-record, lerobot-replay, lerobot-eval) và GR00T WholeBodyControl cho Unitree G1 với run_g1_control_loop.py và run_g1_data_exporter.py. LeRobot cung cấp khung dữ liệu chuẩn cho video, state, action và episode; GR00T WBC cung cấp cách chạy control loop, teleoperation, camera forwarder và data exporter cho humanoid whole-body.
Đọc xong bài này, bạn có thể lập checklist camera/state/action/language, đặt tên episode, phân vai 2 operator, đo throughput, và quyết định ngưỡng chất lượng trước khi thuê thêm người. Nếu bạn đang làm robot arm nhỏ, bài vẫn hữu ích; nếu bạn đang hướng tới G1, humanoid loco-manipulation hoặc GR00T-style VLA, đây là bài nền.
Roadmap series
- Pilot 2 người cho dữ liệu humanoid VLA: thiết kế ca thu đầu tiên, checklist tín hiệu, quy ước episode và throughput.
- Teleop stack cho humanoid VLA: chọn thiết bị teleop, mapping tay/thân/chân, latency, safety gate và reset scene.
- ROS 2, MCAP và đồng bộ dữ liệu: chuẩn hóa topic, timestamp, camera stream, state/action log và playback.
- LeRobot, RoboDM và format dataset: chuyển dữ liệu thô sang format train được, validate schema và publish nội bộ.
- Synthetic QA cho dữ liệu humanoid: dùng rule, vision model và replay để phát hiện episode hỏng.
- Eval và scale đội thu dữ liệu: tính chi phí mỗi episode tốt, mở rộng operator, và theo dõi chất lượng theo tuần.
Nguồn kỹ thuật nên đọc trước
LeRobot documentation mô tả luồng imitation learning cho robot thật: teleoperate robot bằng leader arm, keyboard hoặc thiết bị teleop; record dataset; replay episode đã thu để kiểm tra repeatability; train và evaluate policy. Tài liệu LeRobotDataset v3 cũng nói rõ format chuẩn gồm multi-camera video, sensorimotor signal và metadata để index/search/visualize trên Hugging Face Hub. Repo LeRobot hiện mô tả dataset bằng MP4 hoặc image cho vision, Parquet cho state/action, và CLI như lerobot-record, lerobot-replay, lerobot-eval.
GR00T WholeBodyControl documentation mô tả decoupled WBC cho humanoid, chủ yếu Unitree G1. Control stack chạy run_g1_control_loop.py; teleoperation stack chạy song song; data collection stack dùng helper tạo tmux với các pane cho control loop, camera forwarder, camera viewer và data exporter. Trong source run_g1_control_loop.py, control loop observe robot, nhận command teleop, tính WBC action, queue action vào environment, publish state/action không gồm ảnh qua ROS topic. Trong run_g1_data_exporter.py, exporter đọc proprio message và image message, kiểm tra episode state, thêm frame gồm observation.state, observation.eef_state, action, action.eef, teleop.navigate_command, teleop.base_height_command và ảnh camera, rồi save hoặc discard episode.
Nguồn chính:
- LeRobot: Imitation Learning on Real-World Robots
- LeRobotDataset v3.0
- GR00T WholeBodyControl Decoupled WBC
- NVIDIA Isaac GR00T repository
- NVlabs GR00T-WholeBodyControl repository
Tư duy đúng: pilot không phải dataset production
Pilot có một nhiệm vụ: phát hiện điểm nghẽn thật. Nhiều nhóm mới bắt đầu bằng câu hỏi "cần bao nhiêu nghìn episode để train VLA?". Câu hỏi đó đến quá sớm. Trước khi nói đến 10.000 episode, bạn cần biết 20 episode đầu có mở được không, replay được không, state/action có đúng chiều không, language prompt có nhất quán không, camera có trễ so với proprio không, và operator có mất sức sau 45 phút không.
Vì vậy pilot 2 người không cố tối đa số lượng. Nó cố tối đa khả năng quan sát lỗi. Một người điều khiển robot, một người giám sát scene và dữ liệu. Mọi episode đều có quyết định rõ: save, discard, hoặc mark cần review. Sau buổi pilot, bạn không chỉ có data; bạn có bảng thời gian cho từng bước reset, teleop, save, replay, và QA.
Mô hình 2 người phù hợp vì humanoid có nhiều failure mode hơn robot arm. Robot có thể mất thăng bằng, va vào bàn, đi lệch target, bị occlusion bởi tay, hoặc tạo action không tương ứng với prompt. Nếu chỉ có một operator vừa teleop vừa nhìn log vừa reset scene, dữ liệu dễ bị hỏng mà không ai phát hiện. Nếu có quá nhiều người ngay từ đầu, bạn lại không biết quy trình nào thực sự cần thiết.
Vai trò trong ca pilot
| Vai trò | Trách nhiệm chính | Không nên làm |
|---|---|---|
| Operator A: teleop | Điều khiển robot, bắt đầu/dừng thao tác, giữ chuyển động mượt, báo lỗi cảm giác điều khiển | Tự ý đổi prompt giữa episode, bỏ qua safety, vừa teleop vừa chỉnh dataset |
| Operator B: data captain | Đọc checklist, nhập task prompt, reset scene, quan sát camera/state/action, quyết định save/discard | Điều khiển robot khi chưa thống nhất vai, sửa script trong lúc robot đang active |
Operator A cần tập trung vào chất lượng trajectory. Operator B cần tập trung vào tính đúng của dữ liệu. Trong GR00T WBC, tài liệu data collection cho thấy data exporter có bước nhập task prompt, có phím start/stop recording và discard trajectory. Đây là chỗ Operator B phải làm chủ: prompt phải khớp episode, discard phải nhanh, và mỗi episode phải có note ngắn.
Một ca pilot nên có ba phase:
| Phase | Thời lượng | Mục tiêu |
|---|---|---|
| Dry run | 20-30 phút | Chạy teleop không record, kiểm tra camera, delay, workspace và emergency stop |
| Record pilot | 60-90 phút | Thu 20-40 episode ngắn, có save/discard, có log thời gian |
| Replay/QA | 30-45 phút | Replay mẫu, mở dataset, kiểm tra prompt, state/action, camera sync, tính throughput |
Không nên thu liên tục 3 giờ rồi mới kiểm tra. Với robotics data, lỗi schema ở phút thứ 5 có thể làm hỏng toàn bộ buổi nếu không phát hiện sớm.
Checklist trước khi bật record
Checklist dưới đây cố tình cụ thể. Beginner có thể in ra và đánh dấu từng dòng.
| Nhóm | Cần kiểm tra | Tiêu chí pass |
|---|---|---|
| Camera | Tên camera, vị trí, độ phân giải, FPS, exposure, focus | Mỗi camera có tên ổn định như observation.images.ego_view, không bị đổi index sau reboot |
| State | Joint position, base height, wrist/eef state, navigate command, timestamp | Shape không đổi giữa frame; timestamp tăng đều; không có NaN |
| Action | Joint target/action, eef action, base command, gripper/hand command nếu có | Action cùng hệ tọa độ với replay/evaluate; không bị scale sai |
| Language | Task prompt, scene id, object id, success condition | Prompt ngắn, cùng template, không đổi nghĩa giữa các episode |
| Episode | Episode id, operator id, robot id, start/stop, save/discard reason | Mỗi episode có một outcome: good, discard, review |
| Safety | E-stop, vùng robot, pin, nhiệt, giới hạn joint, vật cản | Operator nào cũng biết cách dừng robot trong 1 giây |
Với LeRobot, command record thường khai báo robot, teleop, camera và dataset repo. Với G1/GR00T WBC, control loop publish state/action, data exporter ghép state với camera và lưu frame. Dù dùng stack nào, checklist vẫn giống nhau: bạn phải biết một frame training gồm gì.
Ví dụ một frame tối thiểu cho humanoid VLA:
timestamp:
camera_ego: 1718000000.123
proprio: 1718000000.118
action: 1718000000.121
observation:
images:
ego_view: "rgb frame"
wrist_left: "optional rgb frame"
wrist_right: "optional rgb frame"
state:
q: [joint_positions]
base_height: 0.72
eef_left: [x, y, z, qw, qx, qy, qz]
eef_right: [x, y, z, qw, qx, qy, qz]
action:
joints: [target_joint_positions]
eef_left: [target_delta_or_pose]
eef_right: [target_delta_or_pose]
teleop:
navigate_command: [vx, vy, yaw_rate]
base_height_command: 0.72
language:
task: "pick up the red cup and place it into the tray"
episode:
id: "g1_pilot_20260610_s01_ep0007"
operator: "op_a"
support: "op_b"
Không cần schema này giống 100% với LeRobot hoặc GR00T. Mục tiêu là bạn biết mapping. Khi chuyển sang LeRobotDataset, các trường thường trở thành feature name như observation.images.ego_view, observation.state, action, task và metadata episode.
Thiết kế task đầu tiên
Task đầu tiên phải đủ đơn giản để replay được, nhưng đủ giống humanoid VLA để lộ lỗi dữ liệu. Đừng chọn "dọn phòng" hoặc "nấu cà phê". Hãy chọn thao tác 10-20 giây, có một mục tiêu rõ, ít vật, và có reset nhanh.
Gợi ý task pilot:
| Task | Vì sao phù hợp | Failure dễ quan sát |
|---|---|---|
| Nhặt cốc đỏ từ bàn và đặt vào khay | Có object, target, grasp, place, prompt rõ | Camera bị che bởi tay, action eef sai, place lệch |
| Tiến tới kệ thấp, nhặt hộp, đặt lên bàn | Có locomotion ngắn + squat/approach | Base command không đồng bộ, mất target khỏi ego view |
| Kéo tay cầm xe đẩy 20 cm | Có contact và lực kéo đơn giản | State/action không thể hiện contact, replay không lặp lại |
Trong pilot đầu, mỗi task nên có cùng layout trong 10 episode liên tiếp. Sau đó mới đổi khoảng cách, hướng tiếp cận hoặc object màu khác. Nếu bạn thay scene mỗi episode, bạn sẽ không biết lỗi đến từ operator, robot, camera hay task.
Prompt nên dùng template ổn định:
<verb> the <object_color> <object_name> from <source> to <target>.
Examples:
pick up the red cup from the table and place it into the black tray.
move the blue box from the low shelf to the table.
pull the cart handle toward the robot by twenty centimeters.
Với bài 4 của series, ta sẽ đi sâu vào mapping prompt sang LeRobot/RoboDM modality config. Ở bài này, nguyên tắc quan trọng là prompt không được là note mơ hồ như "task 1" hoặc "cup thing". VLA học từ ngôn ngữ; prompt xấu là label xấu.
Quy ước episode
Episode là đơn vị kinh tế của data center. Bạn trả tiền bằng thời gian operator, robot wear, pin, reset scene và QA. Vì vậy episode id phải giúp truy vết nhanh.
Quy ước đề xuất:
<robot>_<date>_<session>_<task>_<episode>
g1_20260610_s01_cup_tray_ep0001
g1_20260610_s01_cup_tray_ep0002
g1_20260610_s01_low_shelf_box_ep0001
Metadata đi kèm:
| Field | Ví dụ | Lý do |
|---|---|---|
robot_id |
g1_sim hoặc g1_lab01 |
Tách robot thật, sim, robot sau bảo trì |
teleoperator_username |
op_a |
Tính throughput và chất lượng theo operator |
support_operator_username |
op_b |
Biết ai nhập prompt/reset scene |
task_prompt |
pick up the red cup... |
Label ngôn ngữ chính |
scene_id |
table_a_layout_01 |
Debug thay đổi scene |
outcome |
good, discard, review |
Không trộn episode nghi ngờ vào train |
discard_reason |
camera_occluded, bad_grasp, sync_delta_high |
Tính lỗi hệ thống |
GR00T data exporter có logic start/stop recording, save episode, discard trajectory, và cả thông tin operator khi tạo dataset mới. Hãy tận dụng tinh thần đó ngay cả khi bạn chưa dùng nguyên code: episode không chỉ là file video, nó là một record có provenance.
Chạy thử theo LeRobot: teleoperate, record, replay, evaluate
LeRobot giúp beginner vì nó tách bốn câu hỏi:
- Robot có điều khiển được không? Dùng
teleoperate. - Dữ liệu có ghi được không? Dùng
record. - Episode có phát lại được không? Dùng
replay. - Policy/dataset có đánh giá được không? Dùng
evaluatehoặclerobot-eval.
Một skeleton lệnh cho robot arm nhỏ sẽ giống:
lerobot-teleoperate \
--robot.type=so101_follower \
--robot.port=/dev/ttyUSB0 \
--robot.id=pilot_follower \
--teleop.type=so101_leader \
--teleop.port=/dev/ttyUSB1 \
--teleop.id=pilot_leader
Record dataset:
lerobot-record \
--robot.type=so101_follower \
--robot.port=/dev/ttyUSB0 \
--robot.id=pilot_follower \
--robot.cameras="{ ego: {type: opencv, index_or_path: 0, width: 1280, height: 720, fps: 30}}" \
--teleop.type=so101_leader \
--teleop.port=/dev/ttyUSB1 \
--teleop.id=pilot_leader \
--display_data=true \
--dataset.repo_id=vnrobo/g1-pilot-style-test \
--dataset.num_episodes=10 \
--dataset.fps=30
Replay một episode:
lerobot-replay \
--robot.type=so101_follower \
--robot.port=/dev/ttyUSB0 \
--robot.id=pilot_follower \
--dataset.repo_id=vnrobo/g1-pilot-style-test \
--dataset.episode=0
Điểm cần học không phải là SO101, mà là vòng kiểm chứng. Nếu replay không giống motion đã thu, đừng train. Nếu camera index đổi sau reboot, đừng scale operator. Nếu robot.id khác giữa teleoperate, record và evaluate khiến calibration lệch, sửa quy trình trước.
Chạy thử theo GR00T WBC: control loop và data exporter
Với humanoid G1, control loop không chỉ gửi action cho một arm. Nó observe toàn thân, nhận teleop command, tính WBC action, queue action, publish status, publish state/action cho exporter. Tài liệu GR00T WBC cho thấy simulation có thể chạy:
python decoupled_wbc/control/main/teleop/run_g1_control_loop.py
Với robot thật, cần network theo Unitree G1 SDK và dùng interface real:
python decoupled_wbc/control/main/teleop/run_g1_control_loop.py --interface real
Data collection stack có thể chạy qua deployment helper để mở control loop, teleop policy và camera forwarder trong tmux:
python decoupled_wbc/scripts/deploy_g1.py \
--interface sim \
--camera_host localhost \
--sim_in_single_process \
--simulator robocasa \
--image-publish \
--enable-offscreen \
--env_name PnPBottle \
--hand_control_device=pico \
--body_control_device=pico
Trong data exporter, Operator B nhập task prompt, dùng start/stop recording, và discard trajectory khi cần. Source exporter cũng theo dõi độ lệch thời gian giữa image và proprio; nếu delta quá cao liên tục, nó cảnh báo nên discard data. Đây là một bài học lớn cho pilot: sync không phải việc để sau. Nếu ảnh và proprio lệch 300-500 ms, VLA sẽ thấy tay ở thời điểm này nhưng action ở thời điểm khác.
Đo throughput trước khi thuê thêm người
Sau pilot, hãy tính bằng episode tốt, không tính bằng episode đã record. Công thức:
good_episode_rate = good_episodes / total_recorded_episodes
minutes_per_good_episode = total_session_minutes / good_episodes
usable_seconds_per_hour = sum(good_episode_duration_seconds) / session_hours
discard_rate_by_reason = count(discard_reason) / total_discarded
Bảng log tối thiểu:
| Metric | Ví dụ pilot | Ý nghĩa |
|---|---|---|
| Tổng thời gian session | 120 phút | Gồm setup, dry run, record, replay |
| Episode đã record | 36 | Tất cả episode có file |
| Episode tốt | 24 | Có thể train hoặc review nhẹ |
| Episode discard | 9 | Không dùng train |
| Episode review | 3 | Cần QA thêm |
| Good episode rate | 67% | Dưới 60% thì chưa nên scale |
| Phút/good episode | 5 phút | Cơ sở tính nhân sự |
| Usable seconds/hour | 240-360 giây | Dữ liệu thật thu được mỗi giờ |
Ngưỡng đề xuất trước khi thuê thêm operator:
| Điều kiện | Ngưỡng tối thiểu |
|---|---|
| Good episode rate | >= 75% trong 2 buổi liên tiếp |
| Camera/proprio sync warning | < 5% episode |
| Replay pass sample | >= 8/10 episode mẫu |
| Prompt mismatch | 0 lỗi nghiêm trọng |
| Reset scene time | < 90 giây cho task đơn giản |
| Operator fatigue | Không làm giảm success rõ sau 60 phút |
Nếu chưa đạt, scale sẽ chỉ nhân lỗi lên. Thuê thêm người khi quy trình ổn sẽ rẻ hơn thuê người để tạo thêm episode hỏng.
QA nhanh sau mỗi 10 episode
Sau mỗi block 10 episode, Operator B nên dừng 5-7 phút:
1. Mở 2 episode ngẫu nhiên và xem video.
2. Kiểm tra prompt có đúng object/source/target không.
3. Kiểm tra state/action shape không đổi.
4. Kiểm tra timestamp camera và proprio.
5. Replay 1 episode nếu robot/scene cho phép.
6. Ghi top 2 lỗi vào session log.
7. Chỉ tiếp tục nếu lỗi không mang tính hệ thống.
QA block nhỏ quan trọng hơn QA cuối ngày. Nếu camera wrist phải bị ngược trái/phải, bạn muốn biết sau episode 3, không phải sau episode 80. Nếu operator thường dừng recording quá muộn, bạn muốn sửa cách đếm start/stop ngay.
Lỗi beginner hay gặp
| Lỗi | Hậu quả | Cách sửa |
|---|---|---|
| Prompt quá dài và đổi liên tục | Model học label nhiễu | Dùng template cố định, chỉ đổi object/source/target |
| Không replay episode | Không phát hiện action scale sai | Replay mẫu mỗi block |
| Tính throughput bằng số file | Đánh giá quá lạc quan | Chỉ tính good episode |
| Camera không đặt tên ổn định | Dataset lẫn view | Đặt feature name rõ, kiểm tra sau reboot |
| Operator vừa teleop vừa QA | Bỏ sót lỗi sync/safety | Giữ mô hình 2 người |
| Không lưu discard reason | Không biết lỗi lớn nhất | Bắt buộc chọn reason từ danh sách ngắn |
Kết luận
Pilot 2 người là cách rẻ nhất để biến ý tưởng "humanoid VLA data center" thành một quy trình có số đo. Với LeRobot, bạn học kỷ luật teleoperate, record, replay, evaluate. Với GR00T WBC, bạn học cách control loop, teleop command, state/action publisher, camera stream và data exporter ghép lại thành episode whole-body. Điều quan trọng nhất là không nhảy thẳng sang scale. Hãy chứng minh trước rằng 20-40 episode đầu sạch, replay được, prompt đúng, sync ổn và operator không bị quá tải.
Bài tiếp theo sẽ đi sâu vào teleop stack cho humanoid VLA: chọn thiết bị điều khiển, mapping tay-thân-chân, latency budget và safety gate cho ca thu dài hơn.