# ARMx Setup Guide
**Version 2.0 — EMG Prosthetic Control System**

---

## 📋 Prerequisites

### Software
- **Python 3.10+** — [python.org](https://python.org)
- **Arduino IDE / PlatformIO** — for flashing Teensy firmware
- **Teensyduino** — Teensy 4.1 Arduino add-on

### Python Packages
```bash
cd backend
pip install -r requirements.txt
```
Key packages: `fastapi`, `uvicorn`, `scikit-learn`, `numpy`, `joblib`, `pyserial`

### Hardware
- Teensy 4.1 microcontroller
- MyoWare 2.0 EMG sensors (up to 8 channels)
- MPU6050 IMU module
- MG996R / SG90 servo motors (5 fingers)
- External 5V power supply for servos
- USB cable (Micro-B for Teensy)

---

## 🔌 Hardware Wiring

### EMG Sensors → Teensy (8 Channels)
| EMG Channel | Teensy Pin | Wire Color (suggested) |
|---|---|---|
| CH1 | A0 (pin 14) | Red |
| CH2 | A1 (pin 15) | Blue |
| CH3 | A2 (pin 16) | Green |
| CH4 | A3 (pin 17) | Yellow |
| CH5 | A4 (pin 18) | Orange |
| CH6 | A5 (pin 19) | Purple |
| CH7 | A6 (pin 20) | White |
| CH8 | A7 (pin 21) | Gray |

Each MyoWare sensor has 3 connections:
- **+** → 3.3V
- **-** → GND
- **SIG** → Analog pin

> ⚠️ **Note:** Pins 18 and 19 (A4/A5) are also the default I2C (SDA/SCL) pins. To avoid conflict, the firmware uses **Wire2** (Teensy 4.1's second I2C bus) mapped to **pins 25 and 24**.

### MPU6050 → Teensy (Wire2 — No Pin Conflict)
| MPU6050 Pin | Teensy Pin | Notes |
|---|---|---|
| VCC | 3.3V | |
| GND | GND | |
| SDA | **Pin 25** | Wire2 SDA — no EMG conflict |
| SCL | **Pin 24** | Wire2 SCL — no EMG conflict |
| AD0 | GND | Sets I2C address to 0x68 |
| INT | Not connected | Optional |

### Servo Motors → Teensy
| Servo | Teensy Pin | Finger |
|---|---|---|
| Servo 0 | Pin 2 | Thumb |
| Servo 1 | Pin 3 | Index |
| Servo 2 | Pin 4 | Middle |
| Servo 3 | Pin 5 | Ring |
| Servo 4 | Pin 6 | Pinky |

> ⚠️ **Power servos from an external 5V supply — NOT from Teensy's 5V pin.** Always connect servo GND to both external supply GND and Teensy GND.

---

## 🚀 Software Setup

### 1. Flash Firmware
1. Open `firmware/emg_reader/emg_reader.ino` in Arduino IDE
2. Select Board: **Teensy 4.1**
3. Select USB Type: **Serial**
4. Click **Upload**

### 2. Install Python Dependencies
```bash
cd backend
pip install -r requirements.txt
```

### 3. Launch Dashboard

**Recommended — use the launcher (auto-kills stale port 8000 processes):**
```bash
start.bat
```

**Or run directly:**
```bash
cd backend
py -3.14 main.py
```

### 4. Open Dashboard
Navigate to **http://localhost:8000** in your browser.

> 💡 The launcher (`start.bat` / `run.py`) automatically detects and kills any process already occupying port 8000, preventing the common `WinError 10048` bind error on Windows.

---

## 🎯 Calibration Walkthrough

1. Click **"1. Detect Noise"** — keep all muscles fully relaxed for 3 seconds
2. Click **"2. Detect Range"** — contract all muscles as hard as possible for 5 seconds
3. Adjust the sensitivity sliders per-channel if any channel reads too high/low
4. Click **Save** to persist the calibration profile

---

## 📊 Gesture Training Walkthrough

ARMx now supports **9 gestures** — including independent control of each finger.

### Supported Gestures
| Gesture | Label | Thumb | Index | Middle | Ring | Pinky |
|---|---|---|---|---|---|---|
| Rest | `REST` | Mid | Mid | Mid | Mid | Mid |
| Open Hand | `OPEN` | ✅ | ✅ | ✅ | ✅ | ✅ |
| Fist | `FIST` | ❌ | ❌ | ❌ | ❌ | ❌ |
| Pinch | `PINCH` | ❌ | ❌ | ✅ | ✅ | ✅ |
| Thumb Only | `THUMB` | ✅ | ❌ | ❌ | ❌ | ❌ |
| Index Only | `INDEX` | ❌ | ✅ | ❌ | ❌ | ❌ |
| Middle Only | `MIDDLE_ONLY` | ❌ | ❌ | ✅ | ❌ | ❌ |
| Ring Only | `RING_ONLY` | ❌ | ❌ | ❌ | ✅ | ❌ |
| Pinky Only | `PINKY_ONLY` | ❌ | ❌ | ❌ | ❌ | ✅ |

✅ = Finger open/extended | ❌ = Finger closed/curled

### Guided Training (Recommended)
1. Click **🎓 Guided Train** in the Training panel
2. The system cycles through all 9 gestures automatically:
   - 2 seconds to prepare your hand
   - 3 seconds of recording
   - 1 second rest between gestures
3. Follow the 3D hand visualizer to mimic the correct gesture
4. After all 9 gestures, click **💾 Save Dataset**
5. Click **🚀 Train Model**
6. Click **💾 Save Model**

### Manual Training
1. Hover over any gesture button to preview the hand position in 3D
2. Click the button to start recording (records until you click **■ Stop**)
3. Aim for **50+ samples per gesture** for reliable accuracy
4. Save dataset, train, save model

> 💡 Your last dataset and model automatically reload on server start. Use the dropdown menus to switch between saved profiles.

---

## 🖐️ Per-Finger Independent Control

ARMx supports true independent control of each of the 5 fingers — via both ML prediction and manual override.

### Finger Control Panel
The **Finger Control** panel (bottom of dashboard) provides:
- **5 independent sliders** — one per finger (0° = closed, 180° = open)
- **Quick toggle buttons** — ✊ (close) and ✋ (open) per finger
- **Preset buttons** — All Open, All Closed, Rest

The sliders automatically sync when the ML model predicts a gesture.

### How It Works
When you isolate the movement of a single finger (e.g., raise only your index finger), the 8-channel EMG picks up the unique muscle activation signature. After training on `INDEX`, `MIDDLE_ONLY`, `RING_ONLY`, `PINKY_ONLY`, and `THUMB` individually, the ML classifier maps those patterns directly to single-servo commands.

**EMG → ML Pipeline → Single Servo Command:**
```
Muscle signal → 8-channel EMG → Feature extraction → RandomForest classifier
  → "INDEX_ONLY" → SERVO:1,180   (only index finger opens)
```

### Tips for Better Per-Finger Accuracy
- **Isolate each finger carefully** during training — keep all others relaxed
- Collect at least **50–80 samples per finger gesture**
- Re-train after adding new gestures; don't mix old and new datasets
- Start with broader gestures (REST, OPEN, FIST) before individual fingers

---

## ⚙️ Servo Threshold Tuning

Each physical finger has mechanical limits. Commanding a servo past those limits causes buzzing and motor burnout. Follow these steps to find safe limits.

### Step 1 — Flash the Servo Tuner
1. Open `firmware/servo_tuner/servo_tuner.ino` in Arduino IDE
2. Select **Board: Teensy 4.1**, **USB Type: Serial**
3. Upload, then open Serial Monitor at **115200 baud**

### Step 2 — Tune Each Finger

Commands: letter + angle and press Enter.

| Letter | Finger |
|--------|--------|
| `T` | Thumb |
| `I` | Index |
| `M` | Middle |
| `R` | Ring |
| `P` | Pinky |

**Always start at 90°** — e.g., `T90`. Never jump to 0 or 180 directly.

**Find CLOSE limit:** Decrease in steps of 10 (`I80`, `I70`...) until buzzing. Back off 5°.

**Find OPEN limit:** Increase in steps of 10 (`I100`, `I110`...) until buzzing. Back off 5°.

### Step 3 — Record Your Limits

| Finger | Safe CLOSE Angle (MIN) | Safe OPEN Angle (MAX) |
|--------|------------------------|------------------------|
| Thumb | ___ ° | ___ ° |
| Index | ___ ° | ___ ° |
| Middle | ___ ° | ___ ° |
| Ring | ___ ° | ___ ° |
| Pinky | ___ ° | ___ ° |

**Example for a typical 3D-printed hand:**
| Finger | MIN | MAX |
|--------|-----|-----|
| Thumb | 25 | 155 |
| Index | 20 | 160 |
| Middle | 15 | 165 |
| Ring | 20 | 158 |
| Pinky | 25 | 150 |

### Step 4 — Apply Limits in Code

Edit `backend/control.py` lines 17–18:
```python
SERVO_MINS = [25, 20, 15, 20, 25]       # [Thumb, Index, Middle, Ring, Pinky] — safe CLOSE angles
SERVO_MAXS = [155, 160, 165, 158, 150]  # [Thumb, Index, Middle, Ring, Pinky] — safe OPEN angles
```

Restart the server. Limits are applied automatically to all gesture commands and the per-finger sliders.

### Proportional Control Behaviour
| Muscle Tension | ML Confidence | Finger Movement |
|---|---|---|
| Relaxed | — | REST (mid position) |
| Gentle flex | ~60% | Closes 60% of range |
| Moderate flex | ~80% | Closes 80% of range |
| Hard flex | ~99% | Closes to safe MIN |

---

## 🕹️ Simulation & Debugging

No hardware? No problem. The server automatically enters **Simulation Mode** when no Teensy is detected.

- **8-channel synthetic EMG data** streams in real-time
- All 9 gesture profiles have distinct simulated muscle activations
- Test training, prediction, and the 3D hand visualizer without hardware
- The 3D hologram hand **curls the correct finger(s)** matching each simulated gesture

---

## 🦾 Live Control

1. Ensure model is trained (target accuracy > 80%)
2. Click **▶ Start Control** in the Servo Control panel
3. Perform gestures — the system predicts and sends proportional servo commands
4. Use **Manual Override** buttons to test any of the 9 gestures instantly
5. Use **Finger Control** sliders for direct per-finger angle control
6. Adjust **Speed** and **Sensitivity** sliders as needed

---

## 🐛 Troubleshooting

| Issue | Solution |
|---|---|
| `WinError 10048` on startup | Run `start.bat` — it auto-kills the stale process. Or: `taskkill /IM python.exe /F` |
| "No Teensy found" | Check USB cable, install Teensy drivers from pjrc.com |
| Noisy EMG signals | Check electrode placement, shorten cables, add ferrite beads |
| Low ML accuracy (<70%) | Collect more samples, ensure consistent gesture isolation |
| Single-finger accuracy low | Isolate target finger carefully; train 50–80 samples per finger |
| Servos jittering | Use external 5V power supply; check all GND connections |
| Servo buzzing during tuning | Passed mechanical limit — go back 5–10° |
| Dashboard not loading | Ensure server is running on port 8000 |
| CH5/CH6 not reading | Pins 18/19 conflict with MPU6050 — verify MPU6050 is on Wire2 (pins 24/25) |
| Finger sliders not moving hardware | Hardware must be connected (not in Simulation Mode) |

---

## 📁 Project Structure

```
armx/
├── backend/
│   ├── main.py              # FastAPI server, WebSocket, REST API
│   ├── config.py            # All system parameters (gestures, channels, ML settings)
│   ├── control.py           # Servo gesture → angle mapping, SERVO_MINS/MAXS
│   ├── ml_pipeline.py       # RandomForest/MLP classifier, training, prediction
│   ├── signal_processor.py  # EMG feature extraction, notch filter, windowing
│   ├── serial_handler.py    # Teensy USB serial communication
│   ├── calibration.py       # Noise floor and range calibration
│   ├── data_logger.py       # CSV session recording
│   ├── websocket_manager.py # WebSocket broadcast manager
│   ├── models/              # Saved ML model files (.pkl)
│   └── data/
│       ├── training_sessions/  # Saved training datasets (.npz)
│       ├── calibration/        # Saved calibration profiles
│       └── recordings/         # CSV session recordings
├── frontend/
│   ├── index.html           # Dashboard HTML
│   ├── css/styles.css       # Full dashboard stylesheet
│   └── js/
│       ├── app.js           # Main controller, WebSocket wiring
│       ├── charts.js        # EMG waveform canvas chart
│       ├── imu_viz.js       # 3D hologram hand (CSS 3D transforms)
│       ├── control.js       # Servo control panel UI
│       ├── finger_control.js # Per-finger slider panel UI
│       ├── training.js      # Gesture training UI
│       ├── calibration.js   # Calibration UI
│       ├── recording.js     # Session recording UI
│       ├── feature_heatmap.js # EMG feature heatmap canvas
│       ├── confusion_matrix.js # ML confusion matrix canvas
│       └── websocket.js     # Auto-reconnecting WebSocket client
├── firmware/
│   ├── emg_reader/          # Main Teensy firmware
│   └── servo_tuner/         # Servo limit tuning sketch
├── docs/
│   ├── setup_guide.md       # This file
│   └── api_reference.md     # REST & WebSocket API reference
├── run.py                   # Python launcher with port auto-kill
└── start.bat                # Windows launcher script
```
