Всем привет! Сегодня я расскажу про то, как я собрал ардуино робота, играющего музыку на винных бокалах. Если вам интересно то прошу под кат.

Бокалы

Я перепробовал звучание разных бокалов, которые нашёл у себя в доме и, как оказалось, современные бокалы звучат как-то очень слабо, возможно, в этом есть китайский след. А вот старые хрустальные фужеры звучат приятно и громко. Только у меня их оказалось всего 7 шт., что в последствии выльется в ограничение проигрываемых нот. Не хватило всего 1 бокала для проигрывания полноценной мелодии от начала до конца. Пришлось воспроизводить только небольшие кусочки мелодий.
Сразу оговорюсь, я не музыкант и у меня нет музыкального слуха. Поэтому подгонка тональности бокалов к нотам оказалась для меня самой сложной задачей из этого проекта. Так что заранее прошу меня простить за ошибки в звучании нот.

Молоточек

Ударный молоточек сделал из автомобильного реле, купленного в ближайшем авто-магазине. Удалил с него корпус и спилил лишние контакты, а на якорь припаял медную проволоку диаметром 1 мм. Этот медный провод я извлек из силового кабеля, который используется для бытовой проводки 220 В. В качестве самого молотка колотушки я использовал кусочек деревянного, мебельного шканта.

Просверлил в нём отверстие и нанизал его на кусок провода из меди, после чего для надежности капнул сверху клеем «Момент».
Для управления этой барабанной палочкой я использовал старый, советский транзистор KT972, управление которым осуществляется с контроллера через резистор от 270 до 510 Ом. Для гашения отрицательных импульсов самоиндукции, параллельно катушке, припаял выпрямительный диод 1N4007. Такой можно найти в любой, отслужившей свой срок, светодиодной лампочке или в старой бытовой технике. Транзистор можно заменить на любой другой, в том числе и на MOSFET, с минимальным током перехода не менее 1 А.

Соленоид с молоточком разместил на пластиковой рейке. После чего его нужно сбалансировать, так как дисбаланс будет вызывать вибрацию. Для этого, на противоположной стороне рейки, прикрутил металлическую гайку, предварительно подобрав её по весу. Далее, приклеиваем рейку на распечатанную 100 лет назад на 3D принтере шестеренке.

Чтобы выравнять ударный механизм по высоте с бокалами, я приклеил ШД на пластиковую банку через прокладку из вспененного полиэтилена. Прокладка нужна, чтобы банка не усиливала шум мотора.

Шаговый двигатель

ШД использовал HANPOSE 17HS4401. Для максимальной скорости вращения, попробовал полношаговый режим, но в этом режиме есть один недостаток: мотор очень громко работает и его жужжание очень сильно выделяется на на фоне звука бокалов. Пришлось пожертвовать скоростью и использовать режим полушага(1/2), а это в свою очередь 400 шагов на один оборот вала. В таком режиме шаговый двигатель начал работать заметно тише, но и почти в 2 раза медленнее, хотя этого вполне хватает для проигрывания спокойной музыки.

В проекте использовался драйвер шагового двигателя A4988, но где-то на форумах я прочитал про тихий драйвер TMC-2100, к сожалению, на момент сборки проекта у меня такого не нашлось и пришлось подстраиваться к пониженной скорости мотора. Отказавшись от библиотеки «A4988.h», мне удалось с выжать с ШД максимум.

Подсветка

Подсветка сделана всего на одном светодиоде ws2812, который я отрезал от светодиодной ленты.

Цвет светодиода изменяется рандомно, в пределах семи основных цветов: от белого до красного. Для управления им я использовал библиотеку NeoPixel. Для снижения боковой засветки, на светодиод я приклеил пластиковое кольцо.

Схема

Соединил все компоненты по нарисованной мной схеме. Установил переключатели на драйвере шагового двигателя в режим полудуплекса. На соленоид и мотор подал 15 В., так как молоточек для соленоида тяжеловат и, иногда, при 12 В  он не до конца притягивает якорь. Ещё, для уменьшения щелчков якоря, я приклеил на сердечник электромагнита кусочек ткани.

Используемые в схеме компоненты:
Arduino Nano
Шаговый двигатель 17HS4401
Драйвер шагового двигателя A4988
Плата расширения для драйвера шагового двигателя
Провода соединительные
Светодиод WS2812
Транзистор Mosfet
Реле автомобильное на 30 А

Музыка

Мелодию можно написать самому или найти готовую на сайте musicboxmaniacs. Если вы будете использовать готовую мелодию, то для начала у неё нужно убрать многоголосность — это значит, что в одном музыкальном такте не должно быть более одной ноты. После чего, перенести её в ручную следующем порядке: самая низкая нота имеет значение 0 и так далее до самой высокой. В моем распоряжении всего 7 бокалов, а это значит, что и нот не должно быть больше 7. Для простых мелодий этого будет достаточно. И ещё есть пустой такт — его значение в массиве равно 255. Звук бокалов подстраивается под нужную ноту при помощи воды. Для понижения тона нужно подливать в него воду. Для точной подстройки можно воспользоваться приложением для смартфона «Тюнер пианино» из play Google.

Скетч для ардуино

Алгоритм работы кода следующий: в массиве хранятся ноты, пронумерованные в порядке возрастания от самой низкой равной 0 и до самой высокой равной 6. Каждой ноте соответствует свой бокал. Пустой такт нумеруется значением 255.

Тактирование мелодии происходит по таймеру и темп музыки можно задавать в настройках кода. Для этого нужно указать требуемое количество тактов за одну секунду. Но имейте ввиду, всему есть предел и настанет момент, когда мотор не будет успевать за темпом музыки и начнет пропускать ноты. Особенно при переходе с самой высокой тональности на самую низкую, и наоборот. Кстати, чем больше будет бокалов, тем меньше шагов нужно прокручивать между нотами.

С каждым тактом из массива выбирается текущая и следующая нота, которая преобразуется в соответствующее количество шагов и отправляется на выполнение в шаговый двигатель. Алгоритм считывает ноты с опережением на 1 шаг, что дает возможность заранее переместить молоточек к следующему бокалу .
Все настройки находятся в шапке скетча и прописаны в директивах define.

#include "Adafruit_NeoPixel.h"
#include "CyberLib.h"

#define DEBUG     false //false true включить режим отладки
#define DIR_1     D8_High
#define STEP_1    D9_High
#define HAMMER_1  D10_High 
#define DIR_0     D8_Low 
#define STEP_0    D9_Low              
#define HAMMER_0  D10_Low             
#define WS2812_PIN   11              // выход для подключения ws2812

#define step_num 400                // количество шагов на 1 оборот ШД. включен полушаговый режим для снижения шума
#define note_num 7                  // Количество нот-бокалов
#define step_note step_num/note_num // количество шагов двигателя между нотами. вычисляет автоматически
#define step_duration 950          // длительность шага влияет на скорость ШД: чем ниже значение, тем быстрее, но есть вероятность пропуска шагов
#define ratio 1.3                   // коэффициент делитель длительности отрицательного импульса шага
#define kick_duration 8             // длительность удара молоточка в мс.
#define tact 6                    // количество тактов за 1 сек., но нужно учитывать скорость перемещения ШД от ноты к ноте
#define tact_us 1000000/tact        // длительность такта в мкс. вычисляет автоматически

#define NUM_PIX 1                   // количество светодиодов в ленте
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_PIX, WS2812_PIN, NEO_GRB + NEO_KHZ800);

volatile uint8_t tact_num=0, int_state=0; 
uint8_t sound=0;
int next_sound=0;

 const uint8_t music[] PROGMEM = {255,255,0,1,2,255,2,255, 2,3,4,255,4,255,4,5, 3,255,3,255,2,1,1,2,
                                  255,255,0,1,2,255,2,255, 2,3,4,255,4,255,4,5, 3,255,3,255,2,1,2,255,255,255 };
                                  
 /* const uint8_t music[] PROGMEM = { 255,255,2,255,2,255,2,255,   255,255,2,255,2,255,2,255,   255,255,2,255,4,255,0,255,
                                   255,1,2,255,255,255,255,255, 255,255,3,255,3,255,3,255,   255,2,3,255,2,255,2,255,
                                   1,2,255,1,255,1,255,2,       255,1,255,255,255,4,255,255,  255,2,255,2,255,2,255,255,
                                   255,2,255,2,255,2,255,255,   255,2,255,4,255,0,255,255,    1,2,255,255,255,255,255,255,
                                   255,3,255,3,255,3,255,255,   2,3,255,2,255,2,255,255,      2,4,255,4,255,3,255,1,
                                   255,0,255,255,255,255,255,255   };
                                     
 const uint8_t music[] PROGMEM = { 255,255, 5,3,0,3,5,3,0,3,     5,2,0,2,5,2,0,2,       4,2,0,2,4,2,0,2,   4,2,0,2,4,2,0,2, 
                                            5,3,0,3,5,3,0,3,     5,3,0,3,5,3,0,3,       5,2,0,2,5,2,0,2,  5,2,0,2,5,2,0,2, 
                                            5,3,1,3,5,3,1,3,     5,3,1,3,4,3,1,3,       6,4,2,4,6,4,2,4,   6,2,0,2,5,2,0,2, 
                                            5,3,0,3,5,3,0,3,     6,3,0,3,6,3,0,3,      255,255,255,255 }; */
                 
 // const uint8_t music[] PROGMEM = { 255,0,1,2,3,4,5,6,5,4,3,2,1,0,255 }; // для расстановки бокалов   

void setup()      
{
 D10_Out; 
  HAMMER_1; D8_Out; D9_Out; DIR_0; STEP_0;   //Настраиваем пин D8, D9 и D10 на выход
  D12_In; D12_High; 
 
 pinMode(12, INPUT_PULLUP);
 
  randomSeed(analogRead(0));      // получаем начальное значение случайного числа
  strip.begin(); 
  strip.setBrightness(255);       // яркость светодиода на максимум
  strip.setPixelColor(0,0,0,0);
  strip.show();
   
  while(D12_Read){} // ждем нажатия кнопки
  
  #if DEBUG                       // для отладки кода
    Serial.begin(115200);
  #endif

  StartTimer1(tempo, tact_us);  // запуск таймера, первый параметр это обработчик прерывания
}

void loop()
{ 
  if( int_state )                 // если было прерывание по таймеру
   { 
      cli();                     // запрет прерываний, чтобы избежать нарушений последовательности тактов   
       uint8_t tmpS = pgm_read_byte_near(&music[tact_num]);   // текущая нота
       uint8_t tmpN;
       if(tact_num != sizeof(music)-1)
       {
        tmpN = pgm_read_byte_near(&music[tact_num+1]); // следующая нота
       } else tmpN = pgm_read_byte_near(&music[0]);     // иначе в начало массива
      sei(); 

      if(tmpN != 255) next_sound = tmpN;  // проверяем следующий сэмпл на пустой такт
      if(tmpS != 255)                    // если не пустой такт, то ударяем молоточком и перемещаемся на следующую ноту
      {    
         HAMMER_0;
          sound = tmpS;
          uint8_t r=random(2); if(r) r=255;
          uint8_t g=random(2); if(g) g=255;
          uint8_t b=random(2); if(b) b=255;
          if(r==0 && g==0) b=255;
          strip.setPixelColor(0,r,g,b);
          strip.show(); 
          delay_ms(kick_duration);       // длительность импульса удара. Можно регулировать силу удара
        HAMMER_1;
      } 
        #if DEBUG                             //для отладки кода
          Serial.println(tact_num);
          Serial.println();
        #endif
      
     steps((next_sound-sound) * step_note); // перемещаем на следующий бокал
     int_state=0;                           // сбросить флаг прерывания
   }     
}

//******************выполнение шагов************************
void steps(int shag)
{       
  if(shag>0) { DIR_1; } else { DIR_0; shag=abs(shag); }       // проверка направления вращения, убираем знак(-)
   for(uint16_t i = 0; i < shag; i++)  // Выполняем заданное количество шагов
   {
    STEP_1;
    delay_us(step_duration);          // длительность шага, влияет на скорость вращения
    STEP_0;
  //  delay_us(step_duration/ratio);
  } 
}

//****************обработчик прерывания таймера1***********
void tempo()
{
 int_state=1;             // флаг прерывания установлен
 tact_num++;              // добавим 1 такт
 if( tact_num > sizeof(music)-1) tact_num=0; //если достигли конца массива, то сбрасываем в начало
}

Скачать скетч с библиотеками

Теперь в видео можно посмотреть результат моей работы

Заключение

Спасибо, что дочитали до конца!

Надеюсь, эта статья вам понравилась и вы сможете воспользоваться моей наработкой в своих проектах.

Если у Вас остались вопросы и замечания, то можете задать их в комментариях. Я с удовольствием на них отвечу.

Комментарии (16)


  1. usa_habro_user
    19.11.2021 18:49
    +1

    Идея "зачОтная", равно, как и имплементация, "плюсую" однозначно! Играть на бокалах сами придумали, или где-то подсмотрели? (в принципе, без разницы, все равно очень забавно получилось)

    Поэтому подгонка тональности бокалов к нотам оказалась для меня самой сложной задачей из этого проекта.

    Думаю, не только для вас: попробовал сейчас свои хрустальные бокалы (по моему, из чешского хрусталя, не "Китай"), но они, хоть и звучат немного по разному, но явно не "по нотам". Как вы добились нужной тональности, есть секрет, или просто повезло?


    1. CyberBot Автор
      19.11.2021 18:54
      +1

      Играть на бокалах сами придумали, или где-то подсмотрели?

      Сам придумал. Даже специально проверял поиском по инету, ничего подобного не нашел

      Как вы добились нужной тональности, есть секрет, или просто повезло?

      Наверно повезло. В самом конце если посмотрите на видео, расстановку бокалов, так там тон бокалов почти попадают в ноты без налитой в них воды.


      1. GennPen
        19.11.2021 18:57
        +1

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


        1. CyberBot Автор
          19.11.2021 19:04
          +1

          Пробовал несколько программ "Тюнеров" они впадают в ступор от звуков бокала. При каждом ударе по бокалу, показывают разные ноты, да еще и в разных октавах.

          В самом конце видео я показал как настраивал. Нажимал на ноту в сматртфоне и подгонял по резонансу


          1. unsignedchar
            19.11.2021 19:58
            +2

            впадают в ступор от звуков бокала


            Спектр другой. У гитарной струны четко видно 1 и 2 гармонику (скорее всего, след от щипка ближе к середине струны). А что в спектре у бокала — сложно представить.


          1. Daddy_Cool
            20.11.2021 01:57
            +1

            Впечатляет!
            У меня на столе чашка, розетка для варенья и неглубокая тарелка — постучал ручкой и попробовал тюнер gStrings — не стразу, но вполне частоту определяет.
            Можно двигаться дальше — делать несколько голосов. По хорошему нужна мелодия и три-четыре ноты аккорда в гармонии.
            — Тут была статья про аналогичный ударный инструмент, но в большем размере.
            habr.com/ru/company/pult/blog/405653


      1. usa_habro_user
        19.11.2021 23:28

        Наверно повезло.

        Мне вот какая мысль в голову пришла: вместо бокалов можно использовать музыкальные колокольчики, наподобие вот таких (хотя с бокалами, конечно, эффектнее). Зато можно сделать цельный, стационарный гаджет, годящийся и на Рождество, и на Новый Год, да на любой праздник.


        1. CyberBot Автор
          19.11.2021 23:39

          Хорошая идея. Я размышлял над алюминиевыми трубками. Можно нарезать разной длины. Учитывая малый диаметр их по кругу можно очень много разместить. И играть И.С.Баха. Но колокольчики тоже интересны, так как они уже настроены на ноты


          1. usa_habro_user
            20.11.2021 00:02
            +1

            Тогда еще одна идея, "вдогонку": печатаете на 3D принтере фигурку гнома/Санты/Деда Мороза/Дарта Вейдера с рукой, раскрашиваете ярко акрилом, "одеваете" на степпер и молоточек - и получаете практически готовый к продаже/производству оригинальный гаджет (но нужно тогда взять вместо "наны" ESP32 (рекомендую мини - классная штука, сам только что опробовал, до этого использовал обычные, "большие") и добавить еще встроенную веб-страничку, на которой можно загружать мелодии, выбирать темп игры, ну, и, короче, все, что придет в голову, пока "фиче-демона" не прихлопните :D


            1. CyberBot Автор
              20.11.2021 00:25
              +2

              Если колокольчики куплю до НГ, то поздравительное видео сделаю


  1. drauger
    19.11.2021 22:57
    +1

    А почему не сделали просто 7 молоточков? Тогда и шаговик был бы не нужен, и мелодии можно было бы многоголосные играть?


    1. CyberBot Автор
      19.11.2021 23:26

      Слишком много проводов пришлось бы прокладывать. Но когда нибудь соберу без шагового двигателя


    1. usa_habro_user
      19.11.2021 23:29
      +1

      Со степпером эффектнее получается, хотя и ваша идея тоже неплоха.


  1. greendog
    20.11.2021 23:27
    +2

    Крутяк! А то, что "старые хрустальные фужеры звучат приятно и громко" неудивительно, потому как только хрусталь и звучит, а стекло - нет.
    Именно так отличают настоящий хрусталь от подделки - хрусталь имеет долгое звучание, а стекло не имеет.


  1. GeorgKDeft
    21.11.2021 14:51
    +2

    Такое же на ложках деревянных и железных тарелках и можно собрать группу электро робот хеви металл)))


    1. da411d
      21.11.2021 17:12
      +1

      Буквально "металл"