Pengontrol Napas Arduino Terjangkau dengan Integrasi USB-MIDI
Komponen dan Perlengkapan
Arduino Micro
Anda mungkin bisa menurunkan biaya dengan klon tetapi saya merekomendasikan yang asli. Hanya Micro (ATmega32U4) yang akan bekerja karena kemampuan USB asli.
×
1
Solderless Breadboard Half Size
×
1
MPS20N0040D-D Pressure Sensor
Murah dan cukup mudah ditemukan.
×
1
LM358-N Op Amp
Kami akan menggunakan op amp LM358 populer untuk memperkuat sinyal sensor.
×
1
Resistor 1M ohm
×
2
Hook Up Wire Kit, 22 AWG
Anda tidak perlu kit lengkap tentu saja, hanya beberapa cm kawat inti padat.
×
1
Baby Nasal Aspirator
Ya, Anda membaca dengan benar. Kami akan menggunakan bucal sisi orang tua dan aspirator sisi bayi. Ada banyak aspirator manual jenis yang sama di sekitar (misalnya Physiomer Nasal Aspirator, Chicco Physioclean dll.). Pilih jenis bucal yang Anda temukan lebih nyaman.
×
1
5mm aquarium airline tubing
Opsional, jika tabung aspirator tidak cukup panjang. Tabung aquarium standar akan cukup.
×
1
3-way air tubing connector
Konektor OEM China spesifik ini dapat ditemukan dengan mudah di toko akuarium dengan nama yang berbeda. Ini cocok langsung pada sensor.
Dalam proyek ini kita akan membangun pengontrol napas USB MIDI plug-and-play sederhana. Ini dirancang menggunakan komponen murah yang mudah ditemukan sehingga total biaya tetap terjangkau dan jauh di bawah setara komersial. Ini adalah versi dasar yang hanya menggunakan sensor tekanan udara tetapi rencananya adalah untuk meningkatkannya untuk menyertakan sensor gigit dan nod/tilt di masa depan.
Proyek ini mengasumsikan pengetahuan elektronika dan Arduino yang sangat dasar tetapi bahkan pemula dapat membangunnya karena tidak ada pengelupan yang terlibat. Tentu saja pengguna yang lebih maju dapat menyelubungkan semuanya pada perma-protoboard. Saya tidak membahas instalasi IDE/library dan petunjuk untuk mengunggah kode karena ada tutorial yang luar biasa di internet.
Oversampling digunakan untuk menyelaraskan input sensor dengan hasil yang sangat baik. Anda juga dapat menyesuaikan rentang sesuai keinginan dan bahkan menyesuaikan kurva kustom untuk menyesuaikan perilaku pengontrol.
Karena sensor dapat mengukur tekanan negatif juga, ada aliran kedua pesan kontrol yang dihasilkan ketika Anda menarik udara daripada menghembuskan. Keduanya dapat diatur oleh pengguna. Misalnya Anda dapat mengatur hempusan untuk pitch bend up dan menarik untuk pitch bend down. Secara default keduanya diatur ke controller no. 2.
Langkah Membangun
1. Masukkan Arduino ke breadboard seperti yang ditunjukkan pada foto/skematik.
2. Masukkan sensor dan op amp ke posisi masing-masing, perhatikan orientasi berdasarkan indentation kecil di sisi mereka.
3. Masukkan resistor setelah memotong kaki mereka ke panjang yang sesuai.
4. Potong/strip kabel inti padat dan tempatkan di posisi masing-masing. Saya menggunakan merah untuk 5V, hitam untuk ground dan kuning untuk sinyal untuk membuat ini lebih mudah dipahami tetapi Anda tentu dapat menggunakan apa pun yang tersedia.
5. Hubungkan bucal, tabung, konektor 3-way dan aspirator seperti yang ditunjukkan pada foto. Anda akan perlu memotong sepotong tabung untuk "exhaust".
6. Tekan konektor 3-way sehingga sesuai pada sensor. Itu harus tetap tempat.
7. Instal Arduino IDE dan instal dua library yang diperlukan (Oversampling dan USB-MIDI) dari Tools->Manage Libraries. Hubungkan Arduino dengan kabel USB ke komputer Anda. Unggah kode yang dilampirkan.
8. Anda seharusnya siap, Arduino sekarang harus muncul sebagai perangkat MIDI di DAW/Music Software Anda. Aktifkan dan rute bersama keyboard Anda ke plug-in yang mendukung breath controller.
Info Lanjutan
Salah satu kekurangan fisik dari desain ini adalah ludah yang akan eviden mengalir di tabung dan dapat menyebabkan fluktuasi aliran udara yang terlihat. Konektor 3-way digunakan untuk mengatasi masalah ini dengan mengarahkan ludah ke tabung "exhaust". Untuk meminimalkan ludah yang terperangkap di tabung, pastikan ada kemiringan terus-menerus dari bucal ke konektor 3-way dengan menyesuaikan panjang tabung. Jika tabung tergantung di bawah tingkat konektor 3-way, ludah akan terperangkap di titik terendahnya yang menyebabkan fluktuasi. Bagian sisi bayi aspirator termasuk filternya dipasang di exhaust untuk meminimalkan titik serta kebisingan dan meningkatkan aliran udara ke sensor.
Dalam kode ada nilai yang dapat Anda sesuaikan sesuai keinginan, termasuk kurva kustom. Komentar menjelaskan cara melakukannya. Jika Anda merasa sulit mencapai titik 127 kurangi rentang maksimum, atau jika terlalu mudah, tingkatkan. Setiap kali Anda mengubah nilai, Anda perlu mengunggah ulang kode.
Beberapa pembacaan pertama setelah Arduino boot dirata-rata untuk mengkalibrasi posisi istirahat. Jangan hempuskan ke tabung saat menghubungkan/mereset perangkat.
Anda dapat mengubah nama perangkat MIDI dengan mengedit file boards.txt (info cara melakukannya untuk setiap platform tersedia di internet).
Kode
Kode pengontrol napas
Kode pengontrol napasArduino
Unggah kode ini ke pengontrol napas Anda melalui Arduino IDE
/* Breath Controller */ //Libraries used - install them from Tools->Manage Libraries #include <Oversampling.h> #include <USB-MIDI.h> //Debug mode (uncomment to enable) //#define DEBUG 1 //Creation of the USB MIDI interface USBMIDI_CREATE_DEFAULT_INSTANCE(); //Oversampling init Oversampling adc(10, 13, 6); // ***************** User Setup ***************** // Values ending in 1 correspond to blowing while those ending in 2 to drawing in air // Pin setup const int sensorPin1 = A0; // select the Arduino input pin for the Sensor/Op Amp output // Range Calibration. Adjust this manually so that you can reach maximum but not too easily. int sensorRange1 = 800; int sensorRange2 = 800; // Output controller number. Select from below table // 0-127: regular control change messages // 128: monophonic aftertouch // 129: Pitch Bend Up // 130: Pitch Bend Down int controllerNumber1 = 2; // Controller sent when blowing int controllerNumber2 = 2; // Controller sent when drawing in air // Output controller channels int controllerChannel1 = 1; int controllerChannel2 = 1; // Safety thresholds for lowest and highest values to avoid fluctuations when at rest or max. // If multiple messages are sent when at rest increase the lowThreshold. // If multiple messages are sent when at max increase the highThreshold. const int lowThreshold1 = 5; const int lowThreshold2 = 5; const int highThreshold1 = 0; const int highThreshold2 = 0; // Curve definition. Tables can have any legth equal or larger than 2. Values can be 0-127 . Tables should have the same number of elements and "in" tables should be in ascending order. // Conversions are done at a readings level so loss of definition is minimized. int in1[] = {0, 127}; int out1[] = {0, 127}; int in2[] = {0, 127}; int out2[] = {0, 127}; // Example curves (modify sensor number accordingly) //Soft //int in1[] = {0, 6,24,78,127}; //int out1[] = {0,32,64,96,127}; // Reduced range //int in1[] = {50, 100}; //int out1[] = {50, 100}; // Refresh Cycle (milliseconds). Lower values mean more messages are sent during operation. int refreshCycle = 0; // ***************** Implementation ***************** // Do not modify from this point and onward if you do not intent to alter the operation of the sensor. // Internal Value of Sensors int sensorValue1 = 0; int sensorValue2 = 0; // Minimum sensor values int sensorMin1; int sensorMin2; // Output controller values int controllerValue1 = 0; int controllerValue2 = 0; // Previous cycle values used to avoid repetition of identical messages int previousControllerValue1 = 0; int previousControllerValue2 = 0; // Range conversion variable init int outputRange1; int outputRange2; int sensorLow1; int sensorLow2; int sensorHigh1; int sensorHigh2; void setup() { MIDI.begin(1); #ifdef DEBUG Serial.begin (115200); //Only for debug mode #endif // Calibrate sensor's rest point by averaging 10 first values. Do not use the sensor while booting the device. sensorMin1 = adc.read(sensorPin1); sensorMin2 = 0; // Determine output ranges for the controllers chosen outputRange1 = outputRange(controllerNumber1); outputRange2 = outputRange(controllerNumber2); } void loop() { // read the value from the sensor: sensorValue1 = adc.read(sensorPin1); // Blowing air sensorValue2 = sensorMin1 - sensorValue1; // Drawing in air // Store previous values previousControllerValue1 = controllerValue1; previousControllerValue2 = controllerValue2; // Usable range limits for sensor up/down sensorLow1 = sensorMin1 + lowThreshold1; sensorLow2 = sensorMin2 + lowThreshold2; sensorHigh1 = sensorLow1 + sensorRange1 - highThreshold1; sensorHigh2 = min(sensorMin1,sensorRange2) - highThreshold2; // Convert internal values to output range (0..127 for controllers/aftertouch 0..+/-8191 for Pitchbend Up/Down) using the curves defined in "in" and "out" tables. controllerValue1 = map(mapToCurve(constrain(sensorValue1,sensorLow1,sensorHigh1),sensorLow1,sensorHigh1,in1,out1,sizeof(in1)/sizeof(int)),sensorLow1,sensorHigh1,0,outputRange1); controllerValue2 = map(mapToCurve(constrain(sensorValue2,sensorLow2,sensorHigh2),sensorLow2,sensorHigh2,in2,out2,sizeof(in2)/sizeof(int)),sensorLow2,sensorHigh2,0,outputRange2); // Send MIDI messages if (controllerValue1 != previousControllerValue1) sendSensorOutput(controllerNumber1, controllerValue1, controllerChannel1); if (controllerValue2 != previousControllerValue2) sendSensorOutput(controllerNumber2, controllerValue2, controllerChannel2); // Debug #ifdef DEBUG // Sensor (input) values (uncomment for debug) // Serial.print (sensorValue1); // Serial.print (","); // Serial.print (sensorValue2); // Serial.print (","); // Controller (output) values Serial.print (controllerValue1); Serial.print (","); Serial.println (controllerValue2); #endif // stop the program for for <refreshCycle> milliseconds: delay(refreshCycle); } // Function used to send MIDI messages according to controller number void sendSensorOutput (int number, int value, int channel) { if (number < 128) MIDI.sendControlChange(number, value, channel); else if (number == 128) MIDI.sendAfterTouch(value, channel); else if (number == 129) MIDI.sendPitchBend(value, channel); else if (number == 130) MIDI.sendPitchBend(-value, channel); } // Function used to determine the range of a specific controller. This is due to the fact pitch bend has a larger range than regular controllers. int outputRange (int number) { if (number > 128) return 8191; else return 127; } // Modified multiMap function used to create curves. Original by Rob Tillaart. int mapToCurve(int val, int sensorLow, int sensorHigh, int* _in, int* _out, uint8_t size) { // take care the value is within range // val = constrain(val, _in[0], _in[size-1]); if (val <= map(_in[0],0,127,sensorLow,sensorHigh)) return map(_out[0],0,127,sensorLow,sensorHigh); if (val >= map(_in[size-1],0,127,sensorLow,sensorHigh)) return map(_out[size-1],0,127,sensorLow,sensorHigh); // search right interval uint8_t pos = 1; // _in[0] already tested while(val > map(_in[pos],0,127,sensorLow,sensorHigh)) pos++; // adjusting range from ..127 to sensor range int inPos = map(_in[pos],0,127,sensorLow,sensorHigh); int outPos = map(_out[pos],0,127,sensorLow,sensorHigh); int inPrv = map(_in[pos-1],0,127,sensorLow,sensorHigh); int outPrv = map(_out[pos-1],0,127,sensorLow,sensorHigh); // this will handle all exact "points" in the _in array if (val == inPos) return outPos; // interpolate in the right segment for the rest return ((long)val - (long)inPrv) * ((long)outPos - (long)outPrv) / ((long)inPos - (long)inPrv) + (long)outPrv; }