VR空間移動用いす型デバイスを作成する⑤いすの回転を光センサで読み取ってみる

続けて椅子の回転を読み取ってみます。

#目次
１．エンコーダと回転検知について
２．歯車を作ってみる
３．センサ部分を組み立てる
４．ArduinoUNOのプログラム

#１．エンコーダと回転検知について
回転を検知するには、エンコーダというものが使われます。世の中にあるのは小型になっているので同じサイズは難しいのですが、大きくても良ければ自作できます。
エンコーダは歯車の歯を検知することにより、歯車が回転したかを検出します
さらにセンサを二つ使用する（他にもいろいろやり方あります）と回転の方向までわかります。

通常のエンコーダは歯車が回転し、歯をセンサや電気的接触等で検知しますが、今回はセンサが回転し、歯車は固定となります。いすは上部の座る部分が回転しますが、こちらにArduinoはじめ回路部分が存在するため、センサもこっち側になりました。
<img width=75% src=https://qiita-image-store.s3.amazonaws.com/0/184089/c15d4630-ac82-ba17-90ff-0b132a11850e.png>
センサには反射型の光センサを使用しています。秋月電子で売ってる「反射型フォトインタラプタ GP2A200LCS」というやつです。
近赤外線の光を照射し、物がる場合、反射してきた光を検知するというセンサです。
<img width=50% src=https://qiita-image-store.s3.amazonaws.com/0/184089/28396747-30c4-5945-eb15-766e61753e66.png>
センサを二つ使うと、センサのON・OFFする順番が歯車の右回りと左回りで異なりますので、回転方向もわかります。
<img width=75% src=https://qiita-image-store.s3.amazonaws.com/0/184089/9ae764ff-4056-9f70-f6b2-6437b83307f3.png>

#２.歯車を作ってみる
歯車を作ります。
<img width=25% src=https://qiita-image-store.s3.amazonaws.com/0/184089/adcc7764-d75b-2349-6cbf-1a3b6c8747c2.png>
歯の数は18です。とりあえず勘で歯の数は決めてます。歯の数が多くなるほど細かく角度を検知できまが、歯車のサイズは大きくなるでしょう。作った歯車の直径240㎜です、反射型光センサの横幅が二つで18㎜あるので、歯の横幅および歯のない部分の幅も18㎜なるようにしました（狭すぎるとセンサが二つともにOFFまたはONにならない。）。
歯車はカラーボードで作成しました。100均で売っています。カッターで加工できるので便利です。
<img width=75% src=https://qiita-image-store.s3.amazonaws.com/0/184089/00a25fd5-597c-9e07-9392-7482d0e67927.png>
ネット上にある分度器の絵を当該サイズに拡大して裏面になる側に貼っておくとうまく切れます。色は黒だと赤外線が反射しにくいため検知距離が短い、白だと逆に反射しすぎるてチャタリングが発生するので青にしました（本当は灰色が良かったのだが、売ってなかった。）。青でも少しチャタリングするのですが・・・。
これをいすに取り付けます。適当なものが見当たらなかったので、サドルバンド（塩ビ管の固定に使うやつね）を使った。内径が合わないので、内側にゴム巻いてサイズを合わせた。
<img width=30% src=https://qiita-image-store.s3.amazonaws.com/0/184089/e7683214-e9d0-be99-3bf4-3b435b5f4151.png>
いすの座面を外した後、上に歯車をつけられるようにL字の金具をはめて閉めています。反対側についているのはUSBケーブルを通すための冶具です（。USBケーブルはそのまま下に垂らすと歯車やセンサに絡まる可能性があるからです。3Dプリンターで作りました。
<img width=75% src=https://qiita-image-store.s3.amazonaws.com/0/184089/3c873941-7296-e378-0099-d66c5509a03b.png>
なお、USBケーブルを使用している理由は展示会等に出展するためです。展示会のような人の多い会場では電波が汚染されており、無線通信の使用はむずかしいです。もし、個人で使う場合ならBluetooth等を使用したほうが楽でしょう（この冶具だけで1800円・・・）。
<img width=50% src=https://qiita-image-store.s3.amazonaws.com/0/184089/4f021ae8-e5d8-d81c-d268-a5302243cb4f.png>

