MeKaBuキーボード開発記 - 一人のメンバーが語る挑戦と挫折の物語
はじめに
MeKaBuキーボードプロジェクトのメンバーとして、この開発期間を振り返ると、技術的な学びだけでなく、自分自身の成長を感じる日々でした。
この記事では、華やかな技術解説ではなく、一人の開発者として私が直面した課題、失敗、そしてそこから得た教訓について率直に書いてみたいと思います。
プロジェクトとの出会い
なぜMeKaBuキーボードプロジェクトに参加したのか
共同でキーボードを作るメンバーの募集を見かけて、ソースコードくらいならサクッと作れるから参加して手伝ってみようか〜くらいの軽い気持ちで参加しました。
最初は軽い気持ちで参加したものの、実際に開発が始まると想像以上の困難が待ち受けていました。特に、MeKaBuキーボードの最大の特徴である「外部モジュールによって入力デバイスを変更できる」という機能の実現が、予想をはるかに超える技術的挑戦だったのです。
MeKaBuキーボードの革新的な特徴
外部モジュール交換システム
MeKaBuキーボードの最大の特徴は、外部モジュールを交換することで入力デバイスを自由に変更できることです:
トラックボール:精密なポインター操作
ロータリーエンコーダー:スクロールやボリューム調整
アナログスティック:ゲーミング用途や3D操作
「キーボードなのにマウスもゲームパッドも不要」という発想は魅力的でしたが、これを実現するソフトウェアの複雑さを理解するまでに時間がかかりました。
開発メンバーとしての日々
担当した領域と初期の甘い認識
私が主に担当したのはソフトウェア面でした。
正直に言うと、最初は「モジュールが変わったら設定ファイルを読み込み直せばいいだけでしょ?」と思っていました。この認識の甘さが、後に大きな壁となって立ちはだかることになります。
最初の大きな挫折:モジュール認識地獄
問題発生:動的モジュール切り替えの実現
開発開始からしばらくして、「ソースコードの量が莫大になる」という深刻な問題が発生しました。
当初の素朴な実装では、モジュールごとにShieldのコードを用意し、ファームウェアをそれぞれビルドさせる方法でした。左手は各種モジュール、右手はトラックボールというように、組み合わせがある程度決まっている想定でした。
しかしある時、メンバーの一人からの「右手ってトラックボール固定ですか?!」という言葉で流れが変わりました。
右手にエンコーダを接続したり、左手にトラックボールを載せたり、なんならダブルトラックボールなんて構成もできてしまうのでは?そう、ここでMeKaBuが秘めていた巨大なポテンシャルの片鱗を垣間見てしまいました。
この時の絶望感は今でも鮮明に覚えています。「モジュールの差し替えなんて、USBデバイスの抜き差しと同じようなものだろう」と思っていたので、モジュールの左右共用可能性が見えたことで、これから爆発的に増加するコードの量に愕然としました。
立ち直るまでの道のり:ZMK Discordでの相談
一人で悩んでいても解決しないと思い、ZMKのDiscordサーバーで相談してみることにしました。
ZMK界隈の先輩方から「snippetを使えばいいんじゃない?」などのアドバイスをいただき、希望の光が見えた気がしました。
しかし、実際にsnippet法を試してみると...
snippet法の挫折と独自解決への道
ZMKのsnippet機能を使った動的モジュール切り替えに挑戦しましたが、以下の問題に直面:
// snippet法での試行(結果的に失敗)
#ifdef MODULE_TRACKBALL
// トラックボール用のコード
#elif MODULE_ENCODER
// エンコーダー用のコード
#endif
この方法では、.confファイルの動的切り替えができませんでした。
「やっぱりダメか...」と一度は諦めかけましたが、snippet法のコンセプトをヒントに、独自の解決方法を模索し始めました。
自力での解決:モジュール.dstiシステムの発見
数週間の試行錯誤の末、snippet法の考えを「逆転する」というアイデアを思いつきました。これが後のモジュール.dstiシステムの原型となります。
モジュールごとに.overlayと.confを用意し、それらからincludeでbase.dstiや共通.dstiを呼び出していきます。
この瞬間の「これだ!」という感覚は今でも忘れられません。誰かに教えてもらった解決策ではなく、自分の頭で考えて辿り着けたことが何より嬉しかったです。
技術的な学びと個人的成長
苦労した技術課題
課題1:モジュール.dstiシステムの設計
状況:各モジュール(トラックボール、ロータリーエンコーダー、アナログスティック)が全く異なる入力特性を持つため、統一的な制御方法が必要だった。
試行錯誤:
- 最初に試したアプローチ:単純な設定ファイルでの切り替え → モジュール特有の機能が使えない
- 次に試したこと:各モジュール用に個別のファームウェアを作成 → メンテナンスが地獄
- 最終的な解決策:各モジュール用の.dstiを動的読み込み
学んだこと:抽象化の重要性と、拡張性を考慮した設計の難しさを痛感しました。
課題2:限られたGPIOでの多様な通信方式の実現
特に印象深いのは、「拡張モジュール用のGPIOがたった4本しかない」という制約の中で、異なる通信方式を実現する問題でした。
物理制約:
- 拡張モジュール接続端子:Vcc、GND + GPIO 4本のみ
- トラックボール:SPIが必要(MISO、MOSI、SCK、CS)
- アナログスティック:アナログ入力2本(X軸、Y軸)
- ロータリーエンコーダー:デジタル入力2本(A相、B相)
深夜の開発で、「SPIを使ったらアナログスティック用のピンが足りない...」と頭を抱えていた自分を思い出します。
結局、解決の鍵は各モジュールが排他的に使用される前提で、GPIO機能を動的に切り替えることでした。この経験で、限られたハードウェアリソースを最大限活用する設計の面白さを学びました。
課題3:物理的なモジュール接続方法の模索
ソフトウェア面でのモジュール.dstiシステムが形になってきた頃、次に立ちはだかったのは物理的な接続方法でした。
初期設計:ZHコネクタ + リボンケーブル
当初はZHコネクタから伸びたリボンケーブルでメイン基板とモジュール基板を接続する想定でした。電気的には問題なく動作していたのですが...
問題点:
- コネクタがでかい(物理的制約)
- モジュールやケースの設計に制約
- 付け外しに力が必要
- とても快適とは言えないユーザー体験
実際に試作品を触った時の「うーん、これは毎日使うには厳しいかも...」という感覚は今でも覚えています。技術的には完璧でも、ユーザー体験が悪ければ意味がないと痛感しました。
2回目の挫折と3回目の挑戦:FFCコネクタ導入
「よりユーザーの体験をよくできないか?」と考え、3回目の試作ではFFCコネクタを採用しました。
FFCコネクタの利点:
✓ ケーブルを差し込むだけの簡単接続
✓ フラットケーブルを折りたたんで収納可能
✓ 取り回しの良さが大幅向上
初めてFFCコネクタでモジュール交換をした時の「これだ!」という感覚。ケーブルの薄さとしなやかさ、接続の簡単さは理想的でした。
しかし新たな問題:FFCコネクタ破壊問題
しかし、今度はFFCコネクタの蓋が華奢で、いつの間にか取れてしまう問題が発生しました。
開発中に何度「あれ?蓋がない...」と探し回ったことか。せっかく快適になった接続が、蓋の紛失で台無しになってしまう。小さな部品一つがユーザー体験を大きく左右することを実感しました。蓋を付け直そうとして、ピンセットでつまみ、押し込んだときに何処かに飛んでいったとき、私の心も何処かに飛んでいきました。
最終解決:国内メーカーの頑丈な部品選定
これを受けて、国内メーカーの頑丈そうな部品を選定し直し、より確実なものとしました。
部品の選定基準も「電気特性」だけでなく「物理的耐久性」「ユーザビリティ」まで含めて考えるようになり、ハードウェア設計における総合的な視点を学ぶことができました。
課題4:ドライバ開発への挑戦
リーダーからこのモジュールを使った新しいデバイスを作りたいと、三軸磁気センサーを渡されました。
「ドライバ開発もやってみたいんだよね。」そういったリーダーの言葉を聞いて、私はなんてこったいと思いました。
ドライバなんて書いたことがなかったので、最初は先人が作成したドライバコードをベースに、データシートを読みながら実装を進めてみました。
初回のビルド成功まで
C言語のプログラミングなんてしたことがなく、最初はビルドするだけでもかなりの困難を伴いました。最初にビルドが通ったとき、動くかはまだ分からないのにチームメンバー一同から歓声が上がりました。
動作しないドライバとの格闘
ビルドが通ったものの、見様見真似で作ったドライバは全く動く気配がなく、データシートを見ると、初期化処理や、読み書き時の手続きなどが記載されていることがわかり、これらに従った実装が必要なことがわかりました。
AIを活用した開発
GeminiやManus、ChatGptなど、いろいろなAIにドライバを実装させてテストする日々。とうとう動作するドライバがManusによって作成されました。(紹介リンクから登録いただいた皆様本当にありがとうございました。)
課題5:センサーIC模索の旅
動作するドライバができたものの、次に直面したのは安定性の問題でした。
TLV493Dでの挫折
10回に一度くらいしか正常にセンサーが起動せず、デバッグが非常に困難でした。データシートを見るとハングアップすることがあるという仕様の記述があり、併せてリセット方法が記載されていました。リセットをしようとコードを修正してみましたが、リセットする前にハングアップしてしまっており完全に手が出せなくなりました。
折角ドライバーを作ることができるようになったのだから、ここで諦めるのは悔しい...と調べていると、センサーの後継品を見つけました。この後継品はハングアップの問題が無くなっているらしく、こちらにしてみることにしました。
しかし、ブレイクアウトボードモジュールが存在していなかったため、PCBAで自作のテスト基板を作成して動作検証を行ってみたものの、動作させることはかないませんでした。
Zephyrサポート品への転向
ふと磁気センサーについて調べていると、他にもいろいろある上に、なんとZephyrがサポートしているものもあることがわかりました。ZephyrでサポートされているならZMKで動作させることはほぼ可能と言っても過言ではありません。
-
HMC5883L: Zephyrがサポートしていましたが、感度が敏感すぎて、30cmほどの周囲にマグネットが存在するだけで反応してしまいました。それもそのはず、地磁気センサーだったためです。とても使い物になりませんでした。
-
LIS3MDL: 測定レンジが広いため、実用可能なことを期待していましたが、それでも敏感すぎました。
しかも取れる。
-
MLX30393: 3度目の正直でもかなわない...と開発中止を打診しようと思いながらClaudeに相談していると、この新たなモジュールを提案してきました。なんとZephyrでサポートされている上に、適用用途としてマグネットロータリーエンコーダが記載されていました。
現在このセンサーで検証を進めていますが、実用化ができそうな感触です。
ちなみにドライバの作り方
- データシート、サンプルコードを入手する
- 機能の要件とかをまとめて、claude.mdを書く
- 全部Claude codeに食わせる
- zmk-workspace[https://github.com/kot149/zmk-workspace]でビルドが通るまで、修正を回す
- 完成!
チーム内での役割変化
最初の立ち位置
プロジェクト開始当初、私はファームウェア担当でした。
転機となった出来事
ファームウェアの大枠が早々に出来上がってしまったことと、各メンバーの持ち寄る激アツなアイディアの摩擦熱、そしてあの特徴的なケースの素案が持ち込まれたことで、各メンバーが担当の垣根を越えて設計に携わるようになりました。
新しい責任と挑戦
ファームウェア担当として、ソフトウェア的な限界を見極めることはもちろん、電子回路設計、ケースへのフィードバックなどもしています。
技術面での成長
Before:「設定ファイルを読み込むだけでしょ?」レベルの組み込み初心者
After:
- 動的モジュールローディングシステムの設計・実装ができる
- モジュール.dstiシステムという独自フォーマットの仕様策定経験
- 複数入力デバイスの抽象化レイヤー設計
現在の状況と今後
プロジェクトの現状
現在、MeKaBuキーボードはv4基板の検証中にあります。
この試作はおそらく完成版か、それにとても近いものになると思います。とても楽しみです。
さらに、他にもいろいろな入力デバイスを実装して、更なる進化の方向を模索しています。
同じような挑戦をする人へのメッセージ
やってよかったこと
共同開発をする:一人では思いつかないアイデアや解決策がチームメンバーから生まれ、技術的な壁を突破できました。
オープンなコミュニティで相談する:ZMK Discordで質問したことで、snippet法というヒントを得られました。考え方の方向性を示してもらえました。
他人のアドバイスを鵜呑みにせず、自分で検証する:snippet法をそのまま使うのではなく、その考え方を自分なりに解釈・発展させたことで、独自のモジュール.dstiシステムにたどり着けました。
失敗を恐れずに独自手法に挑戦:「既存の方法では無理だ」と分かった時点で、自分で新しいアプローチを考える勇気を持てたことが成功につながりました。
おわりに
MeKaBuキーボードプロジェクトに参加したこの経験は、私にとって技術者として、そして一人の人間として大きな成長の機会となりました。
失敗もたくさんしましたし、今でも解決できていない課題もあります。しかし、この経験なしには今の自分はありません。
何より大切なのは、完璧である必要はないということです。
挑戦すること、失敗から学ぶこと、そしてチームメンバーと一緒に困難を乗り越えること。これらが、技術的なスキル以上に価値のある経験だったと思います。
MeKaBuキーボードはまだ完成していませんが、この記事を読んでくださった方に少しでも開発の現実や、挑戦することの意味が伝われば嬉しいです。
Discussion