何か作った系

【自作】キーボードの作り方について解説してみる

どうも、バイト戦士です。

今回は、左手デバイスを自作しました。

ま、解説と言いつつ自己満の記録なんですよね。。。(スマン)

やりたいことやるんじゃぁッ

Youtube始めます

今回も動画を作りました。

概要はまとめることができたと思います。

全部動画にしようかとも考えたんですけど尺が長すぎる上に面白くないのでやめました。

カバーしきれなかった分をこっちで解説したいと思います。

何となくですが、コミュニケーション不足が改善されそうな気がします。(多分一人でしゃべってるから大して効果はない。。。)

少しずつ、ステップアップしていきます。よろしく。

自作キーボードを作る理由①

なんか作るうえで理由は大事。

そしてワイが左手用のキーボードが欲しい理由、それは、

左手がいてぇ。

ということ。具体的にはCtrl+Zキーを連打するときです。

みての通り、小指と薬指を酷使します。

最近は慣れてきた感もありますが、左手の左半分が腱鞘炎っぽくなったりするのでマジで何とかしたいです。

自作キーボードを作る理由②

キーボードって思ったより種類があります。

私も調べるまであんまり詳しくなかったんですがかなりの数出てます。なのですぐに欲しいなら買った方が速いと思います。

でも今回は自作します。

価格が高めな商品が多い

自作する理由ですが、一つ目は高いことです。

キーボードって安いものだと1000円しないんですが、なぜか左手キーボードになると平均的に1万円くらいします。

やっぱり普通のキーボードから外れるデバイスというのは、良くも悪くも「カスタムパーツ」なんだと思います。

もちろん、価値を感じて物品を購入すること、それ自体を否定はしません。

が、自分のように普段の検索や落書き趣味絵を描く程度の人間に、3万円のデバイスはちょっと高いです。

だから安く作ってやろう、というわけです。

気楽に使えない

あとはなんだろう、、、

ポテチ食ったり飯食いながら触りたくはないんですよね。(ものがいいだけに、買ったら多分大切にします。)

自作なら「利益」に相当する部分がないので出費した金額と工夫の数だけ自分好みに仕上げることができます。

左手デバイスといえど、普通に使いたい。

でもって、完全に自分好みのデバイスに仕上げたい。

そういうわけです。

なので今回は自作。

全体的な仕様

まずは仕様を決めます。

おおざっぱに、どんな機能がほしいかなぁ~っていうのを決めていきます。

キーの種類と数

今回は以下のキーを実装することにします。

①頻繁に使うキー(E/J、W、A、S、D、1、2、3、4)
②Ctrl キーと Z キーの代用スイッチ(腱鞘炎防止)
③リニア入力デバイス_ゲームパッドスイッチ
④リニア入力デバイス_ロータリーエンコーダ(拡大率調整)
⑤リニア入力デバイス_スライド抵抗器(拡大率詳細調整)

こんな感じです。割と数は多め。

PCとの接続

接続に求める条件は以下の通り。

①USBでパソコンと接続する
②バッテリとかはつけない(充電とかめんどくさい)

ここで細かく書いてもいいですが、基本的にプログラムをいじればどうとでもなるのでここでは考えないことにします。

短いですが、以上。これを満たすものを作ります。

全体の構成

全体の構成は以下のようになります。

HIDデバイスとしての認識・設定などはArduino Pro Microがすべてやってくれます。

あとはつけたいスイッチの種類(キー、エンコーダ、スライド抵抗器、etc.)に応じたコードを書きこんでいくだけです。

Arduinoにはマウスやキーボードの操作に対応するためのライブラリが用意されているので、複雑なコードは必要ないです。

必要なパーツ

欲しい機能や仕様をだいたい決めたので、次はパーツを購入していきます。

今回はHIDデバイスとして使用することが着る「Arduino Pro Micro」をメインの制御に用います。

その他のキーやスイッチなどはAmazonから格安で購入しました。

マイコンボード

ぶっちゃけこの辺のマイコンはストックしておいても困らないので2個入を購入しました。

単品も売ってますが届くまでに時間かかるね。

なんか昔に比べてだいぶ値上がりしている感があります。

KeyStudioあたりで安いのだしてくれないかな・・・・・

キースイッチ

キーはこちらを選びました。赤軸です。(多分互換品です)

そういえば「赤軸」って商標なんですかね?
結構いろいろなところで使われてますけど単に押し心地の分類みたいな使われ方をしている気がします。。。

キーキャップ

キーキャップです。

クソ安いですがつくりはしっかりしてました。(バリとかはナシ。ベタベタしていたりとかもない。)

ジョイスティック

ゲームパッドなどについているジョイススティックと同じものです。

激安中華パーツの部類のなので耐久性はどうかわかりませんが、今んとこ大丈夫。

ロータリーエンコーダ

最後にロータリーエンコーダです。

回転数の制限がなく、いつまでもコリコリ回せる音量調節とかのやつです。

マウスホイール操作を行うために使います。

回路図

早速回路図を描いていきます。(再掲です。)

今回は簡素なので実体配線図で十分です。

以下のような感じ。

かなりシンプルです。

スイッチ類のはんだ付けを行う

次にスイッチにはんだ付けを行っていきます。

今回は数が少ないので直接線をはやして接続します。

Arduino Pro Microに直付けするのは嫌だったので、小さい基盤を用意して接続しました。

組み立てテストを行う

ハードがないとプログラムもどうしようもないので、まずは組み立てていきます。

まずは適当に配置を確かめるために、3Dプリンターで筐体を印刷しました。

粗目の設定で筐体を印刷

印刷した筐体は以下のような感じです。

う~ん。
テスト(のちに捨てる)ので超絶適当な設定(レイヤー高さ0.5、サポート材なし)でやったんですが、いくら高品質なプリンタといえど無理がありますね、、、

ていうかフィラメントの押出径が0.4mmなのになんで0.5mmで積層できたんだ?

まぁ、これは後で捨ててしまうのでひとまず良しとします。

部品を取り付けて何となくイメージをつかむ

先ほどはんだ付けしたスイッチなど、おおよその部品を取り付けてみました。

見た目は微妙ですが、大体の完成予想はできそうです。

割と適当でもいいかと思ったんですけど、結構使いにくさが際立ちました。

ちゃんと考えないとゴミを作ってしまいそう。

プログラムを作成する

適当にキースイッチ、ロータリーエンコーダ、ジョイスティックの設定を行っていきます。

プログラムを以下に示します。

#include <Mouse.h>
#include <Keyboard.h>

//エンコーダ設定
const int Encoder_phase_A=2;
const int Encoder_phase_B=3;

volatile int Encoder_pos = 0;               //何も操作しなかったとき(エンコーダを操作しなかったとき)にコンパイラに消されることを防ぐ
volatile uint8_t AB_prev = 0;
static int count_now=0;                      //スクロールの一度の操作量を制限

//Joystick設定
const int Joystick_switch = 9;
const int Joystick_x_Axis = A1;
const int Joystick_y_Axis = A0;

int range = 25;                   //XY軸動作範囲
int center = range / 2;           //Joystick中心位置
int threshold = range / 4;        //Joystickデッドゾーン


//Arduino入力ピン割り当て
const int Key1_input = 4;

const int Key2_input = 5;
const int Key3_input = 6;
const int Key4_input = 7;

const int Key5_input = 10;
const int Key6_input = 16;
const int Key7_input = 14;
const int Key8_input = 15;


//入力ピン-入力文字割り当て
const char Key1='w';

const char Key2='a';
const char Key3='s';
const char Key4='d';

const char Key5='1';
const char Key6='2';
const char Key7='3';
const char Key8='4';


//

#define Key1_Joystick_switch KEY_LEFT_CTRL      //ショートカット用:2つ入力
const char Key2_Joystick_switch = 'z';

//プロトタイプ宣言
void Encoder();
void readAxis();

void setup() {
  //エンコーダ信号入力:A/B
  pinMode(Encoder_phase_A,INPUT_PULLUP);                //プルアップ抵抗を有効化
  pinMode(Encoder_phase_B,INPUT_PULLUP);                //プルアップ抵抗を有効化

  //Joystick信号入力:X/Y,switch
  pinMode(Joystick_switch, INPUT_PULLUP);
  pinMode(Joystick_x_Axis, INPUT);
  pinMode(Joystick_y_Axis, INPUT);

  //キー入力
  pinMode(Key1_input,INPUT_PULLUP);                //Wキー
  
  pinMode(Key2_input,INPUT_PULLUP);                //Aキー
  pinMode(Key3_input,INPUT_PULLUP);                //Sキー
  pinMode(Key4_input,INPUT_PULLUP);                //Dキー

  pinMode(Key5_input,INPUT_PULLUP);                //1キー
  pinMode(Key6_input,INPUT_PULLUP);               //2キー
  pinMode(Key7_input,INPUT_PULLUP);               //3キー
  pinMode(Key8_input,INPUT_PULLUP);               //4キー
  

  //ロータリーエンコーダ入力
  attachInterrupt(0,Encoder,CHANGE);
  attachInterrupt(1,Encoder,CHANGE);
  
  //その他
  Mouse.begin();
  Keyboard.begin();

  Serial.begin(9600);
}

void loop() {
  //Serial.println(Encoder_pos);

  //*******エンコーダ設定*******
  if(Encoder_pos == 1){
    Mouse.move(0,0,1);
  }else if(Encoder_pos == -1)
  {
    Mouse.move(0,0,-1);
  }
  Encoder_pos=0;


  //*******Joystick設定*******
  if(digitalRead(Joystick_switch) == LOW){
    Keyboard.press(Key1_Joystick_switch);
    Keyboard.press(Key2_Joystick_switch);
  }else if(digitalRead(Joystick_switch) == HIGH){
    Keyboard.release(Key1_Joystick_switch);
    Keyboard.release(Key2_Joystick_switch);
  }

  Mouse.move(readAxis(Joystick_x_Axis), (-1*readAxis(Joystick_y_Axis)),0);


  //*******キー設定*******
  if (digitalRead(Key1_input) == LOW){
    Keyboard.press(Key1);
  }else{
    Keyboard.release(Key1);
  }

    if (digitalRead(Key2_input) == LOW){
    Keyboard.press(Key2);
  }else{
    Keyboard.release(Key2);
  }

    if (digitalRead(Key3_input) == LOW){
    Keyboard.press(Key3);
  }else{
    Keyboard.release(Key3);
  }

    if (digitalRead(Key4_input) == LOW){
    Keyboard.press(Key4);
  }else{
    Keyboard.release(Key4);
  }

    if (digitalRead(Key5_input) == LOW){
    Keyboard.press(Key5);
  }else{
    Keyboard.release(Key5);
  }

    if (digitalRead(Key6_input) == LOW){
    Keyboard.press(Key6);
  }else{
    Keyboard.release(Key6);
  }

    if (digitalRead(Key7_input) == LOW){
    Keyboard.press(Key7);
  }else{
    Keyboard.release(Key7);
  }

    if (digitalRead(Key8_input) == LOW){
    Keyboard.press(Key8);
  }else{
    Keyboard.release(Key8);
  }
}


void Encoder(){
  uint8_t A=digitalRead(2);             //A相の信号を読み取る:読み取り値 0 or 1
  uint8_t B=digitalRead(3);             //B相の信号を読み取る:読み取り値 0 or 1
  

  uint8_t AB = (A << 1) | B;            //A相の読み値を1bit上位に、B相の読み値を下位に配置:2bitの2進数表現
  uint8_t ABAB = (AB_prev << 2) | AB;   //最新の読み値を下位2bitに配置、[4321]の順に配置

  if(ABAB == 0b1101 || ABAB == 0b0100 || ABAB == 0b0010 || ABAB == 0b1011 )   //正回転
  {
    Encoder_pos=1;
  }else if(ABAB == 0b1110 || ABAB == 0b0111 || ABAB == 0b0001 || ABAB == 0b1000 ) //逆回転
  {
    Encoder_pos=-1;
  }

  AB_prev=AB;       //現在のA相とB相の組み合わせ(2進数2bit)を保存しておく
}

