次のような周回コース(黒い線)を動くロボットを作成せよ。
センサー、モーターはいくつ使ってもよい。プログラムは次の2つを作成すること。
1. 直角のコーナーを通る
2. 直角のコーナーを通らない(近道する)
ただし互いに逆方向に周回すること。
ばば
中島
僕たちのチームは先生の考えたコースをもとにして、近道の部分は直角にしました。
以下の写真が今回用いたコースです。
このコースでセンサーが読み取るのは以下の4種類だけである。
(センサー1、センサー3)
1.(白、白)→黒い線を2つのセンサーがまたいでいるとき ⇒直進
2.(白、黒)→センサー3(右)が黒を認識 ⇒右に修正
3.(黒、白)→センサー1(左)が黒を認識 ⇒左に修正
4.(黒、黒)→交差点(ロータリー)に差し掛かった ⇒直進or右に修正
ロボット本体は、重々しいのが嫌だったのでシンプルにしました。
そして今回のポイントとなる光センサーも2人で違う形として使うために簡単に作りました。
センサー間は3.0mmのです。
これを車体前方につけて
こうしてできた、今回のロボットはこちら↓
中島は最初が急カーブなのでセンサーを少し改造!
使用コース
#define THRESHOLD 40 //閾値 sub except_a_crossing() { if((SENSOR_1>THRESHOLD)&&(SENSOR_3>THRESHOLD)) //(白、白):直進 { OnFwd(OUT_A+OUT_C); } if((SENSOR_1<THRESHOLD)&&(SENSOR_3>THRESHOLD)) //(黒、白):左に修正 { Off(OUT_A); OnFwd(OUT_C); } if((SENSOR_1>THRESHOLD)&&(SENSOR_3<THRESHOLD)) //(白、黒):右に修正 { OnFwd(OUT_A); Off(OUT_C); } } sub Right() { if((SENSOR_1>THRESHOLD)&&(SENSOR_3>THRESHOLD)) //(白、白):直進 { OnFwd(OUT_A+OUT_C); } if((SENSOR_1>THRESHOLD)&&(SENSOR_3<THRESHOLD)) //(白、黒):右に大きく修正 { OnFwd(OUT_A); OnRev(OUT_C); } } sub right() { if((SENSOR_1>THRESHOLD)&&(SENSOR_3>THRESHOLD)) //(白、白):直進 { OnFwd(OUT_A+OUT_C); } if((SENSOR_1>THRESHOLD)&&(SENSOR_3<THRESHOLD)) //(白、黒):右に修正 { Off(OUT_A); OnFwd(OUT_C); } } sub b_b_go() { if((SENSOR_1<THRESHOLD)&&(SENSOR_3<THRESHOLD)) //(黒、黒):直進 { OnFwd(OUT_A+OUT_C); PlaySound(SOUND_CLICK); } //交差点で音を鳴らす } sub b_w_left() { if((SENSOR_1<THRESHOLD)&&(SENSOR_3>THRESHOLD)) //(黒、白):左に修正 { Off(OUT_A); OnFwd(OUT_C); } } sub b_b_Right() { if((SENSOR_1<THRESHOLD)&&(SENSOR_3<THRESHOLD)) //(黒、黒):右に大きく修正 { OnFwd(OUT_A); OnRev(OUT_C); PlaySound(SOUND_CLICK); } //交差点で音を鳴らす } sub w_w__w_b_go() { if((SENSOR_1>THRESHOLD)&&(SENSOR_3>THRESHOLD)) //(白、白):直進 { OnFwd(OUT_A+OUT_C); } if((SENSOR_1>THRESHOLD)&&(SENSOR_3<THRESHOLD)) //(白、黒):直進 { OnFwd(OUT_A+OUT_C); } b_w_left(); } task main() { SetSensor(SENSOR_1,SENSOR_LIGHT); //センサー1は光センサー SetSensor(SENSOR_3,SENSOR_LIGHT); //センサー3は光センサー ClearTimer(0); //タイマーをリセット while(FastTimer(0)<=1200) //12秒以下でwhile内を繰り返し { except_a_crossing(); b_b_go(); } ClearTimer(0); //タイマーをリセット while(FastTimer(0)<=300) //3秒以下でwhile内を繰り返し { except_a_crossing(); b_b_Right(); } ClearTimer(0); //タイマーをリセット while(FastTimer(0)<=250) //2.5秒以下でwhile内を繰り返し { w_w__w_b_go(); b_w_left(); } ClearTimer(0); //タイマーをリセット while(FastTimer(0)<=200) //2秒以下でwhile内を繰り返し { Right(); } ClearTimer(0); //タイマーをリセット while(FastTimer(0)<=250) //2.5秒以下でwhile内を繰り返し { right(); } ClearTimer(0); //タイマーをリセット while(FastTimer(0)<=500) //5秒以下でwhile内を繰り返し { Right(); } ClearTimer(0); //タイマーをリセット while(FastTimer(0)<=200) //2秒以下でwhile内を繰り返し { Right(); b_w_left(); b_b_Right(); } ClearTimer(0); //タイマーをリセット while(FastTimer(0)<=200) //2秒内でwhile内を繰り返し { right(); } ClearTimer(0); //タイマーをリセット while(FastTimer(0)<=200) //2秒以下でwhile内を繰り返し { Right(); } ClearTimer(0); //タイマーをリセット while(FastTimer(0)<=1000) //10秒以下でwhile内を繰り返し { Right(); b_w_left(); b_b_go(); Off(OUT_A+OUT_C); PlaySound(SOUND_DOUBLE_BEEP); //ゴールしたら音を鳴らす }
使用コース
#define threshold 40 #define turn_left(t) OnRev(OUT_A);OnFwd(OUT_C);Wait(t);Float(OUT_A+OUT_C); #define turn_right(t) OnRev(OUT_C);OnFwd(OUT_A);Wait(t);Float(OUT_A+OUT_C); #define go_straight(t) OnFwd(OUT_A+OUT_C);Wait(t);Float(OUT_A+OUT_C); sub line_trace() //ライン上を進む { if(SENSOR_3 < threshold) { OnFwd(OUT_A); Off(OUT_C); } if(SENSOR_1 < threshold) { Off(OUT_A); OnFwd(OUT_C); } else { OnFwd(OUT_A); OnFwd(OUT_C); } } task main() { SetSensor(SENSOR_1, SENSOR_LIGHT); //センサー1は光センサー SetSensor(SENSOR_3, SENSOR_LIGHT); //センサー3は光センサー ClearTimer(0); while(FastTimer(0) <= 1320) //急カーブの部分について { line_trace(); //ライン上を進む } ClearTimer(0); while(FastTimer(0) <= 210) //ロータリーについて { if(FastTimer(0) <= 40) //0.4秒間右に曲がる { turn_right(40); } line_trace(); //ライン上を進む } ClearTimer(0); while(FastTimer(0) <= 260) //一つ目無視して進むために { if(FastTimer(0) <= 100) //1秒間右回転 { OnFwd(OUT_C);Wait(100); } line_trace(); //ライン上を進む } ClearTimer(0); while(FastTimer(0) <= 425) //ロータリー1終わり→3.8秒進む { if(FastTimer(0) <= 45) { turn_right(45); //4.5秒間右に曲がる } line_trace(); //ライン上を進む } ClearTimer(0); while(FastTimer(0) <= 540) //近道について { if(FastTimer(0) <=442) //4.42秒の間 { turn_left(102); //直角に左まわり go_straight(230); //2.3秒直進 turn_left(110); //直角に左まわり } line_trace(); //ライン上を進む } ClearTimer(0); while(FastTimer(0) <= 200) //ロータリー2について { if(FastTimer(0) <= 40) //0.4秒間 { turn_right(40); //右に0.4秒 } line_trace(); //ライン上を進む } ClearTimer(0); while(FastTimer(0) <= 335) //一つ目無視するために { if(FastTimer(0) <= 100) //1秒間 { OnFwd(OUT_C); //1.7秒間左回転 Off(OUT_A); Wait(170); } line_trace(); //ライン上を進む } ClearTimer(0); while(FastTimer(0) <= 1400) //ロータリー2終わり→15.2秒進む { if(FastTimer(0) <= 100) //1秒間 { turn_right(100); //右回転 } line_trace(); //ライン上を進む } ClearTimer(0); while(FastTimer(0) <= 250) //最後がうまく曲がれないので { if(FastTimer(0) <= 150) //1.5秒間 { OnFwd(OUT_A); //右に回転 Off(OUT_C); Wait(150); } line_trace(); //ライン上を進む } Off(OUT_A+OUT_C); //終わり }
交差点やロータリーでは2つのセンサーは(黒、黒)を認識します。なので交差点の時は(黒、黒)を認識したら直進するという命令を出しました。ロータリーでは(黒、黒)を認識したら右に曲がるように命令を出しました。その後、1つ目の道は無視しないといけないので(白、黒)を認識したら直進するように命令を出しました。ただ、その次の道は右に曲がらないといけないので、タイマーで時間を区切って(白、黒)で右に曲がるようにプログラミングしました。今回の最大の難関はこのロータリーの攻略だと思いました。
急カーブは普通に曲がっていてはコースから外れてしまうので、OffにしていたモーターをOnRevにして対応しました。また、直角や近道は(白、黒)のときに右折というプログラムでなんとかなりました。
今回の課題はロボット本体の製作にはあまり手こずらなかったが、その分プログラミングの難易度が高かった。課題1でやった関数やサブルーチンに加え、whileやifなども出てきて大変だった。一番難しかったのは、タイマーとwhileの調節です。この時間内にはこの条件という命令を出すのは厳しかったです。工夫した点は、サブルーチンを使ったところ。交差点以外は基本同じ動きをするので、except_a_crossing というサブルーチンを定義したら、プログラムがすっきりしました。さらに、交差点を通過するたび音を鳴らしたので、プログラムの修正中にちょっとした目印となった。今回の課題ではプログラミング力がついたと思うので、次の課題ではプログラムに工夫点をたくさん組み込んでいきたいです。
まずロータリーの仕組みを理解してなかったのはすごく反省しています。一度は完成したプログラムも全て書き直しました。課題そのものをちゃんと理解することが大切だと実感しました。
前回の最大の反省点である「作業に取り掛かるのが遅すぎた」のは改善されましたが、少ない作業時間をもっと密度の濃いものにしていかないといけないと思った。自宅でタイマーの時間以外のプログラムを終わらせてきて、集まったときに時間調節をしたのは良かったと思うので、次の課題3でも自宅でできることは全部終わらせて集まったときは、その時にしかできないことをやりたいと思います。
Today:1
Yesterday:0
All:&counter([total|today|yesterday]);