# 플랜: 조이스틱 이질지시 + 강한좌우(극단 cx) 통합 데이터 수집 (규모 확대판)

> 작성일: 2026-07-07
> 배경: CH61 §7,10 — (a) 언어조건화 counterfactual 0%, (b) 강한좌/우(cx<0.25 또는 >0.75)
> 학습 프레임 비율 3.2%뿐. 이 둘을 하나의 수집 캠페인으로 동시에 해결.
> 수집 도구: `ROS_action/src/mobile_vla_package/mobile_vla_package/mobile_vla_data_collector.py`
> (mode="2", WASD 조이스틱, `fixed_episode_length=18`)

## 0. 결론 먼저: 현재 데이터셋만으로는 (학습 기법을 뭘 써도) 해결 불가

- Synthetic 이질지시 실험(같은 이미지에 라벨만 다르게)으로 이미 확인: counterfactual
  changed_rate 0.3%→0.8%, 사실상 무효. 근본 원인이 **데이터에 신호 자체가 없는 것**이라
  알고리즘/재학습 레벨에서는 우회 불가 — **재수집이 유일한 해법**.
- 단, "목표(gray basket)에 도달하는 것만이 태스크"라면 ②(텍스트-장면 confound) 자체는
  실패 원인이 아님 — 그래서 아래를 **두 트랙으로 분리**해서, 순수 도달 성능에 필요한
  트랙 A를 우선시하고 트랙 B(언어조건화용)는 "수집 세트 중 하나"로 격을 낮춰 포함.

## 1. 설계 (트랙 분리판)

> ⚠️ **2026-07-09 수정**: 타겟은 gray basket 하나뿐이라 "제3의 다른 목표 지시" 같은
> 목적지 분기는 애초에 불가능. 또한 목표 도달 성능만 놓고 보면 언어조건화(트랙B) 자체는
> 필수가 아님 — 그래서 트랙 A(도달 성능 직결)와 트랙 B(언어조건화 로드맵용, 선택)로 분리.

### 트랙 A — 극단cx 커버리지 + 경로 다양성 (핵심, 도달 성능 직결)

목표: obj_* 실패의 직접 원인인 ①극단cx 부족, ③cx-경로곡선 confound(FWD+L 반복,
`right_left` 편향) 해소. **지시문 불필요** — 오퍼레이터가 같은 극단 cx 위치에서
자유롭게 다른 경로(좌곡선/직진/우곡선)로 여러 번 다르게 주행하기만 하면 됨.

| 축 | 값 | 개수 |
|---|---|---|
| 목표 위치(극단, 바구니 화면상 cx) | 강한좌(cx≈0.10), 준극단좌(cx≈0.20), 강한우(cx≈0.90), 준극단우(cx≈0.80) | 4곳 |
| 접근 경로(지시 없이 자유 주행) | 좌곡선 / 직진 / 우곡선 — 오퍼레이터 재량으로 다양하게 | 3종 |
| 반복 | 세팅당 | 15회 |
| **트랙 A 총 에피소드** | 4 × 3 × 15 | **180개** |

### 트랙 B — 지시-경로 디커플링 (선택, 언어조건화 로드맵용)

목표: ②텍스트-장면 confound 해소(향후 "말로 접근 방식을 바꿔달라"는 요구가 로드맵에
있을 경우 대비). §1-1 참고. **트랙 A보다 후순위, 수집 세트 중 하나로 축소 포함**.

| 축 | 값 | 개수 |
|---|---|---|
| 목표 위치(극단, cx) | 트랙A와 동일 4곳 | 4곳 |
| 지시(instruction, 접근 경로) | 좌곡선/직진/우곡선 — **매 회차 cx와 무관하게 랜덤 배정**, 오퍼레이터는 지시를 실제로 따라 주행 | 3종 |
| 반복 | 세팅당 | 5회 (트랙A 15회보다 축소 — 검증용 규모) |
| **트랙 B 총 에피소드** | 4 × 3 × 5 | **60개** |

