[[2017a/Member]]
#contents

*課題�� [#q952db12]
今回の課題は、光センサを利用して黒い線をたどることでゴールを目指す、ライントレースロボットの制作だった。
詳しくは[[こちらを参照>http://yakushi.shinshu-u.ac.jp/robotics/?2017a%2FMission2]]

私はE地点直進コースを制作した。

*ロボット本体について [#h602091e]
&ref(2017a/Member/Kobakazu/Mission2/IMG_3.jpg,前方);
&ref(2017a/Member/Kobakazu/Mission2/IMG_4.jpg,横);

ライントレースに重要な光センサは、タイヤとセンサの位置が三角形くらいの形になるように設置した。
最初はアームのようなものをつけてもう少し機体の前方に設置したのだが、そうすると光センサとタイヤの位置が離れすぎてしまい、ラインを踏み越えてしまったり、進み足りなかったりしたので非常にプログラムが組みづらかった。
2つのタイヤの間に設置してやってみたこともあるが、そうすると少しの動きでは光センサが反応できず、一旦ラインから外れて白い部分に出てしまうとその場で旋回してしまいコースに戻ることができないということがあった。
よって、タイヤと光センサの位置が三角形くらいの形になるように光センサを設置するのがベストであった。

&ref(2017a/Member/Kobakazu/Mission2/IMG_1.jpg,裏);
&ref(2017a/Member/Kobakazu/Mission2/IMG_2.jpg,キャスター);

また、コースの中の一部に厳しいコーナーがあったのでできるだけ本体の大きさを小さくし、小回りが利くように制作した。
そのためモーター間の距離は最小にし設置し、タイヤもできるだけ小さいものを使うようにした。
後ろにはキャスターをつけることで小回りをきかせ、自由に動くことができるにした。


*プログラムについて [#ie9c12a8]
**マクロ [#u3b2f1f8]
 #define go_forward OnFwd(OUT_AC);//前進
 #define turn_right OnFwd(OUT_A);//右折
 #define turn_left OnFwd(OUT_C);//左折
 #define migisenkai OnFwd(OUT_A); OnRev(OUT_C);//右旋回
 #define hidarisenkai OnFwd(OUT_C); OnRev(OUT_A);//左旋回
 #define power(s) SetPower(OUT_AC,s); //モーターの出力が変更可能
 #define sound1 PlaySound(SOUND_UP);//SOUND_UPを鳴らす
 #define sound2 PlaySound(SOUND_DOWN);Wait(100);//SOUND_DOWNを鳴らし1秒停止
 #define GO(t) OnFwd(OUT_AC); Wait(t); Off(OUT_AC);//時間tだけ前進
必要となる動作を定義した。 それぞれの定義についてはコメント文にて説明したのでそちらを参照してほしい。
 
**サブルーチン [#h31d7a69]
***ライントレース [#he81bb87]
ライントレースは光センサの値で右旋回したり左旋回してコースをたどるようにプログラムした。
詳しい光センサの値はプログラムを見てほしい。 たどるコースによって若干センサの値に違いがあったのでそれぞれに値を決めた。

私はコースの左側をたどるプログラムなので交差点では基本的に左に曲がることになる。よって黒い部分が長く続いている、つまり左旋回の時間が長い場合が交差点に差し掛かったと判断することができる。左旋回の時間の計測にはRCXに付いているタイマを利用した。左旋回の時間をカウントしたFastTimerの値が一定の値以下の時にwhileのループに入るようにし、FastTimerの値が一定値を超えた場合はループからぬけ出すようにしてある。

 sub trace()
 {
     ClearTimer(0);  
 
     while (FastTimer(0)<=30){
         if (SENSOR_1 > 49){//右旋回
             migisenkai; ClearTimer(0);
         } else if (SENSOR_1 > 44){//右折
             turn_right; ClearTimer(0);
         } else if (SENSOR_1 > 42){//前進
             go_forward; ClearTimer(0);
         } else if (SENSOR_1 > 39){//左折
             turn_left; ClearTimer(0);
         } else if (SENSOR_1 > 35){//左旋回
             hidarisenkai;//タイマをリセットせずに左回転のカウント開始
         }
     }
     Off(OUT_AC);
   
 }
 
上のサブルーチンではFastTimerの値が30以上の値になった場合にループを抜け出すようにしてある。主に直角の交差点を判断するときに用いた。


 
 sub trace2()
 {
     ClearTimer(0);  
 
     while (FastTimer(0)<=25){
         if (SENSOR_1 > 49){//右旋回
             migisenkai; ClearTimer(0);
         } else if (SENSOR_1 > 44){//右折
             turn_right; ClearTimer(0);
         } else if (SENSOR_1 > 40){//前進
             go_forward; ClearTimer(0);
         } else if (SENSOR_1 > 36){//左折
             turn_left; ClearTimer(0);
         } else if (SENSOR_1 > 33){//左旋回
             hidarisenkai;//タイマをリセットせずに左旋回のカウント開始
         }
     }
     Off(OUT_AC);
 }
 
上のサブルーチンではFastTimerの値が25以上の値になった時にループを抜け出すようになっている。これは主にQ,R,S,Pの円の交差点を判断するときに用いた。円形の部分の判断では直角の時ほど黒の時間が続かないので、ひとつ目のtrace()の時間では反応せずにスルーしてしまうことがあった。その改善のためにFastTimerの時間を誤反応しない程度ですこし短く設定し、交差点の判断をしやすくした。


 
 sub trace3()
 {
     ClearTimer(0);  
     ClearTimer(1);
 
     while ((FastTimer(0)<=30) || (FastTimer(1)<=1500)){//論理和を用いている!
         if (SENSOR_1 > 49){//右旋回
             migisenkai;ClearTimer(0);
         } else if (SENSOR_1 > 46){//右折
             turn_right;ClearTimer(0);
         } else if (SENSOR_1 > 40){//前進
             go_forward;ClearTimer(0);
         } else if (SENSOR_1 > 35){//左折
             turn_left;ClearTimer(0);
         } else if (SENSOR_1 > 33){//左旋回
             hidarisenkai;//タイマをリセットせずに左旋回のカウント開始
         }
     }
     Off(OUT_AC);
  }
 
上のサブルーチンは上の2つのサブルーチンとは違いタイマを2つ用いて、2つのタイマを利用した条件の論理和を用いている。一つ目のタイマFastTimer(0)は上の2つサブルーチンの時と同様に左旋回をする時間をカウントし、2つ目のタイマFastTimer(1)はこのサブルーチンが呼びだされた瞬間からカウントを始めるようになっている。ループに入る条件はFastTimer(0)の値が30以下またはFastTimer(1)の値が1500以下の場合である。
反対にループを抜け出す条件はFastTimer(0)の値が30より大きくなる時、且つ、FastTimer(1)の値が1500を超える場合である。

このサブルーチンは急なカーブがあるG-Hの区間で用いた。FastTimer(0)<=30だけの条件では急カーブの途中で黒い部分が連続して続き、交差点だと誤った反応をしてしまった。それを改善するために試行錯誤したが、たどり着いた答えは急カーブをすぎるまでには反応させないということだった。急カーブを通り過ぎるまでは15秒程かかるので15秒間だけはFastTimer(0)の値が30を超えてしまったとしても交差点だと認識しないようにするために論理和を使った。15秒が過ぎればFastTimer(0)の値が30以上になったら交差点だと認識するようになる。
これにより急カーブを交差点だと認識することなく曲がりきることができるようになった。
このサブルーチンは急なカーブがあるG-Hの区間で用いた。FastTimer(0)<=30だけの条件では急カーブの途中で黒い部分が連続して続き、交差点だと誤った反応をしてしまった。それを改善するために試行錯誤したが、たどり着いた答えは急カーブをすぎるまでには反応させないということだった。急カーブを通り過ぎるまでは15秒程かかるので15秒間だけはFastTimer(0)の値が30を超えてしまったとしても交差点だと認識しないようにするために論理和を使った。15秒が過ぎた後、FastTimer(0)の値が30以上を超えたら、交差点であると認識するようになる。
これにより困難であった急カーブを交差点だと認識することなく曲がりきることができるようになった。

***交差点での動作 [#zbe48e8d]

 sub hidari1()
 {
     sound1;
     go_forward;
     Wait(20);
     hidarisenkai;
     Wait(40);
     turn_left;
     Wait(30);
 }
 
 sub hidari2()
 {
     sound2;
     go_forward;
     Wait(20);
     hidarisenkai;
     Wait(40);
     turn_left;
     Wait(30);
 }
 
上のサブルーチンは左方向に進むときに用いた。hidari1()はSOUND_UPを鳴らす必要があるF,S(一回目),G,H,P
で用い、hidari2()はSOUND_DOWNを鳴らして一秒停止する必要があるQ,R(二回目),Eで利用した。
前進、左旋回、左回転を組み合わせることによって曲がってから次のトレースがしやすようにラインの縁に乗るようにした。

 sub tyokushin()
 {
     sound2;
     turn_right;//左に傾いた分を右に向かせる
     Wait(30);
     go_forward;//前進
     Wait(40);
 }
 
上のサブルーチンはT地点で直進するために利用した。

 sub RS()
 {
     sound1;
     turn_right;//停止した時は左を向いているので右回転するとちょうどラインの縁に乗せることができる
     Wait(70);
  }
 
上のサブルーチンはR(一回目)、S(二回目)の地点で直進するために利用した。

 sub Goal()
 { 
     sound2;
     turn_right;//左に傾いた分を右に向かせる
     Wait(30);
     GO(150);
 }
 
上のサブルーチンは最後にゴールの枠に侵入するために利用した。

**タスクメイン [#k7588b6b]
 
 task main()
 {
     SetSensor(SENSOR_1, SENSOR_LIGHT);
     power(0);//モーターの出力を調整
 
     GO(100);//スタート枠から前進
 
     trace();//A-F区間
     hidari1();//Fを左折
 
     trace2();//F-Q区間
     hidari2();//Qを左方向
 
     trace2();//Q-R区間
     RS();//Rを直進
    
     trace2();//R-S区間
     hidari1();//Sを左方向
 
     trace();//S-G区間
     hidari1();//Gを左折
 
     trace3();//G-H区間
     hidari1();//Hを左折
 
     trace();//H-T区間
     tyokushin();//Tを直進
 
     trace();//T-T区間
     tyokushin();//Tを直進
 
     trace2();//T-R区間
     hidari2();//Rを左方向
 
     trace2();//R-S区間
     RS();//Sを直進
 
     trace2();//S-P区間
     hidari1();//Pを左方向
 
     trace();//P-E区間
     hidari2();//Eを左折
 
     trace();//E-A区間
     Goal();//ゴール!!
 }

タスクメインの中身、同じ動作をする部分が多かったのでサブルーチン作った。それによってタスクメインの中身を簡潔にすることができた。それぞれの動作についてはコメント文で説明した。

*まとめ [#xb7d541a]
**問題点・良い点 [#d144effe]
交差点での反応が完全ではなく、交差点だと判断できずにスルーしてしまうことがあった。改善方法としてFastTimerの値を小さく設定することにより、判断しやすくしたりしたが、しばしば判断できないことがありそれは改善することができなかった。同じプログラムでやるにもかかわらず、成功したりで失敗してしまったりと安定感にかけた。

モーターのパワーの調整でpower1だと速すぎて交差点が反応できずなかった場合が多かったのでpower0にしたのだが、交差点の判断はしやすくなったがその分動作は遅くなってしまい素早い動作ができずにゴールまでに時間がかかってしまった

前回の課題の問題点であった、タスクメインの中身を簡潔にするというのは今回は、サブルーチンやマクロを有効に使ったので前回よりも簡潔に記述することができたという点は良かった。

**感想 [#ib276b26]
センサの反応によって動作を行うため課題�気茲蠅睚�雑なプログラムを書く必要があった。特に交差点の判断はちょっとした値の違いで、うまく反応してくれないことも多く難しかった。個人的には急カーブを曲がる部分のライントレースのプログラムが良く出来たと思う。前回の課題よりは電圧の低下による出力の変化が起こす影響が少なかったので調整はしやすかったと思う。前回の課題での問題点を意識しながら制作したのでサブルーチンなどを効率的に使ったが、それらを使うことでタスクメインがわかりやすくなり調整もしやすくなるという利点を実感できた。次回の課題では、今までの反省点とよく出来た点を活かしながら制作したい。

トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS