*課題2(第1コース) [#n2ab6bc0] #contents 下の図のようなコースを各チームで作成し、「ミッション」を遂行するためのロボットを作成せよ。 **ミッション [#j6a6c3cd] 次のいずれかのコースで黒い線に沿って動き、途中でボールをゴール付近に立てた350mlの空き缶(黄色で表示)に当てるロボットを製作せよ。 (相棒と違うコースを選ぶこと) http://yakushi.shinshu-u.ac.jp/robotics/?plugin=ref&page=2018b%2FMember%2FJerry%2FMission2&src=%A5%B3%A1%BC%A5%B9.png +ロボットを長方形X内におき、Aをスタート +Bを右折 +Kで一時停止して左折 +Jを直進 +Iを直進 +Hを左折 +Gで一時停止して左折 +Eで一時停止して右折 +Lを経て正方形Y内に入って停止 (一時停止の指定がある場所は、1秒間停止すること) ボールはロボットが弧IHKJ上にある時にQ地点の空き缶に当てる *ロボットの説明[#sd3ebdf4] **全体像 [#s5157bea] http://yakushi.shinshu-u.ac.jp/robotics/?plugin=attach&pcmd=open&file=C28CF2AD-EBF7-4DC6-BAD4-E41C3BCDE9D9.jpeg&refer=2018b%2FMember%2Fyamada%2FMission2 [#d0f606ea] ***説明(工夫した点や反省点) [#x078071a] 車体自体は参考書のサンプルを基本とすることで安定した動きができるようにした。ボールを持ち上げない構造にすることで、ボールを持っている時と持っていない時とでの重心やバランスの違いを無くし、プログラムを作りやすくした。また、ボールを囲むアームを少し大きめに作ることで、ボール自体が転がり、ロボットが動いた時に摩擦などによって動きの妨げにならないようにした。光センサーを設計図よりタイヤに近づけるためにできるだけ元の車体バランスを崩さないようにしながらNXTの真下の部品を1段分後ろに下げた。 それによって急なカーブをより良い精度で通過できるようになった。 **各種センサーの位置 [#a9f92a47] http://yakushi.shinshu-u.ac.jp/robotics/?plugin=attach&pcmd=open&file=721D9563-2EBC-45A6-92F9-D74A4BE851C6.jpeg&refer=2018b%2FMember%2Fyamada%2FMission2 ***説明(工夫した点や反省点) [#a51e9743] 超音波センサーをアームや光センサーの邪魔にならない程度で、できる限り低く設置することで缶を見つけやすくした。 光センサーをタイヤの近くに設置することで急なカーブの成功率を上げた。 タッチセンサーは、今回の課題においてボールを探すことからまず始まると勘違いしていたので、余分に取り付けてあるように見えるが、ボールを缶に当てる時に、このタッチセンサーにぶつけることでボールのスピードや飛距離がより伸び、成功率が高まったことを考慮し、取り付けたままの状態となっている。 **ボールを缶に充てる方法 [#veba20c6] 缶の方向を向いた後にアームを上げ、少しスピードをつけて前進することでボールに体当たりをする。ここでタッチセンサーに当てることで、タッチセンサーの物体が当たった時の反発を用いてスピードと飛距離を伸ばした。 ***ほかのグループの方法を見て ボールを車体に乗せて、ボールを保持している位置と地面との高低差を生かして、スロープを用いて転がして缶に当てるという方法は正直想像もしていなかったのでかなり驚き感動した。 *プログラムについて [#t8183ddf] **基本動作に関する定義 [#gd0a5a5e] #define THRESHOLD 54 [#o897b273] #define SPEED 30 #define speed 20 #define OnRL(speedR,speedL) OnFwd(OUT_B,speedR);OnFwd(OUT_C,speedL); #define LEFT OnRL(speed,-speed); #define left OnRL(speed,0); #define straight OnRL(SPEED,SPEED); #define right OnRL(0,speed); #define RIGHT OnRL(-speed,speed); #define STEP 1 #define nMAX 300 #define short_break Off(OUT_BC);Wait(1000); #define CROSS_TIME 700 #define cross_line OnFwd(OUT_BC,speed);Wait(CROSS_TIME);short_break; #define turn_time 3000 #define turn_left LEFT;Wait(turn_time);short_break; #define turn_right RIGHT;Wait(turn_time);short_break; #define kaiten OnRL(SPEED,-SPEED); #define kaiten_time 5500 #define arm_up OnRev(OUT_A,SPEED);Wait(500);Off(OUT_A); **まとまった動作に関する定義 [#ja1f6d69] ***ラインの右側トレース時に交差点を判断して一時停止した後横断するサブルーチン関数 [#u38f75b4] sub kousaten_trace() { SetSensorLight(S3); int nOnline=0; while (nOnline < nMAX) { //黒を認識した回数がnMAX(300)を越えたら交差点判断して横断 if (SENSOR_3 < THRESHOLD-10) { RIGHT; nOnline++;} else { if (SENSOR_3 < THRESHOLD-3) {right;} else if (SENSOR_3 < THRESHOLD+2) {straight;} else if (SENSOR_3 < THRESHOLD+6) {left;} else {LEFT;} nOnline=0;} Wait(STEP); } short_break; LEFT; Wait(nMAX*STEP); cross_line; nOnline=0; } ***ラインの左側トレース時に交差点を判断して一時停止した後右折するサブルーチン関数 [#h0f47ee3] sub kousaten_usetsu(){ SetSensorLight(S3); int nOnline=0; while (nOnline < nMAX) { //黒を認識した回数がnMAX(300)を越えたら交差点判断して横断 if (SENSOR_3 < THRESHOLD-8) { LEFT; nOnline++;} else { if (SENSOR_3 < THRESHOLD-3) {left;} else if (SENSOR_3 < THRESHOLD+2) {straight;} else if (SENSOR_3 < THRESHOLD+6) {right;} else {RIGHT;} nOnline=0;} Wait(STEP); } short_break; RIGHT; Wait(nMAX*STEP); turn_right; nOnline=0; } ***ラインの左側トレース時に交差点を判断したら1秒間停止した後再発進サブルーチン関数 [#o27cfc00] sub kousaten_teishi() { SetSensorLight(S3); int nOnline=0; while (nOnline < nMAX) { if (SENSOR_3 < THRESHOLD-8) { LEFT; nOnline++;} else { if (SENSOR_3 < THRESHOLD-3) {left;} else if (SENSOR_3 < THRESHOLD+2) {straight;} else if (SENSOR_3 < THRESHOLD+6) {right;} else {RIGHT;} nOnline=0;} Wait(STEP); } short_break; nOnline=0; } ***360°回転して障害物(缶)を見つけ出しその方向に向かうサブルーチン関数 [#z92ab83f] sub serch_kan() { SetSensorLowspeed(S4); long t10,t11; int L=10000; //仮の最小値 t10=CurrentTick(); //回転前の時刻 while(CurrentTick()-t10<=kaiten_time){ OnRL(speed,-speed); if(SensorUS(S4)<L) { L=SensorUS(S4); t11=CurrentTick()-t10; //仮の最小値より近いものを見つけた時の時間 } } OnRL(-speed,speed); Wait(kaiten_time-t11); Off(OUT_BC); } ***シュート(体当たり)をするサブルーチン関数 [#lb6d2652] sub shoot(){ arm_up; OnFwd(OUT_BC,100); Wait(200); Off(OUT_BC); } **今後このプログラムを簡単に、見やすく、効率的なものに書き換えるための追加のサブルーチン関数 [#k5ba6c27] ※このサブルーチン関数はチームで話し合われた結果、結局使用することはなかったのですが、用いることでより良いプログラムを作成できるのではないかと勝手に制作したものです。単なる自己満であり、今回のプログラムには含まれていません。 ***黒線の右側をトレースするサブルーチン関数[#mc631e28] sub line_trace_R() { while (true) { if(SENSOR_3<THRESHOLD-8){RIGHT;} else if(SENSOR_3<THRESHOLD-3){right;} else if(SENSOR_3<THRESHOLD+2){straight;} else if(SENSOR_3<THRESHOLD+6){left;} else{LEFT;} Wait(STEP); } ***黒線の左側をトレースするサブルーチン関数[#m060bc2b] sub line_trace_L() { while (true) { if(SENSOR_3<THRESHOLD-8){LEFT;} else if(SENSOR_3<THRESHOLD-3){left;} else if(SENSOR_3<THRESHOLD+2){straight;} else if(SENSOR_3<THRESHOLD+6){right;} else{RIGHT;} Wait(STEP); } ***黒線の右側トレース時に交差点で一時停止して横断するサブルーチン関数 [#z725f4b9] sub kousaten_trace_R() { SetSensorLight(S3); int nOnline=0; while (nOnline < nMAX) { if (SENSOR_3 < THRESHOLD-10) { RIGHT; nOnline++;} else { if (SENSOR_3 < THRESHOLD-3) {right;} else if (SENSOR_3 < THRESHOLD+2) {straight;} else if (SENSOR_3 < THRESHOLD+6) {left;} else {LEFT;} nOnline=0;} Wait(STEP); } short_break; LEFT; Wait(nMAX*STEP); cross_line; nOnline=0; } ***黒線の左側トレース時に交差点で一時停止して横断するサブルーチン関数[#j0b5a596] sub kousaten_trace_L() { SetSensorLight(S3); int nOnline=0; while (nOnline < nMAX) { if (SENSOR_3 < THRESHOLD-10) { LEFT; nOnline++;} else { if (SENSOR_3 < THRESHOLD-3) {left;} else if (SENSOR_3 < THRESHOLD+2) {straight;} else if (SENSOR_3 < THRESHOLD+6) {right;} else {RIGHT;} nOnline=0;} Wait(STEP); } short_break; RIGHT; Wait(nMAX*STEP); cross_line; nOnline=0; } ***黒線の右側トレース時に一時停止して左折するサブルーチン関数[#t6696adb] sub kousaten_sasetsu_R() { SetSensorLight(S3); int nOnline=0; while (nOnline < nMAX) { if (SENSOR_3 < THRESHOLD-8) { RIGHT; nOnline++;} else { if (SENSOR_3 < THRESHOLD-3) {right;} else if (SENSOR_3 < THRESHOLD+2) {straight;} else if (SENSOR_3 < THRESHOLD+6) {left;} else {LEFT;} nOnline=0;} Wait(STEP); } short_break; LEFT; Wait(nMAX*STEP); turn_left; nOnline=0; } ***黒線の左側トレース時に一時停止して右折するサブルーチン関数[#o0dd26fa] sub kousaten_usetsu_L() { SetSensorLight(S3); int nOnline=0; while (nOnline < nMAX) { if (SENSOR_3 < THRESHOLD-8) { LEFT; nOnline++;} else { if (SENSOR_3 < THRESHOLD-3) {left;} else if (SENSOR_3 < THRESHOLD+2) {straight;} else if (SENSOR_3 < THRESHOLD+6) {right;} else {RIGHT;} nOnline=0;} Wait(STEP); } short_break; RIGHT; Wait(nMAX*STEP); turn_right; nOnline=0; } **メインのプログラム [#g73aba0b] task main() { SetSensorLight(S3); SetSensorLowspeed(S4); long t0,t1,t2,t3; //それぞれの時間を定義 t0=CurrentTick(); //スタートした時間をt0とする while(CurrentTick()-t0<=15000){ //15秒間ライントレースをする if(SENSOR_3<THRESHOLD-8){RIGHT;} else if(SENSOR_3<THRESHOLD-3){right;} else if(SENSOR_3<THRESHOLD+2){straight;} else if(SENSOR_3<THRESHOLD+6){left;} else{LEFT;} Wait(STEP); } kousaten_trace(); //交差点Kを発見したら横断 t1=CurrentTick(); //K地点を横断したらその時間をt1とする while(CurrentTick()-t1<=15000){ //15秒間ライントレースをする if(SENSOR_3<THRESHOLD-8){RIGHT;} else if(SENSOR_3<THRESHOLD-3){right;} else if(SENSOR_3<THRESHOLD+2){straight;} else if(SENSOR_3<THRESHOLD+6){left;} else{LEFT;} Wait(STEP); } serch_kan(); //缶を探す。見つけたらボールに体当たりしてシュートする shoot(); t2=CurrentTick(); while(CurrentTick()-t2<=18000){ if(SENSOR_3<THRESHOLD-8){LEFT;} else if(SENSOR_3<THRESHOLD-3){left;} else if(SENSOR_3<THRESHOLD+2){straight;} else if(SENSOR_3<THRESHOLD+6){right;} else{RIGHT;} Wait(STEP); } kousaten_teishi(); //交差点Gを発見したら一時停止 t3=CurrentTick(); //地点Gを出発する時間をt3とする while(CurrentTick()-t3<=40000){ //40秒間ライントレースをする if(SENSOR_3<THRESHOLD-8){LEFT;} else if(SENSOR_3<THRESHOLD-3){left;} else if(SENSOR_3<THRESHOLD+2){straight;} else if(SENSOR_3<THRESHOLD+6){right;} else{RIGHT;} Wait(STEP); } kousaten_usetsu(); //交差点Eを発見したら右折 kousaten_trace(); //交差点Lを発見したら横断 OnFwd(OUT_BC,SPEED); 前進して枠内に入る Wait(2000); Off(OUT_BC); } **右側トレースと左側トレースの分割図 [#tf38eae7] #ref(IMG_4977_LI.jpg) **ライントレースのプログラムに関する説明 [#ha70b48b] 交差点判断をしないライントレースについては白から黒の色の値を白、白よりの灰色、灰色、黒よりの灰色、黒の五段階に分けそれぞれについて順に大きくライン側に旋回、ライン側に曲がる、スピードを出して直進、ラインから離れる方向に曲がる、ライン側から離れるように旋回という風にしてラインのどちらかをジグザグと移動するような形にした。 **プログラムに関する説明と反省 [#e79adcd4] 結局チームで話し合った結果、ラインの右側をトレースするサブルーチン関数しか用いなかった。個人的には両方用いたプログラムで動かしてみたかったので、プライベートで挑戦してみたい。 基本的にはタイマーで時間を計りながら交差点判断をするかしないかを決めている。そのためこのコースでしか使えないうえに想定した以上にスムーズに進んだり時間がかかったりしてしまうとコースを間違えてしまうためコースを完走しないことが多くなってしまった。 時間ではなく、タイヤの回転角などで距離を測りながら進むと今よりは成功率の高いプログラムになったのではないだろうか。また、task mainの中の時間を計測しながらのライントレースもサブルーチンとして簡略化できたなどの改善点も見つかった。 *感想 [#z1ea2fc1] 課題1の時と比べてかなりプログラムも改善されたとは思うが、まだ学んだことを最大限に生かし切れていないので課題3ではより高度なプログラムを作成したいと感じた。また、ジグザグ走行ではなく、よりラインに合わせてスムーズに動くロボットを制作したい気持ちが高まった。