目次
課題は指定されたルートに沿ってロボットをライントレースさせるというもので、具体的には、
という動きである。
(2014年後期/課題2より)
NXCの前に光センサを取り付けたシンプルな構造である。 この光センサによって白と黒の判断をさせることが出来る。
また、小回りを利かせるためにパーツ1つ分だけ光センサをNXCに近づけた。
今回私はタイマー機能を使って区間ごとにプログラムを変え、ロボットにライントレースをさせた。ライントレースさせるためのプログラムは主に黒い線(の境界線)に沿って動くプログラム、白黒のプログラムより滑らかに動くプログラム、交差点を渡るプログラムである。滑らかに動くプログラムは交差点のプログラムに含まれている。
また、小タイトル後の()内はそのプログラムの略称を示している。
プログラミング方法は、ある基準となる時刻を記憶しておき、その時刻と現在との差を計算するという方法である。
測る直前の時刻をlong型の変数t0(t1、t2、…など複数の変数を使用することで、途中の段階でもタイマー機能を使用することが出来る)に代入して今後はこのt0を基準に時間測定をする。
long t0=CurrentTick(); //CurrentTick()で現在の時刻が得られる
while(CurrentTick()-t0<=○){ … } //CurrentTick()とt0の差が○以下の時だけ{}内を繰り返し(○の部分に時間を記入する)
ラインに沿ってロボットをライントレースをするための一般的なプログラム。
方法として、光センサが白い部分に差し掛かったら黒い線へ、黒い線の上なら白い方へと動かすというシンプルな方法を用いた。
#define SPEED 53 #define THRESHOLD 45 #define turn_left3 OnFwd(OUT_B,SPEED);Off(OUT_C); //左折 #define turn_right3 Off(OUT_B);OnFwd(OUT_C,SPEED); //右折 #define STEP 1
task main() { SetSensorLight(S3); while(タイマー){ if(SENSOR_3<THRESHOLD){ turn_left3 //黒線上なら左折 }else{ turn_right3 //白い部分なら右折 } Wait(STEP); }
白黒のプログラムをもっと滑らかに進ませるために工夫したプログラム。 一般に、交差点を渡るために下のようなプログラムが使用される。
#define THRESHOLD 45 //仕切り値 #define SPEED_H1 60 //直進する用の速さ #define SPEED_L 30 //カーブ用の速さ #define OnRL(speedR,speedL) OnFwd(OUT_B,speedR);OnFwd(OUT_C,speedL); #define go_forward OnRL(SPEED_H1,SPEED_H1); //直進 #define turn_left1 OnRL(SPEED_L,-SPEED_L); //左旋回 #define turn_left0 OnRL(SPEED_L,0); //左折 #define turn_right0 OnRL(0,SPEED_L); //右折 #define turn_right1 OnRL(-SPEED_L,SPEED_L); //右旋回 #define STEP 1 //一回の判断で動く時間 #define nMAX 100 //繰り返しの最大値 #define short_break Off(OUT_BC);Wait(1000); //小休止 #define CROSS_TIME 200 //交差点通過にかかる時間 #define cross_line OnRL(SPEED_L,SPEED_L);Wait(CROSS_TIME);short_break; //交差点を渡る
task main() { SetSensorLight(S3); int nOnline=0 while(タイマー){
while(nOnline<nMAX){ //黒を続けてnMAX回繰り返さない間、スムーズな動きのライントレースをする。 if(SENSOR_3<THRESHOLD-12){ turn_left1; //33以下なら左旋回 nOnline++; //カウンタを増やす }else{ if(SENSOR_3<THRESHOLD-7){ turn_left0; //38以下なら左折 }else if(SENSOR_3<THRESHOLD+7){ go_forward; //52以上なら直進 }else if(SENSOR_3<THRESHOLD+13){ turn_right0; //58以上なら右折 }else{ turn_right1; //上記以外なら右旋回 } nOnline=0; //カウンタをリセット } Wait(STEP); }
short_break; turn_right1;Wait(nMAX*STEP); cross_line; //交差点を渡る nOnline=0; //カウンタをリセット }
私が一番苦労したことは、ロボットがちゃんとライントレースをしてくれないということである。と、いうのは、資料通りのプログラムなら交差点に差し掛かった際、ライン上に沿ってロボットは進もうとするため、右または左に曲がってしまい工夫を施して交差点で直進出来るようにしなければならない。しかし私のロボットは例題のプログラムにしても交差点を直進してしまう。つまり、ちゃんと線に沿って進んでいないということである。
これを改善しようと光センサの値やスピードを変えるなどの工夫をしたものの、交差点で直進してしまうのは変わらなかった。しかし、他の班のロボットとレースで私のプログラムを使用したところ、ちゃんと線に沿ってくれ、交差点部分で右または左に沿うように進んでくれた。このことから、私の班のレース(線)の交差点に何らかの不具合があることが分かった。
レース自体を書き直すわけにはいかない為、プログラミングで交差点に差し掛かったら左右に向きを変えるよう調整した。その方法として、交差点を渡るためのプログラムを応用して、何度も何度も左に繰り返し、連続した黒の点がある数を超えると右または左に旋回するというプログラムを作ろうとした。しかし、上手くいかなかったため、交差点を渡るためのプログラムをロボットに実際に動かせ、ストップウォッチで交差点に差し掛かるまでの時間を計り、その時間を使ってタイマー機能によって、交差点に差し掛かった時間になったら右または左に旋回させるというプログラミングを作ったところ、上手く左右へ曲がれるようになったため、このプログラムを使うことにした。
ロボットにライントレースをさせるために4つのパターンを考え、4つ目のプログラムがライントレースを成功させることが出来た。
1~3パターン目のプログラムでは、失敗した理由と改善点を説明する。
交差点(18s)→左旋回(黒線にかかるまで)→交差点(27s)→右旋回(黒線にかかるまで)→交差点(18s)
始め課題のライントレースのプログラムを作るとき、交差点と旋回のプログラムだけで作ろうとしたところ、交差点のプログラムの中に直進するプログラムを入れていたせいで、大きなカーブを曲がる際に途中で脱線してしまい、違うところへ進んでしまうということが多く発生したため、大きなカーブを曲がる際は確実に曲がれる白黒のプログラムを使用することにした。
交差点(10s)→白黒(10s)→左旋回(黒線にかかるまで)→交差点(10s)→右旋回(黒線にかかるまで)→交差点(18s)
パターン1のプログラムの問題点を改善することが出来た。しかし、このプログラムで時間調整していた途中に電池を交換したところ、交差点のプログラム部分が暴走し始め、黒い線の上など関係なしに進み始めたためスピードを速くなることよりも確実さを重視することにした。
白黒(21s)→左旋回(黒線にかかるまで)→白黒(20s)→右旋回(黒線にかかるまで)→白黒(10s)→右旋回(黒線にかかるまで)→白黒(30s)
白黒のプログラムの方が安定で確実にライントレースをするため、一度速さのことを忘れ、指示通りに進んでくれる可能性が高いプログラムにすることにした。そのため、時間もずれることも考え微調整を行っていたところ、旋回する部分で今までは気にかからなかったのだが、時間が過ぎても旋回をせずに交差点を渡ることが多々あった。
その理由として今までは、旋回を行う時間をuntil(THRESHOLD_3<THRESHOLD-7)とやっていた。つまり黒線にかかるまで旋回をするということであるが、これではもし旋回をする時間になった時にすでに黒線上に光センサがある場合、旋回をせずに次のプログラムを実行してしまうのだ。
旋回を確実に行うためにもWaitを用いて、この問題を解決させた。
白黒(21s)→左旋回(0.8s)→白黒(20s)→右旋回(0.8s)→白黒(10s)→右旋回(0.8s)→白黒(30s)
#define SPEED 53 #define THRESHOLD 45 #define SPEED_L 30 #define OnRL(speedR,speedL) OnFwd(OUT_B,speedR);OnFwd(OUT_C,speedL); #define turn_left1 OnRL(SPEED_L,-SPEED_L); #define turn_right1 OnRL(-SPEED_L,SPEED_L); #define turn_left3 OnFwd(OUT_B,SPEED);Off(OUT_C); #define turn_right3 Off(OUT_B);OnFwd(OUT_C,SPEED); #define STEP 1
task main() { SetSensorLight(S3);
long t0=CurrentTick(); while(CurrentTick()-t0<=21000){ 21秒間白黒 if(SENSOR_3<THRESHOLD){ turn_left3 }else{ turn_right3 } Wait(STEP); }
turn_left1; 0.8秒間白黒 Wait(800);
long t1=CurrentTick(); while(CurrentTick()-t1<=20000){ 20秒間白黒 if(SENSOR_3<THRESHOLD){ turn_left3 }else{ turn_right3 } Wait(STEP); }
turn_right1; Wait(800); //0.8秒間右旋回
long t2=CurrentTick(); while(CurrentTick()-t2<=10000){ //10秒間白黒 if(SENSOR_3<THRESHOLD){ turn_left3 }else{ turn_right3 } Wait(STEP); }
turn_right1; Wait(800); //0.8秒右旋回
long t3=CurrentTick(); while(CurrentTick()-t3<=50000){ //50秒間白黒 if(SENSOR_3<THRESHOLD){ turn_left3 }else{ turn_right3 } Wait(STEP); } }
プログラム自体はそんなに長いものではなく、おおまかなプログラムを作るはほぼ参考冊子に載っているものとそんなに変わらないため時間はかからなかった。しかし、私が今回タイマーを使用したことによって微調節の繰り返しを行わなければならなくなってしまった。長いこと微調節していると電池の残量が減ってきて出力が変わり、最初に調整した部分をもう一度やり直すことが多々起こった。時間を使ってプログラムを作ると長い時間プログラムを実行するものほど誤差が生じやすいということが分かった。