#３．センサ部分を組み立てる
センサ側を組みましょう。
<img width=50% src=https://qiita-image-store.s3.amazonaws.com/0/184089/70f3296d-d76a-cf33-9edd-f105ddb3fc6d.png>
同じように軸の回転する側にサドルバンドや金具をつけます。先端のセンサを取り付ける部分は３Dプリンタで作っています。センサの裏に凸部と先端に丸穴があるのでうまくはまるようにしています。できたものが思ってたより肉薄かったので裏をパテで補強しています。
<img width=75% src=https://qiita-image-store.s3.amazonaws.com/0/184089/7db77dde-21a0-810c-f574-e79d6d1efddf.png>
歯車とセンサの距離は（自分が座って、少し沈み込んだ状態で）1㎝程度としました。重い人が乗るとさらに沈み込んで、歯車とセンサが接触する可能性があります。余裕を見ておいたほうが良いでしょう、一方で、遠すぎると赤外光が距離の分だけ広がりますので、センサの検知範囲が広くなります。凹部を検知しにくくなります。
以下のような回路でセンサの出力をArduinoにつなぎます。
<img width=100% src=https://qiita-image-store.s3.amazonaws.com/0/184089/a7bfe5d6-6e5b-e297-5a87-3b40c32084ec.png>
センサの出力にLEDをつけているのは目視でセンサのON/OFFを確認するためです。なお、出力をいったんコンパレータで整形してArduinoに送付しています。おそらくこのコンパレータは不要と思うのですが、センサからArduinoまでの距離が長いので、波形がなまっていないか不安で入れました。オシロスコープとかあれば波形を確認できるのですが・・・。
また、TLP222Aはフォトモス（無接点スイッチ）です。このスイッチでセンサの電源をArduino側からON/OFFできます。センサは出力確認時のみ電源をつなぎます。下図のようなセンサ間の干渉を避けるためです。二つのセンサが同時に動作していると、隣のセンサからの赤外光が反射し入ってきてしまいます。
<img width=30% src=https://qiita-image-store.s3.amazonaws.com/0/184089/94ddca4c-6e45-eb36-69c7-a4d5e786e0fc.png>
フォトモス使った理由は安いからです。リレーとかでも問題ありません。
実際の回路とか
<img width=40% src=https://qiita-image-store.s3.amazonaws.com/0/184089/2df7bfeb-7a52-f83b-6073-54ff87b531b6.png>

#4．ArduinoUNOのプログラム
Arduno側のプログラムを組みPCに角度っを表示してみましょう。

```arduino:interrupter.ino
#define	VddClock		7
#define	VddAntiC		8
#define	Clockwise		12
#define	Anticlockwise	13
int pdClock,pdAntiC,pdStatus,prePdStatus,transStatus,angle;

void setup() {
	pinMode(VddClock,OUTPUT);
	pinMode(VddAntiC,OUTPUT);
	Serial.begin(9600);
	GetInterrupterStatus();
}
void loop() {
	GetInterrupterStatus();
	if(transStatus==0) angle=angle;
	else angle=angle+transStatus;
	if(angle<0) angle=355;
	if(angle>355) angle=0;
	Serial.print(" angle ");
	Serial.println(angle);
}
void GetInterrupterStatus(){
	//pdStatus=12output+13output 00=0 01=1 11=2 10=3
	//transStatus 0->1=5 1->2=5 2->3=5 3->0=5 0->3=-5 3->2=-5 2->1=-5 1->0=-5
	digitalWrite(VddClock,LOW);		//Vdd ON
	digitalWrite(VddAntiC,HIGH);	//Vdd OFF
	delayMicroseconds(3500);
	pdClock = digitalRead(Clockwise);
	digitalWrite(VddClock,HIGH);	//Vdd ON
	digitalWrite(VddAntiC,LOW);		//Vdd OFF
	delayMicroseconds(3500);
	pdAntiC = digitalRead(Anticlockwise);
	digitalWrite(VddClock,HIGH);	//Vdd OFF
	digitalWrite(VddAntiC,HIGH);	//Vdd OFF
	
	if(pdClock==0){
		if(pdAntiC==0) pdStatus=0;
		else pdStatus=1;
	}
	else{
		if(pdAntiC==0) pdStatus=3;
		else pdStatus=2;    
	}
	transStatus=5*(prePdStatus-pdStatus);
	if(transStatus==15||transStatus==-15) transStatus=-1*transStatus/3;
	prePdStatus=pdStatus;
}'
```
Arduinoのツール→シリアルモニタを起動し結果を見てみます。
いすを回転させると角度が変化するのがわかります。
<img width=50% src=https://qiita-image-store.s3.amazonaws.com/0/184089/72f2c983-bcba-0562-6471-c465d601b3a5.png>

ちょっと解説です。
<font color="DeepSkyBlue">ⅰ．Arduinoのプログラムについて</font>
・ GetInterrupterStatus()　以下
干渉を避けるためセンサは片側ずつ電源ONにします。TLP222AのターンON時間が最大2ms、センサの応答時間が最大1msでした。500us余裕を見て、3500us後にセンサの出力を確認しています。
Arduinoの13pinにつながっているセンサと12pinにつながっているセンサについて、各センサの出力が0（凸部）、1（凹部）かにより、下表のように状態を0~3に振り分けています。これで状態が一つ増えるごと（3から0をのぞく）に右回り５度増加、一つ減るごと（0から3をのぞく）に右回り5度減少となります。

| センサ_12pin | センサ_13pin | 状態 |
|:-----------:|:------------:|:----:|
|0            |0             |0     |
|0            |1             |1     |
|1            |1             |2     |
|1            |0             |3     |
<img width=30% src=https://qiita-image-store.s3.amazonaws.com/0/184089/b05745ab-2ad1-fa58-ee11-e14ae76b7458.png>
10度刻みで凹凸が入っているため、どちらかのセンサの値が変化すると5度の変化です。状態の差分に5をかけます。その後、3からまたは3に変化した場合には変化量が15度になってしまいますので、15の場合は-5にもどしています。
・void loop() のなか
変化量を角度に加算しています。なお、360度になる場合は0度、-5度になる場合には355度に変更します。

<font color="DeepSkyBlue">ⅱ．結果について</font>
Arduinoに電源投入した位置が原点（0度）です。
右に回してみました。５度ずつ値が大きくなっていくのがわかります。

以上になります。
UnityとかのPCとのデータの受け渡しをどうするのかについては、ネット上にいろいろあるので説明しないです。
次は少し振動モーターの話をしてみたい。