🐯 룸핏 앱 아키텍처 v4

모듈 · 데이터 파이프라인 · 화면 연결도 — FW 2.0.0-dev.1 / APP feat/spoex-v3 @ 14caeef4

📦 전체 구조
📡 BLE 파이프라인
🏋️ VBT 엔진
🎪 SPOEX 모듈
🎛️ 리모컨
📱 화면 연결
📋 PRD 매핑

모듈 의존성 맵

🔵 레이어 구조
┌──────────────────────────── 화면 (Presentation) ────────────────────────────┐spoex/screens remote/screens home/ device/screens │ │ (묠니르, VBT) (리모컨, DEV) (메인홈) (기기설정) │ ├──────────────────────────── 비즈니스 로직 (Domain) ──────────────────────────┤vbt_common/ vbt_engine/ spoex/domain remote/domain │ │ (ViewModel) (파이프라인) (묠니르Ctrl) (리모컨Ctrl) │ │ │ │ motion_analysis/ device/domain exercise/ workout/ │ │ (v1 분석, 레거시) (DeviceState) (운동 DB) (세션 관리) │ ├──────────────────────────── 데이터/인프라 (Data) ────────────────────────────┤bluetooth/ vbt_common/data spoex/data │ │ (BLE 프로토콜) (DataSource) (BLE 커맨드) │ └─────────────────────────────────────────────────────────────────────────────┘ FW (RoomFitMCU) ←──── Nordic UART BLE ────→ bluetooth/

핵심 모듈 6개

bluetooth BLE 통신 계층
FW와의 유일한 통신 채널. Nordic UART Service 기반.
Commands (앱→FW): weight, mode_change, set_range, report, 0xF5 서브코드
Responses (FW→앱): ReportResponse(v3 17B / Dev 41B), OnOff, WeightMode, FirmwareVersion
핵심 클래스: BleBufferServiceImpl (패킷 파싱) → DeviceStateService (상태 저장)
device 기기 상태 서비스
DeviceStateService — GetX 전역 서비스. BLE 응답을 Rx 변수로 변환.
positionL/R, forceL/R, speedL/R, motionTime, weightMode 등.
모든 화면이 이 서비스를 통해 기기 상태를 읽음. 단일 진실 소스.
vbt_engine VBT 분석 엔진
순수 Dart 로직 (Flutter 의존 없음). 4단 파이프라인:
Pipeline (LPF+속도) → TurningPointDetector (극점) → RepCounter (렙) → FeedbackService (코칭)
34개 유닛테스트. BLE/Sim 무관하게 동일 동작.
vbt_common VBT 공통 계층
VbtDataSource 추상화: BLE/Sim/Touch/Random 4종 구현.
VbtWorkoutViewModel: DataSource → Pipeline → Detector → FeedbackService 풀체인 조립.
화면(VbtWorkoutScreen 등)은 이 ViewModel만 바라봄.
spoex SPOEX 2026 모듈
묠니르 + AI-VBT 전시 전용.
MjolnirController: 자동세팅(밴드59kg+리포트시작+저점등록), 무게ON/OFF, 세션관리
SpoexBleCommands: FW 명령 래퍼 (devReportOn/Off, sendWeight, sendMode 등)
화면: M0(세팅)→M1(캘리)→M2(카운트다운)→M3(운동)→M4(결과)
remote 리모컨 모드
기존 앱의 핵심 운동 화면. 스태프가 태블릿으로 제어.
RemoteWorkoutController: 무게±, 모드변경, 가동범위, 자동무게, 시작/종료
RemoteDevScreen: DEV 리모컨. Dev Report 차트 + VbtEngine 연동.
v4 수정 대상: 6종 모드 탭 UI, ±0.5/±5 조절

레거시 vs 신규

영역레거시신규 (v4)상태
속도 계산motion_analysis/ position 미분vbt_engine/ FW Speed 직접 수신완료
렙 감지repetition_service (Worker 기반)StreamingRepDetector (실시간, 1-rep 버퍼)완료
Report 파싱v3 17B 고정v3/Dev(41B) 자동 판별 (패킷 길이)완료
무게 모드3종 (Const/Neg/Band)6종 (+Iso/Hyd/Vib)P0
BLE 파라미터weight/mode/range만+0xF5 0x05 런타임 파라미터P0

BLE 데이터 파이프라인

FW (MCU)
ISR 10kHz
BLE TX
50ms 주기
FlutterBluePlus
Nordic UART
BleBufferService
패킷 조립
ResponseFactory
cmd 코드 분기
DeviceStateService
Rx 변수 갱신

패킷 판별 로직

// ResponseFactory (response_factory.dart:67) case startReportData (0x41): if (data.length >= 41 && data[2] == 38) → ReportResponse (isDevReport = true, 41B) // Dev Report elseReportResponse (isDevReport = false, 17B) // v3 Normal case debugReportData (0xF5): → DebugReportResponse (28B) // 구버전, DEV 리모컨 전용

Report 필드 비교

필드v3 (17B)Dev (41B)사용처
posL/R차트, 가동범위, 렙 감지
forceL/R✅ (Iq 기반)✅ (Iq 기반)무게 표시
speedL/R✅ (mm/s)VBT 속도, 인디케이터
accelL/R✅ (mm/s²)(미사용, 향후 분석)
IcmdL/R✅ (×1000)DEV 차트
IfbL/R✅ (×1000)DEV 차트
fLoadL/R✅ (×100 kg)Power 계산, DEV 차트
modeL/R모드 확인
regionL/R구간 표시
weightSetL/R✅ (×100 kg)설정무게 확인

BLE 명령 (앱→FW)

명령코드용도주의
SET_WEIGHT-무게 설정60kg=에러, 59kg 사용
WEIGHT_ON/OFF-모터 구동-
MODE_CHANGE-무게 모드 변경 (0~5)상한 5
SET_RANGE_DIGIT-가동범위 수치 설정Weight OFF에서만
ECC_LEVEL-네거티브 부하ClampEccWeight 50%
0xF5 0x05debug모드별 파라미터 런타임 변경paramId별 분기
0xF5 0x20/21debugDev Report ON/OFF진입/이탈 시 전환
START_REPORT0x41리포트 시작Start_Report() 필수

VBT 엔진 파이프라인

BleVbtSource
50ms Timer
VbtPipeline
LPF + 속도
TurningPointV3
극점 감지
StreamingRepDetector
렙 세그먼테이션
FeedbackService
코칭/리포트

VbtPipeline 상세

