ARDUINO Ардуино играет музыку на бокалах

Ардуино играет музыку на бокалах


Схема

glass-harp.jpg



Скетч
C++:
#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; //если достигли конца массива, то сбрасываем в начало
}
 
Изменено:

Комментарии

Divin

★★★✩✩✩✩
30 Янв 2021
412
184
Звук металлический, скорей всего наложен на видео, настройка бокалов( уровень налитой жидкости) займет кучу времени, а настройка ударного молоточка потребует несколько комплектов посуды, ну а так забавно.
 
  • Лойс +1
Реакции: CyberLab

CyberLab

★✩✩✩✩✩✩
7 Сен 2018
48
25
Москва
Звук металлический, скорей всего наложен на видео
Ничего не накладывалось, вся музыка записана на микрофон встроенный в камеру.

а настройка ударного молоточка потребует несколько комплектов посуды
Молоточек деревянный, сила удара настраивается в коде. За все время съемок не разбил ничего
 
  • Лойс +1
Реакции: Divin

Divin

★★★✩✩✩✩
30 Янв 2021
412
184

@CyberLab,
А настройка тональности по какому то принципу или на слух?
 

CyberLab

★✩✩✩✩✩✩
7 Сен 2018
48
25
Москва
Пробовал использовать приложение для смарта "тюнер пианино" но от бокалов его вводит в ступор. Пришлось на слух настраивать. В самом конце видео я показал как на слух настраивал
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,185
1,280
Москва
Непонятно почему полушаг жертвует скоростью. Задержки между шагами в полушаге в 2 раза меньше можно делать.
 

kDn

★★★★★✩✩
18 Ноя 2019
1,103
437
Непонятно почему полушаг жертвует скоростью. Задержки между шагами в полушаге в 2 раза меньше можно делать.
Тут в основном драйвер "музыкальный", нужно ставит ь TMC2008/TMC2009, будет и быстро и тихо. Впрочем ТС в курсе.
 

CyberLab

★✩✩✩✩✩✩
7 Сен 2018
48
25
Москва
Да драйвер нужно менять на TMC200x/
По поводу полного шага и полушага согласен, что не 2 раза, но все равно добиться в полушаговом режиме скорости равной полношаговому невозможно
 
Изменено:

Старик Похабыч

★★★★★★★
14 Авг 2019
4,185
1,280
Москва
Но не в 2 раза же. Вот мои опыты: Проигрыш 1.5% это фигня
Это максимальные скорости когда мотор мог крутиться сразу, без нагрузки. задержка при полном щаге 720 мкс. Но обычно я делаю общий период такта для полного шага 1000 микросеунд. Т.е. 5 оборотов в секунду. Для дробления соотв уменьшаю интервал пропорционально шагу.
A4988
digitaWrite
/16 5,3 оборота. 3200 оборотов 0,1125
/8 6,3 оборота. 1600 оборотов 0,225
/4 6,5 оборота. 800 оборотов 0,45
/2 6,7 оборота. 400 оборотов 0,9
1 6,8 оборота. 200 оборотов 1,8
И на 1/16 а4988 гораздо тише себя ведет.
 
  • Лойс +1
Реакции: CyberLab

CyberLab

★✩✩✩✩✩✩
7 Сен 2018
48
25
Москва
Странно, но у меня почему то совсем другие результаты получились.
Может из-за того , что я использовал свой код управления. Библиотека "A4988" мне не понравилась.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,185
1,280
Москва
Это тоже без библиотеки, т.е. эксперимент был именно с delayMicroseconds
А в последних ковыряниях использовал Гайверовскую билиотеку для шаговиков - там скорость тоже не теряется. Но и ускорения и скорости я увеличиваю в соотв. число раз.
 
  • Лойс +1
Реакции: CyberLab

Старик Похабыч

★★★★★★★
14 Авг 2019
4,185
1,280
Москва
Сегодня уже не буду искать - завтра могу свой код скинуть, для теста.
Но возможные варианты: неверный vref выставлен. Для 1.2 и 100 ом резистора что то типа 0.9в получается. Мотор по размером похож на тот, что с тестами.

Вот нашел образцы как что двигается, скорость одинаковая для всех драйверов

1) Драйвер А4988, делитель 1, т.е. все MS притянуты к земле, то что собрано,
IMG_1706.MOV
Посмотреть и скачать с Яндекс.Диска
disk.yandex.ru
disk.yandex.ru

2) Драйвер А4988, делитель 4, MS1и MS3 к земеле, MS2 к +5.
IMG_1707.MOV
Посмотреть и скачать с Яндекс.Диска
disk.yandex.ru
disk.yandex.ru

