⌨️

自作キーボードを自作した話

2024/01/27に公開

この記事は mfk60 という 60% ANSI 配列 (US 配列) の左右分割自作キーボードの制作の過程をまとめたものです。

mfk60

  • 欲しいキーボードが売っていないけれど、自作するにはどうしたら良いのか
  • 自作キーボードのキットは作ったことがあるけれど、次のステップを迷っている
  • 左右分割キーボードが欲しいけれど、欲しい配列の物が売っていない

そんな方に、参考になればと思います。

ソースコード

このキーボードおよびプロトタイプの KiCad のプロジェクト、ツール、ファームウェアのソースコードは GitHub で公開されています。

はじめに

ここ数年、ゲーミング PC の流れもあって以前より多くのキーボードが普及しているように思います。自分も Apple の純正キーボード以外に KeychoneNuPhyMistel などさまざまなブランドのキーボードを購入して試してきました。その中で、長時間作業には姿勢への影響から左右分割キーボードが有効とわかりました。

しかし、もともと Apple 製品を使っていることが多かったこともあって、薄いキーボードを嗜好していたのですが、左右分割キーボードでかつ薄い Low Profile [1] のキーボードという製品はなかなか見かけませんでした。

そこで「無いなら作る」ということで自作キーボードへの道を進むこととなりました。

キットを作る

初めて自作したキーボードは Recompile さんの Choco60 60 rev.2 で、遊舎工房でキットとスイッチ、キーキャップを購入し組み立てました。Choco60 は左右分割キーボードで Cherry MX 互換のスイッチが使えます。Low Profile ではないのですが、分割キーボードの中では組み立てやすく配列も ANSI 配列によく似た Happy Hacking Keyboard (HHKB) と同様のものになっています。

その後 Choco60 をしばらく使っていましたが、Low Profile キーボードを試してみたいという思いも常にありました。そこで Low Profile のスイッチを使った左右分割のキーボードを作ることにしました。

また自作キーボードが完成するまでにサリチル酸さんの 7sKB (Choc) も作り、しばらくの間使っていました。Low Profile で左右分割、安定した構造で使いやすいです。

これらのキットはこの自作キーボードの参考になっています。

プロトタイプの制作

仕様を決める

まず最初に作るキーボードの仕様を固めました。

Gateron Low Profile スイッチの利用は多分わりとレアな選択だと思っています。
自作キーボード界隈では Kailh Choc v1 の利用が多いのですが(最近は Kailh Choc v2 も多いですね)、自作を検討し始めた当時、Kailh Choc v1 のスイッチや、対応したキーキャップの入手性に困難がありました。Gateron Low Profile は既製品の Keychrone や NuPhy が利用しており、スイッチの入手性がよく、構造が Cherry MX 互換なのでキーキャップの選択肢も広がるということで選択しました。

Hot Swap のソケットを使ってスイッチを直付けにしないのは、組み立てのしやすさとやはり交換できたほうが活用の幅が広がるかな、という思いからです。

配列に関しては、自作キーボードのキットでは ANSI 配列でも HHKB の配列で、右上に ~ があるキーボードが多いのですが、自分は MacBook のキーボードを使ってきたこともあって普通の ANSI 配列に馴染みがあり、右上は通常のレイアウトとすることにしました。

作り方を把握する

先人のブログ記事やまとめサイト、作ったキットなどを参考に大まかなキーボードの構造と製造の流れを理解しました。

また設計にはフリーでオープンソースの基板 CAD、KiCad[2] がよく使われるのでその使い方もざっと調べました。

初めてのプロトタイプ

最初に行ったのはスイッチとスタビライザーの仕様を調べて、KiCad の Footprint[3] を作ることでした。
Cherry MX や Kailh Choc v1 などよく使われるスイッチやスタビライザーの Footprint は公開されていているのですが、少なくとも当時は Gateron Low Profile のものはありませんでした。

また、スイッチやスタビライザーそのものは Gateron のショップから直接購入したり、NuPhy のキーボードについているのをバラして手元にあったのですが、なかなか寸法の詳細が手に入りませんでした。
当時は AliExpress に掲載されていた不完全なデータシートや、実物や NuPhy のキーボードを見ながらノギスを使って寸法を調べるなどして Footprint を作りました。

しかしこの Footprint をいきなり実際のキーボード制作にいきなり使うにはばかられました。まず実物から採寸した形状でなのできちっと実装できるかわかりませんし、そもそも基板の製造も初めてなので、大きなキーボードのようなものをいきなり作ると失敗した時の金銭的ダメージが大きいです。

そこで最低限キーボードとして機能するのに必要なものだけを載せたプロトタイプを制作しました。

  • コントローラーに Pro Micro を利用
  • 作った Footprint 使った 5個だけのキーで実装を確認
  • 回路基板とスイッチをはめるトッププレートだけ

プロトタイプの基板製造には JLCPCB を使いました。サイトに書かれている手順に従って、KiCad から Gerber ファイルを出力しアップロード、詳細を選び見積もりして問題なければ発注です。

そして待つこと1週間、ついに基板が届きます。それがこちら、mfk5 rev. 1 です。

mfk5 rev. 1
mfk5 rev. 1

組み立てると、すぐに間違いに気がつきました。トッププレートの形状を間違えてスタビライザーがつきません。幸い修正できる程度の間違いなので無理やりカットして組み立てました。こういったバグ出しがプロトタイプの目的なのでちゃんと目的を果たしたことになります。

mfk5 rev. 1 のミス(1)
スタビライザーの金具が通る隙間が開いていない
mfk5 rev. 1 のミス(2)
無理やりカットして修正

ミドルプレートの追加

最初のプロトタイプではスタビライザーの Footprint が間違っていた以外にも細かな寸法の間違いもあり、それらを修正して再度プロトタイプで確認をすることにしました。

まず回路基板の厚みです。Gateron Low Profile のソケットは基板に埋め込む部分が 1.2mm なので、回路基板も1.2mm である必要があります。しかし最初のプロトタイプでは一般的な 1.6mm で作ってしまったためスイッチがちゃんと固定されませんでした。

またスイッチを固定するトッププレートと回路基板の間に約 1.2mm の隙間ができるのですがこれをネジのナットで支えるのではなく、1.2mm のミドルプレートを追加することで安定させることにしました。

KiCad で追加の新しいミドルプレートを設計し、最初と同じ回路基板データも 1.2mm で発注しなおしてこの構造がうまくいくことを確認しました。

これが mfk5 rev. 2 です。

mfk5 rev. 2
mfk5 rev. 2

Pro Micro を諦める

ここまでのプロトタイプを通して実際のキーボードを作る下準備が整いました。後はこの5個しかないキーを60個くらいまで増やして配置すれば完成、となるはずだったのですが、ここで問題が起こります。

これまでプロトタイプではコントローラーに自作キーボードでよく使われる Arduino 互換の MCU 基板、Pro Micro を使っていたのですが、実際のキーボードのデザインでこれをどこに配置するかという問題があります。

キーの裏面に配置する場合、Pro Micro は左右のピンの幅が 600 mil[4] なのですが Gateron Low Profile のソケットとスイッチの配置上、どう頑張ってもこの幅のピンを干渉することなく配置できません。

他の自作キーボードのキットではスイッチが直付けで幅に余裕があったり、ソケットのサイズが小さくギリギリ 600mil の内側に収まる配置だったり、あるいは Pro Micro を配置する余白をキーの周辺に設けるなど、色々と工夫されているのですが、Gateron Low Profile とソケットを使ったデザインでは物理的に困難でした。

7skb (Choc) における Pro Micro の配置
7skb (Choc) では左右の角にスイッチをギリギリ避ける形で配置されている

他の MCU 基板で、例えば Raspberry Pi Pico のような 700 mil の幅があればなんとか配置できるのですが、Raspberry Pi Pico は Pro Micro と比べても大きいです。

しかし、既存の MCU 基板を場合はどれを使っても厚さかサイズのどちらかを諦める必要がでてきてしまいます。

そこで、カドでスイッチが揃っていて、薄い、すっきりしたデザインにしようと思いたので、Pro Micro などの MCU 基板を使うのを諦め、コントローラーの MCU を含めて全て回路基板に実装する道を選ぶことにしました。

ATmega32U4 を実装する

実は一番最初に自作キーボードを作ることを考えた時は流行病の影響で自作キーボードでよく使われる ATmega32 シリーズがほぼ入手不可でした。そこで、RP2040 など他の MCU も調べていました。

しかし昨今は状況が改善し、ATmega32 シリーズも再び手に入るようになったので、採用例の多さも考えて ATmega32U4 を選択しました。

また QFN[5] でも手ハンダできる場合もあるようなのですが、組み立て環境と道具の問題もあったので、基板製造とともに基板実装も委託することにして、スルーホールの部品のみ手で組み立てることにしました。

ATmega32U4 を使ったキーボードの設計は既にかなりの例があり、部品点数も少なく、動作する部品の組み合わせもわかっていたので、既存の設計を参考に回路設計を行い再度プロトタイプを制作しました。

このプロトタイプでは ATmega32U4 の回路以外にも左右分割キーボードを作る上で必要な左右のシリアル通信用の TRRS コネクタの追加、USB-C の採用など、試さないといけないことを全部詰め込みました。その結果、基板の配線にとても苦労しました。

mfk5 rev. 3 の基板デザイン
mfk5 rev. 3 の基板デザイン

さらに、左右分割キーボードの左右二つのボードを一つのプロジェクトでデザインするため、フレームやマウスバイトをつける KiKit を使ったパネライズも試しました。

こうして出来上がった最後のプロトタイプが mfk5 rev. 3 です。

mfk5 rev. 3
mfk5 rev. 3

キーボードの制作

ここまで、プロトタイプの制作を通じて基本的なキーボードの構造や回路のテスト、スイッチやスタビライザーの実装を確認できたので、実際に使うことができるサイズのキーボードを作ることになります。

ボトムプレートと回路基板の固定方法

キーボードの構造は、スイッチとスタビライザーを固定するトッププレート、隙間を埋めるミドルプレート、回路基板、そして底面を覆うボトムプレートをスペーサーとネジでサンドイッチにする構造にしました。

すべて FR-4 の PCB で製造することにして、全てを基板製造業者に委託すれば完成できるようにしました。

ボトムプレートに関して、裏面にはとても背の高い USB-C レセプタクル (3.22mm) や、TRRS コネクタ (5mm) があるので、先のプロトタイプのように普通にスペーサーを使い両側からネジでサンドイッチする方式だととても厚みがでてしまいます。

そこで、ミドルプレートとボトムプレートの間に 3mm のスペーサーを入れて基盤を挟み込む方式を採用しました。

mfk60 の構造
mfk60 の構造を横から見た図。薄い色の部分は穴が空いている。

その結果、スイッチを除いた部分で厚みを 7mm、スイッチと Low Profile のキーキャップで全体の厚みも MacBook Pro と同程度に抑えることができました。

キーの配列をつくる

まず Keyboard Layout Editor を使ってキーの配列を作成しました。60% の ANSI 配列をつくり 56 の間で分割、右上はそのままです。

mfk60 のキー配列
mfk60 のキー配列

悩んだのは分割されてしまうスペースキーを左右でどのサイズにするかという点です。結局、左右両方とも 2.25u (左の Shift や Enter のサイズ) にしたのですが、実際売られているキーキャップのセットで 2.25u が 4 つ入っていることはレアで、これは失敗だったかなと思っています。
それ以外は特徴がないことが特徴のような配列にしました。

回路と基板の設計

左右それぞれの回路設計を一つのデザインに載せるので、左右ほとんど同じ回路なのですがそのままだと GND など左右に存在するものが繋がってしまいます。それを避けるため、右側のシンボルにすべて R_ のプレフィックスを追加しました。

ちなみにサフィックスにすると USB_D+USB_D- などディファレンシャル信号の認識に失敗してしまうのでプレフィックスになってます。

mfk60 の回路図(右側)
mfk60 の右側回路図の一部

基板設計は前のプロトタイプで詰め込む練習はしたので結構サクサクと進んだのですが、やはり両面基板で綺麗にルーティングするのはなかなか難しいかったです。

表と裏で横方向と縦方法を分ける、ビアの開け方を工夫するなど基本的なことはしているのですがどうしても隙間に詰め込んでいるので結構厳しかったです。この辺プロの技や高価なツールがあったらもっと楽になるのでしょうか。

mff60 の基板デザイン
mfk60 の基板デザインの一部

ツールの作成

KiCad で行う設計を全部手動で行ってもいいのですがスイッチの数が多いのでかなりしんどいので、いくつかの作業をソフトウェアで解決しました。

KiCad の基板設計ツールである pcbnew は C++ の API に Python バインディングがあり、Python スクリプトで基板設計を操作できます。

kicad-kbplacer はそういった Python のツールで Keyboard Layout Editor の JSON ファイルの位置情報をつかって KiCad の基板にスイッチを配置してくれます。
また、プロトタイプでも使った KiKit もパネライズで使いました。

また、KiCad では一つのプロジェクトで一つのデザインとなるので、このキーボードの構成ではトッププレート、ミドルプレート、回路基板、ボトムプレートの4つのプロジェクトを使う必要があります。

そこでそれぞれのプロジェクト間で切り抜きの位置やスイッチなどの位置をベースとなる回路基板とトッププレート、ミドルプレート、ボトムプレートで同期するスクリプトも作成しました。

KiCad のバグとワークアラウンド

ところで、これらのツールはそのまま使うことができませんでした。特に KiKit は独自でフォークしたものを使っています。

理由は2つあって、1つめは KiCad 問題です。KiCad の pcbnew が C++ の API と Python のバインディングにつかう、Swig で生成されたコードに問題があります。モジュールへの参照カウントが正しく行われず、GC が走ったりすると型情報が不必要に解放されてしまい、それ以降オブジェクトの解放ができずリークしたり、メソッドの呼び出しに失敗するという現象が起こります。

これはかなり調べてわかったのですが、問題は Swig の生成するコードにあるので、まず Swig を直した上で KiCad を問題を修正した Swig を使ってコード生成し直してビルドし直すしか解決する方法がなくわりと根深い問題です。しかしワークアラウンドはできるので、このプロジェクトでは KiKit 側でワークアラウンドすることにしました。

2つめは左右のボードを一つのデザインで作っている、データの問題です。二つのボードがあるので外側が Multi Polygon になってしまい、KiKit はそのようなデザインのパネライズを想定しておらず[6]、内側の矩形の検出に失敗します。
これも KiKit を修正してワークアラウンドしました。

キーボードの発注と組み立て

プロトタイプと同様、JLCPCB に全ての基板の製造と実装を発注しました。
ツールをつかって生成したそれぞれのプレートと回路基板のプロジェクトから Gerber ファイルを出力してそれぞれ JLCPCB のサイトアップロードして見積もりに出します。

ここでプレビューが表示されるのですがこのプレビューがかなり曲者で、内側の穴が空かなかったりして混乱しました。かなり動作がランダムで穴がちゃんと空く条件は結局わからなかったのですが、これはあくまでもプレビューなので、Gerber データとしてちゃんと Edge Cut レイヤーに穴があれば実際に穴が空いた基板が製造されます。
これで一日時間を無駄にしました。

mfk60 のJLPCBの回路基板のプレビュー
mfk60 のJLPCBの回路基板のプレビュー。穴の箇所が詰まって表示される。

見積をする際に、パネライズしている場合は必ずその数を指定する必要があります。昔は一つの基板として製造してくれたこともあったようなのですが、左右のボードがパネライズされているような場合は二つのデザインとして事前に指定しないと、後で追加料金がかかります。

また基板外形のサイズがデフォルト値から変わらず正しく指定されなかったことに気が付かずそのまま発注してしまい、余計なやり取りと追加料金が発生してしまいました。必ず発注データを確認しましょう。

ヨシ!
ヨシ!

発注後、基板実装も含めて約5日ですべて手元に届きました。

また並行して事前に Gateron のショップでスイッチとソケット、スタビライザーも発注しておきました。こちらは届くのに1週間はかかったと思います。

これで全てのパーツが揃ったので動作テストをして組み立てます。

mfk60 トッププレート
mfk60 トッププレート
mfk60 ミドルプレート
mfk60 ミドルプレート
mfk60 ボトムプレート
mfk60 ボトムプレート
mfk60 回路基板
mfk60 回路基板

動作テスト

