[W] Własny kontroler MIDI, cz. 6 - kontroler żyroskopowy
Po wielu eksperymentach przyszedł wreszcie czas na złożenie czegoś "do kupy" i zrobienie kontrolera z prawdziwego zdarzenia, czyli nadającego się do normalnego użytku. Trwają ciągle prace nad "dużym" kontrolerem, zwłaszcza nad jego obudową, ale równolegle postanowiłem zbudować coś mniejszego a przydatnego.
Kontroler do machania
No, może nie do machania, ale do kręcenia nadgarstkiem. W części czwartej cyklu omawiałem różne czujniki reagujące na ruch ręki - pomiar odległości, akcelerometr czy żyroskop. Z tych wszystkich najbardziej spodobał mi się ostatni wariant, czyli czujnik żyroskopowy. Raz, że można kontrolować trzy parametry jednocześnie. Dwa, że można zamknąć czujnik w obudowie tak, by nic nie było wystawione na świat zewnętrzny. I trzy - prostota połączeń.
Nie wygląda może imponująco, ale działa, a to najważniejsze
Początkowo chciałem wykorzystać nie tylko trzy osie obrotu, ale i czujniki przyspieszenia, jednak próby z prototypem wykazały, że faktyczne wykorzystanie "machania" jest niepraktyczne. Zawsze dochodzi wówczas do zmian wartości obrotów, więc jeśli się obu tych zmian nie zgra w czasie i nie wykorzysta łącznie, całość traci sens.
Założenia
Choć początkowo chciałem czujnik zamknąć w malutkiej obudowie i np. nasunąć na palec, łącząc cienkim kabelkiem z większą obudową na biurku, ostatecznie stanęło jednak na małym pudełeczku do trzymania w dłoni, które zawiera w sobie i czujnik, i małą płytkę stykową, i Arduino. Dlaczego tak? Nie miałem odpowiedniego kabelka z czterema żyłami, poza tym chciałem uprościć konstrukcję - małe pudełeczko z kabelkiem USB jest poręczniejsze od pudełeczka na kablu, podłączonego do drugiego pudełeczka z kablem USB. Widoczny na zdjęciach biały przycisk służy do wywołania kalibracji podczas pracy.
Podłączenie
Wykorzystany czujnik MPU6050 jest o tyle wygodny, że wykorzystuje tylko dwa piny: SDA i SCL, podłączane do Arduino Pro Micro odpowiednio do pinów 2 i 3. Prócz tego wystarczy podpiąć zasilanie i masę:
Pełna amatorka - wykorzystałem po prostu płytkę stykową
Także program, korzystający z biblioteki MPU6050_light, jest stosunkowo prosty:
#include <MIDIUSB.h> #include <Wire.h> #include <MPU6050_light.h> const int CHANNEL = 0; const byte CC[] = {1, 3, 21, 22, 30, 31}; const bool ACTIVE[] = {true, true, true, false, false, false}; const int CAL_PIN = 9; int last[] = {0, 0, 0, 0, 0, 0}; MPU6050 mpu(Wire); unsigned long timer = 0; void setup() { Serial.begin(9600); Wire.begin(); pinMode(CAL_PIN, INPUT_PULLUP); byte status = mpu.begin(); while(status!=0){ } delay(1000); // mpu.upsideDownMounting = true; mpu.calcOffsets(); } void loop() { mpu.update(); if ((millis() - timer) > 10) { if (ACTIVE[0]) last[0] = midiValue(mpu.getAngleX(), CC[0], last[0]); if (ACTIVE[1]) last[1] = midiValue(mpu.getAngleY(), CC[1], last[1]); if (ACTIVE[2]) last[2] = midiValue(mpu.getAngleZ(), CC[2], last[2]); if (ACTIVE[3]) last[3] = midiValue(mpu.getAccX(), CC[3], last[3]); if (ACTIVE[4]) last[4] = midiValue(mpu.getAccY(), CC[4], last[4]); if (ACTIVE[5]) last[5] = midiValue(mpu.getAccZ(), CC[5], last[5]); timer = millis(); } if (digitalRead(CAL_PIN) == LOW) { mpu.calcOffsets(); delay(1000); } } void controlChange(byte cc, byte value) { midiEventPacket_t event = {0x0B, 0xB0 | CHANNEL, cc, value}; MidiUSB.sendMIDI(event); MidiUSB.flush(); } int midiValue(float value, byte cc, int last_value) { int tempValue = (int) value; if (tempValue < -100) { tempValue = -100; } else if (tempValue > 100) { tempValue = 100; } tempValue = map(tempValue, -100, 100, 0, 127); int diff = abs(last_value - tempValue); if (diff > 1) { controlChange(cc, tempValue); } return tempValue; }
Jak widać, w programie pozostał ślad po próbie skorzystania z czujnika akceleracji, ale ostatecznie te odczyty wyłączyłem. Obroty wokół osi X, Y i Z zostały na stałe przypisane do CC1, CC3 i CC21.
W metodzie midiValue(), która przekształca odczyt z czujnika w wartość zgodną z Continous Controller, zastosowałem pewien trik. Ogólnie czujniki obrotu dostarczają wartości w stopniach - od -180 stopni do +180 w przeciwnym kierunku. Nie planowałem aż tak mocno wyginać nadgarstka, stąd wartości mniejsze od -100 i większe od 100 są "obcinane", a zakres -100:100 jest konwertowany na 0:127. Dopiero taka wartość zostaje zamieniona na komunikat CC i wysłana.
Czy działa? Działa!
Muszę przyznać, że szczególnie we współpracy z syntezatorami kontroler jest nad wyraz przydatny. Operowanie za pomocą jednej dłoni aż trzema różnymi parametrami naprawdę jest przyjemne i dostarcza frajdy z samej gry. Na razie nie mam jeszcze pomysłu, jak można by połączyć obrót z ruchem, aby to jakoś kreatywnie wykorzystać, więc pozostaję przy żyroskopie.
Próbowałem wykorzystać posiadany drugi czujnik, ADXL345 (akcelerometr), ale prawdopodobnie mam uszkodzony egzemplarz, bo mimo starannego podłączenia, nie udało mi się zmusić go do pracy i dostarczenia jakichkolwiek odczytów.
Komentarze
Prześlij komentarz