ページ

2021年1月2日土曜日

完全無線分割キーボード Thumbsplit58 を作った話

 TL; DR

  • 完全無線分割キーボードを設計しました。今のところエンドゲームです。
  • 日本語キーボードは親指周りにキーが多いので、BackSpace/Enterを無変換/変換等に割り当てることで、ノートPC使用時にもキーマップの互換性をある程度担保できます。

はじめに


2019年の中頃に、完全無線分割キーボード Thumbsplit58 を設計しました。1年ほどキーボードを使って出てきたフィードバックを取り込んで、今年の終わりに一度ケースを作り直しました。スイッチはKailh Choc  (ソケット対応)、キーキャップは MBK Low Pro (1u/1.5u) を想定しています。MitosisComet46 がベースになっていて、NordicのGazellプロトコルで左手と右手がキー情報をQMKが動くUSB接続のレシーバに対して送信します。

最近流行りのBluetooth自作キーボードに対する利点としては、とりあえずレシーバをUSB接続したら動く、左右の手が独立にレシーバに送信するので低レイテンシー低消費電力(のはず)、QMKはレシーバのatmega32で動くのでQMK標準の方法で書き込み可能、とかでしょうか…?


今のところこのキーボードを販売する予定はありませんが、備忘録も兼ねて設計思想をここに残しておこうと思います。

どうして作ったのか?


もともと自分は10年以上ThinkPadの日本語キーボードを愛用していて、ノートパソコンはX40からずっとThinkPadですし、USB接続のトラックポイントキーボードも初代から使い続けています。

※世代が変わってもずっと同じ配列 (13インチの日本語キーボードは違いますが…) でキーボードを設計してくれているので安心です。

ただトラックポイントが必須かというとそういうわけではなくて、人差し指が腱鞘炎になりかけてVimキーバインドを覚えてからは打鍵中にトラックポイントを使うことは減り、現在は特になくても不自由ではないという状態です。

ちょうど2年前ぐらいに自作キーボード界隈に入沼し、ErgoDashを作って分割キーボードの素晴らしさに目覚めたあとは、エンドゲームを求めて自分でキーボードを設計する方法を模索していました。椅子の肘掛けに置いて使うために、完全無線分割にするという構想は当初からあったような気がします。

分割キーボードというとErgoDoxの地を受け継いだColumn Staggeredのものが多い印象ですが、実際に使ってみてRow Staggeredのほうがあっている感じがしたのと、ノートパソコンを使う際にはThinkPadの配列で打鍵するので、それに近いものが良いなぁと思っていました。ただ、親指周りにキーを配置して小指の負担を減らすのは非常に効果があったので、親指周りは3キーずつ欲しいという思いがありました。

なので設計の要望をまとめると、
  • 完全無線分割
  • Row Staggeredで、ThinkPadと同じ配列(各行が0.5u/0.25u/0.5uズレる)
  • 日本語キーボードのキーマップができるキー数(右手小指に十分なキーが必要)
  • 親指にBackSpace、Space、Enterを配置したい
みたいな感じでした。

自分が日本語キーボードにこだわっている理由は親指周りのキーの豊富さにあって、USキーボードのスペースバーの部分(CVBNMの下)に4キー配置されています。そのため、ThinkPadを使用しているときにも無変換にBackSpace、変換にEnter、カタカナ/ひらがなにDeleteを割り当てることで、最低限の互換性を保つことができるようになっています。

※キーマップについての詳細は後述します

具体的には、Thumbsplit58では日本語キーボードのこの範囲を切り出しました。右手小指が担当していたBackSpace、Enterは無変換、変換にマップしているので、その範囲のキーは省いています。

※6とBは右手にも置きたかったのですが、後述のNordic MCUのGPIO数の制約があって配置できませんでした。



基板


基板の設計はKiCadで行いました。設計にあたっては @foostan さんの「自作キーボード設計入門」を参考にしています。また、使用している部品は殆ど Comet46に使われているもの と同じで、MCUはNordic nRF51822が載っている Raytac MDBT40 を使用しています。

MDBT40周りは一応データシートに沿って設計したつもりですが、これで無線電波特性がちゃんと期待通り出ているかはわかりません…



実装部品を少なくするために全キー直接GPIOに繋いでスイッチ入力を検知しているのですが、MDBT40はGPIOが31本しかないので、右手30キー + ステータス用のLEDでいっぱいいっぱいになっています。

なお、レシーバは自分で設計は行っておらず、 Comet46 の OLED Display Receiver をそのまま使わせてもらっています。

基板はFusion PCBに発注しました。キーマトリクスがないのでLEDはついておらず、スッキリしてます。


もともとは写真のようにCR2032を1個で運用していたのですが、普通に使っていると1ヶ月で電池が切れてストレスに感じたので、設計変更時に塩化チオニルリチウム電池を使用するようにしました。

定格上は 3V 220mAh から 3.6V 2600mAh なのでエネルギーは14倍になりますが、実際はそれ以上に電池の持ちは良くなると思います (まだ切れたことがないので分かりませんが…)。というのも、MDBT40は無線の送信時に 15mA 程度の電流を消費しており、CR2032を1個で運用していたときは標準的な放電電流を大きく上回ってしまっていたためです。

※消費電力の計測については後述します

ケース


マウント方式はサンドイッチマウントというかボトムマウントというか…、トッププレートがPCBの貫通穴を通してボトムケースのボスにネジ止めされています。あまり打鍵感について理解せずにケースを設計したので、8本のボス + 外周でトッププレートを支えており、打鍵感は非常に硬いです。


もともとは奥に見えるケースのように、CR2032の部分のケースをくり抜くことで、高さをなるべく低く & 電池が外から交換可能を実現していました。ただ、いくら外から簡単に電池が交換できるとはいえ月イチでキーボードの反応が悪くなるのはダメでした…


そこで設計変更時にはキーボードに10度の傾斜をつけ、足の部分に単三電池と同じ形状の塩化チオニルリチウム電池を入れることにしました。手前側はCR2032がなくなったことで、逆に高さを低くすることができています。


プレートは過去記事でお世話になった、AliExpressのBestCarbonに注文しました。1mm の綾織マットを切削してもらっています。特にカーボンである必要はないのですが、見た目が好きなのでカーボンを使用しています。

※カーボンは導電性で電波を遮断してしまうので、電波特性的には樹脂のトッププレートのほうが良いかもしれません


このときは1.5uキーキャップが手に入らなかったのですべて1uの位置にキースイッチを配置していますが、今は1.5uの位置にキースイッチを挿し直して、プレートも1.5u専用のものを作り直しています。

ファームウェア


このキーボードは、左手と右手にそれぞれ入っているNordic MCUがキー状態が変更されるたびに現在のキー押下状態を送信し、PCにUSB接続されたレシーバに入っているNordic MCUがそれを受信します。レシーバのatmega32はNordic MCUからシリアル通信でキー状態を受信して、QMKのマトリクススキャン関数の中では、実際にはマトリクスをスキャンせずに受信した値を使用します。

左手と右手は電池で動くので、可能な限り消費電力を少なくする必要があります。そのため、なるべくMCUがスリープしている時間を長くして、キー入力があったときだけ割り込みで起動するようなファームウェアにしなくてはいけません。

ところが、割り込みとスリープが絡むとファームウェアの挙動を追うのは難しいですし、クロックソースや無線送信の設定で大きく消費電力が変わってしまうこともあるので、消費電力が少ないファームウェアを開発する際には、実際にボードが消費している電流を計測してみるのが良いと思います。

良いオシロスコープを持っていればそれで計測することもできたのですが、自分は持っていなかったので、Nordic Power Profiler Kit を購入してみました。


