キーボード制作
1. はじめに
このページは基本的に制作を進めるうえで必要な情報やアイデアを忘れないようにするためのページです.
1.1 なんでキーボード?
もともと何か作りたいなと思っていたときに天下一キーボードワイワイ会を知り、興味を持ったのが始まり(のはず)。ちょうどそのときRaspberry Pi pico wを研究で使っていたり片手デバイスが欲しいと思っていたので始めた。
1.2 設計の目標とその優先順位
やりたいことが曖昧だと進捗が悪化するのは卒業研究でよく分かったので、設計目標とその優先順位をまとめる。
- 片手でほぼ全ての文字を打てるようにする
・同時押しは最大で2キー - 無線通信を行う
- 小型化を目指す
・キー点数を減らす
・キー以外の要素で補う(ジョイスティックなど) - 日本語入力に対応する
1.2.1 片手で全ての文字を。
もともと左手デバイス(左利きなので右手デバイスか。)が欲しいとは思っていたが、そのうち片手でキー入力、もう片方の手でマウス操作がしたいな思うになった。ので片手で文字入力を完結させるキーボードを制作したい。
ただ同時に押すキー数が増えるとストレスなので、最大で2キーまでにしたい。
1.2.2 無線通信に対応
毎回線を繋ぐのは面倒なので、無線通信に対応したい。あと線は邪魔。
1.2.3 小型化を目指す
片手で扱うには小さい方が都合がいいので、小型化もやりたい。そのためにキー数を減らすことと、他の電子部品を用いることで省スペース化(ジョイスティックで十字キー入力など)を目指す。
1.2.4 日本語入力に対応
日本語入力の時に毎回アルファベットを打つと時間がかかるので、日本語入力の時は日本語を直接入力出来るようにしたい。
ということで、これに沿ってキーボードを開発します。
1.3 開発のフロー
開発は以下の手順で進める。注意事項として、複数の構成要素(プログラム、回路設計、3DCAD)を扱う場合は、より複雑な要素から取り組むべきだという点。そうしないと後から変更がいっぱい出てきてやり直しになるので。
◉環境構築
⚫︎c言語をマイコンに書き込むための環境構築(Lチカ含む)
⚫︎bluetooth(ble)を扱えるようにする
⚫︎hid(Human Interface Devise)を扱えるようにする
◉プログラムの制作
⚫︎ble hid入力に対応
⚫︎キー入力をパソコンに出力
⚫︎キーマトリクスに出力を対応
⚫︎制御文字(ctrl、shiftなど)にも対応
⚫︎レイヤー分けに対応(補助デバイスとメインデバイスの切り替え)
◉基板の設計・制作
⚫︎基盤制作機で加工する基板の制作
⚫︎問題点の精査
⚫︎外注用基板の設計&外注
◉筐体の設計・制作
⚫︎Fusion360で設計&3Dプリンタで制作
⚫︎粉末焼結製or木製への変更
2. 環境構築
2.1 c言語をマイコンに書き込むための環境構築
まずC言語をRaspberry Pi Pico(Wも同様)に書き込むにはコンパイル環境をローカルPCで構築する必要がある。細かいやり方は下記参考文献を参照。正直公式サイトは無知の人間からしたら心が折れた。のでYouTubeの動画を参考にした。YouTubeの解説動画はある程度頼るべきだと感じた。
LチカはRaspberry Pi ProjectからNewC/C++ Projectを選択し、Pico wireless optionsからPico W onboard LEDにチェックを入れることで自動で生成される。これをCompileしuf2ファイルをRaspberry pi picoに保存することでプログラムを実行することが出来る。
C言語を使う理由は、もともとCircuitPythonとMicroPythonを試したが、CircuitPythonはBlueToothに非対応でMicroPythonはHID機能が提供されていなかったからである。非常に残念だ。
またC言語をマイコンで動かすために必要な最低限の知識を下記にまとめる。
・cmake:C言語をコンパイルする環境を自動で整えてくれるスーパーツール
・コンパイルとは : プログラム言語を機械言語に直す(.c, .cppを.o, .objファイルに変換する)
・ビルドとは : コンパイルしてさらにバイナリ化することで実行できるようにする一連の過程。
・つまりビルド>コンパイル
・デバッグとは : エラーを探す過程
・SDKとは : 製品を動かす際に必要なプログラムをまとめてくれたライブラリ(≒API)
やっていること(中身)が比較的オープン。プログラムを丸ごと享受できる。
・APIとは : 製品を動かす際に必要な機能を公開してくれるサービス
やっていること(中身)が不明。サービスのみを享受できる。
参考文献:https://www.youtube.com/watch?v=722gfJmlkS8 (特に9章参照)
2.2 bluetooth(ble)
2.1章の動画内でBlueToothの導入もされている。これについて簡単にまとめる。
まずRaspberry Pi Pico用のSDKにはBlueToothが入っていない。そのため別でGitHubから必要なライブラリを取得する。今回は以下のGitHubを使用した。なんとありがたいことに、ここにはBlueToothだけでなくHIDのためのソースコードも含まれている。そして問題はこれを使うまでの設定である。
まず重要なのがこのライブラリを、BLEを使用するプロジェクトのフォルダ直下に保存することである。これを間違えると後が面倒になる。2.1章の環境構築に従うと、workspace-pico-ble_projectに保存する。(ble_projectは任意のプロジェクト名)
もう1つ大事なのがcmakelists.txtを変更することである。このファイルにライブラリが増えたことを設定しておかないと、BlueToothもHIDも出来ない。ちなみにcmakelists.txtとは何かというと、C言語をコンパイルするために必要な設定ファイルみたいなものである(現状の理解だと)。
またBLEを行う為のサンプルプログラムもあったので、それを用いてBLEとHIDを試した。
参考文献:https://github.com/bluekitchen/btstack
2.3 hid(Human Interface Devise)に対応
2.2章と同様。
3. プログラムの制作
3.1 ble hid入力に対応
前述の通りサンプルがあるのでこれを使って簡単な入力を試す。まず問題としてこのサンプルにはmain関数がない。のでまずはmain関数を実装する。これも複雑でややこしいので、前述のYouTube動画をもとにコーディングしていく。今回はcherry mx キースイッチを使いたかったので下図のようにジャンパ線でジャンクな接続をした。この動作確認をするためのmain関数を以下に示す。
X
これを実行するとpcに a と入力されるはずである。この時pcがbluetoothを有効にして接続をしないといけない(当たり前だけどたまに忘れる)。
3.2 キーマトリクスに出力を対応
次にこれを扱うキー全てに対応させる。まずそもそもキーマトリクスとはなんぞやという話から。キーマトリクスは下図のように、n+m個のピンでn*m個のキー入力を判別する手法である。なので例えば81キーのキーボードを作りたいとなったら9+9で18ピンだけで足りる。
X
ここで上側のピンが出力、右側のピンが入力に設定しないといけない。ダイオードは逆流防止用であり、抵抗がないのはマイコン側に内部プルアップ(プルダウン)抵抗がついているからである。キーマトリクスの具体的な話は以下参照。
参考サイト:https://geekyfab.com/entry/2020/10/17/201500
特に大事なのは似た機能のキーを同じ行もしくは列にまとめることである。これをしないとプログラムの条件分岐が地獄になってしまう。顕著な例がテンキーである。下図のようにまとめると0から9までの数字を行列成分を用いて2次元成分(i, j)を、5i+jで変換することが出来る。また似たような機能であるshift・ctrl・alt・Windows・Fnもまとめることでプログラムをしやすくしている。
これに基づいてまず、キーのON/OFFを判定するプログラムを追加する。ピンを初期化し、プルダウン抵抗を設定し、出力ピンからfor文で1つずつ出力し、入力ピンから読み取る。毎回各ピンの出力をOFFにすることを忘れずに。
<!-- この定義はmain関数の外 -->
static const uint8_t keytable_us_none [] = {
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 0-3 */
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', /* 4-13 */
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', /* 14-23 */
'u', 'v', 'w', 'x', 'y', 'z', /* 24-29 */
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', /* 30-39 */
CHAR_RETURN, CHAR_ESCAPE, CHAR_BACKSPACE, CHAR_TAB, ' ', /* 40-44 */
'-', '=', '[', ']', '\\', CHAR_ILLEGAL, ';', '\'', 0x60, ',', /* 45-54 */
'.', '/', CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 55-60 */
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 61-64 */
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 65-68 */
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 69-72 */
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 73-76 */
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 77-80 */
CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, CHAR_ILLEGAL, /* 81-84 */
'*', '-', '+', '\n', '1', '2', '3', '4', '5', /* 85-97 */
'6', '7', '8', '9', '0', '.', 0xa7, /* 97-100 */
};
//~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~main関数の中~~~~~~~
// 入力を保存
for(int i=0;i<column_digit;i++){
gpio_put(columns[i], true); //OUTPUTピンの出力を設定
for(int j=0;j<row_digit;j++){
// チャタリング防止のため1周期前の出力を保存
past_button_checker[i][j] = button_checker[i][j];
button_checker[i][j] = gpio_get(rows[j]);
if(button_checker[i][j] != 0 && button_checker[i][j] != past_button_checker[i][j]){
// 文字入力の場合
key_input(keytable_us_none[i][j]);
printf("%d行%d列:%d\n",i, j, button_checker[i][j]);
// 処理が速すぎて検出できないためDelay
sleep_ms(1);
}
gpio_put(columns[i], false); //OUTPUTピンの出力を設定
}
}
あとはONされたスイッチに対応した文字を出力する。
3.3 レイヤー分けに対応
補助デバイスとメインデバイスの切り替えに対応させる。まず補助デバイスとメインデバイスに含める機能をまとめる。メインデバイスには一般的なキーボードで扱える全ての機能を入れたい(Fn周りが厳しい)。補助デバイスはコーディングやイラスト制作の際に必要なショートカットをメインにしたい。現在は最低限メインデバイスで扱えるレベルのレイヤーのみ作成する。
・メイン入力
・CAD用ショートカットまとめ
・
3.4 制御文字にも対応
ctrlや shiftにも対応したい。まずhidデバイスからメインデバイスに送信されるのはuint8_t report[] = { modifier, 0, keycode, 0, 0, 0, 0, 0};
という配列である。そしてkey_input()という関数は、この配列の第2成分に出力する文字を格納して送信する関数である。しかし制御文字(ctrlやshift)は出力する文字がない。ではどうするのかというと、この配列の第0成分を用いる。
uint8_t report[] = { modifier, 0, keycode, 0, 0, 0, 0, 0};
は第0成分がmodifier、第1成分が予約キー(謎)、第2成分から第8成分が出力したい文字に割り当てられている。このうちのmodifierがなんと制御文字に対応している。対応は下の表の通り。よって直接modifierに代入して送信すれば制御文字が実行できる。この関数を下にまとめる。
// ここのModifierを変更することで制御文字に対応
void hid_send_ctrl(uint8_t modifier, char character) {
uint8_t hid_report[HID_REPORT_SIZE] = {0};
// 修飾キーを設定
uint8_t keycode = ascii_to_hid_usage_id(character);
if (keycode == 0 && character != 0) {
printf("Unsupported character: %c\n", character);
return;
}
// 修飾キーを設定
hid_report[0] = modifier;
// キーコードを設定
hid_report[2] = keycode;
// HID レポートを送信
// btstack_hid_device_send_report() はスタックに応じた送信関数を使用
hids_device_send_input_report(con_handle, hid_report, sizeof(hid_report));
}
ただここには大きな落とし穴がある。key_input()関数と送信方式が違うことである。その中でも特に問題なのが文字コードである。key_input()関数がASCIIコードに対応しているのに対して、hids_device_send_input_report()関数はHID Usege IDに対応している。なのでアルファベットや記号文字はHID Usege IDに直さないといけない。ここはchatGPTに関数を作成して頂いた。やってることは条件分岐しているだけである。
uint8_t ascii_to_hid_usage_id(char character) {
// アルファベット(小文字)
if (character >= 'a' && character <= 'z') {
return character - 'a' + 0x04; // 'a' -> 0x04, 'b' -> 0x05, ...
}
// 特殊文字・記号
switch (character) {
case ' ': return 0x2C; // スペース
case '-': return 0x2D; // ハイフン
case '=': return 0x2E; // イコール
case '[': return 0x2F; // 左角括弧
case ']': return 0x30; // 右角括弧
case '\\': return 0x31; // バックスラッシュ
case ';': return 0x33; // セミコロン
case '\'': return 0x34; // アポストロフィ
case '`': return 0x35; // グレーブアクセント
case ',': return 0x36; // カンマ
case '.': return 0x37; // ピリオド
case '/': return 0x38; // スラッシュ
default:
break;
}
}
他にもkey_input()関数はリングバッファに送信するデータを一時保存するためメモリの問題がないのに対して、hids_device_send_input_report()関数はこれが出来ないという違いがある。多分問題はないと思うけど。
もう一つ注意点として、長押しは自分でコーディングしないといけない点がある。これも対応する。といってもやったことは毎回入力を確認するだけ。一応この関数を示す。ctrl_checkerは制御文字が押されていたら0にする。そうでなければ1のままにする。そして1のままの時だけ制御文字が押されていないという状態をPCに送っている。こうしないとチャタリングのような現象が発生した。(そりゃ高速で無限ループしてるんだからね。)
// 制御文字を取得
void ctrl_check(){
// ここは将来的にmainに合併
ctrl_counter = 1;
for(int i=0;i<=4;i++){
if(button_checker[3][i] != 0){
ctrl_checker[i] = true;
hid_send_ctrl(ctrl_raws[i], 0x00);
ctrl_counter = 0;
break;
}else{
ctrl_checker[i] = false;
}
}
if(ctrl_counter != 0){
hid_send_ctrl(0x00, 0x00);
}
if(button_checker[4][0] != 0){
num_checker = true;
printf("num\n");
}else{
num_checker = false;
}
}
3.5 日本語入力にも対応
さてアルファベットを毎回日本語入力の時も押していると、打鍵回数は単純計算で2倍になってしまう。これはユーザビリティが圧倒的に低いので、日本語入力にも対応したい。方法としては以下の二種類があるだろう。
・たとえば「が」と打つ場合、連続で入力する。
key_input('g');
key_input('a');
・入力対応行列を更に多次元にしてuint8_t report[] = { modifier, 0, keycode, 0, 0, 0, 0, 0};
の後ろ側にまとめて代入する。
下の方がスタイリッシュな気がするが、コーディングが面倒なのでよりシンプルな上のやり方を実装する。無理な(遅い)場合は下に切り替える。三次元配列を定義すれば解決!
X
ちなみに例えば「が」と入力するときにkey_input('が');もしくはkey_input(”が”);とすることは出来ない。理由はUnicodeにおいてアルファベットや記号文字がASCII文字であるため1バイトであるのに対し、ひらがなは2バイト以上を要するからである。何故か、それはアルファベットや記号文字は世界中で使われるからデータを軽くしたいからである。ひらがなが2バイト以上を要するのは、Unicodeで扱うときに識別文字(日本語なのか中国語なのかetc)を判別する文字にバイト数を使われるからである。
3.6 言語切り替えに対応する
さてここまで頑張って日本語入力を可能にしたが、最後の問題がある。それは変換、無変換、半角/全角キーに対応していないことである。なぜか、それは対応するキーが分からなかったから。
幸い半角/全角キーはAlt+@(or spaceキー)で出来るのでそれをキーマトリクスに割り当てることでしのぐ。
そして変換キーはspaceキーで代用する。
問題は無変換である。私はこのキーボードのために、Microsoft IMEを有効にする」に割り当てた。そして、これ故にこのキーが押せなければ日本語配列に対応できない。(HIDデバイスがPCの入力状態(日本語か英語か)を認識できないため、接続時にどちらかに初期化する信号を送信しないといけないから。)
なんて色々考えていたが、制御文字に対応しているときにHID Usage IDを知った。そしてこの文字コードには変換、無変換、半角/全角キー(Grave Accent)があった!あとdeleteも。ただGrave Accentは「`」でもある。どうしよ。
IMUを有効にする設定方法:
時刻と言語>言語と地域>オプション>Microsoft IME>キーとタッチのカスタマイズ
3.7 今後やる(今回できなかった)機能
・ジョイスティックに対応:燃え尽きたから
・Fキー、PrtSc、delete、補助デバイス用レイヤーに非対応:そもそもあまり使わないし、このキーボードだと使う気にならないから
👉必要になったら今後やるかも?
・iPadに対応する:2つ以上のデバイスを接続することはできないので毎回BlueTooth設定から切断し ないといけない。ダルイ
👉マイコンをPICかAVRにしてBlueToothモジュールを接続する設計にしたい。
3.8 実際に使ってみての感想
まずバッテリーをつけないとどうにもならない。昇圧コンバータかコイン電池を採用する必要あり。
そして操作性がカスである。自明である。
具体的には以下の3つが挙げられる。
・キーとの対応が非常に分かり辛い
・日本語英語入力が自動で切り替わったとき、キーボードはそれを認識しない☞入力と出力で日本語と英語が混ざる。これは非常にまずい。
・制御文字がいろいろややこしい。(日本語と英語で場所が違う:設計ミス?、変換の場所が分からん、Tabが2個ない?)
・小さい文字(っ、ゃなど)を打つのが非常に面倒。あと「ー」どこ?
4. 基板の設計・制作
4.1 基板の制作
まず必要な機能をまとめる。
・無線接続時の電源ON/OFF
・無線接続時はリポバッテリーで(電力足りる?)
・キースイッチ×20
・3ポジションスイッチ×1
・使用するマイコンはRaspberry Pi Pico W(WHとの違いはピンヘッダーがついているか否か)
・余裕があればいくつかのキーをジョイスティックで置き換える(いったん無視)
・キースイッチには整流ダイオードが必須(最低5個)
・プルダウン抵抗はRaspberry Pi Pico内部にあるのでなくていいはず
これを基に必要な部品を選定した。以下の表に使用する部品をまとめる。また3章のプログラムおよび上記の部品を考慮したうえで回路図とPCB基板レイアウトを制作した。下図に回路図とレイアウトを示す。
品名 | 個数 | 型番(品番) |
---|---|---|
キースイッチ | 20 | Cherry MX X |
ロッカースイッチ | 1 | X |
キーキャップ | 20 | Happy BallHappy Balls |
ピンソケット01x20 | 2 | ー |
マイコンボード | 1 | Raspberry Pi Pico W |
XHコネクタ | 1 | ー |
リポバッテリー | 1 | LP653042-PCM-LD/3.7V 820mAh |
4.2 問題点の精査
制作した結果発覚した問題を以下にまとめる.
・Raspi picoのピンソケットが左右逆向きで配置されていた
☞9のキーとUSBが被る。
そのくらい確認しろ馬鹿垂れ。一瞬の作業を面倒がるな。失敗した時の方が圧倒的に面倒や。学べ。
・ロッカースイッチのフットプリント割り当てが違う
☞ 何となくで進めた結果。上の回路図およびレイアウト図では改善済み
・SW22とSW24が逆
まああるあるでしょう。
・SW18が導通せず
なんで?
・思ったよりでかい
☞Enterが遠くて押しづらい
☞配置も変更して104 * 117mmに縮小
☞100 * 100mmを超えると発注費用が爆上がるので、100 * 100mmに抑えた
But マウンティングホールの位置がえぐい
・十字キーはマウスで代用できるので不要
☞Windowsキーなどに追加で対応
4.3 外注用基板の設計&外注
上記の通り1通り問題点を解消したので外注に入る。ここで大きな問題が、基板サイズが100mm * 100mmを超えると発注費用が非常にかさむ点。これを解消するために無理やり100mm * 100mmピッタリに抑えた。また降圧コンバータの必要性は不明なので、回路上で降圧コンバータを取り付ける場所を用意し、もし必要であればそれをはんだ付け、不要であれば何もしないことにする。
4.4 完成した基板
筐体の設計製作
筐体の設計のやり方を手探りでやっていたところこんな参考文献が。
これに従ってできた筐体を下図に示す。いつか。
DEVELOP LOG
2025/06
・去年まで使ってたPC(Windows11 23H2)では正常に動いた!
・今年買い替えたPC(Windows11 24H2)では無反応...
What?(BlueToothドライバーのバージョン違いが原因説が濃厚)
👉新しいパソコンでデバッグ作業をする必要がある=環境構築やり直し!
電源周りに納得がいかないので変更したい
・コイン電池は3.3V出力可能なのでコネクタにコイン電池を繋ぐ。(一番簡単)
・昇圧コンバータを使えば単三電池1本で動作可能。(構成がシンプル)
・BlueTooth SoCを使えばよりシンプルに。(マイコン制御から変更が必要だが小型化可能)
2025/05
・大学生活が落ち着いた&貸してたケーブルが返ってきた
・改良した基板の動作確認完了
2025/03
👉改良してJLCPCBに再発注(初回ということもあり,送料込みで600¥くらい)
2025/02
・到着
👉・バッテリーと電源スイッチの配線が逆
・Raspberry pi pico w用ピンソケットの幅が合わず
2025/01
・小型化してFusionPCBに発注(送料込みで3000¥くらい)
2024/12
・基板がでかいため発注費用が4000¥くらいかかる(JLCPCBの場合)
👉小型化して500¥程度に抑える(JLCPCBの場合)
・制御文字の同時押しが出来ない
👉こっちはASCIIコードをHID Usage IDに変換しないといけなくなった
👉key_inputでは限界なので別の関数を作成
👉key_input()関数を修正すべき?
・キーの場所が合ってない&導通してないキーあり
・基板設計、印刷、動作確認
・キーマトリクスに対応
2024/11
・c言語の環境構築とble, hidの実装
・circuitpythonにble機能はない
👉c言語に
・micropythonにhid機能はない
👉circuitpythonに
2024/10
構想を練る
・片手で全キー網羅
・無線
プログラムを作り始める(micropython)
雑談・余談・メモ
結局環境構築が1番クレイジー
たまに接続が不安定
複雑になってDelayしないかだけ心配
今のうちにコードをきれいにしておかないと次やるときに地獄を見るぞ。
環境依存性について
あたらしいパソコンだと正しく動かない原因について、色々調べたところBlueTooth接続をいろいろいじっていたら解決した。どれが改善した要因か不明なので以下に試したことをまとめる。
・デバイスマネージャーからこのキーボードデバイスを消去 (リセットできた?)
・BlueToothの「その他の設定」から受信ポートの作成
☞受信ポートを消しても正常に動作するのでこれではなさそう
・なぜかBlueTooth接続されていた「Pico」なるデバイスを消去(これかな?)
日本語入力時に欲しい記号文字
・通常時(なるべく固める)
、。・「」:+-¥@^
・Shift時(左から順に0~9に割り当て)
!?=()~%&<>#{}$
日本語入力時に欲しいショートカット(Ctrl+~)
'd', 'a', 'c', 'v', 's', 'y', 'z', 'x', 'f', 'h'
PrtSc(Windows + ~)
リポバッテリーの発火リスクについて。今回はターミナルブロックにリポバッテリーを接続する予定だったが、発火の恐れがあるので対処に困っている。
反省
目標は具体的に。
・数値目標や明確なゴールを持つべき
・より定量的に。
ちょっとの時間を使って確認をしなさい。
・事の始まり:回路図の確認を怠る ☞ マイコンのソケットが逆向きで配置 ☞ 9のキーが邪魔でマイコンにUSBケーブルを挿せない。
・ミスってた時の方がめんどいでしょうが。
・はんだ付けなんて尚のこと。
大きくプログラムを変更するときは別ファイルにデータのバックアップを置いておく
・途中からやりだした。
・いつも元に戻れなくなっていたので改善されたね!やったね! ####
chatGPTに聞く時は解決したら別のディレクトリで作業しよう
・質問を内容ごとに分けると引用しやすい
・後々参考サイトとして探しやすい