▶영상: 사람 원본 → 데이터셋 이미지 → 물리 시뮬 재생
각 영상은 한 episode 전체(30 fps)이고 세 패널이 같은 시각을 보여준다. tools/render_physics.py --with-dataset --video로 production 출력(0cb02f5)에서 렌더했다.
왼쪽: 사람 원본
H2O ego 영상. task, GT 물체 높이.
가운데: 데이터셋 이미지
학습에 들어가는 observation.images.ego. 손을 지운 영상에 로봇을 합성한 것.
오른쪽: 물리 시뮬 재생
dataset action만 MuJoCo 트윈에서 재생. 초록은 GT 물체 위치, 빨강은 로봇 없이 둔 물체. 판정, ADD-S, sim 높이, finger 접촉, gap 표시.
두 로봇 모두 성공 (_phys에 포함)
ALOHA 성공 place the espresso: 들고 있던 상자(GT 158 mm)를 내려놓음. sim 최고 높이 158 mm, 최종 오차 4 mm. 로봇이 없으면 상자는 떨어짐(빨강).
UR5e 성공 같은 episode를 UR5e로. 최종 오차 7 mm.
ALOHA 성공 squeeze the lotion: 로션을 들어 올려 짬. sim 167 mm / GT 174 mm, 최종 오차 6 mm.
UR5e 성공 같은 episode를 UR5e로. sim 165 mm, 최종 오차 9 mm.
ALOHA 성공 apply the spray: sim 139 mm / GT 146 mm, 최종 오차 7 mm.
UR5e 성공 같은 episode를 UR5e로. sim 145 mm, 최종 오차 3 mm.
넓은 물체: UR5e 성공, ALOHA 실패
UR5e 성공 pour the milk: 2F-85(85 mm stroke)가 우유팩을 잡고 따름. 최종 오차 4 mm.
ALOHA 실패: start_collision 같은 episode. ALOHA(58 mm stroke)로는 우유팩을 잡을 수 없어(오른팔 100% ungraspable) 사람 손 궤적을 따름. 시작부터 gripper가 물체 안 18 mm(가운데 패널에서 gripper가 팩을 관통). 오른팔 모든 frame에 aux.object_penetration 표시. 기본 데이터셋에는 있고 _phys에서는 빠짐.
UR5e 성공 take out the chips: 통을 들어 올림. sim 121 mm / GT 125 mm, 최종 오차 5 mm.
ALOHA 실패: slipped 같은 episode. 통 폭 74 mm가 ALOHA 최대 개폐폭 58 mm보다 넓어 grasp를 만들 수 없음(ungraspable, 왼팔 88% frame). 손가락이 14 frame 닿기만 하고 들지 못함(sim 높이 0). 왼팔 97% frame에 관통 표시. 기본 데이터셋에만 있음.
1배경 / 목적
이전 production 데이터셋(2026-10-17)은 사람 손 keypoint에서 바로 gripper pose와 폭을 만들었다. H2O와 같은 장면을 MuJoCo로 만들고 dataset action만 재생하면, 물체가 영상처럼 움직인 episode는 ALOHA 4/829, UR5e 61/829뿐이었다. gripper가 물체 폭보다 넓게 열려 있거나, 물체를 관통한 상태로 움직였기 때문이다.
사용자 요구는 "h2o랑 같은 세팅을 시뮬에 만들어놓고, 동작을 잘 하는지 성공을 만들어서 확인"이다. 그래서 두 가지가 필요했다.
- 물리적으로 실행되는 grasp를 만드는 retargeting
- 시뮬에서 성공이 확인된 데이터셋
2작업 내용
Object-aware grasp retargeting (8864596 → 0cb02f5)
- 검출: GT 물체 pose와 mesh로 손–물체 접촉 구간(grasp)을 찾음.
- 합성: 로봇 손 형상으로 물체 좌표계에 고정한 parallel grasp를 만들고, IK 연속성으로 후보를 고름. squeeze 폭은 twin의 grip law에서 구하고, approach/release는 transition blend로 이음.
- 도달 검사 (3·4차): IK가 도달한 손을 매 frame 물체와 검사함. 잡고 있는 frame에서는 pad를 제외하고 finger allowance를 둠. planner가 정한 frame이 관통하면 replan하고, 끝까지 남으면 L1 reject(
grasp.max_collision_ratio = 0)함.
- ALOHA flip: IK가 따라가는 180° 뒤집힌 gripper까지 두 variant를 모두 검사함.
- UR5e joint wrap: ±2π joint는 frame 0을 범위 중앙에서 시작함. 팔이 한 바퀴 도는 문제가 없어짐.
- GT flip relabel: GT 물체 pose의 한 frame짜리 회전 flip을 hull 대칭으로 relabel하고, 가장 가까운 정확한 대칭 쪽으로 보정함.
- export: state는 실제 도달한 opening, action은 command임.
aux.grasp와 aux.object_penetration을 내보내고, stale grasp work dir는 거부함.
독립 검증 (2회, 마지막은 wf_f513babd-51d)
- 다른 노드에서 0cb02f5를 다시 돌린 출력이 평가 출력과 npz 72/72 byte-identical.
grasp.enabled: false의 출력은 이전 코드와 같음. e2e export에서 v2.1과 v3.0 모두 데이터 계약이 맞음.
- data lens major D1: L4가 꺼진 상태라 >10 mm 관통 episode가 accepted 집합에 들어감(ALOHA 432/690, UR5e 155/521, 그중 L4 실패 411, 125). → 기본과
_phys 두 벌로 export해 대응.
Production 재변환
snapshot tmp/runs/0cb02f5 (git worktree)
cli invalidate --stages prepare
run_pipeline.sh <cfg> 8 replan vlm # GPU 8: UR5e 76분, ALOHA 84분
run_physics.sh <cfg> 32 # CPU: 68초, 49초
run_export.sh <cfg> # 기본 (L1–L3)
run_export.sh <cfg> --override export.physics_filter=true \
--override export.repo_id=local/h2o_ego2robot_<robot>_phys
3결과
Physics replay (H2O 디지털 트윈, 933 episode / 로봇)
| grasps off ALOHA | 0cb02f5 ALOHA | grasps off UR5e | 0cb02f5 UR5e |
| moved 성공 /829 | 4 | 174 (21%) | 61 | 317 (38%) |
| null baseline(frozen)보다 나은 성공 | – | 152 | – | 262 |
| static 건드리지 않음 /104 | 81 | 85 | 68 | 76 |
production physics 결과는 평가 run(eval9)과 정확히 같다(174, 317).
라운드별 변화 (전체 184 seq, ALOHA ; UR5e)
| 8864596 | 3차 | 4차 = 0cb02f5 |
| moved 성공 /829 | 176 ; 314 | 183 ; 318 | 174 ; 317 |
| accepted episode 중 planner frame이 물체 안 | 측정 안 함 | 측정 안 함 | 0 ; 0 |
| ALOHA tracked hold frame 관통 >2 mm | – | 596 | 51 |
| UR5e joint-0 한계에 닿은 팔 | 18 | 0 | 0 |
| 사람에게 없는 15° 초과 회전 step | 10 ; 7 | 0 ; 0 | 0 ; 0 |
데이터셋 (/home/nas_main/taewoongkang/Dataset/H2O_ego2robot/<robot>/lerobot/)
| dataset (episodes / frames) | ALOHA | UR5e |
| 이전 기본 (grasps off, suffix로 보존) | 688 / 63,116 | 509 / 46,431 |
기본 h2o_ego2robot_<robot>_{v21,v30} | 680 / 63,992 | 518 / 46,123 |
| 그중 moved / physics 성공 | 624 / 145 | 468 / 246 |
| 그중 static / 검증됨 | 56 / 34 | 50 / 43 |
_phys h2o_ego2robot_<robot>_phys_{v21,v30} | 179 / 16,735 | 289 / 26,939 |
933 후보의 reject 사유 (첫 사유)
| 사유 | ALOHA | UR5e |
L1 ik_fail_ratio > 0.1 | 196 | 357 |
| L1 planner frame 물체 충돌 | 23 | 42 |
| L2 gripper rate / z-score | 15 / 9 | 1 / 12 |
| L3 VLM | 10 | 3 |
L4 moved replay 실패 (_phys만) | 479 | 222 |
L4 static 검증 불가 / disturbed (_phys만) | 17 / 5 | 2 / 5 |
관통 flag는 physics 실패를 예측함
| 기본 데이터셋 episode | ALOHA L4 실패 | UR5e L4 실패 |
object_penetration frame 있음 | 436 / 466 (94%) | 134 / 181 (74%) |
| 없음 | 65 / 214 (30%) | 95 / 337 (28%) |
정합성 검증
tools/verify_dataset.py: 8개 데이터셋(기본·_phys × v2.1·v3.0 × 2 로봇) 모두 통과. 검사 항목은 action[k] = state[t+1+k](arm 오차 0), gripper command ≤ 도달 opening, state − robot.npz ≤ 2e-7, image ≈ composite(평균 오차 ≤ 2.9/255).
_phys의 episode 집합은 기본 집합에서 L4 reject를 뺀 것과 정확히 같다. 두 export의 L1–L3 사유와 stage config hash가 같고, prepared_with_grasps는 184/184.
ALOHA 183 → 174 원인 정정 (0cb02f5 ablation, 검증자 측정)
| 변형 | moved 성공 /829 |
| 0cb02f5 그대로 | 174 |
| wait/detour가 물체를 따라감 (3차 방식) | 181 (+7) |
| flip variant 1개만 | 179 (+5) |
| relabel 보정 없음 | 174 (14 episode 뒤바뀜) |
| table floor 없음 / 3차 round 선택 | 175 / 174 |
이전 해석("열린 손이 물체를 밀어 생긴 가짜 성공이 빠짐")은 틀렸다. 잃은 19개 중 release 뒤 접촉은 3개뿐이다. 실제 원인은 grasp 재선택·상태 변화 약 11개, 검출 변화 4개, IK history 4개다. accepted moved로 한정하면 성공은 150 → 149로 거의 같다. flip variant를 빼면 성공은 +5지만 ALOHA hold 관통 frame이 11 → 1,140으로 늘기 때문에 유지한다.
4Takeaway
같은 H2O 장면을 재현한 트윈에서 dataset action을 재생하면, 물체가 영상처럼 움직이는 episode가 ALOHA 43배(4 → 174), UR5e 5배(61 → 317)로 늘었다. _phys가 "시뮬에서 성공을 확인한" 학습셋이다.
기본 데이터셋은 episode 수를 유지하지만, 사람 손 궤적을 그대로 따른 관통 frame이 많다. 그런 episode는 거의 physics에서 실패하므로(ALOHA 94%), 학습에는 _phys를 쓰거나 aux.object_penetration으로 mask해야 한다.
분석
ALOHA moved 실패 1위는 start_collision 288건(손이 시작부터 물체 안)이고, 2위는 ik_fail 137건이다. start_collision은 stroke 58 mm로 잡을 수 없는 넓은 물체(grasp frame의 63%가 ungraspable)에서 사람 손을 그대로 따른 구간과 연결된다. UR5e는 1위가 ik_fail 256건이다. 두 팔이 20 mm floor에서 만나는 경우가 많다.