静電容量無接点方式分割キーボードを自作した

9月半ば頃に今は静電容量無接点方式(以降 静電容量式 と略す)のキーボードも自作できる時代なのだと知り、そこから自分でも作ってみようとちょこちょこ進めていましたが、ようやく完成させることが出来ました! ちなみにキーボード名は「小石」(英名: miniEC)です。

私の場合、自作キーボードはキットで組み立てたことはあるけど基板の設計からはやったことがないという状態からのスタートでしたが、先人たちの情報のおかげで思い立ってから2ヶ月ほどで完成させることが出来ました。

この記事ではこの2ヶ月どんなことをやって静電容量式キーボードを作れるまでに至ったのかを紹介します。

自作するまでにやったこと

ざっくりとやったことを時系列で並べると以下のような手順を踏みました。

キーボード関連の同人誌を読む

まずは「真の静電容量キーボードを作る本」を読みました。これを読めば静電容量式キーボードを作るときはどんな回路が必要で、どんな firmware を書く必要があるのかわかります。理論のようなハイレイヤーの話が主なので基板の設計をしたことないという場合でも安心して読めます。代わりに高校物理程度の知識はないとおそらく数式追うのが辛いと思うので適宜復習を推奨します。

次に「自作キーボード設計入門」「自作キーボード設計入門2」を読む & 実際に手を動かして KiCad の使い方と QMK Firmware の書き方を学びました。これらの本はメカニカルキーボードの話ですが、メカニカルは動作原理が単純で firmware も書きやすいのではじめの一歩としては丁度よかったです。ただし、これらの本は出版から歳月が経って本の中で使われているソフトウェアのバージョンも上がって本のままでは動かないのでそこは適宜修正する必要があります。幸いメカニカルは作っている人が多く情報も多いので特段困らないと思います。

最後に「静電容量式自作キーボード設計資料」ですが、こちらは他と比べると難しいと感じました。実際に静電容量式キーボードを作る段になってようやく内容が分かってきたという感じだったので初期段階から理解する必要はないと思いますが、とりあえず設計するときには注意を払わなければならない点があるのだなということを頭の片隅に置きましょう。

静電容量 Helix を作る

いくら作り方を学んだところで実物はそうそう思い通りに動いてくれるものではありません。特に静電容量式キーボードの場合、ノイズのせいで入力がうまくいかないという話を見かけますが、実際問題ノイズでどれだけ入力がブレるのかは実物を触らないことには想像できません。 ということで、勉強教材として静電容量 Helix を買って作りました。

goropikari.hatenablog.com

実際に作ってみて以下の気づきを得ました

  • コニックリングが検出用電極パッドからずれると顕著に入力精度が下がる
  • プレート固定用のネジの締め具合で入力精度が変わる
  • 検出用電極パッドは指で触っても反応する
  • 打鍵感向上させるためにはハウジングの固定が大事
  • 私がはんだ付けできる表面実装パーツの最小は 1N4148W のサイズが限界

この中で個人的に一番大事だと思っているのはコニックリングの位置でこれをいかに中心からずらさないかが入力精度に一番効いてくる感じがします。ネジの締め具合で精度が変わったのもおそらくコニックリングの位置がずれたからだと思います。

ちなみにこの頃に Froggy の存在を知り私の中のキーボード観が大きく変わりました。キーボードにトラックボールついたやついいなぁなどと思っていましたが、そもそも片手でキーボード打てば逆の手でマウス使えるじゃん、天才か!? と思いました。生まれてこの方キーボードは両手で打つものだと刷り込まれていましたが、別に両手で打たなければならないなんて決まってないんだ!片手打ちに限らずキーボードはもっと自由でいいんだ!と思い始めたのがこの頃です。よくよく考えてみると人によって手の大きさ、指の可動域は違うのだから個々人にあったキーボードをオーダーメイドするサービスがあってもおかしくないと思うのですが、今の所そのようなサービスは聞いたことがないので不思議なものです。また Froggy 考案者のたくま氏のブログのコメントをみて、世の中には片手しか使えない方もいるのだから片手キーボード分野はもっと発展してもおかしくないし、自作キーボードは配列からキーマップまでなんでもありの世界なので自作キーボード界隈はハンディキャップがある方々の 力になれる存在なのではないかなと思い始めました。

hum-id.jp

カニカルキーボードを基板から設計して作る

カッコつけて(?)初キーボード設計から静電容量式を作るというチャレンジをしようかと一瞬考えましたが、まずは情報も多く簡単そうなメカニカルキーボードを設計して基板発注までの流れを練習しました。

goropikari.hatenablog.com

決して自分にとってベストな配列ではありませんでしたが、不思議なもので自分が設計したということもあってとても可愛く見えました。

1, 2週間は作ったキーボードをメインに使っていましたが、そのあと keyball39 を作ってメインはそちらに移りました。keyball39 を使う前までは片手3x6+親指3キーがベストと思っていましたが、keyball39 のおかげで6列目はなくても特段困らないということに気付かされたので作成する静電容量式キーボードも5列で作ることに決めました。このあとキーマップについて更に考え、親指キーは2つあれば十分だと気づきましたが、回路のバランス的に3つあったほうがきれいになる(3x6のキーボードとみなすことができる)ので親指キーは3つのままでいくことにしました。

goropikari.hatenablog.com

ブレッドボードで実験

Designing a custom Topre board - deskthority にブレッドボードで実験している写真があってこれはいいなと思ったので真似することにしました。 静電容量スイッチスキャンモジュールの使い方もよくわかっていなかったのでこの段階で実際に動かしつつ確認しました。

Designing a custom Topre board - deskthority より

参考元のように1スイッチ分の検出用電極だけ入った基板を作ろうかと思いましたが、どうせならキーマトリックスで実験できるようにしようと思ったので 2x2 で作りました。

静電容量スイッチスキャン用モジュールの参考コードは今の QMK Firmware だと動かないところがありましたが、出てくるエラーを地道に修正したら無事に動きました。

github.com

静電容量式キーボードを設計する

あとはそれまでの知識を総動員してひたすら基板を作っていきました。

配線

配線の仕方一つでノイズがでる怖い世界らしいので、既存の静電容量式キーボードの配線の仕方をよく参照しました。静電容量 Helix の基板データ、「静電容量式自作キーボード設計資料」についてくる CorneEC の基板データ、あとは Cipulot さんという方が静電容量式のキーボードをよく設計されていてデータを GitHub で公開されているのでそれらを参考にしていました。静電容量式キーボードの場合 freerouting 等使わずみんな人力で配線していると思いますが、実際のところ自動で引いた配線でどれだけノイズが出るのかは怖いものみたさで試してみたい気はします。

スイッチ

静電容量式スイッチとしては Niz or BTO のどちらかを選ぶ1ことになりますがハウジングのサイズがそれぞれ異なります。それぞれ用のトッププレートを作ってみましたが結果的に言うと BTO 用のもので Niz のスイッチもブレずに固定できました。

自作スキャンモジュール

この頃、静電容量スイッチスキャン用モジュールが品切れでもう再販されないかなぁと思っていたので互換回路を作ったりもしました。このあとすぐに在庫が復活しましたが、PCBA のやり方を覚えることが出来、回路的にも一応動くものが作れたので自分の技術の幅は広がりました。

完成

そんなこんなで晴れて静電容量式キーボードが出来上がりました!(右手用基板の TRRS ジャックの向きは間違えた)。 色が白いのは HHKB 雪モデルに影響された結果です。promicro の存在が浮いていますが promicro カバーを白色で作れば良いかなぁと思っています。

今後

とりあえず TRRS ジャックの向き間違えた右手用基板は修正しようと思います。 需要があるなら今回作ったキーボードのキット化して販売することも考えるかも? 36キー/格子配列/静電容量式の組み合わせはニッチ過ぎるのでおそらく売れないと思いますが。

静電容量式キーボードを作るという目標は達成して静電容量式キーボード作りたい欲は落ちついたので、次作るキーボードは気をはらずに作れるメカニカルで作ると思います。今作りたいものとしてはマイコンを基板の裏に隠してついでに親指キーを片手2キーにして全体34キーのキーボードを作ろうと思っています。ちっちゃくて可愛いキーボードになる予感。

keyball39 を静電容量式化することも考えていましたが、L字コンスルーが手に入らないので今の所保留です。コンスルーを手に入れるか、ヨーキースさんがトラックボール読み取り基板を再販されたらまた考えます。


  1. REALFORCE 分解してパーツ取りという選択肢もあることにはある

keyball39 を組み立てた

同僚が使っていた keyball44 を触らせてもらって「キーボードにトラックボールがついているのは最高だな!」となったので私も keyball を買ってみました。ここ最近買っているキーボードはこれから長く常用するためのものというよりも自分でキーボードを設計する際の参考資料という面が強いので今まで体験したことがない片手5列の keyball39 を選択してみました。

購入当初は片手5列に慣れることは難しいだろうと思っていたので本当に資料になるだけと思っていましたが、3日もしたら大体の操作に慣れて、その頃にはすっかりこのキーボードの虜になってしまいました。

私は格子配列が好きでカラムスタッカードは趣味ではないと思っていましたが、5列だとそんなに違和感がありませんでした。6列カラムスタッカードだと両端の列を小指で打つのは辛いと感じますが5列だとそれほど苦でもありませんでした。ただ、親指キーの孤がゆるいので個人的には一番内側(pro micro 側)のキーはより手前にほしいと感じます。

スイッチは軽めのタクタイルである Kailh Super Speed Switch Copper と親指キーは Kailhロープロファイルスイッチ茶にしました。親指キーの方は早々にバネを 25 g のものに交換しました。 最初は親指キーのバネを変えずにそのまま打っていましたが、あまりの重さに親指が痛くなってきたのでバネの交換をしました。バネを変えたらどういうわけか親指キー以外の本体のキーの打鍵も軽く感じるようになって、全体的なバランスは重要なのだなぁとしみじみ思いました。

スイッチはプラスチックのこすれる音なのか耳心地の良くない音がしていましたが、ルブを塗ったら落ち着いたカタカタとコトコトの間くらいの打鍵音になりました。

Kailhロープロファイルスイッチshop.yushakobo.jp

スイッチオープナーは Kailh 用のものを持っていなかったので新たに購入しました。Choc の方はこれでは開けられないのでピンセットで爪を持ち上げて開きました。

トラックボールは動作確認をされている PERIPRO-303 を無難に選びました。

pro micro は今まで micro USB のものを使っていましたが、今の時分で micro 見ることも少なくなってきたので type c にしました。

talpkeyboard.net

組み立てについて

はんだ付けはトラックボール用のパーツ分があるので他の一般的な自作キーボードに比べると多少増えますがさして労力は変わりませんでした。

特に深い意味はありませんが、基板が白いことが分かっていたのでソケットを白のものにしてみました。Kailh choc のソケットも白にできたら良かったのですがなさそうだったので致し方なし。ついでにリセットスイッチもボタンが白のものに変えました。

