ボール運搬ロボット 以下のコースを移動し青と赤のボールを運搬して、それぞれ所定の350ml缶の上に乗せる
ロボットの全体像
後輪の2つのキャスター
ロボットの土台は付属の冊子に記載されているロボットを参考にしたのだが、課題3のロボットはNXT本体を2台も乗せるためキャスターにかかる負荷が大きかった。そのためキャスターを2つに増やし、負荷を軽減した。
ボールを掴む機構
制作初期の頃は下のような腕でボールを掴もうと考えていたのだが、この腕を取り付けるためにはどうしても斜めに設置することしかできなく、かなり正確に本体をボールに知被けなければうまくつかむことができなかった。そこで、上の写真のように手のひらを大きくすることで、少し距離に誤差があったとしても漏れることなく持ち上げることができる。
試作段階の腕
前方の2つのセンサー
ロボットの前面はセンサーや部品が集中しているため、超音波センサーの取り付けには苦労した。ロボットを制作しているときは、的となる缶だけでなくボールも超音波センサーで探すように考えていたため、センサーはかなり低く取り付け、少し下に傾けた。
#define UP OnFwd(OUT_B,20);Wait(4750);Off(OUT_BC); //腕上げ #define DOWN OnRev(OUT_B,20);Wait(2600);Off(OUT_BC); //腕下げ #define CATCH OnRev(OUT_C,15);Wait(725);Off(OUT_BC); //手掴み task main() { DOWN CATCH UP }
#define LOST OnFwd(OUT_C,15);Wait(685);Off(OUT_C); //手離す task main() { //ボールを持って腕は上がっている状態 LOST }
#define turn_l1 OnFwd(OUT_B,33);OnRev(OUT_C,33); //左旋回 #define turn_r1 OnFwd(OUT_C,33);OnRev(OUT_B,33); //右旋回 #define turn_l0 OnFwd(OUT_B,30);Off(OUT_C); //左折 #define turn_r0 Off(OUT_B);OnFwd(OUT_C,30); //右折 #define go_s OnFwd(OUT_BC,30); //直進 #define stoop Off(OUT_BC); //止まる #define speed 70 #define speed_s 50 #define CONN 1 const float diameter=5.54; const float track=10.35; const float pi=3.1415; void fwdDist(float d) { long angle; angle= d/(diameter*pi)*360.0; RotateMotorEx(OUT_BC,speed_s,angle,0,true,true); } void turnAng(long ang) { long angle; angle=track/diameter*ang; RotateMotorEx(OUT_BC,speed_s,angle,100,true,true); } int searchDirection(long ang) { long angle,tacho_min=0,tacho_corr; int d_min; d_min=500; angle=(track/diameter)*ang; turnAng(ang/2); ResetTachoCount(OUT_BC); OnFwdSync(OUT_BC,speed_s,-100); while(MotorTachoCount(OUT_B)<=angle){ if(SensorUS(S4)<d_min){ d_min=SensorUS(S4); tacho_min=MotorTachoCount(OUT_B); } } OnFwdSyncEx(OUT_BC,speed_s,100,RESET_NONE); until(MotorTachoCount(OUT_B)<=tacho_min||SensorUS(S4)<=d_min); Wait(14); Off(OUT_BC);Wait(500); return d_min; } void tuuzyou() { SetSensorLight(S1); //通常のライントレース long t0; t0=CurrentTick(); while(CurrentTick()-t0<90){ //交差点(黒が一定時間以上)につくまでライントレース if(SENSOR_1>58){ turn_r1; t0=CurrentTick(); }else if(SENSOR_1>53){ turn_r0; t0=CurrentTick(); }else if(SENSOR_1>44){ go_s; t0=CurrentTick(); }else if(SENSOR_1>34){ turn_l0; t0=CurrentTick(); //黒以外はt0をリセット }else{ turn_l1; } } } void massugu() //一定時間の直進 { turn_r1; Wait(150); go_s; Wait(1200); } void massugu2() //一定時間の直進 { turn_l1; Wait(400); go_s; Wait(2000); } void special() //特別なライントレース { SetSensorLight(S1); long t1; t1=CurrentTick() while(CurrentTick()-t1<23500){ //一定時間内は交差点を認識しない if(SENSOR_1>58){ turn_r1; }else if(SENSOR_1>53){ turn_r0; }else if(SENSOR_1>44){ go_s; }else if(SENSOR_1>34){ turn_l0; }else{ turn_l1; } } } void sirotuuzyou() //Dで止まるプログラム { SetSensorLight(S1); long t2; t2=CurrentTick(); while(CurrentTick()-t2<90){ //白を一定時間以上認識したら止まる if(SENSOR_1>58){ turn_r1; }else if(SENSOR_1>53){ turn_r0; t2=CurrentTick(); }else if(SENSOR_1>44){ go_s; t2=CurrentTick(); }else if(SENSOR_1>34){ turn_l0; t2=CurrentTick(); else{ turn_l1; t2=CurrentTick(); //白以外はt2をリセット } } } void gyakutuuzyou() //逆走する { SetSensorLight(S1); long t5; t5=CurrentTick(); while(CurrentTick()-t5<90){ if(SENSOR_1>56){ turn_l1; t5=CurrentTick(); }else if(SENSOR_1>51){ turn_l0; t5=CurrentTick(); }else if(SENSOR_1>42){ go_s; t5=CurrentTick(); }else if(SENSOR_1>34){ turn_r0; t5=CurrentTick(); }else{ turn_r1; } } } void gyakuspe() //DE間を「逆走」 { SetSensorLight(S1); long t6; t6=CurrentTick(); while(CurrentTick()-t6<6000){ //一定時間内は交差点を無視 if(SENSOR_1>58){ turn_l1; }else if(SENSOR_1>53){ turn_l0; }else if(SENSOR_1>44){ go_s; }else if(SENSOR_1>34){ turn_r0; }else{ turn_r1; } } } task main() //ボールを掴んだあと缶の位置を調べるプログラム { go_s; Wait(1000); stoop; RemoteStartProgram(CONN,"CATCH.rxe"); //通信によりボールを掴む Wait(9000); go_s; Wait(2000); special(); tuuzyou(); massugu(); sirotuuzyou(); SetSensorLowspeed(S4); int d=searchDirection(360); //位置を調べる if (d>13.5){ long t3,t4; t3=CurrentTick(); fwdDist(d-13.5); t4=CurrentTick(); stoop; RemoteStartProgram(CONN,"lost.rxe"); Wait(2000); OnRev(OUT_BC,30); Wait(t4-t3); } gyakuspe(); gyakutuuzyou(); go_s; Wait(700); stoop; RemoteStartProgram(CONN,"CATCH.rxe"); Wait(9000); SetSensorLowspeed(S4); int e=searchDirection(100); if (e>12){ fwdDist(e-12.0); RemoteStartProgram(CONN,"lost.rxe"); Wait(2000); stoop; } }
今回はロボットを今までの基礎を使わずに、1から作り直したこともあって政策に時間がかかった。また、プログラムにおいても、NXT同士の通信や、今までのライントレースの応用など難しいものが多かったように感じる。しかし、このゼミを通してロボットの動作において、いかにプログラミングが大事かということを学び、これからの工学部の授業や将来の仕事に役立てたいとおもいます。 また、前日までプログラムやロボットの調整をしていてギリギリになってしまい、余裕をもって全体の調整をすることができなかったのが残念だった。