Nordic PPKはNordicのMCUに限らず、(出力電圧電流の範囲であれば、)どんなボードでも消費電流を計測することができます。もちろんオシロスコープでも同様のことは可能ですが、PPKはUSBで繋ぐだけで簡易的に計測可能なので、お手軽さが良い感じです。

最近、後継の Nordic Power Profiler Kit II が出たようです。最大出力可能電圧が3V -> 5V、サンプリングレートが10倍になって、さらにアクリルのケースもついてくるようなので、無線自作キーボードを作っている方は消費電力計測用にに購入してみても良いかもしれません。

実際にPPKで計測するとこのような計測結果を得ることができます。グラフで大きく立っているスパイクが無線を送信したときの消費電流になっていて、1キー押して離した時には2回の送信が行われます。

※このグラフはThumbsplit58のファームウェアで、nRF5 SDK 11のデフォルトの無線設定を使用した状態の計測結果です

Comet46の実装では何もキーの状態に変更がない場合でも10秒間に一度キーの状態を送信しようとする挙動になっていたのですが、Comet46は最大リトライ回数が100回に設定されているのもあり、PCがスリープしてレシーバに電流が共有されていない状態では10秒おきに100回の送信が行われてしまっていました。

そこで、Thumbsplit58のファームウェアでは送信失敗した場合に、送信成功するか500msが経過するまで125ms周期でキー状態を再送信する挙動に変更することで、送信失敗時に不整合が起きる状況をなるべく回避しつつ、無駄な送信をしないように変更しています。

※このグラフでは送信成功しているので、再送信は発生していません
※500msタイムアウトはデバウンス用の1000Hz割り込みの中でカウントしているのですが、もう1本周期割り込みを追加すれば消費電力を更に減らせるかもしれません


次のグラフはサンプリングレートを上げて送信部分を取り直したものです。1回の送信(上のグラフでスパイクに見えていた部分)は実際は「キーボードからレシーバへの送信」と「レシーバからのACK受信」の繰り返しになっています。


このグラフは送信信号強度を +4dbm に設定したときのものですが、送信信号強度を落としてもデータ送信の山が小さくなるだけでACK受信の山は変化しないため、送信信号強度はそこまで消費電力に大きな影響を与えず、むしろリトライ回数を減らすほうが重要そうです。

送信時にリトライが発生するのは周波数ホッピングを行っているためです。Nordic MCUは下記のようにある一定時間ごとに送受信するチャンネルを変更しながら送受信を行いますが、送信側と受信側で時刻同期が取れていない状態では、チャンネルが合わずに送受信を行うことができません。そこで、送信側は送信が成功するまで同じ周波数で何度も(timeslots_per_channel_when_device_out_of_sync回)送信を行い、送信が成功したあとは受信側と同期してホッピングを開始します。

Gazell Link Layer User Guide の Frequency Hopping より

デフォルトでは channel_table に入っているのが 4ch, 25ch, 42ch, 63ch, 77ch の5つで、Timeslot が 600us 、timeslots_per_channel は 2 になっていて、1.2ms毎にチャネルホッピングしているようです。

timeslots_per_channel_when_device_out_of_syncのデフォルト値は 15 になっていたのですが、そのチャンネルが競合しているケースのリトライ回数を減らすために、自分のファームウェアでは 10 (ちょうど総当り) に変更してみました。また、最大リトライ回数は20に設定しているので、チャンネルが競合していた場合は次のチャンネルを試します。ただし、この設定変更をしても劇的にリトライ回数が減らせるわけではなく、ベストな設定はいまいち見つけられていません…

※channel_tableに入っているチャネル数を減らすと良かったりするかもしれませんが、未検証です

送信側と受信側が同期している時間を増やせばリトライ回数を大きく減らすことができるのですが、syncを維持するには16MHzクロック(HFCLK)を動かし続ける必要があるので、sync維持時間をむやみに伸ばしてしまうとsync維持中の消費電流が1mA程度に増えてしまって本末転倒になってしまいます。