まず最低限、回路がショートしてないかなどをテスターを使って調べました。

そして、いきなり高価な MacBook に繋いで MacBook を USB ポートごとお釈迦にする勇気はなかったので、テスターでテストしたあと、念の為まずその辺にあった Raspberry Pi Zero に繋いで USB デバイスとして認識することを確認しました。

これで ATmega32U4 のブートローダーが認識されていて、ちゃんと動いているのがわかったので、ファームウェアを書き込みます。

ファームウェアの作成と書き込み

ファームウェアは QMK を使いました。基本的には QMK のガイドに従って JSON ファイルと Make ファイル、キーマップのソースファイルを作成します。そして VIA への対応なども行いました。

注意点としては左右分割キーボードの場合、キーのマトリクスで、右側が下にくるという点です。

QMK のファームウェアのビルドには以下の Dockerfile で、Docker の qmkfm/qmk_cli イメージを使いました。

x86_64 のイメージですが、macOS では Docker Desktop や colima などで Virtualization.framework の Rosetta が使えれば問題なく動作します。

FROM qmkfm/qmk_cli

VOLUME /qmk_firmware
WORKDIR /qmk_firmware

CMD qmk compile -kb all -km default
# 上の Dockerfile を qmk_firmware のディレクトリに作成

# Docker イメージ作成
docker build -t qmk_firmware .

# ファームウェア作成
docker run -it -v $(pwd):/qmk_firmware --rm qmk_firmware qmk compile -kb niw/mfk60 -km default

QMK を使って作ったファームウェアを QMK Toolbox を使って書き込んで[7]ショートさせないように気をつけながら基板をテストしていきます。まだスイッチは載っていないのでピンセットなどでパターンをショートさせてそれぞれのキーが押下されることを確認しました。

組み立て

道具と作業場の都合もあって遊舎工房の工作室を使いました。

表面実装部品はすでに実装済みなので、組み立ては簡単です。
左右のボードをすべてフレームから切り離し、マウスバイトのバリをやすりがけします。

mfk60 組み立て (1)

左右の回路基板にソケットをハンダ付けします。

mfk60 組み立て (2)

トッププレート、ミドルプレート、回路基板を重ねて、スイッチとスタビライザーをはめます。

mfk60 組み立て (3)

ボトムプレートをスペーサーがねじ止めしてサンドイッチにします。

mfk60 組み立て (4)

最後にキーキャップをはめて完成です。

完成

mfk60 完成

最後に

自作キーボードを自作してみてハードウェアの難しさがとてもよくわかりました。
この mfk60 はまだ rev. 1 ですでに問題や改善点がいくつも見つかっています。

  • スペースキーの大きさ — 2.25u のキーが4つあるのはレアだった
  • マウスバイトの位置 — フレームの弱い場所につけてしまい折れない箇所があった
  • ミドルプレートの厚み — 0.1mm 足らない
  • スペーサーの高さ — 0.05mm 足らない

他にも基板の色や表面デザインの改善、打ち心地の改善、他のスイッチの利用などまだまだ試したいことはいくつもあるので今後も制作を続けて行けたら良いなと思います。

この記事[8]が何かの参考になれば幸いです。

脚注
  1. 背の低いキー、キーキャップ、キーボードのことをそう呼びます ↩︎

  2. KiCad の読みが謎です。多分キーキャドなんですが、米語読みだとカイキャドになりそうです。どっちか判然としません。 ↩︎

  3. Footprint とは、KiCad 上で書く部品の大きさ、実装の穴やパッドの位置をモジュールにしたものです。*.kicad_mod ファイルで作られます。 ↩︎

  4. 1mil は 0.0254mm です ↩︎

  5. パッケージのひとつで、側面にパッドがあり、リードがないやつです。 ↩︎

  6. KiKit にはマルチボードを1つのプロジェクトで扱う方法があるので、実際には、たぶん、左右のボードを1つのデザインで使う使い方が間違っているのだと思います。 ↩︎

  7. 基板端にはブートローダーが飛んだ時のためにISP用のピンを出しています。通常ブートローダーが書き込まれているので、リセットボタンを押せば USB から直接書き込めます。 ↩︎

  8. この記事は mfk60 で書かれました。 ↩︎

Discussion