今回のメンバーは「カズ」と「ZWEI」です
ホームページ・プログラム担当 「カズ」
ロボット制作担当 「ZWEI」
黒い線に沿って動くロボットを作成せよ。ただし、
1、速さと正確さを追求すること 2、交差点で優先側を走っていない場合には、一時停止すること 3、前方にあるもう一台のロボットに接触した場合には停止して, 相手のロボットが行き過ぎる、あるいは距離が離れるのを待つこと
今回の課題のメインはライントレースです。しかし、ライントレースより厄介なのは交差点です。交差点を識別し、優先道路なら直進、違うなら一時停止しなければならないからです。この課題は、光センサーの使い方がポイントだと感じました。よって、センサーの付け方からロボットのベースを決めることにしました。
ライントレースするための光センサーの取り付け方は、(僕の思いついた限り)3つあります。それぞれの長所、短所を述べたうえで、僕たちの班が選んだ取り付け方と、それを選んだ理由を説明しようと思います。
※取り付け方1
光センサー1つを使います。もし、センサーがライン上にあれば、ロボットがラインから出るようにタイヤを動かし、センサーがラインを出たら、逆のタイヤを動かし、ラインに戻るようにします。
☆メリット
ライントレースにおいてセンサーを1つしか使わないため、プログラムが簡単になります。
急なカーブもクリアすることができます。
★デメリット
交差点が識別できません。
※取り付け方2
光センサー2つを使います。光センサーの間隔を2,5cm(ラインの幅)以上広げ、もし、どちらかのセンサーがライン上にきたら、モーターを調整して、もとの状態にもどすプログラムを作る。
☆メリット
ライントレースが比較的簡単です。コースを脱線する恐れが、ほとんどありません。
★デメリット
交差点において一時停止するのが少し遅れます。(優先道路へ入ってしまいます)
※取り付け方3
光センサー2つを使います。光センサーの間隔を2,5cm(ラインの幅)以内にして、もし、どちらかのセンサーがライン外にきたら、モーターを調整して、もとの状態にもどすプログラムを作る。
☆メリット
交差点を認識できます。(センサーが両方ともライン外にきたとき交差点)
★デメリット
急なカーブに対応できず、ラインを見失なってしまいます。
僕たちの班は、光センサーを「取り付け方3」のようにしました。理由はいたって単純。交差点をちゃんと攻略できるのは、「取り付け方3」だと判断したからです。ライントレースにおける「カーブ」に至っては、「取り付け方1」及び「取り付け方2」のほうがいいと思います。しかし、今回の課題では、1番上の2に書いたように、交差点で優先道路でない場合、一時停止しなければなりません。「取り付け方2」では、やり方によってはできますが、1番きれいに交差点を攻略できるのは「取り付け方3」です。総合してみると、1番だと思った「取り付け方3」を採用しました。
交差点を攻略できても、急なカーブをライントレースできないのでは、意味がありません。そこで、プログラムを工夫して、急なカーブにも対応できるようにしました。下に、元のプログラムと改善後のプログラムを書きます。
元のプログラム(左に曲がりたいとき)
OnFwd(OUT_C); //右のタイヤを回転させます Off(OUT_A); //左のタイヤを止めます
改善後のプログラム(左に曲がりたいとき)
SetPower(OUT_A,3); //左のタイヤの出力を弱く設定 SetPower(OUT_C,7); //右のタイヤの出力を強く設定 OnFwd(OUT_C); //右のタイヤを回転させます OnRev(OUT_A); //左のタイヤを反対の方向に回転させます
このように、曲がりたい方向にあるタイヤを進行方向に対して逆の方向に回転させるだけで、かなり曲がりやすくなります。右に曲がりたいときも、同様の方法ですることが可能です。
交差点が2つのシンプルなコースです。しかし、両方の交差点が、急カーブのあとすぐにあるので、そこを調整するのが難しかったです。
立てた作戦に基づき、ロボットの構造を考えました。左右のタイヤにそれぞれモーターを1つずつ使い、土台を支えるために3つのタイヤを使いました。タッチセンサー・光センサーともにロボットの前に取り付ける予定だったので、土台は後ろに重心がくるようにしました。
タッチセンサーはこのロボットのチャームポイントです!!
2枚の写真を見比べてください。前方の障害物にあたると、タッチセンサーが反応する仕組みになっています。
このように光センサーをつけました。青いブロックが光センサーです。
試験走行用のプログラムを作って走らせました。しかし、以下のような問題が発生しました。
1つ目、光センサーが床に近すぎたため、ラインと、そうでない部分を判別できなかった。
2つ目、ロボットの動きが速すぎたためすぐにラインをはずれてしまった。
3つ目、プログラムのミスで、タッチセンサーが当たっても止まらないときがあった。
このような問題が発生したため、ロボットとプログラムを組みなおす必要がありました。
ギアの組み合わせをかえることにより、ロボットの速さを適度にすることに成功しました。また、センサーの地面からの高さと、前輪のタイヤの大きさをかえることにより、ちゃんとラインを区別してくれるようになりました。
・とても急なカーブには対応できないが、ほとんどのカーブをクリアする事ができる
・交差点前で一時停止をきちんとできる
・コースの完走率は今のところ80%ぐらいである
・このロボットは、ほぼ、左右対称にできています。(配色もそうです)
・タッチセンサーが他の班と比べて個性的です。
//どこのプログラムを実行中か分かるようにするために音楽をつけました。 #define Dol 1047 定数を定義 「ド」の波長 #define Rel 1175 定数を定義 「レ」の波長 #define Mil 1319 定数を定義 「ミ」の波長 #define Fal 1397 定数を定義 「ファ」の波長 #define Sol 1568 定数を定義 「ソ」の波長 #define Sofl 1661 定数を定義 「ソのシャープ」の波長 #define Ram 1760 定数を定義 「ラ」の波長 #define Rafm 1865 定数を定義 「シのフラット」の波長 #define Shm 1976 定数を定義 「シ」の波長 #define Dom 2093 定数を定義 「ド、1オクターブ上」の波長 task play_music(){ //MUSIC while (true) //この曲は「おもちゃのチャチャチャ」です { PlayTone(Dol,20); Wait(30);//「ド」 PlayTone(Dol,20); Wait(30);//「ド」 PlayTone(Dol,20); Wait(30);//「ド」 PlayTone(Mil,20); Wait(30);//「ミ」 PlayTone(Sol,20); Wait(30);//「ソ」 PlayTone(Sol,20); Wait(30);//「ソ」 PlayTone(Sol,20); Wait(60);//「ソ」 PlayTone(Rel,20); Wait(30);//「レ」 PlayTone(Rel,20); Wait(30);//「レ」 PlayTone(Rel,20); Wait(30);//「レ」 PlayTone(Fal,20); Wait(30);//「ファ」 PlayTone(Sol,20); Wait(30);//「ソ」 PlayTone(Sol,20); Wait(30);//「ソ」 PlayTone(Sol,20); Wait(90);//「ソ」 PlayTone(Sol,20); Wait(30);//「ソ」 PlayTone(Sol,20); Wait(30);//「ソ」 PlayTone(Sofl,20); Wait(30);//「ソ#」 PlayTone(Ram,20); Wait(30);//「ラ」 PlayTone(Ram,20); Wait(30);//「ラ」 PlayTone(Ram,20); Wait(30);//「ラ」 PlayTone(Sofl,20); Wait(30);//「ソ#」 PlayTone(Sol,40); Wait(60);//「ソ」 PlayTone(Shm,40); Wait(60);//「シ」 PlayTone(Dom,40); Wait(120);//「ド」 PlayTone(Sol,20); Wait(30);//「ソ」 PlayTone(Sol,20); Wait(30);//「ソ」 PlayTone(Fal,20); Wait(30);//「ファ」 PlayTone(Mil,20); Wait(30);//「ミ」 PlayTone(Mil,20); Wait(30);//「ミ」 PlayTone(Mil,20); Wait(30);//「ミ」 PlayTone(Fal,20); Wait(30);//「ファ」 PlayTone(Sol,20); Wait(30);//「ソ」 PlayTone(Sol,20); Wait(30);//「ソ」 PlayTone(Sol,20); Wait(30);//「ソ」 PlayTone(Sol,20); Wait(30);//「ソ」 PlayTone(Dol,80); Wait(120);//「ド」 PlayTone(Fal,20); Wait(30);//「ファ」 PlayTone(Fal,20); Wait(30);//「ファ」 PlayTone(Mil,20); Wait(30);//「ミ」 PlayTone(Rel,20); Wait(30);//「レ」 PlayTone(Rel,20); Wait(30);//「レ」 PlayTone(Rel,20); Wait(30);//「レ」 PlayTone(Rel,20); Wait(30);//「レ」 PlayTone(Rel,20); Wait(30);//「レ」 PlayTone(Shm,20); Wait(30);//「シ」 PlayTone(Shm,20); Wait(30);//「シ」 PlayTone(Ram,20); Wait(30);//「ラ」 PlayTone(Sol,80); Wait(120);//「ソ」 PlayTone(Ram,20); Wait(30);//「ラ」 PlayTone(Ram,20); Wait(30);//「ラ」 PlayTone(Ram,20); Wait(30);//「ラ」 PlayTone(Shm,20); Wait(30);//「シ」 PlayTone(Dom,20); Wait(30);//「ド」 PlayTone(Dom,20); Wait(30);//「ド」 PlayTone(Dom,40); Wait(60);//「ド」 PlayTone(Shm,20); Wait(30);//「シ」 PlayTone(Shm,20); Wait(30);//「シ」 PlayTone(Shm,20); Wait(30);//「シ」 PlayTone(Shm,20); Wait(30);//「シ」 PlayTone(Ram,80); Wait(120);//「ラ」 PlayTone(Sol,20); Wait(30);//「ソ」 PlayTone(Sol,20); Wait(30);//「ソ」 PlayTone(Sofl,20); Wait(30);//「ソ#」 PlayTone(Ram,20); Wait(30);//「ラ」 PlayTone(Ram,20); Wait(30);//「ラ」 PlayTone(Ram,20); Wait(30);//「ラ」 PlayTone(Sofl,20); Wait(30);//「ソ#」 PlayTone(Sol,40); Wait(60);//「ソ」 PlayTone(Shm,40); Wait(60);//「シ」 PlayTone(Dom,40); Wait(360);//「ド」 }} //ここからライントレースのプログラム int k_s; //変数を用意(soundを鳴らすか鳴らさないかをきめる変数) int s_p; //変数を用意(交差点を見分けるときに使用) int k_p; //変数を用意(どちらに曲がっているかをあらわすために使用) define LI 43 //光の強さの境界線を定義 sub search_pro() //ラインを見失ったとき用のサブルーチン { while ((SENSOR_1 > LI) && (SENSOR_3 > LI)) //ラインが見つかるまで繰り返す { SetPower(OUT_A+OUT_C,7); OnRev(OUT_A);OnFwd(OUT_C); 左を探す Wait(30); OnRev(OUT_C);OnFwd(OUT_A); 右を探す Wait(60); OnRev(OUT_A);OnFwd(OUT_C); ロボットの向きを元にもどす Wait(30); OnFwd(OUT_A+OUT_C); 直進する repeat(7) //7回繰り返す { Wait(10); if (SENSOR_2 == 1) //タッチセンサーにあたったら10秒とまる { Off(OUT_A+OUT_C); Wait(100); } } } } sub s_touch() //タッチセンサーにあたったとき用の命令文(サブルーチン) { SetPower(OUT_A+OUT_C,7); Off(OUT_A+OUT_C); モーターの出力をとめる Wait(100); 10秒待つ } task main () { SetSensor(SENSOR_1, SENSOR_LIGHT); //センサー1を光センサーと定義 SetSensor(SENSOR_2, SENSOR_TOUCH); //センサー2をタッチセンサーと定義 SetSensor(SENSOR_3, SENSOR_LIGHT); //センサ−3を光センサーと定義 s_p = 2 ; 変数に2を代入 start play_music ; //音楽を再生する k_s =1; 変数に1を代入 while (true){ while (SENSOR_2 == 0){ //タッチセンサーが反応するまで繰り返す while ((SENSOR_1 < LI) && (SENSOR_3 < LI)) //センサー1、3共にライン上のとき { SetPower(OUT_A+OUT_C,7); OnFwd(OUT_A+OUT_C); 直進する if ( k_s == 2) {start play_music;k_s = 1;} //ライン上なら音楽再生 s_p = 1; if (SENSOR_2 == 1) タッチセンサーが反応したら、ロボットを止める { s_touch(); } } while ((SENSOR_1 < LI) && (SENSOR_3 > LI)) //センサー1がライン上、センサー3がライン外のとき { if ( k_s == 2) {start play_music;k_s = 1;} //ライン上なら音楽再生 SetPower(OUT_A,3); //左のタイヤの出力を弱く設定 SetPower(OUT_C,7); //右のタイヤの出力を強く設定 OnFwd(OUT_C); //右のタイヤを回転させます OnRev(OUT_A); //左のタイヤを反対の方向に回転させます s_p = 1; if(k_p ==1) { ClearTimer(2); //右に曲がっていた時間を計っていたタイマーをリセット } k_p=2; if (SENSOR_2 == 1) タッチセンサーが反応したら、ロボットを止める { s_touch(); } } while ((SENSOR_1 > LI) && (SENSOR_3 < LI)) //センサー1がライン外、センサー3がライン上のとき { SetPower(OUT_C,3); //右のタイヤの出力を弱く設定 SetPower(OUT_A,7); //左のタイヤの出力を強く設定 OnFwd(OUT_A); //左のタイヤを回転させます OnRev(OUT_C); //右のタイヤを反対の方向に回転させます if ( k_s == 2) {start play_music;k_s = 1;} //ライン上なら音楽再生 k_s=2; s_p = 1; if(k_p ==2) { ClearTimer(1); //左に曲がっていた時間を計っていたタイマーをリセット } k_p=1; if (SENSOR_2 == 1) タッチセンサーが反応したら、ロボットを止める { s_touch(); } } if ((SENSOR_1 > LI) && (SENSOR_3 > LI)) センサー1、3共にライン外のとき { stop play_music ;k_s=2; //交差点にくると、音楽の再生を停止 if (s_p == 1){ //このパターンは交差点です SetPower(OUT_A,3); SetPower(OUT_C,7); Off(OUT_A+OUT_C); ロボットを停止させる if(Timer(2) >= 20) //2秒以上、左にカーブして交差点に入ったとき { OnRev(OUT_A); //ロボットの向きを微調整する Wait(23); } if(Timer(1) >=20) //2秒以上、右にカーブして交差点に入ったとき { OnRev(OUT_C); //ロボットの向きを微調整する Wait(23); } Off(OUT_A+OUT_C); //10秒間停止する Wait(100); OnFwd(OUT_A+OUT_C); //交差点を横切る repeat(14){ Wait(10); s_p = 2; if (SENSOR_2 == 1) タッチセンサーが反応したら止まる { s_touch(); } } }else{ //コースを見失ったとき SetPower(OUT_A+OUT_C,7); search_pro(); サブルーチンのサーチプログラムを作動させる } } } } }
今回の課題をこなすにあたって、プログラムは非常に重要な役割を担います。前回の書道ロボットの課題は、与えた命令通りにロボットが動くので、プログラミングは比較的やさしいものでした。しかし、今回の課題では、ロボットがセンサーによる情報を分析して動くので、予想外の動きをすることがあります。あらゆるパターンを考え、プログラミングをすることは結構難しいことでした。
プログラムが長くなったので、なるべく{ と } が上下に同じ位置にくるようにして、少しでもプログラムがみえやすくなるように努力した。
プログラムにおいて、変数を使用したこと。そのことにより、センサーから送られてくる情報だけでなく、現在ロボットがどのように走っているかという事をロボットに認識させることが可能になった。(何秒間、どちらにカーブしたかが分かる)
if文、while文をたくさん使ったため、{}が多くなりプログラムを組むのが難しかった。
最初から課題のすべてをこなすロボットを作ろうとしたので、初めて試験走行したときはライントレースさえ、してくれなかった。その後のロボット、プログラムの組みなおしは想像以上にきつかった。
(カズ) 今回の課題の収穫は、timerとmusicの命令文を使うことができたという点です。timerの命令文(時間をはかる命令文)はライントレースには使わないだろうと、最初は思っていました。しかし、その命令文と、変数、if文をうまく組み合わせてプログラムを組むことにより、何秒間どちらにカーブしたのか、ということさえ分かるようになりました。新しい命令文を使うことができたので、プログラム面では、よくできたと思います。
(ZWEI) 自分はロボット本体の作成を主に行いました。タイヤ、センサーの位置、重量バランス、剛性などを考えました。しかし途中、旋回方法に問題があることに気づき苦労した場面があります。タッチセンサー部分の工夫と本体の剛性に関しては満足です。