[[2016b/Member]] 目次 #contents *課題 [#s530d136] **課題の内容 [#yc6819d1] 定められたコース上をライントレースし、道中でピンポン玉をキャッチしてゴールへシュートする。ただし、交差点では一秒間静止する。 **コース [#r1504dc3] 下図のコースを用いた、今回はAスタート→P直進→Q直進→Q直進→R右折→P直進→S左折→Dゴールのコースを進んだ。 #ref(2016b/Member/sennokiseki/Mission2/課題2コース.jpg,100%,コース) *機体 [#q9db8c0a] **全体 [#u002d445] -正確なライントレースをするため、できるだけコンパクトにしたほか、前輪駆動にして機体前部の振りを小さくした。後輪は前回の反省を活かして摩擦の少ないキャスターにした。 -全体的に強度を高めることに気を遣った。 #ref(2016b/Member/sennokiseki/Mission2/DSC_0045.JPG,100%,全体) -今回の機体でも持ち運びのために分解性は重視した。組み立て、分解が迅速にできる機体になった。 #ref(2016b/Member/sennokiseki/Mission2/DSC_0048.JPG,100%,分解) **ライトセンサー [#g967053f] -ライトセンサーはNXT本体とモーターの間のスペースを活用して取り付けたが、少し床からの位置が高かったため、誤検知の要因となってしまった。 **ピンポン玉のキャッチ [#tc76bcfd] -超音波センサーとピンポン玉をキャッチするための機構はまとめてNXT本体上部に取り付けた。しかしその結果モニターが非常に見づらくなり、苦労することになった。 -超音波センサーでピンポン玉を検知するとモーターが回転してピンポン玉をキャッチするようになっている。 #ref(2016b/Member/sennokiseki/Mission2/DSC_0046.JPG,100%,機体前部) *プログラム [#t2e3b7fb] **基本動作の定義 [#c4b5ed38] -まずは基本動作を定義した。TYOKUSHINではSyncによって両車輪の動作をリンクして、正確に直進するようにしている。TURNやSENKAI_Rでは、左右のモーターを逆に動かすことで機体を回転させている。 -TURN_LがTURN_Rよりパワーが強いのは、普通のカーブではできる限り黒い線から外れて、交差点を誤検知しないようにするためである。 -SENKAI_Rは急な右カーブを曲がりきるために作ったが、実際にはほとんど意味をなさなかった。 #define TYOKUSHIN OnFwdSync(OUT_BC,30,0); //直進する #define TURN_L OnFwd(OUT_B,50);OnRev(OUT_C,30); //左回転 #define TURN_R OnFwd(OUT_C,40);OnRev(OUT_B,10); //右回転 #define SENKAI_R OnFwd(OUT_C,50);OnRev(OUT_B,25); //右回転(強) -CROSSとつくものは全て交差点での動作である。交差点での右左折は正確に曲がってライントレースに復帰するために角度制御を用いている。 -CROSS_STOPにてOnRevSync(OUT_BC,50,100);と右回転しているが、これは交差点検知時に機体が左に傾いているのを真っ直ぐに戻すためである。 -CROSS_RにてOnFwdSync(OUT_BC,40,0);と前進しているが、これはラインの左側をトレースしているところ、右折時にラインの右側をとってしまうのを防ぐためである。 #define CROSS_GO OnFwdSync(OUT_BC,40,0);Wait(500); //交差点直進 #define CROSS_STOP Off(OUT_BC);Wait(1000);OnRevSync(OUT_BC,50,100);Wait(550);Off(OUT_ABC);Wait(200); //交差点一時停止 #define CROSS_L RotateMotorEx(OUT_BC,40,220,-100,true,true); //交差点左折 #define CROSS_R OnFwdSync(OUT_BC,40,0);Wait(400);RotateMotorEx(OUT_BC,40,180,100,true,true); //交差点右折 **ライントレース [#t0bba094] ***しきい値の定義 [#q91c994e] -機体の動作を切り換える境目となるしきい値を定義する。この値を少しでも変えるとトレースに大きな影響を及ぼすので慎重に調整したが結果的に非常にわかりやすい値に落ち着いた。 #define THRESHOLD_SR 50 //SENKAI_RとTURN_Rの境目(白強め) #define THRESHOLD_R 45 //TURN_RとTYOKUSHINの境目(白と黒が同じくらい) #define THRESHOLD_T 40 //TYOKUSHINとTURN_Lの境目(黒強め) ***ライントレースのプログラム(サブルーチン) [#a6110236] -トレースの動作をサブルーチンで作っていつでも呼べるようにしておく。 -基本の仕組みとしてはラインの左側を、ライトセンサーの値に対応してジグザグにトレースしていく。ごく簡単な言い方をすれば、黒の時は左回転、白の時は右回転することでトレースする。 -一定時間ライトセンサーがTHRESHOLD_T未満の値を検知し続けた時(ずっと黒)whileから外れる。条件を満たしていない間はwhile内を繰り返す。 -プログラム内のコメントにもあるように、sub TRACE の中にあるために載せてあるが、ボールのキャッチ動作に当たる部分については後で説明する。 sub TRACE() { long n=CurrentTick(); //nを現在時間と定義 while(CurrentTick()-n<570){ //その時の現在時間からnを引いた差が0.570秒未満の時while内のプログラムを繰り返す if(SENSOR_1>THRESHOLD_SR){ //ライトセンサーが指定したしきい値より大きい値を返した時if内のプログラムを実行(※) SENKAI_R; n=CurrentTick(); //nをリセットする } else if(SENSOR_1>THRESHOLD_R){ //(※) TURN_R; n=CurrentTick(); //nをリセットする } else if(SENSOR_1>THRESHOLD_T){ //(※) TYOKUSHIN; n=CurrentTick(); //nをリセットする } else { //上記if内の条件のどれにも当てはまらない時実行 TURN_L; } if(x==0){ //以降は「キャッチ」にて説明 if(SensorUS(S2)>17){ CATCH; GET_MUSIC(); OnFwdSync(OUT_BC,30,-100); Wait(300); x=x+1; n=CurrentTick(); } } } } **交差点検知 [#c1520078] - sub TRACE のwhileから外れると交差点と認識するようにしている(黒が多い)。 -mの値を交差点の数としている。(mは task main で定義している。「本文」参照。) CROSS_STOP; PlayTone(440,200); //交差点を検知した時に合図として音を鳴らす Wait(220); m = m +1; //交差点の数をカウント if(m>6){ //交差点の数が6を超えた時if内を実行 SHOOT(); //「シュート」参照 GOAL(); //ゴール時に鳴る音楽。載せはしないがサブルーチンで作った。 } else if(m==6){ //交差点の数が6の時if内を実行 CROSS_L; } else if(m==5){ //交差点の数が5の時if内を実行 CROSS_GO; } else if(m==4){ //交差点の数が4の時if内を実行 CROSS_R; } else { //交差点の数が3以下の時実行 CROSS_GO; } **ピンポン玉キャッチ&シュート [#sf263de1] ***超音波センサー [#o3e86ca0] -今回はピンポン玉をキャッチする際、検知に超音波センサーを用いた。 -床までの距離が17cmでピンポン玉を挟むと12cm程になるはずなので最初は if(SensorUS(S2)<13){ と書いたのだが、うまくいかなかった。 -うまくいかなかった原因として、ピンポン玉が曲面であるために超音波が真っ直ぐセンサーに返って来ず他の場所でも反射して戻ったことで、かえって長距離と認識したということが考えられる。実際17cmより大きい時ピンポン玉を検知すると書き換えたら成功した。 ***キャッチ [#yf7f732e] -まずはキャッチの動作自体を定義する。 #define CATCH Off(OUT_BC);Wait(500);OnFwd(OUT_A,40);Wait(600); -次に sub TRACE 内にピンポン玉キャッチのためのプログラムを書く。 -Aのモーターが二回以上動くのを防ぐための措置をとった。そこで使う関数xも定義する(他動作の定義のすぐ下で定義した)。 int x; if(x==0){ //ピンポン玉をキャッチするまで実行 if(SensorUS(S2)>17){ //超音波センサーがピンポン玉を検知した時実行 CATCH; //ピンポン玉キャッチ GET_MUSIC(); //キャッチ時に鳴る音楽。載せはしないがサブルーチンで作った。 OnFwdSync(OUT_BC,30,-100); //交差点誤検知防止のための軌道修正。しかし必要なかったと思われる Wait(300); x=x+1; //一度ピンポン玉をキャッチしたらそれ以上Aのモーターが動かないようにするための措置 n=CurrentTick(); //nをリセットする } } ***シュート (サブルーチン)[#v8fac765] sub SHOOT() { OnRevSync(OUT_BC,40,0); //7つ目の交差点から後退 Wait(1000); Off(OUT_BC); //シュートするためにその場で静止 Wait(400); RotateMotor(OUT_A,70,-60); //シュート } **本文 [#o28ad173] -重複はあるが本文は以下のようである。サブルーチンを用いたことで本文の分量は大部減らすことができた。 task main() { SetSensorLight(S1); //ライトセンサーをセット SetSensorLowspeed(S2); //超音波センサーをセット int m=0; //交差点の数を数えるための関数を定義 while(true){ //ずっと繰り返す TRACE(); CROSS_STOP; PlayTone(440,200); Wait(220); m = m +1; if(m>6){ SHOOT(); GOAL(); } else if(m==6){ CROSS_L; } else if(m==5){ CROSS_GO; } else if(m==4){ CROSS_R; } else { CROSS_GO; } } } **プログラムについての反省 [#sc90b45c] -SENKAI_Rがほとんど意味をなしてなかった。急カーブは曲がりきれたが、よりスムーズに曲がるためにはもう少ししきい値の調整をするべきだった。 -ボールキャッチ時の軌道修正然り、余分なところやもっとスマートにまとめられそうなところがあった。 *実演の結果 [#b2696d87] **成功 [#vf665e20] 発表時は二回目にして完璧に成功させることができた。 **失敗 [#vcb15851] 発表時一回目は途中交差点を検知しなかった。練習では一度も失敗しなかったところだったので予想外だった。 ***原因 [#j2eec63e] しきい値と回転の角度の調整の甘さということも考えられるが、一番の原因はライトセンサーの位置が高かったことだと思われる。 ***改善点 [#s2912cec] -ライトセンサーをもっと低い位置にする。 -発表時の失敗とは関係ないが、アームが重さに負けて降りてきてしまったり、モニターが見づらかったことから、アームと超音波センサーの機構の位置は変更すべきだった。 *反省と感想 [#xe5673ef]