Skip to content

Latest commit

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

RAMCOD — Myoelectric Control Training System

RAMCOD Logo

PythonMATLABArduinoWokwiPlatformLicense

RAMCOD is a real-time myoelectric control training platform for mechano-electric prosthetics.
It captures EMG signals from surface electrodes, filters them through a clinical-grade MATLAB pipeline, and drives a servo motor on voluntary muscle contraction — replicating the closed-loop control of a real prosthetic limb.

Full simulation available — run the complete system without any hardware using Wokwi + VS Code.


Table of Contents


System Architecture

┌───────────────────────────────────────────────────────────────────────┐
│ PHYSICAL (Mode A) │
│ [AD8232 sensors] → [Arduino UNO] ──── USB UART 230400 ────────────── │
│ or │
│ SIMULATION (Mode B) │
│ [Wokwi potentiometers] → [Virtual Arduino] ── RFC2217 TCP:4000 ────── │
│ │ │
├───────────────────────────────────────────────────────────────────────┤
│ PYTHON HOST (src/python/) │
│ serial_comm.py → auto-detects hardware OR rfc2217://localhost:4000 │
│ matlab_bridge.py → MATLAB Engine OR SciPy fallback │
│ activation.py → refractory period + alternating S1↔S2 logic │
│ gui_*.py → PyQt5 GUI + pyqtgraph real-time plots │
├───────────────────────────────────────────────────────────────────────┤
│ MATLAB (src/matlab/functions/) │
│ emg_filter.m emg_rms.m emg_calibrate.m emg_activate.m │
└───────────────────────────────────────────────────────────────────────┘

Hybrid Design Philosophy

LayerToolRationale
Signal processingMATLABSignal Processing Toolbox; validated butter/filtfilt; industry-standard in clinical labs
Application & GUIPythonModern GUI (PyQt5); modular architecture; deployable without MATLAB licence
Embedded firmwareArduino C++Low-cost open hardware; real closed-loop for demonstrations
Circuit simulationWokwiFull hardware simulation; RFC2217 bridge connects to real Python GUI

The Python host calls MATLAB functions via the MATLAB Engine API. If MATLAB is unavailable, a numerically identical SciPy fallback runs transparently. A badge in the header shows the active backend.


Hardware Requirements

ComponentSpecification
Arduino UNO (or compatible)ATmega328P, 5V
AD8232 EMG sensor modules1 or 2 (system validated with 2)
Surface EMG electrodesStandard ECG/EMG snap-on electrodes
PWM servo motorAny 5V standard servo (SG90, MG996R…)
USB-A to USB-B cableArduino connection

Pin connections

SensorSignalLO+LO−
Sensor 1A0D8D9
Sensor 2A1D10D11
Sensor 3A2D12D13
Sensor 4A3D2D4
Servo PWMD7

Sensors 3 & 4 mirror S1/S2 in the current 2-sensor hardware build. Full 4-sensor support is preserved in the code.


Software Requirements

Python

Python >= 3.10
PyQt5 >= 5.15.0
pyqtgraph >= 0.13.0
pyserial >= 3.5
numpy >= 1.24.0
scipy >= 1.11.0

MATLAB Engine API (optional — enables MATLAB backend)

  • MATLAB R2022a or newer + Signal Processing Toolbox
cd<MATLAB_ROOT>/extern/engines/python
python setup.py install

Wokwi simulation (optional — enables hardware-free demo)

Arduino firmware (hardware mode)

  • Arduino IDE 1.8+ or Arduino CLI
  • Library: Servo (bundled with Arduino IDE)

Repository Structure

RAMCOD/
├── src/
│ ├── arduino/
│ │ └── RAMCOD_firmware.ino Production firmware (230400 baud)
│ │
│ ├── matlab/
│ │ ├── functions/
│ │ │ ├── emg_filter.m
│ │ │ ├── emg_rms.m
│ │ │ ├── emg_calibrate.m
│ │ │ └── emg_activate.m
│ │ ├── RMC_GUI_Comun.mlapp Standalone MATLAB GUI
│ │ └── RAMCOD_tests.m 17 unit tests
│ │
│ ├── python/
│ │ ├── main.py Entry point
│ │ ├── requirements.txt
│ │ └── ramcod/
│ │ ├── serial_comm.py Hardware + RFC2217 auto-detection
│ │ ├── matlab_bridge.py MATLAB Engine + SciPy fallback
│ │ ├── activation.py Servo activation controller
│ │ ├── profiles.py JSON profile persistence
│ │ ├── worker.py QThread acquisition
│ │ ├── gui_constants.py Theme, widgets, constants
│ │ ├── gui_setup.py Setup panels
│ │ └── gui_training.py Real-time training view
│ │
│ └── wokwi/
│ ├── RAMCOD_wokwi.ino Simulation firmware (115200 baud)
│ ├── diagram.json Circuit: Arduino + pots + servo + LED
│ └── wokwi.toml VS Code config + rfc2217ServerPort=4000
│
├── profiles/ Saved user calibration profiles
├── docs/
│ └── RAMCOD_Technical_Documentation.docx
├── demo/
│ └── logo.png
└── README.md

Installation

Python dependencies

cd src/python
pip install -r requirements.txt

Arduino CLI (needed for Wokwi VS Code mode)

# Install Arduino CLI: https://arduino.github.io/arduino-cli/
arduino-cli core install arduino:avr

Wokwi VS Code extension

  1. Open VS Code → Extensions → search Wokwi
  2. Install Wokwi for VS Code
  3. Press F1Wokwi: Request a new License → follow browser prompt (free)

Running the Application

Mode A — Hardware (real Arduino)

# 1. Flash firmware
arduino-cli compile --fqbn arduino:avr:uno src/arduino/RAMCOD_firmware.ino
arduino-cli upload --fqbn arduino:avr:uno --port /dev/ttyUSB0 src/arduino/RAMCOD_firmware.ino
# 2. Run GUI — auto-detects the board on COM/ttyUSB portscd src/python
python main.py

The header badge shows ● COM3 (or equivalent). Connection LED is green.


Mode B — Full simulation (Wokwi + VS Code)

This is the most impressive demo mode: the real Python GUI connects to a virtual Arduino running in Wokwi. No physical hardware needed.

Step 1 — Compile the simulation firmware

arduino-cli compile \
--fqbn arduino:avr:uno \
--output-dir src/wokwi/build \
src/wokwi/RAMCOD_wokwi.ino

Step 2 — Start the Wokwi simulator

Open VS Code in the project root, then:

F1 → Wokwi: Start Simulator

The Wokwi panel opens — you see the Arduino UNO, two potentiometers, and the servo. Leave this panel visible (Wokwi pauses when hidden).

Step 3 — Run the Python GUI

cd src/python
python main.py

Step 4 — Connect

Click Search Board in the GUI.

  • The app first scans hardware COM ports (finds none)
  • Then tries rfc2217://localhost:4000 — finds the Wokwi simulation
  • Header badge changes to ● Wokwi Simulation in cyan
  • Connection LED turns blue

Step 5 — Use it

  • Check Electrodes → returns 1,1,1,1 (LO pins wired to GND in simulation)
  • Calibrate → captures 10 s baseline from the potentiometers at rest (leave them at 0)
  • Start Training → real-time EMG plots appear
  • Turn pot1 clockwise past 70% → servo in Wokwi moves to 0° + activation flash in GUI
  • Turn pot2 clockwise past 70% → servo moves to 90° + flash

Mode C — Wokwi web editor (no Python GUI)

Use this to quickly show the circuit to someone without installing anything.

  1. Go to wokwi.com/projects/new/arduino-uno
  2. Paste src/wokwi/RAMCOD_wokwi.ino → sketch.ino tab
  3. Paste src/wokwi/diagram.json → diagram.json tab
  4. Press ▶ Play
  5. Open Serial Monitor → send commands:
CommandResponse
CRAMCOD — handshake confirmed
A1,1,1,1 — all sensors OK
1Starts 10 s binary stream. Turn pots to activate servo.
SSine wave test stream. Send any key to stop.

How RFC2217 Connects Python to Wokwi

