
家に置くロボットペットが欲しくなった。条件は4行だけだった。
この4行から発注まで、半日かかった。その間に、最初に書いた仕様のうち2行を捨てている。そして最後の部品選定で、AI に二度だまされた。
全部書く。
スタックチャン。M5Stack という手のひらサイズのマイコンに、サーボ2軸と画面の顔を載せたデスクトップロボットだ。GitHub で公開されていて、3Dプリント用の筐体データもファームウェアも手に入る。M5Stack 社とユーザーコミュニティが一緒に作った完成品版が、スイッチサイエンスで売られてもいる。
つまり、設計としては既に解かれている。
それでも自作を選んだ理由は最後に書く。先に、自作を選んだときに必ず踏む穴から。
部品代は1万円弱で済む。安い。ただし安いのは部品だけだ。
1. 配線のねじれ。 土台を回すと、上に載った液晶とスピーカーのケーブルが必ずねじれる。対策は2つしかない。回転角を ±160 度に制限するか、スリップリング(回転しながら通電できる部品。数百円)を入れるか。前者で妥協するのが普通だが、一周できないペットは生き物らしさが落ちる。
2. サーボの突入電流。 サーボが動き出す瞬間に大きな電流が流れて、マイコン側の電圧が一瞬落ちる。ESP32 はこれでリセットする。軽視すると「たまに再起動する謎の不具合」に何日も溶かす。原因が電気なのかコードなのか、測らないと分からないからだ。
3. 描画と通信が同時に走らない。 WiFi 通信中に SPI(液晶へデータを送る通信規格)の描画が止まり、目のアニメーションがカクつく。ESP32 はコアが2つあるので、描画タスクと通信タスクを別のコアに固定する設計が事実上必須になる。これは後から直せない。
並べてみると性質が見えてくる。ねじれは筐体設計、突入電流は電源回路、コア分離は最初のアーキテクチャ。どれも、コードを書き始める前に決まってしまう。 AI にコードを書かせられる時代になっても、ここは変わらない。
仕様の4行のうち、1行だけ扱いがまったく違う。
| やり方 | 手間 | 問題 |
|---|---|---|
| 事前録音を再生 | 1日で作れる | 1週間で飽きる |
| クラウドの音声合成 | 中 | 応答まで2〜4秒 |
| ラズパイで自前合成 | 大 | 起動20秒、電源ぶち切りでSDカードが死ぬ |
人間は、生き物に対して0.5秒以上の沈黙を許さない。 返事が遅い時点で、それはペットではなく端末に見える。そこで「エッジAI で喋らせる」を検討した。
一言でまとめられがちだが、中身は4段ある。
VAD(発話の検知)→ ASR(文字起こし)→ LLM(応答生成)→ TTS(音声合成)
で、ESP32 にこれは載らない。
つまり ESP32 でできるのは「決まった言葉に決まった返事」までで、事前録音の再生と実質同じだ。
日本語であることも効いてくる。英語前提の記事をそのまま真似ると詰まる。ASR は kotoba-whisper、TTS は VOICEVOX CORE か Open JTalk、LLM は Qwen3 4B や Sarashina2.2-3B あたり。選択肢は限られている。
生き物らしさが成立するのは、呼びかけから発声開始まで1秒以内。許容限界が2秒。
ボード別に4段の合計を見積もったところ、Pi Zero 2W はメモリ不足で話にならず、Pi 5 で 5 秒前後でファン必須、RK3588 系で 3 秒前後、Jetson Orin Nano でやっと 1 秒台。その Jetson は小型ペットの筐体に入る大きさでも発熱でもない。
(この数字はまだ実測ではない。見積もりだ。実測したらこの連載で書き直す)
表を埋めて初めて、自分の前提が逆だと気づいた。ロボットペットの用途では、ローカルLLM は大抵クラウドAPI より遅い。エッジの利点はレイテンシではなく、だった。
だからクラウドに振り切った。OpenAI Realtime API。音声を直接投げて音声が返るので、ASR / LLM / TTS の3段が1回の往復に潰れる。1秒前後になる。VOICEVOX サーバも Whisper も要らない。
代償は3つ。音声トークン課金だからウェイクワードで区切らないと無音を課金され続ける。VOICEVOX のキャラクター音声が使えなくなる。WiFi が落ちたら置物になる。
全部飲んだ。
さらに一歩進めて、土台の回転をやめた。これで、さっきの3つがほぼ全部消えた。
| 問題 | サーボを外した後 |
|---|---|
| 配線のねじれ | 回らないので存在しない |
| 突入電流による再起動 | 消える |
| 電源系統の分離 | USB 5V/1A で足りる |
| 動作音とジッター | 完全な無音 |
| サーボID設定、半二重変換 | 全部不要 |
部品も3点減って、約4,000円安くなった。
失うのは動きだけだが、「首を向ける」は生き物らしさへの寄与が大きい。そこは丸型液晶2枚で埋めに行く。サッカード(視線が細かく跳ぶ動き)と短い瞬き、両目の独立制御による寄り目と追視、瞳孔径の変化。
首振りは「向くか向かないか」の離散的な動きだが、視線は連続的で、情報量としてはこちらのほうが多い。妥協ではなく別の表現に振ったと考えていいと思っている。これは実機で確かめる。
ここで、丸型液晶2枚の顔にするためにスタックチャンを離れ、自作に戻った。スタックチャンの顔は四角い画面1枚だからだ。
設計が決まったので、具体的な部品を選び始めた。Amazon の商品ページを貼って「これでいい?」と AI に聞く。仕様を読んで答えてくれる。便利だった。
途中で、同じ回答の中に寸法が2つ並んでいるのに気づいた。「40.4×37.5mm」と「45.5×48×11.5mm」。両方が同じ製品のものであるはずがない。
「別のページ見てない?」と聞いた。AI は全面的に謝った。
ドライバIC・ピン配置・CS端子・寸法・枚数、どれも私は確認できていません。
部品表が一瞬で砂になった。
対話だけで進めるのをやめて、Claude Code にブラウザを開かせ、商品ページを自分で読ませた。
「40.4×37.5mm」も「45.5×48×11.5mm」も、両方とも実際にそのページに載っていた。 箇条書きと商品説明で寸法が違う。枚数も同じだった。
| 場所 | 枚数 |
|---|---|
| 商品名 | 2個セット |
| 箇条書き | 3個 |
| 商品の説明 | 2個 |
出品者がメーカー(Waveshare)の公式文章をコピーして、自社製品の寸法と並記してしまっている。確かめたら 40.4×37.5mm は Waveshare の公称値と一字一句同じだった。
つまり最初の回答は「別のページの情報を混ぜた」のではなかった。読んでいた。読んだ先が矛盾していただけだ。間違っていたのは「3枚入り」と断定した点だけ。箇条書きだけを採用した、というミスだ。
嘘をつくのも問題だが、正しい情報を全部引っ込めるのも同じくらい困る。 謝罪を信じていたら、実際には正しかった仕様を全部捨てて、もう一度調べ直すところだった。
どちらも、一次情報に当たっていないから起きる。
一番心配していたのは CS 端子の有無だった。丸型液晶を2枚使うには SPI バスを共有して CS(どちらの画面に送るかを選ぶ端子)だけ分ける。安いモジュールには CS が GND 固定で外に出ていないものがあり、その場合は2枚制御ができない。
商品説明にピンの一覧はなかった。でも商品画像には基板が写っている。拡大した。
VCC / GND / SCL / SDA / DC / CS / RST
CS あり。 発注していい。仕様欄を何回読んでも出てこない情報だった。画像にしかなかった。
アンプの型番も同じやり方で確定した。MAX98357 には A と B があり、ESP32 の標準的な I2S 出力には A が要る。商品名には両方書いてある。基板写真を拡大したら MAX 98357A I2S Amp と印刷されていた。
候補の Freenove ESP32-S3 ボードは型番に「Lite」と付いている。対話の AI は「Lite は PSRAM が削られている可能性がある」と警告した。開いてみたら、商品ページに「8MBのフラッシュメモリ、8MB PSRAM」と明記されていた。レビューにも「PSRAM が別途 8MB ある」と書いている人がいた。警告は空振りだった。
ただし、同じ AI の別の警告は正しかった。 「PSRAM の設定を Octal(OPI)にしないと起動ループする」。これはメーカー公式リポジトリの推奨設定のスクリーンショットで裏が取れた。PSRAM: "OPI PSRAM" とはっきり写っていた。
当たるものと外れるものが混ざる。それが一番厲介だ。
今回使った裏取り先を、信頼できる順に並べる。
| 順位 | 一次情報 | 確定したもの |
|---|---|---|
| 1 | メーカーの公式 wiki / データシート | GC9A01、240×240、8ピンの内訳 |
| 2 | メーカーの GitHub リポジトリ | 推奨ビルド設定(OPI PSRAM) |
| 3 | 公的データベース | 総務省 電波利用ポータルで技適番号 |
| 4 | 商品ページの画像 | 基板のシルク印刷(CS 端子、MAX98357A) |
| 5 | 商品ページの仕様欄 | 信用しない。矛盾している |
2つの AI の違いは、賢さではなかった。実際にページを開けたかどうかだけだった。
そして、AI が謝ったときもそのまま受け取らない。謝罪は検証ではない。
| 品目 | 内容 | 税込 |
|---|---|---|
| 丸型液晶 GC9A01 | 1.28インチ 240×240 IPS 4線式SPI、2個セット | ¥1,799 |
| ESP32-S3 開発ボード | Freenove、8MB Flash + 8MB PSRAM | ¥1,956 |
| I2S マイク | INMP441 | 約¥745〜1,000 |
| I2S アンプ | MAX98357A、2個・デュポンケーブル付 | ¥739 |
| スピーカー | 直径40mm 4Ω/3W、2個 | ¥1,270 |
| ジャンパーワイヤ | 40P×3種 120本 10cm | ¥599 |
| 合計 | 約¥7,100 |
サーボを捨てたので電源は USB 5V/1A で足りる。1000µF のコンデンサも、電流を測る USB テスターも不要になった。筐体は 3D プリントなので実質ゼロ円。
スピーカーを 4Ω にしたのには根拠がある。アンプの商品説明に「4Ω および 10% THD で 3.2W、8Ω および 10% THD で 1.8W」とある。8Ω だと出力が半分になる。
Core2 を外した代償は小さくない。M5Unified というライブラリが電源管理・画面・音声を全部抽象化してくれるし、スタックチャンのファーム資産がそのまま使える。それを全部捨てて、丸い目2枚と引き換えた。見た目がこのプロジェクトの目的なので、そこは割り切っている。
この3つは、届いてから測るしかない。
board_build.arduino.memory_type = qio_opi を先に書いておくface happy、say テスト のように単機能を叩ける状態を作る4つ目が一番効くと思っている。組込みで時間が溶けるのはコードを書く工程ではなく、「動かない理由が分からない」工程だ。AI にコードを書かせても、シリアルに何が出ているかは見えていないし、電源が瞬断しているかも測れない。観測の部分だけが人間に残る。
今回も、実際に商品ページを開いて画像を拡大できたから、確定した。見えないものは、誰が調べても確定しない。
部品は発注済み。届いたら、まず丸型液晶2枚を光らせるところから始める。