### 트랙 C — 오버슈트→재수렴 (CH62 근거로 2026-07-12 추가, 신규 필수)

목표: CH62에서 확인한 "초반 1회 회전 후 직진 고착, 중간 재보정 능력 없음"을 직접
해소. 205228 반례(첫 탐지 성공했는데 초기 회전이 과도해 cx가 반등 없이 계속 밀려
결국 빗나감) 및 VSC 35.5%(우연 이하)가 근거 — 완화책(재가중치/hybrid rule) 오프라인
실험(§61-16)이 전부 무효로 확인돼, **새 궤적 유형 자체가 없으면 답이 없다**는 게 확정됨.

오퍼레이터가 **의도적으로 과도하게 꺾은 뒤 되돌아오는(overshoot → recover) 궤적**을
반복 수집. 지시 불필요(트랙A와 동일하게 자유 주행), 단 "일부러 지나치게 꺾었다가
다시 중앙으로 되돌리는" 동작을 명시적으로 요청.

| 축 | 값 | 개수 |
|---|---|---|
| 목표 위치(극단, cx) | 트랙A와 동일 4곳 | 4곳 |
| 오버슈트 방향 | 과도한 좌회전→우측 재보정 / 과도한 우회전→좌측 재보정 | 2종 |
| 반복 | 세팅당 | 8회 |
| **트랙 C 총 에피소드** | 4 × 2 × 8 | **64개** |

수집 시 체크: (a) 초반 몇 프레임 동안 반드시 "과함"이 느껴질 정도로 꺾을 것(205228처럼
cx가 반등 없이 극단까지 밀리는 정도), (b) 그 다음 명확한 반대방향 보정 조작을 넣을 것,
(c) 실제로 목표에 도달(성공)하는 궤적과 계속 못 찾고 끝나는(실패) 궤적을 섞어도 무방 —
"재보정 시도가 라벨에 존재하는지"가 핵심이지 매번 성공할 필요는 없음.

**총 규모**: 트랙 A 180개 + 트랙 B 60개 + 트랙 C 64개 = **304개**. 예산이 빠듯하면
**트랙 A + 트랙 C를 우선**(도달 성능 직결, 244개)하고 트랙 B(언어조건화, 60개)는
여유 될 때 추가하는 순서 권장 — 트랙 C가 트랙 B보다 CH62 근거상 더 시급.

기존 9종 path_type(목표 좌/중/우 × 경로 좌/직/우, cx 0.24~0.74 범위)과 겹치지 않도록
**목표를 화면 가장자리(cx<0.25 또는 >0.75)에 두는 것**이 핵심 — 이게 지금 3.2%밖에
없는 구간.

### 트랙 F — 중앙(center) 위치 커버리지 (2026-07-16 추가, V6 단독 학습 위해 신규 필수)

**배경**: 트랙A(180ep)는 의도적으로 weak_right/strong_right/weak_left/strong_left
4개 극단 위치만 수집했고 **center 위치가 전혀 없음**. exp73(트랙A 단독 학습 실험) 진행 중
확인된 문제: `v6` 단독 arm은 학습·검증 모두 center 상황을 한 번도 못 보고, 이를 보완하려면
레거시 V5의 center 51ep(`target_center_*`)을 섞어야 하는데 V5는 시간축이 완전히 다른
키프레임식(~17프레임/ep, STOP 라벨 없음) 데이터라 시간축 이질성 문제(§0 참고)가 재발함.

**결론**: V6를 메인 데이터 포맷으로 갈 거면 V5 레거시를 섞어 땜질하는 대신, **center 위치도
트랙A와 동일한 프로토콜(6.2Hz 연속 조이스틱 수집)로 신규 수집**해서 V6 자체를 완결시키는
것이 맞음.

| 축 | 값 | 개수 |
|---|---|---|
| 목표 위치 | center (신규 — 트랙A 4위치에 추가) | 1곳 |
| 접근 경로 | left_curve / straight / right_curve (트랙A와 동일) | 3종 |
| 반복 | 세팅당 | 15회 (트랙A 동일 규모) |
| **트랙 F 총 에피소드** | 1 × 3 × 15 | **45개** |

