ディスプレイをモジュール化してキーボードを作るぞ（nowpad）

この記事は、[キーボード #2 Advent Calendar 2021](https://adventar.org/calendars/6280 "Qiita Home")の24日目の記事です。

あまりTwitterでつぶやかない、人見知りの[あんりある](https://twitter.com/unreal5050 "Twitter")と申します。
自作キーボード界隈の皆様に、少しでも有益な情報・刺激になるプレゼントになればと思い、記事をしたためました。

#はじめに
さて、自作キーボードの良い所は、自由な所です。
自分の好きなものだけを、好きなだけ、勝手にギュッと詰め込めます。
というわけで、私の好きなものをギュッと詰めたキーボード**nowpad**の制作経緯と、技術的に面白い所をピックアップしてご紹介します。

#先に結論
できた。かわいいがすぎるぞ。End Game。
![neko-2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2398079/f727ec55-ae08-f4e4-86fb-dd2ace6fafaf.gif)

#要求定義
##①キー入力でキャラクタが動く
https://www.sanwa.co.jp/product/syohin.asp?code=A-DTUH-01

発売当時、研究室で貧乏生活をしていた私にとっては高価で、購入を断念していましたが、欲しくてたまらないキーボード周辺機器？でした。今回物理的な実現は断念したので、ソフト的にやってみます。

##②好きなドット絵を表示
<img width="750" alt="c7861c51-ea78-728b-59dc-aa9a0263042c.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2398079/c7861c51-ea78-728b-59dc-aa9a0263042c.png">
ドット絵、大好きです。物理的には[昔キーキャップで作った](https://booth.pm/ja/items/2443942 "booth")のですが、ソフト的にやってみます。

##③時計を表示
<img width="750" alt="53f0d258-2d70-3d49-b0f9-3165293036a6.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2398079/53f0d258-2d70-3d49-b0f9-3165293036a6.png">
いいですよね、ニキシー管時計。[昔作って展示](https://pc.watch.impress.co.jp/docs/news/event/577240.html#contents-section-8 "impress")した物を家にいくつも置いています。古い表示デバイスが好きです。

##④TENTAKUとサイズ互換
<img width="750" alt="e5b0ac4c-38bc-f85b-7128-efe23900f6f7.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2398079/e5b0ac4c-38bc-f85b-7128-efe23900f6f7.png">
特に[海外で高い反響があった](https://www.youtube.com/watch?v=OAGMwWjefJg "youtube")電卓です。[TENTAKU](https://booth.pm/ja/items/1069765 "booth")とサイズを互換にします。

#ハードウエアの準備
##基板作成＆128個のカラーLED実装
製造が早いと評判のJLCPCBにデータを投げてみます。**結果1週間くらいで作ってくれました。**おすすめです。部品実装をお願いすることが久しぶりすぎて、自分で捨て基板を用意しないといけないと考えてしまい、無駄にパネライズしてしまいました。最終的には、右の黒い基板になります。
ポイントは、ノイズ対策部品は裏面に載せ、8x16個キワッキワに部品を載せた事ですね。手実装はさすがにちょっと。
<img width="750" alt="8331241f-00b4-54c4-b84f-2561d5c5acf1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2398079/8331241f-00b4-54c4-b84f-2561d5c5acf1.png">

##LED間の仕切りの準備
試行錯誤しました。仕切りのポイントは
　①背を高くするときれいに光が拡散する傾向があるが、高くしすぎるとデザイン的に恰好が悪い
　**⇒写真下部にある拡散板をちょうど良いものにする事によって背を低くできました。**
　
　②隣のLEDの色がもれない
　**⇒現物合わせで調整していきます。いくつか設計して3Dプリント出力します。最終的には一番右のモノになりました。**
<img width="750" alt="59537453-c288-55ac-afcf-153978c428fd.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2398079/59537453-c288-55ac-afcf-153978c428fd.png">

材料は、生産性・価格とのバランスで、最終的にレジンを選択しました。
ただ、色付きのレジンはお高いので、**遮光性を高めるために自分で黒に染色**します。
キーボード界隈の方にはおなじみのキーキャップを染める染料を用いました。
<img width="750" alt="59537453-c288-55ac-afcf-153978c428fd.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2398079/2b3e787f-d281-cf85-2e51-23bd6af8d66c.jpeg">

**なんかおいしそう**
<img width="750" alt="2331cdd1-2181-5336-b1f1-0542cc55683e.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2398079/2331cdd1-2181-5336-b1f1-0542cc55683e.jpeg">

加減が難しいのですが、5分～10分くらい高めの温度で漬けます。
<img width="750" alt="2331cdd1-2181-5336-b1f1-0542cc55683e.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2398079/46cc6d6e-46d1-11b7-51d0-406b58219243.jpeg">

##ディスプレイを傾ける
TENTAKUの時のように、素直に水平に取り付けるのがセオリーではあるのですが、ここは自由な自作キーボードの世界。
傾けられたディスプレイにはロマンがありますので、普通はやらない方法を含めて何とか実現できる方法を考えます。

###設計の際の前提条件
　□　装着するLEDモジュールは全3種（記事公開時には2種かも…)
　□　LEDモジュールは取り外し・交換が可能
　□　キーキャップの高さ(プロファイル)の違いによってLEDモジュールの高さも可変できる
　□　裏面の実装部品に干渉しない
　□　見えやすい約30度の傾きすぎない傾斜角
　□　TENTAKUとサイズ互換

　最終的な結果の図面はこちら～
<img width="750" alt="59537453-c288-55ac-afcf-153978c428fd.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2398079/17269f01-596f-cc3e-7927-9cee0ee8cf9e.png">
ここはかなり苦心しました。。

　⇒マックエイトのブラケットを使う

https://www.mac8sdk.co.jp/products/759

　傾斜が45度しかありません。また、パーツ単価も高めです。一応試しましたが、もっとよさそうな方法を探します。

　⇒アクリルで固定する

https://www.acry-ya.com/products/detail/285/

　アクリルにねじ穴をタップし曲げ加工。**曲げ加工はヒーター温度を測りながら、角度に合わせ適切な深さで掘った溝に沿って、ちょうどいいタイミングで曲げる職人技**ですね。うーん、もうちょっと楽がしたい…

https://akizukidenshi.com/catalog/g/gC-06360/

　ピンソケットは、足が短いし傾斜できないだろう
　**⇒Arduino用？の長い足のピンソケットがあった！**

　ピンソケットを傾けようとしても、部品穴が小さいから傾けられない
　**⇒部品穴を大きくしよう！**

　ピンソケットはまっすぐ傾斜をかけて固定できない
　**⇒実装用の固定ジグを作ろう！**

　というちょっと普通じゃない方法で挑戦した所、予想以上にうまくいきました。気になる挿抜の耐久性もまあまあ十分な数だし、接点も荷重や振動をかけるものでもなく、特に問題なさそうと判断。　（あくまでも自由な自作キーボードの世界の話ですので、一般的な使い方ではない事にご注意くださいませ）

　**なんといってもモジュールの抜き差しがとても楽＆必要なスペースが少なくて済む**ので、この設計で正解でした。

#時計の表示

##部品選定
　ニキシー管時計ではGPSで時計を合わせていましたが、時刻設定入力時のタイミング誤差もあるので、今回ppm単位の精度はあまり追わないことにしました。いろいろ検証した結果、**DS1307** を使います。選定理由としては、

https://www.adafruit.com/product/3296

　□　QMKで利用できるI2Cを使っている
　□　入手性の高い電池の電圧で、長期間(数年レベル)で、現在時間を保持できる
　□　部品サイズが小さい

時刻合わせはの際は、”F24”に割り当てたキーを押した後に
　 year XX -> month XX -> day XX -> hours XX -> minutes XX -> seconds XX
の順に数字キーを押すと設定ができるようになっています。**キー配置がテンキーベースなので、数字入力の相性が良く直感的**です。

https://github.com/unreal5050/qmk_firmware/tree/nowpad/keyboards/nowpad

```php:keymap.c
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
    if (keycode == KC_F24 && record->event.pressed) {
		is_in_effect_mode = true;
        is_in_set_time = true;
        new_time_index = 0;
        toggle_pic = false;        
    } else if (is_in_set_time) {
        if (!record->event.pressed && keycode >= KC_1 && keycode <= KC_0) {
            new_time[new_time_index++] = (keycode == KC_0) ? 0 : keycode - KC_1 + 1;
            if (new_time_index == 12) {
                is_in_set_time = false;
                ds1307_set_time(
                        (new_time[0]) * 10 + (new_time[1]),
                        (new_time[2]) * 10 + (new_time[3]),
                        (new_time[4]) * 10 + (new_time[5]),
                        (new_time[6]) * 10 + (new_time[7]),
                        (new_time[8]) * 10 + (new_time[9]),
                        (new_time[10]) * 10 + (new_time[11])
                );
                for (int i = 0; i < 12; i++) {
                    tap_code(KC_BSPACE);
                }
                #ifdef CONSOLE_ENABLE
				uprintf("new_time[0]: %u\n", new_time[0]);
				uprintf("new_time[1]: %u\n", new_time[1]);
				uprintf("new_time[2]: %u\n", new_time[2]);
				uprintf("new_time[3]: %u\n", new_time[3]);
				uprintf("new_time[4]: %u\n", new_time[4]);
				uprintf("new_time[5]: %u\n", new_time[5]);
				uprintf("new_time[6]: %u\n", new_time[6]);
				uprintf("new_time[7]: %u\n", new_time[7]);
				uprintf("new_time[8]: %u\n", new_time[8]);
				uprintf("new_time[9]: %u\n", new_time[9]);
				uprintf("new_time[10]: %u\n", new_time[10]);
				uprintf("new_time[11]: %u\n", new_time[11]);
				#endif
            }
        }
    }
```

#猫を動かす
界隈では有名なひよこさんを動かそうか迷ったのですが、ここでは猫にします。

##猫を動かすための手順
　①8x16の猫のドット絵を考える
　②動いた後のコマの差分のドット絵を考える
　③ドット絵の表示を、QMK対応のコードにする
　
　エクセルでツールを作りました。ツールにはどうしてもGUIが必要になるため、簡易なもので恥ずかしいのですが、VBAのマクロを使用して作成しています。
　https://github.com/unreal5050/qmk_firmware/blob/nowpad/keyboards/nowpad/color_matrix.xlsm
　上記より”color_matrix.xlsm”をダウンロードして、マクロを有効にしてください。
<img width="750" alt="59537453-c288-55ac-afcf-153978c428fd.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2398079/202dfd57-2f41-a117-8678-82491762a5f2.png">



　**左側の表**
　⇒カラーインデックスです。hsvの値で表現される色を登録しています。自分の好きな色を追加できます。カラーは理論値とLEDの色が大きく異なるため、実際に色を確認して登録しないといけません。RemapやVIAに対応しているので、それらを使うとPC画面と連動し、リアルタイムにhsv値とLEDの色を確認しやすいです。
　![iro_2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2398079/6de3fbb7-37f0-dfa3-8b57-32c52e8bdb9e.gif)
(実際にRemapで確認している様子)

　**右側の8x16の格子**
　⇒カラーインデックスのセルを、格子の中にコピーして、ドット絵をかきます

　**Code conversionのボタン**
　⇒押すと、格子のドット絵をコードに変換します。生成されたコードをコピーし、keymap.cの　”Please Paste the code generated by the Excel tool”以下の適切な場所にペーストします。

```php:keymap.c
    else if ( ( (keycode == KC_0) || (keycode == KC_1) || (keycode == KC_2) || (keycode == KC_3) || (keycode == KC_4) || (keycode == KC_5) || (keycode == 6) || (keycode == KC_7) || (keycode == KC_6) || (keycode == KC_7) || (keycode == KC_8) || (keycode == KC_9) || (keycode == KC_DOT) ) && (is_in_set_time == false) && (is_in_effect_mode == false) && (record->event.pressed) ) {
		if(toggle_pic == false){
			toggle_pic = true;
			//Please Paste the code generated by the Excel tool. Start first image.
			sethsv(0, 0, 255, (LED_TYPE *)&led[0]);
			sethsv(0, 0, 255, (LED_TYPE *)&led[1]);
			sethsv(0, 0, 255, (LED_TYPE *)&led[2])
```
数字とドットのキーを押したときにドット絵が遷移し、猫のしっぽが動いているように見えるはずです。

デフォルトのnowpadのファームウエアでは、容量の99％までギリギリ使っています。2枚目の差分のドット絵は、更新される絵の差分のみ入力しています。今回はQMKで対応している各種LEDのエフェクトなどを全て入れたかったので入れていますが、表示できるドット絵を増やしたいと思う方は、下記のページを参考にしてエフェクト種類を含む必要な機能を絞って容量を節約すると登録できる絵を増やすことができます。

https://thomasbaart.nl/2018/12/01/reducing-firmware-size-in-qmk/

##時計のフォントも変更可能
<img width="750" alt="6c4f9e68-e3db-6b7c-412b-709d6010081f.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2398079/6c4f9e68-e3db-6b7c-412b-709d6010081f.png">
時計のフォントも自由に変更ができます。3x8サイズの数字の大きさの前提であれば、
先ほど紹介したエクセルのfontシートを開くと上記の画面が表示されます。
猫の絵と同様に、自由に自分の思い描く色・形をフォントとして作成・登録していきます。

　①3x8の0～9のドットフォントを考える
　②ドットの数字の絵を、QMK対応のコードに変換する
　③ws2812c.cの数字に対応する部分コピー＆ペーストする

下記は”0”の数字の部分に相当する、フォントに対応する部分です。
こちらにエクセルで生成したコードを貼り付けます。残り1～9まで同様に作成すればOKです。

```php:ws2812c.c
void Disp_0(uint8_t digit_offset){
	//Please copy and paste the code generated by the Excel tool.
	sethsv(0, 0, 0, (LED_TYPE *)&led[digit_offset + 0]);
	sethsv(0, 0, 0, (LED_TYPE *)&led[digit_offset + 1]);
	sethsv(0, 0, 0, (LED_TYPE *)&led[digit_offset + 2]);
	sethsv(0, 0, 0, (LED_TYPE *)&led[digit_offset + 16]);
	sethsv(85, 255, 255, (LED_TYPE *)&led[digit_offset + 17]);
	sethsv(0, 0, 0, (LED_TYPE *)&led[digit_offset + 18]);
	sethsv(85, 255, 255, (LED_TYPE *)&led[digit_offset + 32]);
	sethsv(0, 0, 0, (LED_TYPE *)&led[digit_offset + 33]);
	sethsv(85, 255, 255, (LED_TYPE *)&led[digit_offset + 34]);
	sethsv(85, 255, 255, (LED_TYPE *)&led[digit_offset + 48]);
	sethsv(0, 0, 0, (LED_TYPE *)&led[digit_offset + 49]);
	sethsv(85, 255, 255, (LED_TYPE *)&led[digit_offset + 50]);
	sethsv(85, 255, 255, (LED_TYPE *)&led[digit_offset + 64]);
	sethsv(0, 0, 0, (LED_TYPE *)&led[digit_offset + 65]);
	sethsv(85, 255, 255, (LED_TYPE *)&led[digit_offset + 66]);
	sethsv(85, 255, 255, (LED_TYPE *)&led[digit_offset + 80]);
	sethsv(0, 0, 0, (LED_TYPE *)&led[digit_offset + 81]);
	sethsv(85, 255, 255, (LED_TYPE *)&led[digit_offset + 82]);
	sethsv(0, 0, 0, (LED_TYPE *)&led[digit_offset + 96]);
	sethsv(85, 255, 255, (LED_TYPE *)&led[digit_offset + 97]);
	sethsv(0, 0, 0, (LED_TYPE *)&led[digit_offset + 98]);
	sethsv(0, 0, 0, (LED_TYPE *)&led[digit_offset + 112]);
	sethsv(0, 0, 0, (LED_TYPE *)&led[digit_offset + 113]);
	sethsv(0, 0, 0, (LED_TYPE *)&led[digit_offset + 114]);
}
```

#宣伝
下記boothのページで12/24(土)　22：00～
nowpadのキットが予約販売される予定です。 こちらもご興味あればご参照ください。

https://anlabo.booth.pm/items/3519021

#おわりに
<img width="750" alt="68c6ee2c-1325-9977-0d02-51ad931b7ecd.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2398079/68c6ee2c-1325-9977-0d02-51ad931b7ecd.png">
<img width="750" alt="2f9108e8-908d-1f16-bc8e-59deae4a8fa1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2398079/2f9108e8-908d-1f16-bc8e-59deae4a8fa1.png">
というわけで、①～④までの私の身勝手な要求仕様を満たした私のEndGameが完成しました。**本当にエフェクトには癒されるし、時計は便利だし、猫はかわいいので専用ケースを作って常に持ち運んでいます。MIDI機器としても動きます。**キーボードとしても使えますが、時計や癒しの照明として、机上のインテリアになるのはとても良い事です。

<img width="750" alt="693ada03-33f6-3824-d0ff-121886ef8551.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2398079/693ada03-33f6-3824-d0ff-121886ef8551.png">

※デフォルトFWの書き込みやキーマップの更新は、ブラウザ上で操作できる[Remap](https://remap-keys.app/catalog?keyword=nowpad "Remap")に対応しています。このような素晴らしい自作キーボードの世界を盛り上げ支え続けているQMK・KLE・VIA・Remapの関係者の皆様・および界隈の皆様にはこの場をお借りして感謝申し上げます。