組み込み用途向けのGo言語のサブセットTinyGoによるM5Stack Basicの制御を試す

この記事ははてなエンジニアアドベントカレンダー 2023の6日目の記事です。

6日目の記事は、id:tomato3713 が担当します。

今回は、TinyGoというGo言語の組み込み用途向けのサブセットの紹介をします。

tinygo.org

本家Go言語はリッチなランタイムを持っているためバイナリサイズが大きくなることからマイコンプログラミングには使えませんが、TinyGoは組み込み向けなので非常に小さなバイナリになります。

例えば、TinyGoを試すなかで作成したシリアル通信に文字を書き込むプログラムのバイナリサイズは387KByteと小さいです。 普段書いているWebアプリケーション向けのバイナリは数十MByte単位のサイズなのを考えると信じられないですね。 tomato3713/tinygo-m5stack-sample

> tinygo build -target=m5stack .\cmd\serial\main.go

TinyGoの紹介ではWio Terminal というマイコンを使っていることが多いですが、その他のマイコンでも動作します。 今回は、プロとタイピング用のマイコンとして知られている M5Stack BasicをTinyGoを使って制御してみました。

使用するマイコンは手元にあった古いバージョンのM5Stack Basicです。 M5Stack Basic V2.6--在庫限りwww.switch-science.com

M5Stack Basic はディスプレイやバッテリー、重力加速度センサー、スピーカーなどが内蔵されたプロトタイピング用のマイコンマイコンプログラミング初心者でも手を出しやすい作りになっています。

TinyGoでプログラムを書くための準備

まずは、TinyGoでプログラムを書くための環境を準備します。 Windows を使ってプログラムを書くのでQuick install guide | TinyGoに従い、scoop を使って各種バイナリのインストールを行いました。

scoop install go
scoop install tinygo
scoop install python
pip install esptool

注意点ですが、インストール手順そのままではマイコンに書き込む際に、 error: failed to flash C:\Users\NEKOTO~1\AppData\Local\Temp\tinygo591627648\main.bin: exec: "esptool.py": executable file not found in %PATH% というようなエラーが出てしまいます。 そのため、ワークアラウンドとして %USERPROFILE%\scoop\persist\python\Scripts にある esptool.exeesptool.py.exe にリネームしておきます。 これによりTinyGoが esptool.py のバイナリを見つけられるようになるので書き込みに成功するようになります。

ここまでの環境が動作するかを確認するため、 Serial Monitor | TinyGo を参考にしてシリアルモニタに出力するプログラムを書きました。

package main

import (
    "fmt"
    "time"
)

func main() {
    count := 0
    for {
        fmt.Println(count, ": Hello, World")
        time.Sleep(time.Millisecond * 1000)
        count++
    }
}

ビルドと書き込みは次のコマンドで行います。 実行する際は、M5Stack Basic をPCにUSBで接続してから行ってください。

tinygo flash -target=m5stack .\sample.go

今回はm5stack向けにビルドするので、-target=m5stack を指定しました。 書き込み先のポートは指定していませんでしたが、勝手に検索してM5Stackを指したポートを見つけて書き込んでくれました。 指定しなくても良い感じにしてくれるの便利ですね。

書き込みに成功すると自動的にM5Stack Basic が再起動して先ほど書き込んだプログラムが実行されます。

VSCodeArduino拡張で使えるシリアルモニターを使ってシリアル通信で fmt.Println(count, ": Hello, World") で書き込んだ内容が出力されていることを確認できました。

シリアル通信で書き込まれた文字を受信している様子

環境が整ったことが確認できたので、画面の描画やボタンクリックの取得するプログラムを書いてみました。 M5Stack BasicにはいっているボードはESP32なので無線通信機能についても試したかったのですが、TinyGoではESP32のWiFi機能等はまだ未サポートだったので試せていません。

実行例

今回作成したサンプルプログラムのリポジトリは、tomato3713/tinygo-m5stack-sample です。 時間が足りなかったので一部の機能しか試せていませんが、今後他の機能についても調査して追加する予定です。 実行可能なプログラムは、cmd ディレクトリの下においているので自分でも試したい場合は、clone して試してみてください。

git clone git@github.com:tomato3713/tinygo-m5stack-sample.git
cd tinygo-m5stack-sample

画面描画

tinydraw パッケージもあるが描画が遅いので可能なら tinygo.org/x/drivers/ili9341 パッケージに定義されているメソッドのほうを使って描画したほうが高速に描画されます。 気になる方は、ライブラリのコードを読みに行くとなんとなく早い理由がわかると思います。

ili9341 package - tinygo.org/x/drivers/ili9341 - Go Packages GitHub - tinygo-org/tinydraw: TinyDraw is a package of drawing primitives on TinyGo displays.

次のコマンドで書き込みます。

// https://github.com/tomato3713/tinygo-m5stack-sample/blob/main/cmd/drawing/main.go
tinygo flash -target=m5stack .\cmd\drawing

書き込みが終わると写真のような図形と文字が描画されます。

./cmd/drawing のプログラムを実行した様子

また、画像を描画したサンプルも作りました。 描画の最適化を行っていないので、かなり描画が遅いですが描画できています。 TinyGoやM5Stack Basicだから描画が遅いというわけではなく、何も工夫をせずに画面描画のプログラムを書くとどのマイコンや言語でもこのぐらいになると思います。 画像はpng形式で用意した後に、 https://xem.github.io/3DShomebrew/tools/image-to-bin.html を使ってbinary形式に変換したものをembedでバイナリに埋め込んでいます。 Renée FrenchによってデザインされたGopherくんを表示してみました。 なお、Gopherくんは CC BY 4.0ライセンスが適用されています。

// https://github.com/tomato3713/tinygo-m5stack-sample/blob/main/cmd/image/main.go
tinygo flash -target=m5stack .\cmd\image

youtu.be

ボタン入力の取得

ボタンが押されているかを取得して、押されているボタンを表示するサンプルを作ってみました。 次のコマンドで書き込んで試します。

// https://github.com/tomato3713/tinygo-m5stack-sample/blob/main/cmd/button/main.go
tinygo flash -target=m5stack .\cmd\button

ボタンをクリックすると pressed key A のように表示されているのでボタンクリックを取得できていることがわかります。 ちらついているように見えるかもしれませんが撮影の関係で肉眼だと気になりません。 youtu.be

感想

ESP32 の無線通信周りがTinyGoではサポートされていないのが少し残念ですが、無線を使わない用途については色々と書けそうでした。 通常のマイコンプログラミングだとC言語を使うことになるので、リッチな型が使いにくいですがTinyGoではGo言語のパッケージが利用できるので書きやすいです。

明日のはてなエンジニアアドベントカレンダー2023担当は id:chris4403さんです。 楽しみです。