완료 시 V6가 **5위치(weak_right/strong_right/weak_left/strong_left/center) × 3경로 =
225ep**로 완결되어, `v6` 단독 arm만으로 중앙+양끝 전 구간을 커버하고 V5 혼합이 불필요해짐.

**수집 방식**: 트랙A와 완전히 동일한 대시보드 시나리오 흐름(cx_position=center 선택 후
동일 3경로 순환) — 신규 UI 불필요, 기존 위치 선택지에 `center` 옵션만 추가.

## 1-1. (트랙 B 상세) 지시-경로 디커플링 (왜 "같은 장면, 다른 지시 → 다른 결과"가 가능한가)

**문제의 재확인**: 기존 9종 `path_type`은 지시(경로)와 화면상 바구니 위치(cx)가
스크립트 설계 단계에서부터 1:1로 묶여 있었다.

| | 기존(동기적) | 신규(디커플링) |
|---|---|---|
| 바구니 cx | 시나리오마다 고정 | 4개 극단 포지션 중 하나로 고정 |
| 지시(경로) | 시나리오 이름이 곧 지시 (`center_left_path`→항상 좌곡선) | **같은 cx에서 좌/직/우 지시를 무작위 배정** |
| 실제 주행 | 지시=경로가 항상 일치 | 지시대로 오퍼레이터가 실제 조이스틱 주행 (지시 무시 없음, 단 cx는 지시가 결정 못 함) |
| 결과 | 장면(cx)만 봐도 지시를 100% 추측 가능 → confound | 같은 시작 장면인데 지시에 따라 실제 궤적(라벨)이 달라짐 → 진짜 counterfactual 쌍 |

**목적지는 바뀌지 않는다.** gray basket 하나로 계속 간다 — 바뀌는 건 "그 바구니까지
어떤 곡선으로 접근하느냐"뿐이다. 이 접근 곡선 지시를 화면상 바구니 위치와 무관하게
매 회차 랜덤 배정하고, 오퍼레이터가 실제로 그 지시를 따라 조이스틱을 조작해 물리적으로
다른 궤적을 만들어내면, "바구니 cx=0.9(강한우)로 보이는 같은 시작 프레임"에서 좌곡선
지시를 받은 에피소드와 우곡선 지시를 받은 에피소드가 각각 존재하게 되고, 두 경우 실제
주행 궤적(=학습 라벨 시퀀스)이 다르다. 이게 지금까지 데이터에 전혀 없던,
counterfactual changed_rate를 실제로 움직일 수 있는 유일한 신호 종류다.

**주의**: 지시를 아예 무시하고 임의로 운전하면 안 됨 — 그러면 지시와 결과의 상관이
아예 사라져서 이번엔 "지시가 무의미한 노이즈"라는 반대쪽 잘못된 신호를 학습시키게
된다. 반드시 "지시받은 경로를 실제로 따라가려 애쓰며" 주행해야 한다.

## 2. 시간 배분 (트랙A 180개 + 트랙B 60개 + 트랙C 64개 = 304개 기준)

| 단계 | 시간 | 비고 |
|---|---|---|
| 로봇/카메라/극단배치 지그 준비 | 30분 | 1회성, 바구니 위치 마커 4곳 표시 |
| **트랙A 촬영 (180ep × 2~3분)** | **6~9시간** | 지시 없이 자유 경로 다양화, 편당 실측 기준 |
| **트랙B 촬영 (60ep × 2~3분)** | **2~3시간** | 지시-경로 디커플링, 트랙A와 별도 세션 가능 |
| **트랙C 촬영 (64ep × 2~3분)** | **2.1~3.2시간** | 오버슈트→재수렴, CH62 근거로 신규 필수(§1-2) |
| 실패/재촬영 버퍼 (20%) | 2.1~3.0시간 | 조이스틱 미숙, 센서 이슈 |
| vis feature 인코딩 (신규 304ep) | 25~40분 | 오늘 150ep 인코딩 시간 비례 추정 |
| 재학습 (window3 / exp71 레시피) | 15~25분 | 오늘 여러 번 실측한 것과 동일 규모 |
| counterfactual/OOD 커버리지 재검증 | 15분 | 기존 스크립트 재사용 |
| **합계** | **약 11~15.5시간** | 트랙A만 우선 진행 시 약 8.5~12시간으로 축소 가능 |

**현실적 제안**: **1일차는 트랙A 180개만 우선 완료**(도달 성능 직결, 약 8~11시간)하고,
재학습·실로봇 검증으로 obj_* 개선 여부를 먼저 확인. 이후 여유 될 때 **2일차로 트랙B
60개 추가**(언어조건화 로드맵 대비용, 약 3~4시간)하는 순서 권장.

## 3. 준비 체크리스트 (제가 지금 준비 가능한 것)

- [x] `mobile_vla_data_collector.py`의 `cup_scenarios`에 극단 배치 4개 시나리오 키 추가
      (`target_extreme_left`, `target_near_left`, `target_extreme_right`, `target_near_right`,
      각 target=45 = 3경로×15회, 키 10~13) — 2026-07-10 완료
- [ ] (트랙B 전용) 에피소드별 **instruction 문자열을 h5 attrs에 기록**하는 필드 추가
      (현재는 시나리오 이름만 기록되고 자유형 instruction 텍스트 필드가 없음 — 확인 필요.
      트랙A는 지시 기록 불필요)
- [ ] 촬영 후 자동으로 `docs/v5/bbox_frame_level/` 포맷에 맞게 병합하는 스크립트 준비
- [ ] 촬영 진행률 실시간 카운터(포지션×지시별 목표 15회 대비 현재 횟수) 표시

## 4. 결정이 필요한 것

- [ ] 180개 전체 vs 1일차 120개로 먼저 시작할지
- [ ] 극단 포지션 좌표(cx≈0.10/0.20/0.80/0.90)가 실제 물리 공간에서 몇 미터/각도인지
      (로봇-바구니 배치를 실측해서 정해야 함 — 지금은 cx 목표값만 있음)
- [ ] 지시 3종의 정확한 문장(현재는 자리표시자, 실제 조이스틱 조작자가 읽을 문장 확정 필요)
- [ ] **학습 window 리샘플링 (500ms/2Hz 기준)**: 수집 자체는 이벤트기반 4~7Hz 그대로 두되,
      window(3/6프레임) 구성 시 실제 추론 cadence(레이턴시 450~600ms → ~2Hz)에 맞춰
      **500ms 간격으로 리샘플링한 시퀀스로 학습셋을 재구성**하는 전처리 단계 추가 검토.
      현재는 프레임개수 기준 window라 "체감 시간폭"이 조작 밀도에 따라 최대 3배 이상
      들쭉날쭉(촘촘한 조작 구간 ~0.85초 vs 성긴 구간 ~3초) — 추론 시 실제로 보는
      시간폭(window=6 @ ~2Hz ≈ 3초)과 불일치. 리샘플링으로 균일 Δt 확보 + 추론 cadence
      정합.
- [ ] **action chunking 도입 검토**: π0/SmolVLA 등 최신 VLA는 "느린 VLM 추론 + 빠른
      로봇 실행"을 구조적으로 분리(청크 단위 예측, open-loop 실행)해서 추론-실행 주기
      불일치 문제 자체를 없앰. 우리는 현재 청크 없이 매 프레임 단일 클래스 예측
      (closed-loop) 구조 — 위 500ms 리샘플링은 이 구조를 유지한 채 적용 가능한 값싼
      절충안이고, 근본적으로는 action chunking 구조 도입 여부를 별도 실험 트랙으로
      검토할 가치 있음 (우선순위: 리샘플링 먼저 검증 → 효과 부족 시 chunking 검토).

