Промышленное производство
Промышленный Интернет вещей | Промышленные материалы | Техническое обслуживание и ремонт оборудования | Промышленное программирование |
home  MfgRobots >> Промышленное производство >  >> Manufacturing Technology >> Производственный процесс

Робот-пианино, управляемый Arduino:PiBot

Компоненты и расходные материалы

Arduino 101
× 1
Texas Instruments 74HC595
× 11
IRFZ44N
N-Channel Mosfet
× 88
Аккумулятор 12 В
× 2
Конденсатор 100 мкФ
× 11
Проводной кабель OpenBuilds - пешком
многие из них.
× 1
Макет (общий)
Или общий прототип платы. Практически все, что может соединить все вместе.
× 11
8-контактный разъем для ИС
Необязательно, если вы уверены, что не сожжете ЛЮБОЙ из этих дорогих 595
× 11
Резистор 10 кОм
Не используется в этом проекте, но лучше иметь для каждого mosfet
× 88
1N4007 - высоковольтный диод с высоким номинальным током
Не используется в этом проекте, но лучше иметь для каждого mosfet
× 88

Необходимые инструменты и машины

Пистолет для горячего клея (общий)

Приложения и онлайн-сервисы

Обработка
Python
двоичный файл MIDI в текст

Об этом проекте

Как это началось:

Много лет назад Yamaha представила автоматическое фортепиано. Молодой и невинный я видел, как рояль играет на музыке за стеклянной витриной инструментального магазина.

Хватит разговоров, на самом деле нет большой причины, по которой я начал этот проект, кроме того, что я просто хотел.

Обзор:

Одна плата Arduino Mega стоит около 40 долларов, а две потребуются для управления 88 соленоидами. Это довольно дорого. Вместо этого возьмите дешевую Arduino Uno и сдвиговый регистр 11. Регистр сдвига - это метод управления множеством выходов (обычно светодиодами) с небольшим количеством выходных контактов. По сути, это одна Arduino с 11 регистрами сдвига и управляющими 88 соленоидами.

Поскольку мы используем регистры сдвига, ПК будет отправлять набор битов в Arduino вместо MIDI com. Файл MIDI будет заранее преобразован в набор битов.

Оборудование:

Когда я получил соленоиды прямо из Китая, я обнаружил, что эти соленоиды недостаточно сильны, чтобы нажимать на клавиши пианино. Конечно, нажатие на клавиши пианино из самой внутренней точки требует больше силы, но я подумал, что это лучший метод, который не повредит пианино. В конце концов я пропустил 24 В через соленоиды 12 В, чтобы получить достаточно энергии.

88 Соленоиды потребляют много энергии, и, поскольку я не могу пойти и купить дорогой блок питания, я решил использовать автомобильный аккумулятор моего отца. (Думаю, теперь он никуда не пойдет!)

После этого каждый из регистров сдвига и полевых МОП-транзисторов будет размещен на плате контроллера.

595 справа с розеткой на случай, если я сожгу. (Что я и сделал однажды.) Принципиальная схема в точности такая же, как в примере 2 отсюда. Замените светодиоды затвором MOSFET. Как видите, понижающего резистора нет, потому что дополнительные резисторы увеличивают стоимость, а их пайка на этой плате расплавит мои пальцы. С более серьезной стороны, эти полевые МОП-транзисторы открываются при 5 В и закрываются при 4 В или около того. Подтверждено через бесчисленные часы тестирования. (Теоретически неверно. Не слушайте меня.)

Наконец, возьмите кусок пластиковой пластины, чтобы приклеить к ней соленоиды. Использовать горячий клей и пластиковую пластину - плохая идея, учитывая, что она будет горячей, но это лучшее, что я могу себе позволить.

Затем протяните одну сторону проводов соленоида к плюсовому полюсу батареи.

Программное обеспечение:

Самый первый шаг - получить файл формата midi.

Второй шаг - преобразовать миди в текстовую форму. Это можно сделать на удобном веб-сайте:http://flashmusicgames.com/midi/mid2txt.php.

Для простоты игнорируйте размер, темп и пар. Темп может быть увеличен на время позже. По сути, вам нужен такой файл:

Теперь используйте это, чтобы со временем создать 11 наборов 8-битных данных, запустив их через код Python (прилагается).

Они готовы к отправке в Arduino через обработку COM.

См. Приложение, чтобы выяснить, как обработка отправляет эти данные и как Arduino обрабатывает их.

* Примечание:у меня плохие привычки кодирования, и мне может быть трудно их читать. Обработка отправляет данные справа налево, потому что Arduino передает данные на физическом пианино вправо.

Вот эта штука работает:

Устранение неполадок:

Если профессиональный инженер увидит этот пост, он подумает, что вся эта система будет иметь много проблем. И есть много проблем.

Поскольку соленоиды были приклеены к пластине горячим способом, перегрев соленоидов и плавление горячего клея были большой проблемой. Решением было просто удалить их и заменить на двусторонний скотч, выдерживающий температуру до 150 ° C.

Код

  • Код Python для перевода
  • Обработка для отправки данных в Arduino
  • Код Arduino
Код Python для перевода Python
Принимает текстовый файл mifi и преобразует его в 11 наборов двоичных файлов для Arduino.
 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 ():for a in 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 (True, 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)) для b в результате:output_file .write (b) output_file.write ("\ n") output_file.close () def set_bit (On, note):# Принимает логическое значение, если он включен или нет, и номер заметки. # Генерирует бит if (note> =21 and note <=28 и On):return str (2 ** (note - 21)) + ", 0,0,0,0,0,0,0,0,0 , 0 "elif (note> =29 and note <=36 and On):return" 0, "+ str (2 ** (note - 29)) +", 0,0,0,0,0,0, 0,0,0 "elif (note> =37 и note <=44 and On):вернуть" 0,0, "+ str (2 ** (note - 37)) +", 0,0,0,0 , 0,0,0,0 "elif (note> =45 and note <=52 and On):return" 0,0,0, "+ str (2 ** (note - 45)) +", 0, 0,0,0,0,0,0 "elif (примечание> =53 и примечание <=60 и On):вернуть" 0,0,0,0, "+ str (2 ** (примечание - 53)) + ", 0,0,0,0,0,0" elif (note> =61 и note <=68 and On):return "0,0,0,0,0," + str (2 ** ( note - 61)) + ", 0,0,0,0,0" elif (note> =69 и note <=76 and On):return "0,0,0,0,0,0," + str (2 ** (примечание - 69)) + ", 0,0,0,0" elif (примечание> =77 и примечание <=84 и On):return "0,0,0,0,0,0, 0, "+ str (2 ** (примечание - 77)) +", 0,0,0 "elif (примечание> =85 и примечание <=92 и On):return" 0,0,0,0,0 , 0,0,0, "+ str (2 ** (примечание - 85)) +", 0,0 "elif (примечание> =93 и примечание <=100 и On):return" 0,0,0, 0,0,0,0,0,0, "+ str (2 ** (примечание - 93)) +", 0 "elif (примечание> =101 и note <=108 и 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):# То же, что и set_bit, но ранее известно temp =result [index] temp =temp [(temp.find (",") + 1):] if (note> =21 и note <=28):local_temp =temp [0:temp.find (",")] if (On):return str (int (local_temp) + (2 ** (примечание - 21))) + temp [temp.find (","):] if (not On):return str (int (local_temp) - (2 ** (note - 21))) + temp [temp.find (","):] elif (note> =29 и note <=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 ** (примечание - 29))) + temp [indexTh (temp, ",", 2):] elif (note> =37 и 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 ** (примечание - 37))) + темп [дюйм dexTh (temp, ",", 3):] if (not On):return temp [0:indexTh (temp, ",", 2) + 1] + str (int (local_temp) - (2 ** (примечание - 37))) + temp [indexTh (temp, ",", 3):] elif (note> =45 и 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 ** (примечание - 45))) + temp [indexTh (temp, ",", 4):] if (not On):return temp [0:indexTh (temp, ",", 3) + 1] + str (int (local_temp ) - (2 ** (note - 45))) + temp [indexTh (temp, ",", 4):] elif (note> =53 и 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 ** (примечание - 53))) + temp [indexTh (temp, ",", 5):] if (not On):return temp [0:indexTh (temp, ",", 4) + 1] + str (int (local_temp) - (2 ** (note - 53))) + temp [indexTh (temp, ",", 5):] elif (note> =61 и note <=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 ** (note - 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 и примечание <=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 (примечание> =77 и примечание <=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 ** (note - 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 (note> =85 и note <=92):# здесь ошибка 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 ** (примечание - 85 ))) + temp [indexTh (temp, ",", 9):] if (not On):return temp [0:indexTh (temp, ",", 8) + 1] + str (int (local_temp) - (2 ** (примечание - 85))) + temp [indexTh (temp, ",", 9):] elif (note> =93 и 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 ** (примечание - 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 и note <=108):local_temp =temp [(indexTh (temp, ",", 10) + 1):] if (On):return temp [0:indexTh (temp, ",", 10) + 1] + str (int (local_temp) + (2 ** (примечание - 101))) if (not On):return temp [0:indexTh (temp, ",", 10) + 1] + str (int (local_temp) - (2 ** (примечание - 101) )) def indexTh (in_string, find_this, th):# Принимает строку, строку для поиска и порядок поиска строки для поиска в этот порядок # возвращает index order =1 last_index =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):# Берет строку и находит время, возвращает ее как int time_end =in_string.index ("") return int (in_string [0:time_end]) def time_finder_comm (in_string):# Берет строку и находит время, возвращает ее как целую запятую time_end =in_string.index (",") return int (in_string [0:time_end]) def note_finder (in_string):# Берет строку, ищет n =, возвращает значение n как 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):# принимает строка, ищет On или Off, возвращает истину, если On start =in_string.index ("") + 1 end =in_string.index ("ch =") - 1, если in_string [start:end] =="On":return True elif in_string [start:end] =="Off":return Falsemain () 
