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) и дарим маме или любимой девушке. Собранную схему музыкальной шкатулки необходимо поместить в корпус. Для этого я использовал сундучок, купленный в китайском магазине. Вы можете собрать данный проект, используя товары из магазина Радиодеда. Каких только замков ни придумали! И с хитрым ключом, и на комбинации цифр, и с распознанием частей тела. Однако, мне захотелось сделать замок, который я ещё не встречал. Поскольку я увлекаюсь игрой на пианино, за идеей далеко ходить не пришлось: было решено сделать шкатулку, которая открывается, лишь «услышав» знакомую мелодию. В этом посте я бы хотел рассказать про алгоритм распознания мелодии, об управляющей схеме и о процессе создания шкатулки. Как известно, то, что мы воспринимаем как звук, можно рассматривать как толчки воздуха в барабанную перепонку. Воздух надавил – нерв зарегистрировал. То, что мы воспринимаем как ноту, можно рассматривать как толчки с постоянным периодом. Иначе говоря, если этот нерв щекотать 130 раз в секунду, то мы «услышим» ноту «до». Есть несколько разных алгоритмов, которые превращают данные с микрофона в частоты. Самый известный – преобразование Фурье . Принцип работы таков: на вход подаётся с какой силой воздух давил на микрофон в каждый момент времени. На выходе – сколько какой частоты содержалось. Его работу проще всего объяснить картинкой: Так можно было бы реализовать распознание нот. В каждый момент времени определять, какая из частот громче всего. Если она совпадает с ожидаемой, переходить к распознанию следующей ноты или открыть замок, если мелодия кончилась. Однако, мы пойдём другим путём. Знать, какие именно ноты играют, нам не обязательно. Надо лишь узнать, играет ли в данный момент та нота, которую мы ожидаем. На помощь приходит алгоритм Гёрцеля . Этот алгоритм используется в телефонии, когда надо определить тональный сигнал. Суть проста: алгоритму дают искомую частоту и данные с микрофона, а он отвечает, какова «громкость» искомой частоты. На реализацию алгоритма можно взглянуть в файле . Я остановился на довольно стандартных компонентах. Вот, что мне пригодилось: ATMega328P
с кристаллом на 16Mhz – «мозг» устройства. Выбор пал именно на него, поскольку уж больно просто с ним работать. Электретный микрофон
с усилителем OPA344
– эти два устройства продавались комплектом на одной плате на сайте Sparkfun . Данные с этого устройства можно считывать прямо с аналогового входа микроконтроллера. Выключатель TPS2020
– это отличный выключатель с очень низким энергопотреблением в выключенном состоянии (10 μA). Он будет управлять питанием серво. Регулятор LM2936Z
– линейный регулятор на 3.3V с небольшим током в рабочей точке (≤ 15 μA). То, что надо для нашего устройства, которое будет питаться от батарейки. Зарядное устройство MAX1555
– чип, который управляет зарядкой батарейки и мигает лампочкой, когда батарейка полна. Ничего особо сложного в схеме устройства нет. можно найти полную схему. А вот упрощённая схема, которая поясняет, какие компоненты при чём: Довольно интересным делом оказалось скомпоновать плату так, чтобы она уместилась в небольшую коробку. Поскольку я решил делать всё сам, дома, варианты с многослойной платой не подходили. Поэтому пришлось придумать фейк многослойной платы: устройство состоит из двух уровней, которые соединяются как шилды для Arduino. Получилось что-то подобное: Синие соединения – те, что будут на самой плате. Красные – те, что будут добавлены позже, либо шилдиковыми коннекторами, либо проводами поверх платы. Я решил использовать фоторезистивный метод создания. Я его описывал на хабре , так что лишь приведу пару фоток. Печатаем схему на прозрачной плёнке и выпиливаем основу для платы: Плата до лужения и проделывания отверстий: Платы с одной стороны: Платы с другой стороны: Собранные платы: С другой стороны: Шкатулка состоит из самой шкатулки и стенок, окружающих схему и моторчик. Я решил купить неотделанную шкатулку , чтобы самому покрыть её краской и лаком. Стенки и вспомогательные детали я заказал на сайте Ponoko : им можно послать чертёж в SVG, а они вырежут её лазером на тонкой фанерке. Чертёж можно найти . Вот, как выглядит этот чертёж и его реализация: Плюс три недели: После того как эти части были интегрированы в шкатулку, получилось так: Теперь можно окрасить шкатулку и покрыть её лаком. Я нанёс два слоя краски и два слоя лака, чтоб на века. Пожалуй, ничего особо сложного в этом процессе нет. Разве что шкурить дерево надо очень качественно: места, где схалтурил отчётливо видны. Вот что получилось: Механизм замка выглядит вот так: В результате схема отлично поместилась в шкатулку: Я отнёс поделку к нескольким своим знакомым: правильная мелодия распознаётся на разных фортепиано: и на электронных пианино, и на обычных пианино, и на рояле. Точность распознавания: полтона. Исходный код контроллера, схему и чертёж платы можно найти на . Я буду рад ответить на любые вопросы, выслушать критику и предложения.
Рис. 4. Собранная схема музыкальной шкатулки
Рис. 5. Сундучок - корпус музыкальной шкатулки
Рис. 6. Устанавливаем схему музыкальной шкатулкив корпус
Что получилось
Распознание мелодии
Устройство, которое распознаёт ноты, старается понять, сколько раз в секунду ему «щекотали» микрофон и какая получилась частота (и, стало быть, нота). Переход от частоты к ноте – штука простая, есть таблица «частота → нота» .Выбор компонентов
Схема
Создание платы
Создание шкатулки
Результат