kumak1’s blog

kumak1のイラストや技術ログ

好きなキーボードを使い続けるためにキーボード作り始めた

これは pepabo Advent Calendar 2016 - Qiita 11日目の記事です。 昨日はいつも隣の席で頑張っている yinm さんの 社会人生活をふりかえります - 楽しいだけで十分です でした。

はじめに

Amazon Dash Button が日本で開始されたり、ペパボのデザイナさんが 自宅の照明を点けたり消したりできるWebサービスを公開 していたり、いよいよIoTが特別なものではなく、身近なものになってきましたね。 「わたしだってソフトだけじゃなくてハードもエンジニアリングしたい!けど、いんたぁねっと使うの敷居高い・・」ので、まずは簡単な組み込み機器を作ってみようと思いました。

せっかくなので普段使える物を・・ということで、エンジニアらしくキーボードを作ってみます。静電容量方式の打ち心地が好みのため、仕事では REALFORCE104UG-HiPro を利用しています。が、 周りを見渡すElgo DoxKINESIS を使ってる人がいます。うぅむ・・親指で打鍵できるの便利そう・・。なので作ってみよう!

つかったもの

  • Pro Micro
    • Arduino Micro互換機
    • 500円程度で購入できてお財布に非常に優しい(Arduino Micro は3000円ほど)
  • Arduino UNO
    • AVR ライターとして
    • 3000円程度で購入できますが、部屋に転がっていたので有効活用
  • CHERRY メカニカル MXスイッチ 赤軸 + キートップ
    • キーボードのメインとなる機器
    • 安いタクトスイッチなどでもいいのですが、なんとなく拘ってみました
    • 2000円程度で揃いました
  • アルミ板
    • アルミ板自体は500円、加工代で3000円しました・・
    • 自分で加工するのがベストかもしれない

殆ど Amazon で手に入りますが、アルミ板を東急ハンズで購入、スイッチとキートップJW system から購入しました。キートップはベースとなる部分と透明なカバーで構成されていて、中にシールや紙を挟むことで好きな印字に変更できます。 Pro Micro は一昔前の USB メモリよりも小さく、初めてみたときは感動ものでした・・

f:id:kumak1:20161210212940j:plain

Pro Micro へ気軽に書き込みをできるようにする

キーボードを簡単に作るために、 Pro Micro を利用します。 Pro Micro はマイコンが1つのみで、プログラムの書き込みをした後、ずっとUSB機器として動作するため今回の用途にぴったりです。 (しかも、キーボード用のライブラリも公式で提供されているため、至れり尽くせり) 反面、プログラムの書き込みを何回も行いたい場合は面倒な操作(RSTとGNDを短絡させて8秒以内に云々・・)が必要になってしまいます。 そこで Arduino UNO を書き込み装置(AVR ライター)にしてしまい、Pro Micro へ Arduino Micro のブートローダを書き込むことで、プログラムの書き込みと実行がスムーズに行えるようにしてしまいます。 (Arduino Micro のブートローダを書き換えたら、Arduino IDE がよしなにしてくれるため、追加で書き込み放題となります)

Arduino UNO を AVR ライター化

MacArduino IDE を起動し、Arduino UNO と USB ケーブルをつないで以下画像の通り、 ボード: "Arduino/Genuino Uno" シリアルポート: "Arduino/Genuino UNO" 書込装置: "AVRISP mkII" と接続設定を行います。

f:id:kumak1:20161210174543p:plain

Arduino IDE には AVR ライターのサンプルプログラム(スケッチ)が収録されているので、これを選択、Arduino UNO へと書き込みを行います。

f:id:kumak1:20161210174935p:plain

f:id:kumak1:20161210175715p:plain

これで Arduino UNO の準備は完了です。

Pro Micro を Arduino Micro 化

早速 Arduino UNO を使って Pro Micro へ書き込みをできる様、以下の通りに接続します。

UNO Pro Micro
GND GND
10 RST
5V VCC
13 (SCLK) 15 (SCLK)
12 (MISO) 14 (MISO)
11 (MOSI) 16 (MOSI)

実際に接続した図です。

f:id:kumak1:20161210200322j:plain

接続できたら、ボード: "Arduino/Genuino Micro" シリアルポート: "Arduino/Genuino UNO" 書込装置: "Arduino as ISP" と設定し、ブートローダを書き込みます。

f:id:kumak1:20161210203106p:plain

ブートローダが書き込み終えたら、Arduino UNO はもう取り外してしまって構いません。

ハードウェアの実装

まずはアルミ板からですが、金属加工の道具を持っていないため、下の図面を Illustrator でおこして(CADとかよくわからない・・)東急ハンズのお兄さんに加工してもらいます。

f:id:kumak1:20161210214054p:plain

アルミ板の加工が終われば、スイッチの組み付けを行います。穴にピッタリはまる!とはならないため、厚手の両面テープをアルミとスイッチの間に貼り付けることで、隙間を埋め接着します。 (接着剤は取り外しできなくなるので避けた。グルーガンを持っていれば、それが最適解な気がする。)

f:id:kumak1:20161210200335j:plain

接着物はやはりピンセットで作業を行うと捗ります。

f:id:kumak1:20161210200352j:plain

接着し終えたら、 Pro Micro とクリップやジャンパピンでつなげて仮実装します。 Mac と Pro Micro も USB ケーブルで繋いでしまいましょう。

f:id:kumak1:20161211122049j:plain

ソフトウェアの実装

短押し長押し で挙動が変わるキーを実装したいなと思いました。(具体的には Karabiner で設定する様な、短押しで かな/カナ 変更、長押しで となるキー操作ができるようにしたい) サンプルプログラムは以下の通り。

#include <Keyboard.h>

const uint8_t PIN_MAX   = 21;     // Pro Micro のPIN数
const uint8_t PIN_R_B_0 = 9;      // 仮実装で使う Pro Micro のPIN番号

uint8_t keyPressedTimes[PIN_MAX]; // キーボードが押下されている時間を記録する

void setup() {
  // キーボートとして認識させるPINの初期化
  for(uint8_t i = 0; i <= PIN_MAX; i++) {
    switch (i) {
        case PIN_R_B_0:
            pinMode(i, INPUT_PULLUP);
            keyRelease(i);
            break;
    }
  }

  Keyboard.begin();
}

void loop() {
  keyRead(PIN_R_B_0, 'a', 'b');

  delay(10);
}

/**
 * PIN の状態から、キーボードを動作させる
 *
 * @param uint8_t pinNumber   キーボートとして認識するPINの番号
 * @param char onClickKeyCode 短押し時のキーの振る舞い
 * @param char onPressKeyCode 長押し時のキーの振る舞い
 */
void keyRead(uint8_t pinNumber, char onClickKeyCode, char onPressKeyCode) {
  if (digitalRead(pinNumber) == LOW) {
    if (isKeyLongPress(pinNumber)) {
      Keyboard.press(onPressKeyCode);
    } else {
      keyPress(pinNumber);
    }
  } else if (isKeyPress(pinNumber)) {
    if(isKeyLongPress(pinNumber)) {
      Keyboard.release(onPressKeyCode);
    } else {
      Keyboard.write(onClickKeyCode);
    }
    keyRelease(pinNumber);
  }
}

/**
 * キーが押されたことを記録する
 * 
 * @param uint8_t pinNumber キーボートとして認識するPINの番号
 */
void keyPress(uint8_t pinNumber) {
  if (!isKeyLongPress(pinNumber)) {
    keyPressedTimes[pinNumber]++;
  }
}

/**
 * キーが離れたことを記録する
 * 
 * @param uint8_t pinNumber キーボートとして認識するPINの番号
 */
void keyRelease(uint8_t pinNumber) {
  keyPressedTimes[pinNumber] = 0;
}

/**
 * キーが押されているか確認する
 * 
 * @param uint8_t pinNumber キーボートとして認識するPINの番号
 */
bool isKeyPress(uint8_t pinNumber) {
  return keyPressedTimes[pinNumber] > 0;
}

/**
 * キーが長押しされているか確認する
 * 
 * @param uint8_t pinNumber キーボートとして認識するPINの番号
 */
bool isKeyLongPress(uint8_t pinNumber) {
  return keyPressedTimes[pinNumber] > 20;
}

プログラムの書き込み

Mac と Pro Micro をUSBケーブルで接続し、ボード: "Arduino/Genuino Micro" シリアルポート: "Arduino/Genuino Micro" 書込装置: "AVRISP mkII" と設定し、プログラムを書き込みます。

f:id:kumak1:20161211015731p:plain

書き込み後にキーボードを押してみると、短押し時には a 、長押し時には b が入力されるようになりました!

おわりに

自作キーボードの良さは拡張性の高さにあります。 自分で好き勝手にできるので、自分の動作環境に依存するものを容赦なく作れるのが魅力でもあります。

  • ESC キーなどの単一機能を実装
  • 短押し長押し で挙動が変わるキーを実装して Karabiner への依存を減らす
  • SHIFT のトグルボタン(iOSのshift 2回押しみたいな挙動)の実装
  • API連携による、定型文tweet、プロダクトのデプロイ
  • コンソール連携による、Git pull、タスクランナーの動作

などなど、作りたい・作れるものを挙げればキリがありません。 時間とスキルの関係上、「完璧に作り終えた!」という段階までできなかったのが悔やまれますが、あとは実際に使用してみながら調整して行こうと思います。

明日のアドベントカレンダーの執筆者は zipper さんです。めっちゃテッキーな話をしてくれそうだー。

参考記事