先日こういうのを作りました。
LEDはM5Stack経由でWifiでつないでいて、全体はこういう構成になってます。
LEDは50個一つずつRGBがコントロールできるものを使いました。今回使ったのはこれです。
https://www.amazon.co.jp/gp/product/B08PVYXJJW/ref=ppx_yo_dt_b_asin_title_o03_s00
自由な位置にLEDを取り付けられるようにしたかったので、M5Stackはwifi接続にしました。
M5StackはBluetoothでも無線対応できますが、TouchDesignerから通信したかったのでwifi接続のUDP通信にしました。
#人の動きをMediaPipeでトラッキング
公式のサンプルにUDP通信を足しただけなので省略。
https://google.github.io/mediapipe/solutions/pose#python-solution-api
TouchDesignerから50個分のRGBデータを送信する
横50 x 縦10ピクセルのTOPデータをCHOPに変換、0~1のRGBデータを0~255に変換してChop Excute DAT
でUDP Out DAT
使ってM5Stackに送信してます。
TOPの視認性のために縦10pixel使ってますが、データ上は縦1pixelで良いので、Top to CHOP
で縦1pixel分のデータを取り出して数値化してます。
この部分のオペレータはこんな感じ。
この部分ができれば、Null TOP
に好きなように映像渡せばTouchDesignerからLEDが自由に操作できるようになります。
Chop Excute DAT
はValueChangeで処理するようにして、中身はこうなってます。
高速通信しても問題ないようになるべく通信サイズを抑えるため、文字列としては送らずにbyte配列にしてデータを送るようにしているので、50個のRGB用LEDに対して無駄なく150byteで送れます。
udpOut = op("udpout1")
allcolorData=op("null4")
sendDataArray=[0]*150 #50個のLED x RGBの3色分のデータ
def onOffToOn(channel, sampleIndex, val, prev):
return
def whileOn(channel, sampleIndex, val, prev):
return
def onOnToOff(channel, sampleIndex, val, prev):
return
def whileOff(channel, sampleIndex, val, prev):
return
def onValueChange(channel, sampleIndex, val, prev):
sendAllData()
return
def sendAllData():
for i in range(50):
sendDataArray[i*3]=int(allcolorData["r"][i])
sendDataArray[i*3+1]=int(allcolorData["g"][i])
sendDataArray[i*3+2]=int(allcolorData["b"][i])
#byte配列にして送信。150byteでデータが送信できる。
data = bytearray(sendDataArray)
udpOut.sendBytes(data)
M5Stackで受信してLED制御
AsyncUDPで非同期にUDPデータを受信、uint8_tに変換して、50個のLEDを制御してます。
#include <M5Stack.h>
#include <WiFi.h>
#include <AsyncUDP.h>
#include <Adafruit_NeoPixel.h>
#define PIN 5
#define NUMPIXELS 50
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
bool isDataReceive=false;
uint8_t rData[NUMPIXELS];
uint8_t gData[NUMPIXELS];
uint8_t bData[NUMPIXELS];
const char SSID[] = "SSIDが入ります"; //WiFi SSID
const char PASSWORD[] = "パスワードが入ります"; //WiFi パスワード
AsyncUDP udpReciever;
const int myUdpPort=12345; //TouchDesignerと合わせておく
void setupNetwork(){
WiFi.begin(SSID, PASSWORD);
M5.Lcd.print("WiFi connecting\n> ");
M5.Lcd.print(SSID);
M5.Lcd.print("\n");
//接続をまつ
while (WiFi.status() != WL_CONNECTED) {
M5.Lcd.print(".");
delay(100);
}
M5.Lcd.print("WiFi connected!");
if(udpReciever.listen(myUdpPort)) {
//M5Stack自身のIPを画面に表示しておく。このIPをTouchDesignerのUDP OUTの送信先に入力する。
M5.Lcd.print("UDP Listening on IP: ");
M5.Lcd.print(WiFi.localIP());
}
udpReciever.onPacket([](AsyncUDPPacket packet) {
uint8_t* colorData=packet.data();
isDataReceive=true;
for(int i=0; i<NUMPIXELS; i++) {
rData[i]=(uint8_t)colorData[i*3];
gData[i]=(uint8_t)colorData[i*3+1];
bData[i]=(uint8_t)colorData[i*3+2];
}
});
}
void setup() {
M5.begin();
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setTextColor(GREEN , BLACK);
M5.Lcd.setTextSize(2);
setupNetwork();
pixels.begin();
}
void loop() {
M5.update();
if(isDataReceive){
for(int i=0; i<NUMPIXELS; i++) {
pixels.setPixelColor(i, pixels.Color(gData[i], rData[i], bData[i]));
}
pixels.show();
}
delay(1); //delayいらない気がするけど、光具合の調整の名残で残してある
}
まとめ
TouchDesigner側からLEDをフルコントロールできるようになると、M5Stack側は一度作っておけば使いまわしが利きます。
あと、プログラムで数値操作するよりTouchDesignerの得意な映像操作で自由に光らせられるので直感的な制御が可能です。
今回は人の動きに反応するだけでなく、自動でカラフルに光ったり、音に反応して光ったりするものも作りました。
TouchDesignerで制御してるので、こういうのもサクッと作れるのが良いところです。
本当はLEDをクリスマスツリーに飾りたかったけど、ツリーが無いので壁に貼り付けて楽しみました。
クリスマス時期に家族に見てもらったら、時期的なこともあり、家族受けがとてもよかったので個人的にも満足しました。