紙に黒のサインペンで書かれたコースを光センサーを使って感知するロボットを作り、コースを2周するプログラムを作成すること。
コースの規定
プログラムの条件
青山伊吹
山崎雄生
最初はロボの先端にキャスターがついていたが、取り付けた角度が地面に垂直じゃなかった結果コーナーを曲がるときなどの突っかかってしまって、ロボの行進を妨げていたので取り外しました。結局2つのタイヤともともとキャスターがついていた部分のパーツで車体を支える感じになりました。
申し訳程度に回転センサーをつけましたが、結局使用しませんでした。光センサーは一応位置が調整できて、プログラミングの際に線の両外側を感知するタイプと線と紙との境界を感知するのと、どちらもできるようになってます。
欠点はなんといっても、ギア比が低いことと2つのタイヤの間隔が広いこと。おかげで通常のライントレースのプログラムでは直角を曲がることができずに、別のプログラムが必要になってしまいました。後になって思えば、プログラムをいちいちいじるよりもロボットを性能の高いものに作り替える方が圧倒的に早かった。
#define THRESHOLD 50 #define turn_left OnFwd(OUT_C);OnRev(OUT_A);Wait(10);Off(OUT_A+OUT_C); #define RUN_TIME 75 #define RUN_TIME2 105 #define RUN_TIME3 250 #define RUN_TIME4 290 #define RUN_TIME5 320 int cross; sub line_trace() //サブルーチンでライントレースを定義 {if((SENSOR_3>THRESHOLD)&&(SENSOR_1>THRESHOLD)) //白白のときは直進 {OnFwd(OUT_A+OUT_C); }if((SENSOR_3<THRESHOLD)&&(SENSOR_1>THRESHOLD)) //コースをそれそうになったら進路を戻す {OnFwd(OUT_A);OnRev(OUT_C); }if((SENSOR_3>THRESHOLD)&&(SENSOR_1<THRESHOLD)) //上と同じ {OnFwd(OUT_C);OnRev(OUT_A); }if((SENSOR_3<THRESHOLD)&&(SENSOR_1<THRESHOLD)) //交差点は直進 {OnFwd(OUT_A+OUT_C); }} sub acsel_turn() {if (SENSOR_1<THRESHOLD) //サブルーチンで直角ターンを定義 {turn_left; OnFwd(OUT_A+OUT_C);Wait(1); Off(OUT_A+OUT_C); }else {OnFwd(OUT_A+OUT_C);Wait(1); Off(OUT_A+OUT_C); }} task main() {SetSensor(SENSOR_1,SENSOR_LIGHT); SetSensor(SENSOR_3,SENSOR_LIGHT); ClearTimer(0); //タイマー0をリセットする cross=1; //変数の値を定義する while(Timer(0)<RUN_TIME) //時間になるまでライントレースする {line_trace(); } Off(OUT_A+OUT_C); while(Timer(0)<RUN_TIME2) //時間になるまで直角ターンする {acsel_turn(); } Off(OUT_A+OUT_C); while(Timer(0)<RUN_TIME3) //時間になるまでライントレースする {line_trace(); } Off(OUT_A+OUT_C); while(Timer(0)<RUN_TIME4) //時間になるまで直角ターンする {acsel_turn(); } Off(OUT_A+OUT_C); while(cross<=6) //変数の値が6になるまで繰り返す {if((SENSOR_3>THRESHOLD)&&(SENSOR_1>THRESHOLD)) {OnFwd(OUT_A+OUT_C); }if((SENSOR_3<THRESHOLD)&&(SENSOR_1>THRESHOLD)) {OnFwd(OUT_A);OnRev(OUT_C); }if((SENSOR_3>THRESHOLD)&&(SENSOR_1<THRESHOLD)) {OnFwd(OUT_C);OnRev(OUT_A); }if((SENSOR_3<THRESHOLD)&&(SENSOR_1<THRESHOLD)) //交差点、ゴールラインを感知したら変数に1足す {OnFwd(OUT_A+OUT_C); cross=cross+1; PlaySound(SOUND_UP); }} Off(OUT_A+OUT_C);Wait(100); //2周目 ClearTimer(0); while(Timer(0)<RUN_TIME) //時間になるまでライントレースする {line_trace(); } Off(OUT_A+OUT_C); OnFwd(OUT_A+OUT_C); until(SENSOR_1<THRESHOLD) while(Timer(0)<RUN_TIME2) //時間になるまで直角ターンする {acsel_turn(); } Off(OUT_A+OUT_C); while(Timer(0)<RUN_TIME3) //時間になるまでライントレースする {line_trace(); } Off(OUT_A+OUT_C); while(Timer(0)<RUN_TIME4) //時間になるまで直角ターンする {acsel_turn(); } Off(OUT_A+OUT_C); while(Timer(0)<RUN_TIME5) //時間になるまでライントレースする {line_trace(); } Off(OUT_A+OUT_C); }
ライントレースするプログラムと直角でライントレースができるプログラムを交互に使って、2周目に入るときにゴールラインを変数で交差点の数を数えて感知し、基本的には1周目と同じプログラムを使うようにしました。直角に入るときの角度の違いが原因だと思われるのですが、2つ目の直角だけは通常のライントレースのプログラムで曲がれまして、そのほかの直角は、直角までの時間を測ってだいたいの時間になったら直角用のプログラムになるようにしてあります。
#define THRETHOLD 40 //光センサーの数値 task main() {
SetSensor(SENSOR_1,SENSOR_LIGHT); SetSensor(SENSOR_3,SENSOR_LIGHT); SetSensor(SENSOR_2,SENSOR_ROTATION);
int closs=0; //交差点を数える関数を定義 while((closs==0)||(closs==1)||(closs==3)||(closs==5)||(closs==7)){ //通常のラインとレース if(SENSOR_3<THRETHOLD) { OnFwd(OUT_A+OUT_C); } if(SENSOR_3>THRETHOLD) { Off(OUT_A+OUT_C); Wait(3); OnRev(OUT_A); OnFwd(OUT_C); until(SENSOR_3<THRETHOLD); } if(SENSOR_1<THRETHOLD) //交差点を数えて音を鳴らす { closs++; PlaySound(SOUND_CLICK); } if((SENSOR_1<THRETHOLD)&&(SENSOR_3<THRETHOLD)) { Off(OUT_A+OUT_C); Wait(50); OnFwd(OUT_A+OUT_C); until(SENSOR_1>THRETHOLD); Off(OUT_A+OUT_C); } } while((closs==2)||(closs==6)){ //点線のラインとレース if(SENSOR_1<THRETHOLD) { Off(OUT_A+OUT_C); OnRev(OUT_A); OnFwd(OUT_C); until((SENSOR_3>THRETHOLD)&&SENSOR_1>THRETHOLD); } if((SENSOR_1<THRETHOLD)&&(SENSOR_3<THRETHOLD)) //交差点を数えて音を鳴らす { closs++; PlaySound(SOUND_CLICK); } if((SENSOR_1>THRETHOLD)&&(SENSOR_3>THRETHOLD)) { OnFwd(OUT_A+OUT_C); } if((SENSOR_1<THRETHOLD)&&(SENSOR_3>THRETHOLD)) { OnRev(OUT_A); OnFwd(OUT_C); until(SENSOR_1>THRETHOLD); } if((SENSOR_1>THRETHOLD)&&(SENSOR_3<THRETHOLD)) { OnRev(OUT_C); OnFwd(OUT_A); until(SENSOR_3>THRETHOLD); } } while(closs==4){ //2つ目のコーナーでのプログラム if(SENSOR_3<THRETHOLD) { OnFwd(OUT_A+OUT_C); } if(SENSOR_3>THRETHOLD) { Off(OUT_A+OUT_C); Wait(3); OnRev(OUT_C); OnFwd(OUT_A); until(SENSOR_3<THRETHOLD); } if(SENSOR_1<THRETHOLD) { closs++; PlaySound(SOUND_CLICK); } if((SENSOR_1<THRETHOLD)&&(SENSOR_3<THRETHOLD)) { Off(OUT_A+OUT_C); Wait(50); OnFwd(OUT_A+OUT_C); until(SENSOR_1>THRETHOLD); Off(OUT_A+OUT_C); } } while(closs==8){ //止まるためのプログラム ClearSensor(SENSOR_2<SENSOR_ROTATION); if(SENSOR_3<THRETHOLD) { OnFwd(OUT_A+OUT_C); } if(SENSOR_3>THRETHOLD) { Off(OUT_A+OUT_C); Wait(3); OnRev(OUT_A); OnFwd(OUT_C); until(SENSOR_3<THRETHOLD); } if(SENSOR_2>20) { Off(OUT_A+OUT_C); } }
} 今回短縮ルートに入るところに苦戦しました。最初は線をまたいで白を感知していましたがうまくいかず、線を感知するようにし、点線のところを線をまたぐようにすることでうまく短縮ルートに入ることができました。
反省点は、ロボットを作る時点で完成を急ぐために問題点のあるまま進めずに、1から作り直せばよかった。一応授業以外の時間にやったときには課題をこなすことができましたが、結局時間どうりにいかなっかたり、交差点をうまく感知しなかったりで、精度はいまいちでした。
今回はロボットを大きく作りすぎてしまって、強度や小回りを利かせることが難しくなってしまいました。途中でいろいろ改造しながらなんとかやったのですがやはり作り変えるべきだったなと思います。
プログラムでは空行やindentを用いたほうが見やすく、わかりやすいと思います。FI