自分の計測では1回のリトライあたり6.7uC、1msのsync維持に1.2uCの電荷が消費されました。チャンネル競合がないとするとリトライ回数の期待値は3.6回になるので、全くsyncしない場合の送信1回のリトライによる電荷消費量の期待値は24.12uCになり、これはsync維持時間の20msに相当します。つまり、20msの間に送信が2回以上連続して発生しない場合は、sync維持時間を20msより伸ばしてしまうとsyncの意味がなくなってしまいます。

デフォルトでは 18ms 間syncを維持するようになっていますが、キーボード用途の場合は1回の送信ペイロードにすべてのデータが収まるためにデータを連続送信する必要がなく、普通に打鍵していて20ms以内にキー入力が重複することは多くないので、自分のファームウェアではsync維持時間は 0ms にして常に out of sync 状態にするように無線設定を変更しています。


キーマップ


現在のキーマップはこんな感じで、前述の通り日本語キーボード配列がベースになっています。BackSpace、Space、Enter、DelはThinkPadでも近い場所にリマップしているので、ノートPC使用時でもそこまで違和感なく使用できます。1年程このキーマップを使っていますが、特に不満な点は出てきませんでした。


キーが2つ書いてあるキーは QMK の Mod-Tap の機能を使って、短押しで通常のキー入力、長押しで Modifierキー入力になるように設定しています。例えばCapsLockのところにあるキーの場合、短押しでEsc、長押しでCtrlになります。

残念ながら Mod-Tap は Windows/Ubuntu で容易に実現する方法がないので、ノートPCのキーボードを使用しているときには使えません。ノートPCとのキーマップ互換性の観点では入れないほうが良いのかもしれませんが、Esc/Ctrl等は実際使っていて結構便利なので入れてしまっています。

レイヤー機能は(ノートPC使用時に使えないのもあって)あまり使いこなせておらず、F1 ~ F12を数字キーに入れたり、HJKLをカーソルキーにしたり、WASDをマウスキーにしている程度です…

おわりに


初代 Thumbsplit58 を1年間使って見えてきた電池の持ち等の課題については、無事に rev2 で解決できました。今のところこれが自分にとってのエンドゲームな気がしていますが、使っていて不便なところが出てきたらまた改良していこうと思います。

--

塗装に関するTips

ケースは DMM.make のサービスを使って MJF で出力しました。材料はPA12GBを使用しています。

塗装はなしでも良いかなと思っていたのですが、1辺が100mmを超えていてブラック染色オプションを選べなかったのと、MJFには吸水性があるという話を聞いていたので、汚れる前に塗装することにしました。

MJFの出力は積層痕が目立ちにくく、全く表面処理をせずに塗装しても上の記事のように十分綺麗になります。

PA12はナイロンなので、プライマーは必須です。自分はミッチャクロンマルチのスプレーを使いました。ベランダで塗装するときはホコリが舞わないように水を撒いてからやると良いと思います。ただし冬場は乾燥を室内で行う必要があるので、塗料は水性のものをオススメします。自分はアサヒペンの水性多用途シリーズを愛用しています。

塗装前のPA12GBナチュラルはこんな感じで、薄いまだらなグレーです。


これをつや消しブラックで塗装するとこんな感じになりました。塗装前の表面処理は全くやっていないため、造形の都合でできた線のようなものが見える箇所があります。気になる場合は塗装前に目地埋めしたり、何度か重ね塗りする必要があるかもしれません。


突然押したキーと全く違うバラバラなキーが入力された際のTips

1年使っている中で突然押したキーと全く違うバラバラなキー入力を返したり、(キーコードにマップされてなくて)押しても反応しなくなったりする現象に遭遇したのですが、これはどうもQMKの問題というか、EEPROMが壊れたときに起きる現象のようです。

このページにあるように、EEPROM Resetを行うことで無事に押した通りのキーが入力されるようになりました。

dfu-programmer atmega32u4 flash --eeprom eeprom_reset.hex

0 件のコメント:

コメントを投稿