## 5. 평가지표 (CH62, 2026-07-12 추가)

2026-07-11 세션 raw H5 분석(CH62)에서 "그라운딩 실패"보다 "액션-그라운딩 라벨 confound"가
더 근본 원인으로 확인됨 (VSC 35.5% = 우연 이하). 재수집/재학습 전후 비교용 지표:

| # | 지표 | 정의 | 현재값(2026-07-12 기준) | 목표 |
|---|---|---|---|---|
| 1 | VSC(방향 일치율) | 방향성 액션에서 sign(cx-0.5)=sign(vyaw) 비율 | 35.5% 전체 / 극단구간 47~53% | 70%+ |
| 2 | 오버슈트 회복률 | cx 반전 후 5프레임 내 회전 액션 비율 | 14.3%(1/7) | 유의미한 증가 |
| 3 | Grounding-Action 반응 지연 | 유의미한 cx 변화 후 액션 반응까지 프레임 수 | 사실상 무한 | 유한값으로 감소 |
| 4 | first_detect_frame 무관 성공률 | obj_* 성공률을 첫탐지=0군 vs ≥3군으로 분리 | 75% vs 0% | 격차 축소 |
| 5 | closed-loop obj_* 종합 성공률 | 기존 회귀 확인용 앵커 | 34.7%(25/72) | 유지/개선 |

지표 1·2는 로봇 재수집 없이 기존 학습 annotation만으로 오프라인 측정 가능 —
"지시-경로 디커플링"이 confound를 실제로 끊었는지 재수집 전에 먼저 검증할 것.

**결정 완료(2026-07-12)**: 오프라인 완화책(재가중치/hybrid rule, §61-16)이 전부 무효로
재확인돼(B: FWD+L recall 78.1%→63.1%↓, cx<0.25 정확도 48%→42%↓ / C: 극단구간 정확도 0%로
붕괴), 기존 데이터 재활용으로는 답이 없음이 확정. **트랙 C(오버슈트→재수렴, 64ep)를
신규 필수 트랙으로 §1에 추가** — 상세는 §1 "트랙 C" 항목 참고. 초반 1회 회전 에피소드를
데이터셋에서 빼는 방안은 **비권장**(패턴 자체가 문제가 아니라 다양성 부족이 문제라
삭제보다 추가가 맞음). 상세: `docs/v5/closed_loop_eval/CH62_FORWARD_LOCK_AND_LABEL_CONFOUND.md`

## 6. 기존 free 에피소드 49개 처리 방침 (2026-07-12 추가)

재수집 전 "혹시 이미 쓸 수 있는 데이터가 있나" 확인한 결과:

| 데이터셋 | 위치 | 개수 | 상태 | 이번 트랙과의 관계 |
|---|---|---|---|---|
| basket free | `ROS_action/mobile_vla_dataset_v5/` (2026-05-21/22) | 21 | annotation·exp55 학습 완료(oversample3x val_acc 81.2%), 단 exp71엔 미포함 | 오버슈트 궤적은 없지만 극단위치/거리/조명 다양성은 있음 → **재학습 시 병합 권장** |
| chair free | `ROS_action/mobile_vla_dataset_v5_2/` | 28 | annotation 완료(`bbox_chair/`), 미학습 | 목표물이 basket이 아니라 chair — R3 멀티오브젝트 일반화 로드맵 전용, **이번 트랙과 분리 유지** |

**방침**: 트랙A(180)+트랙C(64) 물리 수집 완료 후 재학습 시, 기존 150ep + 트랙A/C 244ep +
basket free 21개 = **총 415ep**으로 학습(exp55 방식대로 free는 오버샘플 고려).
chair 28개는 포함하지 않음(별도 로드맵).

## 7. soda에 문의 — az는 이미 연속 보존, lx/ly도 가능한지 (2026-07-17)

