M5Stack 2台と ESP32光ファイバー LED テープオブジェを1つの画面として制御する実験

M5Stack

こんばんは。

今回は、前回の記事で製作した、NeoPixel の光ファイバーの卓上イルミネーションに、更に M5Stack 2台を横にスタックさせて、「ちょっと変な」卓上イルミネーションにしてみました。
要するに、合計3台の ESP32 を Art-Net DMX で制御しているだけなのですが、全体として1画面として制御しているところがミソです。

スポンサーリンク

とりあえず、以下の動画をご覧ください。

見て分かると思うのですが、左の M5Stack が 8×5 pixel、中央の ESP32 と NeoPixel が 12×5 pixel、右の M5Stack が 8×5 pixel で、それぞれ連結して全体として 28×5 pixel の画面として、フリーウェアの Jinx による Art-Net DMX で制御しています。

わざわざこのようにしなくても、単体で普通にイルミネーションとして成立するのですが、 Art-Net が複数のデバイスを同時に制御できるという特徴を使って、何か面白い利用方法がないか考えていたら、こんな風になってしまいました。

要するに、Art-Net DMX ノード(端末)を3つ作ったようなものです。
単なる自己満足です。

M5Stack に表示されているフレーズは季節的に「メリークリスマス 」としましたが、自分の好きなフレーズに変更すれば、意外と面白いものが出来ると思います。

Art-Net や DMX の使い方に慣れていらっしゃる方は分かると思いますが、3つのデバイスを1つの画面として制御するには、Patch するだけで意外と簡単に実現できてしまいます。

因みに、FFT スペクトラムアナライザー的なイルミネーションはこんな感じです。

Google Home Mini のアナウンスをパソコンのマイクで拾っています。
3つのディスプレイがそれぞれ連動していて、見ているだけで意外と面白いです。
フリーフェアの Jinx でシーンをメモリして、Chase で動かせば良いと思います。

この卓上イルミネーションはパソコンを使わないとできませんが、いつか独立してスタンドアローンでできたらいいなとは思っています。
(プログラムが面倒なので、実現しないかも・・・)

では、この作り方を説明します。

因みに、ここで使用している Art-Net 制御用パソコンソフトは、Windows専用です。

また、何度も申し上げておりますが、私は素人独学アマチュアです。
ここで紹介した回路やプログラムの動作保証はしません。
ただ、もし何か誤り等がありましたら、コメント投稿等でご連絡いただけると助かります。

    【目次】

  1. 使ったもの
  2. パソコンソフトおよびライブラリ、日本語フォント等のインストール
  3. 接続
  4. 左側 M5Stack 用のスケッチ(プログラムソースコード)
  5. 中央の NeoPixel Ring および LED テープ用のスケッチ(プログラムソースコード)
  6. 右側 M5Stack 用のスケッチ(プログラムソースコード)
  7. コンパイル書き込み実行
  8. Jinx ソフトウェアの DMX Patch ( パッチ )
  9. Jinx ソフトウェア実行

使ったもの

ESP32 と NeoPixel LED テープおよび光ファイバーのオブジェについては前回の記事を参照してください。

また、M5Stack の日本語文字表示や、NeoPixel リング等については前々回の記事を参照してください。

ESP32 搭載の M5Stack は、今回2台使用しました。

(追記)
M5Stack Basicは、この記事を書いた当時より格段にバージョンアップしております。
以下のスイッチサイエンスさんの公式サイトをご参照ください。
https://www.switch-science.com/collections/%E5%85%A8%E5%95%86%E5%93%81/products/9010

※M5Stack Gray(9軸IMU搭載)現在は販売終了しております

 

パソコンソフトおよびライブラリ、日本語フォント等のインストール

以下の2つの記事を参照して、必要な開発環境やライブラリ、および日本語フォントをインストールしておいてください。

M5Stackと NeoPixel で Art-Net DMX を使った LED エフェクト実験

ESP32 と NeoPixel フルカラー LED テープで Wi-Fi 卓上イルミネーションオブジェを作ってみた

Arduino IDE はver1.8.8 で動作確認しています。
Arduino core for the ESP32 は stable 1.0.0 で動作確認しています。

その他、Arduino IDE 用ライブラリは以下の物が必要です。

●ArtnetWifi ライブラリ
● FastLEDライブラリ
● mgo-tec自作ライブラリ

また、パソコンソフトは以下の物が必要です。

●Jinx! – LED Matrix Control ( Windows専用フリーウェア )

接続

ESP32 開発ボード ( ESP32-DevKitC )と NeoPixel の接続は前回の記事と同じです。
それに加えて、M5Stack を2台横に置いただけです。
ただ、今回の NeoPixel ( WS2812B ) LED テープは3分の1しか使いません。
そして、右側の M5Stack は USBケーブルが邪魔にならないように上下逆さに置き、プログラムで上下を入れ換えています。

因みに、NeoPixel 電源のACアダプターと、ESP32-DevKitC の電源は同じコンセントおよびテーブルタップから取ってください。
ESP32-DevKitC のUSB電源をパソコンから取っている場合は、パソコンの電源も同じコンセントおよびテーブルタップから取ってください。
GNDの電位差を極力少なくするためです。

左側 M5Stack 用のスケッチ(プログラムソースコード)

では、Arduino IDE にスケッチ(プログラムソースコード)を入力します。
まずは、左側の M5Stack は以下のようになります。
以前のこちらの記事のスケッチと重複しているところもあります。

【ソースコード】 (※無保証 ※PCの場合、ダブルクリックすればコード全体を選択できます)

#include <WiFi.h>
#include <WiFiUdp.h>
#include <ArtnetWifi.h>

#define MGO_TEC_BV1_M5STACK_SD_SKETCH
#include <mgo_tec_bv1_m5stack_sd_simple1.h> //ESP32_mgo_tec library beta ver 1.0.67

const char* ssid = "xxxxxxxx"; //ご自分のルーターのSSIDに書き換えてください
const char* password = "xxxxxxxx"; //ご自分のルーターのパスワードに書き換えてください

const char* utf8sjis_file = "/font/Utf8Sjis.tbl"; //UTF8 Shift_JIS 変換テーブルファイル名を記載しておく
const char* shino_full_font_file = "/font/shnmk16.bdf"; //オリジナル東雲全角フォントファイル
const char* shino_half_font_file = "/font/shnm8x16.bdf"; //半角フォントファイル名を定義

ArtnetWifi artnet;
const uint16_t max_pixels = 40; //文字数
const uint16_t max_dmx_ch = max_pixels * 3;
const uint8_t device_universe = 0;
uint8_t dmx[max_dmx_ch] = {};
uint8_t lcd_px[max_dmx_ch] = {};
uint16_t c0, c1, c2;
String str[max_pixels][8];
uint16_t font_width;
uint16_t font_height;
double str_per_dmx = (double)7.0 / 255.0;

