各チームで次のようなコースを作成し、コースを2周するロボットを製作せよ。
・黒い線の幅は15〜25mmの範囲で一定にすること
・交差点が3箇所以上あること
・直角のコーナーを2箇所以上設置すること
・近道を2箇所(直角のコーナーをショートカットしてもよい)
・スタート地点にはコースに直角に横5cmのラインを描く
ただし、
・速さと正確さを追求すること
・2周目はスタート地点の直前で自動的に止まること
・近道を選択するプログラムとそうでないプログラムを2人で分担して作成すること
・竹園
・中村
ロボットの本体です。細かい動きができるようにするため、土台はコンパクトに、タイヤは前輪のみにしました。
回転センサの位置は本体の後部です。
↓↓↓
ロボット本体の構造とプログラミングの問題点を両方考えて作業を行いました。
光センサは黒い線をまたぐように取り付けました。左右のセンサの間隔を調整できるようにしてあります。 しかし、近道との分岐点でセンサの間隔が問題でプログラムの2つのif文の条件だけを交互に繰り返してしまうということが起こりました。これは調整できる目一杯の間隔をとってもうまくいかなかったので、一度、本体に直接光センサを取り付けることによってセンサどうしの間隔をさらに広げてみました。
・直線(2つのセンサーがどちらも白を認知)
まっすぐ進む
・曲線・曲がり角
黒線に差し掛かったら、黒線に向かうようにする。この時、センサが黒を認知した側のモーターを逆回転、さらになめらかに曲がるように、反対側のモーターを正回転させる。
直角をまがるときはこの条件文に従う。
・交差点(2つのセンサーがどちらも黒を認知)
まっすぐ進む
近道を無視して実線をたどる場合です。近道に差し掛かると、近道がある方のセンサの情報を動きに反映させないようにしました。近道を通るタイミングはタイマーで計りました。
#define THRESHOLD1 50 //黒と白の閾値を設定 #define THRESHOLD3 40 //黒と白の閾値を設定 #define RUN_TIME 650 //65秒間走る sub turn_left() //左に曲がる { OnRev(OUT_A); OnFwd(OUT_C); } sub turn_right() //右に曲がる { OnFwd(OUT_A); OnRev(OUT_C); } task play_music() //1秒ごとに音を鳴らす { while(true) { PlaySound(SOUND_CLICK); Wait(100); } } task main() { SetSensor(SENSOR_1,SENSOR_LIGHT); //センサ1は光センサ SetSensor(SENSOR_3,SENSOR_LIGHT); //センサ3は光センサ ClearTimer(0); //タイマー0をリセット start play_music; //音を鳴らし始める while(Timer(0)<=90) //開始から9秒まで、基本パターン(以下、基本) { if(SENSOR_1>THRESHOLD1) { if(SENSOR_3>THRESHOLD3) //センサ1,3がどちらも白を認知するとき { OnFwd(OUT_A+OUT_C); //まっすぐ前に進む } else //センサ1が白,センサ3が黒を認知するとき { turn_right(); //右に曲がる } } else { if(SENSOR_3>THRESHOLD3) //センサ1が黒,センサ3が白を認知するとき { turn_left(); //左に曲がる } else //センサ1,3がどちらも黒を認知するとき { OnFwd(OUT_A+OUT_C); //まっすぐ前に進む } } } while((Timer(0)>90)&&(Timer(0)<=100)) //9秒から10秒まで、左に行くパターン(以下、左) { if(SENSOR_1>THRESHOLD1) //センサ1が白を認知するとき { OnFwd(OUT_A+OUT_C); //まっすぐ前に進む } else //センサ1が黒を認知するとき { turn_left(); //左に曲がる } } while((Timer(0)>100)&&(Timer(0)<=150)) //10秒から15秒まで(基本) { if(SENSOR_1>THRESHOLD1) { if(SENSOR_3>THRESHOLD3) { OnFwd(OUT_A+OUT_C); } else { turn_right(); } } else { if(SENSOR_3>THRESHOLD3) { turn_left(); } else { OnFwd(OUT_A+OUT_C); } } } while((Timer(0)>150)&&(Timer(0)<=160)) //15秒から16秒まで(左) { if(SENSOR_1>THRESHOLD1) { OnFwd(OUT_A+OUT_C); } else { turn_left(); } } while((Timer(0)>160)&&(Timer(0)<=170)) //16秒から17秒まで(基本) { if(SENSOR_1>THRESHOLD1) { if(SENSOR_3>THRESHOLD3) { OnFwd(OUT_A+OUT_C); } else { turn_right(); } } else { if(SENSOR_3>THRESHOLD3) { turn_left(); } else { OnFwd(OUT_A+OUT_C); } } } while((Timer(0)>170)&&(Timer(0)<=180)) //17秒から18秒まで、右に行くパターン(以下,右) { if(SENSOR_3>THRESHOLD3) //センサ3が白を認知するとき { OnFwd(OUT_A+OUT_C); //まっすぐ前に進む } else //センサ3が黒を認知するとき { turn_right(); //右に曲がる } } while((Timer(0)>180)&&(Timer(0)<=240)) //18秒から24秒まで(基本) { if(SENSOR_1>THRESHOLD1) { if(SENSOR_3>THRESHOLD3) { OnFwd(OUT_A+OUT_C); } else { turn_right(); } } else { if(SENSOR_3>THRESHOLD3) { turn_left(); } else { OnFwd(OUT_A+OUT_C); } } } while((Timer(0)>240)&&(Timer(0)<=250)) //24秒から25秒まで(右) { if(SENSOR_3>THRESHOLD3) { OnFwd(OUT_A+OUT_C); } else { turn_right(); } } while((Timer(0)>250)&&(Timer(0)<=420)) //25秒から42秒まで(基本) { if(SENSOR_1>THRESHOLD1) { if(SENSOR_3>THRESHOLD3) { OnFwd(OUT_A+OUT_C); } else { turn_right(); } } else { if(SENSOR_3>THRESHOLD3) { turn_left(); } else { OnFwd(OUT_A+OUT_C); } } } while((Timer(0)>420)&&(Timer(0)<=430)) //42秒から43秒まで(左) { if(SENSOR_1>THRESHOLD1) { OnFwd(OUT_A+OUT_C); } else { turn_left(); } } while((Timer(0)>430)&&(Timer(0)<=480)) //43秒から48秒まで(基本) { if(SENSOR_1>THRESHOLD1) { if(SENSOR_3>THRESHOLD3) { OnFwd(OUT_A+OUT_C); } else { turn_right(); } } else { if(SENSOR_3>THRESHOLD3) { turn_left(); } else { OnFwd(OUT_A+OUT_C); } } } while((Timer(0)>480)&&(Timer(0)<=490)) //48秒から49秒まで(左) { if(SENSOR_1>THRESHOLD1) { OnFwd(OUT_A+OUT_C); } else { turn_left(); } } while((Timer(0)>490)&&(Timer(0)<=500)) //49秒から50秒まで(基本) { if(SENSOR_1>THRESHOLD1) { if(SENSOR_3>THRESHOLD3) { OnFwd(OUT_A+OUT_C); } else { turn_right(); } } else { if(SENSOR_3>THRESHOLD3) { turn_left(); } else { OnFwd(OUT_A+OUT_C); } } } while((Timer(0)>500)&&(Timer(0)<=510)) //50秒から51秒まで(右) { if(SENSOR_3>THRESHOLD3) { OnFwd(OUT_A+OUT_C); } else { turn_right(); } } while((Timer(0)>510)&&(Timer(0)<=570)) //51秒から57秒まで(基本) { if(SENSOR_1>THRESHOLD1) { if(SENSOR_3>THRESHOLD3) { OnFwd(OUT_A+OUT_C); } else { turn_right(); } } else { if(SENSOR_3>THRESHOLD3) { turn_left(); } else { OnFwd(OUT_A+OUT_C); } } } while((Timer(0)>570)&&(Timer(0)<=580)) //57秒から58秒まで(右) { if(SENSOR_3>THRESHOLD3) { OnFwd(OUT_A+OUT_C); } else { turn_right(); } } while((Timer(0)>580)&&(Timer(0)<=RUN_TIME)) //58秒から終わりまで(基本) { if(SENSOR_1>THRESHOLD1) { if(SENSOR_3>THRESHOLD3) { OnFwd(OUT_A+OUT_C); } else { turn_right(); } } else { if(SENSOR_3>THRESHOLD3) { turn_left(); } else { OnFwd(OUT_A+OUT_C); } } } stop play_music; //音を止める Off(OUT_A+OUT_C); //止まる }
近道をする場合です。変数を定義し、交差点の数を数え、近道の分岐点に差しかかったときに違うタスクを開始させて左側のセンサーのみで白黒を認知するようにしました。 左側のセンサーのみを使うことによって近道でない道を認知しないようにしてあります。 また、交差点の数を数えるとき、1つの交差点で何回も交差点の条件を読み取ってしまうため、0.1秒通ったら回数に加算していくという条件にしました。
#define THRESHOLD1 50 //黒と白の閾値を設定 #define THRESHOLD2 40 //黒と白の閾値を設定 task main(){ ClearTimer(1); //タイマー1をリセット SetSensor(SENSOR_1,SENSOR_LIGHT); //センサ1は光センサ SetSensor(SENSOR_3,SENSOR_LIGHT); //センサ3は光センサ int n=0; while(true){ if(SENSOR_1>THRESHOLD1){ if(SENSOR_3>THRESHOLD2){ //センサ1,3がどちらも白を認知するとき OnFwd(OUT_A+OUT_C); //まっすぐ前へ進む } else if(SENSOR_3<THRESHOLD2) { //センサ1が白、センサ3が黒を認知するとき OnRev(OUT_C); //センサ3(黒)側をバックさせて白い部分へ OnFwd(OUT_A); } } else{ //センサ1が黒を認知するとき if(SENSOR_3>THRESHOLD2) { //センサ3が白だったら OnRev(OUT_A); //センサ1(黒)側をバックさせて白い部分へ OnFwd(OUT_C); } else{ //センサ1,3がどちらも黒を認知するとき ClearTimer(0); //タイマー0をリセット OnFwd(OUT_A+OUT_C); //まっすぐ前へ進む if(Timer(0)>=01){ //タイマー0が0.1秒数えたら PlaySound(SOUND_CLICK); //音をならし n++; //交差点をカウント } } } } while((n==6)||(n==16)){ //交差点6つ目、16つ目にさしかかったとき start follow_line; //task follow_lineをはじめる(近道に進む) n++; //交差点としてカウント } while((n==7)||(n==17)){ //交差点7つ目、17つ目にさしかかったとき stop follow_line; //task follow_lineを終了する(近道を終える) n++; //交差点としてカウント } while(Timer(1)>58){ //58秒したら止まる Off(OUT_A+OUT_C); } } task follow_line() { //センサ1のみを使って黒い線の上を走行する(近道で) SetSensor(SENSOR_1,SENSOR_LIGHT); //センサ1は光センサ int n=0; while(true) { if(SENSOR_1<THRESHOLD1){ //センサ1が黒線上にある場合 OnFwd(OUT_A); Off(OUT_C); //左折 } else{ //センサ1が白線上にある場合 OnFwd(OUT_C); Off(OUT_C); //右折 } } }
プログラミングではタイマー以外は得に工夫しなかった結果、上のようにかなり大きなプログラムになってしまいました。プログラムの大きさに対して動作の確実性は低く、やはりタイマーだけでは限界があることを痛感しました。一つの方法に頼るよりも、変数や回転センサなどいろいろな手法を組み合わせて行った方が、より小さくて確実なプログラムになるので、次回はその辺りをきちんとしたより良いプログラムにするようにします。
今回はプログラミングで苦戦しました。 距離によって分岐点を通るプログラムを想定し、回転センサーをつけたのですが、結局、勉強不足でうまくプログラムを起動させることができませんでした。その後、タイマーや変数を使い、解決策をたてたのですが、やはり確実なプログラムにするには回転センサが必要だったと思います。 ホームページに書いてあることや、過去の受講生の方のを参考にし、復習しなおしたいと思います。
コメントをお願いします。
TAKA まだ出来ていないので、後ほど確認します
TAKA 工夫した点について、写真に説明があると良いと思います
一人目のプログラムでは、3種類のライントレースがあるようですが、それぞれに関数なりサブルーチンをつくれば、もっと見やすいかもしれません。そこまでする必要はないですが、条件判断際にセンサ1の値にTHRESHOLDの値を加えれば常に白と感知することも利用できます。条件判断の際に光センサの値に常にある変数を加えるようにしてライントレースのサブルーチンをつくって、普通に感知させたいときにはその変数を0に、常に感知させるときにはTHRESHOLDと同じ値にするようにすれば簡潔に表現できます。
2人目では最初のwhile(true)から抜け出せるでしょうか?また見やすくするために空行を入れてください。FI