Vì sao EgoHumanoid là stack thứ ba?
Ở bài 1 về OpenWBT, chúng ta bắt đầu bằng teleoperation whole-body có thể debug được: lower-body policy, upper-body IK, simulator trước, robot thật sau. Ở bài 2 về TWIST2, trọng tâm chuyển sang thu dữ liệu robot trực tiếp bằng PICO teleop, Redis bus, low-level controller và vòng sim2real. Cả hai stack đều đặt robot vào trung tâm: muốn có demonstration tốt thì robot phải chạy, operator phải điều khiển robot, và mỗi lỗi latency hoặc tracking đều ảnh hưởng trực tiếp tới dữ liệu.
EgoHumanoid hỏi một câu khác: nếu lab chưa thể thu hàng nghìn episode robot thật thì có thể tận dụng egocentric human demonstrations hay không? Paper và repo OpenDriveLab/EgoHumanoid mô tả framework co-train VLA policy bằng human demos góc nhìn thứ nhất cộng với một lượng robot data giới hạn. Project page của EgoHumanoid nhấn mạnh hai module alignment: view alignment để giảm chênh lệch góc nhìn camera giữa người và robot, action alignment để map chuyển động người sang không gian action robot. Đây là điểm khác hẳn TWIST2: TWIST2 cố làm teleop robot tốt hơn, EgoHumanoid cố làm dữ liệu người trở nên "robot-ready" hơn.
Bài này đi theo pipeline bốn bước đúng tinh thần repo: thu robot/human data, chạy data_alignment/human_data_process/run_human_data_pipeline.sh, chuyển HDF5 sang LeRobot bằng data_alignment/convert_to_lerobot.py, rồi train/deploy bằng scripts/train.py, scripts/serve_policy.py và scripts/deploy.py. Phần quan trọng nhất không phải command cuối cùng, mà là hai lớp alignment ở giữa: view_alignment/viewport_transform_batch_h5.py với cache_3d.py cho ảnh, và process_navigation_pipeline.py với add_hand_status.py cho action.
Roadmap series
- OpenWBT: G1 teleop trong MuJoCo/Isaac: dựng môi trường, kiểm tra ONNX policy, hiểu split lower-body joystick và upper-body IK.
- TWIST2: PICO teleop và G1 sim2real: dùng PICO teleop, Redis và low-level controller để thu dữ liệu robot trực tiếp.
- EgoHumanoid: human demo sang G1 VLA: biến egocentric human demo thành HDF5/LeRobot có ảnh, navigation command và hand status.
- VIRAL: retarget và kiểm tra kỹ năng: dùng motion source bên ngoài, retarget sang humanoid đích và đánh giá lỗi.
- FromW1: chuyển kỹ năng sang robot thật: đi từ sim policy sang real hardware với latency, contact và giới hạn actuator.
- CLONE: closed-loop whole-body teleop: nhìn closed-loop teleop như một stack thu dữ liệu dài hạn cho loco-manipulation.
Nếu bạn đang nối bài này vào pipeline VnRobo rộng hơn, nên đọc thêm GR00T N1 + G1 data collection và WholeBodyVLA open-source guide. Hai bài đó giúp đặt EgoHumanoid vào bức tranh data, VLA và whole-body control lớn hơn.
Nguồn kỹ thuật cần mở song song
| Nguồn | Dùng để làm gì | Điểm cần ghi nhớ |
|---|---|---|
| EgoHumanoid README | Nắm pipeline tổng thể collect, process, train, deploy | Repo chia hệ thành data collection, data processing, model training và deployment |
| Human data pipeline README | Hiểu run_human_data_pipeline.sh |
Script nội bộ có reorder, navigation, downsample, merge camera và hand status |
| View alignment README | Chạy viewport_transform_batch_h5.py |
MoGe depth, Cache3D point-cloud warp, Stable Diffusion inpainting |
| EgoHumanoid paper | Hiểu vì sao cần alignment | Human demo dùng PICO + ZED; robot demo dùng Unitree G1 + Dex3 + ZED; action được tách thành EEF delta, velocity command và hand open/close |
Mental model: EgoHumanoid không chỉ là convert dataset
Beginner dễ hiểu nhầm EgoHumanoid là một script chuyển HDF5 sang LeRobot. Thực tế pipeline có ba khoảng cách phải xử lý:
Người thật
PICO VR + 5 tracker + ZED
body pose, hand pose, egocentric RGB
|
| human_data_process + view/action alignment
v
HDF5 robot-ready
teleop_navigate_command
observation_image_left/right
action_eef, action_delta_eef
delta_height, hand_status
|
| convert_to_lerobot.py
v
LeRobot dataset
observation.images.left
action_eef, action_delta_eef
teleop_navigate, delta_height, hand_status
|
| scripts/train.py
v
π0.5-style G1 VLA policy
|
| serve_policy.py + deploy.py
v
Unitree G1 runtime
Khoảng cách thứ nhất là visual domain gap. Người đeo camera ở độ cao, vị trí và hướng khác camera gắn trên đầu G1. Cùng một thao tác nhặt đồ, ảnh của người có thể nhìn xuống từ cao hơn hoặc lệch hơn so với robot. View alignment dùng depth, point-cloud warping và inpainting để tạo ảnh gần với viewpoint robot hơn.
Khoảng cách thứ hai là action domain gap. Người có xương, tỷ lệ tay, dáng đi và bàn tay khác robot. EgoHumanoid không cố xuất joint người rồi retarget từng joint sang G1. Paper mô tả unified action space: upper body dùng 6-DoF delta end-effector pose, lower body dùng discrete velocity command, hand dùng binary open/close. Đây là thiết kế thực dụng vì policy học mục tiêu thao tác và điều hướng, còn controller/IK bên dưới xử lý embodiment.
Khoảng cách thứ ba là dataset format gap. HDF5 nội bộ phù hợp cho alignment và kiểm tra từng episode. LeRobot phù hợp cho training policy, image writer, metadata, FPS và task instruction. Vì vậy convert_to_lerobot.py không phải bước phụ; nó là nơi khóa schema training.
Bước 1: thu robot data và human data
Repo EgoHumanoid hỗ trợ hai nhánh dữ liệu. Robot data được thu trên Unitree G1 với Dex3 hand, workstation Ubuntu, ZED Mini trên đầu robot và PICO VR cho teleoperation. README robot data ghi vòng chạy thực tế gồm control loop, teleop policy loop và exporter ZED:
# Terminal 1: G1 control loop, real interface, có hands
python decoupled_wbc/control/main/teleop/run_g1_control_loop.py \
--interface real \
--control-frequency 50 \
--with_hands
# Terminal 2: PICO teleoperation
python decoupled_wbc/control/main/teleop/run_teleop_policy_loop.py \
--body-control-device pico \
--hand_control_device pico \
--enable_real_device
# Terminal 3: ZED + robot data exporter
python decoupled_wbc/control/main/teleop/zed_mini_run_g1_data_exporter.py \
--dataset-name pick_toy_v1 \
--visualize
Human data dùng PICO VR headset, năm PICO Motion Trackers cho full-body tracking, ZED Mini gắn trên headset và workstation có USB 3.0. Paper gốc nhắc tới ZED X Mini, còn README repo ghi dùng ZED Mini để dễ tiếp cận hơn. Dữ liệu raw cần có ít nhất các trường:
| Trường raw | Shape tham khảo | Dùng cho bước nào |
|---|---|---|
body_pose |
(N, num_joints, 7) |
Tính pelvis trajectory, navigation command và end-effector pose |
left_hand_pose |
(N, 26, >=3) |
Suy ra trạng thái mở/đóng tay trái |
right_hand_pose |
(N, 26, >=3) |
Suy ra trạng thái mở/đóng tay phải |
local_timestamps_ns |
(N,) |
Đồng bộ motion với frame ZED |
episode_*.svo2 |
video ZED | Trích left/right camera frames |
Cấu trúc raw mà run_human_data_pipeline.sh mong đợi là các batch folder theo ngày. Đừng bỏ mọi episode vào một folder phẳng nếu bạn muốn dùng script mặc định:
raw_human/
2026-06-11_batch1/
episode_0.hdf5
episode_0.svo2
episode_1.hdf5
episode_1.svo2
2026-06-11_batch2/
episode_0.hdf5
episode_0.svo2
Với beginner, hãy thu ít nhưng sạch. Một task như "put the pillow on the bed" hoặc "grasp the toy and put it on the table" tốt hơn mười task lẫn lộn. Mỗi episode nên bắt đầu và kết thúc ở trạng thái dễ nhận diện, camera không bị che, tay không ra khỏi frame quá lâu, và operator lặp lại cùng instruction.
Bước 2: chạy human data pipeline
Command nhanh nhất là:
cd data_alignment/human_data_process
./run_human_data_pipeline.sh \
--input_dir /data/ego/raw_human \
--output_dir /data/ego/intermediate \
--final-output-dir /data/ego/final \
--file all
Mặc dù trong bài này ta gọi đây là bước 2 của pipeline bốn bước, bên trong script có năm stage nhỏ:
| Stage | Script liên quan | Kết quả |
|---|---|---|
| Reorder | scripts/reorder_episodes_for_raw.py |
Sắp xếp episode theo thời gian, copy thành episode_N.hdf5 và episode_N.svo2 |
| Navigation | process_navigation_pipeline.py |
Từ body_pose, tính trajectory, velocity [vx, vy, yaw_rate] |
| Downsample | downsample_episode.py |
Giảm tần số, mặc định factor 5; tạo teleop_navigate_command rời rạc |
| Merge camera | merge_camera_only.py |
Match timestamp và ghi ảnh ZED left/right vào HDF5 |
| Hand status | add_hand_status.py |
Ghi hand_status dạng (M, 2) cho trái/phải |
Nếu muốn debug từng phần, chạy từng script độc lập:
# 1. Reorder
python scripts/reorder_episodes_for_raw.py \
--input_dir /data/ego/raw_human \
--output_dir /data/ego/intermediate \
--file all \
--workers 32
# 2. Navigation: pelvis trajectory -> velocity command
python process_navigation_pipeline.py \
--dataset-dir /data/ego/intermediate \
--baseline-sec 15 \
--tangent-lag 5 \
--overwrite \
--no-png
# 3. Downsample: tạo teleop_navigate_command
python downsample_episode.py \
--dataset-dir /data/ego/intermediate \
--downsample-rate 5 \
--overwrite
# 4. Merge camera: SVO2 -> HDF5 images
python merge_camera_only.py \
--dataset-dir /data/ego/intermediate \
--output-dir /data/ego/final \
--num-workers 32
# 5. Hand status: pose tay -> open/close
python add_hand_status.py \
--raw /data/ego/intermediate/hdf5 \
--mid /data/ego/final \
--target /data/ego/final \
--downsample 5 \
--num_workers 32
Sau bước này, HDF5 cuối nên có các field quan trọng:
body_pose
navigation_command
teleop_navigate_command
delta_height
observation_image_left
observation_image_right
camera_timestamp
timestamp_diff_ms
hand_status
teleop_navigate_command là chỗ lower-body alignment bắt đầu có ý nghĩa. Script navigation đọc pelvis và hip landmarks, smoothing trajectory bằng Savitzky-Golay, ước lượng hướng tangent, rồi biến chuyển động người thành velocity command trong local body frame. Sau downsample, command được rời rạc hóa bằng threshold để giống primitive teleop của robot hơn. Đây không phải ground truth hoàn hảo, nhưng nó đủ nhất quán để policy học khi nào đi tới, lùi, sang trái/phải, quay hoặc đứng.
hand_status là chỗ dexterous hand được đơn giản hóa. add_hand_status.py lấy pose bàn tay, tính metric dựa trên khoảng cách fingertip và độ cong ngón, rồi fit square wave để suy ra 0/1. README định nghĩa 1 = closed, 0 = open, shape (M, 2) theo thứ tự [left, right]. Với G1 + Dex3, biểu diễn này thô hơn joint-level hand pose, nhưng dễ học hơn và ít nhạy hơn với sai số tracker.
Bước 3: view alignment bằng viewport_transform_batch_h5.py
View alignment là phần hay bị bỏ qua vì nó tốn GPU và nhìn giống augmentation ảnh. Với EgoHumanoid, đây là phần cốt lõi. Paper giải thích rằng chênh lệch chiều cao và camera pose giữa người và humanoid tạo ra visual gap rõ rệt. Pipeline view alignment dùng MoGe để suy ra per-pixel 3D point map/depth, dùng Cache3D để warp point cloud sang viewpoint robot, rồi dùng Stable Diffusion inpainting để lấp vùng thiếu do disocclusion.
Chạy một file HDF5:
cd data_alignment/view_alignment
python viewport_transform_batch_h5.py \
--h5_file /data/ego/final/episode_0.hdf5 \
--image_key "observation_image_left" \
--trajectory "down" \
--movement_distance 0.07 \
--output_dir /data/ego/view_aligned/episode_0
Chạy cả thư mục với nhiều GPU:
python viewport_transform_batch_h5.py \
--h5_dir /data/ego/final \
--batch_size 32 \
--trajectory "down" \
--movement_distance 0.07 \
--num_gpus 4 \
--output_dir /data/ego/view_aligned
Các argument cần hiểu:
| Argument | Ý nghĩa | Gợi ý beginner |
|---|---|---|
--image_key |
Field ảnh trong HDF5 | Bắt đầu với observation_image_left; xử lý right sau nếu cần |
--trajectory |
Hướng shift camera: left, right, up, down, forward, backward |
Với người cao hơn robot, thử down trước |
--movement_distance |
Khoảng dịch camera | README ví dụ 0.07; đừng tăng quá mạnh khi chưa xem ảnh |
--movement_distance_noise |
Nhiễu pose mỗi sample | Hữu ích để policy chịu được sai số mounting |
--sd_model |
Inpainting model | Mặc định stabilityai/stable-diffusion-2-inpainting |
--save_h5 |
Lưu lại dạng H5 | Dùng khi muốn thay ảnh trong dataset thay vì chỉ xuất ảnh kiểm tra |
Sau khi chạy, đừng chỉ nhìn loss training. Hãy mở vài frame trước/sau alignment. Nếu warp làm méo bàn tay hoặc đồ vật đang thao tác, policy có thể học tín hiệu sai. Nếu inpainting lấp mất vật nhỏ, giảm distance hoặc kiểm tra depth validity mask. Với robot data thật, bạn thường không cần view alignment; với human data, đây là bước giúp ảnh của người gần với input robot hơn.
Bước 4: action alignment và HDF5 robot-ready
Action alignment trong EgoHumanoid có ba phần. Upper body dùng action_eef và action_delta_eef, lower body dùng teleop_navigate_command, hand dùng hand_status. convert_to_lerobot.py trong repo mong thấy các field kiểu này trong HDF5:
action_eef # (N, 14), pose end-effector
action_delta_eef # (N, 12), delta end-effector action
teleop_navigate_command # (N, 3), command điều hướng rời rạc
delta_height # (N,), thay đổi chiều cao base/pelvis
hand_status # (N, 2), trái/phải open-close
observation_image_left # ảnh RGB/JPEG từ ZED
Nếu file của bạn mới có navigation và hand status nhưng chưa có EEF action, kiểm tra utility process_human_eef_pipeline.py trong thư mục human data process. README ghi utility này tính hand end-effector poses 7D và delta 6D từ skeleton data. Với tutorial beginner, cách kiểm tra tốt nhất là dùng h5py in ra keys và shape:
python - <<'PY'
import h5py
path = "/data/ego/final/episode_0.hdf5"
with h5py.File(path, "r") as f:
for key in [
"action_eef",
"action_delta_eef",
"teleop_navigate_command",
"delta_height",
"hand_status",
"observation_image_left",
"observation_image_right",
]:
if key in f:
print(key, f[key].shape, f[key].dtype)
else:
print("MISSING", key)
PY
Một episode tốt để convert phải thỏa ba điều kiện. Thứ nhất, số frame của action và ảnh phải khớp hoặc được loader xử lý nhất quán. Thứ hai, teleop_navigate_command không được toàn zero nếu task có di chuyển. Thứ ba, hand_status phải chuyển trạng thái ở đoạn grasp/release, không nhảy liên tục từng frame. Nếu hand_status bị rung, hãy chạy lại add_hand_status.py với cấu hình wave type hoặc transition shift thủ công thay vì để policy học nhiễu.
Bước 5: chuyển sang LeRobot
Khi HDF5 đã sạch, chuyển sang LeRobot:
cd data_alignment
python convert_to_lerobot.py \
--src-path /data/ego/final \
--output-path /data/ego/lerobot \
--repo-id egohumanoid_pick_toy_v1 \
--fps 20 \
--task "grasp the toy and put it on the table"
Nếu dataset lớn, dùng worker song song:
python convert_to_lerobot.py \
--src-path /data/ego/final \
--output-path /data/ego/lerobot \
--repo-id egohumanoid_pick_toy_v1 \
--num-workers 16 \
--fps 20 \
--task "grasp the toy and put it on the table"
Trong code, LeRobot feature chính gồm observation.images.left, action_eef, action_delta_eef, teleop_navigate, delta_height và hand_status. Lưu ý ảnh left là feature chính trong converter hiện tại; nếu bạn muốn train stereo left/right, cần mở rộng config và loader thay vì giả định right tự được dùng. Với beginner, hãy train bản left-only trước để giảm số biến.
Task instruction rất quan trọng. Đừng đặt instruction chung chung kiểu "do task". Nếu episode là nhặt đồ bỏ lên bàn, dùng câu cụ thể. Nếu episode là bỏ rác vào thùng, tách thành repo-id khác hoặc ít nhất task khác. VLA học từ ảnh, action và ngôn ngữ; task label mơ hồ làm dataset khó kiểm soát.
Bước 6: train, serve và deploy
Trước training, README EgoHumanoid yêu cầu tính normalization statistics:
uv run python scripts/compute_norm_states_ultra_fast.py \
--config-name=norm_compute
Sau đó train:
XLA_PYTHON_CLIENT_MEM_FRACTION=0.9 \
uv run scripts/train.py pi05_g1_custom \
--exp_name=egohumanoid_pick_toy_v1
Nếu dùng nhiều GPU:
XLA_PYTHON_CLIENT_MEM_FRACTION=0.9 \
uv run scripts/train.py pi05_g1_custom \
--exp_name=egohumanoid_pick_toy_v1 \
--fsdp-devices 4
Checkpoint được lưu dưới:
checkpoints/<config_name>/<exp_name>/<iteration>
Khi có checkpoint, chạy policy server:
uv run scripts/serve_policy.py policy:checkpoint \
--policy.config=pi05_g1_custom \
--policy.dir=checkpoints/pi05_g1_custom/egohumanoid_pick_toy_v1/10000
Server mặc định nghe port 8000. Phía robot/client chạy:
cd /root/Projects/openpi
python scripts/deploy.py \
--host <server_ip> \
--port 8000
Đây là nơi phải quay lại bài 1 và bài 2 về safety. Đừng deploy lên G1 thật chỉ vì server đã trả action. Kiểm tra camera mount, network, emergency stop, low-level locomotion policy, workspace không có người đứng sát robot, và thử task ngắn với tốc độ thấp. EgoHumanoid giúp policy học từ human data, nhưng nó không xóa các rủi ro của whole-body robot thật.
EgoHumanoid hay TWIST2: thu robot trực tiếp hay tận dụng human demos?
| Câu hỏi | TWIST2 | EgoHumanoid |
|---|---|---|
| Dữ liệu chính | Robot teleoperation trực tiếp | Human egocentric demos + robot data giới hạn |
| Điểm mạnh | Action/state gần robot thật, ít embodiment gap | Scale nhanh hơn, đa dạng môi trường hơn, không cần robot cho mọi demo |
| Điểm yếu | Tốn thời gian robot, operator mệt, khó mở rộng scene | Cần view/action alignment, dễ sai nếu HDF5 không sạch |
| Camera | Robot-centric active vision trong teleop | Human headset/ZED được align sang viewpoint robot |
| Lower-body signal | Command từ teleop/retarget trực tiếp | Pelvis trajectory -> teleop_navigate_command |
| Hand signal | Robot hand command/tracking | Human hand pose -> hand_status |
| Khi nên chọn | Lab đã có G1 ổn định, muốn imitation data chính xác | Lab muốn tận dụng người demo ở nhiều bối cảnh, robot time hạn chế |
Cách ra quyết định thực tế: nếu task đòi hỏi contact chính xác, lực tinh tế hoặc robot morphology quyết định thành bại, hãy thu robot data trực tiếp trước. Ví dụ kéo xe nặng, mở tay nắm khó, thao tác ở rìa workspace của G1. Nếu task chủ yếu cần hiểu scene, di chuyển tới vật, grasp/release ở mức tương đối và nhiều biến thể môi trường, EgoHumanoid rất đáng thử vì human demos rẻ hơn robot demos.
Một lab tốt không cần chọn tuyệt đối. Dùng TWIST2 để tạo robot dataset sạch cho vài task lõi. Dùng EgoHumanoid để mở rộng diversity: nhiều phòng, nhiều vị trí đồ vật, nhiều cách tiếp cận. Sau đó co-train để policy vừa có grounding robot thật, vừa thấy nhiều cảnh mà robot chưa từng được teleop trực tiếp.
Checklist debug trước khi train dài
| Kiểm tra | Command/cách làm | Kỳ vọng |
|---|---|---|
| HDF5 có key cần thiết | h5py in keys và shape |
Không thiếu teleop_navigate_command, image, hand_status, EEF action |
| FPS hợp lý | Kiểm tra metadata và frame count | Human data sau downsample thường về 20 Hz |
| Camera sync | Xem timestamp_diff_ms |
Không có spike lớn kéo dài |
| Navigation không toàn zero | Plot hoặc in unique command | Task có đi bộ thì command phải đổi |
| Hand status có nghĩa | Plot hai cột trái/phải | Chuyển trạng thái ở grasp/release |
| View alignment không phá vật | Mở frame trước/sau | Vật và bàn tay vẫn nhận ra được |
| LeRobot load được | Chạy smoke train nhỏ | Dataloader không lỗi image/action shape |
Nếu một trong các dòng trên lỗi, đừng train qua đêm. VLA có thể giảm loss trên dữ liệu bẩn, nhưng robot thật sẽ phơi bày lỗi rất nhanh. Với EgoHumanoid, chất lượng alignment quyết định giá trị của human demo.
Kết luận
EgoHumanoid là stack đáng học vì nó đưa bài toán humanoid VLA ra khỏi giới hạn "có bao nhiêu giờ robot teleop". Thay vì coi human videos là tham khảo thị giác rời rạc, EgoHumanoid biến chúng thành dataset có schema gần robot: ảnh egocentric đã align viewpoint, teleop_navigate_command cho lower body, action_delta_eef cho tay và hand_status cho grasp. Khi convert sang LeRobot và train bằng scripts/train.py, bạn có một đường đi rõ ràng từ human demo tới policy triển khai trên G1.
Nhưng lợi thế này chỉ có ý nghĩa nếu dữ liệu được kiểm tra cẩn thận. run_human_data_pipeline.sh, viewport_transform_batch_h5.py, process_navigation_pipeline.py, add_hand_status.py và convert_to_lerobot.py không phải các bước hành chính; chúng là nơi embodiment gap được thu hẹp. Nếu xem chúng như black box, EgoHumanoid sẽ cho bạn một dataset đẹp tên nhưng khó dùng. Nếu debug từng field HDF5, bạn có một cách mở rộng data thực dụng cho whole-body VLA 2026.