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

記事公開日:2018年12月21日

こんばんは。

今回は、前回の記事で製作した、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専用です。

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

このブログの維持運営にご支援いただけると助かります。
支援方法はこちらの記事をご覧ください。
(管理人:mgo-tec)

 

    【目次】

  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台使用しました。

Amazon.co.jp
M5Stack Basic
スイッチサイエンス

Amazon.co.jp
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の電位差を極力少なくするためです。

m5stack2_esp32_neopixel01.jpg


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

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

#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 テープオブジェのスケッチを紹介します。


スポンサーリンク


コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください