M5Scratchに関するなにか
https://gyazo.com/40d5e93fe01a61260924513c4085c1b0
むとうたけし @50歳専業主夫
M5Stack Advent Calendar 2020 22日目
はじめに
この文章は、M5Stack Advent Calendar 2020の22日目のために書かれたものです。
背景は…
M5Scratch for みんなのM5Stack自慢大会から5ヶ月…
ぶっ倒れている間にM5Stack Japan Creativity Contest 2020も終わったorz
金のやつ、欲しかったorz
なので、なんか、M5Scratchで使ったM5S*を使うためのテクニックやTipsなどの「M5Scratchに関するなにか」でもまとめてみましょうかね。
お品書き
M5Scratchの拡張
イケてるデモを作る
LovyanGFX対応
ボード選択の結果を利用した多機種対応
M5StickC
ATOM Matrix
色々な無線LANの設定方法
LovyanLauncher
SmartConfig
ソースに直書き(network.h)
M5Stack GrayでIMUの地磁気センサーを使う
自己紹介
以下を参照してください。
/610t/610t
M5Scratch=M5S*+Scratch
M5Scratchは、M5ファミリーのボード(M5S*)と、Scratch1.4でインタラクションするためのArduino IDEプログラムです。
https://www.youtube.com/watch?v=zzp7oRjX_WU
github: https://github.com/610t/Arduino/tree/master/M5Scratch
昔書いた解説は、M5Scratch for みんなのM5Stack自慢大会など、/M5S/に集めてます
table:ボードサポート状況
Support LCD LED IMU Keyboard 備考
M5Stack Basic o o None x x
M5Stack Gray (Faces) o o None o (9axis) o (Faces)
M5StickC o o o (Red LED) o (6axis) x
M5StickC plus o o o o (6axis) x
ATOM Matrix o x o (Matrix) o (6axis) x
(ATOM Lite) △ x - (RGB LED) x x headerの切り分け不可
Wio Terminal x ? ? ? x
みんなのM5Stack自慢大会発表時点で残っていた問題点
みんなのM5Stack自慢大会発表時点で残っていた問題点には、以下のようなものがあります。
ネットワーク関連(無線LAN設定とScratch動作PCのIPアドレス)の設定をnetwork.hに書かなければならない
code:network.h
const char* ssid = "SSID";
const char* password = "PASSWORD";
const char* host = "Scratch Host IP";
無線LANの設定がいけてない
Scratchが動いているホストIPの設定がいけてない
デモ環境で、無線LAN環境が普段と異なり、DHCPでホストIPが変わる場合、Arudino IDEで再コンパイルが必要
コンパクトな無線LAN AP機器などを使えば吸収はできなくもない (おまけ参照)
新しい機器への対応
M5StickC/Plus
ATOM Matrix/Lite
Wio Terminal
しょぼいデモをなんとかしたい
M5Scratchを拡張する
M5Scratchを拡張するためには、Arduino IDEでコードを変更する必要があります。
M5S*側からScratchへ情報を送るには、以下の関数を使います。
それぞれ、Scratch Remote Sensor Protocolのbroadcast(broadcast())とsensor-update(sensor_update())に対応しています。
broadcast(String msg):メッセージstringを送る
sensor_update(String varName, String varValue): 変数varNameの値varValueを送る
code:M5Scratch.ino
// ボタンAが押されたら、メッセージBtnAを送る
if (M5.BtnA.isPressed()) {
broadcast(client, "BtnA");
}
// 0-255の乱数を変数vとして送る
sensor_update(client, "v", String(random(0, 255)));
逆に、Scratchから送った情報をM5S*側で受け取るためには、以下のようにします。
現在は、switch文で場合分けをしているため、Scratch側からの変数名は1文字しか使えません。
code:M5Scratch.ino
if (msg.startsWith("broadcast") == true) {
// broadcast
msg.replace("broadcast ", "");
msg.replace("\"", "");
M5.Lcd.println("broadcast:\"" + msg + "\""); // LCDにメッセージ内容を表示
} else if (msg.startsWith("sensor-update")) {
(snip)
// sensor-update
if (msg.startsWith("r") == true) {
r = constrain(int(getValue('r', msg).toFloat()), 0, 255);
} else if (msg.startsWith("g") == true) {
(snip)
LovyanGFXでイケてるデモ
これまでのデモでは、M5S*のディスプレイに表示しているのは、Scratch側から送られた(r,g,b)値に基づいて、M5S*の背景色を変えるだけの地味なものでした。
これを、さらにx,y座標や向いている方法t、キャラクタの拡大率zなどを追加して、画面にキャラクタが表示されるようにしてみました。
画面へのキャラクタ表示のためには、LovyanGFXを使いました。
LovyanGFXは、ESP32用のイケてるグラフィックスライブラリです。
以下のような特徴があります。
高速
高機能
たくさんのデバイスに対応
LovyanGFXでのプログラミングに関しては、LovyanGFX入門が参考になります。
このサイトには、に、任意の大きさのBMP,JPEG,PNGから、C用のイメージデータを作ってくれる機能もあります。
LovyanGFXを使ってM5S*側でのイケてるデモを作ります。
キャラクタを動かす例は、サンプル例 → LovyanGFX → Sprite → MovingIconsを使うのが一番良いと思います。
今回は、スプライトをScratchCatに、ScratchCatの(x,y)座標と角度(t)とズーム倍率(z)、右上の丸の色(r,g,b)をM5S*側で受け取るように作りました。
https://gyazo.com/aa0275f36c90597d0752f850be7a00d2
https://www.youtube.com/watch?v=Y_04pz9JAas
無線LANの設定について
無線LANの設定ですが、以下のような方法が考えられます。
LovyanLauncher対応にする
SmartConfigを使う(ESP32にSmartConfigでWiFi情報を伝える)
SDなどの不揮発性の領域に設定情報を書き込んでおく
プログラム中に直書きする
LovyanLauncherによる方法では、LovyanLauncherの無線LAN設定で設定した無線LAN設定(SSID/PASSWORD)が、アプリケーション側にも渡されるようになっています。
このため、LovyanLauncherの無線LAN設定が一度すんでしまうと、再起動後も自動的にこの設定が渡されます。
SmartConfigを使う方法では、スマートフォンから、設定用アプリでWiFi情報を設定することになります。
設定した情報をどこかにキャッシュしていない状況では、起動時に毎回設定を行う必要があります。
SDなどを利用する方法は、上記の方法と併用して使うことができます。
ただ、SDが存在しないデバイスもあるため、一概にこの方法が取れるとは限りません。
M5S*の不揮発性領域に書き込んでおく方法も考えられますが、これを変更するには他のコンピュータで書き換えればいいSDよりも敷居が上がってしまいます。
LovyanLauncher対応
LovyanLauncherは、多機能なプログラム起動などを行うLauncherです。
以下のような特徴があります。
SDカードに格納されたアプリを実行する(Launcher)
WiFiの設定機能: アプリにもこの情報が提供される
バイナリのダンプなどなど
使い方は、M5Stack LovyanLauncherの使い方が詳しいです。
LovyanLauncherに対応したアプリケーションの作り方は、M5Stack LovyanLauncher対応アプリの作り方が詳しいです。
LovyanLauncher化を行ったM5Scratchは、https://github.com/610t/Arduino/blob/LovyanLauncher/M5Scratch/M5Scratch.ino です。
以下のような3ステップで、対応は完了です。
#include <M5StackUpdater.h>
WiFi設定で、ssidとpasswordを渡さないように変更
BUTTON Aを押しながら起動すると、LovyanLauncherを読み出すように変更
code:M5Scratch.ino.diff
--- a/M5Scratch/M5Scratch.ino
+++ b/M5Scratch/M5Scratch.ino
@@ -46,6 +46,7 @@
// #define M5STACK_200Q
#include <M5Stack.h>
+#include <M5StackUpdater.h>
#if defined(M5STACK_MPU9250)
#include "utility/MPU9250.h"
@@ -60,8 +61,6 @@ MPU9250 IMU;
/*
network.h contains network information below:
- const char* ssid = "SSID";
- const char* password = "PASSWORD";
const char* host = "Scratch Host IP";
*/
#include "network.h"
@@ -73,7 +72,7 @@ void WiFiSetup() {
wifisetup:
Serial.println("Wifi begin.");
WiFi.disconnect();
- WiFi.begin(ssid, password);
+ WiFi.begin();
Serial.println("End of Wifi begin.");
int c = 0;
@@ -93,6 +92,15 @@ void setup() {
M5.begin();
delay(100);
+#if defined(ARDUINO_M5Stack_Core_ESP32)
+ // for LovyanLauncher
+ if (digitalRead(BUTTON_A_PIN) == 0) {
+ Serial.println("Will Load menu binary");
+ updateFromFS(SD);
+ ESP.restart();
+ }
+#endif
+
// Init Serial
Serial.begin(115200);
delay(10);
無線LANの設定のためのSmartConfig化
SmartConfigを利用するためには、ESsaiP32にSmartConfigでWiFi情報を伝えるを参考にしてください。
これに対応したM5Scratchは、 https://github.com/610t/Arduino/blob/SmartConfig/M5Scratch/M5Scratch.ino になります。
設定情報をどこかにキャッシュしていない状況では、毎回SmartConfigする必要があるために、それはそれでめんどくさいことになります。
各種M5Stackシリーズ対応
この項目は、らびやんさんからの情報: です。
Arduino IDEでは、ツール→ボードを選択すると自動的にARDUINO_*マクロが定義されます。
これを使って、#ifdefやdefined()などで場合わけが可能になります。
現状では、以下のようにboards.txtに、*.build.boardとして定義されています。
code:shell
% grep build.board ~/Library/Arduino15/packages/m5stack/hardware/esp32/1.0.7/boards.txt|grep M5
m5stack-core-esp32.build.board=M5Stack_Core_ESP32
m5stack-fire.build.board=M5STACK_FIRE
m5stick-c.build.board=M5Stick_C
m5stick-c-plus.build.board=M5Stick_C_Plus
m5stack-atom.build.board=M5Stack_ATOM
m5stack-core2.build.board=M5STACK_Core2
m5stack-tough.build.board=M5STACK_TOUGH
m5stack-timer-cam.build.board=M5Stack-Timer-CAM
m5stack-coreink.build.board=M5Stack_CoreInk
m5stack-m5paper.build.board=M5STACK_Paper
% grep build.board ~/Library/Arduino15/packages/Seeeduino/hardware/samd/1.8.1/boards.txt|grep TERMINAL
seeed_wio_terminal.build.board=WIO_TERMINAL
この情報をまとめると、以下の表のようになります。
table:ボード選択で定義されるARDUINOマクロ
機器 ボード選択で定義されるマクロ #include 備考
M5Stack Basic, Gray ARDUINO_M5Stack_Core_ESP32 M5Stack.h
M5Stack Fire ARDUINO_M5STACK_FIRE M5Stack.h
M5StickC ARDUINO_M5Stick_C M5StickC.h
M5StickC plus ARDUINO_M5Stick_C_Plus M5StickCPlus.h
ATOM Matrix ARDUINO_M5Stack_ATOM M5Atom.h
ATOM Lite (ARDUINO_M5Stack_ATOM) M5Atom.h ATOM Matrixと切り分けできない
M5Stack Core 2 ARDUINO_M5STACK_Core2 M5Core2.h
Wio Terminal ARDUINO_WIO_TERMINAL
例えば、ヘッダファイルの読み込み部分では、以下のようなコードを書くことになります。
code:M5Scratch.ino
#if defined(ARDUINO_M5Stick_C) // M5StickCの場合
#include <M5StickC.h>
#elif defined(ARDUINO_M5Stack_Core_ESP32) // M5Stackの場合
#include <M5Stack.h>
#elif defined(ARDUINO_M5Stack_ATOM) // ATOM Matrixの場合
#include <M5Atom.h>
#endif
画面まわりのコードを共通化する
画面まわりのコードでは、LCDの横と縦のピクセル数を表すM5.Lcd.width()とM5.Lcd.height()を使って画面の大きさの違いを吸収可能です。
画面の向きをLandscapeやPortrateに変更する場合には、M5.Lcd.setRotation()を適切に設定します。
フォントのサイズの吸収に関しては、良い方法がわからないので、固定値で行っています。
M5StickC対応
M5StickCに対応するためには、以下のようなことを行いました。
マクロARDUINO_M5Stick_Cで場合分けを行う
#include <M5StickC.h>
BUTTONスイッチ関連の処理がM5Stackとは違う
LCDの出力方向を考えて、必要であれば変更する(M5.Lcd.setRotation())
フォントの大きさを変更(M5.Lcd.setTextSize())
LEDの対応の追加(digitalWrite(M5_LED, led))
code:M5Scratch.ino.diff
// M5StickC用ヘッダーファイルの読み込み
+#if defined(ARDUINO_M5Stick_C)
+#include <M5StickC.h>
(snip)
+#endif
(snip)
// BUTTONスイッチの初期化
+#if defined(ARDUINO_M5Stick_C)
pinMode(M5_BUTTON_HOME, INPUT);
pinMode(M5_BUTTON_RST, INPUT);
+#endif
(snip)
// BUTTONスイッチの利用
+#if defined(ARDUINO_M5Stick_C)
if (digitalRead(M5_BUTTON_HOME) == LOW) {
broadcast(client, "BtnA");
}
if (digitalRead(M5_BUTTON_RST) == LOW) {
broadcast(client, "BtnB");
}
+#endif
// LCDの出力方向変更
#if defined(ARDUINO_M5Stick_C)
+ M5.Lcd.setRotation(3);
M5.Lcd.setTextSize(1);
#elif defined(ARDUINO_M5Stack_Core_ESP32)
(snip)
// 出力する文字の大きさを小さく
+#if defined(ARDUINO_M5Stick_C)
+ M5.Lcd.setTextSize(1);
+#elif defined(ARDUINO_M5Stack_Core_ESP32)
+ M5.Lcd.setTextSize(2);
+#endif
(snip)
// 変数lによるLEDの点灯/消灯
case 'l':
int led = int(getValue('l', msg).toFloat());
+#if defined(ARDUINO_M5Stick_C)
digitalWrite(M5_LED, led);
+#endif
M5StickC plusは、ARDUINO_M5Stick_Cのような専用のマクロ定義が無いので場合分けできませんが、ヘッダとしてM5StickCPlus.hを使う必要があります。
ATOM Matrix対応
ATOM Matrixへの対応は以下のように行いました。
マクロARDUINO_M5Stack_ATOMで場合分けを行う
#include <M5Atom.h>
M5.begin(true, false, true)でないとLEDは使えない(LED利用選択の第3引数デフォルトはfalse)
M5Stackシリーズ M5.begin()の互換性を参照
ディスプレイはないので当たり前だけど、M5.Lcd.*は使えない
LEDの輝度はあまり高くしない方が良いらしい
とりあえず、Max0x20にした
code:M5Scratch.ino.diff
// ヘッダファイルの切り替え
+#elif defined(ARDUINO_M5Stack_ATOM)
+#include <M5Atom.h>
+#endif
(snip)
// 初期化
+#if defined(ARDUINO_M5Stack_ATOM)
+ M5.begin(true, false, true);
+#else
M5.begin();
+#endif
(snip)
// LCD(は無いので)に出力しない
+#if !defined(ARDUINO_M5Stack_ATOM)
M5.Lcd.println("WiFi connected.");
+#endif
(snip)
// 全てのLEDに、LED保護のためにRGBを抑制した出力を行う
+#if defined(ARDUINO_M5Stack_ATOM)
+ // Conver raw rgb(0-255) to led rgb(0-0x20)
+ int rl = constrain(int((r / 255.0) * 0x20), 0, 0x20);
+ int gl = constrain(int((g / 255.0) * 0x20), 0, 0x20);
+ int bl = constrain(int((b / 255.0) * 0x20), 0, 0x20);
+ Serial.println("LED RGB:(" + String(rl) + ", " + String(gl) + ", " + String(bl) + ")");
+ setBuff(rl, gl, bl);
+ M5.dis.displaybuff(DisBuff);
+#else
M5.Lcd.fillScreen(uint16_t (((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3) ));
M5.Lcd.println("RGB:(" + String(r) + ", " + String(g) + ", " + String(b) + ")");
+#endif
(snip)
ATOM Liteも、専用のマクロ定義が無いので、場合分けできません。
M5Stack Grayで地磁気センサーを使う
M5Stack Grayなどの9軸IMUモデルでは、3軸の地磁気センサーが利用可能です。
6軸IMUのMPU6886互換で利用する時は、M5StickCと同じM5.Imu.*インタフェース経由で6軸のIMUが利用可能ですが、このインタフェースでは地磁気センサーを扱うことができません。
地磁気センサーを使う場合は、MPU9250を使って自力で頑張る必要があります。
code:M5Scratch.ino
// 必要な.hファイルを読みこむ
#include "utility/MPU9250.h"
#include "utility/quaternionFilters.h"
MPU9250 IMU;
(snip)
// 初期化
IMU.MPU9250SelfTest(IMU.SelfTest);
IMU.calibrateMPU9250(IMU.gyroBias, IMU.accelBias);
IMU.initMPU9250();
IMU.initAK8963(IMU.magCalibration);
(snip)
// 地磁気データの読み込み
IMU.readMagData(IMU.magCount);
IMU.getMres();
mx = (float)IMU.magCount0 * IMU.mRes;
my = (float)IMU.magCount1 * IMU.mRes;
mz = (float)IMU.magCount2 * IMU.mRes;
実際に地磁気センサーを利用するためには、初期化時にキャリブレーション(補正)が必要となります。
M5Scratchでキャリブレーションの実装をどのようにするのかは、考えているところです。
TODOとか、いくすえについて
これから作業する必要があるのは、以下のようなことです。
なんか、ヒントがあったら教えてください(_o_)
ScratchホストのIP設定の改善
ソースファイルに書くのはいけてない(host変数)
code:network.h
const char* ssid = "SSID";
const char* password = "PASSWORD";
const char* host = "Scratch Host IP";
初期化時に入力する?: 入力がめんどくさそう
SDに保存した設定見る?: 対応できない機種がある
LovyanLauncher使ってる場合、どうせSDはあるから/M5Scratch.txtなんかで設定する
他の不揮発性メモリを使う?
無線LAN設定をどうするのがいいのか?
現状では、LovyanLauncher、SmartConfig、直書きの方法が取れる
他の方法は? 初期化時にUI使って手入力? 不揮発性メモリに記録?
他ボード対応
Wio Terminal対応
ATOM Lite対応 (vs ATOM Matrix): どうやって、ATOM Matrixの場合と切り分けるか?
2021/02/24時点で、boards.txtにM5StickC Plus対応が入っているので、場合分けが可能になりました。M5StickC Plus対応 (vs M5StickC): どうやって、M5StickCの場合と切り分けるか?
なんちゃってheadingの改善: 初期化時に地磁気のカリブレーションが必要
M5Scratch側では、1文字の変数名しか使えない: switch文を使って分岐しているためでifで分岐すればいいだけ
ScratchからM5S*へのデータのパース部分がイケてない
Scratch 3.0対応
Scratch を改造しように説明が
やっぱり、Bluetooth Low Energyで接続したい: Microbit Moreが参考になる?
おわりに
何回か発表とかしていたら、みなさまのおかげで、えらく遠いところにきてしまいました。
これからも、懲りずに色々教えてください(_o_)
M5Scratchとむとうのこれからにご期待ください。
おまけ:きしかた
/CoderDojoNara/M5Scratch for DojoCon Japan 2020 2020年12月27日(日) DojoCon 2020 プログラミングコンテスト
M5Stack Christmas with M5Scratch 2020年12月11日(金)〜2021年01月13日(水) M5Stack Christmas Contest 2020
M5Scratch for みんなのM5Stack自慢大会 2020年07月14日(火) みんなのM5Stack自慢大会, 【オンライン】M5Stackユーザーミーティング vol.8
Scratch Remote SensorとM5StickC/M5Stack Grayとの連携 2020年02月07日(金) M5Stack関西ユーザーミーティング vol.3
/CoderDojoNara/M5StickCとScratchであそぼ 2020年01月18日(日) CoderDojo奈良
/CoderDojoNara/M5StickCとScratchで遊ぼう 2019年12月05日(木) M5Stack Advent Calendar 2019の5日目
/CoderDojoNara/M5StackとScratchであそぼ 2019年05月18日(土) CoderDojo奈良
/BSD/うち、やっぱ、Scratch_Remote_Sensorが、むっちゃ好っきゃねん 2018年8月15日(水) Scratchers Meetup 関西 夜の部 LT
Scratch1.4をBSDで使ってみるために 2017年02月11日(土) 関西*BSDユーザ会 第1回研究会
Scratch遠隔センサーとESP8266 2016年12月24日(土) CoderDojo奈良
おまけ:デモ用のネットワーク環境
PQI Air Penみたいな、上流用WiFi接続と、無線LAN APとして働くものがあれば、インターネット接続もでき、Scratch側のIPを固定した構成が可能です。
https://gyazo.com/88b845a823538f452fb7513b2bd4b05a
#M5Stack #M5StickC #ATOMMatrix #Wio_Terminal