┌──────────────────────────────────────────────────────────────────┐
│ Wokwi VS Code extension │
│ ┌─────────────────────────┐ │
│ │ Virtual Arduino UNO │ │
│ │ pot1 → A0 (EMG S1) │ │
│ │ pot2 → A1 (EMG S2) │ UART at 115200 baud (simulated) │
│ │ servo ← D7 │ │ │
│ └─────────────────────────┘ │ │
│ ↕ wokwi.toml: rfc2217ServerPort = 4000 │
│ ┌─────────────────────────┐ │ │
│ │ RFC2217 TCP server │◄───────┘ │
│ │ localhost : 4000 │ │
│ └─────────────────────────┘ │
└─────────────────┬────────────────────────────────────────────────┘
│ TCP (RFC2217 — serial-over-TCP standard)
┌─────────────────▼────────────────────────────────────────────────┐
│ Python — serial_comm.py │
│ serial.serial_for_url("rfc2217://localhost:4000", baud=115200) │
│ │
│ find_board() search order: │
│ 1. Scan hardware COM/ttyUSB ports → not found │
│ 2. Try rfc2217://localhost:4000 → RAMCOD handshake OK ✔ │
│ │
│ After connection — identical API regardless of mode: │
│ .check_sensors() .start_stream() .read_sample() │
│ .send_servo() .start_sine() .close() │
└──────────────────────────────────────────────────────────────────┘

RFC2217 is an IETF standard (RFC 2217) for tunnelling serial port data over TCP. PySerial supports it natively via serial_for_url() — no extra libraries needed. The virtual serial port behaves identically to a real COM port from the application's perspective.


Usage Walkthrough

StepActionResult
① ConnectSearch BoardAuto-detects hardware or Wokwi simulation
② SensorsCheck ElectrodesGreen LED = contact OK (or always OK in simulation)
③ CalibrateRun Calibration Wizard10 s rest capture → baseline RMS per sensor
④ ProfileSavePersist calibration — skip next session
⑤ TrainStart TrainingReal-time raw + filtered EMG plots
⑥ ActivateContract muscle / turn potServo moves + activation flash in GUI
⑦ TuneSensitivity slidersAdjust threshold without recalibrating

Signal Processing Pipeline

Raw ADC [0–1023]
│
▼ emg_filter.m / scipy.signal.butter + filtfilt
Butterworth bandpass 10–200 Hz, order 2, zero-phase
│
▼ emg_rms.m / numpy
RMS envelope per 50 ms window → 4 values (one per sensor)
│
▼ emg_activate.m / activation.py
RMS > sensitivity × RMS_baseline ?
│ Yes → servo command byte → Arduino
│ + 1 s refractory period
│ + S1↔S2 alternation
▼
Servo moves

MATLAB Functions Reference

FunctionSignatureReturns
emg_filter(raw_data, fs, 'LowHz', 10, 'HighHz', 200, 'Order', 2)filtered N×4
emg_rms(filtered_window)rms_vals 1×4, rectified N×4
emg_calibrate(filtered_data, active_sensors)noise_profile struct
emg_activate(rms_vals, noise_profile, sensitivity, next_cmd)cmd uint8, sensor int

Run unit tests from MATLAB:

cdsrc/matlab
run('RAMCOD_tests.m') % 17 assertions, 4 suites

Arduino Protocol Reference

DirectionByteMeaning
PC → Board'C'Handshake → "RAMCOD\r\n"
PC → Board'A'Sensor check → "1,0,1,0\r\n"
PC → Board'1''6'Stream N×10000 samples
PC → Board'S'Sine test stream
Board → PCuint16 ×4One sample, 8 bytes, LSB first: S1 S2 S3 S4
PC → Boarduint8 2–4Servo → Position A
PC → Boarduint8 6–9Servo → Position B

Baud rate: 230400 (hardware) / 115200 (Wokwi simulation).


Configuration Reference

ParameterFileDefaultNotes
BAUD_HARDWAREserial_comm.py230400Real Arduino
RFC2217_URLserial_comm.pyrfc2217://localhost:4000Wokwi endpoint
rfc2217ServerPortwokwi.toml4000Must match above
SAMPLE_RATEgui_constants.py1000 HzHardware nominal
WINDOW_MSgui_constants.py50 msRMS window
SCROLL_SECgui_constants.py10 sPlot time window
CALIB_SECSgui_constants.py10 sCalibration duration
SERVO_POS_A/Bfirmware0° / 90°Servo target angles
EMG_THRESHOLDRAMCOD_wokwi.ino700/1023Wokwi standalone threshold

Developed by Alonso Martín Díez · Biomedical Engineering · UEM 2026

About

Myoelectric control training system for prosthetic hand activation · MATLAB + Arduino + Python

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages