不務正業之音樂節奏燈
前幾天在知乎上看到一個音樂節奏燈得帖子,覺得很有意思。就上淘寶買了材料,跟著淘主得視訊做了個LED音樂節奏燈。(我可能是吃飽撐著沒事做)。在此記錄一下製作過程。
本程式程式碼由Scott Lawson編寫,併發布在Github,這個程式碼最後一次更新在2年前。由於相容性問題,由知乎使用者:(英語老師摸我腿)修改,其還有製作教程。感謝各位大佬支援。
工具
1.Arduino
2.Anaconda(Python)
3.PVC管
4.ESP8266開發板
5.LED燈帶(60顆/1米)
6.5V的燈座
7.燈罩
8.杜邦線
9.MicroUSB資料線
實現步驟:
1.
下載並安裝Arduino和Anaconda
2.
在Anaconda中建立Python環境,並命名為MusicLed
3.
在Anaconda的MusicLed環境下Open Terminal安裝一些庫:
conda install numpy scipy pyqtgraph
pip insatll pyaudio
4.
注:最好先連上VPN,不然安裝很容易失敗。
安裝完Arduino,開啟安裝一些庫。
然後點選(工具)-(開發板)-(開發板管理器)-(等它載入完成在搜尋框輸入:ESP8266。只有一個結果直接點選安裝)。
接著點選(專案)-(載入庫)-(管理庫)-(搜尋框輸入websock,安裝的版本為2.1.1)。
5.
注:電腦小白最好安裝Notepad++
修改程式碼:注意以下注釋就好了。只要修改ws2812_controller.ion和config.py兩處的部分註釋程式碼。
6.
修改完兩個程式碼後,就要把arduino程式碼上傳到ESP8266上。
首先把板子插在電腦的USB埠上。
然後檢視裝置管理器中板子在哪個口,例如:CH340(COM3)。
接著點選ws2812_controller.ino進入Arduino,點選(工具)-(開發板)-(SparkFun ESP8266 Thing Eev)-修改埠為(COM3)-(上傳程式碼即可)。
最後點選Strat.bat,看到以下介面說明程式碼基本無誤:
7.
接下來就是組裝節奏燈就好啦。
注:這裡注意燈帶上的箭頭,不要接反了。
如果看不懂上圖可以看這個(靈魂畫手):
這裡將用將兩根杜邦線分別接上5v的紅線與GND,然後用PVC電氣膠布纏繞上即可。
記得用一根杜邦線將ESP8266的RX口和燈帶的DI口連線起來,否則燈帶不會亮。
然後將燈帶纏繞到PVC管上。
最後通電就可以啦。注:燈座的插頭電壓可能不夠導致燈帶亮的時候,ESP板子不通電(分壓)。這時候把充電頭換成手機的快充頭即可給兩個部件同時通電。
節奏燈,程式打開了,燈不亮。PING一下你給ESP8266設定的IP地址,如果通,那說明ESP8266執行正常,請檢查線是否接好,並保證兩個檔案設定正確。關閉PC程式,重新開啟試試。
8.
大家電腦可能沒有混音功能。所以先下載Viocemeeter,點選A1選擇如下圖所示:
然後在(聲音)-(播放)將其設定為預設裝置即可,(錄製)也是如此。
9.
最後(給燈座通上點)-(點選Start.bat)-(開啟Voicemeeter)-(開啟音樂播放器播放音樂即可,當然你直接對著電腦講話也有同樣效果只要是有聲音輸入都行)。
完!
Arduino程式碼
ws2812_controller.ino
/*
* 注意,一定要看到檔案隔壁還有很多字尾名為".h"的檔案,如果沒有的話,那說明當前資料夾下沒有這個檔案。編譯會出錯。
* 參考資料:https://github.com/scottlawsonbc/audio-reactive-led-strip
* 原始碼2年未更新,稍作修改。
* 你只需要修改程式碼後面後中文註釋的地方!
*/
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <WebSocketsServer.h>
#include <Hash.h>
#include <WiFiUdp.h>
#include "ws2812_i2s.h"
#define NUM_LEDS 120 //LED燈數量
#define BUFFER_LEN 1024
#define PRINT_FPS 1
const char* ssid = "zzzzzzzccccccc"; //你家WIFI名字
const char* password = "zcp5313.."; //你家WIFI密碼
unsigned int localPort = 7777;
char packetBuffer[BUFFER_LEN];
static WS2812 ledstrip;
static Pixel_t pixels[NUM_LEDS];
WiFiUDP port;
//你可以使用Windows+R鍵輸入cmd,然後輸入命令ipconfig 檢視自己網路情況。
IPAddress ip(192, 168, 1, 150); //你給ESP8266設定的IP地址,注意,這個IP不可以跟其他裝置(手機電腦燈)重複。
IPAddress gateway(192, 168, 1, 1); //你家網路的閘道器,這個跟你電腦的閘道器一樣
IPAddress subnet(255, 255, 255, 0); //子網掩碼,跟你電腦的一樣,一般不需要修改。
void setup() {
Serial.begin(115200);
WiFi.config(ip, gateway, subnet);
WiFi.begin(ssid, password);
Serial.println("");
// Connect to wifi and print the IP address over serial
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
port.begin(localPort);
ledstrip.init(NUM_LEDS);
}
uint8_t N = 0;
#if PRINT_FPS
uint16_t fpsCounter = 0;
uint32_t secondTimer = 0;
#endif
void loop() {
// Read data over socket
int packetSize = port.parsePacket();
// If packets have been received, interpret the command
if (packetSize) {
int len = port.read(packetBuffer, BUFFER_LEN);
for(int i = 0; i < len; i+=4) {
packetBuffer[len] = 0;
N = packetBuffer[i];
pixels[N].R = (uint8_t)packetBuffer[i+1];
pixels[N].G = (uint8_t)packetBuffer[i+2];
pixels[N].B = (uint8_t)packetBuffer[i+3];
}
ledstrip.show(pixels);
#if PRINT_FPS
fpsCounter++;
#endif
}
#if PRINT_FPS
if (millis() - secondTimer >= 1000U) {
secondTimer = millis();
Serial.printf("FPS: %d\n", fpsCounter);
fpsCounter = 0;
}
#endif
}
Python程式碼
config.py
# 你只需要修改有註釋的地方
# 其他未備註的地方,看得懂程式碼的人,請自行修改,需要需要了解numpy,pyaudio
#conding = utf8
from __future__ import print_function
from __future__ import division
import os
DEVICE = 'esp8266'
if DEVICE == 'esp8266':
# 下面是你剛才在Arduino中為ESP8266設定的IP地址,不要填錯了。
UDP_IP = '192.168.1.150'
UDP_PORT = 7777
SOFTWARE_GAMMA_CORRECTION = False
if DEVICE == 'pi':
LED_PIN = 18
LED_FREQ_HZ = 800000
LED_DMA = 5
BRIGHTNESS = 255
LED_INVERT = True
SOFTWARE_GAMMA_CORRECTION = True
if DEVICE == 'blinkstick':
SOFTWARE_GAMMA_CORRECTION = True
USE_GUI = True
DISPLAY_FPS = True
# 下面是你LED燈的數量,這個也不能搞錯,錯了,程式就執行出錯!
N_PIXELS = 120
GAMMA_TABLE_PATH = os.path.join(os.path.dirname(__file__), 'gamma_table.npy')
MIC_RATE = 44100
FPS = 60
_max_led_FPS = int(((N_PIXELS * 30e-6) + 50e-6)**-1.0)
assert FPS <= _max_led_FPS, 'FPS must be <= {}'.format(_max_led_FPS)
MIN_FREQUENCY = 200
MAX_FREQUENCY = 12000
N_FFT_BINS = 24
N_ROLLING_HISTORY = 2
MIN_VOLUME_THRESHOLD = 1e-7