Skip to content

About

Non-invasive myoelectric control testbed: surface EMG → movement-intent decoding → effector, with a tactile feedback loop. Research spine: EMG decoder drift robustness across days. Not a medical device.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

myo-control

A non-invasive myoelectric control testbed: read surface EMG from the forearm, decode movement intent, drive an effector (virtual hand first, physical hand later), and close a tactile feedback loop back to the skin.

This is Phase 0 of a long-horizon neural-integration limb project. The research spine is decoder drift robustness — quantifying and mitigating how an EMG decoder degrades across days as electrode placement, arm position, and fatigue vary, and publishing the resulting multi-day dataset.

Design notes and architecture decisions live under docs/.

⚠️ NOT A MEDICAL DEVICE

Experimental research conducted by the maintainer on themselves. Not for clinical, diagnostic, or third-party use. No warranty. Anyone building body-worn or stimulation hardware from this assumes all regulatory and safety responsibility. Anything electrically connected to a human body must be battery-powered and isolated.

Status

Phase 0: the full Week-1 loop runs end-to-end on a synthetic signal source (no hardware required) — acquisition through to a decoded gesture driving a virtual hand:

synthetic EMG → windowing → time-domain features (RMS, MAV, WL, ZC, SSC)
              → parquet recording (+ .meta.json sidecar)
              → LDA decode (trained model card) → virtual hand

A baseline LDA is trained in Python (myotrain) on synthetic, separable data and exported as a model card the Rust loop reads directly (native LDA — no ONNX runtime). Still to come: a real acquisition path (BrainFlow), real recordings, proportional control, tactile feedback, and the multi-day drift study.

Quick start

Develop with no hardware against the synthetic board:

# Record 2 s of synthetic EMG to data/sessions/ and log feature vectors
cargo run -p myo-rt -- --board synthetic

# Options: --duration <s> --channels <n> --rate <hz> --window-ms --increment-ms --fast
cargo run -p myo-rt -- --board synthetic --duration 5 --channels 8 --fast

cargo test                                  # unit tests
cargo fmt && cargo clippy --all-targets -- -D warnings

Recorded sessions land in data/sessions/ and are git-ignored — raw recordings are never committed (the curated dataset is published separately).

Close the loop with a trained decoder

Train a baseline LDA (synthetic, separable data for now) and export a model card, then let the Rust loop decode live windows and drive the virtual hand:

# One-time: pinned Python env for training
uv venv --python 3.12 python/myotrain/.venv
uv pip install --python python/myotrain/.venv numpy scikit-learn

# Train -> model card (JSON consumed directly by the Rust decoder; no ONNX)
PYTHONPATH=python/myotrain python/myotrain/.venv/bin/python \
    -m myotrain.train --out models/lda.json

# Run the loop with the model: each window is classified and drives the hand
cargo run -p myo-rt -- --board synthetic --fast --model models/lda.json

Without --model the loop just records; with it, predictions drive the virtual hand. (Classification on synthetic noise is not meaningful — this proves the train → card → decode plumbing; real signal comes later.)

Watch it in 3D

Add --hand to stream poses to a browser viewer (an articulated 3D hand that opens/closes with the decoded gesture). Add --gesture-demo to cycle the synthetic signal through rest/open/close so the hand visibly animates (without it, constant synthetic noise just decodes to rest):

cargo run -p myo-rt -- --board synthetic --duration 300 \
    --model models/lda.json --hand --gesture-demo

Then open viewer/hand.html in a browser. It connects to the loop over WebSocket (ws://127.0.0.1:8765, override the port with --hand-port and viewer/hand.html?port=NNNN) and eases the finger curl toward each pose's closure target. three.js is vendored under viewer/vendor/, so it works offline. The loop runs fine whether or not a browser is connected.

Repository layout

crates/myo-rt/     Rust real-time control loop (acquisition → features → decode → effector)
python/myotrain/   training + offline analysis (LDA, model-card export)
viewer/            browser 3D hand viewer (WebSocket client, vendored three.js)
data/              recording schema + protocol (raw recordings gitignored)
docs/              architecture notes, design specs

Future trees (firmware/, hardware/) arrive with later phases.

Licensing

  • Code: Apache-2.0 (see LICENSE).
  • Dataset: CC-BY (published separately).
  • Hardware/CAD: CERN-OHL or CC-BY.

Built on the field's open infrastructure (BrainFlow, LibEMG, OpenBCI, HACKberry/InMoov) — cite it.

About

Non-invasive myoelectric control testbed: surface EMG → movement-intent decoding → effector, with a tactile feedback loop. Research spine: EMG decoder drift robustness across days. Not a medical device.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages