← Index
2026-09-08 — scene-mem-datagen · Routine(type3) 데이터 생성

exo 카메라 벽 관통 버그 — 진단·렌더 컬링·위치 기반 예방

사용자 리포트 영상 지적("exo cam이 벽면으로 가득 찬 구간이 있다") → 실측·수정·전수 감사·최종 확정까지 하루 전체 스레드

TL;DR

19% / 11%
5400 / 5401 벽 안 (수정 전)
0% / 0%
5400 / 5401 벽 안 (최종)
4/4
유닛 성공 유지
439s → 308s
sim 시간 (5400)

1배경 / 목적

사용자가 리포트 영상을 보고 "카메라가 벽 밖으로 튀어나가서 exo cam에서는 뭘 하는지 안 보이는 부분이 있다"고 지적(260908). exo는 학습·평가의 주 관측 카메라라 이 구간은 데이터로 못 쓴다. 먼저 얼마나 자주 발생하는지, 어떤 실패 모드인지부터 재야 했다.

2작업 내용

2.1 실측 (렌더 없음, tmp/cam_wall_probe.py)

h5의 실제 카메라 자세(obs/sensor_param/<cam>/cam2world_gl)로 광선을 쏴 embedded(시선 첫 히트 <0.25m = 기하 안) / occluded(카메라→작업지점 사이 벽) 두 모드를 가른다.

프로브를 두 번 틀렸다: ① 전방 축을 -Z로 잡았는데 이 파이프라인은 +Z가 전방(routine_visibility 픽셀 로그로 검증된 규약과 동일). ② 목표점을 obs/extra/tcp_pose(베이스 상대 좌표)로 삼아 월드에서 집 반대편을 가리켜 "가림 99%"라는 거짓 결과가 나왔다. robot_base_pose(월드) + 전방 0.5m·z 0.9로 교정. 교훈: 좌표계 규약(전방 축·베이스 상대)은 영상 프레임으로 교차 검증하고 넘어갈 것.

2.2 1차 조치 — 렌더 컬링 (cam_wall_cull.py 신규 + SegmentedPolicy 훅)

매 스텝 data.cam_xpos로 exo 카메라 위치가 벽 geom 내부(로컬 좌표 |p| ≤ half + 0.10m)인지 검사, 내부면 그 벽과 붙은 문·창·액자의 시각 geom만 group=5로 숨긴다(빠져나오면 25스텝 뒤 복구 — 즉시 복구 시 벽이 깜빡임). 충돌 geom(group≥3)은 그대로라 물리·주행·판정 불변. 기본 꺼짐(SCENEMEM_WALL_CULL=1일 때만) — type1/type2 재현을 안 건드린다.

실패 시도: 첫 시도(job 113066)는 모델 카메라 목록이 비어([wall-cull] 벽 36장 · 카메라 [] 감시) 아무것도 못 감시했다. exo는 MuJoCo 모델 안에 없고, RobotMountedCameraConfig가 fr3_link0에 오프셋을 얹어 파이프라인 바깥에서 자세를 만드는 구조라서다 → xpos[mount] + xmat[mount] @ offset으로 카메라 자세를 직접 계산하도록 수정.

2.3 전수 감사 (tools/cam_wall_audit.py)

사용자가 "쌍둥이 편(__5401) 마지막 부분도 벽만 보인다"고 재지적 → 리포트에 쓰인 편 전부를 stride 25로 전수 감사. 한 편(5400)만 보고 "0~19%"라 정리한 게 틀렸다 — 같은 집·같은 무대라도 동선이 달라 다른 벽에 걸린다(5400은 66% 지점, 5401은 100% 지점).

2.4 근본 조치 — 위치 기반 예방 (사용자 승인)

렌더 컬링은 "카메라가 벽 안"만 덮는다. 벽 밖에서 바짝 붙어 화면이 벽면으로 가득한 경우, 가구·가전 기하 안, 컬링의 부작용(벽 자리로 실외가 비쳐 보임)은 못 덮는다. 실측(tmp/cam_pose_cost.py, tmp/cam_where.py): 문제 프레임은 서 있는 자리 몇 곳에 몰림(5455 113표본 중 85개가 통 도킹 자세 1곳). 로봇이 벽에서 0.37~0.43m에 서면 뒤 0.47m 카메라 반경이 반드시 벽을 넘지만, 36방향 중 9~17방향만 해당 — 못 박힌 상면 도킹은 이미 0개 손해(train_5455 3개 중 0개, train_1652 67개 중 0개가 카메라 벽 안).

cam_wall_cull.py — 벽 기하 벡터화(any_inside), pose_clear(xy,yaw): 베이스 자세 → exo 카메라 두 점이 벽 밖인가 room2room.base_candidates — 카메라가 벽 안이 되는 자세를 뒤로 미는 안정 정렬(거르지 않음 — 유일한 자세면 그걸 써야 유닛이 산다) resume_stage._prefer_cam_clear_spots — 통 자리 후보를 깨끗한 도킹 방향이 많은 자리 먼저로 재정렬(12방향×0.75m) scene_mem_policy — 런타임에도 같은 판정기 전역 설치

base_candidates 한 곳에 넣어 파지·놓기·통 도킹·응시가 모두 혜택을 받는다(호출처 11곳). 정렬은 거리 1순위·카메라 2순위 유지(카메라를 1순위로 두면 먼 standoff가 뽑힘).

3결과 (수치)

편벽 안 비율 (수정 전)조치벽 안 비율 (최종)유닛비고
train_5455__540019% (84/440)컬링 → 위치 예방(job 113066→113078→113400→113502)0% (0/309)4/4 ✅sim 439s → 308s, 통 자리 (13.76,5.55)→(10.21,9.90)
train_5455__5401 (쌍둥이)11% (37/327), 편의 100% 지점재실행(job 113313→113426)0% (1/502, exo2 표본 1건)4/4 ✅컬링 1,087→164스텝, 짝과 통 자리 일치
train_1652__2001 (쇼케이스 A′)1% (5/802), 편의 73% 지점 차단재실행(job 113319)미기록(감사 0%, 4/819)4/6 (원본과 동일 사유로 2 실패)컬링 1,770스텝, 정본 교체 + 쇼케이스 미디어 재생성(13:21→13:38)
train_1652__3002·_tv각 1%보류(D② 노출 분석용 클립)––재생성 시 컬링 켬
나머지 5편0%조치 없음0%––

공격적 vs 보수적 통 자리 선호 (각 2편)

방식통 자리카메라 벽 안 (5400/5401)컬링 발동유닛
공격적(깨끗한 방향 많은 순)(13.76,5.55) → (10.21,9.90)0% / 0%102 / 164스텝4/4 · 4/4
보수적(min_clear 미만만 demote)원래 자리 유지19% / 11%2,348 / 1,087스텝3/4(폐기) · 4/4
진단 함정: 처음엔 공격적 판의 쌍둥이 T1 u0가 3회 시도(822s)여서 "통을 옮겨 주행 경로가 바뀐 회귀"로 오진했다. 틀렸다 — 보수적 판에서는 다른 유닛(T1 u1)이 아예 실패(3회, 1070s). 천 운반 실패는 두 설정 모두에서 나는 이 task의 편차였다. 한 번의 재실행 차이를 원인으로 단정하지 말 것 — 같은 설정을 두 편 이상 돌려야 비교가 된다.

4Takeaway

의미

렌더 컬링은 안전망(남은 102~164스텝, 약 4초의 주행 통과분만 덮음)이고, 위치 기반 선호가 근본이다 — 로봇이 애초에 그 자리에 안 서면 감사 수치 자체가 0%가 된다. 둘을 겹치면 긴 정지 구간은 애초에 안 생기고 남는 것은 몇 프레임짜리 통과뿐이다. 성능 손해가 없다는 점(4/4 유지, 오히려 편이 짧아짐)도 확인해 이 방식을 데이터 생성 파이프라인 기본값으로 채택할 근거가 됐다.

5Next Steps

미해결 한계

이동 중 프레임(5455 13/113·1652 38/70)은 도킹 자세 필터로 못 막는다 — 주행격자를 카메라 봉투만큼 부풀리면 막을 수 있지만 문 통과(폭 1.02~1.14m)가 깨진다. 벽 밖에서 바짝 붙어 보는 경우도 위치 기반·컬링 둘 다 못 잡는다.

다음 작업

  • routine_batch.py finish에 편별 "카메라가 벽 안 N%(컬링 O/X·발동 스텝)" 지표를 자동으로 찍어 물량 단계에서 걸러지도록 함 — 구현 완료.
  • 벽을 숨긴 스텝에서 픽셀 로그가 벽 너머를 잡았는지 D② 증거 추출과 교차 확인(현재는 발동 스텝 수만 남김) — 미실행.
  • 보류 편(train_1652__3002·_tv)은 D② 노출 분석용이라 재생성 시점에 컬링을 켜서 처리.