スクラッチ&スクラップ

簡単なプログラミングや電子工作など。しょうもない工作の記録。

ミニマルな自作キーボード

自作キーボードが流行って2年ぐらい経つでしょうか。私もちょっとだけ、かじってみようと思います。

f:id:macrochelys99:20190529034811j:plain

きっかけ

ある知人のノートPCがカンマとピリオドがキー入力を受け付けなくなり、ショップに修理を頼んだら見積もりが2万越えだったようです。

安いデスクトップ用のキーボードつないでしのぐことにしたようですが、実際に使っているところを見るとかなり邪魔そうです。

そうだ、効かなくなったカンマとピリオドだけのキーボードなら邪魔にならないかも。

回路図

f:id:macrochelys99:20190528234723p:plain

ProMicroにスイッチをキー入力用2個リセット用1個つけただけです。キーボード用ではなく手元にあった汎用のタクトスイッチを使いました。

スイッチマトリックスではないのでダイオードは要らないし、プルアップ抵抗もINPUT_PULLUPで内部プルアップさせ部品点数は思ったより少ない。

12セグメント基板で余ったフルカラーLED の WS2812B も4個付けてあります。

基板アートワーク

A面
f:id:macrochelys99:20190529001316p:plain

B面
f:id:macrochelys99:20190529001350p:plain

今回使うスイッチは裏側にガイドボスの出っ張りがあるのですが、KiCad に初期導入されている12mmのタクトスイッチのフットプリントはガイドボスが入る孔がありません。

f:id:macrochelys99:20190529002328p:plain
https://www.alps.com/prod/info/J/HTML/Tact/SnapIn/SKHC/SKHCBJA010.html


そのまま使うと残念なことに。というか、KiCad でフットプリントの3D 表示させたらまさにそういう状態に配置されてて笑う。
f:id:macrochelys99:20190529002853p:plain

海外メーカーの安いスイッチはガイドボスが無い物もあるのでそれを使うのも有りですが、パネルを取り付けるので位置をしっかり出したかったのと、試しに買ってみたらパッチンパッチン安っぽいクリック音がうるさかったのでやめました。


ガイドボタン用の孔を追加したフットプリントを作ります。

f:id:macrochelys99:20190529003230p:plain
https://www.alps.com/prod/info/J/HTML/Tact/SnapIn/SKHC/SKHCBJA010.html


基板サイズが基板屋さんの指定する最小サイズより小さいので面付けして発注します。
f:id:macrochelys99:20190529013352p:plain

パネル

基板むき出しだと使いにくいので上面と下面だけアクリル板のパネルを取り付けます。基板CADが吐き出したDXF に重ねるようにパネル外形と孔を描いていきます。
f:id:macrochelys99:20190529012630p:plain

細かい寸法を入れていったら、微妙にズレているではないですか。
f:id:macrochelys99:20190529013911p:plain

上パネルは上下が非対称、下パネルは左右が非対称。しかもぱっと見ただけではわからない微妙なズレ。組み立てるときに逆向きに取り付けて「なんか精度悪くね?」となるやつです。

基板の外形はミリのグリッドに乗せ、部品の配置はミル(インチ系)のグリッドに乗せたので、スイッチを中央に置いたつもりが微妙にズレたようです。

コネクタやICなどの部品はインチ系が多いので、部品を配置するときはグリッドをミルにすることが多いのですが、パネルに関係する部品はミリ系で配置しないといけなかったですね。

ズレていても良いのですが、その場合は組立て時に上下左右裏表が判りやすいよう目印をつけておきたかったです。この場合だと、1か所だけカドのRをC面にするとかでしょうか。
f:id:macrochelys99:20190529015000p:plain

気付いたのが発注後だったので、このまま作ります。

10cm×10cmの正方形から2セット取れます。発注単位が5枚なので10台分。思ったよりたくさん取れました。基板も面付けして40台分あるのですが..... 配っても邪魔になるだけですね。
f:id:macrochelys99:20190529015153p:plain

入荷

f:id:macrochelys99:20190529034437p:plain

組立て

ProMicro の泣き所、「表面実装の Micro USB がもげる」の対策として、コネクタを上から押さえるだけの基板を作り、ピンヘッダに重ねてハンダ付けしています。どの程度強度アップしてるか試してないけど、無いよりマシかな?
f:id:macrochelys99:20190529032745j:plain

スイッチとキートップ
f:id:macrochelys99:20190529033545p:plain

Arduinoスケッチ

#include "Keyboard.h"
#include <Adafruit_NeoPixel.h>

#define   NUM_KEY     2   // 使用するキーの数
#define   PIN_PIXELS  A0  // WS2812B を接続するピン
#define   NUM_PIXELS  4   // WS2812B の数

Adafruit_NeoPixel pixels(NUM_PIXELS, PIN_PIXELS, NEO_GRB + NEO_KHZ800);