Обработка для отправки данных в Arduino Обработка
Читает переведенный текстовый файл и отправляет его в Arduino.
Необходимо изменить множитель темпа, если темп отличается от 50000.
Переворачивает байты, потому что сдвигается слева направо. (Текстовый файл предполагает справа налево)
 import processing.serial. *; Serial myPort; String [] inputLines; void setup () {myPort =new Serial (this, "COM3", 9600); inputLines =loadStrings ("translated.txt"); run ();} void run () {// считывает время и отправляет данные в строку bt с помощью метода данных int lastTime =0; for (int i =0; i  
Код Arduino Arduino
Простой код для ардуино. Принимает входные данные от Serial. 888 и 999 зарезервированы для команды открытия и закрытия сдвигового регистра.
 Предварительный просмотр отсутствует (только загрузка). 

Схема

Прошу прощения за непрофессиональный рисунок. В этом вся концепция. Нет никакой разницы между диаграммой документа Arduino -ShiftOut, за исключением mosfet. Я рекомендую посмотреть и на это.

Производственный процесс

  1. Робот Raspberry Pi, управляемый через Bluetooth
  2. Создайте своего робота для видеостриминга, управляемого через Интернет, с помощью Arduino и Raspberry Pi
  3. Робот, управляемый Wi-Fi и использующий Raspberry Pi
  4. Светодиоды, управляемые Alexa через Raspberry Pi
  5. Железный человек
  6. Найди меня
  7. Управление увлажнителем Arduino
  8. Робот, управляемый речью
  9. MobBob:самостоятельный робот Arduino, управляемый смартфоном Android
  10. Джойстик Arduino