Описание
В этом уроке мы сделаем музыкальную шкатулку на основе Raspberry Pi и Flash-I2C модулей Бампер с 9-ю датчиками линий, Мотор-редуктор с управляющим контроллером и Энкодер. Мотор будет крутить барабан с нарисованными от руки нотами, датчики линий будут регистрировать наличие нот, а Raspberry PI будет проигрывать соответствующие звуки.
Видео
Нам понадобится
Аппаратная часть
- Raspberry Pi
- Набор Сделай сам - "Музыкальная шкатулка"
- Trema+Expander Hat
- i2C HUB
- Бампер с 9-ю датчиками линий, FLASH-I2C
- Мотор-редуктор с управляющим контроллером, FLASH-I2C
- Энкодер, потенциометр, FLASH-I2C
Программная часть
- Библиотека pyfluidsynth
- Файл - звуковой шрифт (soundfont)
- Библиотека pyiArduinoI2Cbumper
- Библиотека pyiArduinoI2Cmotor
- Библиотека pyiArduinoI2Cencoder
Подключение
Перед подключением необходимо установить адреса модулей.
В нашем случае это адреса 0x0a
для модуля Бампер, 0x0b
для модуля Мотор и 0x0c
для модуля Энкодер в шестнадцатеричной системе счисления.
- Подробнее про установку адресов модулей с технологией Flash-i2C
- Смена адреса Бампера на шине I2C
- Смена адреса Мотора на шине I2C
- Смена адреса Энкодера на шине I2C
Установка библиотек
Откроем эмулятор терминала
Для проекта понадобится установить библиотеки pyfluidsynth
,pyiArduinoI2Cbumper
и pyiArduinoI2Cmotor
в уже существующую или новую виртуальную среду
Введём строку ниже в окно терминала и нажмём <enter>
pip install pyiArduinoI2Cbumper pyiArduinoI2Cmotor pyiArduinoI2Cencoder pyfluidsynth
Подробнее об установке библиотек можно узнать в этой статье.
Cкрипт проекта
Скрипт можно запустить из эмулятора терминала, сохранив его в файл например под названием musicbox.py
, командой python musicbox.py
или скопировать содержимое скрипта в программу Thonny Python IDE и запустить его там. В Thonny IDE так же необходимо настроить виртуальную среду и установить в ней вышеперечисленные библиотеки. Подробнее об установке библиотек можно узнать в этой
статье.
font = synth.sfload('/home/pi/Downloads/soundfont.sf2'
Для написания скриптов мы будем использовать рекомендованный Raspberry Pi Foundation редактор Thonny Python IDE. Для запуска нажмём на кнопку меню в правом верхнем углу, затем Программирование->Thonny Python IDE:
Откроется редактор, можем приступать к написанию скриптов:
Для работы с модулей необходимо включить шину I2C.
Ниже приведён универсальный скетч, который позволяем менять инструменты нажатием на кнопку энкодера, а также изменять скорость вращения барабана. Помимо этого, в конце статьи вы найдёте уже готовые ленты для барабанов с записанными мелодиями и скетчи к ним, в которых настроены необходимые инструменты.
# Подключаем библиотеки import fluidsynth from pyiArduinoI2Cbumper import * from pyiArduinoI2Cmotor import * from pyiArduinoI2Cencoder import * from time import sleep # Адреса модулей i2c BUM_ADDRESS = 0x0a MOT_ADDRESS = 0x0b ENC_ADDRESS = 0x0c # Диапазон энкодера ENC_RANGE = 2 #Начальная скорость мотора (ШИМ) MOT_SPEED = 6 # Константы с номерами инструментов SOLO = [76, 55, 31, 25, 1, 8, 42, 56, 82] BASS = 37 BANK = 0 # Константы дорожек инструментов BASS_TRACK = 0 SOLO_TRACK = 1 # Константы динамики инструментов BASS_VEL = 127 SOLO_VEL = 90 # Констаната разделения инструментов по датчикам SPLIT = 5 # Создаём объект бампера bum = pyiArduinoI2Cbumper(address = BUM_ADDRESS, bus = "/dev/i2c-3") # Создаём объект мотора mot = pyiArduinoI2Cmotor(address = MOT_ADDRESS, bus = "/dev/i2c-3") # Создаём объект энкодера enc = pyiArduinoI2Cencoder(address = ENC_ADDRESS, bus = "/dev/i2c-3") # Устанавливаем диапазон энкодера enc.setPosSettings(ENC_RANGE) # Создаём объект синтезатора synth = fluidsynth.Synth() # Включаем синтезатор, указывая драйвер synth.start(driver='alsa') # Подключаем файл звукового шрифта. # Если файл шрифта не лежит в одной папке # с этим скриптом, укажите абсолютный путь здесь font = synth.sfload('soundfont.sf2') # Выбираем программу синтезатора для каждого инструмента # Полный список названий General Midi звуков - # https://soundprogramming.net/file-formats/general-midi-instrument-list/ synth.program_select(BASS_TRACK, font, BANK, BASS) synth.program_select(SOLO_TRACK, font, BANK, SOLO[0]) # Гамма для проигрывания (в данном случае пентатоника Ля-минор) # Цифры - ноты по номенклатуре MIDI, где 60 - нота ДО малой октавы scale = [ 81, 78, 76, 74, 71, 33, 31, 28, 26 ] # Список проигрываемых нот is_playing = [False] * len(scale) # Индекс для списка с тембрами index = 0 try: # Запускаем мотор mot.setSpeed(MOT_SPEED, MOT_PWM) # Считываем положение энкодера p = enc.getPosition() while True: # Считываем положение энкодера в бесконечном цикле new_p = enc.getPosition() # Если положение энкодера изменилось: if p != new_p: p = new_p # меняем скорость мотора mot.setSpeed(p, MOT_PWM) # Если кнопка была нажата и отпущена if enc.getButton(KEY_RELEASED): # Приращиваем индекс для списка с тембрами index += 1 # Проверяем диапазон списка с тембрами if index >= len(SOLO): index = 0 # Меняем инструмент на следующий списка с тембрами synth.program_select(SOLO_TRACK, font, BANK, SOLO[index]) # Читаем состояние всех датчиков линий readall = bum.getLineDigital(BUM_LINE_ALL) for i in range(len(scale)): # Если бит датчика установлен if readall & (1 << i + 1): track = 0 track_vel = 100 # Выбор инструмента if i < SPLIT: # Соло track = SOLO_TRACK track_vel = SOLO_VEL else: # Бас track = BASS_TRACK track_vel = BASS_VEL # Если нота ещё не играет if is_playing[i] == False: # играем ноту synth.noteon(track, scale[i], track_vel) # Устанавливаем, что нота уже играет is_playing[i] = True else: track = 0 # Выбор инструмента if i < SPLIT: # Соло track = SOLO_TRACK else: # Бас track = BASS_TRACK # Выбор ноты if is_playing[i] == True: # Выключаем ноту synth.noteoff(track, scale[i]) # Устанавливаем, что нота больше не играет is_playing[i] = False # Если выполнения скрипта прервано - посылаем сигнал закончить все ноты # и остановить мотор except: for i in scale: synth.noteoff(BASS_TRACK, i) synth.noteoff(SOLO_TRACK, i) mot.setSpeed(0, MOT_PWM)
Настройка автозапуска
Если есть необходимость запускать скрипт при загрузке Raspberry OS - то необходимо добавить путь к скрипту в файл /etc/rc.local
(текстовый редактор должен быть запущен от имени суперпользователя) и установить все библиотеки от имени суперпользователя. Для этого необходимо установить их с командой sudo
. Например sudo pip3 install pyiArduinoI2Cbumper pyiArduinoI2Cmotor
.
Пример файла rc.local
для автозапуска скрипта проекта. Путь к скрипту проекта должен быть указано до exit 0
.
#!/bin/sh -e # # rc.local # # Этот скрипт запускается в конце загрузки любого многопользовательского режима. # Скрипт должен заканчиваться строчкой "exit 0" при успешном завершении # или с кодом ошибки в ином случае # # Для включения или выключения скрипта достаточно установить биты # разрешений. Например: # Не запускать скрипт "sudo chmod -x /etc/rc.local" # Запускать скрипт "sudo chmod +x /etc/rc.local" # # Вывести IP адрес _IP=$(hostname -I) || true if [ "$_IP" ]; then printf "My IP address is %s\n" "$_IP" fi # Запустить скрипт музыкальной шкатулки python3 /home/pi/Python/musicbox.py exit 0
Обсуждение