Arduino tone мелодия. Шкатулка с музыкальным замком

Каких только замков ни придумали! И с хитрым ключом, и на комбинации цифр, и с распознанием частей тела. Однако, мне захотелось сделать замок, который я ещё не встречал. Поскольку я увлекаюсь игрой на пианино, за идеей далеко ходить не пришлось: было решено сделать шкатулку, которая открывается, лишь «услышав» знакомую мелодию.

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

Что получилось

Распознание мелодии

Как известно, то, что мы воспринимаем как звук, можно рассматривать как толчки воздуха в барабанную перепонку. Воздух надавил – нерв зарегистрировал. То, что мы воспринимаем как ноту, можно рассматривать как толчки с постоянным периодом. Иначе говоря, если этот нерв щекотать 130 раз в секунду, то мы «услышим» ноту «до».
Устройство, которое распознаёт ноты, старается понять, сколько раз в секунду ему «щекотали» микрофон и какая получилась частота (и, стало быть, нота). Переход от частоты к ноте – штука простая, есть таблица «частота → нота» .

Есть несколько разных алгоритмов, которые превращают данные с микрофона в частоты. Самый известный – преобразование Фурье . Принцип работы таков: на вход подаётся с какой силой воздух давил на микрофон в каждый момент времени. На выходе – сколько какой частоты содержалось. Его работу проще всего объяснить картинкой:

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

Однако, мы пойдём другим путём. Знать, какие именно ноты играют, нам не обязательно. Надо лишь узнать, играет ли в данный момент та нота, которую мы ожидаем. На помощь приходит алгоритм Гёрцеля . Этот алгоритм используется в телефонии, когда надо определить тональный сигнал. Суть проста: алгоритму дают искомую частоту и данные с микрофона, а он отвечает, какова «громкость» искомой частоты.

На реализацию алгоритма можно взглянуть в файле .

Выбор компонентов

Я остановился на довольно стандартных компонентах. Вот, что мне пригодилось:

ATMega328P с кристаллом на 16Mhz – «мозг» устройства. Выбор пал именно на него, поскольку уж больно просто с ним работать.

Электретный микрофон с усилителем OPA344 – эти два устройства продавались комплектом на одной плате на сайте Sparkfun . Данные с этого устройства можно считывать прямо с аналогового входа микроконтроллера.

Выключатель TPS2020 – это отличный выключатель с очень низким энергопотреблением в выключенном состоянии (10 μA). Он будет управлять питанием серво.

Регулятор LM2936Z – линейный регулятор на 3.3V с небольшим током в рабочей точке (≤ 15 μA). То, что надо для нашего устройства, которое будет питаться от батарейки.

Зарядное устройство MAX1555 – чип, который управляет зарядкой батарейки и мигает лампочкой, когда батарейка полна.

Схема

Ничего особо сложного в схеме устройства нет. можно найти полную схему. А вот упрощённая схема, которая поясняет, какие компоненты при чём:

Довольно интересным делом оказалось скомпоновать плату так, чтобы она уместилась в небольшую коробку. Поскольку я решил делать всё сам, дома, варианты с многослойной платой не подходили. Поэтому пришлось придумать фейк многослойной платы: устройство состоит из двух уровней, которые соединяются как шилды для Arduino. Получилось что-то подобное:

Синие соединения – те, что будут на самой плате. Красные – те, что будут добавлены позже, либо шилдиковыми коннекторами, либо проводами поверх платы.

Создание платы

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

Печатаем схему на прозрачной плёнке и выпиливаем основу для платы:

Плата до лужения и проделывания отверстий:

Платы с одной стороны:

Платы с другой стороны:

Собранные платы:

С другой стороны:

Создание шкатулки

Шкатулка состоит из самой шкатулки и стенок, окружающих схему и моторчик. Я решил купить неотделанную шкатулку, чтобы самому покрыть её краской и лаком. Стенки и вспомогательные детали я заказал на сайте Ponoko : им можно послать чертёж в SVG, а они вырежут её лазером на тонкой фанерке. Чертёж можно найти . Вот, как выглядит этот чертёж и его реализация:

Плюс три недели:

После того как эти части были интегрированы в шкатулку, получилось так:

Теперь можно окрасить шкатулку и покрыть её лаком. Я нанёс два слоя краски и два слоя лака, чтоб на века. Пожалуй, ничего особо сложного в этом процессе нет. Разве что шкурить дерево надо очень качественно: места, где схалтурил отчётливо видны. Вот что получилось:

Механизм замка выглядит вот так:

Результат

В результате схема отлично поместилась в шкатулку:

Я отнёс поделку к нескольким своим знакомым: правильная мелодия распознаётся на разных фортепиано: и на электронных пианино, и на обычных пианино, и на рояле. Точность распознавания: полтона.

Исходный код контроллера, схему и чертёж платы можно найти на . Я буду рад ответить на любые вопросы, выслушать критику и предложения.

Наш следующий проект на контроллере Arduino – музыкальная шкатулка. Программный скетч для Ардуино прилагается, так что вы легко сможете добавить свои мелодии, даже не имея больших познаний в программировании Ардуино. Принцип работы устройства очень прост - при открытии шкатулка будет играть приятную мелодию, при закрытии шкатулки воспроизведение мелодии прекращается. Для данного проект потребуется сама плата Arduino и минимум деталей: динамик, потенциометр (переменный резистор), сопротивление на 10кОм, батарейки АА, кнопка и транзистор КТ503А или любой другой маломощный n-p-n транзистор, например КТ315.

Звук – колебательное движение частиц упругой среды, распространяющееся в виде волн в газообразной, жидкой или твёрдой средах. Если сказать просто - это колебания волн. В динамике колеблется мембрана. В зависимости от частоты колебания мы слышим звук разной тональности. От глубины хода мембраны зависит громкость. Управляют мембраной за счёт подаваемого напряжения.
В платах Arduino для вывода звука на динамик используются цифровые или аналоговые выходы. Для воспроизведения мелодии необходимо подавать последовательно звуки определенной частоты и длительности. Для генерации звуков определенной частоты и длительности в Arduino используется функция tone():
tone(pin,frequency,duration);

Функция tone() генерирует на выводе pin прямоугольный сигнал частоты frequency с коэффициентом заполнения 50%. Третий (необязательный) параметр функции duration позволяет задавать длительность сигнала. Если длительность сигнала не указана, звук будет генерироваться до вызова функция noTone().
Обычно в примерах по генерации звуков на Arduino для воспроизведения звука используется пьезоэлектрический излучатель, но к сожалению громкость звука при этом недостаточна. Поэтому Мы для воспроизведения звука мы будем использовать маленький динамик.

В качестве контроллера Arduino я использовал Arduino Pro Mini, которая отличается малым размером и очень удобна при использовании на плате. Можно использовать любую плату Ардуино, например, подойдет наиболее популярная Arduino Uno. Соберем схему, показанную на рисунке 1 (схема соединений на рисунке 2).


Рис. 1. Принципиальная схема музыкальной шкатулки
Рис. 2. Схема подключения компонентов к Arduino

Для написания скетча нам понадобятся значения частот для нот 1 и 2 октавы и обозначения для каждой ноты (см. таблицу 1).


Таблица 1. Таблица нот

Теперь подберем мелодию, которую будет воспроизводить музыкальная шкатулка. Желательно найти мелодию, записанную на нотном стане. Я выбрал простую мелодию – "В траве сидел кузнечик" (ноты на рисунке 3).


Рисунок 3. Мелодия "В траве сидел кузнечик" на нотном стане.

Теперь приступим к написанию скетча. Потенциометр в схеме (рисунок 1) присутствует для подбора нужного темпа мелодии. Темп может принимать значения от MIN_TEMPO до MAX_TEMPO. Для вычисления подобранного темпа используем функцию map(), которая преобразует значение на аналоговом входе A0 в значение подобранного темпа.
tempo=map(analogRead(PIN_POT),0,1024,MIN_TEMPO,MAX_TEMPO);

Занесем в массив melody последовательность воспроизводимых нот, список длительностей нот занесем в массив duration, при этом длительность целой ноты равна 32, половинной 16, и т.д. до 1/32 – длительность1. Данные с обозначением нот занесем в массив notes, а данные с частотами для соответствующих нот занесем в массив frequency. Паузу обозначим символом "*".

// МЕЛОДИЯ – массив нот и массив длительностей char melody={"A", "E","A","E","A", "U","G","G","G", "E","U","E","G", "A","A","A","A", "E","A","E","A", "U","G","G","G", "E","U","E","G", "A","A", "H","H","H","H","H", "c","c","c","c","c", "c","H","A","U", "A","A","A","A", "H","H","H","H","H", "c","c","c","c","c", "c","H","A","U", "A", "*" }; int bb={4, 4,4,4,4, 4,4,4,4, 4,4,4,4, 4,4,4,4, 4,4,4,4, 4,4,4,4, 4,4,4,4, 8,8, 4,2,2,4,4, 4,2,2,4,4, 4,4,4,4, 4,4,4,4, 4,2,2,4,4, 4,2,2,4,4, 4,4,4,4, 4,64 }; // массив для наименований нот в пределах двух октав char names={"c","r","d","s","e","f","t","g","u","a","b", "h","C","R","D","S","E","F","T","G","U","A","B", "H","F"}; // массив частот нот int tones={261,277,293,311,329,349,370,392,415,440,466, 494, 523,554,587,622,659,698,740,784,830,880,932,988};

В цикле loop() мы проверяем отжатие кнопки (открытие шкатулки). По отжатию кнопки начинается проигрывание мелодии понотно, вызывая процедуру playNote(), в которую передает обозначение текущей ноты и продолжительность. Процедура playNote() находит по обозначению ноты значение соответствующей частоты и вызывает для проигрывания ноты функцию tone(). Продолжительность звучания ноты – это базовая нотная длительность (32 – для целой, 16 – для полуноты, 8 – для четвертной и т.д.) умноженная на значение темпа произведения – temp. Значение temp устанавливается по значению потенциометра, и подбирается при отладке, в работе не меняется. Для лучшего звучания музыкального отрезка после воспроизведения каждой ноты делаем небольшую паузу delay(beats*tempo+tempo). По нажатии кнопки при воспроизведении мелодии, воспроизведение прекращается. При нажатии клавиш обязательно использовать процедуру проверки на дребезг debounce(boolean last).

Запустим Arduino IDE. Создадим новый скетч и внесем в него содержимое листинга 1.

// МЕЛОДИЯ – массив нот и массив длительностей char melody={"A", "E","A","E","A", "U","G","G","G", "E","U","E","G", "A","A","A","A", "E","A","E","A", "U","G","G","G", "E","U","E","G", "A","A", "H","H","H","H","H", "c","c","c","c","c", "c","H","A","U", "A","A","A","A", "H","H","H","H","H", "c","c","c","c","c", "c","H","A","U", "A", "*" }; int bb={4, 4,4,4,4, 4,4,4,4, 4,4,4,4, 4,4,4,4, 4,4,4,4, 4,4,4,4, 4,4,4,4, 8,8, 4,2,2,4,4, 4,2,2,4,4, 4,4,4,4, 4,4,4,4, 4,2,2,4,4, 4,2,2,4,4, 4,4,4,4, 4,64 }; // подключить динамик к pin 8 #define PIN_SPEAKER 8 // переменные - темп воспроизведения, ноты, длительности int tempo,notes,beats; #define MIN_TEMPO 20 #define MAX_TEMPO 100 // пин подключения потенциометра #define PIN_POT A0 // пин подключения кнопки // при отжатии - включить проигрывание мелодии // при нажатии прекратить // пин подключения потенциометра #define PIN_BUTTON 5 // Переменная для сохранения текущего состояния кнопки int tekButton = LOW; // Переменная для сохранения предыдущего состояния int prevButton = LOW; // Переменная для сохранения количества проигрываний int countPlay = 0; void setup() { // Сконфигурировать контакт динамика как выход pinMode(PIN_SPEAKER, OUTPUT); // Сконфигурировать контакт кнопки как вход pinMode (PIN_BUTTON, INPUT); } void loop() { tekButton = debounce(prevButton); if (prevButton == HIGH && tekButton == LOW) // если отжатие... { // получить темп воспроизведения tempo=map(analogRead(PIN_POT),0,1024,MIN_TEMPO,MAX_TEMPO); for(int i=0;i

После загрузки скетча и настройки потенциометром скорости воспроизведения мелодии все упаковываем в шкатулку (рисунки 4, 5, 6) и дарим маме или любимой девушке.


Рис. 4. Собранная схема музыкальной шкатулки

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


Рис. 5. Сундучок - корпус музыкальной шкатулки
Рис. 6. Устанавливаем схему музыкальной шкатулкив корпус

Вы можете собрать данный проект, используя товары из магазина Радиодеда.

Каких только замков ни придумали! И с хитрым ключом, и на комбинации цифр, и с распознанием частей тела. Однако, мне захотелось сделать замок, который я ещё не встречал. Поскольку я увлекаюсь игрой на пианино, за идеей далеко ходить не пришлось: было решено сделать шкатулку, которая открывается, лишь «услышав» знакомую мелодию.

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

Что получилось

Распознание мелодии

Как известно, то, что мы воспринимаем как звук, можно рассматривать как толчки воздуха в барабанную перепонку. Воздух надавил – нерв зарегистрировал. То, что мы воспринимаем как ноту, можно рассматривать как толчки с постоянным периодом. Иначе говоря, если этот нерв щекотать 130 раз в секунду, то мы «услышим» ноту «до».
Устройство, которое распознаёт ноты, старается понять, сколько раз в секунду ему «щекотали» микрофон и какая получилась частота (и, стало быть, нота). Переход от частоты к ноте – штука простая, есть таблица «частота → нота» .

Есть несколько разных алгоритмов, которые превращают данные с микрофона в частоты. Самый известный – преобразование Фурье . Принцип работы таков: на вход подаётся с какой силой воздух давил на микрофон в каждый момент времени. На выходе – сколько какой частоты содержалось. Его работу проще всего объяснить картинкой:


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

Однако, мы пойдём другим путём. Знать, какие именно ноты играют, нам не обязательно. Надо лишь узнать, играет ли в данный момент та нота, которую мы ожидаем. На помощь приходит алгоритм Гёрцеля . Этот алгоритм используется в телефонии, когда надо определить тональный сигнал. Суть проста: алгоритму дают искомую частоту и данные с микрофона, а он отвечает, какова «громкость» искомой частоты.

На реализацию алгоритма можно взглянуть в файле .

Выбор компонентов

Я остановился на довольно стандартных компонентах. Вот, что мне пригодилось:

ATMega328P с кристаллом на 16Mhz – «мозг» устройства. Выбор пал именно на него, поскольку уж больно просто с ним работать.

Электретный микрофон с усилителем OPA344 – эти два устройства продавались комплектом на одной плате на сайте Sparkfun . Данные с этого устройства можно считывать прямо с аналогового входа микроконтроллера.

Выключатель TPS2020 – это отличный выключатель с очень низким энергопотреблением в выключенном состоянии (10 μA). Он будет управлять питанием серво.

Регулятор LM2936Z – линейный регулятор на 3.3V с небольшим током в рабочей точке (≤ 15 μA). То, что надо для нашего устройства, которое будет питаться от батарейки.

Зарядное устройство MAX1555 – чип, который управляет зарядкой батарейки и мигает лампочкой, когда батарейка полна.

Схема

Ничего особо сложного в схеме устройства нет. можно найти полную схему. А вот упрощённая схема, которая поясняет, какие компоненты при чём:

Довольно интересным делом оказалось скомпоновать плату так, чтобы она уместилась в небольшую коробку. Поскольку я решил делать всё сам, дома, варианты с многослойной платой не подходили. Поэтому пришлось придумать фейк многослойной платы: устройство состоит из двух уровней, которые соединяются как шилды для Arduino. Получилось что-то подобное:

Синие соединения – те, что будут на самой плате. Красные – те, что будут добавлены позже, либо шилдиковыми коннекторами, либо проводами поверх платы.

Создание платы

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

Печатаем схему на прозрачной плёнке и выпиливаем основу для платы:

Плата до лужения и проделывания отверстий:

Платы с одной стороны:

Платы с другой стороны:

Собранные платы:

С другой стороны:

Создание шкатулки

Шкатулка состоит из самой шкатулки и стенок, окружающих схему и моторчик. Я решил купить неотделанную шкатулку , чтобы самому покрыть её краской и лаком. Стенки и вспомогательные детали я заказал на сайте Ponoko : им можно послать чертёж в SVG, а они вырежут её лазером на тонкой фанерке. Чертёж можно найти . Вот, как выглядит этот чертёж и его реализация:

Плюс три недели:

После того как эти части были интегрированы в шкатулку, получилось так:

Теперь можно окрасить шкатулку и покрыть её лаком. Я нанёс два слоя краски и два слоя лака, чтоб на века. Пожалуй, ничего особо сложного в этом процессе нет. Разве что шкурить дерево надо очень качественно: места, где схалтурил отчётливо видны. Вот что получилось:

Механизм замка выглядит вот так:

Результат

В результате схема отлично поместилась в шкатулку:

Я отнёс поделку к нескольким своим знакомым: правильная мелодия распознаётся на разных фортепиано: и на электронных пианино, и на обычных пианино, и на рояле. Точность распознавания: полтона.

Исходный код контроллера, схему и чертёж платы можно найти на . Я буду рад ответить на любые вопросы, выслушать критику и предложения.