# RoboCasa State / Action 명세 > 근거 파일: `env.py`, `gym_wrapper.py` (`PandaOmronKeyConverter`), `robosuite/controllers/parts/arm/osc.py`, `robosuite/controllers/config/robots/default_pandaomron.json` --- ## State (총 16차원) `env.py: convert_state()` 기준으로 concatenate됨. | 인덱스 | 차원 | 키 | absolute / relative | 표현 | |--------|------|----|---------------------|------| | 0~2 | 3 | `state.base_position` | **absolute** | xyz | | 3~6 | 4 | `state.base_rotation` | **absolute** | **Quaternion** (`robot0_base_quat`) | | 7~9 | 3 | `state.end_effector_position_relative` | **relative** (base → EE) | xyz | | 10~13 | 4 | `state.end_effector_rotation_relative` | **relative** (base → EE) | **Quaternion** (`robot0_base_to_eef_quat`) | | 14~15 | 2 | `state.gripper_qpos` | — | joint position | --- ## Action (총 12차원) `env.py: convert_action()` 기준으로 분해됨. | 인덱스 | 차원 | 키 | 설명 | |--------|------|----|------| | 0~3 | 4 | `action.base_motion` | 베이스 이동 (아래 참고) | | 4 | 1 | `action.control_mode` | 제어 모드 스위치 (아래 참고) | | 5~7 | 3 | `action.end_effector_position` | EE delta position, **base frame 기준** | | 8~10 | 3 | `action.end_effector_rotation` | EE delta rotation, **base frame 기준, axis-angle** | | 11 | 1 | `action.gripper_close` | 그리퍼 닫기 (0.5 threshold → binary) | ### base_motion (4차원) 상세 | 인덱스 | 대상 | controller type | 설명 | |--------|------|-----------------|------| | 0~2 | `robot0_base` | `JOINT_VELOCITY` | 모바일 베이스 x속도 / y속도 / yaw속도 | | 3 | `robot0_torso` | `JOINT_POSITION` | 몸통 수직 리프트 joint position (≈ 높이) | ### control_mode (1차원) 상세 | 값 | base_mode | 동작 | |----|-----------|------| | < 0.5 | -1 | **Arm mode** — 베이스 고정, 팔로 조작 (goal: `achieved` 기준) | | ≥ 0.5 | +1 | **Base mode** — 베이스 이동, 팔 목표 유지 (goal: `desired` 기준) | --- ## EE Rotation: axis-angle을 쓰는 이유 OSC controller(`osc.py`)는 rotation input을 `Rotation.from_rotvec()` 으로 해석 → **axis-angle 고정**. RPY(Euler angle) 대신 axis-angle을 쓰는 이유: 1. **Gimbal lock 없음** — RPY는 특정 자세에서 두 축이 겹쳐 DOF를 잃는 singularity 발생. EE는 자유 회전하므로 실제 문제가 됨. 2. **Delta 제어에 자연스러움** — "이 축 방향으로 θ만큼 회전" 의미가 직관적이고 보간이 smooth. RPY delta는 순서 의존성(roll→pitch→yaw) 때문에 합성이 복잡함. 3. **크기 = 회전량** — 벡터 norm이 회전각이라 output clipping이 자연스러움. (`output_max: [0.5, 0.5, 0.5]` rad) > RPY 입력은 코드상 지원하지 않음. 필요하면 wrapper에서 변환 필요: > ```python > from scipy.spatial.transform import Rotation > axis_angle = Rotation.from_euler('xyz', rpy).as_rotvec() > ``` --- ## 시뮬레이션 연결 흐름 ``` policy output (12-dim) ↓ convert_action() [env.py] action dict (base_motion, control_mode, EE_pos, EE_rot, gripper_close) ↓ unmap_action() [gym_wrapper.py] { robot0_right: concat(EE_pos[3], EE_rot[3]) → OSC_POSE controller robot0_right_gripper: threshold(gripper_close, 0.5) → -1 or +1 robot0_base: base_motion[0:3] → JOINT_VELOCITY controller robot0_torso: base_motion[3:4] → JOINT_POSITION controller robot0_base_mode: threshold(control_mode, 0.5) → -1 or +1 } ↓ env.step() [robosuite] MuJoCo simulation ```