int readAxis(int thisAxis){
  int reading = analogRead(thisAxis);            //値を読み出す
  reading = map(reading, 0, 1023, 0, range);     //ADCの値を実際の範囲に変換
  int distance = reading -center;               //正負の値に変換

  if(abs(distance) < threshold){
    distance = 0;                               //閾値以下なら、Joystickは中心位置にあるものとする:誤作動防止のデッドゾーン
  }

  return distance;
}

Mouse.hとKeyboard.hのライブラリは最初から入っていると思っていなかったんですが、いつの間にか標準搭載になってました・・・
(ていうかエディタ自体がCCSみたいな仕様に変更されていてすごく驚きました。。。。)

ライブラリ内の関数の使い方は検索すればだいたい出てくると思います。

いやぁ~、、、、Arduinoめっちゃ便利やな、、、

通信テスト

確認ができたら通信テストを行ってみます。

とりあえず問題はなさそうでした。

ジョイスティック・ロータリーエンコーダ・キースイッチ、三つとも正常でした。

さすがキースイッチ、なんも保護入れてないけど一切チャタリングはないですね。

この辺の技術って普通のスイッチに適用できないんですかね。

(マウスのスイッチとかね。。。。)

ロータリーエンコーダの動作とプログラム内容

今回マウスホイールの動作を左手で実現したかったため、ロータリーエンコーダを使用しています。

ロータリーエンコーダの動作原理、、、というか回転方向の認識の仕方は以下の通り。

プログラムの書き方によっては速度も検知しますが、今回は向きだけで充分。

チャタリング防止・誤検知防止のためにいくつか書き方はあるようですが、この書き方が一番正確なようです。

今回購入したロータリーエンコーダ(Arduinoに使える系のエンコーダ)は指で回してコリコリとした感触が感じられるくらい分解能が低いので、これを一回検知したらマウスホイールを回転させたと認識させることにします。

ホイール操作の誤作動って結構イライラするので、これだけは割り込み処理で実行することにします。

サンプリング速度がクソだと明らかな遅延になる可能性があるのでそこだけ少し心配かな。。。。

ジョイスティックの動作とプログラム内容

ジョイスティックの動作原理は以下のような感じです。

回転タイプの可変抵抗器がx軸とy軸についているだけなので単純です。

Arduinoの5Vを加えると中点から0~5Vの電圧が取り出せます。

これをデジタル値で0~1023の10bitへ変換してくれるので、これをmap関数(Arduino標準搭載)で範囲変更し、Mouse.move関数へ割り当てるだけでOKです。

まぁ、やってなんですが、マウス操作よりもキー入力割り当てた方がいいですね。。。。

すべての準備が終わったので、動作テストを行ってみます。

筐体の作成(再)

中身のハード、プログラムは完成したので、最後に筐体を作り直します。

再設計

先ほどテストパーツを作ってみて感じた不満点・違和感は以下のような感じでした。(再掲)

これを踏まえたうえで形状を変更しました。だいぶ使いやすくなったはず!

筐体完成

最後にテストパーツに組み込んでいた部品を移植しました。

全体として完成図は以下のような感じです。

いや、色。

なんだか色の組み合わせがあべこべすぎて人体標本みたいな感じがします。

せめてプリント用素材の色はもうちょいましなものを選べばよかったですね。

完成図

完成しました。

いやぁ~、、、割と紆余曲折あったんですが、割と上出来だと感じます。

使用感は、極めて普通。

超絶悪くはないし、超絶良いわけでもない。

いわゆる普通のデバイスとして使えます。

個人的に案外こういう並な感想が出た方が息が長い気がします。

部品取りは免れそうだぜ☆!

まとめ

今回は日常的に使うキーボードを自作しました。

購入してもいいですが、飯食ったりポテトチップスを食ったり炭酸飲んだりしながら使いたいのでなるべく安く作ってみました。

無論、実用性はちゃんとあります。

キースイッチなどは全部使っていないので、全体としてかかった費用は2500円くらいになるかと思います。

参考になれば幸いです。

それでは。

興味あったら見てみてね

-何か作った系