WSL2 + Docker で M5Stack CoreS3 Lite にスタックチャンをデプロイする

Tips

はじめに

スイッチサイエンスで販売されたM5 スタックチャン AIデスクトップロボット(ESP32-S3搭載)の争奪戦に敗れました。 しばらく放心したあと、完成品が買えないなら作ればよいということで、M5Stack CoreS3 Lite – ESP32S3 IoT開発キットを購入しました。

今回は WSL2 上で公式リポジトリの Docker 環境を使い、M5Stack CoreS3 Lite にスタックチャンのファームウェアをデプロイするまでの手順をまとめます。 初めての M5Stack だったため、起動しなくなったときはかなり焦りました。 同じ環境で作る方が、復旧手段を含めて見通しを持てるように残しておきます。

スタックチャンとは

スタックチャンはししかわさんが開発、公開している、手乗りサイズのスーパーカワイイコミュニケーションロボットです。 作品ページ:https://github.com/stack-chan/stack-chan

動作確認環境

項目 内容
Windows 側 Windows + PowerShell
Linux 側 WSL2 / Ubuntu 24.04
USB パススルー usbipd-win
ビルド環境 Docker
デバイス M5Stack CoreS3 Lite
target esp32/m5stack_cores3

WSL2 から M5Stack へ直接 USB 接続するため、Windows 側では usbipd を使います。 ビルド環境はホストの WSL に直接作らず、公式リポジトリの Dockerfile をベースにしました。

なぜ Docker を使うのか

スタックチャンのファームウェアをビルドするには、Node.js、xs-dev、Moddable SDK、ESP-IDF、fontbm などが必要です。 WSL に直接入れることもできますが、依存関係が多く、失敗したときに環境を戻しづらいと感じました。

Docker に閉じ込めておけば、失敗してもイメージを作り直せます。 一方で、実機へデプロイするには USB デバイスをコンテナへ渡す必要があります。 そのため、Windows から WSL へは usbipd、WSL から Docker へは --device を使う構成にしました。

Windows 側で USB を WSL2 に渡す

まず Windows 側の PowerShell(管理者権限) で M5Stack の BUSID を確認します。

usbipd list

初回は対象デバイスを bind します。

usbipd bind --busid <BUSID>

その後、WSL2 へアタッチします。 筆者の環境では、抜き差し後も自動で再アタッチしたかったため --auto-attach を付けました。

usbipd attach --wsl --auto-attach --busid <BUSID>

実行すると、次のように WSL 側へデバイスが渡されます。

usbipd: info: Using WSL distribution 'Ubuntu-24.04' to attach; the device will be available in all WSL 2 distributions.
usbipd: info: Loading vhci_hcd module.
usbipd: info: Detected networking mode 'nat'.
usbipd: info: Using IP address 172.21.32.1 to reach the host.
usbipd: info: Starting endless attach loop; press Ctrl+C to quit.
WSL Monitoring host 172.21.32.1 for BUSID: <BUSID>
WSL 2026-05-26 22:31:45 Device <BUSID> is available. Attempting to attach...
WSL 2026-05-26 22:31:45 Attach command for device <BUSID> succeeded.
WSL 2026-05-26 22:31:53 Device <BUSID> is now attached.

--auto-attach は待ち受け続けるため、PowerShell はそのまま開いておきます。 途中でデバイスが外れても、次のように再接続を試みてくれます。

WSL 2026-05-26 22:55:45 Device <BUSID> is now detached.
WSL 2026-05-26 22:55:45 Device <BUSID> is available. Attempting to attach...
WSL 2026-05-26 22:55:45 Attach command for device <BUSID> succeeded.
WSL 2026-05-26 22:55:53 Device <BUSID> is now attached.

WSL 側では、デバイスが /dev/ttyACM0 として見えることを確認します。

ls /dev/ttyACM0

存在しない場合は、BUSID が合っているか、PowerShell を管理者権限で開いているかを確認します。

Dockerfile を修正する

公式リポジトリの Dockerfile を使ってビルドしようとしたところ、fontbm が見つからずに失敗しました。

npm run build --target=esp32/m5stack_cores3

エラーは次の内容です。

> stack-chan@0.2.1 build
> cross-env npm_config_target?=esp32/m5stack cross-env-shell mcconfig -d -m -p \$npm_config_target -t build "$PWD/stackchan/manifest_local.json"

# warning: no modules match: /workspace/typings/btutils!
mcconfig: mod partition of size 0x40000 created from factory app partition
mcconfig: file storage partition of size 0x10000 created from factory app partition
### Error: $(FONTBM) environment variable not set. Is fontbm installed?

fontbm はフォント画像を生成するために必要なツールです。 コンテナ内でビルドし、FONTBM 環境変数を設定するように Dockerfile を変更しました。

FROM node:22-trixie-slim

RUN npm install -g xs-dev

# 必要なパッケージをインストール
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        build-essential \
        ca-certificates \
        cmake \
        git \
        libfreetype-dev \
        sudo \
        python3-venv && \
    apt-get clean

# node ユーザーにパスワードなしの sudo 権限を付与
RUN echo "node ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers

USER node

# fontbm をセットアップ
RUN git clone https://github.com/vladimirgamalyan/fontbm.git /home/node/fontbm && \
    cmake -S /home/node/fontbm -B /home/node/fontbm/build && \
    cmake --build /home/node/fontbm/build --parallel

ENV FONTBM=/home/node/fontbm/build/fontbm

# xs-dev をセットアップ
RUN CI=true xs-dev setup
RUN . /home/node/.local/share/xs-dev-export.sh && \
    CI=true xs-dev setup --device=esp32

# 必要な環境変数をロード
RUN echo ". /home/node/.local/share/xs-dev-export.sh" >> ~/.bashrc && \
    echo "export FONTBM=/home/node/fontbm/build/fontbm" >> ~/.bashrc

# 作業ディレクトリの設定
WORKDIR /workspace

ポイントは fontbm をソースからビルドし、ENV FONTBM=/home/node/fontbm/build/fontbm を入れることです。 さらに .bashrc にも同じ設定を追記しておくと、コンテナ内でシェルを開いたあとも同じ環境で作業できます。

Docker イメージをビルドする

Dockerfile を修正したら、公式リポジトリのファームウェアディレクトリでイメージを作ります。

cd firmware
docker build -t stack-chan/dev .

ここで xs-dev setup --device=esp32 まで済ませておくことで、コンテナ起動後にすぐビルドできます。 ビルドに時間はかかりますが、ホスト側の WSL 環境を汚さずに済むのが大きな利点です。

コンテナへ USB デバイスを渡す

WSL 側で /dev/ttyACM0 が見えている状態で、次のコマンドを実行します。

cd firmware
docker run \
    --rm -it \
    --privileged \
    --device /dev/ttyACM0:/dev/ttyACM0 \
    --group-add dialout \
    --user "$(id -u):$(id -g)" \
    --volume "$(pwd):/workspace" \
    -e DISPLAY=$DISPLAY \
    -e FONTBM=/home/node/fontbm/build/fontbm \
    --net=host \
    stack-chan/dev \
    bash

--device /dev/ttyACM0:/dev/ttyACM0 で、WSL に見えている M5Stack をコンテナへ渡しています。

--volume "$(pwd):/workspace" により、現在のリポジトリがコンテナ内の /workspace にマウントされます。 コンテナに入ったあと、プロンプトが次のようになれば準備完了です。

node@EVO-X1:/workspace$

ビルドとデプロイ

コンテナ内で CoreS3 向けの target を指定してビルドします。

npm run build --target=esp32/m5stack_cores3

ビルドが通ったら、そのままデプロイします。

npm run deploy --target=esp32/m5stack_cores3

esp32/m5stack_cores3 は M5Stack CoreS3 向けの target です。 esp32s3/... ではなく、esp32/ 配下の m5stack_cores3 を指定する点に注意します。

今回の環境では、Dockerfile に fontbm を追加したあと、この手順でデプロイまで成功しました。

M5Stack が起動しなくなったときの復旧

一番焦ったのは、ファームウェアのインストールと mod の導入を試したあと、M5Stack が起動しなくなったことです。 初めての M5Stack だったため、壊したのではないかとかなり不安になりました。

結論としては、コンテナ内で npm run erase-flash を実行し、フラッシュ全体を消去することで復旧できました。 このコマンドは内部で esptool erase-flash を呼び出し、ファームウェアだけでなく mod が書き込まれるパーティションも含めて一括で消去します。

Moddable SDK の mod は、ファームウェアとは別の専用パーティションに保存されます。 そのため、ファームウェアを再書き込みするだけでは mod パーティションが残り、起動に失敗し続けることがあります。 erase-flash でフラッシュをまっさらな状態に戻してから、あらためてスタックチャンをデプロイすることで正常起動を確認できました。

この復旧手段を知っているだけで、かなり落ち着いて作業できます。 mod を試す前に npm run erase-flash で全消去して戻せることを把握しておくと安心です。

ハマりポイントまとめ

今回のハマりポイントを整理すると、以下のとおりです。

問題 原因 対処
WSL から M5Stack が見えない USB デバイスが WSL に接続されていない usbipd attach --wsl --auto-attach --busid <BUSID> を使う
Docker 内から /dev/ttyACM0 が見えない コンテナへデバイスを渡していない --device /dev/ttyACM0:/dev/ttyACM0 を付ける
FONTBM エラーでビルド失敗 fontbm が未インストール Dockerfile で fontbm をビルドし、FONTBM を設定する
target を間違える CoreS3 は ESP32-S3 だが target 名は esp32/m5stack_cores3 npm run build --target=esp32/m5stack_cores3 を使う
起動しなくなって焦る mod がフラッシュの専用パーティションに残り起動に失敗し続ける コンテナ内で npm run erase-flash を実行してフラッシュ全体を消去し、再デプロイする

特に FONTBM のエラーは、Docker を使っていても追加対応が必要でした。 公式 Dockerfile をそのまま使えば終わり、と思っていたので少し意外でした。

まとめ

完成したスタックチャン(顔だけ)
完成したスタックチャン(顔だけ)

M5 スタックチャンの争奪戦には敗れましたが、M5Stack CoreS3 Lite を購入して WSL2 + Docker でスタックチャンを動かせました。

WSL2 では USB 接続が少し特殊ですが、usbipd と Docker の --device の流れを押さえれば再現性は高いです。 初めて試す場合は、M5Burner で復旧できる状態を先に作っておくと安心です。 今後は mod の導入やボディの作成なども試していきたいと思います。

コメント

タイトルとURLをコピーしました