[[2016a/Member]] *今回の課題について [#b8f9634b] #ref(s_IMG_1335.PNG) ロボティクス入門ゼミ2つ目の課題は、ロボットにセンサーをつけ、黒い線の、与えられたコースに沿って走るロボットを作ることでした。コースは3種類あり、3人グループなので、1人1つコースを選んでプログラミングをすることになります。僕は1つ目のコースの、A地点からB地点へのコースを担当しました。コースについて説明します。A地点→P直進 →Q直進→Q直進→R左折→B地点というコースです。 *制作したロボットについて [#m8d3c615] #ref(s_IMG_1325.JPG) これが今回制作したロボットです。なるべくセンサーが地面に近く、より正確に黒線を読み取れるものを目指しました。 #ref(s_IMG_1323.JPG) ロボット本体と、センサーの部分を別にするとこのようになります。とてもシンプルです。 *今回の課題のポイントとそれに対する工夫 [#j6416d9d] プログラムについて説明する前に、今回の課題の難しい点と、それをどう解決したかについて説明します。 今回の課題で最も難しい点は、交差点をどのように攻略するかという点です。交差点では、交差点を認識したことの証として音を鳴らし、1秒間停止しなければなりません。その後、交差点を右折、左折、直進のどれかを行います。交差点を通過し、また走り始めるためには、センサーの位置が黒線上になければなりません。ロボットが毎回同じ動きをしてくれないことは前回の課題でよくわかっており、機体を旋回させて正確にセンサーを線上に移動させる自信は0だったので、ここである工夫をしました。 #define find_line turn_right1;until(SENSOR_1 < THRESHOLD);Off(OUT_AC); その工夫というのは、このfind_lineと定義されたものです。turn_right1については後程説明しますが、要するに右旋回です。find_lineとは、黒線が見つかるまで旋回し、センサーが線上に来たら止まるという優れものです。これをどのように使うかというと、 #ref(s_IMG_1328.JPG) まず、ロボットが交差点でこのように止まります。ここでは例として直進をさせたいと思います。、 cross_right2; find_line; cross_right2についてはまた後程説明しますが、要するに右旋回です。このようにすると、 #ref(s_IMG_1329.JPG) このようになります。cross_right2でセンサーが線外に出るまで旋回し、、find_lineで線上まで旋回します。これによって今回の課題に取り組む上での、ロボットの動きによる失敗が大幅に減ったと思います。 *カウンタについて [#bf2d0138] 交差点を判断する基準として、カウンタを使いました。例えば、カウンタをnと定義した時、nの値を決めておきます。センサーが線上にあるときの回数を数え、その回数がnを超えたときに交差点に差し掛かったと判断するようにしました。カウンタの決め方は、出発地点から交差点までの間に何度センサーが線上にあると判断するかを、カウンタの値を変えながら何度も試し、交差点から交差点の間1つ1つ調べて決めました。 *プログラムについて [#g92f8ce3] #define THRESHOLD 55 //白黒の境界 #define SPEED_H 50 #define SPEED_H2 45 #define SPEED_L 25 //3つの異なる速さ #define OnRL(speedR,speedL) OnFwd(OUT_A,speedR);OnFwd(OUT_C,speedL); #define go_forward OnRL(SPEED_H,SPEED_H); //直進 #define turn_left1 OnRL(SPEED_L,-SPEED_L); //その場で左旋回(速さのみ) #define turn_left0 OnRL(SPEED_L,0); //前進+左旋回(速さのみ) #define turn_left2 OnRL(SPEED_H2,0); //前進+左旋回2(速さのみ) #define turn_right0 OnRL(0,SPEED_L); //前進+右旋回(速さのみ) #define turn_right1 OnRL(-SPEED_L,SPEED_L); //その場で右旋回(速さのみ) #define turn_right2 OnRL(0,SPEED_H2); //前進+右旋回2(速さのみ) #define cross_right1 turn_right2;Wait(500);Off(OUT_AC); //右旋回(ロング) #define cross_right2 turn_right2;Wait(250);Off(OUT_AC); //右旋回(ショート) #define cross_left turn_left2;Wait(500);Off(OUT_AC); //左旋回 #define find_line turn_right1;until(SENSOR_1 < THRESHOLD);Off(OUT_AC); まずはdefineです。白黒の判断の基準となる値や、スピード、右旋回、左旋回、先ほど紹介したfind_lineなどを定義しました。cross_right2はfind_lineの説明に用いたもので、交差点を直進するときに使い、cross_right1は2より時間が長いため、交差点を右折するときに使います。 今回の課題に取り組むうえで、コースを5つに分け、5つのサブルーチンを作りました。「A地点→P直進」をCROSS1()、「P直進 →Q直進」をCROSS2()、「Q直進→Q直進」をCROSS3()、「Q直進→R左折」を CROSS4()、「R左折→B地点」をCROSS5()としました。 まずは「A地点→P直進」のCROSS1()について説明します。 sub CROSS1() { SetSensorLight(S1); //S1は光センサーである。 int n ; //続けて黒になった回(カウンタ)をnとする。 while(n < 4300) //nが4300以下のとき、 { if(SENSOR_1<THRESHOLD-15) { turn_left1; //線上なら、その場で左旋回 n++; //そして、カウンタを増やす。 } else if(SENSOR_1<THRESHOLD-7) { turn_left0; //少し白ければ、前進しながら左旋回 } else if(SENSOR_1<THRESHOLD+7) { go_forward; //境界付近(白黒半々)なら直進 } else if(SENSOR_1<THRESHOLD+15) { turn_right0; //少し黒ければ、前進しながら右旋回 } else { turn_right1; //それらのどれでもない場合(線上にないとき)、その場で右旋回 } } Float(OUT_AC); //カウンタが4300になったら、停止 PlaySound(SOUND_UP); //音を鳴らす。 Wait(400); //少し停止 cross_right2; //直進するために1度線の外へ。少し右旋回 find_line; //センサーを線の上へ n=0; //カウンタをリセット } 他のサブルーチンは交差点を右折、左折、直進のどれをするかを決める、最後の部分が違うだけなので、一応載せて説明はしますが、読んでも読まなくてもどっちでもいいです。 「P直進 →Q直進」のCROSS2() sub CROSS2() { SetSensorLight(S1); int j ; while(j < 6000) { if(SENSOR_1<THRESHOLD-15) { turn_left1; j++; } else if(SENSOR_1<THRESHOLD-7) { turn_left0; } else if(SENSOR_1<THRESHOLD+7) { go_forward; } else if(SENSOR_1<THRESHOLD+15) { turn_right0; } else { turn_right1; } } Float(OUT_AC); PlaySound(SOUND_UP); Wait(400); cross_right2; //大きく右旋回 j=0; } カウンタを表すアルファベットをjにしました。 「Q直進→Q直進」のCROSS3() sub CROSS3() { SetSensorLight(S1); int k ; while(k < 15000) { if(SENSOR_1<THRESHOLD-15) { turn_left1; k++; } else if(SENSOR_1<THRESHOLD-7) { turn_left0; } else if(SENSOR_1<THRESHOLD+7) { go_forward; } else if(SENSOR_1<THRESHOLD+15) { turn_right0; } else { turn_right1; } } Float(OUT_AC); PlaySound(SOUND_UP); Wait(400); cross_right2; find_line; k=0; } 今度はkにしました。 「Q直進→R左折」のCROSS4() sub CROSS4() { SetSensorLight(S1); int n ; while(n < 5300) { if(SENSOR_1<THRESHOLD-15) { turn_left1; n++; } else if(SENSOR_1<THRESHOLD-7) { turn_left0; } else if(SENSOR_1<THRESHOLD+7) { go_forward; } else if(SENSOR_1<THRESHOLD+15) { turn_right0; } else { turn_right1; } } Float(OUT_AC); PlaySound(SOUND_UP); Wait(400); n=0; } なぜかここでまたnです。なぜアルファベットを変えていたかというと、カウンタをリセットするときに、同じアルファベットだとリセットされないのではないかと思ったことがきっかけです。結果としては同じ文字でも問題がないことが分かったため、nが再登場しました。 「R左折→B地点」のCROSS5() sub CROSS5() { SetSensorLight(S1); int n ; while(n < 3000) { if(SENSOR_1<THRESHOLD-15) { turn_left1; n++; } else if(SENSOR_1<THRESHOLD-7) { turn_left0; } else if(SENSOR_1<THRESHOLD+7) { go_forward; } else if(SENSOR_1<THRESHOLD+15) { turn_right0; } else { turn_right1; } } Float(OUT_AC); PlaySound(SOUND_FAST_UP); Wait(400); go_forward; Wait(800); n=0; } 5つのサブルーチンの最後です。そして、それらを組み合わせたものが次のものです。 task main() { CROSS1(); Wait(1000); CROSS2(); Wait(1000); CROSS3(); Wait(1000); CROSS4(); Wait(1000); CROSS5(); Float(OUT_AC); } これで、A地点からB地点までロボットを走らせることができます。 *結果と感想 [#b74e7b3d] 今回作ったプログラムでロボットを走らせた結果、A地点からB地点までを51,70秒で走り終えました。他の班はどうか知りませんが、なかなか良いタイムではないかと思います。 今回の課題は前回の課題よりはやりやすいように感じました。最初はカウンタの使い方がわからず、苦戦しましたが、カウンタを使えるようになり、工夫をして、カウンタの値を調節することで、順調に課題を達成することができました。やり残したことといえば、タイムをもう少し縮められるようにすることくらいなので、とてもよくできたと思います。