目次
黒い線上を動くロボット
次のような周回コース(黒い線)を動くロボットを作成せよ。
通常の交差点が2箇所以上ある
ロータリー型の交差点が1箇所以上ある (ロータリーでは反時計まわりに進む)
直角に曲がるコーナーおよびそのコーナーをショートカットするコース(点線)が存在する
急なヘアピンカーブが1箇所以上ある
スタート地点に目印がある
黒い線の幅は15〜20mm程度
センサー、モーターはいくつ使ってもよい。プログラムは次の2つを作成すること。
1. 直角のコーナーを通る
2. 直角のコーナーを通らない(近道する)
ただし互いに逆方向に周回すること。
線を追っていくための重要なセンサー部分は、センサーを二つ使用して黒い線の両端を伝っていくものにした。
これは今回の課題の中でなるべく速くという条件があったからであり、
センサー一つで黒い線を追っていくとどうしても修正がなんども入って遅くなってしまうと感じたからです。
胴体部もなるべく小回りにしたかったため、
写真のロボットの後輪を外して軽量化と小回りにすることを成し遂げました。
これによってモーターの負担も減り、結果的にトルクをあげることも叶いました。
(完成品のロボットの写真をこちらの手違いで消してしまったようなので
完成形は上のロボットの後輪を外したものと思ってください。)
今回のロボットはいたってシンプルな形を目指し、
そのかわりプログラミングで解決しようということにしました。
#define border 40 // 白黒の境界 #define t90 75 //90度旋回 #define turn_r OnFwd(OUT_A);OnRev(OUT_C); #define turn_l OnFwd(OUT_C);OnRev(OUT_A); int cross=0 ; //交差点に入った回数 void lortary() { Off(OUT_A+OUT_C); PlaySound(SOUND_UP); Wait(100); turn_r; Wait(t90); cross=cross+1; } void shortcut() { ClearTimer(0); while(FastTimer(0)<=300){ //ショートカットに入るまでは通常と同じ if ((SENSOR_1 >= border)&&(SENSOR_3 >= border)){ // どちらも白 OnFwd(OUT_A+OUT_C); } else if ((SENSOR_1 < border)&&(SENSOR_3 > border)){ // センサー1が黒 OnRev(OUT_A); OnFwd(OUT_C); } else if ((SENSOR_1 > border)&&(SENSOR_3 < border)){ // センサー3が黒 OnRev(OUT_C); OnFwd(OUT_A); } } OnFwd(OUT_A); OnRev(OUT_C); Wait(t90); //ショートカットに入るために曲がる } //その後は通常のプログラムへ戻る task main(){ SetSensor(SENSOR_1, SENSOR_LIGHT); //センサー1は光センサー SetSensor(SENSOR_3, SENSOR_LIGHT); //センサー3は光センサー while (true) { if ((SENSOR_1 >= border)&&(SENSOR_3 >= border)){ // どちらも白 OnFwd(OUT_A+OUT_C); } else if ((SENSOR_1 < border)&&(SENSOR_3 > border)){ // センサー1が黒 OnRev(OUT_A); OnFwd(OUT_C); } else if ((SENSOR_1 > border)&&(SENSOR_3 < border)){ // センサー3が黒 OnRev(OUT_C); OnFwd(OUT_A); } else { cross=cross+1; PlaySound(SOUND_CLICK);Wait(50); while((SENSOR_1 <= border)&&(SENSOR_3 <= border)) {OnFwd(OUT_A+OUT_C);} if((cross==3)||(cross==7)){lortary();} //ロータリーに入ったときの対応 if((cross==5)||(cross==9)){turn_l;} //ロータリー内での修正 if(cross==10){turn_r;} //ロータリー内での修正 if(cross==6){shortcut();} //ショートカット用の関数に移る else {OnFwd(OUT_A+OUT_C);} } } }
今回のプログラミングで工夫したことは線を追っていく通常時のプログラムと、
ロータリーや交差点などの特殊な状況に直面したときのプログラムを関数でわけたことです。
これは結局はロータリーや交差点はいつも各々同じ処理をすればいいことなので、
1回目のロータリーと2回目のロータリーでプログラムを分けるというのは必要ないと感じたからです。
これをすることによって毎回のロータリーや交差点で安定した挙動を見せるようになりました。
他にもtask mainがすっきりとしたものになり、再確認の時により見やすくなるなどのメリットもうまれました。
しかし関数などをバラしたことによって、その関数一つ一つに変数などを定義するのが面倒になるというデメリットも発生しました。
これには最上位の部分で変数などを定義しておき、一つ一つの箱で定義しなおすことのないよう工夫しました。
#define VOLUME 40 //光の量 多いほど明るい #define BIT 10 //微調節のためのマクロ #define STOP 10 //それたときの待ち時間 #define TURN 50 //直角に曲がるためのマクロ task main() { SetSensor(SENSOR_1,SENSOR_LIGHT); SetSensor(SENSOR_3,SENSOR_LIGHT); while (true){ if ((SENSOR_1>VOLUME)&&(SENSOR_3>VOLUME)){ //黒線上にいるとき OnFwd(OUT_A); //直進する OnFwd(OUT_C); Wait(BIT); //0.1秒ずつ進む } else if ((SENSOR_1<VOLUME)&&(SENSOR_3>VOLUME)){ //右にそれたとき Off(OUT_A+OUT_C); Wait(STOP); OnFwd(OUT_C); OnRev(OUT_A); Wait(BIT); //左に少し曲がる } else if ((SENSOR_3<VOLUME)&&(SENSOR_1>VOLUME)){ Off(OUT_A+OUT_C); Wait(STOP); OnFwd(OUT_A); //それ以外(左にそれたとき) OnRev(OUT_C); Wait(BIT); //右に少し曲がる } else{ //両方のセンサーが黒の時(ロータリー入り口&出口) Off(OUT_A+OUT_C); Wait(STOP); OnFwd(OUT_A); //右に直角に曲がる OnRev(OUT_C);Wait(TURN); OnFwd(OUT_A); //少し直進 OnFwd(OUT_C); Wait(BIT); } } }
↓