//*************************************************
void setup(){
  Serial.begin(115200);
  ConnectWifi();
  artnet.begin();
  artnet.setArtDmxCallback(onDmxFrame);

  mM5.init( utf8sjis_file, shino_half_font_file, shino_full_font_file );
  LCD.brightness(255); //LCD LED Full brightness
  mM5.font[0].Xsize = 2, mM5.font[0].Ysize = 3;
  font_width = mM5.font[0].Xsize * 16 + 8;
  font_height = mM5.font[0].Ysize * 16;

  for(int i = 0; i < max_pixels; i++){
    str[i][0] = "メ";
    str[i][1] = "リ";
    str[i][2] = "ー";
    str[i][3] = "ク";
    str[i][4] = "リ";
    str[i][5] = "ス";
    str[i][6] = "マ";
    str[i][7] = "ス";
  }

  TaskHandle_t th; //マルチタスクハンドル定義
  xTaskCreatePinnedToCore(Task1, "Task1", 8192, NULL, 10, &th, 0); //マルチタスク起動
}
//*************************************************
void loop(){
  int i;
  int ch = 0; //DMX channel number
  uint16_t x0 = 0, y0 = 0;
  int str_num = 0;

  for(i = 0; i < max_pixels; i++){
    c0 = ch++, c1 = ch++, c2 = ch++;
    if((dmx[c0] != lcd_px[c0]) || (dmx[c1] != lcd_px[c1]) || (dmx[c2] != lcd_px[c2])) {
      lcd_px[c0] = dmx[c0];
      lcd_px[c1] = dmx[c1];
      lcd_px[c2] = dmx[c2];
      x0 = i * font_width - 320 * (uint16_t)floor((double)i / 8.0);
      y0 = font_height * (uint16_t)floor((double)i / 8.0);
      str_num = (uint8_t)round( (double)lcd_px[c0] * str_per_dmx );
      mM5.font[0].x0 = x0; mM5.font[0].y0 = y0;
      mM5.font[0].colorRGB255( lcd_px[c0], lcd_px[c1], lcd_px[c2] );
      mM5.disp_fnt[0].dispText( mM5.font[0], str[i][str_num] );
    }
  }
}
//************ マルチタスクループ ******************
void Task1( void *pvParameters ){
  while(1){
    artnet.read();
    delay(1); //マルチタスクの場合、これ絶対必要!
  }
}
//***************************************
boolean ConnectWifi(void){
  boolean state = true;
  int i = 0;

  WiFi.begin(ssid, password);
  Serial.println("");
  Serial.println("Connecting to WiFi");

  // Wait for connection
  Serial.print("Connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
    if (i > 20){
      state = false;
      break;
    }
    i++;
  }
  if (state){
    Serial.println("");
    Serial.print("Connected to ");
    Serial.println(ssid);
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
  } else {
    Serial.println("");
    Serial.println("Connection failed.");
  }
  return state;
}
//**************************************************
void onDmxFrame(uint16_t universe, uint16_t length, uint8_t sequence, uint8_t* data){
  int ch = 0; //DMX channel number
  if(universe == device_universe){
    for (ch = 0; ch < length; ch++){
      dmx[ch] = data[ch];
      ch++;
      dmx[ch] = data[ch];
      ch++;
      dmx[ch] = data[ch];
    }
  }
}

【解説】

●8-9行:
ご自分の Wi-Fiルーターの SSID とパスワードに書き換えてください。

●11-13行:
M5Stack の micro SDHC カードに保存してあるフォントデータファイルの定義です。

●16行:
M5Stack に表示する最大文字数です。

●17行:
1文字にRGBの三色をDMXで割り当てているので、DMXの最大チャンネル数は40×3=120 となります。

●18行:
左側の M5Stack の Universe 設定は 0番とします。
中央の LED テープは 1番、右側 M5Stack は2番です。

●20行:
M5Stack の LCD の日本語表示は、Art-Net 通信に比べて速度が遅いので、異なる DMX 値になった場合に LCD に表示するための配列バッファです。

●25行:
8文字をDMX値(0~255)に割り当てるための定数です。

●40-49行:
日本語文字はString型オブジェクト配列にしました。
これならば、誰でも好きな文字に変更できると思います。

●51-52行:
ESP32 のマルチタスク定義です。
77-82行でマルチタスクを実行していて、Art-Net は CPU core 0で受信しています。
LCD表示はメインループの CPU core 1 で動作させています。
マルチタスクについてはこちらの記事を参照してください。

●55-75行:
メインループで、CPU core 1 でLCDに日本語表示させています。
LCD表示はそんなに早く無いので、Art-Netで受信した DMX 値が以前の値と異なる場合のみ LCD を書き換えるようにしています。

●77-82行:
マルチタスクで、CPU core 0 のループです。
79行目の関数で、Art-Net 通信を受信しています。

●116-127行:
ここで、Art-Net 通信の DMXデータを受信していますが、今までのスケッチと異なるのは、118行で Universe を指定して受信しているところです。

では、次では中央の光ファイバーと NeoPixel LED テープオブジェのスケッチを紹介します。

コメント

タイトルとURLをコピーしました