exp73 hybrid 헤드 개발 중 raw 액션 실측 스캔 결과 확인된 사실 (`mona_dashboard.py`
`_axis_to_key()`/`_loop()` 코드 직접 확인, 우리 쪽에서 코드 수정은 안 함):

- **az(angular_z)**: `rd(self._axes["right_x"])` — 우측 스틱 아날로그 raw 값을 그대로
  기록. 실측 225ep 스캔 시 고유값 33개+ (진짜 연속). 하드웨어가 이미 연속 신호를
  주고 있고, 소프트웨어도 그걸 그대로 살리고 있음.
- **lx, ly(linear_x/y)**: 좌측 스틱도 물리적으로는 동일하게 연속 axis(`left_x`,
  `left_y`)를 읽지만, `_axis_to_key()`가 이걸 8방향 키(W/S/A/D/Q/E)로 변환하고
  각 키에 고정 속도 1.15를 매핑 — 그래서 실측 데이터에는 항상 {-1.15, 0, +1.15}
  3값만 나옴. **하드웨어 제약이 아니라 소프트웨어 설계(고정속도 키 매핑) 때문.**

**문의**: lx/ly도 az처럼 원본 아날로그 값을 그대로(또는 deadzone 클리핑만 적용)
기록하도록 바꾸는 게 가능한지, 그리고 바꿀 경우:
1. 기존 8-class 이산 라벨(nav_h5_dataset_impl.py 임계값 기반)과의 하위호환은
   `abs(x)>0.3` 등 임계값으로 그대로 재이산화 가능해서 문제 없음(연속값 저장은
   ADD-ONLY, 기존 파이프라인 안 깨짐)
2. 다만 이미 수집된 405ep(트랙A 180+트랙F 45+구버전 150+free 21+기타)를 다시 찍을
   필요는 없음 — **차기 수집(트랙C 64ep부터)에 한해 적용 여부만 검토 요청**
3. exp73 63-9(hybrid 헤드: 이산 lx/ly + 연속 az 분리)가 offline/closed-loop 양쪽
   1위(84.8% success) — lx/ly가 연속화되면 이 구조를 그대로 확장해 추가 개선
   여지가 있는지 확인해볼 가치 있음

## DoD

- [ ] 촬영 시나리오/instruction 세트 확정
- [ ] `mobile_vla_data_collector.py` 시나리오 추가 + instruction 필드 기록 확인
- [x] 트랙A 극단cx 4개 시나리오 키 추가 — 2026-07-10 완료
- [x] 트랙A 극단cx 4위치×3경로(180ep) 물리 수집 완료 — 2026-07-16 (soda, monavla-driving)
- [x] 트랙C(오버슈트→재수렴) 시나리오 키(overshoot_left_recover/
      overshoot_right_recover cx_path) 추가 완료 — 2026-07-16, CH62 근거
      (soda, monavla-driving). 물리 수집(64ep)은 아직 미착수.
- [x] **트랙F(center 위치, 45ep) 신규 추가 + 물리 수집 완료 — 2026-07-16/17
      (soda, monavla-driving).** V6가 5위치×3경로=225ep로 완결, V5 혼합
      불필요해짐. 상세: `docs/DATASET_V6_STATUS.md` "최신 현황 업데이트" 참조.
- [x] exp73 V6(트랙A+F, 225ep) 액션헤드 종합 ablation 완료 — 2026-07-17.
      mlp 헤드 최고 성능, V5 혼합은 전 조합에서 성능 저하, pi0식 flow-matching
      헤드는 전체 최하위권. 상세: `docs/v5/research_story.html` CH63 참조.
- [ ] 트랙C(오버슈트→재수렴, 64ep) 물리 수집 — exp73 결과 확인 후 우선순위 판단 예정
- [ ] 재학습(V6 단독 225ep+트랙C 64ep=289ep, 또는 기존 150ep+트랙A/C 244ep+
      트랙F 45ep+basket free21=460ep) + §5 평가지표(VSC/오버슈트회복률/
      반응지연/first_detect그룹 격차) 재검증으로 개선 여부 확인
