
Interaktywna rękawica MIDI oparta na Arduino reaguje na zginanie palców i odtwarza dźwięki: w wersji pierwszej za pomocą buzzera, w wersji drugiej – poprzez sygnały MIDI USB do programu DAW. Projekt łączy przetwarzanie sygnałów analogowych z cyfrową kontrolą dźwięku.
1. Arduino UNO
2. Buzzer
3. Arduino Pro Micro (ATmega32u4)
4. Rękawiczka do sterowania programem:
- Rezystancyjne czujniki zgięcia
- Rękawiczka
- Przewody
5. Breadboard
6. Przewody połączeniowe
7. Kabel microUSB
Komputer z DAW (np. FL Studio)
Projekt zakładał wykonanie rękawicy z czujnikami zgięcia palców oraz zaprogramowanie reakcji dźwiękowej w zależności od stopnia ich ugięcia. W ramach pracy powstały dwie wersje funkcjonalne:
Wersja 1: Arduino Uno + buzzer
Pierwszy etap polegał na stworzeniu analogowego sterownika dźwięku. Czujnik zgięcia, zamontowany na palcu, działał jako zmienny rezystor, który wraz z rezystorem stałym tworzył dzielnik napięcia. Sygnał z dzielnika był odczytywany przez wejście analogowe Arduino Uno. Program analizował poziom napięcia i zależnie od wartości generował określoną częstotliwość dźwięku przy pomocy funkcji tone(). Zastosowano cztery przedziały napięcia odpowiadające czterem różnym dźwiękom (np. C-D-E-F), a pełne wyprostowanie lub zgięcie palca powodowało ciszę (noTone()). W kolejnej wersji dodano warunek: po przekroczeniu progu 800, wcześniejsze przedziały zaczęły grać inne nuty (np. G-A-H-C5), co symulowało zmianę trybu. Projekt pozwalał na brzęczenie dźwiękiem w czasie rzeczywistym.
Wersja 2: Arduino Pro Micro + MIDI USB
Druga część projektu bazowała na bardziej profesjonalnym podejściu. Arduino Pro Micro zostało wykorzystane ze względu na obsługę interfejsu USB-MIDI bezpośrednio przez port USB. Zastosowano dwa czujniki zgięcia: pierwszy palec decydował o wyborze nuty, a drugi - o jej odtwarzaniu. Próg zgięcia drugiego palca pełnił rolę „klawisza gry”, umożliwiając sterowanie rytmem, podczas gdy pierwszy działał jak przełącznik tonów. Zakresy zgięcia były mapowane do wartości MIDI (np. 60 – C4, 62 – D4, 64 – E4 itp.). Przy pełnym wyprostowaniu żadna nuta nie była odtwarzana (wysyłano Note Off).
Sygnały MIDI wysyłane były do programu DAW, gdzie mogły sterować dowolnym wirtualnym instrumentem. Dzięki użyciu biblioteki MIDIUSB.h, projekt mógł działać bez dodatkowych sterowników. Upload programu wymagał odpowiedniego czasu zwarcia pinów RST i GND w celu aktywacji bootloadera. Kod uwzględniał dynamiczne przypisywanie nut, a także możliwość zmiany trybu po przekroczeniu ustalonego progu zgięcia.
Efekty i wyniki:
Obie wersje projektu spełniły swoje założenia. Wersja buzzerowa umożliwiła szybkie prototypowanie i testowanie reakcji czujnika, natomiast wersja MIDI otworzyła drogę do integracji z profesjonalnym oprogramowaniem muzycznym. Projekt pozwala zrozumieć zarówno elektronikę analogową (dzielniki napięcia, PWM), jak i cyfrową komunikację MIDI. Daje solidną bazę do dalszego rozwoju: dodanie czujników na więcej palców, zaprogramowanie trybów instrumentów, odtwarzanie akordów lub sekwencji rytmicznych. Rękawica MIDI pokazuje, jak w prosty sposób można przekształcić ruch ręki w ekspresję muzyczną i jest dobrym przykładem połączenia inżynierii z kreatywnością.


#include <MIDIUSB.h> const byte PIN_SEL = A0; const byte PIN_TRG = A1; const int SEL_MAX = 760; const int SEL_MIN = 550; const int TRG_MIN = 720; const int TRG_MAX = 530; const byte ON_PCT = 60; const byte OFF_PCT = 40; const float EMA = 0.20; const byte SCALE[] = {60, 62, 64, 65, 67, 69, 71}; const byte N_SCALE = sizeof(SCALE); float fSel = SEL_MAX; float fTrg = TRG_MIN; byte curNote = 255; bool playing = false; inline void noteOn(byte n, byte v) { MidiUSB.sendMIDI({0x09, 0x90, n, v}); MidiUSB.flush(); } inline void noteOff(byte n) { MidiUSB.sendMIDI({0x08, 0x80, n, 0}); MidiUSB.flush(); } void setup() { pinMode(PIN_SEL, INPUT); pinMode(PIN_TRG, INPUT); Serial.begin(115200); } void loop() { fSel = EMA * analogRead(PIN_SEL) + (1 - EMA) * fSel; fTrg = EMA * analogRead(PIN_TRG) + (1 - EMA) * fTrg; float relSel = constrain(fSel - SEL_MIN, 0, SEL_MAX - SEL_MIN) / float(SEL_MAX - SEL_MIN); byte idx = relSel * N_SCALE; if (idx >= N_SCALE) idx = N_SCALE - 1; byte note = SCALE[idx]; int spanTrg = TRG_MIN - TRG_MAX; int onThr = TRG_MIN - spanTrg * ON_PCT / 100; int offThr = TRG_MIN - spanTrg * OFF_PCT / 100; bool bent = fTrg < onThr; bool flat = fTrg > offThr; static float fPrev = fTrg; static unsigned long tPrev = millis(); unsigned long now = millis(); if (bent && !playing) { float speed = abs(fTrg - fPrev) / (now - tPrev + 1); byte vel = constrain(speed * 3000, 1, 127); noteOn(note, vel); curNote = note; playing = true; } else if (flat && playing) { noteOff(curNote); playing = false; } fPrev = fTrg; tPrev = now; delay(4); }