Meguru2238 が 2021年02月28日23時32分08秒 に編集
ステータス表示信号機を追加しました。
メイン画像の変更
記事種類の変更
製作品
本文の変更
# 概要
M5StackシリーズのATOM Matrixを用いて起動する度にパターンの異なるライフゲームシミュレーションを表示するデバイスを作成する。
M5StackシリーズのATOM Matrixを用いて起動する度にパターンの異なるライフゲームシミュレーションを 表示するデバイスを作成する。
実現する機能は以下のとおりとする。
実現する機能は以下の通りとする。
- 起動時にWiFiに接続し、現在日時を取得する。 - 起動後の一定時間(今回は5秒)は現在日時のうち月日時分秒を表示する。 - 現在日時表示後は毎秒ライフゲームのステップを進める。 - 盤面の全てのビットが消滅したことを判定可能とする。 # 余談:ライフゲームとは? 詳細はWikipedia[https://ja.wikipedia.org/wiki/%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B2%E3%83%BC%E3%83%A0]を参照。 簡単に説明すると周囲の状態によって生命がどのような変化をするかをシミュレーションするセル・オートマトンの一種。 # 部品 - ATOM Matrix ( https://m5stack.com/collections/m5-atom/products/atom-matrix-esp32-development-kit ) - 任意でON/OFF可能なUSB Type-C電源 - 今回はATOM TailBat( https://m5stack.com/collections/m5-atom/products/atom-tailbat )を使用
- 信号機風拡張基板 ( https://www.switch-science.com/catalog/6129/ ) - Groveケーブル
# 接続
中核となるWiFi機能およびLED Matrix制御はATOM Matrixにて行うため、 電源のみATOM MatrixのUSB Type-Cコネクタに接続する
使用する部品を拡張基板~ATOM TailBat~ATOM Matrixの順に接続する。 なお、拡張基板は適当な方法でBatと固定する。(今回は輪ゴムを使用した)
# LED表示について 現在時刻を表示するにあたり、ATOM MatrixのUSB Type-Cコネクタを左側になるように置いた時に以下のように各値を配置した。 - 1行目:月 - 2行目:日 - 3行目:時 - 4行目:分 - 5行目:秒 なお、分および秒については1行あたりLEDが5個しかないため、そのまま表示すると0~31までしか表示できないため、 苦肉の策として1bit右シフトを行うことで範囲内に収めている。
また、状態表示を行う信号機風拡張基板は以下の規則で表示する。 - 青:現在日時 - 黄:ライフゲーム実行中 - 赤:全滅
# プログラム ```arduino:Atom_LifeGame #include <M5Atom.h> #include <WiFi.h> // Settings const char* ssid = "Your SSID"; const char* password = "Your Pass"; // Global bool map_now[5][5] = {0}; bool map_next[5][5] = {0}; void connectWiFi() { WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); } } void setTime() { struct tm timeInfo; char s[32]; configTime(9 * 3600L, 0, "ntp.nict.jp", "time.google.com", "ntp.jst.mfeed.ad.jp"); getLocalTime(&timeInfo);
sprintf(s, "%02d/%02d %02d:%02d:%02d", timeInfo.tm_mon + 1, timeInfo.tm_mday,
sprintf(s, " %04d/%02d/%02d %02d:%02d:%02d", timeInfo.tm_year + 1900, timeInfo.tm_mon + 1, timeInfo.tm_mday,
timeInfo.tm_hour, timeInfo.tm_min, timeInfo.tm_sec); setnextline(0, timeInfo.tm_mon + 1); setnextline(1, timeInfo.tm_mday); setnextline(2, timeInfo.tm_hour); setnextline(3, (timeInfo.tm_min / 2)); setnextline(4, (timeInfo.tm_sec / 2)); drawLED(map_next); Serial.println(s);
digitalWrite(26, LOW); digitalWrite(32, LOW);
delay(5000); } void setup() { M5.begin(true, false, true);
pinMode(26, OUTPUT); pinMode(32, OUTPUT); digitalWrite(26, HIGH); digitalWrite(32, HIGH);
Serial.begin(115200); delay(10); connectWiFi(); setTime(); } bool moveMap(bool src[5][5], bool dest[5][5]) { int i, j; bool ret = false; for(i = 0; i < 5; i++) { for(j = 0; j < 5; j++) { dest[i][j] = src[i][j]; src[i][j] = 0; if(dest[i][j] == true) { ret = true; } } } return ret; } void drawLED(bool ledmap[5][5]) { int i, j; M5.dis.clear(); for(i = 0; i < 5; i++) { for(j = 0; j < 5; j++) { if(ledmap[i][j] == true) { M5.dis.drawpix(i, j, CRGB::White); }
else { }
} } } void drawRed() { int i, j; M5.dis.clear(); for(i = 0; i < 5; i++) { for(j = 0; j < 5; j++) { M5.dis.drawpix(i, j, CRGB::Red); } } } void setnextline(int line, int num) {
Serial.println(num);
if( (num & 0x01) != 0x00) { map_next[line][0] = true; } else { map_next[line][0] = false; } if( (num & 0x02) != 0x00) { map_next[line][1] = true; } else { map_next[line][1] = false; } if( (num & 0x04) != 0x00) { map_next[line][2] = true; } else { map_next[line][2] = false; } if( (num & 0x08) != 0x00) { map_next[line][3] = true; } else { map_next[line][3] = false; } if( (num & 0x10) != 0x00) { map_next[line][4] = true; } else { map_next[line][4] = false; } } int countDot(int i, int j) { int ret = 0; if((i != 0) && (j != 0)) { if(map_now[i-1][j-1] == true) ret++; } if((i != 0)) { if(map_now[i-1][j] == true) ret++; } if((i != 0) && (j != 4)) { if(map_now[i-1][j+1] == true) ret++; } if((j != 0)) { if(map_now[i][j-1] == true) ret++; } if((j != 4)) { if(map_now[i][j+1] == true) ret++; } if((i != 4) && (j != 0)) { if(map_now[i+1][j-1] == true) ret++; } if((i != 4) && (j != 0)) { if(map_now[i+1][j] == true) ret++; } if((i != 4) && (j != 4)) { if(map_now[i+1][j+1] == true) ret++; } return ret; } void loop() { int i, j; int ret; if(moveMap(map_next, map_now) == true) {
digitalWrite(26, LOW); digitalWrite(32, HIGH);
for(i = 0; i < 5; i++) { for(j = 0; j < 5; j++) { ret = countDot(i, j); if(map_now[i][j] == false) { switch(ret) { case 3: map_next[i][j] = true; break; } } else { switch(ret) { case 2: case 3: map_next[i][j] = true; break; } } } } drawLED(map_next); } else {
drawRed();
digitalWrite(26, HIGH); digitalWrite(32, LOW);
} delay(1000); M5.update(); }
``` # 動作 以下のTwitterページを参照 https://twitter.com/i/status/1366024248909647880 # 改善点 - 左上の1dot分については、1行目の値が月であるため取りうる値(1~12)において絶対に点灯しない状態になっている。 対して分および秒で1bitシフトで情報が欠落しているため、初期パターン配置を工夫することで全bitを使用することが できるようになる。
- 現在はWiFi接続情報埋め込みのため屋外で使用することができない。幸いにもATOM Matrixの外部接続ポートは 未使用であるため時刻取得をGPS等を用いることでWiFi環境に依存しなくなる。
- 現在はWiFi接続情報埋め込みのため屋外で使用することができない。幸いにもATOM Matrixの背面接続ポートは 未使用であるため時刻取得をGPS( https://m5stack.com/products/atom-gps-kit-m8030-kt )等を用いることでWiFi環境に依存しなくなる。