Skip to content

AryanRajpal/hack-hack-goose-product

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

KneeTrack — Waddle

Real-time knee flexion tracking for post-surgical rehabilitation. An ESP32-S3 with dual MPU-6050 IMUs streams joint angle data over WiFi to a Python backend, which runs a biomechanical step detector, scores each walking session, and serves a mobile-first dashboard called Waddle.


How it works

ESP32-S3 (50 Hz) ──WiFi──► laptop:8000/ws
                                 │
                          _handle_packet()
                                 │
                    ┌────────────┴────────────┐
                    │                         │
             StepDetector              /feed WebSocket
          (STANCE/SWING FSM)      ──► browser dashboard
                    │
          Auto-session logic:
          idle → walking  → start session
          walking → stopped → save session + score

The ESP32 is the client — it dials out to your laptop IP on port 8000. Your laptop is the server. The browser dashboard connects to /feed for a live stream of flexion angle, step count, and walking status.


Project structure

firmware/
  src/
    config.h          — WiFi SSID/password, server IP, port
    main.cpp          — 50 Hz sample loop → angle → WebSocket send
    imu.h / imu.cpp   — MPU-6050 initialisation and raw read
    angle.h / angle.cpp — complementary filter, flexion, calibration
    wifi_ws.h / wifi_ws.cpp — WiFi connect, WebSocket client

backend/
  main.py             — FastAPI server: WebSocket receiver, REST API, static file host
  step_detector.py    — STANCE/SWING state machine step detector
  scorer.py           — 0–100 session scoring (ROM + consistency)
  seed_harnold.py     — Dev seed: 2 months of fake recovery data for "harnold"
  requirements.txt
  database.db         — SQLite (auto-created on first run)

app-frontend/
  index.html          — Single-page app (login, walk test, recovery pages)
  style.css           — DM Sans + Playfair Display, green theme
  app.js              — WebSocket client, chart rendering, day aggregation
  images/
    duck.png
    feet.png

1. Firmware setup (ESP32-S3)

Prerequisites

PlatformIO (VS Code extension recommended). It downloads the toolchain and all libraries automatically.

Configure WiFi and server

Edit firmware/src/config.h:

#define WIFI_SSID "your-network-name"
#define WIFI_PASS "your-password"
#define WS_HOST   "192.168.x.x"   // your laptop's local IP
#define WS_PORT   8000

Find your laptop IP on Windows:

ipconfig   # look for "IPv4 Address" under the active adapter

Build

pio run -e freenove_esp32_s3_wroom

Flash

pio run -e freenove_esp32_s3_wroom -t upload

If the board is stuck on waiting for download: hold BOOT, tap RST, release BOOT, then re-run the upload command. Press RST once flashing finishes.

Serial monitor

pio device monitor   # 115200 baud

Output with DEBUG_MODE defined:

IMU1: 12.4  IMU2: -3.1  FLEX: 15.5  dt: 20ms  WS: connected

Change the COM port in platformio.ini if needed:

upload_port = COM7

2. Backend setup

Prerequisites

Python 3.11+

Virtual environment

python -m venv .venv

Activate:

Shell Command
PowerShell .venv\Scripts\Activate.ps1
cmd .venv\Scripts\activate
Mac / Linux / Git Bash source .venv/bin/activate

Install dependencies

pip install -r backend/requirements.txt

Dependencies: fastapi, uvicorn, sqlmodel, python-multipart, tzdata

Run the server

uvicorn backend.main:app --host 0.0.0.0 --port 8000 --reload

Port conflict? If you get WinError 10013, try --port 8080 and update WS_PORT in config.h to match.

Schema error on startup? Delete backend/database.db — it is recreated automatically. This happens when upgrading from an older schema.


3. Frontend (Waddle dashboard)

Open in your browser after starting the server:

http://localhost:8000/app

The frontend is a static SPA served by FastAPI from app-frontend/. No build step required.

Pages

Login — Enter your name (or a new name to create a new patient profile).

Walk Test — Main screen. Shows:

  • Live knee flexion angle and step count (streamed via /feed WebSocket)
  • Device connection status with 3-second silence watchdog
  • Your Day card: aggregated daily score, total steps, ROM breakdown across all sessions today
  • 15s Walk Test button — starts a timed demo session; results slide in inline
  • Calibrate button — sends a zero-reference command to the ESP32 (hold leg straight for 2 s)
  • Auto-sessions run silently in the background whenever walking is detected

Recovery — Bar chart history with four tabs:

  • Daily — 24 hourly bars for today
  • Weekly — 7 daily bars for this week
  • Monthly — day-by-day bars for this month
  • Overall — one bar per calendar month, all time

Bar height = total steps in that period. Bar colour = average session score (red → orange → yellow → green → A-grade green).

User switching

A switch user link appears below the banner on both Walk Test and Recovery pages. It pre-fills the current name so you can edit or replace it.


