PCやスマホは高機能な分、SNSの通知やブラウザの誘惑で、「思考をそのまま吐き出す」ことをいつも邪魔してきます。自作キーボードの打鍵感を活かしつつ、手のひらサイズの独立したハードウェア(M5Cardputer)で文章を書き留め、自動でGitHubへ逃がす。そんなポータブル執筆デバイスを作ることにしました。
作っている途中で、書いていない待機時間にも愛着が持てる存在にしたくなりました。卓上ロボット「スタックチャン」のミニマルな表情アニメーションと、Gemini 2.5 Flash Liteによる対話・英語練習機能も統合することになりました。結果として、「無心で書くノートデッキ」と「デスクで見守ってくれるスタックチャン」が同居する、少し欲張りなデバイスになっています。
全体の構成
自作キーボードをUSB Type-C OTG経由でM5Cardputerに繋ぎ、入力されたキーはローマ字→かな変換エンジンを通ります。Enterを押すと、そのひらがな文字列がGemini APIに送られて自然な漢字混じり文に変換され、GitHubへMarkdownとしてコミットされます。表示は240×135の小さな画面に、M5Canvasのダブルバッファで「ノートモード」「スタックチャン」「システムダッシュボード」の3画面を切り替えて出します。
外付けキーボードと本体キーボードを同時に生かす
Cardputer本体にもキーボードが付いています。それでも自作キーボードを同時に使えるようにしたい、という要望がありました。外付けキーボードはUSBホスト機能(EspUsbHost)のコールバックで非同期に拾い、本体キーボードはloop()の中でポーリングします。どちらから打っても、同じ入力バッファ・同じ変換エンジンに合流させています。
ゼロフリクションを目指した日本語変換
マイコン単体でかな漢字変換(IME)を持たせようとすると、辞書データだけで数MB〜十数MBになり、フラッシュとRAMをすぐに食い尽くします。同音異義語の判定精度も上げにくい。
そこで、入力中はオンメモリのローマ字テーブルで「ひらがな」への変換だけをその場で行い、Enterを押した瞬間に、そのひらがな文字列をまとめてGemini 2.5 Flash Liteに投げる方式にしました。
以下のひらがな・カタカナのメモテキストを、文脈に合わせた自然な漢字かな混じり文に直してください。
挨拶や前置き、解説などは一切付けず、変換結果の文章のみを出力してください。
これで、変換候補を選ぶ手間が一切なくなります。ひらがなで殴り書きしてEnterを押すだけで、文脈に合った漢字混じり文が返ってきます。マイコン側に重い辞書を持たせないという判断が、そのままゼロフリクションな体験につながりました。
書いた文章を絶対に失わない設計
通信が不安定な場所で入力中に送信が失敗すると、書いた内容がそのまま消えます。それを避けるため、Enterを押した瞬間、まず内蔵フラッシュ(LittleFS)の/queue/フォルダに生データをそのまま書き込みます。この時点でメモリ上のバッファはクリアするので、直後に電源が落ちてもデータは残ります。
Wi-Fiが圏外なら「Saved Offline」と表示してすぐ次の入力に戻り、オンラインに復帰した次回送信時に、/queue/内を古い順に「AI変換→GitHubコミット→/sent/へ移動」で自動処理します。/sent/側は最大30件を超えたら古いものから自動的に消していく、というローテーションも入れました。書くことを止めない、失わない。そこを一番優先しています。
バッテリー残量が測れない、の原因を辿ったら基板の設計にたどり着いた
getBatteryLevel()やisCharging()を呼んでも、常に0や誤った状態しか返ってきませんでした。原因を追っていくと、そもそもCardputerにはCore2のような専用の電源管理IC(PMIC)が載っておらず、充電ICのステータスピンもマイコンのGPIOに配線されていない、ということが分かりました。電池電圧は、分圧抵抗を介してGPIO 10に直接つながっているだけの、ただのアナログ入力だったのです。
これが分かってしまえば話は早く、GPIO 10のADCを複数回サンプリングして平均を取り、2倍して実電圧を算出。3.30V〜4.15Vの範囲を線形補間して残量パーセントを出し、USB給電時に電圧が4.23V付近までリフトする特性を使って充電中かどうかを自前で判定するロジックを組みました。
ライブラリの不具合を疑って何時間も費やしていました。最後は、ハードウェアの実物の配線を追うところに答えがありました。
小さなスタックチャンと、英語の練習相手
画面の左側74pxに、白い角丸長方形の目2つと小さな口だけの、ミニマルなスタックチャンの顔を置きました。タイマーで自然なまばたきと視線移動を自律的に行い、AIが考えている間は目が点滅・微小振動してステータスを表す、という演出にしています。
チャット画面はCtrl+Spaceで日本語入力と英語直接入力を切り替えられるようにしました。英語モードにすると、ローマ字変換をバイパスしてそのまま英単語が打てます。Gemini側には「英語で話しかけられたら中学生レベルの分かりやすい英語で1〜2文だけ返す」という指示を与えていて、卓上での英会話練習相手としても使える形にしています。
運用まわり
ローマ字・かな変換のテーブルと入力バッファ管理はromaji_engine.hに切り出し、main.cpp側はUI遷移とハードウェア制御に専念させています。自作キーボードがUSBポートを占有している状態でも、ArduinoOTAでWi-Fi経由でのファームウェア更新ができるようにしてあるので、USBケーブルを抜き差しせずに開発を回せています。
—
| キー | 動作 | |—|—| | Ctrl+S | ノート ⇄ スタックチャンチャット の切り替え | | Ctrl+B | バッテリー・システムダッシュボードの表示 | | Ctrl+Space | チャット中の日本語 ⇄ 英語入力の切り替え | | Shift+Enter | 改行(送信しない) | | Enter | 送信・AI変換の実行 |
市販のどのメモ端末にもない構成にはなりました。自作キーボードの打鍵感、Geminiによる同音異義語の自動解決、GitHub直結の保存、卓上のちょっとした相棒。ポモドーロタイマーやI2Sスピーカーでのタイピング音など、まだ足せそうなところは残っています。


コメント