工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Manufacturing Technology >> 製造プロセス

RGB 32バンド オーディオスペクトラムビジュアライザー - Arduino LEDマトリックスプロジェクト

必要な部品と材料

部品 数量
Arduino Nano R3 1
WS2812B 8×32 RGB LEDマトリックス 1
抵抗 4.75kΩ 3
抵抗 100kΩ 2
抵抗 10kΩ 1
スルーホール抵抗 390Ω 1
コンデンサ 100nF 2
コンデンサ 1000µF 1
SparkFun プッシュボタンスイッチ 12mm 1
4×6cm マルチホール試作基板 1

必要な工具と機械

プロジェクト概要

このプロジェクトについて

Arduino Nanoと8×32 WS2812B RGB LEDマトリックスを使用して、32バンドのオーディオ(音楽)周波数スペクトラムをRGBで可視化するプロジェクトです。

元になったオリジナルプロジェクト

Shajeeb氏による、MAX72xx LEDマトリックスベースのオリジナルプロジェクト「32-Band Audio Spectrum Visualizer Analyzer」に感謝します。私はLEDマトリックス駆動部分のみを修正し、RGB WS2812B LEDマトリックスに対応させました。

WS2812B RGB LEDマトリックスについて

5050 SMD高輝度LEDベースのRGB LEDマトリックスを使用する場合、外部電源が必要です。1LEDあたり10mA以上消費するため、全LEDを最大輝度で点灯させると2.5A以上を消費する可能性があります。

このため、+5Vラインにダイオードを直列挿入し、USBケーブル未接続時にArduinoをスタンドアロンで動作させられるようにし、ArduinoがRGBマトリックスの電源にならないよう保護しています(供給不能な大電流から内部回路を守るため)。

オリジナルプロジェクトに加え、LEDマトリックス入力を電圧スパイクから保護するため、ArduinoピンD6とデータ入力の間に390Ω抵抗を直列挿入し、Arduino電源電圧の安定化のため1000µF 12Vコンデンサを追加しました。

ハードウェア組み立て

メイン写真の通り、最初のプロトタイプは4×6cmのマルチホール基板上に構築しました。2つのRCAオーディオソケットを基板に直接はんだ付け(3.5mmメスジャックソケットに置き換え可能)。ハムノイズを防ぐため、音源とボードの音声入力間はシールドケーブルで接続することが重要です。また、ArduinoとLEDマトリックス間の接続はできるだけ短く保つことを推奨します。

コードについて

ソフトウェア全体は、FFTライブラリを用いたサンプリング手順の作者と、それを完成させたShajeeb氏の素晴らしい仕事に基づいています。

私は以下の2つの関数を追加しました:

  1. GetLedFromMatrix(...): マトリックスを行と列にマッピングし、256個のLEDを行・列座標でアドレッシング可能にする関数
  2. SetColumn(...): オーディオデジタイズで得られたピーク値(0〜7)と、2次元配列でプリセットされた色に基づき、各列のLEDを点灯させる関数。色の値を変更して好みの配色にカスタマイズ可能です。Adafruit NeoPixelライブラリのデモから採用したWheel()サブルーチン(0〜255の値から32bitカラー値を生成)を使用し、setPixelColorに直接渡せるようにしています。メモリ制約を考慮し、32bit変数でRGB値を保持するのは避けるべきです。

オーディオイコライゼーション

PCマザーボード内蔵サウンドカードからの音声でテストしたところ、低域が強く高域が弱いため、32要素のバイト配列 eq[32] でイコライゼーションカーブを定義し、低域を減衰・高域を強調するようにしました。不要な場合は EQ_ON を false に設定するか、eq[32] の32値を変更して調整可能です。値100で変化なし、100未満で減衰、100超で強調されます。

LED輝度

マトリックス輝度はコード内で32(BRIGHTNESS定数)にプリセットされています。WS2812Bの理論上の最大輝度は255ですが、100を超えると白色が薄黄色になってしまいます。これはマトリックスへの給電が右側コネクタのみのためと思われ、中央の赤黒ワイヤーからも給電すれば改善する可能性があります。現在検証中です。

輝度64なら1A電源で十分ですが、それ以上なら2A電源が必須です。

今後のアップデート予定

現在は OpenMusicLabs FHT ライブラリを使用した新バージョンを開発中です。Arduino FFTより何倍も高速に動作します。お楽しみに!

※拙い英語で恐縮です。Google翻訳を使用しました。

コード: Spectrum_Analyzer_WS2812B.ino

/* Copyright (c) 2019 Shajeeb TM
 * MIT License
 * WS2812B LED Matrix version by Janux
 */
#include <arduinoFFT.h>
#include <SPI.h>
#include <Adafruit_NeoPixel.h>

#define SAMPLES 64             // 2の累乗であること
#define xres 32                // 表示列数(SAMPLES/2以下)
#define yres 8                 // 表示行数
#define ledPIN 6               // LEDマトリックス制御ピン
#define NUM_LEDS (xres * yres) // 総LED数 = 256
#define BRIGHTNESS 32          // 輝度(0-255)
#define buttonPin 5            // 表示色切替ボタンピン

byte yvalue, displaycolumn, displayvalue;
int peaks[xres];
byte state = HIGH, previousState = LOW;
byte displaycolor = 0;

double vReal[SAMPLES];
double vImag[SAMPLES];
byte data_avgs[xres];
arduinoFFT FFT = arduinoFFT();

unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 100;

Adafruit_NeoPixel pixel = Adafruit_NeoPixel(NUM_LEDS, ledPIN, NEO_GRB + NEO_KHZ800);

// イコライザーフィルター:低域減衰・高域強調(PC内蔵サウンドカード対策)
bool EQ_ON = true; // falseで無効化
byte eq[32] = {50, 55, 60, 70, 75, 80, 85, 95, 100, 100, 100, 100, 100, 100, 100, 100, 
               100, 100, 100, 100, 100, 100, 100, 100, 115, 125, 140, 160, 185, 200, 225, 255 };

// 表示色プリセット(Wheel関数で変換、0はカスタム色用)
byte colors[][8] = {
  {170, 160, 150, 140, 130, 120, 1, 1},
  {1, 5, 10, 15, 20, 25, 90, 90},
  {90, 85, 80, 75, 70, 65, 1, 1},
  {90, 90, 90, 30, 30, 30, 1, 1},
  {170, 160, 150, 140, 130, 120, 0, 0},
  {170, 160, 150, 140, 130, 120, 1, 1},
  {170, 160, 150, 140, 130, 120, 1, 1}
};

void setup() {
  pixel.begin();
  pixel.setBrightness(BRIGHTNESS);
  // ADCフリーランニングモード、プリスケーラ32設定
  ADCSRA = 0b11100101; // 0xE5
  ADMUX = 0b00000000;  // A0ピン使用、外部基準電圧
}

void loop() {
  // サンプリング
  for (int i = 0; i < SAMPLES; i++) {
    while (!(ADCSRA & 0x10)); // ADC変換完了待ち(ADIFビット)
    ADCSRA = 0b11110101;      // ADIFクリア(0xF5)
    int value = ADC - 512;    // DCオフセット除去
    vReal[i] = value / 8;     // 圧縮して格納
    vImag[i] = 0;
  }

  // FFT処理
  FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
  FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
  FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);

  // FFT結果を表示列数(xres)に再配列
  int step = (SAMPLES / 2) / xres;
  int c = 0;
  for (int i = 0; i < (SAMPLES / 2); i += step) {
    data_avgs[c] = 0;
    for (int k = 0; k < step; k++) {
      data_avgs[c] += vReal[i + k];
    }
    data_avgs[c] /= step;
    c++;
  }

  // 表示処理
  for (int i = 0; i < xres; i++) {
    if (EQ_ON) data_avgs[i] = data_avgs[i] * (float)(eq[i]) / 100; // EQ適用
    data_avgs[i] = constrain(data_avgs[i], 0, 80);
    data_avgs[i] = map(data_avgs[i], 0, 80, 0, yres); // 0-8行にマッピング
    
    yvalue = data_avgs[i];
    peaks[i]--; // ピーク減衰
    if (yvalue > peaks[i]) peaks[i] = yvalue; // ピーク保持
    yvalue = peaks[i];
    
    displaycolumn = i;
    displayvalue = yvalue;
    setColumn(displaycolumn, displayvalue);
  }
  pixel.show();
  displaycolorChange(); // ボタンチェックで色モード切替
}

// 指定列(x)のLEDを値(y)に応じて点灯
void setColumn(byte x, byte y) {
  byte led, i;
  for (i = 0; i < yres; i++) {
    led = GetLedFromMatrix(x, i);
    if (peaks[x] > i) {
      switch (displaycolor) {
        case 4: // 配列値0でピーク色カスタマイズ
          if (colors[displaycolor][i] > 0) {
            pixel.setPixelColor(led, Wheel(colors[displaycolor][i]));
          } else {
            pixel.setPixelColor(led, 255, 255, 255); // 白色でピーク表示
          }
          break;
        case 5: // 列ごとに色変更
          pixel.setPixelColor(led, Wheel(x * 16));
          break;
        case 6: // 行ごとに色変更
          pixel.setPixelColor(led, Wheel(i * 36));
          break;
        default: // displaycolor 0-3: 配列定義色
          pixel.setPixelColor(led, Wheel(colors[displaycolor][i]));
      }
    } else {
      pixel.setPixelColor(led, 0); // 消灯
    }
  }
}

// 座標(x,y)からLED番号を計算(蛇行配置、入力コネクタ右側、右下が0番)
byte GetLedFromMatrix(byte x, byte y) {
  x = xres - x - 1;
  if (x & 0x01) { // 奇数列は逆順
    return ((x + 1) * yres - y - 1);
  } else { // 偶数列は正順
    return ((x + 1) * yres - yres + y);
  }
}

// ボタンで表示色モード切替(デバウンス付き)
void displaycolorChange() {
  int reading = digitalRead(buttonPin);
  if (reading == HIGH && previousState == LOW && millis() - lastDebounceTime > debounceDelay) {
    displaycolor++;
    if (displaycolor > 6) displaycolor = 0;
    lastDebounceTime = millis();
  }
  previousState = reading;
}

// Adafruit NeoPixelデモからのユーティリティ: 0-255からカラー値生成(R→G→B→R遷移)
unsigned long Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if (WheelPos < 85) {
    return pixel.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if (WheelPos < 170) {
    WheelPos -= 85;
    return pixel.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return pixel.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

カスタムパーツとエンクロージャ

3Dプリント用ファイルと設計データ: arduino_rgb_audio_analyzer_lX4Dv4Pta2.zip

回路図

回路図はプロジェクトページに掲載されています。

製造プロセス

  1. 32バンドArduinoオーディオスペクトラムアナライザー:リニア&疑似ログ表示対応
  2. スマート渇きアラート植物アラーム – 最適な水やりタイミングを知らせるDIYセンサー
  3. イタリア語ワードクロック自作:Arduino Nano、NeoPixel、LCD、RTCで時刻を文字で表示
  4. Arduino MKR Fox 1200で作る信頼性の高いSigfox kWhメーター
  5. Bluetooth対応温度モニター:Arduino NanoとHC-06でスマホ監視
  6. 非接触ジェスチャー錠: APDS-9960とArduinoでセキュアアクセス
  7. Arduino Nanoコンパニオンキット – 電子工作に必須の部品とツールを搭載した多機能IC型デバイス
  8. Arduino Micro/Leonardo用 USB-MIDIアダプタキット – 完全パーツリストと実装ガイド
  9. Arduino用絶縁アナログ入力回路の設計:LM331 V-F変換+フォトカプラでノイズ耐性を確保
  10. 抵抗2本だけで作るArduino UNO用TV出力ケーブル (RCA/コンポジット)
  11. Arduino UNOで作る精密反応速度テスター