2D-EMG-GAME
Solo (building on Hugo Devoille's framework) · 2023–24
Overview
Surface electromyography measures the electrical activity a muscle produces when it contracts. Prosthetics use it. So do rehabilitation and control interfaces. Entertainment barely does, and the little research that exists rarely leaves the forearm.
So I asked a blunter question. Can a muscle, any muscle you pick, be a game controller? A real one, mapped to real inputs, playing games that were never designed for it.
The control logic: four bands of effort
Treat the muscle as a dial rather than a button. Contraction strength is normalized against the player’s own maximum, then split into four bands, and each band triggers a different input.
| Effort (% of your max) | Input |
|---|---|
| 0 – 25 % | input 1 |
| 25 – 50 % | input 2 |
| 50 – 75 % | input 3 |
| 75 – 100 % | input 4 |
One muscle, four controls. Add a second channel and the vocabulary multiplies.
Calibration therefore happens per muscle and per player, never as a fixed voltage. Percent of your own maximum is the only unit that survives moving the electrodes to another arm, another muscle, or another person.


The chain
- Acquisition. A BITalino (r)evolution Plugged board with the BioSignals sensor kit, one EMG
module per muscle, three electrodes each:
IN+andIN−straddle the muscle belly,REFsits on bone. The full assembly is documented on the Body Shape Control Suit page, since both projects use the same hardware. - Recording. OpenSignals, for streaming and visual inspection. It is how you find out that a channel is picking up mains hum instead of a biceps.
- Processing. Python with NumPy and SciPy: band-pass, rectify, smooth, then compare against the calibrated maximum to land in one of the four bands.
- Output. The bands are emitted as controller inputs and routed through Steam Input. That last step is what takes the prototype out of the lab and into games nobody wrote for it.

The bridge: Python on one side, Unity on the other
Steam Input covers commercial games. My own Unity game needed something more direct, so the two halves talk over a plain TCP socket.
On the Python side, BitalinoAcquisition.py opens a server on localhost:12345 and streams
comma-separated values, one per reading, as soon as a client connects. On the Unity side, EMGData.cs
opens a TcpClient, reads the stream inside a coroutine so the game loop never blocks, splits on the
comma and parses each value with CultureInfo.InvariantCulture, because a decimal separator that
changes with the machine’s locale will silently break a controller.
That seam keeps showing up in my work. The same shape drives Thoughts in Motion, where a Python classifier feeds a 3D scene, and it is the same problem I solved again in TRON and Chat-Room-API. One process owns the signal, another owns the display, and a socket carries the agreement between them.
The games
Three tiers, deliberately, because each one tests something different.
- Python prototypes. A custom Flappy Bird as the training game. One muscle, one action, instant feedback. It is where a player learns what 40 % of their own strength actually feels like.
- A 2D platformer in Unity. Several scenes, movement and jumping on muscle input. Continuous control, so the band boundaries have to hold steady or the character jitters.
- Real Steam titles. The actual test. No cooperation from the game, no special build.


Evaluation protocol
The test session was structured rather than improvised.
- Setup. Fit the electrodes, calibrate, explain the four bands.
- Training. Free play on the custom Flappy Bird until the mapping stops feeling arbitrary.
- Testing. Play Steam games with the EMG controller, watching for ease of use, accuracy and responsiveness.
Running that protocol in public at the Festival of Learning was its harshest version. Strangers, different body types, no time to fiddle. Anything that only worked on my own forearm failed within seconds.
What was hard
- Signal, not data. Filtering, noise rejection and real-time interpretation all have to be right at the same time. Get one wrong and the controller feels haunted rather than simply broken.
- Mapping is a design problem. Turning EMG features into controls that feel fair took more iterations than the signal processing did. Band edges that look clean on a plot can be exhausting to hold.
- Calibration drifts. Muscle activity changes with fatigue, electrode placement changes with the person, and the room adds its own noise. The per-user maximum absorbs a lot of that. Not all of it, though, and sometimes a mid-session recalibration is the honest answer.
Why it matters
The research this builds on points the same way. MyoGuide uses sEMG to gamify wrist-extension training for stroke patients, and detects movement intention even in a paretic limb. Pedro Lopes’ work on proprioceptive interaction and muscle-propelled force feedback goes further, treating the body as input and output at once. The common thread: a muscle-driven interface can work in situations where a hand on a gamepad cannot.
That is the ambition here. Four bands of effort make a game controller. One that needs no fingers.
Documented in full in From Muscle to Screen: A Comprehensive Tutorial on Integrating surface EMG Detection in game and using it like a game-controller (2023–24). Built on top of Hugo Devoille’s acquisition framework.
Überblick
Oberflächen-Elektromyographie misst die elektrische Aktivität, die ein Muskel beim Anspannen erzeugt. Prothetik nutzt das. Rehabilitation und Steuerungsschnittstellen ebenfalls. Unterhaltung kaum, und die wenige vorhandene Forschung verlässt selten den Unterarm.
Also habe ich die Frage direkter gestellt. Kann ein Muskel, irgendein Muskel, ein Gamecontroller sein? Ein echter, auf echte Eingaben gelegt, für Spiele, die nie dafür gedacht waren.
Die Steuerlogik: vier Kraftstufen
Den Muskel als Regler behandeln statt als Knopf. Die Kontraktionsstärke wird auf das eigene Maximum der Spielerin normiert, dann in vier Stufen geteilt, und jede Stufe löst eine andere Eingabe aus.
| Kraft (% deines Maximums) | Eingabe |
|---|---|
| 0 – 25 % | input 1 |
| 25 – 50 % | input 2 |
| 50 – 75 % | input 3 |
| 75 – 100 % | input 4 |
Ein Muskel, vier Befehle. Ein zweiter Kanal vervielfacht das Vokabular.
Kalibriert wird deshalb pro Muskel und pro Person, nie als feste Spannung. Prozent des eigenen Maximums ist die einzige Einheit, die überlebt, wenn die Elektroden an einen anderen Arm, einen anderen Muskel oder eine andere Person wandern.


Die Kette
- Erfassung. Ein BITalino (r)evolution Plugged Board mit dem BioSignals-Sensorkit, ein EMG-Modul pro Muskel, je drei Elektroden:
IN+undIN−umschließen den Muskelbauch,REFsitzt auf Knochen. Der komplette Aufbau ist auf der Seite Body Shape Control Suit dokumentiert, beide Projekte nutzen dieselbe Hardware. - Aufzeichnung. OpenSignals, für Streaming und Sichtprüfung. So findet man heraus, dass ein Kanal Netzbrummen statt eines Bizeps aufnimmt.
- Verarbeitung. Python mit NumPy und SciPy: Bandpass, Gleichrichtung, Glättung, dann Vergleich mit dem kalibrierten Maximum, um in einer der vier Stufen zu landen.
- Ausgabe. Die Stufen werden als Controller-Eingaben ausgegeben und über Steam Input geleitet. Genau dieser letzte Schritt holt den Prototypen aus dem Labor in Spiele, die niemand dafür geschrieben hat.

Die Brücke: Python auf der einen, Unity auf der anderen Seite
Steam Input deckt kommerzielle Spiele ab. Mein eigenes Unity-Spiel brauchte etwas Direkteres, also reden die beiden Hälften über einen schlichten TCP-Socket.
Auf der Python-Seite öffnet BitalinoAcquisition.py einen Server auf localhost:12345 und sendet
kommagetrennte Werte, einen pro Messung, sobald ein Client verbunden ist. Auf der Unity-Seite öffnet
EMGData.cs einen TcpClient, liest den Stream in einer Coroutine, damit die Spielschleife nie
blockiert, trennt am Komma und parst jeden Wert mit CultureInfo.InvariantCulture, denn ein
Dezimaltrennzeichen, das sich mit der Locale des Rechners ändert, zerlegt einen Controller lautlos.
Diese Naht taucht in meiner Arbeit immer wieder auf. Dieselbe Form treibt Thoughts in Motion an, wo ein Python-Klassifikator eine 3D-Szene speist, und es ist dasselbe Problem, das ich in TRON und Chat-Room-API erneut gelöst habe. Ein Prozess besitzt das Signal, ein anderer die Darstellung, und ein Socket trägt die Vereinbarung zwischen beiden.
Die Spiele
Drei Stufen, mit Absicht, weil jede etwas anderes prüft.
- Python-Prototypen. Ein selbstgebautes Flappy Bird als Trainingsspiel. Ein Muskel, eine Aktion, sofortige Rückmeldung. Dort lernt eine Spielerin, wie sich 40 % der eigenen Kraft wirklich anfühlen.
- Ein 2D-Platformer in Unity. Mehrere Szenen, Bewegung und Sprung über Muskeleingabe. Kontinuierliche Steuerung, also müssen die Stufengrenzen ruhig bleiben, sonst zittert die Figur.
- Echte Steam-Titel. Der eigentliche Test. Keine Mithilfe des Spiels, kein Sonderbuild.


Evaluationsprotokoll
Die Testsitzung war strukturiert statt improvisiert.
- Aufbau. Elektroden anlegen, kalibrieren, die vier Stufen erklären.
- Training. Freies Spiel im eigenen Flappy Bird, bis sich die Zuordnung nicht mehr willkürlich anfühlt.
- Test. Steam-Spiele mit dem EMG-Controller spielen, mit Blick auf Bedienbarkeit, Genauigkeit und Reaktion.
Dieses Protokoll öffentlich beim Festival of Learning zu fahren war seine härteste Fassung. Fremde Menschen, andere Körper, keine Zeit zum Nachjustieren. Alles, was nur auf meinem eigenen Unterarm funktionierte, fiel binnen Sekunden durch.
Was schwer war
- Signal, nicht Daten. Filterung, Rauschunterdrückung und Echtzeitdeutung müssen gleichzeitig stimmen. Stimmt eines nicht, wirkt der Controller eher verhext als kaputt.
- Mapping ist ein Designproblem. EMG-Merkmale in Steuerung zu übersetzen, die sich fair anfühlt, brauchte mehr Durchläufe als die Signalverarbeitung. Stufengrenzen, die im Plot sauber aussehen, können anstrengend zu halten sein.
- Kalibrierung driftet. Muskelaktivität ändert sich mit Ermüdung, die Elektrodenlage mit der Person, und der Raum bringt eigenes Rauschen mit. Das persönliche Maximum fängt viel davon ab. Nicht alles, und manchmal ist eine Neukalibrierung mitten in der Sitzung die ehrliche Antwort.
Warum es zählt
Die Forschung dahinter zeigt in dieselbe Richtung. MyoGuide nutzt sEMG, um Handgelenks-Training für Schlaganfallpatienten zu gamifizieren, und erkennt Bewegungsabsicht sogar in einer gelähmten Extremität. Pedro Lopes’ Arbeiten zu propriozeptiver Interaktion und muskelgetriebenem Force Feedback gehen weiter und behandeln den Körper zugleich als Eingabe und Ausgabe. Der gemeinsame Faden: eine muskelgesteuerte Schnittstelle kann dort funktionieren, wo eine Hand am Gamepad es nicht kann.
Das ist der Anspruch hier. Vier Kraftstufen ergeben einen Gamecontroller. Einen, der ohne Finger auskommt.
Vollständig dokumentiert in From Muscle to Screen: A Comprehensive Tutorial on Integrating surface EMG Detection in game and using it like a game-controller (2023-24). Aufgebaut auf dem Erfassungs-Framework von Hugo Devoille.
Vue d’ensemble
L’électromyographie de surface mesure l’activité électrique produite par un muscle qui se contracte. Les prothèses s’en servent. La rééducation et les interfaces de commande aussi. Le divertissement presque pas, et le peu de recherche qui existe quitte rarement l’avant-bras.
Alors j’ai posé la question plus frontalement. Un muscle, n’importe lequel, peut-il servir de manette ? Une vraie manette, câblée sur de vraies entrées, pour jouer à des jeux qui n’ont jamais été pensés pour ça.
La logique de contrôle : quatre paliers d’effort
Traiter le muscle comme un potentiomètre plutôt que comme un bouton. La force de contraction est normalisée sur le maximum du joueur, puis découpée en quatre paliers, et chaque palier déclenche une entrée différente.
| Effort (% de ton maximum) | Entrée |
|---|---|
| 0 – 25 % | input 1 |
| 25 – 50 % | input 2 |
| 50 – 75 % | input 3 |
| 75 – 100 % | input 4 |
Un muscle, quatre commandes. Ajoute un second canal et le vocabulaire se multiplie.
L’étalonnage se fait donc par muscle et par joueur, jamais en tension fixe. Le pourcentage de ton propre maximum est la seule unité qui survit au déplacement des électrodes sur un autre bras, un autre muscle ou une autre personne.


La chaîne
- Acquisition. Une carte BITalino (r)evolution Plugged avec le kit de capteurs BioSignals, un module EMG par muscle, trois électrodes chacun :
IN+etIN−encadrent le ventre du muscle,REFse pose sur l’os. Le montage complet est documenté sur la page Body Shape Control Suit, les deux projets utilisant le même matériel. - Enregistrement. OpenSignals, pour le flux et l’inspection visuelle. C’est là qu’on découvre qu’un canal capte le 50 Hz du secteur plutôt qu’un biceps.
- Traitement. Python avec NumPy et SciPy : passe-bande, redressement, lissage, puis comparaison au maximum étalonné pour tomber dans l’un des quatre paliers.
- Sortie. Les paliers sont émis comme entrées de manette et passent par Steam Input. C’est cette dernière étape qui sort le prototype du labo et le fait fonctionner avec des jeux que personne n’a écrits pour lui.

Le pont : Python d’un côté, Unity de l’autre
Steam Input couvre les jeux du commerce. Mon propre jeu Unity demandait quelque chose de plus direct : les deux moitiés se parlent par une simple socket TCP.
Côté Python, BitalinoAcquisition.py ouvre un serveur sur localhost:12345 et diffuse des valeurs
séparées par des virgules, une par lecture, dès qu’un client se connecte. Côté Unity, EMGData.cs ouvre
un TcpClient, lit le flux dans une coroutine pour que la boucle de jeu ne bloque jamais, découpe sur
la virgule et parse chaque valeur avec CultureInfo.InvariantCulture : un séparateur décimal qui change
selon la locale de la machine casse une manette en silence.
Cette jointure revient sans cesse dans mon travail. C’est la même forme qui fait tourner Thoughts in Motion, où un classifieur Python alimente une scène 3D, et le même problème que j’ai résolu à nouveau dans TRON et Chat-Room-API. Un processus détient le signal, un autre détient l’affichage, et une socket transporte le contrat entre les deux.
Les jeux
Trois niveaux, délibérément, parce que chacun teste autre chose.
- Prototypes Python. Un Flappy Bird maison comme jeu d’entraînement. Un muscle, une action, un retour immédiat. C’est là qu’un joueur apprend ce que 40 % de sa propre force représente vraiment.
- Un plateformer 2D sous Unity. Plusieurs scènes, déplacement et saut à la contraction. Du contrôle continu, donc les frontières entre paliers doivent tenir sinon le personnage tremble.
- De vrais jeux Steam. Le vrai test. Aucune coopération du jeu, aucune build spéciale.


Protocole d’évaluation
La session de test était structurée plutôt qu’improvisée.
- Installation. Poser les électrodes, étalonner, expliquer les quatre paliers.
- Entraînement. Jeu libre sur le Flappy Bird maison jusqu’à ce que la correspondance cesse de paraître arbitraire.
- Test. Jouer à des jeux Steam avec la manette EMG, en observant la facilité de prise en main, la précision et la réactivité.
Faire tourner ce protocole en public au Festival of Learning en était la version la plus dure. Des inconnus, des morphologies différentes, aucun temps de réglage. Tout ce qui ne fonctionnait que sur mon propre avant-bras s’effondrait en quelques secondes.
Ce qui a été difficile
- Du signal, pas de la donnée. Filtrage, réjection du bruit et interprétation temps réel doivent être justes en même temps. Rate-en un et la manette semble hantée plutôt que simplement cassée.
- Le mapping est un problème de design. Transformer des caractéristiques EMG en commandes qui semblent justes a demandé plus d’itérations que le traitement du signal. Des frontières de paliers qui paraissent propres sur un graphe peuvent être épuisantes à tenir.
- L’étalonnage dérive. L’activité musculaire change avec la fatigue, le placement des électrodes change avec la personne, et la pièce ajoute son propre bruit. Le maximum par utilisateur absorbe beaucoup. Pas tout, et un ré-étalonnage en cours de session est parfois la réponse honnête.
Pourquoi ça compte
La recherche sur laquelle ça s’appuie va dans le même sens. MyoGuide utilise l’EMG de surface pour gamifier la rééducation de l’extension du poignet chez des patients post-AVC, et détecte l’intention de mouvement même dans un membre parétique. Les travaux de Pedro Lopes sur l’interaction proprioceptive et le retour de force propulsé par le muscle vont plus loin et traitent le corps comme entrée et sortie à la fois. Le fil commun : une interface pilotée par le muscle peut fonctionner là où une main sur une manette ne peut pas.
C’est l’ambition ici. Quatre paliers d’effort font une manette. Une manette qui n’a pas besoin de doigts.
Documenté intégralement dans From Muscle to Screen: A Comprehensive Tutorial on Integrating surface EMG Detection in game and using it like a game-controller (2023-24). Construit sur le framework d’acquisition d’Hugo Devoille.
概要
表面筋電図(sEMG)は、筋肉が収縮するときに生じる電気的な活動を測るものです。義肢の分野では使われています。リハビリや操作インターフェースでも使われています。ところがエンターテインメントではほとんど使われておらず、数少ない研究も前腕から先へ出ることが稀です。
そこで、もっと単刀直入に問いを立てました。どの筋肉でもいい、筋肉はゲームコントローラーになれるか。 ジェスチャー認識の実験ではなく、実際の入力に割り当てられ、そのために設計されていない市販ゲームを遊べる本物のコントローラーとして。
操作の考え方:4段階の力
筋肉をボタンではなくつまみとして扱います。収縮の強さをその人自身の最大値で正規化し、4つの帯に分け、それぞれの帯が別の入力を出します。
| 力(自分の最大値に対する%) | 入力 |
|---|---|
| 0 – 25 % | input 1 |
| 25 – 50 % | input 2 |
| 50 – 75 % | input 3 |
| 75 – 100 % | input 4 |
筋肉ひとつで4つの操作。チャンネルを増やせば語彙はさらに広がります。
そのためキャリブレーションは筋肉ごと、人ごとに行い、固定電圧では決してやりません。自分の最大値に対する割合だけが、電極を別の腕、別の筋肉、別の人に移しても生き残る単位だからです。


チェーン
- 取得。 BioSignals センサーキットを載せた BITalino (r)evolution Plugged ボード。筋肉ひとつにつき EMG モジュール1つ、電極は3枚で、
IN+とIN−が筋腹をはさみ、REFは骨の上に置きます。組み立ての手順は Body Shape Control Suit のページに載せてあります。両プロジェクトで同じハードを使っているためです。 - 記録。 OpenSignals でストリーミングと目視確認。「このチャンネル、上腕二頭筋ではなく電源ハムを拾っているな」と気づけるのはここです。
- 処理。 Python の NumPy と SciPy。バンドパス、整流、平滑化を通し、キャリブレーション済みの最大値と比べて4つの帯のどれかに落とします。
- 出力。 各帯をコントローラー入力として送り出し、Steam Input を経由させます。この最後の一段があるおかげで、試作品が研究室を出て、そのために書かれていないゲームでも動くようになります。

橋渡し:片側に Python、もう片側に Unity
Steam Input が担うのは市販ゲームです。自作の Unity ゲームにはもっと直接的な経路が要ったので、2つの半分は 素朴な TCP ソケットで会話しています。
Python 側では BitalinoAcquisition.py が localhost:12345 にサーバーを立て、クライアントが接続した
時点から、計測1回につき1つの値をカンマ区切りで流し続けます。Unity 側では EMGData.cs が TcpClient
を開き、ゲームループを止めないようコルーチンの中でストリームを読み、カンマで分割して各値を
CultureInfo.InvariantCulture でパースします。小数点記号がマシンのロケール次第で変わると、コントローラーは
何のエラーも出さずに壊れるからです。
この継ぎ目は私の仕事に何度も現れます。Python の分類器が 3D シーンを動かす Thoughts in Motion も同じ形ですし、TRON と Chat-Room-API でも同じ問題をもう一度解いています。あるプロセスが信号を持ち、別の プロセスが表示を持ち、その間の取り決めをソケットが運ぶ、という構図です。
使ったゲーム
3段階を意図的に用意しました。それぞれ試すものが違うからです。
- Python の試作。 自作の Flappy Bird を練習用に。筋肉ひとつ、動作ひとつ、反応は即座。自分の力の40%がどんな感覚なのかを体で覚える場所です。
- Unity の2Dプラットフォーマー。 複数のシーンがあり、移動もジャンプも筋肉入力。連続的な操作なので、帯の境界が安定していないとキャラクターが震えます。
- 市販の Steam タイトル。 ここが本番です。ゲーム側の協力もなく、専用ビルドもありません。


評価のやり方
テストはその場任せではなく、手順を決めて行いました。
- セットアップ。 電極を貼り、キャリブレーションし、4段階を説明する。
- 練習。 対応づけが恣意的に感じられなくなるまで、自作 Flappy Bird で自由に遊んでもらう。
- テスト。 EMG コントローラーで Steam のゲームを遊び、使いやすさ、正確さ、反応の速さを観察する。
これを Festival of Learning で一般公開の場でやったのが、いちばん厳しい版でした。初対面の人、さまざまな体格、調整する時間もなし。自分の前腕でしか動かないものは、数秒で馬脚を現します。
難しかったところ
- データではなく信号。 フィルタリング、ノイズ除去、リアルタイムの解釈が同時に正しくないといけません。どれかひとつ外すと、コントローラーは「壊れている」というより「取り憑かれている」ような挙動になります。
- マッピングは設計の問題。 EMG の特徴量を「納得のいく操作」に変える作業には、信号処理そのものより多くの試行が必要でした。グラフ上では綺麗に見える境界でも、保ち続けるのはひどく疲れることがあります。
- キャリブレーションはずれる。 筋活動は疲労で変わり、電極の位置は人によって変わり、部屋そのものもノイズを足してきます。個人の最大値がかなりの部分を吸収してくれますが、全部ではありません。途中で取り直すのが正直な答えになる場面もあります。
なぜ意味があるのか
土台にした研究も同じ方向を指しています。MyoGuide は表面筋電を使って脳卒中患者の手首伸展トレーニングをゲーム化し、麻痺した肢でも運動の意図を検出します。Pedro Lopes による固有感覚インタラクションと筋肉駆動のフォースフィードバックの研究はさらに踏み込み、身体を入力と出力の両方として扱います。共通しているのは、ゲームパッドに手を置けない状況でも、筋肉で動かすインターフェースなら成立しうるという点です。
ここでの狙いもそこにあります。4段階の力はコントローラーになります。指を必要としないコントローラーに。
詳細は From Muscle to Screen: A Comprehensive Tutorial on Integrating surface EMG Detection in game and using it like a game-controller(2023-24)にまとめてあります。Hugo Devoille の取得フレームワークの上に構築しました。
概览
表面肌电图测量的是肌肉收缩时产生的电活动。假肢领域在用它,康复和控制界面也在用。娱乐领域几乎没有,而仅有的一点研究也很少走出前臂。
于是我把问题问得更直接:一块肌肉,任何一块,能不能当游戏手柄? 要的是真手柄,映射到真实输入,玩那些从没为它设计过的游戏。
控制逻辑:四档力量
把肌肉当旋钮,而不是当按钮。收缩强度以玩家本人的最大值做归一化,再切成四档,每一档触发不同的输入。
| 发力(占你最大值的百分比) | 输入 |
|---|---|
| 0 – 25 % | input 1 |
| 25 – 50 % | input 2 |
| 50 – 75 % | input 3 |
| 75 – 100 % | input 4 |
一块肌肉,四个操作。加一个通道,词汇量就翻倍。
因此标定是按肌肉、按人来做的,绝不用固定电压。占你自己最大值的百分比,是唯一能在换手臂、换肌肉、换人之后依然成立的单位。


链路
- 采集。 一块 BITalino (r)evolution Plugged 板配 BioSignals 传感器套件,每块肌肉一个 EMG 模块、三枚电极:
IN+和IN−夹住肌腹,REF贴在骨头上。完整装配步骤写在 Body Shape Control Suit 页面,两个项目用的是同一套硬件。 - 记录。 用 OpenSignals 做串流和肉眼检查。你会在这里发现某个通道收到的是市电工频噪声,而不是二头肌。
- 处理。 Python 配 NumPy 和 SciPy:带通、整流、平滑,然后与标定过的最大值比对,落进四档中的一档。
- 输出。 各档作为手柄输入发出,走 Steam Input。正是最后这一步,把原型带出实验室,让它能在没人为它写过代码的游戏里工作。

桥梁:一边是 Python,一边是 Unity
Steam Input 负责的是商业游戏。我自己的 Unity 游戏需要更直接的通道,于是两半通过一个普通的 TCP 套接字对话。
Python 这一侧,BitalinoAcquisition.py 在 localhost:12345 上开一个服务器,只要有客户端连上,就按每次采样一个值、以逗号分隔的形式持续发送。Unity 这一侧,EMGData.cs 打开一个 TcpClient,在协程里读取数据流,好让游戏主循环永远不被阻塞,然后按逗号切分,并用 CultureInfo.InvariantCulture 解析每个数值——因为小数点符号一旦随机器区域设置改变,手柄会无声地失灵。
这道接缝在我的作品里反复出现。让 Python 分类器驱动 3D 场景的 Thoughts in Motion 是同一种形态,而 TRON 和 Chat-Room-API 里我又解了一遍同样的问题。一个进程掌握信号,另一个进程掌握显示,套接字承载两者之间的约定。
游戏
刻意分成三层,因为每一层检验的东西不同。
- Python 原型。 一个自制 Flappy Bird 作为训练关。一块肌肉、一个动作、即时反馈。玩家正是在这里搞清楚「自己力量的 40%」到底是什么感觉。
- Unity 的 2D 平台跳跃。 多个场景,移动和跳跃都靠肌肉输入。属于连续控制,所以档位边界必须稳,否则角色会抖。
- 真实的 Steam 游戏。 这才是真正的考验。游戏不配合,也没有特制版本。


评估流程
测试是按流程走的,不是临场发挥。
- 准备。 贴电极、标定、解释四个档位。
- 训练。 在自制 Flappy Bird 上自由玩,直到映射不再让人觉得随意。
- 测试。 用 EMG 手柄玩 Steam 游戏,观察上手难度、精准度和响应速度。
在 Festival of Learning 面向公众跑这套流程,是它最严苛的版本。陌生人、不同体型、没有调试时间。任何只在我自己前臂上成立的东西,几秒钟就现原形。
难点
- 是信号,不是数据。 滤波、抗噪和实时解读必须同时做对。错一样,手柄给人的感觉不是坏了,而是闹鬼。
- 映射是设计问题。 把 EMG 特征变成「用起来合理」的操作,迭代次数比信号处理本身还多。在图上看着干净的档位边界,实际保持起来可能非常累人。
- 标定会漂移。 肌肉活动随疲劳变化,电极位置随人变化,房间本身还会加噪。个人最大值能吸收掉很大一部分,但吸收不完,有时候中途重新标定才是诚实的答案。
为什么这件事重要
支撑它的研究都指向同一个方向。MyoGuide 用表面肌电把中风患者的腕伸展训练游戏化,即使在偏瘫肢体上也能检测运动意图。Pedro Lopes 关于本体感觉交互和肌肉驱动力反馈的工作走得更远,把身体同时当作输入和输出。共同点在于:在手放不上手柄的情况下,肌肉驱动的界面依然可能成立。
这也是这个项目的野心。四档力量就是一只手柄。一只不需要手指的手柄。
完整记录见 From Muscle to Screen: A Comprehensive Tutorial on Integrating surface EMG Detection in game and using it like a game-controller(2023-24)。构建于 Hugo Devoille 的采集框架之上。