Trong bài 3, chúng ta đã đi qua nhánh manipulation của GRAIL: từ video RGB, pipeline lấy pose người, mask/depth, object pose 6-DoF bằng FoundationPose, rồi tối ưu HOIOptimizer để có trajectory người-object theo thời gian. Bài 4 đổi góc nhìn: không phải lúc nào "object" trong 4D HOI cũng là vật được nhấc lên, đẩy đi, hoặc xoay trong tay. Với curb, slope, stairs và ghế ngồi, phần quan trọng của scene thường đứng yên. Người di chuyển quanh nó, bước lên nó, đặt chân lên nó, hoặc ngồi xuống nó.
Đây là lý do GRAIL có nhóm config locomotion/sitting như configs/recon_4dhoi/loco_smplx.yaml. Tài liệu reconstruction của GRAIL mô tả file này cho "locomotion / terrain / sitting" với SMPL-X body model. Trong config, pipeline.is_static_obj: true nói rằng object/terrain không có global motion, nên stage object tracking có thể bỏ qua FoundationPose và phát ra static poses trực tiếp. Cùng lúc, filter_object_motion: static_only ở stage filtering giữ lại đúng loại reconstruction mà nhánh locomotion cần: người tương tác với scene tĩnh, chứ không phải video trong đó object bị tracker kéo đi như một vật manipulation.
Nguồn kỹ thuật chính dùng trong bài:
- GRAIL project page
- GRAIL GitHub README
- 4D HOI Reconstruction docs
- loco_smplx.yaml
- manip_smplx.yaml
- gen_terrain.py
- FoundationPose, SAM2, MoGe, Isaac Lab
Roadmap series
- Tạo asset 3D và terrain cho GRAIL: hai nhánh asset, prompt object, sharding và chuẩn bị file cho downstream.
- Sinh video 2D HOI bằng Blender và Kling: render frame điều kiện, camera/depth và video foundation model.
- Tái dựng 4D HOI: GEM, SAM2, MoGe: pose người, object tracking, optimization, filtering và visualization.
- Locomotion trên terrain tĩnh: dùng curb, slope, stairs và sitting như static-scene 4D HOI.
- Retarget trajectory sang Unitree G1: chuyển motion người/object thành mục tiêu robot.
- Train policy và export dữ liệu: đóng gói demonstration, train tracker/policy và chuẩn bị sim-to-real.
Nếu bạn muốn đặt bài này vào bối cảnh locomotion rộng hơn, đọc thêm G1 đi terrain bằng reinforcement learning và Humanoid loco-manipulation. Hai bài đó giải thích vì sao terrain contact, foot placement và whole-body balance quan trọng không kém object grasp.
Mục tiêu của bài
Sau bài này, bạn sẽ biết:
- Vì sao GRAIL xem curb, slope, stairs và sitting là static-scene 4D HOI.
- Cách tạo dataset terrain như
syn_stairsbằnggrail.pipelines.gen_terrain. - Cách chạy reconstruction với
configs/recon_4dhoi/loco_smplx.yaml. - Sự khác nhau giữa
filter_object_motion: dynamic_onlycho manipulation vàstatic_onlycho locomotion/sitting. - Cách kiểm tra output trước khi chuyển sang bài 5: retarget sang Unitree G1.
Điểm cần nhớ: "static object" không có nghĩa là interaction đơn giản. Stairs không chuyển động, nhưng người phải đặt chân đúng bậc, giữ thăng bằng, nâng hông, điều chỉnh torso và tránh xuyên mesh. Ghế không bay lên, nhưng sitting vẫn là contact-rich whole-body motion: chân, hông, lưng và đôi khi tay đều có thể tham gia.
Tư duy đúng: object động và scene tĩnh
Trong manipulation, object là thực thể có trajectory riêng. Ví dụ một người nhấc cordless drill khỏi bàn. Drill thay đổi translation, rotation, contact state và có thể rời khỏi support surface. Reconstruction phải biết object đang ở đâu trong từng frame, vì policy downstream cần học mối quan hệ giữa tay, object và chuyển động object.
Trong locomotion terrain, "object" thường là một phần của environment. Curb, slope và stairs có mesh, material, pose, scale, camera relationship và mask. Nhưng chúng không tự di chuyển trong clip. Nếu người bước lên bậc thang, thứ thay đổi là pose người, contact chân, root trajectory, chiều cao hông và động học toàn thân. Terrain chỉ là geometry cố định tạo constraint.
Sitting nằm giữa locomotion và manipulation. Ghế có thể được gọi là object, nhưng trong clip "ngồi xuống ghế", ghế thường đứng yên. Ta không muốn tracker kết luận rằng ghế trượt theo người chỉ vì mask bị occlusion bởi chân hoặc thân. Với GRAIL, đây là static-object interaction: người đổi trạng thái từ đứng sang ngồi, còn ghế là anchor của scene.
| Tình huống | Object/scene có nên di chuyển? | Config phù hợp | Filter nên dùng | Lý do |
|---|---|---|---|---|
| Nhấc drill lên | Có | manip_smplx.yaml |
dynamic_only |
Object motion là tín hiệu chính của task |
| Đẩy hộp | Có | manip_smplx.yaml |
dynamic_only |
Object translation cần được reconstruct |
| Bước qua curb | Không | loco_smplx.yaml |
static_only |
Curb là geometry cố định, người mới di chuyển |
| Đi trên slope | Không | loco_smplx.yaml |
static_only |
Slope tạo mặt tiếp xúc và thay đổi foot placement |
| Leo stairs | Không | loco_smplx.yaml |
static_only |
Bậc thang không có trajectory riêng |
| Ngồi xuống ghế | Thường không | loco_smplx.yaml hoặc variant sitting |
static_only |
Ghế là support surface, không phải vật pickup |
loco_smplx.yaml khác gì manip_smplx.yaml?
Hai config có cùng mục tiêu tổng quát: lấy video 2D HOI và khôi phục dữ liệu 4D đủ sạch để robot dùng. Chúng vẫn dùng human pose, mask/depth, optimizer, filtering và visualization. Điểm khác nằm ở giả định vật lý về object.
Trong manip_smplx.yaml, comment của config nói rõ đây là dynamic-object HOI: người pick up, push hoặc pull object, và object có chuyển động trong interaction. Vì vậy pipeline.is_static_obj là false. Stage object pose chạy FoundationPose để estimate object 6-DoF theo frame. Sau đó stage 5 dùng filter_object_motion: "dynamic_only" để loại các reconstruction trong đó object gần như đứng yên. Với manipulation, object đứng yên thường là dấu hiệu video không đúng task hoặc tracker thất bại.
Trong loco_smplx.yaml, comment của config nói rõ đây là static-object scenario: terrain features như curbs, slopes, stairs và sitting interactions. Object không di chuyển trong clip, nên FoundationPose được bypass. Stage 3 vẫn tồn tại trong pipeline flow, nhưng thay vì solve trajectory động, nó phát ra static poses dựa trên scene/object pose đã biết. Stage 5 dùng filter_object_motion: "static_only" để giữ những reconstruction có object tĩnh. Với locomotion, object đứng yên không phải lỗi; đó là điều kiện đúng.
Một snippet rút gọn dễ nhớ:
# configs/recon_4dhoi/manip_smplx.yaml
filtering:
filter_object_motion: "dynamic_only"
pipeline:
is_static_obj: false
# configs/recon_4dhoi/loco_smplx.yaml
filtering:
filter_object_motion: "static_only"
object_static_thr: 0.02
pipeline:
is_static_obj: true
object_static_thr là ngưỡng để phân biệt object tĩnh và object có motion đáng kể. Đừng hiểu nó như một thông số vật lý tuyệt đối cho mọi dataset. Nó là threshold kiểm tra reconstruction. Nếu bạn scale asset sai, dùng camera quá xa, hoặc có clip bị jitter mạnh, bạn vẫn cần xem video visualization thay vì chỉ đọc log.
Vì sao bypass FoundationPose là hợp lý?
FoundationPose là công cụ mạnh cho 6D object pose estimation và tracking, đặc biệt khi có CAD/mesh object. Với manipulation, nó giải quyết bài toán rất thực tế: object có thể rời khỏi vị trí ban đầu, quay trong tay, bị che một phần, rồi xuất hiện lại. Pipeline cần pose object theo từng frame.
Nhưng với terrain, bài toán khác hẳn. Stairs, curb và slope vốn nằm cố định trong scene render ban đầu. Camera, mesh, scale và first-frame pose đã biết từ pipeline asset/video. Nếu vẫn bắt FoundationPose track chúng như một vật dynamic, ta tạo thêm một nguồn nhiễu không cần thiết. Một vài frame occlusion bởi chân có thể làm mask đổi hình, tracker jitter, hoặc pose bị kéo theo người. Kết quả là terrain có thể "rung" trong dữ liệu dù trong thế giới vật lý nó đứng yên.
Bypass FoundationPose giúp static scene giữ đúng vai trò của nó:
- Terrain pose ổn định xuyên suốt clip.
- Optimizer tập trung vào human trajectory, foot contact và depth alignment.
- Stage filtering không loại nhầm clip tốt vì object không di chuyển.
- Output phù hợp hơn cho retargeting và policy training, nơi robot cần học đi trên scene cố định.
Điều này cũng tiết kiệm thời gian. Tài liệu GRAIL ghi stage FoundationPose mất khoảng 40 giây/video trên L40S cho nhánh thông thường. Với batch terrain lớn, bỏ qua tracking động không chỉ giảm runtime mà còn giảm failure mode.
Tạo syn_stairs bằng gen_terrain
Nếu bạn đã đọc bài 1, bạn biết GRAIL có nhánh terrain thủ tục. Script grail.pipelines.gen_terrain tạo synthetic terrain assets gồm curb, slope và stairs, xuất mỗi asset thành OBJ/MTL/texture. Theo comment trong code, kích thước terrain đã được pre-scale cho character retargeted theo G1, khoảng 70% chiều cao SMPL-X người; nhờ vậy downstream có thể dùng obj_scale: [1.0, 1.0, 1.0] thay vì scale lại ở render time.
Từ root repo GRAIL, tạo một batch stairs:
python -m grail.pipelines.gen_terrain \
--type stairs \
--num 50 \
--seed 20260607 \
--output_dir data/syn_stairs
Một folder terrain thường có dạng:
data/syn_stairs/
stairs_0000/
model.obj
model.mtl
texture.jpg
stairs_0001/
model.obj
model.mtl
texture.jpg
...
Nếu muốn tạo cả curb, slope và stairs:
python -m grail.pipelines.gen_terrain \
--type all \
--num 300 \
--seed 20260607 \
--output_dir data/syn_terrain
Với beginner, ba tham số quan trọng nhất là:
| Tham số | Ý nghĩa | Gợi ý |
|---|---|---|
--type |
Chọn curb, slope, stairs hoặc all |
Bắt đầu bằng stairs nếu muốn học bài này |
--num |
Số asset tạo ra | 20-50 đủ để test pipeline, lớn hơn khi train |
--seed |
Seed random | Luôn đặt seed để tái lập lỗi |
--output_dir |
Nơi ghi asset | Dùng tên dataset rõ như data/syn_stairs |
Đừng vội tạo hàng nghìn asset ngay lần đầu. Hãy tạo ít, chạy qua 2D HOI/video generation, reconstruction và visualization. Nếu asset quá dốc, bậc quá cao, texture gây mask lỗi, hoặc camera không thấy chân, bạn sẽ phát hiện sớm.
Chạy recon_4dhoi với config locomotion
Sau khi đã có video 2D HOI cho dataset stairs, lệnh reconstruction cơ bản là:
python -m grail.pipelines.recon_4dhoi \
--dataset syn_stairs \
--results_dir results \
--config configs/recon_4dhoi/loco_smplx.yaml
Nếu môi trường của bạn đã expose wrapper CLI recon_4dhoi, ý tưởng tương đương là:
recon_4dhoi \
--dataset syn_stairs \
--results_dir results \
--config configs/recon_4dhoi/loco_smplx.yaml
Nếu chỉ muốn chạy một video cụ thể:
python -m grail.pipelines.recon_4dhoi \
--video_id syn_stairs/<category>/<video_name> \
--results_dir results \
--config configs/recon_4dhoi/loco_smplx.yaml
Trong GRAIL, video discovery mặc định tìm dưới:
results/generation/videos_kling/<dataset>/<category>/*.mp4
Output hợp lệ sau filtering nằm dưới:
results/generation/4dhoi_recon_smplx_valid/<dataset>/<category>/<video_id>/
hoi_data/hoi_data.pkl
mesh_data/
result_vis/input.mp4
result_vis/recon_result.mp4
result_vis/recon_comparison.mp4
result_vis/recon_result_top_view.mp4
result_vis/recon_result.html
Với locomotion, file bạn nên xem đầu tiên là recon_comparison.mp4: nó cho biết body mesh có bám người trong video không. File thứ hai là recon_result_top_view.mp4: nó cho thấy trajectory root và vị trí chân so với stairs từ góc top-down. Một clip có thể nhìn ổn từ camera chính nhưng sai ở trục depth; top view sẽ lộ lỗi người đi xuyên qua bậc hoặc đứng lệch khỏi mặt cầu thang.
Checklist trước khi tin output
Static-object mode không tự động biến mọi video stairs thành dữ liệu tốt. Nó chỉ đặt đúng giả định cho object. Bạn vẫn cần kiểm tra các lỗi cơ bản:
| Cần kiểm tra | Dấu hiệu tốt | Dấu hiệu lỗi | Cách xử lý |
|---|---|---|---|
| Body pose | Skeleton/mesh bám cơ thể | Chân drift, hông nhảy, người đổi scale | Quay lại video 2D hoặc stage human pose |
| Foot contact | Bàn chân gần mặt bậc/slope | Chân xuyên qua mesh hoặc lơ lửng | Kiểm tra depth, camera, terrain scale |
| Static object | Stairs/ghế đứng yên | Mesh terrain rung hoặc trượt | Đảm bảo dùng loco_smplx.yaml và is_static_obj: true |
| Mask/depth | Người và object tách rõ | Mask dính chân vào stairs, depth méo | Kiểm tra first-frame masks, camera gần hơn |
| Filtering | Clip tốt vào _valid |
Tất cả bị invalid | Xem log threshold, kiểm tra static_only và object_static_thr |
Một mẹo thực dụng: nếu bạn chỉ đổi thông số optimizer hoặc filtering, không cần chạy lại toàn bộ stack. Sau khi stage 1-3 đã có cache ổn, bạn có thể skip các stage đầu:
python -m grail.pipelines.recon_4dhoi \
--dataset syn_stairs \
--results_dir results \
--config configs/recon_4dhoi/loco_smplx.yaml \
--skip_step1 \
--skip_step2 \
--skip_step3
Nhưng nếu bạn đổi video, first-frame mask, asset mesh, camera hoặc scale, hãy cẩn thận với cache cũ. --skip_done rất hữu ích khi chạy batch lớn, nhưng nó cũng có thể khiến bạn tưởng config mới đã được áp dụng trong khi pipeline đang dùng artifact cũ.
Sitting: vẫn là static-scene interaction
Sitting thường làm người mới nhầm vì ghế là một object rõ ràng. Trong manipulation, object là thứ robot/human điều khiển. Trong sitting, ghế là support geometry. Mục tiêu của reconstruction không phải học cách nhấc ghế, mà là học motion toàn thân khi hạ trọng tâm, đưa hông về sau, giữ foot support, tránh ngã và tạo contact hợp lý với mặt ghế.
Vì vậy, với clip "người ngồi xuống ghế", is_static_obj: true thường hợp lý hơn. Nếu để dynamic tracking, occlusion giữa chân, thân và ghế có thể làm FoundationPose tạo trajectory ghế giả. Downstream retarget có thể nhận một scene trong đó ghế trượt nhẹ theo hông người. Với robot, đó là dữ liệu nguy hiểm: policy có thể học rằng support surface tự điều chỉnh theo robot, trong khi ngoài đời ghế đứng yên.
Khi kiểm tra sitting output, đừng chỉ nhìn contact hông. Hãy xem cả:
- Hai bàn chân có giữ support đủ lâu trước khi hông chạm ghế không.
- Đầu gối và hông có gập hợp lý không.
- Mesh người có xuyên sâu vào mặt ghế hoặc lưng ghế không.
- Root trajectory có bị kéo về ghế quá nhanh không.
- Ghế có đứng yên trong HTML/MP4 visualization không.
Nếu clip có cảnh người kéo ghế ra rồi mới ngồi, đó không còn là static sitting đơn giản. Bạn có thể cần tách thành hai task: manipulation object động cho pha kéo ghế, và static sitting cho pha ngồi. Trộn cả hai vào một config static có thể làm mất phần object motion thật; chạy dynamic lại có thể làm hỏng pha ghế đứng yên. Với dataset cho humanoid policy, tách task thường sạch hơn.
Static-scene 4D HOI vẫn là 4D HOI
Một hiểu nhầm phổ biến: nếu object không chuyển động, liệu có còn là 4D HOI không? Câu trả lời là có. 4D HOI không bắt buộc mọi thành phần đều động. "4D" nghĩa là hệ 3D được quan sát theo thời gian. Người thay đổi pose theo thời gian, contact thay đổi theo thời gian, khoảng cách giữa chân và terrain thay đổi theo thời gian, và robot downstream cần những tín hiệu đó.
Trong locomotion, static scene đôi khi còn quan trọng hơn object motion. Terrain geometry quyết định feasible motion:
- Curb yêu cầu nâng chân vừa đủ, không quệt mũi chân.
- Slope thay đổi normal của mặt tiếp xúc, ảnh hưởng đến ankle/hip strategy.
- Stairs yêu cầu sequence foot placement theo bậc, không chỉ đi thẳng trên mặt phẳng.
- Chair sitting yêu cầu chuyển trọng tâm và contact support mới ở hông.
Nếu bạn cố ép các task này vào dynamic-object reconstruction, pipeline có thể tối ưu sai mục tiêu. Nó sẽ dành năng lực để giải object pose động không cần thiết, trong khi thứ cần sạch là human-root trajectory, foot contact và scene alignment.
Khi nào không dùng static-object mode?
Không phải cứ thấy terrain hoặc ghế là dùng static mode trong mọi trường hợp. Hãy hỏi: vật đó có thực sự đứng yên trong clip không?
| Câu hỏi | Nếu câu trả lời là có | Config nên cân nhắc |
|---|---|---|
| Người có nhấc object khỏi mặt đất không? | Có object motion thật | manip_smplx.yaml |
| Người có đẩy/kéo ghế, hộp, xe đẩy không? | Có translation/rotation | Dynamic manipulation config |
| Stairs/slope có là scene cố định không? | Có, scene đứng yên | loco_smplx.yaml |
| Người chỉ ngồi xuống ghế đứng yên? | Ghế là support surface | loco_smplx.yaml |
| Clip gồm kéo ghế rồi ngồi? | Hai pha khác nhau | Tách task hoặc tạo config riêng |
Nói ngắn gọn: dùng static mode khi object pose là điều kiện của scene, không phải kết quả của hành động. Dùng dynamic mode khi object pose là biến trạng thái mà robot cần điều khiển.
Chạy batch và sharding
Khi dataset terrain đã ổn, bạn có thể chạy theo shard. Tài liệu GRAIL có pattern --job_chunk_idx và --num_job_chunks để chia video cho nhiều worker:
python -m grail.pipelines.recon_4dhoi \
--dataset syn_stairs \
--results_dir results \
--config configs/recon_4dhoi/loco_smplx.yaml \
--job_chunk_idx 0 \
--num_job_chunks 8 \
--skip_done
Worker thứ hai đổi --job_chunk_idx 1, rồi tiếp tục đến 7. Với static mode, bạn vẫn nên giữ visualization cho một subset. Batch lớn mà không xem video rất dễ tích lũy lỗi scale hoặc camera.
Một workflow lành mạnh:
- Tạo 20-50 terrain assets bằng
gen_terrain. - Sinh một batch video 2D HOI nhỏ.
- Chạy
loco_smplx.yamlcho 5-10 video đầu. - Xem
recon_comparison.mp4, top view và HTML. - Sửa asset/camera/prompt nếu cần.
- Chạy batch lớn với sharding và
--skip_done. - Chỉ chuyển
_validsang retargeting.
Kết luận
loco_smplx.yaml không phải biến thể nhỏ của config manipulation; nó là cách GRAIL nói rõ một giả định vật lý khác. Với manipulation, object phải di chuyển, FoundationPose cần track 6-DoF pose, và dynamic_only giúp loại dữ liệu không có object motion. Với curb, slope, stairs và sitting, scene đứng yên mới là đúng. pipeline.is_static_obj: true bypass FoundationPose để tránh trajectory giả, còn filter_object_motion: static_only giữ lại các interaction mà locomotion policy cần.
Khi làm với GRAIL, hãy phân loại task trước khi chạy reconstruction: object pose là state được điều khiển, hay là geometry cố định của môi trường? Câu trả lời quyết định config, filter, cách debug và cả chất lượng dữ liệu đưa sang retargeting.