[[2017b/Member]] #contents *初めに [#v99eb063] 今回の課題は、ライントレースを行い途中にある紙コップを決められた場所に移動させた後、目的地に向かうというものである。 &ref(2017b/Member/arso/Mission2/2017b-mission2.png,70%,コース); 図1:コースの全体図 自分は第2コースを選んだ。第2コースの経路は D ⇒ Cを直進 ⇒ Bを左折 ⇒ Pを左折(1秒停止) ⇒ Qを直進 ⇒ Rを左折 ⇒ Fを左折 ⇒ Sを直進(1秒停止) ⇒ Y地点の紙コップを取る ⇒ Sを直進(1秒停止) ⇒ Qを左折(1秒停止) ⇒ Rを直進 ⇒ X地点に紙コップを置く ⇒ Pを左折 ⇒ Bを左折(1秒停止) ⇒ A である。 *ロボットについて [#r5f4bb88] **ロボット全体 [#ie0ac42c] &ref(2017b/Member/arso/Mission2/DSCN1185.jpg,50%,ロボット全体); 写真1:ロボット全体 今回は二輪のロボットになっている。特筆すべき点は多くないが、部品も少なくコンパクトにまとまっている。 **ロボット本体 [#g61034e9] &ref(2017b/Member/arso/Mission2/DSCN1180.jpg,70%,ロボット本体); &ref(2017b/Member/arso/Mission2/DSCN1181.jpg,65%,光センサー); 写真2:ロボット本体 写真3:光センサー 使用部品はなるべく減らし軽量化した。特に光センサーの位置に気をつけ、なるべく機体に近づけることで、交差点での判断や移動をわかりやすくできるようにした。 **アーム部分 [#o1e3b114] &ref(2017b/Member/arso/Mission2/DSCN1190.jpg,70%,コップの取得及び配置のためのアーム); 写真4:アーム部分 紙コップを取るための腕は回転させて上下に動かす形式にした。ただ、本体との取り付け方がやや甘く外れやすくなってしまった(ライントレース時に外れるということはなかった)。 *プログラムについて [#nf157121] 今回のプログラムでは、アームのある方をロボットの前方としてモーターA,B,Cは以下のように対応している。 OUT_A //右側のタイヤ OUT_B //左側のタイヤ OUT_C //アーム プログラムは、ライントレース用とコップをとる用のサブルーチン、それらからなるメインルーチンで構成した。今回も引数を多用してしまった。 **定義 [#oe2e53dc] #define BLACK 30 //この数値以下を黒とする #define B_GRAY 37 //この数値を黒よりのしきい値とする #define W_GRAY 44 //この数値を白よりのしきい値とする #define WHITE 50 //この数値以上を白とする #define FAST 35 //モーターの強さ(強) #define SLOW 22 //モーターの強さ(弱) #define MOVE_ARM 25 //モーターの強さ #define On_Motor(vR,vL)OnFwd(OUT_A,vR);OnFwd(OUT_B,vL); //モーターA,BをそれぞれvR、vLの強さで動かす。 #define go_forward On_Motor(FAST,FAST); #define turn_sharp_left On_Motor(SLOW,-SLOW); #define turn_gently_left On_Motor(SLOW,0); #define turn_sharp_right On_Motor(-SLOW,SLOW); #define turn_gently_right On_Motor(0,SLOW); #define INTERSECTION_TIME 150 //交差点判断の時間 #define CURVE_TIME 50 //円形コースでの交差点判断の時間 #define FORWARD_TIME 300 //前進させる時間 **サブ関数 [#uf5dd655] ***ライントレース [#h0880967] sub line_trace(int blacktime,int stoptime,int fwdtime,int sharplefttime) //ライントレースのサブルーチン { SetSensorLight(S1); //光センサーを設定 long t0=CurrentTick(); //時間を測定 while(CurrentTick()-t0<blacktime){ //測定時間が(blacktime/1000)秒未満の間繰り返す if(SENSOR_1<BLACK){ //光センサーが得た値が黒未満のとき turn_sharp_left; //左旋回(この動作の間時間を測定) } else{ t0=CurrentTick(); //測定時間を初期化 if(SENSOR_1<B_GRAY){ //光センサーが得た値が黒以上黒寄りのしきい値未満のとき turn_gently_left; //左折 } else if(SENSOR_1<W_GRAY){ //光センサーが得た値が黒寄りのしきい値以上白寄りのしきい 値未満のとき go_forward; //前進 } else if(SENSOR_1<WHITE){ //光センサーが得た値が白寄りのしきい値以上白未満のとき turn_gently_right; //右折 } else{ //光センサーが得た値が白以上のとき turn_sharp_right; //右旋回 } } Wait(1); //0.001秒続ける } Off(OUT_AB); Wait(stoptime); //(stoptime/1000)秒間ロボットを停止 PlaySound(SOUND_CLICK); //音を鳴らす(交差点判断の合図) go_forward; Wait(fwdtime); //(fwdtime/1000)秒間前進 turn_sharp_left; Wait(sharplefttime); //(sharplefttime/1000)秒間左旋回 t0=CurrentTick(); //測定時間を初期化 } ***コップの取得とリリース [#s46bd0af] sub cop(int armpower,int turnrighttime,int turnlefttime) //コップの取得と配置のサブルーチン { turn_sharp_right; Wait(turntime); //(turnrighttime/1000)秒間右旋回 On_Motor(-FAST,-FAST); Wait(150); //モーターの強さ35で0.15秒間後退 OnFwd(OUT_C,armpower); Wait(400); //モーターの強さarmpowerで0.4秒間腕を回す On_Motor(FAST,FAST); Wait(160); //モーターの強さ35で0.16秒間前進 turn_sharp_left; Wait(turntime); //(turnlefttime/1000)秒間左旋回 PlaySound(SOUND_FAST_UP); //音を鳴らす(コップの取得または配置の合図) } **プログラム全体 [#k03ad36b] #define BLACK 30 #define B_GRAY 37 #define W_GRAY 44 //この数値以上を白とする #define FAST 35 //モーターの強さ(強) #define SLOW 22 //モーターの強さ(弱) #define MOVE_ARM 25 //モーターの強さ #define On_Motor(vR,vL)OnFwd(OUT_A,vR);OnFwd(OUT_B,vL); //モーターA,BをそれぞれvR、vLの強さで動かす。 #define go_forward On_Motor(FAST,FAST); //前進 #define turn_sharp_left On_Motor(SLOW,-SLOW); //左旋回 #define turn_gently_left On_Motor(SLOW,0); //左折 #define turn_sharp_right On_Motor(-SLOW,SLOW); //右旋回 #define turn_gently_right On_Motor(0,SLOW); //右折 #define INTERSECTION_TIME 150 //交差点判断の時間 #define CURVE_TIME 50 //円形コースでの交差点判断の時間 #define FORWARD_TIME 300 //前進させる時間 sub line_trace(int blacktime,int stoptime,int fwdtime,int sharplefttime) //ライントレースのサブルーチン { SetSensorLight(S1); //光センサーを設定 long t0=CurrentTick(); //時間を測定 while(CurrentTick()-t0<blacktime){ //測定時間が(blacktime/1000)秒未満の間繰り返す if(SENSOR_1<BLACK){ //光センサーが得た値が黒未満のとき turn_sharp_left; //左旋回(この動作の間時間を測定) } else{ t0=CurrentTick(); //測定時間を初期化 if(SENSOR_1<B_GRAY){ //光センサーが得た値が黒以上黒寄りのしきい値未満のとき turn_gently_left; //左折 } else if(SENSOR_1<W_GRAY){ //光センサーが得た値が黒寄りのしきい値以上白寄りのしきい 値未満のとき go_forward; //前進 } else if(SENSOR_1<WHITE){ //光センサーが得た値が白寄りのしきい値以上白未満のとき turn_gently_right; //右折 } else{ //光センサーが得た値が白以上のとき turn_sharp_right; //右旋回 } } Wait(1); //0.001秒続ける } Off(OUT_AB); Wait(stoptime); //(stoptime/1000)秒間ロボットを停止 PlaySound(SOUND_CLICK); //音を鳴らす(交差点判断の合図) go_forward; Wait(fwdtime); //(fwdtime/1000)秒間前進 turn_sharp_left; Wait(sharplefttime); //(sharplefttime/1000)秒間左旋回 t0=CurrentTick(); //測定時間を初期化 } sub cop(int armpower,int turnrighttime,int turnlefttime) //コップの取得と配置のサブルーチン { turn_sharp_right; Wait(turntime); //(turnrighttime/1000)秒間右旋回 On_Motor(-FAST,-FAST); Wait(150); //モーターの強さ35で0.15秒間後退 OnFwd(OUT_C,armpower); Wait(400); //モーターの強さarmpowerで0.4秒間腕を回す On_Motor(FAST,FAST); Wait(160); //モーターの強さ35で0.16秒間前進 turn_sharp_left; Wait(turntime); //(turnlefttime/1000)秒間左旋回 PlaySound(SOUND_FAST_UP); //音を鳴らす(コップの取得または配置の合図) } task main() { SetSensorLight(S1); //光センサーを設定 long t0=CurrentTick(); //時間を測定 PlaySound(SOUND_UP); //音を鳴らす(開始の合図) while(SENSOR_1>B_GRAY){ go_forward; //ラインを検知するまで前進 } line_trace(INTERSECTION_TIME,0,FORWARD_TIME,0); //(D地点)枠で0.3秒間前進 line_trace(INTERSECTION_TIME,0,FORWARD_TIME,0); //(C地点)交差点で0.3秒間前進 line_trace(INTERSECTION_TIME,0,200,1600); //(B地点)交差点で0.2秒間前進後1.6秒間左旋回 line_trace(CURVE_TIME,1000,FORWARD_TIME,1600); //(P地点)円形コースへの侵入前に1秒間止まり、0.3秒間前進した後1.6秒間左旋回 line_trace(CURVE_TIME,0,FORWARD_TIME,0); //(Q地点)交差点で0.2秒間前進 line_trace(CURVE_TIME,0,FORWARD_TIME,1600); //(R地点)交差点で0.3秒間前進後1.6秒間左旋回 line_trace(INTERSECTION_TIME,0,FORWARD_TIME,1600); //(E地点)交差点で0.3秒間前進後1.6秒間左旋回 line_trace(CURVE_TIME,0,0,300); //1度目のヘアピンカーブで0.3秒間左旋回 line_trace(INTERSECTION_TIME,0,FORWARD_TIME,1600); //(F地点)交差点で0.3秒間前進後1.6秒間左旋回 line_trace(INTERSECTION_TIME,1000,FORWARD_TIME,0); //(S地点)交差点で1秒間止まり、0.3秒間前進 cop(MOVE_ARM,1000,1100); //1秒間右旋回後前進し、モーターの強さ25で腕を下ろした後、後退して1.8秒間左旋回 line_trace(INTERSECTION_TIME,1000,FORWARD_TIME,0); //(S地点)交差点で1秒間止まり、0.2秒間前進後1.6秒間左旋回 line_trace(CURVE_TIME,,1000,FORWARD_TIME,1800); //(Q地点)円形コースへの侵入前に1秒間止まり、0.2秒間前進後1.6秒間左旋回 line_trace(CURVE_TIME,0,FORWARD_TIME,0); //(R地点)交差点で0.3秒間前進 line_trace(CURVE_TIME,0,FORWARD_TIME,1400); //(P地点)交差点で0.3秒間前進後1.4秒間左旋回 cop(-MOVE_ARM,3400,1800); //3.4秒間右旋回後前進し、モーターの強さ25で腕を上げた後、後退して1.8秒間左旋回 line_trace(INTERSECTION_TIME,0,200,1800); //前の旋回後、0.2秒間前進し1.7秒間左旋回してコースに復帰 line_trace(INTERSECTION_TIME,0,200,1700); //(B地点)交差点で1秒間止まり、0.2秒間前進後1.7秒間左旋回 line_trace(INTERSECTION_TIME,0,0,0); //(A地点)枠で停止 turn_sharp_right; Wait(200); //0.2秒間右旋回 go_forward; Wait(800); //0.8秒間前進 PlaySound(SOUND_FAST_UP); //音を鳴らす(ゴールの合図) } コップを手放した後にライントレースのサブルーチンを入れているのは、コップを離した後の右旋回でロボットの向きを左旋回の前の状態まで戻すと、右旋回の程度と前進や後退の距離によって光センサーがラインから離れてしまいコースに戻れなくなることがあった。そのため、右旋回の時間を半分ほどにして確実にラインに乗るようにしたが、その状態では交差点として検知してしまうので1回分サブルーチンを増やした。しかし、コースを離れてしまっても元に戻って再びライントレースができるようなプログラムを作ったり、一定時間ライントレースを続けるプログラムを作ったりするべきであったと考える。後者はヘアピンカーブでも使えるはずなので、1つのサブルーチンで全てをこなすよりわかりやすかったように考える。 *結果 [#j6b693d7] ライントレースや交差点判断は全て上手くいき、ヘアピンカーブも無事曲がることができた。しかし、紙コップを取るときにわずかにずれが出て引っかかった。だが、その後なんとか腕の中に入り事なきを得た。最終的には、紙コップを置くことにも成功し無事ゴール地点にたどり着くことができた。 *感想と反省 [#n0c0a044] ロボットについては、紙コップを取る腕は振り下ろす形式よりも横から挟むようにした方が、機体や紙コップの位置を気にせずにできてより安定したと考える。また、二輪にしたことが良かったのか悪かったのかはあまりわからなかった。プログラムについては、全ての交差点や円形の経路への進入、ヘアピンカーブなどを全て一つのサブルーチンで書いたが、引数を増やしすぎるという前回の課題のときと同じ失敗をしてしまった。ほかの人のプログラムを見るとサブルーチンやマクロを多用しておりその分のプログラムの増加があっても見やすいものだと思った。次回はサブルーチンやマクロを活用したプログラムを作れるように考えていきたい。