powered by TechFeed
表示モード
Deep Dive

ClaudeはESP32をフルPCと思っている — マイコン向けコード生成で踏む4つの罠と回避策

9月2日、How-To Geekが「Claude forgets that my ESP32 isn't a full computer. Here are my 4 fixes」と題した記事を公開した。この記事では、ClaudeがESP32などのマイコン向けMicroPythonコードを生成する際にフルPCと同等の環境を前提とした実装をしてしまう問題と、その回避策4つについて詳しく紹介されている。

9月2日、How-To Geekが「Claude forgets that my ESP32 isn't a full computer. Here are my 4 fixes」と題した記事を公開した。この記事では、ClaudeがESP32などのマイコン向けMicroPythonコードを生成する際にフルPCと同等の環境を前提とした実装をしてしまう問題と、その回避策4つについて詳しく紹介されている。


ESP32はEspressif製の低価格マイコンモジュールで、Wi-FiとBluetoothを内蔵しIoTプロジェクトに広く使われている。RAMは数百キロバイト程度と極めて限られており、汎用のLinux PCとは動作環境が根本的に異なる。MicroPythonはそうしたマイコン上で動作するPythonの軽量実装で、組み込み開発の入門として人気が高い。

Claudeはいわゆる「バイブコーディング(vibe coding)」――自然言語の指示だけでAIにコードを書かせる手法――において、MicroPythonをある程度まともに書ける。しかし、ESP32のような数百キロバイトのRAMしか持たないマイコン向けに生成させると、しばしばLinux PCを相手にするような実装を出力してしまう。記事の著者が実際のプロジェクトで遭遇した問題と対処法を4点にまとめている。


最大の問題:time.sleep()がボードを完全に止める

組み込み入門の定番「Lチカ(LEDの点滅)」では必ず登場するtime.sleep()。Claudeもデフォルトではこれを多用する。問題は、**sleep()の実行中はボードの処理が完全に停止する**点だ。点滅中にボタンを押しても、その入力は無視される。

対策として記事が勧めるのは、**ticks_ms()ticks_diff()を使ったノンブロッキングなタイミング管理**、あるいはasyncioの活用だ。Claudeに対しては、具体的な関数名を指定するか、「いつでも入力を受け付けられるようにしてほしい」と明示的に伝えることが有効だという。

これと関連して、ボタンのチャタリング(debouncing)問題も同様の落とし穴がある。ボタンを1回押しただけなのに複数回押したと認識されるのは、金属接点の微細な振動によるものだ。Claudeはチャタリング対策としてsleep()を挟む実装を書きがちだが、これもボードを止めてしまう。「**sleep()を使わずにデバウンス処理を実装してほしい**」と明示することが必要だ。

デバウンスの実装としては、前回の入力を記録したタイムスタンプと現在時刻の差をticks_diff()で比較し、一定時間(たとえば50ms)以上経過していた場合のみ入力を有効とする方式が組み込みでは標準的だ。sleep()を使わないことで、ボタン監視と他の処理を並行して走らせられる。


再起動しても復帰しないMQTT接続

MQTT(Message Queuing Telemetry Transport)はパブリッシュ/サブスクライブ型の軽量メッセージングプロトコルで、低帯域・低消費電力が求められるIoTデバイスの通信に広く採用されている。ESP32からHome Assistantなどのスマートホームシステムにセンサーデータを送る用途でも定番だ。

しかしClaudeが生成するコード――記事著者によれば、上位モデルであるClaude Opus 5(Claudeシリーズのフラッグシップモデルにあたるバージョン)を使った場合も含め――では、接続が切れた後の再接続処理が抜けていることが多いと指摘されている。

数ヶ月間触らずに動かし続けるデバイスを想定すると、その間にルーターの再起動や停電が起きる。再接続処理がなければ、その都度手動で介入が必要になる。**umqtt.robustの使用を明示的に指示する**か、「自動で再接続するリトライ関数を含めてほしい」とプロンプトに加えることで解消できる。umqtt.robustはMicroPython向けMQTTクライアントライブラリの堅牢版で、接続断を検知して自動再接続を試みる機能を持つ。


Wi-Fiパスワードをハードコードさせない

ClaudeにWi-Fi認証情報を渡すと、スクリプト内に直接ベタ書きしてくる。ネットワーク名やパスワードが変わるたびにコードを修正してフラッシュメモリへの書き込み(フラッシュ)をやり直す羽目になる。

対策は、設定をボードのフラッシュメモリ上のファイルに分離すること。config.jsonが一般的な選択肢で、起動時にスクリプトが読み込む構成にすれば、設定変更のたびに再フラッシュは不要になる。コードをGitHubなどに公開する際に誤ってパスワードを漏洩するリスクも防げる。

バイブコーディングで作ったプログラムで、認証情報をハードコードしたままリポジトリに公開するケースは実際に多い。config.json.gitignoreに追加する習慣を忘れないようにしたい。


バッテリー駆動を想定するならディープスリープを指示する

ESP32プロジェクトをバッテリーで長期間動かす場合、何も指示しなければボードは常時通電状態になり、数日でバッテリーが尽きる。ESP32は通常動作時に数十〜数百mAを消費するが、ディープスリープ時は数マイクロアンペア程度まで消費電力を落とせる。この差は消費電力で3〜4桁にも及ぶ。

Claudeに対しては、「どのくらいの期間動かしたいか」「バッテリーの種類」「太陽電池など外部からの充電があるか」を明示するとよい。たとえば「単3電池2本で3ヶ月動かしたい」といった具体的な条件を与えれば、アイドル時にディープスリープを活用する実装を生成しやすくなる。ディープスリープからの復帰は、タイマーや外部割り込みをトリガーとして使うのが一般的だ。

なお、開発用ボードはオンボードのLEDやUSBシリアルチップが常時電力を消費しているため、バッテリー駆動の最適化が必要な場合は素のESP32モジュールを使うことも検討する価値がある。Claudeへの指示だけでなく、ハードウェア選定の段階から消費電力を意識することが重要だ。


まとめ:プロンプトでClaudeの前提を上書きする

Claudeは概してMicroPythonを書ける能力を持っているが、マイコン特有の制約――RAMの少なさ、ノンブロッキング処理の必要性、接続断からの自動復帰――を自発的に考慮しない。ターゲットボードの型番やRAM容量、動作要件を毎回プロンプトに明示することが、まともなコードを得る最短経路だ。

詳細はClaude forgets that my ESP32 isn't a full computer. Here are my 4 fixesを参照していただきたい。