ringo9971’s blog

ロボットを作っています. Vimが好きです.

なめらかなライントレースを目指して その1

初めに

反射型フォトインタラプタを8つ使用し,実際の角度と読み取る角度が線形に取れることを目標とします.

フォトインタラプタの性質

フォトインタラプタは赤外線発光素子と受光素子からなり,受光素子が光を受け取ると低い電圧,光を受け取らないと高い電圧を出します.

実際に黒い線を通過させた時の電圧の変化は次のようになります.

f:id:ringo_9971:20190805142848j:plain

真ん中の電圧値が大きくなっているところが黒い線の上を通っている時になります.

本題

今回はフォトインタラプタを8つ使用するのでこれを並べて表示すると次のようになります.

f:id:ringo_9971:20190805143206j:plain

見てわかる通り,フォトインタラプタ一つ一つの個体差があるので,最大の値が異なっています. これではやりづらいので,次のように正規化します

  for(int i = 0; i < FOT_NUM; i++){
    light[i] = map(analogRead(i), minlight[i], maxlight[i], MINLIGHT, MAXLIGHT);
    light[i] = constrain(light[i], MINLIGHT, MAXLIGHT);
  }

このようにすると

f:id:ringo_9971:20190805143644j:plain

のようになり,扱いやすくなります.

まず,最大の電圧値を取ったフォトインタラプタの左右の電圧値の差degを出します. そうすると,今回は次のような波形になりました. この波形は,フォトインタラプタの間隔によっても変化します.

f:id:ringo_9971:20190805144009j:plain

この波形は,多項式関数によく似ているので1/n乗してあげます. ただし,Arduinoはマイナスの値は1/n乗出来ないようなので,絶対値を取ってあげてから1/n乗します.

f:id:ringo_9971:20190805144448j:plain

ここで,直線になってくれれば問題なかったのですが,nを変化させても直線になりませんでした. しかし,真ん中部分の0に落ちている所を除くとcosの波形によく似ているので次のように正規化すると.

// mymap
double mymap(double x, double in_min, double in_max, double out_min, double out_max){
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

// main 
value = mymap(deg, 1, 5.5, -1, 1);
value = constrain(value, -1, 1);

f:id:ringo_9971:20190805145712j:plain

このようにcosのような波形になったので,arccosをとると

f:id:ringo_9971:20190805145757j:plain

こうなります. ここで,頂点より左側と右側でdegがマイナスとプラスで異なっていることを利用すると

f:id:ringo_9971:20190805150052j:plain

一つ直線が出来ました. これを上手に並べることで

f:id:ringo_9971:20190805150141j:plain

のようになり,目標を達成することが出来ました.

おわりに

今回は数式に則って曲線を直線に変形したわけでなく,試行錯誤しながらそれらしくしていったので,フォトインタラプタの間隔が違った時どうなるかわからないなどの課題が残っている