Happy Hacking KeyboardをBluetooth化する

PFUHappy Hacking Keyboard Professional2(HHKB)を購入しました。
今までキーボードはMacbookのもので十分だと感じてましたが、一度触ってみるとキーボードにこだわる人の気持ちがわかる、とても素晴らしいキーボードです。
今回はせっかくならば無線化したいということでBluetooth化してみました。

※当方電子工作は初心者なため、以下の内容の正しさは全く保証出来ません。
また、改造に伴う機器の故障等も自己責任でお願いします。

使用するソフトウェアは全てGitHub上 https://github.com/addsict/YetAnotherHHKBController にあります。

必要なもの

ArduinoでHHKBのコントローラを作成する

HHKBのキータッチを自由にハンドリングするためにはキーボードのコントローラを自前で用意する必要があります。
マイコンの知識は余りないので、今回は手軽にプロトタイピングができるArduinoを使用することにしました。

キーボードのコントローラは、

  1. キーが物理的に押されているかどうかをチェックし
  2. 押されていればその信号をキーボードの接続先デバイス(パソコンなど)に送る

という役割を持ちます。
キーボードというと、キーが押されたら電気信号が流れ、それによってコントローラが動くイベント駆動的なものだと直感的には思いますが、実際はとても短い間隔(HHKBの場合15ms)で全てのキーを1つ1つ押されているかチェックする、ポーリング処理を行なっています。

コントローラの処理を擬似コードで書くとこのようになります。

while(1) {
    for (全てのキー) {
        check_key_pressed();
        if (押されていたら) {
            send_key_code_to_computer();
        }
    }
}

全てのキーをチェックするにはその分だけマイコンのGPIOピンの数が必要ですが、実際は「キーの数 >> マイコンのGPIOピンの数」なので、キーはマトリックス状(行×列)に配置しマルチプレクサを介してキーを選択します。
例えば64個のキー(行8 × 列8)がある場合、行と列を2進数で表せば合計6本のGPIOがあれば十分です。

while(1) {
    start = timer_start();

    for (行から1つ選択) {
        for (列から1つ選択) {
            check_key_pressed();
            if (押されていたら) {
                send_key_code_to_computer();
            }
        }
    }

    while(timer_end() - start <= 15);
}

15ms毎にキーのスキャンを行うタイマーコードも含めました。 完全なコードはこちらにあります。
コントローラ周りに関しては、自作キーボードの作り方を説明しているShiggy Enterprisesというサイトが参考になりました。

BluetoothとHIDキーボード

Bluetoothは使用したいサービスによって様々なプロファイルを使い分けますが、
Bluetoothキーボードでよく使われるプロファイルはHID(Human Interface Device Profile)とSPP(Serial Port Profile)のどちらかです。 HIDはホストマシンにあらかじめドライバなどを入れておく必要がないので、改造するにあたってはHIDプロファイルが手っ取り早そうです。

HIDキーボードではキーボードのキーの状態を、HIDレポートと呼ばれる8バイトのパケットでホストマシンに伝えます。 HIDレポートの構成は以下のようになっています。

|       0        |       1        |     2 ~ 7     |
|----------------|----------------|---------------|
| modifier keys  | reseverd(0x00) | keycode 1 ~ 6 |
|----------------|----------------|---------------|
  • 0バイト目: modifier keys
    • 修飾キー(ShiftやControlキーなどのこと)を1ビットずつ論理和(OR)を取ったものを入れます
  • 1バイト目: reserved
    • 常に0x00が入ります
  • 2 ~ 7バイト目: keycode1 ~ 6
    • 実際に押されているキー(修飾キーを除く)を入れます

たとえば「左Shift(0xE1) + 左Command(0xE3) + a(0x04) + b(0x05)」が押されている場合、

0x0A #0xE1を0x01, 0xE3を0x03にし論理和を取った値
0x00
0x04
0x05
0x00
0x00
0x00
0x00

をホストマシンに送ります。

USBキーボードの同時押しは最大6キーまでとなっているのが多いですが、それはこのHIDレポートの構造から来ているのでした。
HIDレポートでは単純に現在押されているキーを送ればよく、「どのキーが新規に押された」「押されていたこのキーが離された」などのキーの状態を把握する必要がないので、 コントローラ側の実装はシンプルになります。これらのキーの状態の管理はキーのバウンシングも含めてホストマシン側でやってくれます。 HIDキーボードで使うキーコードの仕様は http://www.usb.org/developers/devclass_docs/Hut1_11.pdf (P.53〜)を参照してください。

今回使用したBluetoothモジュール、RN-42HIDはArduinoとUART(シリアル)で通信が出来るようになっています。
Arduino側はHIDレポートを組み立て、それをシリアル通信でRN-42HIDに送信するだけで、Bluetoothのパケットのペイロードに入れて送ってくれます。 コントローラはBluetoothのことを一切気にする必要がなくシリアルで送りたい信号を送ればいいので、実際の通信路がUSBケーブルであろうとBluetoothであろうと透過的に扱うことが出来るので便利です。

回路を製作しHHKBと接続する

電気回路・電気工作については全くの初心者なので余り深くは触れません。詳しくは写真から判断して下さい。

f:id:furuyamayuuki:20130727161232j:plain

f:id:furuyamayuuki:20130727161412j:plain

気を付けなければいけない点としては、

  1. HHKBのVccは5V、RN-42HIDのVccは3.3Vなので5V, 3.3Vの両方が必要
  2. 電池1本1.5Vなので2本直列に繋げても3Vにしかならない。昇圧回路AS1322Aで5Vにする
  3. 5Vにした入力電圧は三端子レギュレータで3.3Vに落としRN-42HIDのVccとする
  4. RN-42HIDのUARTは3.3Vの電圧なので、ArduinoのTXからRN-42HIDのRXに入力される信号を3.3Vに降圧させる

UARTを3.3Vに降圧するために、5.1kΩと10kΩの抵抗で分圧回路を作りRXの入力電圧にしています。
コントローラとHHKBとの接続に関してはtmkさんのInternal of HHKB proを非常に参考にさせて頂きました。

ホストマシンに接続する

回路を組み立てたら電源スイッチをONにしホストマシンとペアリングを行います。 ペアリング後以下のように接続されていればBluetooth化完了です。

f:id:furuyamayuuki:20130727163327p:plain

HHKBは見た目もそうですが中身も非常にコンパクトになっていて、電池や回路を中に組み込むのに苦労しました。

f:id:furuyamayuuki:20130727160759j:plain

*1:秋月で売っているRN-42-EKも同じRN-42が載っているので代わりに使えるかもしれません。HIDプロファイルも設定により切り替えれるみたいですので。