Órgão de Luz com Arduino DUE

Órgão de Luz com Arduino DUE Deixe um comentário

Neste artigo vamos utilizar a capacidade computacional de um Arduino Due e a flexibilidade dos LEDs RGB endereçáveis (em um painel 4×4) para apresentar efeitos visuais baseados nas frequências do som capturado por um microfone e assim, construir um órgão de luz.

Um órgão de luz (ou órgão de cores) é um dispositivo que gera efeitos visuais a partir de um sinal sonoro. É uma ideia que remonta ao século XVIII. Inicialmente estes dispositivos eram mecânicos, depois passaram a ser eletromecânicos e finalmente eletrônicos (sendo bastante populares nos anos 70).

Material necessário

Como alternativa ao Sensor de Som Groove ou KY-038, você pode montar um sensor com os seguintes componentes:

  • Microfone de eletreto
  • Transistor 2N3904
  • Resistores de 10K, 15K e 470K (um de cada)
  • Capacitor eletrolítico 1uF x 16V
  • Protoboard

Importante: O sensor de som para este projeto precisa fornecer uma saída analógica. O projeto não vai funcionar com um sensor que forneça uma saída digital. 

Montagem do circuito do Órgão de Luz

A montagem consiste em ligar ao DUE o sensor de som (em uma entrada analógica) e o painel de LEDs (em uma saída digital):

Esquemático do projeto órgão de luz

A figura acima mostra o Sensor de Som de Groove, se você for usar o Sensor de Som KY-038, você deve ligar o sinal A0 do sensor ao pino A0 do Arduino, o pino + ao 3V3 do Arduino e o pino G ao GND do Arduino.

Se você optou por montar o seu próprio sensor de som, siga as figuras abaixo:

sensor de som para o órgão de luz

Desenvolvimento

Para entendermos o funcionamento deste projeto precisamos estudar duas coisas: como detectar as frequências presentes em um som e como comandar o painel de LED RGB.

Analisando as Frequências de um sinal: A Transformada Rápida de Fourier (FFT)

Um sinal analógico elétrico (como um som) é normalmente visto como uma tensão variando com o tempo (neste exemplo vamos considerar que a tensão está em V e o tempo em milissegundos):

Entretanto, ele pode também ser visto como a soma de sinais senoidais de frequência e amplitude (intensidade) diversas (no caso um senóide com amplitude 10 e frequência 100Hz somada a outra com amplitude 20 e frequência 50Hz) :

Esta segunda forma pode ser apresentada graficamente com as frequências na horizontal e a amplitude na vertical:

A Transformada Rápida de Fourier é um algoritmo que determina as frequências e intensidades correspondentes a sinal que foi amostrado periodicamente. É um assunto matematicamente complexo e que ainda é objeto de estudos atualmente.

Felizmente já temos bibliotecas prontas para realizar a FFT. A que vamos usar aqui pode ser instalar diretamente na IDE do Arduino:

Existem dois parâmetros da amostragem que impactam na análise da frequência: a quantidade de amostras (SAMPLES) e a frequência com que as amostras são feitas (SAMPLE_FREQ). O resultado da FFT são SAMPLES/2 valores que correspondem à amplitude das frequências múltiplas de SAMPLE_FREQ/SAMPLES. Por exemplo, se usarmos SAMPLES=16 e SAMPLE_FREQ=8000Hz, a FFT retornará as amplitudes para 500, 1000, 1500, 2000, 2500, 3000, 3500 e 4000 Hz. O valor de SAMPLES precisa ser uma potência de 2. Quanto maior a frequência de amostragem, maior a frequência máxima analisada. Quanto maior a quantidade de amostras, maior a precisão.

A FFT é um algoritmo bastante exigente em termos de capacidade de processamento e memória. Por isso estamos usando um DUE, que tem um processador ARM rodando a 84MHZ e com 96K de memória RAM.

Controlando o Painel de LEDs RGB

Os LEDs RGB endereçáveis são LEDs capazes de apresentar uma quantidade muito grande de cores e que podem ser ligados sequencialmente. A nossa aplicação envia uma sequência de valores de intensidade de vermelho, verde e azul para o primeiro LED, ele acende conforme o primeiro conjunto da sequência e passa o restante para o LED seguinte, que repete o processo. Esta sequência precisa ser enviada com a formatação e tempos definidos pelas especificações do controlador embutido em cada LED (no caso o WS2812).

Portanto, controlar as cores de um painel de LEDs consiste em montar esta sequência de valores e a enviar por um pino digital com os tempos corretos. Novamente contamos com uma biblioteca pronta para a segunda parte, a Adafruit NeoPixel:

A última informação que precisamos é saber a ordem dos LEDs no painel:

leds para o órgão de luz

Código para o Órgão de Luz

O laço principal do código a seguir é composto de três partes:

  • A amostragem do som, armazenando o resultado no vetor vReal.
  • A análise das amostras, usando o FFT, atualizando vReal com as amplitudes calculadas.
  • A escolha da intensidade dos LEDs conforme o resultado da análise

Por simplificação, neste projeto estamos considerando apenas 3 frequências (“graves”, “médios” e “agudos”) como base para a escolha da intensidade dos LEDs. A rotina conv converte a intensidade do som na intensidade do LED, ela foi feita empiricamente para realçar as variações de intensidade do som observadas nos testes.

/*
 * Órgão de Luz - Efeitos visuais em um painel 4x4 de LEDs RGBs
 *                conforme as frequências captadas com um microfone
 */
#include "arduinoFFT.h"
#include <Adafruit_NeoPixel.h>

const int AMOSTRAS = 128; // número de amostras, precisar ser potência de 2
const int SAMPLING_FREQUENCY = 16000; // Frequência da amostragem

// Conexões
const int pinLED = 7;   // saída digital ligada ao painel de LEDs
const int pinSOM = A0;  // entrada analógica onde está ligado o sensor de som

// Variáveis para analisar as frequências
arduinoFFT FFT = arduinoFFT();
unsigned int sampling_period_us;
 
double vReal[AMOSTRAS];
double vImag[AMOSTRAS];

// Variáveis para o controle dos LEDs
Adafruit_NeoPixel painel(16, pinLED,  NEO_GRB + NEO_KHZ800);

// Iniciação do programa
void setup() {
    Serial.begin(115200);
    sampling_period_us = round(1000000*(1.0/SAMPLING_FREQUENCY));
    painel.begin();
    painel.show();
}

// Laço eterno
void loop() {
  unsigned long microseconds;
  
  // Amostra o som no intervalo determinado pela frequência de amostragem
  for (int i = 0; i < AMOSTRAS; i++)
  {
      microseconds = micros();
      vReal[i] = analogRead(A0);
      vImag[i] = 0;
      while(micros() < (microseconds + sampling_period_us)){
      }
  }

  // Usa FFT para analisar as amostras
  // Resultado da FFT é a intensidade em AMOSTRA/2 frequências espaçadas
  // de SAMPLING_FREQUENCY/AMOSTRAS
  FFT.Windowing(vReal, AMOSTRAS, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
  FFT.Compute(vReal, vImag, AMOSTRAS, FFT_FORWARD);
  FFT.ComplexToMagnitude(vReal, vImag, AMOSTRAS);
  
  // Mostra os graves nos cantos, em tons de azul
  byte graves = conv(vReal[2]);   // Frequência = 2*125 = 250Hz
  painel.setPixelColor(0, 0, 0, graves);
  painel.setPixelColor(3, 0, 0, graves);
  painel.setPixelColor(12, 0, 0, graves);
  painel.setPixelColor(15, 0, 0, graves);

  // Mostra os médios nas bordas, em tons de verde azulado
  byte medios = conv(vReal[20]);   // Frequência = 20*125 = 2500Hz
  painel.setPixelColor(1, 0, medios, medios/4);
  painel.setPixelColor(2, 0, medios, medios/4);
  painel.setPixelColor(4, 0, medios, medios/4);
  painel.setPixelColor(7, 0, medios, medios/4);
  painel.setPixelColor(8, 0, medios, medios/4);
  painel.setPixelColor(11, 0, medios, medios/4);
  painel.setPixelColor(13, 0, medios, medios/4);
  painel.setPixelColor(14, 0, medios, medios/4);
  
  // Mostra os águdos no centro, em tons de vermelho
  byte agudos = conv(vReal[40]);     // Frequência = 40*125 = 5000Hz
  painel.setPixelColor(5, agudos, 0, 0);
  painel.setPixelColor(6, agudos, 0, 0);
  painel.setPixelColor(9, agudos, 0, 0);
  painel.setPixelColor(10, agudos, 0, 0);

  // Atualiza os LEDs
  painel.show();

  // Dá um tempo entre as amostragens e atualização
  delay(30);
}

// Converte a intensidade do sinal na intensidade do LED
byte conv(double val) {
  if (val < 256) {
    return (byte) (8 + val / 8);
  } else if (val < 1024) {
    return (byte) (40 + val / 16);
  } else if (val < 4864) {
    return (byte) (104 + val / 32);
  } else {
    return 255;
  }
}

Conclusão

Neste projeto aprendemos um pouco sobre como processar um sinal analógico capturado com um microfone e determinar a intensidade das frequências que os compõe. Usamos isso para apresentar efeitos visuais em um painel de LEDs.

órgão de luz com arduino Due

Você pode montar este projeto apenas para curtir as suas músicas preferidas ou experimentar alterar o código para criar os seus próprios efeitos.

E aí? Pretende montar o seu próprio Órgão de Luz? Ajude-nos a melhorar o blog comentando abaixo sobre este tutorial.

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *