目次 #contents *課題2:黒い線上を動くロボット [#s2a9e895] 次のような周回コース(黒い線)を動くロボットを作成せよ。 -通常の交差点が2箇所以上ある -ロータリー型の交差点が1箇所以上ある (ロータリーでは反時計まわりに進む) -直角に曲がるコーナーおよびそのコーナーをショートカットするコース(点線)が存在する -急なヘアピンカーブが1箇所以上ある -スタート地点に目印がある -黒い線の幅は15〜20mm程度 センサー、モーターはいくつ使ってもよい。プログラムは次の2つを作成すること。 1. 直角のコーナーを通る 2. 直角のコーナーを通らない(近道する) ただし互いに逆方向に周回すること。 *メンバー紹介 [#qf933802] -イシイ(近道担当) -ゆきち(直角コーナー担当) *課題 [#q735ffe3] **コースについて [#e3f78d38] 先生が例として挙げたコースとほとんど同じコースを作った。 コースの線の幅は15mmで統一した。 ●コースの概要 #ref(course.jpg) 以下は、メンバーのロボットがたどるコース。 ●イシイ(近道担当)のコース #ref(course_ishii.jpg) ●ゆきち(直角コーナー担当)のコース #ref(course_yukichi.JPG) **ロボットについて [#ic2a75be] ロボットは四輪の車体に光センサーを取り付けたシンプルな作りになった。 ●全体 #ref(trace_robot.JPG) ●光センサー シンプル、と言っても、光センサーの取り付け方には注意した。 #ref(sensor.JPG) 3センチという幅は組み立ての際に偶然たどり着いた値だが、広すぎず狭すぎない幅だった。広すぎればラインに対する反応が遅れ、カーブを曲がりきれない。また、狭すぎればロボットがコースの曲線に過剰に反応してしまい、一周を回るのにかかる時間が長くなると予想できる。 もう一点、光センサーとロボットを旋回させたときの回転軸との距離に注意した。 #ref(trace_robot_side.JPG) この距離が長ければ、わずかに旋回しただけでも光センサーが大きく動くことになってしまい、急カーブでラインを追いかけることが難しくなると考えた。その点を意識してロボットを作った。 *プログラム [#o770212f] **イシイ [#d645274a] #ref(course_ishii.jpg) #define go(t) OnFwd(OUT_A+OUT_C);Wait(t);Off(OUT_A+OUT_C); //直進 #define turn_r(t) OnFwd(OUT_A);OnRev(OUT_C);Wait(t);Off(OUT_A+OUT_C); //右旋回 #define turn_l(t) OnFwd(OUT_C);OnRev(OUT_A);Wait(t);Off(OUT_A+OUT_C); //左旋回 #define THRESHOLD 45 //閾値 task main() { SetSensor(SENSOR_1,SENSOR_LIGHT); SetSensor(SENSOR_3,SENSOR_LIGHT); ClearTimer(0); //タイマーをリセット while(FastTimer(0)<=500) //5秒後まで繰り返し { OnFwd(OUT_A+OUT_C); OnFwd(OUT_A+OUT_C); //前進 if(SENSOR_1<THRESHOLD) { turn_l(10); //センサー1が反応したら左旋回 turn_l(10); //センサー1が反応したら0.1秒左旋回 } if(SENSOR_3<THRESHOLD) { go(20); //センサー3が反応したら直進 go(20); //センサー3が反応したら0.2秒直進 } } ClearTimer(0); //タイマーをリセット while(FastTimer(0)<=800) //8秒後まで繰り返し { OnFwd(OUT_A+OUT_C); OnFwd(OUT_A+OUT_C); //前進 if(SENSOR_3<THRESHOLD) { turn_r(10); //センサー3が反応したら右旋回 turn_r(10); //センサー3が反応したら0.1秒右旋回 } if(SENSOR_1<THRESHOLD) { go(20); //センサー1が反応したら直進 go(20); //センサー1が反応したら0.2秒直進 } } ClearTimer(0); //タイマーをリセット while(FastTimer(0)<=150) //1.5秒後まで繰り返し { OnFwd(OUT_A+OUT_C); OnFwd(OUT_A+OUT_C); //前進 if(SENSOR_3<THRESHOLD) { turn_r(10) turn_r(10) //センサー3が反応したら0.1秒右旋回 } if(SENSOR_1<THRESHOLD) { go(50); turn_r(70); turn_r(70); //センサー1が反応したら0.5秒直進し、0.7秒右旋回 } } //1回目のロータリー ClearTimer(0); //タイマーをリセット while(FastTimer(0)<=350) //3.5秒後まで繰り返し { OnFwd(OUT_A+OUT_C); OnFwd(OUT_A+OUT_C); //前進 if(SENSOR_1<THRESHOLD) { turn_l(10) //センサー1が反応したら左旋回 turn_l(10) //センサー1が反応したら0.1秒左旋回 } } ClearTimer(0); //タイマーをリセット while(FastTimer(0)<=250) //2.5秒後まで繰り返し { OnFwd(OUT_A+OUT_C); OnFwd(OUT_A+OUT_C); //前進 if(SENSOR_1<THRESHOLD) { turn_l(10); //センサー1が反応したら左旋回 turn_l(10); //センサー1が反応したら0.1秒左旋回 } if(SENSOR_3<THRESHOLD) { go(50) turn_r(60); //センサー3が反応したら turn_r(60); //センサー3が反応したら0.5秒直進し、0.6秒右旋回 } } ClearTimer(0); //タイマーをリセット while(FastTimer(0)<=550) //5.5秒後まで繰り返し { OnFwd(OUT_A+OUT_C); OnFwd(OUT_A+OUT_C); //前進 if(SENSOR_3<THRESHOLD) { turn_r(20); turn_r(20); センサー3が反応したら0.2秒右旋回 } } ClearTimer(0); //タイマーをリセット while(FastTimer(0)<=300) //3秒後まで繰り返し { OnFwd(OUT_A+OUT_C); OnFwd(OUT_A+OUT_C); //前進 if(SENSOR_3<=THRESHOLD) { turn_r(10); turn_r(10); //センサー3が反応したら0.1秒右旋回 } if(SENSOR_1<=THRESHOLD) { go(50); turn_r(80); turn_r(80); //センサー1が反応したら0.5秒直進し、0.8秒右旋回 } } //2回目のロータリー ClearTimer(0); //タイマーをリセット while(FastTimer(0)<=350) //3.5秒後まで繰り返し { OnFwd(OUT_A+OUT_C); OnFwd(OUT_A+OUT_C); //前進 if(SENSOR_1<THRESHOLD) { turn_l(10) turn_l(10) //センサー1が反応したら0.1秒左旋回 } } ClearTimer(0); //タイマーをリセット while(FastTimer(0)<=250) //2.5秒後まで繰り返し { OnFwd(OUT_A+OUT_C); OnFwd(OUT_A+OUT_C); //前進 if(SENSOR_1<THRESHOLD) { turn_l(10); turn_l(10); //センサー1が反応したら0.1秒左旋回 } if(SENSOR_3<THRESHOLD) { go(50) turn_r(100); turn_r(100); //センサー3が反応したら0.5秒直進し、1秒右旋回 } } ClearTimer(0); //タイマーをリセット while(FastTimer(0)<=400) //4秒後まで繰り返し { OnFwd(OUT_A+OUT_C); OnFwd(OUT_A+OUT_C); //前進 if(SENSOR_3<=THRESHOLD) { turn_r(10); turn_r(10); //センサー3が反応したら0.1秒右旋回 } if(SENSOR_1<=THRESHOLD) { go(25); OnFwd(OUT_A); Wait(20); Off(OUT_A); Off(OUT_A); センサー1が反応したら0.25秒直進し、0.2秒左車輪のみ前進 } } //ヘアピンカーブ ClearTimer(0); //タイマーをリセット while(FastTimer(0)<=600) //6秒後まで繰り返し { OnFwd(OUT_A+OUT_C); OnFwd(OUT_A+OUT_C); //前進 if(SENSOR_3<=THRESHOLD) { OnRev(OUT_A+OUT_C); Wait(10); Off(OUT_A+OUT_C); turn_r(20); turn_r(20); //センサー3が反応したら0.1秒後退し、0.2秒右旋回 } } ClearTimer(0); //タイマーをリセット while(FastTimer(0)<=400) //4秒後まで繰り返し { OnFwd(OUT_A+OUT_C); OnFwd(OUT_A+OUT_C); //前進 if(SENSOR_1<THRESHOLD) { turn_l(10); turn_l(10); //センサー1が反応したら0.1秒左旋回 } if(SENSOR_3<THRESHOLD) { go(25); go(25); //センサー3が反応したら0.25秒直進 } } while(SENSOR_3<THRESHOLD) //センサー3が反応するまで繰り返し { OnFwd(OUT_A+OUT_C); OnFwd(OUT_A+OUT_C); //前進 if(SENSOR_1<THRESHOLD) { turn_l(10); turn_l(10); //センサー1が反応したら0.1秒左旋回 } } Off(OUT_A+OUT_C); } **ゆきち [#i0f9386d] #ref(course_yukichi.JPG) -右カーブと左カーブのそれぞれを曲がるだけならば必要なセンサーがどちらか一方であることを考え、交差点などでのコースの誤認をかなり少なくできた。 -右カーブ、左カーブ、ロータリーを移動するプログラムのサブルーチンを定義し、プログラムを短くできた。 -タイマーをアバウトに使い、さらに光センサーによる判定を組み合わせることで、ライントレースの精度を高めることができた。 #define GO(t) OnFwd(OUT_A+OUT_C);Wait(t);Off(OUT_A+OUT_C); //前にt秒進む #define THRESHOLD 45 //明るさを判定する基準値。 sub RIGHT_CURVE() //コースが右にカーブしているときのプログラム { //右側のセンサー3のみを考慮します。 if (SENSOR_3>THRESHOLD)//センサーに反応がなければ直進。 { OnFwd(OUT_A+OUT_C); } if (SENSOR_3<THRESHOLD)//センサーに反応があれば、右にカーブします。 { Off(OUT_C); OnFwd(OUT_A); } } sub LEFT_CURVE() //コースが左にカーブしているときのプログラム { //左側のセンサー1のみを考慮します。 if (SENSOR_1>THRESHOLD) //センサーに反応がなければ直進。 { OnFwd(OUT_A+OUT_C); } if (SENSOR_1<THRESHOLD) //センサーに反応があれば、左にカーブします。 { Off(OUT_A); OnFwd(OUT_C); } } sub ROTARY() //ロータリーのプログラム。 { //ロータリーに入った時点から、このプログラムを使用します。 GO(35); OnFwd(OUT_A);OnRev(OUT_C);Wait(20) //ロボットの回転の中心がロータリーの黒線上に来るように移動。 while(SENSOR_1>THRESHOLD) { OnFwd(OUT_A); OnRev(OUT_C); } Off(OUT_A+OUT_C); OnFwd(OUT_A+OUT_C); //この時点で、ロータリーの黒線が二つのセンサーの間にあります。 ClearTimer(0); while(FastTimer(0)<400) //4秒という時間は、一つ目の分岐を通りすぎるのに十分な時間です。 { LEFT_CURVE(); //その間、ロータリーを左カーブとみなすことができます。 } while(SENSOR_3>THRESHOLD) //4秒以降に3センサーが黒線を感知するとき、ロータリーの出口に達したことになります。 { LEFT_CURVE(); //それまでは、ロータリーを左カーブとみなします。 } Off(OUT_A+OUT_C);GO(35); OnFwd(OUT_A);OnRev(OUT_C);Wait(20); //入ったときと同様に、ロボットの回転の中心がロータリーの黒線上にあるように移動します。 while(SENSOR_1>THRESHOLD) { OnFwd(OUT_A);OnRev(OUT_C); } //この時点でロータリーから伸びる黒線が二つのセンサーの間にあります。 } //ロータリーを抜けました。 task main() { SetSensor(SENSOR_1,SENSOR_LIGHT); SetSensor(SENSOR_3,SENSOR_LIGHT); //センサー1、3を光センサーと定義。 ClearTimer(0); while(FastTimer(0)<=330) //最初はなだらかな右カーブ。 { RIGHT_CURVE(); } while(FastTimer(0)<=850) //ここは左の急カーブなので、別のプログラムを使います。 { if ((SENSOR_1>THRESHOLD)&&(SENSOR_3>THRESHOLD)) { OnFwd(OUT_A+OUT_C); } if ((SENSOR_1<THRESHOLD)&&(SENSOR_3>THRESHOLD)) //反対のタイヤを逆回転させることで、急カーブを回りきります。 { OnRev(OUT_A); OnFwd(OUT_C); } } while(FastTimer(0)<=1100) //緩やかな左カーブ { LEFT_CURVE(); } while(SENSOR_3>THRESHOLD) //ロータリーまで、左カーブが続きます。 { LEFT_CURVE(); } Off(OUT_A+OUT_C); //ロータリー入り口で停止。 ROTARY; ClearTimer(0); while(FastTimer(0)<300) { LEFT_CURVE(); } GO(50); //近道を無視します。 while(FastTimer(0)<700||SENSOR_1>THRESHOLD||SENSOR_3>THRESHOLD) //直角カーブを回るため、急カーブのときと同じプログラムを使用。 { //ロータリーを感知するまでこのプログラムを継続します。 if ((SENSOR_1>THRESHOLD)&&(SENSOR_3>THRESHOLD)) { OnFwd(OUT_A+OUT_C); } if ((SENSOR_1<THRESHOLD)&&(SENSOR_3>THRESHOLD)) { OnRev(OUT_A); OnFwd(OUT_C); } } Off(OUT_A+OUT_C); //ロータリー入り口。 ROTARY; ClearTimer(0); while(SENSOR_1>THRESHOLD||SENSOR_3>THRESHOLD) { LEFT_CURVE(); } GO(15); //交差点を無視して進みます。 while(SENSOR_1>THRESHOLD||SENSOR_3>THRESHOLD) { LEFT_CURVE(); } GO(10); //交差点を無視。 while(SENSOR_1>THRESHOLD||SENSOR_3>THRESHOLD) //「どちらかが白である間、継続」つまり「ゴールの黒線を感知するまで継続」 { if ((SENSOR_1>THRESHOLD)&&(SENSOR_3>THRESHOLD)) { OnFwd(OUT_A+OUT_C); } if ((SENSOR_1<THRESHOLD)&&(SENSOR_3>THRESHOLD)) { OnRev(OUT_A);OnFwd(OUT_C); } if ((SENSOR_1>THRESHOLD)&&(SENSOR_3<THRESHOLD)) { OnRev(OUT_C);OnFwd(OUT_A); } } Off(OUT_A+OUT_C); //ゴール } *反省・感想 [#m39f9cd2] -タイマーを上手く利用して動かすことができたが、時間の調整がとても大変だった。 -論理式を有効に活用することでコースの判定の精度を高めることができた。 -プログラムを短くするのが大変だった。 -プログラムには試行錯誤を繰り返したが、ロボットの改良はほとんどしなかった。先輩方のホームページを見ると、「光センサーと回転軸の距離」を詰めるためにロボットを大幅に改造したものもあり、次回の課題ではロボットとプログラムの二面から課題にアプローチしたいと感じた。 *コメントをお願いします [#d155cfe7] #comment