夢の無線キーボードを自作したい。 第1話「マクロキーボード」

# 導入「自作キーボードにBluetoothをひとつまみ」
![20210930_164514-01.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500333/f7fbcbcf-afc9-891a-cd00-ffb822cb5fef.jpeg)
これを作りました。

遡って1年前、友人から勧められた[Mint60](https://booth.pm/ja/items/1041991)が初めて触れた自作キーボードでした。
分割キーボードなので、キーボードの間に書見台を置いて文字起こしをしたり、社用のノートPCを置いたり、お皿を置いたりと、デスクワークの利便性が飛躍的に向上しました。ありがとう、Mint60。

そして、ふと思ったわけです。
「これ、無線にしたら最強じゃね？」
と。

しかし、テストもせず、いきなり難度の高いものを作り始めるなんて愚の二乗。
まずは小さく手軽なもの、マクロキーボードを試作してみました。

この記事は、キーボード制作の流れをざっくりと紹介するものになります。個々の説明などはいずれ。

# コンセプト
+ 回路の動作検証のため、発注・制作コストを抑える。
+ 後に使いたい技術要素を試験的に盛り込む。

# 試したい要素と技術
### 無線(Bluetooth)
Bluetoothを搭載しているArduinoマイコンといえば、[ESP32](https://ht-deko.com/arduino/esp-wroom-32.html#11)。
技術資料も多いので、少なくとも色々試すには良いと思います。
そして何より安い。(国内で1500円、海外の通販で500円)
3.3V系なので、後述する3.7Vの電池との相性がいいのもポイント高いです。

### 電池
充電したい。乾電池は重い。なら、[リチウムイオンポリマー電池](https://www.marutsu.co.jp/pc/i/836348/)を使っちゃいましょう。
今回の試作で特に試験したいのは、ここの充電回路がうまく動くかどうかですね。

### フルカラーLED
ゲーミング需要。
開発中の動作確認にも便利です。
キーボードでよく使われているフルカラーチップLEDが5V系ばかりだったので、原始的な[4本足のフルカラーLED](https://akizukidenshi.com/catalog/g/gI-03037/)を採用しました。

# 回路図設計
8キーしかないので、キースイッチのダイオードは必要ないから省略。
![image (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500333/d91e1cc4-5962-17b0-d99d-0c28fb9b6523.png)

# 基板図設計
名刺サイズにしました。名刺ケースとしても使えるようにしたかった(未実装)。
![image (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500333/98101fa0-fc94-78a6-7a45-007797d28f7b.png)
このあと、ゾーンをGNDで塗りつぶします。

# 発注
PCB(基板)とキーボードアクリルプレートを[Elecrow](https://www.elecrow.com/services.html)さんに発注。
10セットで、
> PCB: $19.90
> プレート: $5.80 x2
> 送料: $9.30
>合計: $40.80
---

1万円くらいは覚悟していたので想定より安くて驚きました。


# 制御
[ArduinoIDEにESP32のライブラリを適用して](https://spiceman.jp/esp32-arduino-ide/)開発しました。
Bluetoothの接続部分は、[ESP32 BLE Keyboard library](https://github.com/T-vK/ESP32-BLE-Keyboard)を使用させてもらいました。
フルカラーLEDのテストに、RGBにそれぞれスイッチを対応させ、スイッチを押すと色が変化していくようプログラムしました。

````
#include <BleKeyboard.h>

#define BUILTIN_LED 2
#define LED_R 17
#define LED_G 21
#define LED_B 19
#define KEYSW_1 33
#define KEYSW_2 25
...
#define SETTINGSW 32
#define LEDC_BASE_FREQ 12800
#define LEDC_RESOLUTION 8
#define LEDC_CHANNEL_R 0
#define LEDC_CHANNEL_G 1
#define LEDC_CHANNEL_B 2

BleKeyboard bleKeyboard("BleMacroKeyboard", "BleMacroKeyboardd_manufacturer", 100);

void PwmLed(int channel) {
  static uint8_t brightness[3] = {0, 0, 0};
  static int diff[3] = {1, 1, 1};
  ledcWrite(channel, brightness[channel]);
  if (brightness[channel] == 0) {
    diff[channel] = 1;
  } else if (brightness[channel] == 255) {
    diff[channel] = -1;
  }
  brightness[channel] += diff[channel];
}

int read_all_sw() {
  unsigned int pushed = 0;
  if(digitalRead(SETTINGSW) == LOW) {
    pushed |= (1<<0);
  }
  if(digitalRead(KEYSW_1) == LOW) {
    pushed |= (1<<1);
  }
  if(digitalRead(KEYSW_2) == LOW) {
    pushed |= (1<<2);
  }
  ...
  return pushed;
}

void setup() {
  pinMode(KEYSW_1, INPUT_PULLUP);
  pinMode(KEYSW_2, INPUT_PULLUP);
  ...
  pinMode(SETTINGSW, INPUT_PULLUP);
  pinMode(BUILTIN_LED, OUTPUT);
  digitalWrite(BUILTIN_LED, LOW);
  ledcSetup(LEDC_CHANNEL_R, LEDC_BASE_FREQ, LEDC_RESOLUTION);
  ledcAttachPin(LED_R, LEDC_CHANNEL_R);
  ledcSetup(LEDC_CHANNEL_G, LEDC_BASE_FREQ, LEDC_RESOLUTION);
  ledcAttachPin(LED_G, LEDC_CHANNEL_G);
  ledcSetup(LEDC_CHANNEL_B, LEDC_BASE_FREQ, LEDC_RESOLUTION);
  ledcAttachPin(LED_B, LEDC_CHANNEL_B);
  ledcWrite(LEDC_CHANNEL_R, 0);
  ledcWrite(LEDC_CHANNEL_G, 0);
  ledcWrite(LEDC_CHANNEL_B, 0);
  bleKeyboard.begin();
}

void loop() {
  // static variable defind.
  static unsigned int sw_pushed_saved = 0;
  // measures for chattering.
  if(sw_pushed_saved != read_all_sw()) {
    digitalWrite(BUILTIN_LED, HIGH);
    delay(5);
    // for LED
    unsigned int sw_pushed = read_all_sw();
    unsigned int sw_pushed_xor = sw_pushed ^ sw_pushed_saved;
    if(sw_pushed & (1<<1)) {
      PwmLed(LEDC_CHANNEL_R);
    }
    if(sw_pushed & (1<<2)) {
      PwmLed(LEDC_CHANNEL_G);
    }
    if(sw_pushed & (1<<3)) {
      PwmLed(LEDC_CHANNEL_B);
    }
    // setting sw
    if(sw_pushed_xor & (1<<0)) {
      //
    }
    // ble
    if(bleKeyboard.isConnected()) {
      if(sw_pushed_xor & (1<<4)) {
        if(sw_pushed & (1<<4)) {
          bleKeyboard.press('a');
        } else {
          bleKeyboard.release('a');
        }
      }
      if(sw_pushed_xor & (1<<5)) {
        if(sw_pushed & (1<<5)) {
          bleKeyboard.press(KEY_ESC);
        } else {
          bleKeyboard.release(KEY_ESC);
        }
      }
      ...
    }
    sw_pushed_saved = sw_pushed;
    digitalWrite(BUILTIN_LED, LOW);
  }
}
```

# 組み立て
ソケットにしたので、キースイッチの交換が出来ます。
![20210930_161913-02.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500333/bc5e2be3-cd4f-7e08-b09b-1f32ff34dc5b.jpeg)
フルカラーLEDも期待通りに動作しました。
![20210930_162106-01.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500333/7da10cf9-1606-20e9-dc94-582e18c75d7d.jpeg)
充電して、Bluetooth接続も出来ました。

# レビュー
## 得られたもの
やりたかったこと(技術的に)はだいたい出来ました。試作機としては十分。何回か失敗することを想定していたのですが、1回でパスしてしまい拍子抜けです…

## 要改善箇所
### 厚さ
約40mm。ほかの自作キーボード(mint60など)と比べると10mm程度厚い。電源を内蔵しているので、仕方ないところもありますが、もう少しスリムにしたいですね。
![20210930_162320-01.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500333/1eba667a-7d29-0878-4e89-b203c8229df7.jpeg)

### Bluetooth接続
AndroidとWin10には接続出来たのですが、[Macには接続出来ません](https://qiita.com/optimisuke/items/b258b1c7a0d2388bde64)でした。ライブラリをそのまま使っているので、接続部分を自分で書く必要がありそうです。

### 電池もち
300mAhのバッテリーでは、2,3時間で充電が切れてしまうようです。
今回採用した電池は、Li-Poの中では容量の少ない方ですので、もっとバッテリー容量の大きいものを採用する必要がありそうです。
また、消費電力量を抑える工夫なども特にしていないので、そのあたりもやっていきたいですね。

### 見た目
基板表面が見えたほうが洒落ていると考え、トッププレートを透明にしたのですが、汚いはんだが見えてしまうのは盲点でした。
色の濃い背景の上に透明アクリルを配置すると、薄く反射するのできれいなのですが、無難にいくなら透過しないプレートがベターですね。
![20210930_162447-01.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500333/d94f285a-eb54-b0c6-4027-016c50b9889c.jpeg)
↑ ここ、好きところとダメなところが同時に同時に楽しめる角度。

# 次回
本丸である分割キーボードの制作をします。

↓ 只今の進捗。
![スクリーンショット 2021-09-17 141305.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500333/fa101a83-1efc-36ce-3f4c-33833c69b0c8.png)
乞うご期待!!!
（ここに第2回のリンク貼る）