ingest(timeMs, rawPosition, side, {fwSpeedMmS}) { // 1. Butterworth LPF (3Hz cutoff, 20Hz sample) filteredPosition = lpf.filter(rawPosition); // 2. 속도: FW Speed 우선, 없으면 position 미분 if (fwSpeedMmS != null) velocity = fwSpeedMmS / 1000.0; // mm/s → mm/ms else velocity = (filteredPosition - prev.position) / dt; // 3. Raw + Filtered 히스토리 저장 (오브젝트 풀링) // 4. 다운스트림 Stream 전달 }

데이터소스 4종

소스용도FW Speed사용 화면
BleVbtSource실기기 BLE✅ DeviceStateService.speedL/RVBT 체험, 묠니르
SimVbtSourcesine파 시뮬❌ (미분 fallback)VBT 시뮬레이터
TouchVbtSource터치 드래그터치 시뮬 위젯
RandomVbtSource랜덤 운동 패턴자동 데모

ViewModel 풀체인

VbtWorkoutViewModel.create(source, exerciseName, goal, loadKg) { // 동일 detector 인스턴스 공유 (중요!) detector = StreamingRepDetector(concDir, dt: 0.05); feedbackService = VbtFeedbackService(detector, goal, loadKg); pipeline = VbtPipeline(); } // 데이터 흐름: source.samples.listen(_onSample) { pipeline.ingest(raw.timeMs, raw.posLMm, Side.left, fwSpeedMmS: raw.speedLMmS); // velocity: FW Speed 우선 detector.onSample(positionMm, velocityMmS, fMuscle, fMotor); // → repFeedbacks stream → UI }

SPOEX 모듈 구조

묠니르 (Mjolnir)

M0 Setup
자동세팅
M1 Calibration
고점 등록
M2 Countdown
3초
M3 Workout
1RM 측정
M4 Result
QR+순위
MjolnirController
settings: side(L/R/Both), weight(59kg 고정)
autoSetup: 밴드모드 설정 → 리포트 시작 → 저점 등록 → 캘리브레이션 진입
MjolnirSession: start→end 시간, maxPosition, Supabase 업로드
BLE 순서: MODE_CHANGE(2) → SET_WEIGHT(59) → START_REPORT → SET_RANGE_LOW

AI-VBT 체험

V1 ExercisePick
운동 선택
V2 MachineSetup
무게/모드/범위
V3 GoalSelect
훈련 목표
V4 Workout
실시간 VBT
V5 SetReport
세트 결과
V6 SessionReport
전체 리포트
SpoexBleCommands
FW 명령 래퍼. 모든 BLE 명령을 한곳에서 관리.
sendWeight(side, kg) · sendWeightMode(mode) · sendWeightOnOff(bool)
sendSetRangeLow/High(side) · sendStartReport() · sendStopReport()
sendDevReportOn/Off() · sendModeParam(paramId, value)
v4 추가 필요: 6종 모드 파라미터 전송 (0xF5 0x05 확장)

리모컨 모듈

기존 리모컨 (RemoteWorkoutScreen)

구조: 3분할 레이아웃 (Chart : Config : Control = 3:2:4)
RemoteWorkoutConfigBox: 무게 표시, 줄 선택, 현재 모드
RemoteWorkoutControlBox:
  • 가동범위 설정 / 리셋 (무게ON 시 잠금 🔒)
  • ±0.5kg / ±5kg 무게 조절
  • 자동 무게 토글
  • 무게 모드 선택 (바텀시트)
  • 시작 / 일시정지 / 종료
v4 수정: 6종 모드 탭 UI, 모드별 파라미터, Dev Report 차트 채널

DEV 리모컨 (RemoteDevScreen)

DEV flavor 전용. 고급 디버깅 + 튜닝 도구.
기존 기능:
  • VbtEngine 연동 (렙 감지, 속도 인디케이터)
  • 무게 모드/가동범위/자동무게 제어
  • PI 게인 (Kp, Ki) 슬라이더 (등속성)
  • Vtarget 범위 50~2000 mm/s
  • Debug/Dev Report 자동 ON/OFF (진입/이탈)
  • FW 버전 + 앱 커밋 해시 AppBar 표시
v4 수정: 모드별 탭 전환, 차트 채널 토글, 관측→조작→세부 레이아웃

컨트롤러 계층

RemoteWorkoutController ├── weightPlus/Minus/PlusFive/MinusFive() → DeviceCommandController ├── toggleAutoWeightActive() → BLE AutoWeight ├── startRemoteWorkoutSession() → BLE StartReport + WeightOn ├── showRangeOfMotionDialog() → BLE SetRange └── changeWeightMode() → BLE ModeChange RemoteWorkoutDeviceController └── changeMode(WeightMode) → 모드별 분기 ├── constant → setConstantMode() ├── negative → setNegativeMode() + eccLevel() ├── band → setSqueezeMode() ├── iso/hyd/vib → setConstantMode() (임시!) ← P0 수정 대상

화면 → 모듈 연결도

화면경로사용 모듈데이터 소스
home/ device BLE 연결 상태
리모컨 remote/remote_workout_screen device bluetooth motion_analysis DeviceStateService (positionL/R, forceL/R)
DEV 리모컨 remote/remote_dev_screen device vbt_engine bluetooth DeviceStateService + VbtEngine (렙감지)
묠니르 세팅 spoex/mjolnir/mjolnir_setup_screen spoex device MjolnirController + SpoexBleCommands
묠니르 운동 spoex/mjolnir/mjolnir_workout_screen spoex device camera DeviceStateService (position), MjolnirSession
VBT 머신세팅 spoex/vbt/vbt_machine_setup_screen spoex device SpoexBleCommands (무게/모드/범위)
VBT 운동 spoex/vbt/vbt_workout_screen vbt_common vbt_engine spoex BleVbtSource → VbtWorkoutViewModel
VBT 세트리포트 spoex/vbt/vbt_set_report_screen vbt_common VbtWorkoutViewModel.completedSets
VBT 시뮬레이터 dev/vbt_simulator_screen vbt_engine SimVbtSource / 수동 입력

핵심 데이터 흐름

═══ VBT 운동 (V4 WorkoutScreen) ═══ FW ISR(10kHz) → BLE(50ms) → BleBufferService → ReportResponse(41B) → DeviceStateService.positionL/R, speedL/R → BleVbtSource(50ms Timer) → VbtRawSample{pos, speed} → VbtWorkoutViewModel._onSample() → VbtPipeline.ingest(pos, fwSpeedMmS: speed) // FW Speed 우선! → StreamingRepDetector.onSample(pos, vel, force) → VbtFeedbackService → RepFeedback stream → UI (렙카운트, 속도바, 차트) ═══ 리모컨 (RemoteWorkoutScreen) ═══ DeviceStateService.motionTime → Worker trigger → MotionAnalysisService → position/velocity/force → LineChartComponent (차트) → RemoteWorkoutConfigBox (무게/속도 표시) ═══ DEV 리모컨 (RemoteDevScreen) ═══ DeviceStateService.positionL/R → VbtEngine.ingest() → 렙 감지 DeviceStateService.speedL/R → 속도 인디케이터 (FW 직접) DeviceStateService.forceL/R → LineChart (실시간)

PRD v4 항목 → 코드 매핑

PRD항목수정 파일상태
P0 2.1 VBT FW Speed vbt_pipeline.dart (fwSpeedMmS)
ble_vbt_source.dart (speedL/R 전달)
vbt_workout_viewmodel.dart (FW 우선)
vbt_workout_screen.dart (devReport ON/OFF)
완료
P0 2.2 V2 BLE 6종 모드 vbt_machine_setup_screen.dart (모드 탭)
spoex_ble_commands.dart (sendModeParam 확장)
remote_workout_device_controller.dart (case 3/4/5)
진행중
P0 2.3 M0 UI 깨짐 mjolnir_setup_screen.dart (Spacer→고정 spacing) 완료
P1 2.4 DEV 리모컨 모드탭 remote_dev_screen.dart (전면 재설계) 대기
P1 2.5 렙 시각화 line_chart.dart (vertical line layer)
vbt_workout_screen.dart (토글)
대기
P1 2.6 카메라 토글 workout_camera/ → 독립 위젯 분리 대기
P2 2.7 Dev Report 차트 remote_dev_screen.dart (채널 토글) 대기
P2 2.9 바텀시트 fallthrough remote_workout_device_controller.dart:78-80 P0-2.2에서 통합