4. Auto-session logic

Sessions start and stop automatically — no button needed.

Walk status What happens
idlewalking A new continuous session begins silently
walkingstopped Session is scored and saved; "Your Day" card updates

Walking is detected when ≥ 2 steps occur within a 4-second window. A session stops after 3 seconds with no new steps.

The 15s Walk Test button (demo mode) runs a fixed-duration session instead and displays results inline when it finishes.


5. Scoring

backend/scorer.py produces a 0–100 score from per-step ROM values:

Component Weight Measure
Max ROM score 15% How close the best single step was to 55° target
Avg ROM score 60% How close the mean step ROM was to 43° target
Consistency score 25% Step-to-step repeatability (penalises high std dev)

Grades: A ≥ 85 · B ≥ 70 · C ≥ 62 · D ≥ 48 · F < 48

Scores above 78 receive a small boost so genuine A-grade walking scores near 95–100 rather than being capped at the weighted sum. Low-ROM gaits (post-surgical, limping) score in D–F as expected — the scale is designed to show meaningful progress even when absolute ROM is still limited.


6. Step detection

backend/step_detector.py — online STANCE/SWING state machine running on each 50 Hz packet:

  • Pre-filter: 5-sample moving average (~100 ms) to smooth noise before transitions
  • STANCE → SWING: knee flexion rises above 12°
  • SWING → STANCE (valid step): flex drops to 70% of the swing peak, step duration 300–2500 ms
  • Step timing gate: rejects stumbles (< 300 ms) and pauses (> 2500 ms)
  • Walking detection: ≥ 2 completed steps within a 4 s sliding window
  • Stop detection: no step for > 3 s after walking

The 70% adaptive exit threshold means reduced-ROM patients (peak flex 20–30° post-op) are detected correctly without requiring a fixed low-angle return.


7. API reference

WebSockets

Endpoint Description
WS /ws ESP32 connects here, pushes {"t":ms,"a1":°,"a2":°,"flex":°} at 50 Hz
WS /feed Browser subscribes for forwarded IMU frames + status events

/feed message types:

{"t": 4521, "flex": 15.5}                     // IMU frame (50 Hz)
{"steps": 12, "walk_status": "walking"}        // step/walk status broadcast
{"esp32_connected": true}                      // device connect/disconnect

Patient management

Method Endpoint Description
POST /set_patient?patient_id=x Set active patient for auto-sessions
GET /current_patient Return the currently active patient ID

Sessions

Method Endpoint Description
POST /start_demo?patient_id=x&duration_s=15 Start a timed demo session
GET /demo_status Poll demo progress / result
POST /stop_demo Early-stop demo and save
POST /start_continuous?patient_id=x Start open-ended session
GET /continuous_status Live stats for the running session
POST /stop_continuous Stop and save continuous session
POST /calibrate Forward calibration command to ESP32

History

All history endpoints are bucketed and timezone-aware (America/Chicago). Each bucket includes total_steps, avg_score, session_count, and a sessions array.

Method Endpoint Description
GET /history/daily?patient_id=x&date=YYYY-MM-DD 24 hourly buckets for one day
GET /history/weekly?patient_id=x&week_start=YYYY-MM-DD 7 daily buckets (Monday start)
GET /history/monthly?patient_id=x&month=YYYY-MM Day-by-day buckets for one month
GET /history/alltime?patient_id=x All sessions bucketed by calendar month

Other

Method Endpoint Description
GET /health {"status":"ok","esp32_connected":bool}
GET /metrics?patient_id=x Aggregate lifetime stats
GET /steps?session_id=n Per-step records for a session
GET /score?session_id=n Score record for a session
GET /app Serves the Waddle SPA (index.html)

8. Database schema

SQLite at backend/database.db, managed by SQLModel. Three tables:

SessionData — one row per session
id · patient_id · start_time (UTC naive) · duration_s · mode
mode is "continuous" (auto-session), "demo" (15 s test), or "manual" (legacy API).

StepEntry — one row per detected step
id · session_id · timestamp_ms · peak_flex · min_flex · rom · duration_ms

ScoreRecord — one row per session
id · session_id · overall · max_rom_score · avg_rom_score · consistency_score · grade · interpretation · max_rom · avg_rom · std_rom · step_count


9. Development & testing

Seed data

To populate a demo patient with 61 days of realistic recovery data (grades F → D → C → B → A):

python backend/seed_harnold.py

Then log in as harnold on the frontend. The Recovery → Overall tab shows the full improvement arc.

Re-running the script prompts before overwriting existing data.

Simulated ESP32

backend/esp32.py can feed synthetic IMU data to the server without physical hardware — useful for testing the step detector and scoring pipeline.

No ESP32? No problem

The dashboard works without a device connected — the device status dot shows amber ("disconnected") but all history and scoring features are fully usable.

About

This our submission for Hack Hack Goose.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors