ATOM Matrix(M5Stack)で作るライフゲームマシン
概要
M5StackシリーズのATOM Matrixを用いて起動する度にパターンの異なるライフゲームシミュレーションを
表示するデバイスを作成する。
実現する機能は以下の通りとする。
- 起動時にWiFiに接続し、現在日時を取得する。
- 起動後の一定時間(今回は5秒)は現在日時のうち月日時分秒を表示する。
- 現在日時表示後は毎秒ライフゲームのステップを進める。
- 盤面の全てのビットが消滅したことを判定可能とする。
余談:ライフゲームとは?
詳細はWikipedia[https://ja.wikipedia.org/wiki/ライフゲーム]を参照。
簡単に説明すると周囲の状態によって生命がどのような変化をするかをシミュレーションするセル・オートマトンの一種。
部品
- 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ケーブル
接続
使用する部品を拡張基板~ATOM TailBat~ATOM Matrixの順に接続する。
なお、拡張基板は適当な方法でBatと固定する。(今回は輪ゴムを使用した)
LED表示について
現在時刻を表示するにあたり、ATOM MatrixのUSB Type-Cコネクタを左側になるように置いた時に以下のように各値を配置した。
- 1行目:月
- 2行目:日
- 3行目:時
- 4行目:分
- 5行目:秒
なお、分および秒については1行あたりLEDが5個しかないため、そのまま表示すると0~31までしか表示できないため、
苦肉の策として1bit右シフトを行うことで範囲内に収めている。
また、状態表示を行う信号機風拡張基板は以下の規則で表示する。
- 青:現在日時
- 黄:ライフゲーム実行中
- 赤:全滅
プログラム
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, " %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) {
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 {
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( https://m5stack.com/products/atom-gps-kit-m8030-kt )等を用いることでWiFi環境に依存しなくなる。
投稿者の人気記事
-
Meguru2238
さんが
2021/02/28
に
編集
をしました。
(メッセージ: 初版)
-
Meguru2238
さんが
2021/02/28
に
編集
をしました。
-
Meguru2238
さんが
2021/02/28
に
編集
をしました。
(メッセージ: ステータス表示信号機を追加しました。)
ログインしてコメントを投稿する