*目次 [#pdbe1a7d] #contents *課題について [#s030a29a] 課題2は光センサーを使ったライン・トレース・ロボットの製作。 コースは以下の通り(課題2のページより) #ref(./コース.png,50%) -A地点からB地点へ (P三叉路およびQ交差点はともに直進) -B地点からA地点へ (Q交差点では直進、P三叉路では直進) -C地点からA地点へ (Q交差点では直進、P三叉路では右折) また、これらの経路の途中(PQ間)においたボールをゴールまで運ぶこと。三叉路および交差点では二秒間停止すること。 今回は、B地点からA地点のコースとする。 *ロボット本体について [#j1672ef1] &ref(./image1 (2).JPG,70%); &ref(./image2 (1).JPG,59%); &ref(./image3 (1).JPG,59%); ボールをつかむためにタッチセンサをつけると邪魔になりそうだったので、つけないことにした。 アームはモーターAで動かす。BCは移動用に使った。基本的な形は課題1ともそう変わらない。説明書にのっているものを基にした。タイヤより前に光センサーが付いていて、液晶の横にアームがついている。 アームは上からボールにかぶせる形にした。OnFwdでアームが下がり、OnRevで上がる(出力が正の値の時)。アームの幅は、ボールの直径とほぼ同じで、後ろ側によりボールをしっかり固定するための部品がついている。中央がアームを挙げた状態で、これでスタートする。右が下した状態。 *プログラムについて [#z4ee3701] **ライントレース1[#k3c8fb05] このプログラムは線の右側をライントレースし、交差点や三叉路を直進する。 交差点や三叉路の判定にはタイマーでもよかったがカウンターを使うことにした。ロボットが線上にあり、光センサーの値が小さいときが連続する場合、それがどれだけ連続するかを数え判定する。 定義 #define hikari 50 //光センサーの閾値で、これと実際に測った光センサーの値を比較しロボットの行動を決める #define SPEED1 55 //直進するときのスピード #define SPEED 25 //曲がるときのスピード #define turn_left OnFwd(OUT_B,SPEED);OnRev(OUT_C,SPEED); #define TURN_LEFT OnFwd(OUT_B,SPEED); #define go_forward OnFwd(OUT_BC,SPEED1); //ロボットの行動で、小回りだと小文字とした #define TURN_RIGHT OnFwd(OUT_C,SPEED); #define turn_right OnFwd(OUT_C,SPEED);OnRev(OUT_B,SPEED); #define STEP 1 //ライントレースの一回の判断の時間 #define nMAX 175 //カウンターでこれを超えると、交差点と判断 #define pose Off(OUT_BC);Wait(200); //交差点を判断した後の二秒停止のルール #define CROSS_TIME 200 #define cross_line OnFwd(OUT_BC,SPEED);Wait(CROSS_TIME);pose; //交差点を渡るプログラム プログラムの本文 task main() { SetSensorLight(S3); int nOnline=0; //交差点を判断するために使う while(true){ while(nOnline<nMAX){ //交差点でないとき if(SENSOR_3<hikari -7){ //光センサーの値が特に小さい(真っ黒である)ときは turn_right; //小回りをしてカウンターを回す(nMax以上真っ黒である時は、交差点と判断) nOnline++; }else{ //そのほかの時は if(SENSOR_3<hikari -3){ TURN_RIGHT; }else if(SENSOR_3<hikari +3){ //光センサーの値によりロボットの動きを変えつつ go_forward; //ライントレースをして、カウンターはリセット }else if(SENSOR_3<hikari +10){ TURN_LEFT; }else{ turn_left; } nOnline=0; } Wait(STEP); //STEPの間、上の動作をする } //ことをカウンターがnMaxに達するまで無限ループ pose; //カウンターがnMaxに達し、交差点と判断 turn_left;Wait(nMAX*STEP); //それまでにずれた分軌道を修正 cross_line; //交差点を渡る nOnline=0; //カウンターをリセットし、再びライントレースに戻れるようにする } } **ライントレース2 [#p10a79f3] 1を参考に改良しようと思った。 ライントレース1でロボットにコースを走らせてみた結果、早くライントレースさせるためには、コースを区間に区分し、それぞれに最適化するほうがよいと思った。というのも小回りでの左右の回転では、ロボットが進まないからである。そして、分けてしまえばその時には全く五段階である必要がなくなるので、光センサーの値を分けるのを二段階か三段階にして小回りさせる数を減らした。 また、直進go_forwardは直線の時には観察さず、時々カーブの時に直進して脱線しかけるという事態を招いたので、ライントレースからは削った。 定義 #define hikari 50 #define SPEED 25 #define SPEED1 35 #define turn_left OnFwd(OUT_B,SPEED);OnRev(OUT_C,SPEED1); #define TURN_LEFT OnFwd(OUT_B,SPEED1);Off(OUT_C); #define go_forward OnFwd(OUT_BC,SPEED1); #define TURN_RIGHT OnFwd(OUT_C,SPEED1);Off(OUT_B); #define turn_right OnRev(OUT_B,SPEED);OnFwd(OUT_C,SPEED); #define STEP1 5 //直線のときのライントレースの一回の判断の時間 #define STEP2 2 //曲線のときのライントレースの一回の判断の時間 #define nMax 70 //カウンターで真っ黒であると判断され回数がこれ以上の時交差点とする #define curve 100 //カウンターで真っ白であると判断された回数がこれ以上の時急カーブとする #define arm_down OnFwd(OUT_A,SPEED);Wait(300); //ボールをつかむプログラム #define shoot OnRev(OUT_BC,SPEED);Wait(1000);\ OnRev(OUT_A,SPEED);Wait(500);\ //ボールをシュートするプログラム OnFwd(OUT_BC,SPEED1);Wait(500); プログラムの本文 task main() { SetSensorLight(S4); int nOnline=0; //交差点の判断に使う。初期値を代入してnOnlineを使えるようにおく int nKousa=0; //交差点の回数を数えるのに使う int nMax_RIGHT=0; //急なカーブの判定に使う while(nOnline<nMax){ //�〆能蕕猟梢� if(SENSOR_4<hikari){ TURN_RIGHT; nOnline=0; //進行方向線の右側をなぞる }else{ TURN_LEFT; nOnline++; } Wait(STEP1); } turn_right;Wait(STEP1*nMax/2); //曲がり角を判定するまでにずれた分の修正 go_forward;Wait(560); //そのまま曲がると、光センサーがだいぶ線から外れてしまうので、少し前進させてから until(SENSOR_4<hikari){ turn_left; //線の右側まで回転させる } turn_left;Wait(200); //次から線の左側ををなぞるようにする(次の直進の後からでもよいが、曲がったついでに) nOnline=0; 最初の直線はロボットが曲がり角をまがった後、本体がなるべく次の直線をなぞりやすいような曲がり方をさせるために右側をなぞるようにした。 直線であるため、そう外れることはない。そのためロボットの行動は線上にある時左へ、線上にないとき右へ曲がるという2段階にした。 同様に外れにくいので一回の判断の時間STEPも5と大きめにとり、進みやすくした。 少し前に進んでから曲がることで、次のライントレースをしやすくした。 while(nOnline<nMax){ //�⊆,猟梢福D樟�であるため�,汎韻犬�2段階でSTEPが5 if(SENSOR_4<hikari){ TURN_LEFT; nOnline++; //線の左側をなぞる }else{ TURN_RIGHT; nOnline=0; } Wait(STEP1); } arm_down;Off(OUT_ABC);Wait(500); //交差点を判断したら TURN_RIGHT;Wait(STEP1*nMax); //ボールをつかむ nOnline=0; long t0=CurrentTick(); while(CurrentTick()-t0<9000){ //��左側をなぞったほうが緩くなるカーブ。コースの中で最も急 if(SENSOR_4<hikari){ TURN_LEFT; nMax_RIGHT=0; }else{ //線の左側をなぞる TURN_RIGHT; nMax_RIGHT++; } Wait(STEP2); if(nMax_RIGHT>curve){ until(SENSOR_4<hikari){ //カーブの半径のほうがタイヤの回転の半径より turn_right; //小さいので小回りさせる。このとき線上に来るまで回転させるため、nOnlineも0になり、適当な時間が来るまでライントレースに戻れる } } } until(SENSOR_4<hikari){ //カーブの終わりごろに TURN_RIGHT; } //次から線の右側をなぞるようにする turn_right;Wait(200); while(nKousa<2){ while(nOnline<nMax){ //�だ�の右側をなぞったほうが緩くなるカーブ(三叉路も、反対だと判定せずにそのまま通過してしまうので、直前の直線から右側をなぞらせている) if(SENSOR_4>hikari){ TURN_LEFT; nOnline=0; //線の右側をなぞる }else{ //カーブは緩いため、2段階でSTEPも5 TURN_RIGHT; nOnline++; } Wait(STEP1); } TURN_LEFT;Wait(STEP1*nMax);Off(OUT_BC); nKousa++; } shoot; //三叉路(一回目の交差点)は通過し、ゴールの周りの線を二回目の交差点と判断させてボールをシュートする } *感想 [#bfb90857] プログラムの1からみれば2は早くなったのではないかとも思うが、回転半径を小さくしてロボットのブレを減らし、出力を上げればもっと速くなると思う。あるいはどちらかのタイヤと、光センサーを近づければ、回転半径が左右で異なるので、左右の出力を変えてやればまた違うのではないかと思ったが、タイヤ間の距離を縮めたほうが早そうだと思った。 本体についてはまだある。二つのタイヤよりだいぶ前(真横から見てタイヤの接地面から5cmほど前)に光センサーがあるので、曲がり角も線から離れないというのは難しかった。 最近文字化けが多い気がする。