Bertahun-tahun yang lalu, Yamaha memperkenalkan piano otomatis. Saya yang masih muda dan polos melihat piano itu memainkan musik di balik jendela kaca sebuah toko instrumen.
Cukup obrolan ringan, sebenarnya tidak ada alasan besar mengapa saya memulai proyek ini selain saya hanya ingin.
Satu papan Arduino Mega berharga sekitar $40 dan dua akan diperlukan untuk mengontrol 88 solenoida. Itu cukup mahal. Sebagai gantinya, dapatkan Arduino Uno murah dan 11 shift-register. Shift Register adalah metode untuk mengontrol banyak output (biasanya LED) dengan jumlah pin output yang sedikit. Pada dasarnya, ini adalah satu Arduino dengan 11 register geser dan mengontrol 88 Solenoid.
Karena kita menggunakan register Shift, PC akan mengirim satu set bit ke Arduino, bukan MIDI com. File MIDI akan diterjemahkan ke dalam set bit sebelumnya.
Ketika saya mendapatkan solenoida langsung dari China, saya menemukan bahwa solenoida ini tidak cukup kuat untuk menekan tuts piano. Tentu saja menekan tuts piano dari bagian paling dalam membutuhkan lebih banyak tenaga, tetapi saya pikir itu adalah metode terbaik yang tidak merusak piano. Akhirnya saya mendorong 24V melalui solenoida 12V untuk mendapatkan daya yang cukup.
88 Solenoid menghabiskan banyak daya dan karena saya tidak dapat membeli PSU yang mahal, saya memutuskan untuk menggunakan aki mobil ayah saya. (Kurasa dia tidak akan pergi kemana-mana sekarang!)
Tanpa itu, masing-masing register geser dan MOSFET akan masuk ke papan pengontrol.
595 di sebelah kanan dengan soket jika saya membakarnya. (Yang saya lakukan sekali.) Diagram Sirkuit persis sama dengan contoh 2 dari sini. Ganti LED dengan gerbang MOSFET. Seperti yang Anda lihat, tidak ada resistor tarik karena resistor tambahan akan menaikkan biaya dan menyoldernya di papan itu akan melelehkan jari saya. Di sisi yang sedikit lebih serius, MOSFET ini akan terbuka pada 5V dan menutup di bawah 4V atau lebih. Mengkonfirmasinya melalui pengujian selama berjam-jam. (Secara teori tidak benar. Jangan dengarkan saya.)
Terakhir, ambil sepotong piring plastik untuk merekatkan solenoida. Menggunakan lem panas dan piring plastik adalah ide yang buruk mengingat akan menjadi panas, tapi itu yang terbaik yang saya mampu.
Dan kemudian jalankan satu sisi kabel solenoida ke sisi positif baterai.
Langkah pertama adalah mendapatkan file midi.
Langkah kedua adalah memasukkan midi ke dalam bentuk teks. Ini dapat dilakukan di situs web praktis ini:http://flashmusicgames.com/midi/mid2txt.php.
Demi kesederhanaan, abaikan tanda waktu, tempo, dan par. Tempo bisa dikalikan dengan waktu nanti. Pada dasarnya Anda menginginkan file seperti ini:
Sekarang, gunakan ini untuk membuat 11 set data 8 bit dengan waktu dengan menjalankannya melalui kode Python (terlampir).
Mereka siap dikirim ke Arduino melalui pemrosesan COM.
Lihat lampiran untuk mengetahui bagaimana pemrosesan mengirimkan data ini dan bagaimana Arduino menanganinya.
*Catatan:Kebiasaan pengkodean saya buruk dan mungkin sulit untuk membacanya. Pemrosesan mengirimkan data dari kanan ke kiri karena Arduino mendorong data ke kanan pada piano fisik.
Jika seorang insinyur profesional melihat posting ini, dia akan berpikir bahwa seluruh sistem ini akan memiliki banyak masalah. Dan ada banyak masalah.
Karena solenoida panas terpaku pada pelat, solenoida terlalu panas dan melelehnya lem panas adalah masalah besar. Solusinya adalah dengan melepasnya dan menggantinya dengan selotip dua sisi yang dapat bertahan hingga 150C.
Kode
- Kode Python untuk terjemahan
- Memproses pengiriman data ke arduino
- Kode Arduino
Kode Python untuk terjemahanPython
Mengambil file mifi teks dan menerjemahkannya ke 11 set biner untuk arduino untuk mengambilnya.output_file =open("translated.txt", "w")input_file =open("megalocania.txt")raw_input_data =input_file.read ()work_data =raw_input_data.splitlines()result =[]#output_file =open("result.txt", "w")def main():untuk a di work_data:temp_time =time_finder(a) if result ==[] :result.append(str(temp_time) + ",") if on_off_finder(a):result[-1] +=set_bit(True, note_finder(a)) elif not on_off_finder(a):result[-1] +=set_bit(Benar, note_finder(a)) elif time_finder_comm(result[-1]) ==temp_time:result[-1] =str(temp_time) + "," + set_bit_prev(on_off_finder(a), note_finder(a), - 1) elif time_finder_comm(result[-1]) !=temp_time:result.append(str(temp_time) + "," + set_bit_prev(on_off_finder(a), note_finder(a), -1)) untuk b dalam hasil:output_file .write(b) output_file.write("\n") output_file.close() def set_bit(On, note):#Mengambil boolean apakah aktif atau tidak, dan catat nomornya. #Menghasilkan bit if(note>=21 dan note <=28 and On):return str(2**(note - 21)) + ",0,0,0,0,0,0,0,0,0 ,0" elif(catatan>=29 dan catatan <=36 dan Aktif):return "0," + str(2**(catatan - 29)) + ",0,0,0,0,0,0, 0,0,0" elif(catatan>=37 dan catatan <=44 dan Aktif):return "0,0," + str(2**(catatan - 37)) + ",0,0,0,0 ,0,0,0,0" elif(catatan>=45 dan catatan <=52 dan Aktif):return "0,0,0," + str(2**(catatan - 45)) + ",0, 0,0,0,0,0,0" elif(catatan>=53 dan catatan <=60 dan Aktif):return "0,0,0,0," + str(2**(catatan - 53)) + ",0,0,0,0,0,0" elif(catatan>=61 dan catatan <=68 dan Aktif):return "0,0,0,0,0" + str(2**( catatan - 61)) + ",0,0,0,0,0" elif(catatan>=69 dan catatan <=76 dan Aktif):return "0,0,0,0,0,0,," + str (2**(catatan - 69)) + ",0,0,0,0" elif(catatan>=77 dan catatan <=84 dan Aktif):return "0,0,0,0,0,0, 0," + str(2**(catatan - 77)) + ",0,0,0" elif(catatan>=85 dan catatan <=92 dan Aktif):return "0,0,0,0,0 ,0,0,0," + str(2**(catatan - 85)) + ",0,0" elif(catatan>=93 dan catatan <=100 dan Aktif):return "0,0,0, 0,0,0,0,0,0," + str(2**(catatan - 93)) + ",0" elif(catatan>=101 dan note <=108 and On):return "0,0,0,0,0,0,0,0,0,0," + str(2**(note - 101)) else:return "0,0 ,0,0,0,0,0,0,0,0,0"def set_bit_prev(On, note, index):#Sama seperti set_bit tapi sebelumnya sadar temp =result[index] temp =temp[(temp.find (",") + 1):] if(note>=21 dan note <=28):local_temp =temp[0:temp.find(",")] if(On):return str(int(local_temp) + (2**(catatan - 21))) + temp[temp.find(","):] if(not On):return str(int(local_temp) - (2**(catatan - 21))) + temp[temp.find(","):] elif(catatan>=29 dan catatan <=36):local_temp =temp[(temp.find(",") + 1):indexTh(temp, "," , 2)] if(On):return temp[0:temp.find(",") + 1] + str(int(local_temp) + (2**(note - 29))) + temp[indexTh(temp , ",", 2):] if(not On):return temp[0:temp.find(",") + 1] + str(int(local_temp) - (2**(catatan - 29))) + temp[indexTh(temp, ",", 2):] elif(note>=37 dan note <=44):local_temp =temp[(indexTh(temp, ",", 2) + 1):indexTh(temp , ",", 3)] if(On):return temp[0:indexTh(temp, ",", 2) + 1] + str(int(local_temp) + (2**(note - 37))) + suhu[dalam dexTh(temp, ",", 3):] if(not On):return temp[0:indexTh(temp, ",", 2) + 1] + str(int(local_temp) - (2**(catatan - 37))) + temp[indexTh(temp, ",", 3):] elif(note>=45 dan note <=52):local_temp =temp[(indexTh(temp, ",", 3) + 1 ):indexTh(temp, ",", 4)] if(On):return temp[0:indexTh(temp, ",", 3) + 1] + str(int(local_temp) + (2**(catatan - 45))) + temp[indexTh(temp, ",", 4):] if(not On):return temp[0:indexTh(temp, ",", 3) + 1] + str(int(local_temp ) - (2**(catatan - 45))) + temp[indexTh(temp, ",", 4):] elif(note>=53 dan note <=60):local_temp =temp[(indexTh(temp, ",", 4) + 1):indexTh(temp, ",", 5)] if(On):return temp[0:indexTh(temp, ",", 4) + 1] + str(int(local_temp ) + (2**(catatan - 53))) + temp[indexTh(temp, ",", 5):] if(not On):return temp[0:indexTh(temp, ",", 4) + 1] + str(int(local_temp) - (2**(catatan - 53))) + temp[indexTh(temp, ",", 5):] elif(catatan>=61 dan catatan <=68):local_temp =temp[(indexTh(temp, ",", 5) + 1):indexTh(temp, ",", 6)] if(On):return temp[0:indexTh(temp, ",", 5) + 1 ] + str(int(local_temp) + (2**(catatan - 61))) + temp[indexTh(temp, ",", 6):] if(not On):return temp[0:indexTh(temp, ",", 5) + 1] + str(int(local_temp) - (2**(note - 61))) + temp[indexTh(temp, ",", 6):] elif(note>=69 and catatan <=76):local_temp =temp[(indexTh(temp, ",", 6) + 1):indexTh(temp, ",", 7)] if(On):return temp[0:indexTh(temp, ",", 6) + 1] + str(int(local_temp) + (2**(note - 69))) + temp[indexTh(temp, ",", 7):] if(not On):return temp[0:indexTh(temp, ",", 6) + 1] + str(int(local_temp) - (2**(note - 69))) + temp[indexTh(temp, ",", 7):] elif(catatan>=77 dan catatan <=84):local_temp =temp[(indexTh(temp, ",", 7) + 1):indexTh(temp, ",", 8)] if(On):return temp[0:indexTh(temp, ",", 7) + 1] + str(int(local_temp) + (2**(catatan - 77))) + temp[indexTh(temp, ",", 8):] if(not On):return temp[0:indexTh(temp, ",", 7) + 1] + str(int(local_temp) - (2**(note - 77))) + temp[indexTh(temp , ",", 8):] elif(catatan>=85 dan catatan <=92):#error here local_temp =temp[(indexTh(temp, ",", 8) + 1):indexT h(temp, ",", 9)] if(On):return temp[0:indexTh(temp, ",", 8) + 1] + str(int(local_temp) + (2**(catatan - 85 ))) + temp[indexTh(temp, ",", 9):] if(not On):return temp[0:indexTh(temp, ",", 8) + 1] + str(int(local_temp) - (2**(catatan - 85))) + temp[indexTh(temp, ",", 9):] elif(note>=93 dan note <=100):local_temp =temp[(indexTh(temp, ", ", 9) + 1):indexTh(temp, ",", 10)] if(On):return temp[0:indexTh(temp, ",", 9) + 1] + str(int(local_temp) + (2**(catatan - 93))) + temp[indexTh(temp, ",", 10):] if(not On):return temp[0:indexTh(temp, ",", 9) + 1] + str(int(local_temp) - (2**(note - 93))) + temp[indexTh(temp, ",", 10):] elif(note>=101 and note <=108):local_temp =temp [(indexTh(temp, ",", 10) + 1):] if(On):return temp[0:indexTh(temp, ",", 10) + 1] + str(int(local_temp) + (2 **(catatan - 101))) if(not On):return temp[0:indexTh(temp, ",", 10) + 1] + str(int(local_temp) - (2**(catatan - 101) )) def indexTh(in_string, find_this, th):#Mengambil String, string untuk ditemukan, dan urutan untuk menemukan string untuk ditemukan di urutan itu #mengembalikan urutan indeks =1 indeks_terakhir =0 while(True):temp =in_string.find(find_this, last_index) if(temp ==-1):return -1 if(order ==th):return temp order + =1 last_index =temp + 1def time_finder(in_string):#Mengambil string dan menemukan waktu, mengembalikannya sebagai int time_end =in_string.index(" ") return int(in_string[0:time_end])def time_finder_comm(in_string):#Mengambil string dan menemukan waktu, mengembalikannya sebagai int koma time_end =in_string.index(",") return int(in_string[0:time_end]) def note_finder(in_string):#Mengambil string, mencari n=, mengembalikan nilai n sebagai int num_start =in_string.index("n=") + 2 num_end =in_string.index("v=") - 1 return int(in_string[num_start:num_end])def on_off_finder(in_string):#takes sebuah string, mencari On atau Off, kembalikan true jika On start =in_string.index(" ") + 1 end =in_string.index("ch=") - 1 if in_string[start:end] =="On":return True elif in_string[start:end] =="Off":return Falsemain()
Processing untuk mengirim data ke arduinoProcessing
Membaca file teks yang diterjemahkan dan mengirimkannya ke arduino.
Harus mod pengganda tempo jika tempo berbeda dari 50000.
Membalikkan byte karena bergeser dari kiri ke kanan. (File teks mengasumsikan kanan ke kiri)import processing.serial.*;Serial myPort;String[] inputLines;void setup(){ myPort =new Serial(this, "COM3", 9600); inputLines =loadStrings("translated.txt"); run();}void run(){ //membaca waktu dan mengirimkan data bt line menggunakan metode data int lastTime =0; for(int i =0; i Kode ArduinoArduino
Kode sederhana untuk arduino. Mengambil input dari Serial. 888 dan 999 dicadangkan untuk perintah buka dan tutup register geser.Tidak ada pratinjau (hanya unduh).
Skema
Maaf untuk gambar yang tidak profesional. Ini adalah keseluruhan konsep. Tidak ada perbedaan antara diagram dokumen Arduino -ShiftOut kecuali untuk MOSFET. Saya sarankan melihat itu juga.