Membuat Lampu Meja Reaktif Audio dengan Arduino Nano
Komponen dan Perlengkapan
Arduino Nano R3
×
1
Modul suara
×
1
Breadboard (umum)
×
1
Kawat Jumper (umum)
×
1
LED Addressable
×
1
Kaca IKEA DROPPAR
×
1
Pipa PVC kecil
×
1
Alat dan Mesin yang Diperlukan
Paku Solder (umum)
Aplikasi dan Layanan Online
Arduino IDE
Tentang Proyek Ini
HELLO WORLD!!
Halo! Dalam pembuatan ini kita akan membuat lampu yang menari dengan semua suara dan musik, menggunakan komponen sederhana dan beberapa pemrograman Arduino dasar. Ini membuat efek yang luar biasa saat berada di meja saat bermain game, memutar musik, dan segala hal lainnya yang membuat suara. Mari kita mulai!
Ini adalah proyek yang saya ikuti berdasarkan youtuber 'Natural Nerd' yang telah mereka lakukan. Ini adalah versi saya dari proyek ini. Semua kredit diberikan kepada mereka dan ucapan terima kasih besar kepada mereka karena memberikan saya detail cara melakukan proyek ini.
Youtube link
LANGKAH 1: PERLENGKAPAN UTAMA
Pertama-tama: perlengkapan apa yang kita butuhkan dan berapa biayanya? Nah, sebagian besar bersifat opsional dan dapat dibuat dengan banyak improvisasi. Meski begitu, beberapa item kunci diperlukan jika Anda ingin mengikuti panduan ini:
Arduino Nano (atau jenis Arduino kecil lainnya) (RM 12.50 buy link)
Modul Detektor Suara (RM 5.90 buy link)
Sumber daya 5 volt (atau 12 volt dengan Modul Stepdown)
Strip LED Addressable secara individual 60 leds per. meter (buy link)
Bergantung pada tampilan yang Anda inginkan, Anda mungkin ingin mengatur strip secara berbeda atau menyebarkan cahaya dengan cara lain. Di sinilah Anda dapat kreatif. Jika Anda suka pendekatan saya, saya menggunakan item berikut:
Kaca IKEA Droppar yang paling tinggi (IKEA Link)
Sebuah panjang kecil pipa PVC.
Foam Board
Pistol Lem Panas
Secara keseluruhan saya menghabiskan sekitar RM 83,30 bergantung pada toko tempat Anda membeli barang-barangnya, tempat strip LED adalah bagian yang paling mahal yang membiayai saya RM 40 untuk hanya 1 Meter.
LANGKAH 2: MEMENYALAKAN KOMPONEN
Penyalaan komponen akan menjadi metode yang sederhana. Saya hanya menggunakan kabel USB Arduino Nano dan langsung memasangnya ke PC. Jika Anda menggunakan sumber daya eksternal seperti sumber daya AC ke DC, Anda akan memerlukan modul step down untuk membantu Anda mengurangi jumlah arus yang mengalir ke rangkaian Anda. Jika tidak, jika Anda tidak menggunakannya dan Anda mungkin memiliki kesempatan yang sangat besar untuk membakar Arduino termasuk komponen yang terhubung.
Bintang pertunjukan adalah modul detektor suara. Ini akan memberikan sinyal analog ke Arduino, yang dapat kita gunakan untuk (semoga) secara cerdas menyala lampu RGB. Untuk dapat melakukan ini, kita perlu menyala kedua perangkat. Untungnya keduanya membutuhkan masukan 5 volt. Saya menggunakan modul step down untuk menurunkan dari 12 volt menjadi 5 volt, tetapi akan lebih mudah menggunakan sumber daya 5 volt secara langsung. Sambungkan VIN pada Arduino dan pada papan detektor suara ke masukan positif. Kemudian sambungkan GND pada Arduino dan detektor ke negatif. Lihat kabel hitam dan merah pada skema yang dilampirkan. Kita juga perlu menghubungkan masukan positif dan negatif pada strip LED ke sumber daya.
LANGKAH 3: DETEKTOR & STRIP
Setelah menghubungkan ketiga bagian ke sumber daya, kita perlu menghubungkannya satu sama lain.
Modul detektor suara akan berkomunikasi dengan Arduino melalui pin masukan analog. Saya akan menggunakan nomor pin 0 dalam hal ini.
Strip LED memerlukan pulsa digital untuk dapat memahami LED mana yang ingin kita alamatkan. Oleh karena itu kita perlu menghubungkan pin keluaran digital ke Arduino nano. Saya akan menggunakan nomor pin 6.
Gunakan tabut pengecil pada area yang dipilih sehingga kabel tidak akan bentrok satu sama lain dalam ruang sempit nanti.
Hanya ikuti diagram skematik yang saya sediakan di sini dan Anda akan baik-baik saja!
Luarbiasa, sekarang kita sebagian besar selesai dengan elektronika!
LANGKAH 4: MENGUNGGAH KODE
Bagian terpenting dari pembuatan ini akan arguably adalah kode. Ini dapat mengubah pembuatan ini dari cukup keren menjadi sangat luar biasa. Anda dapat menggunakan kode yang saya sediakan bersama dengan proyek ini. Prinsip utamanya adalah memetakan nilai analog yang kita dapatkan dari sensor, ke jumlah LED yang akan ditampilkan.
LANGKAH 5: MENYIAPKAN KOTAK
Pertama saya pikir tutup terbuat dari akrilik, setelah saya membeli kaca dan menyadari itu bukan akrilik tapi kaca. Jadi saya perlu menyesuaikan rencana saya dengan membuat tutup yang mudah ditusuk dan memasang Arduino dan LED. Jadi saya memilih foam board.
Langkah pertama, saya perlu memotong foam board agar berbentuk lingkaran tepat dan memiliki diameter yang sama dengan tutup kaca kaca. Saya tidak memiliki alat pengukur diameter yang tepat, jadi saya mengimprovisasi metode dengan menggunakan pen marker basah dan menandai diameter kaca dan mencetaknya pada potongan kertas. Setelah itu, saya menempelkan kertas pada foam board dan memotong papan dengan mengikuti tepi lingkaran pada kertas. Ini tidak sempurna tetapi seharusnya cukup baik untuk menahan semua komponen Arduino dan LED.
Langkah kedua, saya perlu memecahkan kaca pada tutup kaca. PERINGATAN! tutup kaca dengan kantong plastik tebal untuk mencegah kaca terpucur di sekitar kamar dan lakukan di ruang terbuka. Waspadalah dengan lingkungan Anda. Setelah memecahkan kaca, pastikan semua kaca yang menempel di sisi retakan tutup kaca dihapus. Ini untuk mencegah Anda atau orang lain dari cedera karena teriris oleh kaca yang menempel.
Langkah ketiga, tempatkan foam board berbentuk lingkaran di tengah tutup kaca. Pastikan foam rapat dan tidak terlupa sehingga pas dengan kaca.
Langkah keempat, saya baru saja sadar bahwa saya perlu mengubah tata letak proyek ini. Saya ingin membuat pengguna mudah untuk mengakses komponen Arduino dalam hal kerusakan. Jadi, saya memutuskan untuk menggunakan mini breadboard dan menempatkannya di tengah tutup. Tidak hanya itu, saya membuat dua lubang untuk kabel dari Modul Suara yang akan saya tempatkan di bawah tutup kaca untuk pergi ke dalam kaca dan ke breadboard dan satu lubang lagi untuk Arduino untuk terhubung dengan kabel USB untuk bertindak sebagai sumber daya untuk rangkaian.
Langkah kelima, Saya menandai pipa PVC dengan masking tape dan menggambar garis di tengah pita. Kemudian, saya melemparnya di pipa PVC. Tanda-tanda adalah indikator bagi saya untuk memotong pipa PVC merata dan mencoba untuk mendapatkan potongan yang rapi.
Setelah mengukur jumlah panjang pipa PVC yang saya butuhkan, saya memotongnya dengan hati-hati dengan mengikuti tanda yang saya berikan. Panjang pipa PVC bergantung pada tinggi kaca. Anda dapat menggunakan panjang apa pun yang Anda inginkan.
Langkah keenam, saya membungkus pipa PVC yang saya potong dengan strip LED di sekitarnya dan membuatnya sedikit miring dan berputar spiral ke atas pipa PVC. Saya memastikan bahwa saya membuat lubang kecil untuk panjang kabel berlebihan yang dapat disembunyikan di dalam kaca PVC untuk manajemen kabel. Kemudian saya perlu mencari cara untuk menempatkan pipa PVC di atas breadboard. Menggunakan pistol lem panas atau lem double sided, saya mampu menempelkan pipa PVC pada foam board tambahan lalu menempelkannya pada area yang tidak terpakai di breadboard. Selama langkah ini, saya mampu menghubungkan beberapa komponen ke breadboard.
Gunakan diagram skematik yang disediakan untuk menghubungkan semua komponen.
(Area kiri breadboard akan menjadi positif dan area kanan breadboard akan menjadi negatif. `
Langkah ketujuh, saya menempatkan modul suara di luar tutup kaca. Ini dilakukan sengaja agar modul mudah menangkap suara di luar kaca nanti. Setelah menempatkan modul, hubungkan dengan kabel dan cocokkan seperti yang dinyatakan dalam diagram skematik yang diberikan. Kemudian, hubungkan semua kabel dengan sensor dan Arduino ke breadboard. Arduino diatur secara vertikal sehingga kabel untuk menyala rangkaian dapat terhubung dengan papan Arduino dengan mudah melalui foam board.
Dan demikianlah, saya menyelesaikan proyek ini. Ini memakan waktu serta dengan percobaan dan kesalahan tetapi saya berhasil menyelesaikannya.
Kode
Koding Untuk Arduino
Koding Untuk ArduinoArduino
Kode ini akan mengaktifkan LED untuk bereaksi terhadap suara yang terdeteksi oleh modul suara.
#include <FastLED.h> /** BASIC CONFIGURATION **/ //The amount of LEDs in the setup #define NUM_LEDS 60 //The pin that controls the LEDs #define LED_PIN 6 //The pin that we read sensor values form #define ANALOG_READ 0 //Confirmed microphone low value, and max value #define MIC_LOW 0.0 #define MIC_HIGH 200.0 /** Other macros */ //How many previous sensor values effects the operating average? #define AVGLEN 5 //How many previous sensor values decides if we are on a peak/HIGH (e.g. in a song) #define LONG_SECTOR 20 //Mneumonics #define HIGH 3 #define NORMAL 2 //How long do we keep the "current average" sound, before restarting the measuring #define MSECS 30 * 1000 #define CYCLES MSECS / DELAY /*Sometimes readings are wrong or strange. How much is a reading allowed to deviate from the average to not be discarded? **/ #define DEV_THRESH 0.8 //Arduino loop delay #define DELAY 1 float fscale( float originalMin, float originalMax, float newBegin, float newEnd, float inputValue, float curve); void insert(int val, int *avgs, int len); int compute_average(int *avgs, int len); void visualize_music(); //How many LEDs to we display int curshow = NUM_LEDS; /*Not really used yet. Thought to be able to switch between sound reactive mode, and general gradient pulsing/static color*/ int mode = 0; //Showing different colors based on the mode. int songmode = NORMAL; //Average sound measurement the last CYCLES unsigned long song_avg; //The amount of iterations since the song_avg was reset int iter = 0; //The speed the LEDs fade to black if not relit float fade_scale = 1.2; //Led array CRGB leds[NUM_LEDS]; /*Short sound avg used to "normalize" the input values. We use the short average instead of using the sensor input directly */ int avgs[AVGLEN] = {-1}; //Longer sound avg int long_avg[LONG_SECTOR] = {-1}; //Keeping track how often, and how long times we hit a certain mode struct time_keeping { unsigned long times_start; short times; }; //How much to increment or decrement each color every cycle struct color { int r; int g; int b; }; struct time_keeping high; struct color Color; void setup() { Serial.begin(9600); //Set all lights to make sure all are working as expected FastLED.addLeds<NEOPIXEL, LED_PIN>(leds, NUM_LEDS); for (int i = 0; i < NUM_LEDS; i++) leds[i] = CRGB(0, 0, 255); FastLED.show(); delay(1000); //bootstrap average with some low values for (int i = 0; i < AVGLEN; i++) { insert(250, avgs, AVGLEN); } //Initial values high.times = 0; high.times_start = millis(); Color.r = 0; Color.g = 0; Color.b = 1; } /*With this we can change the mode if we want to implement a general lamp feature, with for instance general pulsing. Maybe if the sound is low for a while? */ void loop() { switch(mode) { case 0: visualize_music(); break; default: break; } delay(DELAY); // delay in between reads for stability } /**Funtion to check if the lamp should either enter a HIGH mode, or revert to NORMAL if already in HIGH. If the sensors report values that are higher than 1.1 times the average values, and this has happened more than 30 times the last few milliseconds, it will enter HIGH mode. TODO: Not very well written, remove hardcoded values, and make it more reusable and configurable. */ void check_high(int avg) { if (avg > (song_avg/iter * 1.1)) { if (high.times != 0) { if (millis() - high.times_start > 200.0) { high.times = 0; songmode = NORMAL; } else { high.times_start = millis(); high.times++; } } else { high.times++; high.times_start = millis(); } } if (high.times > 30 && millis() - high.times_start < 50.0) songmode = HIGH; else if (millis() - high.times_start > 200) { high.times = 0; songmode = NORMAL; } } //Main function for visualizing the sounds in the lamp void visualize_music() { int sensor_value, mapped, avg, longavg; //Actual sensor value sensor_value = analogRead(ANALOG_READ); //If 0, discard immediately. Probably not right and save CPU. if (sensor_value == 0) return; //Discard readings that deviates too much from the past avg. mapped = (float)fscale(MIC_LOW, MIC_HIGH, MIC_LOW, (float)MIC_HIGH, (float)sensor_value, 2.0); avg = compute_average(avgs, AVGLEN); if (((avg - mapped) > avg*DEV_THRESH)) //|| ((avg - mapped) < -avg*DEV_THRESH)) return; //Insert new avg. values insert(mapped, avgs, AVGLEN); insert(avg, long_avg, LONG_SECTOR); //Compute the "song average" sensor value song_avg += avg; iter++; if (iter > CYCLES) { song_avg = song_avg / iter; iter = 1; } longavg = compute_average(long_avg, LONG_SECTOR); //Check if we enter HIGH mode check_high(longavg); if (songmode == HIGH) { fade_scale = 3; Color.r = 5; Color.g = 3; Color.b = -1; } else if (songmode == NORMAL) { fade_scale = 2; Color.r = -1; Color.b = 2; Color.g = 1; } //Decides how many of the LEDs will be lit curshow = fscale(MIC_LOW, MIC_HIGH, 0.0, (float)NUM_LEDS, (float)avg, -1); /*Set the different leds. Control for too high and too low values. Fun thing to try: Dont account for overflow in one direction, some interesting light effects appear! */ for (int i = 0; i < NUM_LEDS; i++) //The leds we want to show if (i < curshow) { if (leds[i].r + Color.r > 255) leds[i].r = 255; else if (leds[i].r + Color.r < 0) leds[i].r = 0; else leds[i].r = leds[i].r + Color.r; if (leds[i].g + Color.g > 255) leds[i].g = 255; else if (leds[i].g + Color.g < 0) leds[i].g = 0; else leds[i].g = leds[i].g + Color.g; if (leds[i].b + Color.b > 255) leds[i].b = 255; else if (leds[i].b + Color.b < 0) leds[i].b = 0; else leds[i].b = leds[i].b + Color.b; //All the other LEDs begin their fading journey to eventual total darkness } else { leds[i] = CRGB(leds[i].r/fade_scale, leds[i].g/fade_scale, leds[i].b/fade_scale); } FastLED.show(); } //Compute average of a int array, given the starting pointer and the length int compute_average(int *avgs, int len) { int sum = 0; for (int i = 0; i < len; i++) sum += avgs[i]; return (int)(sum / len); } //Insert a value into an array, and shift it down removing //the first value if array already full void insert(int val, int *avgs, int len) { for (int i = 0; i < len; i++) { if (avgs[i] == -1) { avgs[i] = val; return; } } for (int i = 1; i < len; i++) { avgs[i - 1] = avgs[i]; } avgs[len - 1] = val; } //Function imported from the arduino website. //Basically map, but with a curve on the scale (can be non-uniform). float fscale( float originalMin, float originalMax, float newBegin, float newEnd, float inputValue, float curve){ float OriginalRange = 0; float NewRange = 0; float zeroRefCurVal = 0; float normalizedCurVal = 0; float rangedValue = 0; boolean invFlag = 0; // condition curve parameter // limit range if (curve > 10) curve = 10; if (curve < -10) curve = -10; curve = (curve * -.1) ; // - invert and scale - this seems more intuitive - postive numbers give more weight to high end on output curve = pow(10, curve); // convert linear scale into lograthimic exponent for other pow function // Check for out of range inputValues if (inputValue < originalMin) { inputValue = originalMin; } if (inputValue > originalMax) { inputValue = originalMax; } // Zero Refference the values OriginalRange = originalMax - originalMin; if (newEnd > newBegin){ NewRange = newEnd - newBegin; } else { NewRange = newBegin - newEnd; invFlag = 1; } zeroRefCurVal = inputValue - originalMin; normalizedCurVal = zeroRefCurVal / OriginalRange; // normalize to 0 - 1 float // Check for originalMin > originalMax - the math for all other cases i.e. negative numbers seems to work out fine if (originalMin > originalMax ) { return 0; } if (invFlag == 0){ rangedValue = (pow(normalizedCurVal, curve) * NewRange) + newBegin; } else // invert the ranges { rangedValue = newBegin - (pow(normalizedCurVal, curve) * NewRange); } return rangedValue; }