3) Драйвер TMC225, делитель 4 , тут это минимальный делитель. MS1 и MS2 к земле, MS3 нет
IMG_1708.MOV
Посмотреть и скачать с Яндекс.Диска
disk.yandex.ru
disk.yandex.ru
 
Изменено:
  • Лойс +1
Реакции: CyberLab

CyberLab

★✩✩✩✩✩✩
7 Сен 2018
48
25
Москва
Избыточное цитирование
Сегодня уже не буду искать - завтра могу свой код скинуть, для теста.
Но возможные варианты: неверный vref выставлен. Для 1.2 и 100 ом резистора что то типа 0.9в получается. Мотор по размером похож на тот, что с тестами.

Вот нашел образцы как что двигается, скорость одинаковая для всех драйверов

1) Драйвер А4988, делитель 1, т.е. все MS притянуты к земле, то что собрано,
IMG_1706.MOV
Посмотреть и скачать с Яндекс.Диска
disk.yandex.ru

2) Драйвер А4988, делитель 4, MS1и MS3 к земеле, MS2 к +5.
IMG_1707.MOV
Посмотреть и скачать с Яндекс.Диска
disk.yandex.ru

3) Драйвер TMC225, делитель 4 , тут это минимальный делитель. MS1 и MS2 к земле, MS3 нет
IMG_1708.MOV
Посмотреть и скачать с Яндекс.Диска
disk.yandex.ru
Как то медленно, у меня побыстрее
Завтра сниму видео
 
Изменено:

Lumenjer

★★★✩✩✩✩
10 Дек 2020
220
112
@Эдуард Анисимов, За видео 18+ не забанят? (кто понял, тот понял)

@CyberLab, Прикольный проект, скинул друзьям заценить) (попутно еще парочку видосов на вашем канале глянул)
 
  • Лойс +1
Реакции: CyberLab

CyberLab

★✩✩✩✩✩✩
7 Сен 2018
48
25
Москва
Ну если вызов принят, то пусть сразу делает деда мороза с молотком в руке, а вокруг него вместо бокалов, колокольчики с алиэкспресс
Хотя это слишком слабо по сравнению с анимацией которая выше
333444.png
 
Изменено:

Старик Похабыч

★★★★★★★
14 Авг 2019
4,185
1,280
Москва
Как обещал код на котором я тестировал:
C++:
#define DIV 16
#define STEP_PIN 7
#define DIR_PIN 6
#define EN_PIN 10

uint16_t all_t = 800;
uint16_t imp_t = 1;

void setup() {
  pinMode(STEP_PIN, OUTPUT);
  pinMode(DIR_PIN, OUTPUT);
  pinMode(EN_PIN, OUTPUT);
  digitalWrite(EN_PIN, 0);
  digitalWrite(DIR_PIN, 0);
  digitalWrite(STEP_PIN, 0);
}

void loop() {
  digitalWrite(STEP_PIN, HIGH);
  delayMicroseconds(imp_t);
  digitalWrite(STEP_PIN, LOW);
  delayMicroseconds(all_t / DIV - imp_t);
}
Это именно код для тестов. Если надо использовать в боевом виде - использую прерывание по таймеру и вызываю шаг там же. Обычно делаю Прерывание раз в 5 -10 чаще чем время шага: шаг включаю при достижении счетчика до нужного интервала, на следующий шаг выключаю пин. При этом меняя предел счетчика можно плавно менять скорость.

Думаю в коде все понятно. Драйвер А4988 , делитель 16 (тоже видно). Работает вот так:
 
Изменено:

CyberLab

★✩✩✩✩✩✩
7 Сен 2018
48
25
Москва
Я сделал небольшую функцию для отработки шагов
с минусом крутит в обратную сторону

C++:
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);
  }
}
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,185
1,280
Москва
С длительностью шага не понятно. Если посмтореть мой код, то общая длительность идет ка 800 микросекунд делить на знаменатель шага дробления. И есть еще микрсекунды , которые надо держать пин шага включенным. в моем случае это 1 . Значение должно быть в датащите, но можно и подобрать.
800/16=50 - общий шаг. Получаетсчя что надо включить пин степ, подождать 1 мкс, выключить пин и подождать 49мкс, что бы дать мотору встать в нужное положение.
Тут есть 2 максроса, которые не раскрывают сути что в них STEP_1 и STEP_0
 

CyberLab

★✩✩✩✩✩✩
7 Сен 2018
48
25
Москва
#include "CyberLib.h"

#define STEP_1 D9_High
#define DIR_1 D8_High
#define STEP_0 D9_Low
#define DIR_0 D8_Low

#define step_num 200 // количество шагов на 1 оборот
#define step_duration 500 // длительность шага влияет на скорость