ModdableのModでスタックチャンの拡張機能を作る
本家スタックチャンのファームウェアはModdableを使って作成されていますが、独自機能の実装はModという仕組みを使って追加することができます。 Modを使うことでファームウェア自体の再焼き込みを行わずに独自機能のみを差し込むことができます。
今回はスタックチャンのModに必要な実装を確認してきます。
とりあえずModを動かしてみる
公式のリポジトリにいくつかModが用意されていますが、特に対向サーバ等の準備が不要な look_at_target を動かしてみます。 ※筆者はM5Gobottom版のケース+M5satck を使用していますが、ソフトウェア的には違いは無いです。
cd /path/to/stack-chan/firmware/mods/look_at_target mcrun -d -m -p esp32/m5stack
mcconfigを使ったファームウェアビルド+焼き込みと異なりあっという間にInstalling mod...complete
と表示され、スタックチャンが左右に一定周期で首振りするようになります。
最小構成で動かしてみる
適当にディレクトリを作成し、必要なファイルは以下2つを用意します。
- manifest.json
通常のModdableアプリケーション同様に使用するModuleやResourceの定義をしますが、今回は特に何も足さないので、Modとして動かすための最小の以下とします。
{ "modules": { "*": "./mod" } }
- mod.js
ここにModのロジックを記載します。まずは、スタックチャンのファームウェア(main.ts)から呼び出される関数を用意します。 これらの関数を用意しなければmain.ts側でデフォルトの動作が設定されます。
// Modの読み込み後に呼ばれる function onLaunch() { trace(`[Mod_test]onLaunch\n`); // Avatarを含むApplicaitonを返す(返さない場合はmain.ts側でデフォルトで生成される) } // Robot(Servo等の制御モジュール)の初期化後に呼ばれる function onRobotCreated(r) { trace(`[Mod_test]onRobotCreated\n`); } // M5stackの物理ボタンが謳歌されると呼ばれる(Core2は非対応) function onButtonChange(btn,released) { trace(`[Mod_test]onButtonChange btn:${btn} / pressed:${released}\n`); } export default { onLaunch, onRobotCreated, onButtonChange, autoLoop: false }
ディレクトリに移動し、同様にmcrun
でインストールすると起動します。
物理ボタンA,B,Cを順番に押下したときのxsbugのログ。
modules of mod: ["mod","check","mod/config"] modules of host: ["pins/digital","ili9341","m5button","time","timer","Resource","mdns","dns","modules","wifi","socket","net","sntp","websocket","base64","logical","crypt","tts-remote","tts-local","http","commodetto/Bitmap","pins/digital/monitor","pins/audioout","setup/target","m5stack/screen","commodetto/Poco","commodetto/parseBMP","commodetto/parseRLE","piu/All","piu/Timeline","piu/CombTransition","piu/MC","piu/WipeTransition","setup/piu","dns/parser","dns/serializer","pins/servo","serial","init-network","speeches","mc/config","avatar","balloon","emoticon","marquee-label","rs30x","main","robot","rs30x-driver","sg90-driver"] [Mod_test]onLaunch [Mod_test]onRobotCreated [Mod_test]onButtonChange btn:A / released:0 [Mod_test]onButtonChange btn:A /released:1 [Mod_test]onButtonChange btn:B / released:0 [Mod_test]onButtonChange btn:B / released:1 [Mod_test]onButtonChange btn:C / released:0 [Mod_test]onButtonChange btn:C /released:1
ちょっと改良してスタックチャンを動かす
import { Target } from 'robot' let robot; let panAngle; let tiltAngle; // Modの読み込み後に呼ばれる function onLaunch() { trace(`[Mod_test]onLaunch\n`); // Avatarを含むApplicaitonを返す(返さない場合はmain.ts側でデフォルトで生成される) } // Robot(Servo等の制御モジュール)の初期化後に呼ばれる function onRobotCreated(r) { trace(`[Mod_test]onRobotCreated\n`); panAngle = 90; tiltAngle = 90; robot = r; robot._driver._pan.write(panAngle) robot._driver._tilt.write(tiltAngle) } // M5stackの物理ボタンが謳歌されると呼ばれる(Core2は非対応) function onButtonChange(btn, released) { trace(`[Mod_test]onButtonChange btn:${btn} / pressed:${released}\n`); if (released) { switch (btn) { case "A": panAngle -= 10; break; case "B": panAngle += 10; break; case "C": panAngle = 90; break; } robot._driver._pan.write(panAngle) robot._driver._tilt.write(tiltAngle) trace(`panAngle:${panAngle} / tiltAngle:${tiltAngle}\n`); } } export default { onLaunch, onRobotCreated, onButtonChange, autoLoop: false }
物理ボタン少し押しづらいですが、押下することで左右方向に動くようになりました。
顔の部分(Avatar)の制御をする場合は、onLaunch
内でApplicationを作成して制御ができます。
スタックチャンの顔こと moddable-avatarを動かしてみた
スタックチャンの顔部分はmoddable-avatarというm5stack-avatarのmodabble移植版から構成されています。
来たる?Walkermanに向けてmoddable-avatarを単独で動かした。
— STC (@stc1988) 2021年11月19日
ということで単独でリポジトリのmain.ts動かすためのメモです。
構築
Typescriptで実装されているので、Moddableを環境構築の上、Typescriptをインストールしておく。
リポジトリをcloneしたらnpm install
で開発ツール類をインストールします。moddableでのビルド自体には必須ではなさそう。
ここでビルドをすると、以下問題が発生します。
- piuの型定義を解消できない
- piu/Timelineの定義ファイルが不足している
- 起動時に
main
モジュールが見つからない- 2023/8/1時点で本件は解消されました。
manifest.json
でincludeとmoduleを修正。
"build": {}, - "include": ["$(MODDABLE)/examples/manifest_base.json", "$(MODDABLE)/examples/manifest_piu.json"], + "include": ["$(MODDABLE)/examples/manifest_base.json","$(MODDABLE)/examples/manifest_piu.json","$(MODDABLE)/examples/manifest_typings.json"], "resources": { "*": ["./assets/images/*"], "*-alpha": ["./assets/fonts/*"] }, "modules": { - "*": ["./main", "./avatar", "./marquee-label", "./balloon", "./emoticon"] + "*": ["./src/main", "./src/avatar", "./src/marquee-label", "./src/balloon", "./src/emoticon"] },
piu/Timelineの型定義ファイルをstack-chanのリポジトリから$(MODDABLE)/typings/piu
に移動します。
https://github.com/meganetaaan/stack-chan/blob/main/firmware/typings/piu/Timeline.d.ts
これで、main.tsが動くようになります。
また、ユーザからのインタラクションも不要であれば、シミュレーターでも動作します。
Avatarクラスのパラメータ
Arguments | Type | Description |
---|---|---|
primaryColor | color | 目の色 |
secondaryColor | color | 顔の色 |
primaryColor : 'white', secondaryColor :'black'
とすると、いつもと顔色が変わります。
Arguments | Type | Default value | Description |
---|---|---|---|
gaze.x | number | 0 | 視線の座標x(setGazeで使う) |
gaze.y | number | 0 | 視線の座標y(setGazeで使う) |
breath | number | 3 | 呼吸してるように上下に揺れる動きの距離(実装未使用?) |
eyeOpen | number | 0 | 未実装? |
eyebrowOpen | number | 0 | 未実装? |
mouthOpen | number | 0 | 未実装? |
gazeInterval | number | 4000 | 眼振動作の有無 (おそらく2回目以降は1~3秒間隔?) |
blinkInterval | number | 4000 | 瞬き動作の間隔(おそらく2回目以降は1~3秒間隔?) |
autoUpdateBlink | boolean | true | 瞬き動作の有無 |
autoUpdateBreath | boolean | true | 呼吸動作の有無 |
autoUpdateGaze | boolean | true | 眼振動作の有無 |
emotion | Emotion | Emotion.NEUTRAL | 喜怒哀楽などの6種定義があるが未実装 |
delegate event
startSpeech
口をパクパク動かす
stopSpeech
startSpeechの動作を止める
setGaze(x, y) setFocusPoint(x, y)
画面の(x, y)座標方向に視線を向ける
Moddable July 12, 2021がリリースされました
XSの改善
ECMAScript® Embedded Systems API 仕様対応
SubPlatformのProvider定義追加
esp32/m5stack などSubPlatformに対してもProvider定義が追加されました。ESP32配下のSubPlatformはほとんど対応されているようです。I2CやSPIをはじめとしてSubPlatform固有のピンアサインが定義されています。
IOクラスを用いたセンサー類のドライバー実装の追加
NTC ThermistorセンサーやAHT10が追加
対応ボード追加
SparkFun Thing Plusが追加となりました。
音声再生
AudioOutでSBCエンコードの再生に対応
SBCとはBluetoothに使用される音声圧縮方法のことだそうです。
AudioOutで矩形波のトーン再生に対応
M5stack本家ライブラリのM5.speaker.tone相当が実現できます。
QRcodeモジュールの改善
TextDecoder, TextEncoderモジュールの追加
UTF-8バイト列と文字列の変換ができる
mcbundleのドキュメント追加
Moddable Store(?!)向けにアプリケーションをパッケージングするためのツールのようです。 パッケージングするための定義はmanifest.jsonに記載する模様。
Windowsには対応してないようなので動作確認は未実施
Moddable June 3, 2021がリリースされました
ESP32関連
ESP-IDFが4.2から4.2.1にアップデート
ESP32を使っている場合は必要となります。アップデート方法は参照
カスタムブートローダーの使用が可能に
XSの改善
今回改善されたString.fromArrayBuffer
はXS独自機能のようで、BTなどの通信時にバイト列から文字列をデコードする用途に使われます。
String.fromArrayBuffer is one of the extensions to JavaScript the XS engine provides for embedded systems. It's a fast, light way to convert a buffer of UTF-8 data to a string. It validates the input as UTF-8 and can optionally extract just a slice of the buffer.
— Moddable (@moddabletech) 2021年6月5日
GIPHYアプリ
contributed
にGIPHYというGIF動画共有サービスから検索し表示するアプリが追加されました。動作にはGIPHYのAPIキーが必要となります。また、検索文字入力のためにタッチスクリーンも必要。
画面が少し小さくタッチスクリーンが使いずらい部分やGIF表示時固まるといった不安点な動作が見られましたがM5stackCore2でも確認ができます。元アプリはModdableTwoをベースに画面作成されています。
ECMA TC53のAPI仕様対応
HostProviderインスタンスの名称変更
ボード固有のピンアサイン等を定義したHostProviderインスタンスの名称がHost
からdevice
に変わります。このHostProviderインスタンスの具体的な使い方については、後述するIOクラスを用いたドライバ実装中で確認できます。
IOクラスを用いたセンサー類のドライバー実装の追加
I2CやSMBusを使ったドライバ実装modules/drivers/sensors
に追加され、examplesにも対応するプログラムがあるので、M5stackのENVⅡUnitとかでサッと動作確認が可能です。
SMBusのメソッド名がTC53の仕様に合ってないとdicussionに書いた一方で、既存のままで実装されてるけど、どうするのだろ。
新しくドライバー類を作成ないし、コントリビュートするに当たっては、IOクラスを用いたほうがよさそうだけど、まだまだ過渡期の入り口な印象です。以下感想
IOクラスのI2C実装見てる。
— STC (@stc1988) 2021年5月30日
pinsの時はdata,clockピンが未指定だとhファイルからdefineを使用していたが、指定は必須となり、デフォルト値はprovider.deviceに定義されるようになってる。
今みでminifestに書いてたのは不要になるのかな。以降の過渡期に混乱しそう。
CRCモジュールの追加
上記のドライバー追加に合わせてチェックサムのためのモジュールが追加されています。使い方はドライバーの実装内で確認できます。
REPL機能の改善
よりNode.jsに近づいたことですが、まだ触ったことがないので試してみたい。
暗号化やTLSの改善
特になし
Moddable May 4, 2021がリリースされました
ほんの思い付きですが、月1,2回ほどあるリリースノートについて簡単にトピックスの紹介や補足でもしていこうかと思います。 あまり詳しくないor関心の薄い部分については適当な紹介となることはご了承ください
続きを読む「リモートワークの達人」と「思考の整理学」を読んだ
「小さなチーム、大きな仕事」は読んだことがあったけど、こちらは読んだことがなかったので、読んでみた。
パフォーマンスを発揮して働くという点において「小さなチーム…」と共通する部分が多く、読み始めから既視感があっだけど、最後まで読み進めていくと、読んだことがないことが分かって安心?した。
確かに必要なことは全部書いてあった。現実に実践できるかどうかは別にして…な気持ちもあるけど、やれることからやってみたらよい、というマインド。
今回物理文庫本を買うに当たって、たまたま近くに陳列されていた「思考の整理学」も買って読んでみた。
文章を書く上で都合のよいとされる場面に「三上」という言葉があり、朝一が最も頭が整理された状態であるし、気分を変えていつもと違う場所で考えてみる、といった部分はリモートワークにもリンクする部分があり面白かった。
もちろん、これ以外にも創造的な思考をするために必要なことが書いてあるので、リモートワーク関係なく読んでよかった。
【Moddable】manifest.jsonで定義した値が適用されているか確認する
manifest.jsonにconfig
やdefine
といった設定値が定義されていますが、Exampleのアプリケーションを動かしてたり、新しいボード対応とかをしていると、ここで定義した値通りに動いてないのでは、みたいな場面に遭遇することが稀によくあります。
ということで、いくつか確認できたものを例に紹介する
確認する場所
mcconfig
コマンドでビルドされた生成物は以下フォルダに格納されている。
${MODDABLE}/build/tmp/$(platform)/$(subplatform)/debug/$(Application)
esp32/m5stack
でhelloworld
アプリを動かしたなら
moddable/build/tmp/esp32/m5stack/debug/helloworld
結論としてはここにあるヘッダファイルが自動生成され、ビルド時に参照される。
define
例えば以下のようにI2Cのデフォルトsda,sclピンとかが定義されていると、
"defines": { "i2c": { "sda_pin": 21, "scl_pin": 22 }
mc.defines.h
のヘッダファイル内で以下のような定義に自動生成される。
#define MODDEF_I2C_SDA_PIN (21) #define MODDEF_I2C_SCL_PIN (22)
この定義はmodules/pins/i2c/esp/modI2C.c
で参照されており、I2Cコンストラクタでsda,sclが指定されていない場合のデフォルト値として利用されていることがわかる。
#if defined(MODDEF_I2C_SDA_PIN) && defined(MODDEF_I2C_SCL_PIN) conf.sda_io_num = (-1 == config->sda) ? MODDEF_I2C_SDA_PIN : config->sda; conf.scl_io_num = (-1 == config->scl) ? MODDEF_I2C_SCL_PIN : config->scl; #else
config
アプリケーションで利用する際にはimport config from "mc/config";
でインポートして参照する設定値。
"config": { "screen": "m5stack/screen", "rotation": 90, "touch": "", }
mc.config.js
を見たらだいだい見たまんま
mc.rotation.h
画面出力する場合は本ファイルで定義されるkPocoRotation
が画面の向きを決定する。実際この値が変わると参照しているcommodettoやpiuは再ビルドが走る。
ここに適用される値は、config.rotaion
が適用されるが、mcconfig
の-rオプション
を指定していた場合はその値が優先される。
複数のmanifest.jsonで同じ定義が衝突したとき
ApplicationやPlatformやModuleごとに定義されるmanifest.jsonファイルで同じ定義がされていた場合は、(恐らく)定義が読み込まれてた順で後勝ちになっていそう。
例えばM5stackのアプリケーションでexamples/manifest_base.json
を読み込んだ場合は、
includeで以下のように辿って読み込まれていく。
(アプリケーションのmanifest.json) ┗ $(MODDABLE)/examples/manifest_base.json ┗$(BUILD)/devices/esp32/manifest.json ┗$(BUILD)/devices/esp32/targets/m5stack/manifest.json ┗(以下略)
ただし、includeで先読みしてくため、下から上に向かってdeinfeやconfigは読み込まれていく(アプリケーションのmanifest.jsonでで定義したものが最終的に後勝ちになる)ので、意図しない定義値が適用されているときは、manifestの読み込み順にも注意したほうがよい。
まとめ
Platformで定義した値をSubPlatformで上書きできない点がモヤモヤする(嵌った)ところですが、意図する値となってないと思ったら値を確認してみましょう。