[Из песочницы] LED RGB куб 4x4x4 для визуализации музыки

В данной статье мы расскажем об опыте сборки куба 4×4x4 на RGB-светодиодах, а также о разработке программного обеспечения, необходимого для использования куба в качестве визуализатора звука. Используется микроконтроллер Arduino Uno.

image


Подготовка


Куб
При исследовании подобных проектов была обнаружена реализация под названием «Чарликуб» («Charliecube») за авторством Эшера Глика (Asher Glick) и Кевина Бэйкера (Kevin Baker). Данный вариант примечателен тем, что, в отличие от других реализаций, не предусматривает наличие счётчиков, регистров сдвига либо каких-либо других компонентов для построения куба с целью его последующего программирования и задействует только 16 выводов микроконтроллера (позволяя при этом адресовать 64 светодиода). В основе этой реализации лежит конструкция светодиодной индикации под названием «Чарлиплексинг».Чарлиплексинг
Цифровые выводы микроконтроллеров имеют трёхзначную логику: присоединён к питанию, присоединён к «земле» и не посоединён ни к чему. Если нам надо зажечь светодиод, необходимо подать »+» на X и »-» на «Y», только в таком случае он будет гореть. Если на Y ничего не подавать, до светодиод не загорится. Подробнее о методе можно почитать в одноимённой статье на Википедии, ниже приведено описание работы конкретно в нашем случае.

image


схема столбика светодиодов

Предположим, что мы хотим зажечь LED1 зелёным цветом. Если проследить по синей линии, видно, что необходимо подать »+» на вход 1. Проследив за красной линией, понимаем, что нужно подать »-» на вход 3. На остальные входы ничего не подаётся.

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

Поскольку у авторов проекта большой опыт работы с Ruby, в рамках проекта хотелось прибегнуть именно к этому языку программирования. Была обнаружена статья Дэвида Гутмана (David Guttman), описывающая визуализацию звука на JRuby с помощью гема ruby-processing и java-библиотеки Minim. Найденная статья была взята за основу для написания визуализатора.

Сборка


Собираем столбик

image

Перед соединением светодиодов в столбец необхобходимо в каждом из четырёх светодиодов выгнуть ноги так, чтобы каждая нога составляла с с соседней 90°.

imageimage

Затем каждый из светодиодов нужно вращать поочерёдно на 90° (каждый последующий должен быть повёрнут на 90° по часовой стрелке по отношению к предыдущему). Предварительно одну из ног можно пометить (у нас она помечена зелёным лаком), чтобы не запутаться.

imageimage

Соединяем наши светодиоды в столбик. После соединения светодиодов обрезаем выступающие концы ног.

imageimageimage

imageimage

Размещаем столбики
Оставшиеся 15 столбиков собираются аналогичным образом.

image

Столбики расставляются на плате на одинаковом расстоянии друг от друга, формируя таким образом куб со стороной, равной 4 светодиодам. Все столбики должны быть повёрнуты в одинаковом направлении (тут очень пригодится предварительная маркировка «опорной» ноги).

imageimage

imageimage

Соединяем столбики между собой
Переворачиваем конструкцию и начинаем присоединять провода. Всего проводов 16, соединение проводилось в 4 этапа.

imageimage

imageimage

imageimage

imageimage

image

Осталось подключить к Arduino — и можно приступать к программированию.

Подключаем к Arduino
Авторы Чарликуба предусмотрели библиотеку cubeplex для удобного программирования куба с Arduino. Для того, чтобы данную библиотеку можно было использовать без модификаций, необходимо подключать наши провода в следующем порядке (нумерация соответствует проводам на изображениях из предыдущего раздела):

imageimage

Программируем Arduino


Базовый функционал
Как было сказано выше, авторы воспользовались библиотекой charlieplex, которая предоставляет функцию drawLed (), принимающая цвет и позицию светодиода в координатах XYZ.

Подсветить весь кубик красным цветом
#include "cubeplex.h"

const int cubeSides = 4;

void setup() {
  initCube();
}

void loop() { 
  for (int xpos = 0; xpos < cubeSides; xpos++) {
    for (int ypos = 0; ypos < cubeSides; ypos++) {
      for (int zpos = 0; zpos < cubeSides; zpos++) {
          drawLed(red, xpos, ypos, zpos);
      }
    }
  }
}



Обмен сообщениями с ПК
Обмен сообщениями реализуется посредством последовательного ввода-вывода в порт, через который контроллер соединяется с машиной. Работа с такими событиями реализована в Arduino через SerialEvent.

Выборочная подсветка куба с вводом пользователя
#include "cubeplex.h"

String inputString = "";         
boolean stringComplete = false;

// Ввод каждого символа в порт сопровождается вызовом SerialEvent, который накапливает введённые символы в строку inputString.
// Как только пользователь вводит Enter, меняется значение флага inputComplete и выполняется дальнейший код из loop().

int color = red;

void setup() {
  Serial.begin(9600);
  inputString.reserve(200);
  initCube();
}

void loop() {
  if (stringComplete) {
      Serial.println(inputString);
      drawString(inputString);
      resetBuffer();
      inputString = "";
      stringComplete = false;
    }
  }
}

void serialEvent() {
  while (Serial.available()) {
    char inChar = (char)Serial.read();
    inputString += inChar;
    if (inChar == '\n') {
      stringComplete = true;
    }
  }
}

// Очистка буфера куба; перед последующей подсветкой диодов куб полностью погаснет.
void resetBuffer() {
  flushBuffer();
  clearBuffer();
}

// Закодируем три кординаты светодиода трёмя цифрами.
// Каждая координата - каждые три символа из строки, которая пришла в порт.
// То есть строка "000001002003" подсветит столбик с координатами { x: 0, y: 0 }.

void drawString(String inputString) {
  int xpos = -1;
  int ypos = -1;
  int zpos = -1;

  for (int i = 0; inputString[i + 3]; i += 3) {
    xpos = charToInt(inputString[i]);
    ypos = charToInt(inputString[i + 1]);
    zpos = charToInt(inputString[i + 2]);

    drawLed(color, xpos, ypos, zpos);
  }
}

void charToInt(char value) {
  return (value - '0');
}



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

Подсветка заданного количества слоёв
void drawBeat(String inputString) {
  int height = charToInt(inputString[0]);
  int color = random(red, white);

  for (int xpos = 0; xpos < cubeSides; xpos++) {
    for (int ypos = 0; ypos < cubeSides; ypos++) {
      for (int zpos = 0; zpos < height; zpos++) {
          drawLed(color, xpos, ypos, zpos);
      }
    }
  }
}



Анализ звука на JRuby


В набор библиотеки Minim входит класс BeatDetect, который предоставляет инструменты для определения ритма музыки. Вообще с помощью этой библиотеки предельно просто подключиться к каналу приёма звука и произвести его частотный анализ. Для наших целей подошёл частотный метод определения ритма.
Код тестировался на Ubuntu 15.10; версия JRuby, использованная авторами — jruby 9.0.5.0. Для запуска скрипта необходимо установить Processing и подключить библиотеку Minim.

Анализ ритма
require 'ruby-processing'

require_relative 'translator'
require_relative 'serial_writer'

class SoundProcessor < Processing::App
  load_library "minim"
  import "ddf.minim"
  import "ddf.minim.analysis"

  def setup
    @minim = Minim.new self
    @input = @minim.get_line_in
    @beat = BeatDetect.new @input.mix.size, 44100
    @beat_value = 0.001
    @beat.set_sensitivity 300
  end

  def draw
    process_beat
    SerialWriter.instance.write(Translator.instance.translate(@beat_value))
  end

  private

  def process_beat
    @beat.detect @input.mix
    @beat_value = @beat.is_kick ? 1 : @beat_value * 0.95
  end
end

SoundProcessor.new


Демонстрация работы


Средствами PulseAudio визуализатору в качестве audio input был присвоен audio output, т.е. получаем визуализацию всего звука, который у нас идёт из динамиков. После записи на видео был наложен звук, который воспроизводился в момент создания ролика.

Посесловие


Нам удалось получить визуализатор звука в связке с пк. В дальнейшем можно улучшить алгоритм определения ритма (стандартные средства определения ритма библиотеки Minim далеки от идеала), также на куб можно выводить информацию о частотах. Как видите, куб несложен в построении и программировании; кроме того, он задействует минимум компонентов.

Ссылки:

Авторы
Макоед Виктор и Евгений Куница, студенты 3 курса БГУиР ВМСиС

© Geektimes