const uint8_t       PIN_KEY[NUM_KEY] = {2, 3};        // キーを接続したピン番号
const char          FUNC_KEY[NUM_KEY] = {',', '.'};   // キーに割り当てる文字
const unsigned int  INSENS = 5;                       // チャタリング対策の不感時間[ms]

/* キーを押すごとに変化するLEDの色 */
const uint32_t      rgb[] = {0x7F0000, 0x007F00, 0x00007F, 0x3F3F00, 0x3F003F, 0x003F3F, 0x3F3F3F};

void setup() {
  for (uint8_t pos = 0; pos < NUM_KEY; pos++) {
    pinMode(PIN_KEY[pos], INPUT_PULLUP);
  }
  Keyboard.begin();
  pixels.begin();
  pixels.clear();
  write_pixels_switch();
  pixels.show();
}

void loop() {
  key_scan();
}

void key_scan() {
  static boolean prev_key[NUM_KEY];
  static unsigned long prev_press_time[NUM_KEY];    // 前回キーを押した時間(チャタリング対策用)
  static unsigned long prev_release_time[NUM_KEY];  // 前回キーを離した時間(チャタリング対策用)

  /* キーの状態を順番にスキャン */
  for (uint8_t pos = 0; pos < NUM_KEY; pos++) {
    boolean key = digitalRead(PIN_KEY[pos]);
    unsigned long time = millis();

    /* キーを押したとき */
    if (prev_key[pos] == HIGH && key == LOW) {
      if (time - prev_press_time[pos] > INSENS && time - prev_release_time[pos] > INSENS) {
        Keyboard.press(FUNC_KEY[pos]);
        prev_press_time[pos] = time;
        write_pixels_switch();
        pixels.show();
      }
    }

    /* キーを離したとき */
    if (prev_key[pos] == LOW && key == HIGH && time - prev_press_time[pos] >  INSENS) {
      Keyboard.release(FUNC_KEY[pos]);
      prev_release_time[pos] = time;
      pixels.show();
    }

    prev_key[pos] = key;
  }
}

/* LED の色を切り替える */
void write_pixels_switch() {
  static uint8_t rgb_pos = 0;
  for (int i = 0; i < NUM_PIXELS; i++) {
    pixels.setPixelColor(i, rgb[rgb_pos]);
  }
  rgb_pos = (rgb_pos + 1) % (sizeof(rgb) / sizeof(rgb[0]));
}

今回キーは2個しかありませんが、マトリックスにしない限りキーが増えても最小限の修正で済むように作りました。

#define   NUM_KEY     2   // 使用するキーの数
const uint8_t       PIN_KEY[NUM_KEY] = {2, 3};        // キーを接続したピン番号
const char          FUNC_KEY[NUM_KEY] = {',', '.'};   // キーに割り当てる文字

試してないですが、ここの3行を書き換えるだけでキーを増やしたり割り当てを変えたりできるはずです。

無駄に光るよ

キーを押すごとに色が変わる。なんとも鬱陶しい
f:id:macrochelys99:20190529032148g:plain

使用感

  • 汎用スイッチはタッチ感が良くないので特殊キーには良いかもしれないが文字キーには向かない。
  • ノートPCのキー入力が効かなくなったせいで、句読点を「まる」「てん」から漢字変換して入力するのよりは使いやすくはなる。
  • シフトを押しながら押せば、ちゃんと 「<」や「>」が入力できた。
  • マクロ用として使うなら良いかもしれない。
  • キーにマウスクリックの機能をアサインしようとしたが、#include "Keyboard.h"#include "Mouse.h" は同時に使えないらしく動かなかった。

部品代

品目 金額 メモ
ProMicro 約1000円 1個 1台分
基板 約600円 4枚取り×10枚で40台
パネル 約700円 10台分
基板とパネルの送料 約2000円
LED (WS2812B) 約50円 4個 1台分
スイッチ 約200円 2個 1台分
キートップ,キーカバー 約60円 2組 1台分
六角スペーサー 約1000円 8本 1台分

反省点

  • もっと小さくしたかった。特に厚み。(現在 27mm)
  • 上下のパネルが 5mm厚なので、薄くしても良さそう。
  • パネルの向きがやはり組み立てる時に迷う。完全に対称にするか、目印を付けたかった。
  • しかし、試しに逆向きに取り付けてみたところ、特に違和感なかった。
  • 基板に ProMicro の取り付け向きをシルクで表示するのを忘れた。
  • 基板にM3のネジ孔がスペース的に入らなかったので M2.6 で設計したが、M2.6 は安価な六角スペーサーが見つからず高く付いた。M2でも良かったかもしれない。
  • キーボード用スイッチを使わず汎用スイッチを使ったので、キートップと透明のキーカバーの間に紙を挟むだけでキートップの印刷を自由に作れる

まとめ

製作のきっかけとなった知人の反応
「そういえばスラッシュのキーも壊れてたんだっけ。」