はんだ付けはすぐに終わったのですが、キースイッチをトップ PCB にハメるのにとても時間がかかりました。Gateron のスイッチだと多少力が必要なもののハマるという感じでしたが、Kailh のスイッチはハウジングのサイズが大きいのかどんなに力を入れてもハメることができませんでした。そのため穴を大きくするためにひたすらヤスリで削りました。あんまり削りすぎると今度はゆるゆるになってしまう可能性があるため少し削ってはスイッチをはめてみてを繰り返していたので制作時間にはトータル5.5時間くらい掛かってしまいました。

最近自分で設計したキーボードでもトッププレートを PCB で作りましたが、同様に Kailh のスイッチはハマりづらいという感覚があったので、トッププレートを PCB で作る場合は穴のサイズを小さくし過ぎずに作ると良さそうだなと思いました。

キーマップについて

今まで片手 3x6 + 親指3キーという構成の分割キーボードを愛用してきましたが、今回初めて5列に挑戦してみたのでキーマップを大幅に変更する必要がありました。またトラックボール付きということでクリックなどの操作もキーに割り当てることになり初めての事だらけでキーマップの決定にはなかなか時間がかかりました。

最終的なキーマップはこちら

github.com

キーマップだけの変更だと限界を感じたのでカスタムキーコードをいくつか追加しました。 ちなみに、カスタムキーコードを設定する場合は enum 値の初期値として SAFE_RANGE でなく KEYBALL_SAFE_RANGE を使う必要があります。SAFE_RANGE から数個はすでに使われているので SAFE_RANGE を使ってしまうとそれらと衝突します。

github.com

レイヤー構成としては Default, Lower, Raise, Adjust, Mouse, trackball 感度設定用の6レイヤー構成で落ち着きました。

設定後は新しいキーマップに慣れるために Speed Coder というサイトでタイピング練習しました。

www.speedcoder.net

modifier key の配置

キーマップを考えるにあたって既存の30%キーボードのキーマップを参考にしました。 それらの中にはアルファベットを mod tap にしているものもありましたが、私の設定した限りでは思った通りに動いてくれなかったため(ワンテンポ入力が遅れてしまう)ので、アルファベットと modifier key を同一のキーに割り当てることは諦めました。

mod tap は親指キーのみにし、使用頻度の高い modifier キーとワンタップで使うキーを mod tap に設定しました。 最終的に親指キーは以下の構成で落ち着きました。

modifier or layer tap
GUI Escape
Lower minus
Control Tab
Raise Enter
Shift Space

Enter はデフォルトレイヤーと、Lower 押しながら M の位置の2箇所に設定しました。普通に文章を書くときは Lower - M に割り当てた Enter を使い、他のキーと同時押しの関係でその Enter が打ちづらいときは親指キーに割り当てた Enter を使っています。

マウスレイヤー

指で打つには厳しそうであったトラックボール横の右下のキーはマウス操作のみを行えるレイヤー(以降マウスレイヤーの呼ぶ)への切り替え用のキーとしました。打つときは指ではなく小指の付け根あたりで打つ(チョップする形に近い)ようにすると無理なく打てました。 マウスレイヤーは基本的には右下の切り替えキーを押している間は有効にし離すとデフォルトレイヤーに戻るようにしました。ですがこれだと単にネットサーフィンするときにずっとキーを押していないといけなくなってしまって大変なので、マウスレイヤー内の特定のキーを打つとデフォルトレイヤーがマウスレイヤーに代わり切り替えキーを押していなくてもマウスレイヤーを維持できるようにしました。

キーマップ模索初期段階では切り替えキーを押したら完全にマウスレイヤーに固定されるようにしてみましたが、いざこの設定でプログラミングをしてみるとマウスレイヤーとデフォルトレイヤーの切り替えで頭が混乱したのでやめました。

マウス用のキーコードについては qmk firmware の Doc をみても何がどれに対応しているのかよくわかりませんでしたが、実際に使ってみてわかった範囲で Linux では KC_BTN1 ~ KC_BTN5 は次のような動きになるようです。

key code 対応する操作
KC_BTN1 左クリック
KC_BTN2 右クリック
KC_BTN3 中クリック
KC_BTN4 戻る
KC_BTN5 進む

qmk firmware のキーコードとしてはマウス用のものとして KC_BTN8 まであるようですが、打ってみても何の反応もなくどういう条件でどういう操作になるのか分からなかったのでとりあえず放置しました。

OLED の表示を変更

OLED の表示項目は軽くいじり現在のレイヤー情報を表示できるようにしました。 もともと固定のマウスレイヤーになっているかどうかをわかりやすくするためにレイヤー情報を出すようにしましたが、数ピクセルの文字だとパッと見ではよくわからなかったのでマウスレイヤーのときだけ独自のロゴを表示するようにしました。

ディスプレイいっぱいに Mouse🐁 と表示されるようになったので視認性は格段に上がりました。

OLED へのオリジナルロゴの表示方法ですが、gimp で 128x32 pixel の画像を作成し、QMK logo editor に upload し、Raw のコードを oled_task_user に入れたら簡単にできました。

joric.github.io

テント

分割キーボード界隈ではキーボードの中央をせりあげるテントなるセッティングがあることを知ってはいましたが、それに対応するための専用のプレートだったり、ケースを用意しなければならず導入コストが高く避けていました。しかし、keyball39 は小さいのでスマホタブレットのスタンドでテントできるのでは?と思って試してみました。

懐へのダメージを最小限にするため材料は100均で買ってきました。 タブレットスタンドx2 と滑り止めという超簡易構成です。 タブレットスタンドの面積が小さいので面に乗り切っていない親指キーを打つとキーボードがガタつきますが、雰囲気は一応味わえました。

最初は打てなくはないが平面においたときよりも打ちやすいかと言われると微妙という感想でしたが、親指側を手前に持ってくると打ちやすくなりました。 一方でトラックボールが常に手で触れてしまうようになりました。触れること自体はそんなに苦でありませんが、打っている間にマウスカーソルが動くのが地味に嫌なので、マウスレイヤー以外のときはトラックボールを無効にするように firmware を書き換えました(コード理解しきれずに突貫でやったので微妙に不具合もありますが)。

キーボードが認識されないことへの対処

USB 接続しても入力が全くできないという現象が度々起こりました。入力できないときは決まって両方の OLED に keyball のロゴが表示されました。一方、普通に入力できるときは USB がつながっている方に keyinfo が、もう片方にロゴが表示されました。何度か USB の抜き差しをすると普通に入力できるようになるのですが、macbook 相手だと5分くらい繰り返し抜き差ししても入力できるようにならないという事態に陥りました。

先に結論を言うと config.hSPLIT_USB_TIMEOUT の値を 500 から 2500 まで増やすと動作が安定するようになりました。 Linux マシンだと 1000 まで上げると安定しましたが、macbook だと 2500 まであげないと安定しませんでした。 twitter で検索したら似たような現象に陥っている方(keyball user かは不明)がおり、その方も SPLIT_USB_TIMEOUT の値を増やされたようでした。

原因探索

対処法に至るまでどんなことを試したのかを軽く残しておきます。

keyball39 の左右判定方法

まず、keyball39 の左右判定方法を調べました。私が今まで知っていた左右判定方法は SPLIT_HAND_PIN を使う方法と EEPROM に書き込む方法の2種類でしたが、SPLIT_HAND_PINgrep かけても何も引っかかりませんし、avrdude-split-left などで flash をした記憶もありません。ではどうやっているのだろうと思ったら SPLIT_HAND_MATRIX_GRID というのでコントロールしているようです。 今になって QMK firmware の Doc を見返してみると確かに書いてあるのですが、以前はどういうことなのかよくわからなかったので完全に読み飛ばしていました。

github.com

keyball39 の回路図を見ると row2, col5 のところのダイオードをジャンパーでつなげるという、パット見何をしたいのかよくわからない部分がありますが、ここをジャンパーしたほうは row2, col5 を読むときに常に High、ジャンパーしていない方は Low になっているのでこれで左右を判定しているようです。作るときに LEFT と書いてあるところをジャンパしましたがそれがここに当たります。

検証1: はんだ付けをやり直してみる

動作が不安定になっている原因はこのダイオードのハンダ付けがうまくできていないせいかなと推測し、このダイオードのハンダの付け直しをまずは試してみました。問題はこのダイオードがどこに該当するのかということですが、幸い keyball シリーズは gerber ファイルを公開していただけているのでそれを見て探しました。見た感じでは LEFT と書かれているところの真下にあるダイオードがお目当てのもののようでした。

はんだをやり直してみましたが結果は変わらず不安定なままでした。また、よくよく考えると SPLIT_HAND_MATRIX_GRID は key matrix のなかのものだったらどれでもよく、スイッチを押しっぱなしにしていればジャンパーするのと同じことだと気がついたので他のスイッチに設定して試してみましたがそれでも不安定なままでした。これでどうやらはんだ付けのせいではなさそうだとなりました。

検証2: MASTER_LEFT で固定してしまう

USB をつなぐのは左の方だけと割り切って MASTER_LEFT を設定したら安定するのか試してみました。 コードの変更箇所としては config.h を以下のように変更しました。

# define MASTER_LEFT
// #define SPLIT_HAND_MATRIX_GRID  F6, B5
// #define SPLIT_USB_DETECT
// #define SPLIT_USB_TIMEOUT       500

github.com

これで設定した場合は成功率が100%になりました。人によってはこれで不便を感じる方もいらっしゃるのかもしれませんが、私が持っている分割キーボードの大半はこの設定で動いているので私としてはこれでも特段不便はありませんでした。

とりあえず確実に動く逃げ道は1つできました。

検証3: SPLIT_USB_TIMEOUT の値を大きくする

SPLIT_HAND_MATRIX_GRID で調べていたところ、keyball シリーズのファームウェアを書かれている kaoriya san が SPLIT_USB_TIMEOUT について言及しているつぶやきを発見し、この辺が怪しいのか?となったので試しに SPLIT_USB_TIMEOUT の値を 500 から 1000 まで増やしてみました。すると今まで2回に1回位のペースで失敗していたのがほぼ100%成功するようになりました。一方で macbook への接続となるとまだ不安定でした。2000 まで増やしても不安定で 2500 まで増やすとようやく macbook でも安定するようになりました。

私同様に keyball が認識されないという問題に直面している人を見かけないので、私の環境がおかしいのかもしれませんが、もしなかなか認識されないとなったら上記の方法で解決するやもしれません。

キーボードを基板から設計して作ってみた

静電容量式のキーボードをゆくゆくは自分で設計して作ってみたいなと思ったものの、初っ端静電容量式はハードルが高そう。ということでまずは PCB 注文の練習がてら情報の多いメカニカルキーボードの基板を作ってみました。

基板の色は5色くらいから選べたので、あまり見たことがない赤色の基板にしてみました。

この記事では私の場合の設計から組み立てまでの流れをまとめています。

配列の決定

3x6 格子配列 + 親指3キー(弧を描いて並ぶ)が一番打ちやすそうだと大体の配列の想像はついていましたが、何故それが良いと感じるのかの自己分析をまずはしました。 当時持っていた自作キーボードである corne chocolate, Manta40, Helix をそれぞれ叩き、普段自分がどのように打っているのかを調べてみました。 結果、どうやら私は小指を曲げて打つのが苦手なのだと気づきました。カラムスタッカードなキーボードの多くは小指でキーが打ちやすいように外側の列が下に下がっていることが多いですが、下げると一番上段のキーは確かに打ちやすくなる一方で下段のキーは小指を曲げねばならず逆に打ちづらさを感じました。格子配列にした場合、真ん中と下の段のキーは小指を伸ばしたまま指を開くか手首を軽く外側に曲げると打てるので小指の曲げ伸ばしがほぼなくストレスなく打てました。上段のキーは小指では打ちづらいですが、そもそも私は一番外側の上段のキーを薬指で打っているということに気づきました。 また親指で打つキーは、親指を開いたときに描く円弧上に配置するのが打ちやすいとわかりました。完全に行の高さが揃っている helix に比べて corne や manta40 のように弧を描いた配置のほうが自然に打つことができました。

これらの結果と設計のしやすさから corne を格子配列にしたようなキーボードを設計しました(親指キーの角度は corne と全く一緒)。

基板設計

foostan san の同人誌2冊と KiCad tutorial でまずはキーボード設計の基礎を学びました。

pskbd.booth.pm

pskbd.booth.pm

同人誌は発行されてからだいぶ経っていることもあって kicad の使い方がすでに変わっていたり qmk firmware の書き方も変わっていたりして本の通りにやれば設計できるという状態でもありませんでしたが、自分で修正して動かせるようにしたりしたおかげで色々と感覚はつかめました。

同人誌ではトッププレートとボトムプレートはアクリルで作るようになっていましたが、Helix をアクリルプレートで組んだときにネジ止めでちょっと力を入れたらプレートが簡単に割れてしまって以来、アクリルは脆いというイメージがついてしまったので今回は PCB と同じ FR4 で作りました。

ただ、トッププレートを FR4 で作る場合の例を見つけることができなくて最初は苦労しました。おそらく PCB と同じように作ればよいからわざわざ言う必要もないということなのでしょうが、私の場合は kicad にも慣れていなかったので、どうやってキースイッチ用の穴は表現できるのかわからず途方にくれていました。foostan san のライブラリを眺めていたら SW_HOLE というそれっぽいフットプリントがあって、3D preview したら望んだ通りに穴が空いていて事なきを得ました。

費用を浮かせるために PCB はリバーシブルで作成しました。上記の同人誌で作る 2x2 キーマトリックスの petit split ですらリバーシブルの配線は大変と感じていたので片手 21 キーの配線は無理だと思っていましたが途中で freerouting という自動的に配線してくれるソフトを知って楽ができました。

この頃はまだ自力で firmware をどうやって作るのかちゃんと理解してなかったので pro micro のピンの使い方やキーマトリックスは完全に corne と同じにしました。

基板発注

正直どこに基板発注するのが良いのかわかっていませんでしたが、送料が安いものを選べる JLCPCB に発注しました。 gerber ファイルをアップロードして簡易 preview でみるとどうにもトッププレートのキースイッチ用の穴が空いていないように見えましたが、kicad の 3D preview では大丈夫だったのだからいけるだろうと考えそのままスルーしました。

注文してからアップロードする gerber ファイルを間違えていることに気づいたり、トッププレートの加工には追加費用が掛かるよという連絡が届いたりしてちょこちょこサポートと連絡しましたが簡単な英語の返答でどうにかなりました。ちなみにトッププレートは7ドル(1000円くらい)を追加で請求されました。

配送は OCS Express に選択し注文してから大体1週間くらいで届きました。

組み立て

今回作ったものは LED を使わない極めてシンプルな構造にしたので特に躓くこともなくあっさりと完成しました。 注文した基板の数からは2つ分キーボードが作れたので、基板余らせてもしょうがないので2つ作りました。また片方は人力で pro micro のピンをジャンパして USB ケーブルを左右どちらの指しても正しく動くようにしました。 (基板を設計しているときは SPLIT_HAND_PIN を知らなかったのでジャンパがやりやすいようにしていなかった。)

github.com

おわりに

基板の設計・発注の仕方を覚えて自作キーボードの幅が広がったのでこれからも自分の理想を体現するキーボードを模索していきたいと思います。

静電容量 Helix を組み立てた

Manta40 を作って以来なので、3年ぶりに自作キーボードを作りました。

goropikari.hatenablog.com

今回作ったのはスイッチがメカニカルでなく、HHKB Professional や REALFORCE と同じ静電容量無接点方式のキーボードです。昔から静電容量無接点方式の分割キーボードが欲しいなと思っていましたがまさか自作キーボードで作れるとは思っていませんでした。 キット化されているものはいくつかあるようですが、Manta40 を3年使ってすっかり格子配列に慣れてしまったので今回は同じ格子配列である「静電容量 Helix」を選びました。

booth.pm

キットが届くまでの予習

静電容量無接点方式の動作原理が全く想像できなかったので 静電容量 Helix を作られた ginjake さんの 真の静電容量キーボードを作る本 - ginjake - BOOTH を読んで予習していました。また、嬉しいことに 静電容量 Helix は PCB データが公開されているのでそれを眺めて脳内シミュレーションをしていました。 ただ、kicad の使い方をよくわかっていなかったので 自作キーボード設計入門 を読みつつ勉強しました。

はんだ付けするチップの向きに悩んだり、導電性チェックするときにどことどこが繋がっているのかわからなかったときに PCB のデータを見ながら確かめていたので kicad の使い方は覚えていて損はないと思います。

材料

キット以外に必要なもの

私はキーボードは光らせない派なので LED 関連のパーツは付けていません。

商品 数量 URL コメント
ProMicro 2 https://shop.yushakobo.jp/products/pro-micro?variant=42225070801127
コンスル 4 https://talpkeyboard.net/items/6229e8c130344b271f290c3c コンスルーがなかった場合は12ピンソケットでも可
NEW NIZ EC SWITCH 64スイッチ分 https://shop.yushakobo.jp/products/5224 遊舎工房で売られているものは30個入りセットなので64キーである Helix には3セット必要です
コニカルリング 64スイッチ分 https://shop.yushakobo.jp/products/4679 遊舎工房で売られているものは30個入りセットなので64キーである Helix には3セット必要です
キーキャップ 64個 NiZ の軸は Cherry MX互換キーキャップ対応です。私は各キーキャップの高さが全て同じならば何でもよかったので DSA プロファイルのものを買いました。
ラバードーム 64スイッチ分 https://shop.yushakobo.jp/products/a0500er-01-1 値段は高いですが DES-DOMES BKE Tactile を使うと東プレの打鍵感に近づくようです
3.5mm オーディオケーブル 1 https://shop.yushakobo.jp/products/trrs_cable
銅線 少し https://akizukidenshi.com/catalog/g/gP-09583/ 抵抗の足を切ったものをジャンパのために使おうかと思っていましたが、穴の直径が小さすぎて入らなかったので 0.29 mm 銅線買いました
絶縁テープ まつうら工業 A種絶縁用、結束用 日東アセテート布絶縁テープ#5 幅19mm 長さ10m 黒

その他あると便利なもの

下で紹介している用具類はなくても作れますがあるととても便利です。

商品 数量 URL コメント
表面実装はんだ付け用ツール SMDクランプ 1 表面実装はんだ付け用ツール SMDクランプ(150mmアーム) (青ラベル) はんだ付けするチップがとても小さいので「仮どめ」に自信がない人は買うと良いと思います。正直ただおさえるための器具に4400円もするのかと最初は思っていましたが買ってよかったとつくづく思いました。
ハンディ顕微鏡 1 レイメイ藤井 顕微鏡 ハンディ ZOOM グリーン RXT203M IC の足と足とあいだの間隔が狭すぎてショートしているのか否かが肉眼では判別できなかったため買いました
フラックス 1 ホーザン(HOZAN) フラックス 鉛フリーハンダ対応 便利なハケ付きキャップ付 容量30mL H-722 チップがとても小さいのでフラックス使わずにはんだ付けするのはとても難易度が高いです
無水エタノール 1 無水エタノール 100ml(掃除) フラックスの洗浄用に使用
キムワイプ 1 キムワイプ 12×21.5cm /1箱(200枚入) S-200 フラックスの洗浄時に使用
黄銅スペーサー(丸)M2, 7 mm 4 https://shop.yushakobo.jp/products/a0800c2?variant=37665435222177 キットには ProMicro のところのアクリルカバー用のスペーサーが入っていないので、カバーをつける場合は必要です
M2 ねじ 4 SRECNO PC ネジセット M2 M2.5 M3 HDD M.2 SSD 固定用平ネジセット ラップトップ スクリューセット 交換用ノートパソコンねじ 収納ケース付き 355本入り アクリルカバー用の M2 用の 4 mm を使いました
Helix ステンレスプレート 2 https://shop.yushakobo.jp/products/helix-stainless-plate アクリルプレートに比べて打鍵感が向上します。5行版は片手単位での販売なので2枚必要です。

製作

ビルドガイドには書かれていない補足情報を残しておきます。

基板の左右

基板はリバーシブルなのでどの基板を右手用・左手用に使うかをまず決めます。目印がないとどっちがどっちだったかわからなくて混乱するので表裏の目印を付けておくと良いと思います。

はんだ付け

ビルドガイド通り銅線でジャンパします。 銅線は左手用の表から通します。

ジャンパすると Pro Micro 用の穴の下図の赤線部分が繋がります。ちゃんと繋がっているかテスターでチェックをすると良いと思います。ちなみに本家の Helix の基板には下図のように Pro Micro を指す位置をシルクで書かれているようですが、静電容量 Helix にはそのようなシルクはありません。右の列と左の列どちらに指すのか正しいのか迷いますが、左右の基板どちらも下図のように右の列に合わせるのが正しいです。コンスルー使っていれば間違えても修正できますが、12ピンソケットを使用する場合は位置に注意してください。

ちなみに、PCB を使っているのだから人力でジャンパなどせずに、基板側で配線すればよいのでは?思って kicad を確認しましたが、Pro Micro の位置に各種パーツを配置しているので PCB 側でやるのは無理だったのだろうなと思いました。

あとはひたすらパーツをはんだ付けしていきます。はんだ付けするのは基本的に基板裏面です。あると便利なものとして上記で紹介したクランプがあると仮どめでパーツがずれる心配をしなくてよいので便利です。

はんだ付けしたら都度顕微鏡を覗いてショートしていないが確認していました。

足の先端がショートしているように見えたが、焦げたフラックスがこびりついているだけだった。

基板の洗浄方法はこちらの動画を参考にしました。 youtu.be

スイッチをはめる

トッププレートにワッシャーとM2スペーサーをM2ネジ(4 mm) で止めてスイッチをはめていきます。下の写真だと全部で6つの M2 スペーサーを付けていますが、ボトムプレートとトッププレートを止めるネジがキットには全部で8個しか同封されていないので四隅にだけ使うのが正解なようです。

打鍵感を比較するために右をステンレスプレート、左をアクリルプレートで一度組んでみました。

キットの説明文に

NiZのスイッチも使えますが、サイズが少し小さい為若干緩めになります。

とあってどういうことかと思いましたが、アクリルプレートを使った場合だとハウジングが固定されません。トッププレートにハウジングはめてもひっくり返すと全部落ちます。一方でステンレスプレートの場合だと内側の幅がきつめに作られているのかプレートをひっくり返してもハウジングは落ちない程度にはかっちりはまります。というかそれなりの力を込めないとそもそもトッププレートにハウジングがはめられませんでした。またアクリルプレートだと材質的に柔らかいせいかはたまた薄いせいか打っているときに若干プレートがたわむ感覚がありました。そのためステンレスプレートのほうが打っているときに安心感があります。 懐事情が許すならばステンレスプレートを買うのはありだと思います。

NiZ のキーボードについていたスイッチのハウジングと遊舎工房から買った NiZ のハウジングの違い

私はもともと持っていた NiZ キーボードからスイッチは工面できたので新たにスイッチを買う必要はなかったのですが、打鍵感に違いがあるのか知りたかったので30個入りを1セットだけ購入しました。

透明なほうが遊舎工房から買ったもの

NiZ のキーボードの方のハウジングはPCB とハウジングをねじで止めるためのネジ穴がありますが、遊舎工房から買ったものにはありませんでした。またトッププレートにハマる部分の大きさが遊舎工房から買ったもののほうが気持ち小さかったです。NiZ のキーボードから取ってきたハウジングはステンレスプレートにはめるのにかなりの力が必要だったり、側面を削らないと入りませんでした。一方で遊舎工房から買ったほうは力を入れればとりあえずハマりました。 当初は全て NiZ のキーボードからの移植で考えていましたが、あまりにはめるのが大変だったので左手用には遊舎工房で買ったハウジングをはめました。

firmware を焼く

ビルドガイドには

ステンレスプレートを使う場合は config.h の #define STAINLESS_PLATE のコメントアウトを外してください

とありましたが、#define STAINLESS_PLATE という記述は静電容量 Helix 用のファイルには見当たらなかったので β版のときの名残だと思います。

github.com

私の場合は、LED 使っていないのでその設定を切るのと、Dvorak 配列ユーザーなので keymap を Dvorak に変更しました。

github.com

avr-gcc 12 だと bug があるらしくうまく compile できませんでしたが、AVR_CFLAGS="-Wno-array-bounds" をつけると通せるというのを qmk firmware の issue から見つけて事なきを得ました。

make ec_helix:dvorak:avrdude AVR_CFLAGS="-Wno-array-bounds"

github.com

qmk firmware は進化が早いのか設定を数年放っておくとコンパイルがそもそもできなくなったりする(実際 corne と manta40 の設定がコンパイルできなくなった)ので自力で firmware を書ける自信がない場合はキット購入前に自分の環境でコンパイルできるかちゃんと確かめたほうがよいと思います。

完成

作り始めてからおよそ1週間で完成しました。予備として基板が余分についてくるというそれだけで組み立て難易度の高さが伺えますが、一つも予備パーツを使うことなく無事に作ることができました。

0.5 mm シャーペンの先との比較

たまに反応の悪いキーがあるのでまだまだ調整が必要そうですが、最低限使える反応速度にはなりました。ボトムプレートのネジの締付け具合でキーの反応具合が変わったりするので静電容量無接点はなかなかシビアだなぁと思いました。

個人的にキーボードは片手3x6 + 親指 3 keys がベストだと思っているので、今後は理想の分割静電容量無接点キーボードの設計もできたらなぁと思います。

ハウジングの色が揃っていないので気持ち悪いものの、見えるところではないので気にしない

DMOJ を使ってオンラインジャッジシステムを構築する

DMOJ という OSS のオンラインジャッジシステムの環境を整えたので使い方をメモしておく。

環境はコンテナ化し、image も Docker Hub に上げたので MySQL や Redis のイメージが消されない限りは動くと思う。(動作確認は Linux 環境でのみ行っている)

github.com

元々のコードだとメールアドレスの認証が必須になっていたが、もっと雑にユーザー登録をできるようにしたかったのでメールアドレスの認証は飛ばすように変更している。(AWS SES などとつなげるのが面倒だった)

オリジナルとの変更点はこの commit
my custom · goropikari/online-judge@02a4a4a · GitHub

基本構成

GitHub で DMOJ Organization を見ると DMOJ/online-judge というのがあるがこれだけではオンラインジャッジシステムとして使うことはできない。これはあくまでフロントエンドであって実際に提出されたプログラムの正誤判定をするジャッジサーバーは DMOJ/judge-server である。よってこれら2つをつなげることでオンラインジャッジシステムとして使うことができる。 ジャッジサーバーは複数登録することができるが、提出されるプログラム数に応じてオートスケーリングするとかはなくて手動で登録するようである。 問題文や提出されたプログラムは MySQL に保存されるが、ジャッジ時に使用するテストケースはジャッジサーバーに配置するようになっている。それ以外のデータはジャッジサーバーに置くことはないせいかジャッジサーバーは MySQL と通信しない。

使い方

環境立ち上げ

とりあえず docker compose でもろもろを立ち上げる。ここで DMOJ/online-judge が動いているコンテナを web コンテナ、DMOJ/judge-server が動いているコンテナを judger コンテナと以降呼ぶこととする。

git clone https://github.com/goropikari/dmoj_docker.git
cd dmoj_docker
make run

立ち上がったら http://127.0.0.1:8080/admin にアクセスする。 user name, password はともに admin。 問題の追加やコンテストの設定はこの admin 画面から行う。

admin画面

問題を追加する

問題文を追加

Problems -> Add で問題追加画面に行く

問題追加

add problem

必須項目は以下のもの

  • Problem code:
    • ^[a-z0-9]+$ を満たす任意の文字列
  • Problem name
    • 任意の文字列。日本語でも可。
  • Problem body:
    • 問題文。MathJax も使える。inline math は ~ で囲み、display math は $$ で囲む。
  • Problem types
    • 適当にタグを作って入れる
  • Problem group
    • 適当にタグを作って入れる
  • Points
    • 点数
  • Time limit
    • 実行時間制限
  • Memory limit
    • メモリ使用量制限
  • Language
    • サポートする言語。ここでチェックを入れた言語でもジャッジサーバー側が対応していない言語では提出できない。

任意項目

  • Publicly visible
    • 追加した問題が公開されるか否かをコントロールする。コンテストの中だけで表示させたい場合はチェックを外しておく。チェックを入れるとコンテスト前から公開された状態になる。
  • Language-specific resource limits
    • 言語ごとに制約を変えることができる

テストケースを追加

入力例と期待する出力を書いたテキストファイルを zip 圧縮したものと、得点や正誤判定方法を記した init.yml を作り judger コンテナの中に配置する。 ファイル構成としては以下のよう

helloworld/  # ディレクトリ名は problem code と名前を合わせる。ここがずれると正誤判定ができない。
├── helloworld.zip
├── init.yml
└── testcases
    ├── 1.in
    └── 1.out

ここで helloworld.zip は testcases 配下を圧縮したもの。

zip -j helloworld.zip testcases/*

zip を作った後は testcases は必要ないので消してしまっても良い。ただ、あとからテストケースに変更したりすることを考えるとそのまま残しておいたほうが良いとは思う。

init.yml

archive: helloworld.zip
test_cases:
- {in: 1.in, out: 1.out, points: 100}

これを judger コンテナの /home/judge/problems に配置する。

docker compose cp helloworld judger:/home/judge/problems

または

cp -r helloworld problems # problems を bind mount しているので docker cp でコピーしなくてもよい

これでジャッジできる準備が整った。 問題ページ (http://127.0.0.1:8080/problem/helloworld) に行き、Judge のところに ExampleJudge が表示されていれば設定は正しく行われている。(設定は正しいはずなのに Judge server が出てこないことがある。そのときは init.yml に改行を入れるなりすると認識されたりする)

得点は init.yml に書いたものでなく、問題を追加するときに設定した得点が表示される。init.yml に書いた得点は問題を解いたときに得られる得点ではなく、得点の重み付けと考えたほうがよいらしい。

例えば、問題の得点が 100 点で、init.yml が以下のようだったとする。

archive: helloworld.zip
test_cases:
- {in: 1.in, out: 1.out, points: 100}
- {in: 2.in, out: 2.out, points: 100}

このとき、1ケース目だけ正答すると 50 点獲得できるといった具合である。

判定方法を指定しなかった場合は、出力が期待するものと一致するかで正誤判定される。ただし末端改行の有無は正誤判定に影響しない。

その他の判定方法や部分点の設定方法などは公式サンプルがあるのでそちらを参考のこと。

docs/problem_examples at fcf7921050fa5d2fdca4a4c3440a7824f0ad38a1 · DMOJ/docs · GitHub

Submit solution から適当な言語を選んでプログラムを提出するとジャッジサーバーで判定される。

余談

利便性はあまり高くないと思うので詳しくは紹介しないが、問題ページにある Edit test data をクリックして遷移するページでもテストケースを追加できる。 上記同様に zip を作りアップロード -> Submit とすると Input file, Output file を選べるようになる。単に zip をアップロードしただけでは選択することはできない。

コンテスト作成

Admin 画面 -> Contests -> Add から情報を入力してコンテストを作成する。

Publicly visible にチェックをいれないと指定した人にしかコンテストが見れなくなってしまうのでそこだけ注意すればあとは必須項目を入れていくだけなので特段迷うところはないと思われる。

PROBLEMS の項目で OUTPUT PREFIX LENGTH OVERRIDE という謎の項目があるが、これは WA だったときに実際に出力されたものの頭 n 文字を表示するという項目である。入力をそのまま出力されるとテストケースがバレるので基本的には 0 のままにしておくのがよい。

保存した後にコンテストページにいくと、コンテストが生えていることが確認できる。

期限を過ぎた後は Virtual Contest として参加できるようにもなっている。

対応言語を追加する(失敗)

  • judge.yml に runtime 追加
  • Executor 作成
  • language_all.json に新しい言語を追加

とすれば行ける気がするが、system call 制限などでうまく追加できなかった。(Julia, Crystal を試して挫折した)

既存 runtime のものでも、judge.yml の設定が悪いのか使えない言語がある (特に JVM 系) ので正直何をしたらちゃんと動くのかコードをちゃんと追っていないので全くわからない。

github.com