今回の課題は積み上げられた缶を特定の場所へ移動させるもの。
ロボットはA,A'からスタートする。X,Yに三段に積み上げられたアルミ缶の一段目と三段目を反対側の円の中に移動させる。移動させた際、積み上げると加点が入る。
短い期間では、全てを積み上げるといった高度な動きを目指すのは危険と判断し、堅実に移動させることを目標とした。
二つのロボットに役割分担をさせている。一つ目のロボットが二段目をつかんでいる間にもう片方が一、三段目を引っ張り移動させる。
二段目をつかむためのロボット。センサーはついていないため、移動する距離、角度は一定である。
掴むための部分。ギアを使うことで左右同時に開閉する。
一、三段目をつかむためのロボット。一段目と三段目をつかむ機構はシャフトを介して連動するようになっている。一段目をつかめる高さにアームを調節するためNXT本体をひっくり返す形となっている。しかし、一段目と三段目が離れているためシャフトが離れたりして三段目をつかむ力が弱くなるなどの課題も出てきた。こちらは、超音波センサーがついているため動き出しの初めに積み上がっている缶を探す動作が入る。
二つのロボットを連携させて動かすため、無線通信によって動きを制御している。全体の流れとしては、二段目をつかむ→一、三段目を引き抜く→掴んでる二段目を離す→反対側へ移動し二段目をつかむ→掴んだ一、三段目を運ぶ→移動させた側の一、三段目を引き抜く→二段目離す→一。三段目移動となっている。
#define kail OnFwd(OUT_B,50);OnRev(OUT_C,50);Wait(500);Off(OUT_BC); //左折のマクロを定義 #define kair OnFwd(OUT_C,50);OnRev(OUT_B,50);Wait(500);Off(OUT_BC); //右折のマクロを定義 sub armc() { OnFwd(OUT_A,30); //アームを閉じる } sub armo() { OnRev(OUT_A,30); //アームを開く } sub zen(int i) { int t; t=i*50; OnFwd(OUT_B,50); OnFwd(OUT_C,49); Wait(t); Off(OUT_BC); } sub zeny(int i) { int t; t=i*100; OnFwd(OUT_B,25); OnFwd(OUT_C,25); Wait(t); Off(OUT_BC); } sub kou(int i) { int t; t=i*50; OnRev(OUT_B,50);OnRev(OUT_C,49); Wait(t); Off(OUT_BC); } task main() { int msg,frg1=1,frg2=1; zen(51); kair; zen(75); kair; zeny(20); armc();//xに移動 SendRemoteNumber(1,MAILBOX1,11);//送信 while(frg1){ ReceiveRemoteNumber(MAILBOX1,true,msg);//受信 if(msg==12){ armo(); kou(20); kair; zen(44); kail; zeny(20); armc();//yに移動 frg1=0; SendRemoteNumber(1,MAILBOX1,13);//送信 } } while(frg2){ ReceiveRemoteNumber(MAILBOX1,true,msg);//受信 if(msg==14){ armo(); frg2=0; } } }
アームを閉じるプログラムは、当初RotateMotorで行おうとしたが、缶を挟むと回転角が所定の角度まで足らなくなりそこでプログラムが止まってしまうという事態になってしまった。なのでアームを閉じるときはOnFwdで記述することにした。
#define SPEED 50 #define SPEED_SLOW 30 #define SPEED_H 40 #define SPEED_L 35 #define OnRL(speedR,speedL) OnFwd(OUT_B,speedR);OnFwd(OUT_C,speedL); #define go_forward OnRL(SPEED_H, SPEED_H); // 前進 #define turn_right1 OnRL(SPEED_L, -SPEED_L); // 右旋回 #define turn_right0 OnRL(SPEED_L, 0); // 右折 #define turn_left0 OnRL(0, SPEED_L); // 左折 #define turn_left1 OnRL(-SPEED_L, SPEED_L); // 左旋回
/* 空き缶を探して、空き缶の手前まで進むプログラム */ const float diameter = 5.45; // タイヤの直径(cm) const float track = 10.35; // タイヤのトレッド幅(cm) const float pi = 3.1415; // 円周率 void fwdDist(float d) // 距離 d cm 前進 { long angle; angle = d/(diameter*pi)*360.0; // 角度を計算する RotateMotorEx(OUT_BC, SPEED_SLOW, angle, 0, true, true); } void turnAng(long ang) // 角度 ang 度の時計回りの旋回 { long angle; angle = track/diameter * ang; RotateMotorEx(OUT_BC, SPEED_SLOW, angle, 100, true, true); } int searchDirection(long ang) // 現在の方向を中心にang度の範囲で探し // 障害物までの距離を返す { long angle,tacho_min=0, tacho_corr ; int d, d_min; d_min = 300; // 仮の最小値 angle = (track/diameter)*ang; // 旋回角度からタイヤの回転を計算 turnAng(ang/2); // 指定された角度の半分を旋回 ResetTachoCount(OUT_BC); // 角度計測をリセット OnFwdSync(OUT_BC,SPEED_SLOW,-100); // 反時計回りに旋回 while(MotorTachoCount(OUT_B)<=angle){ d = SensorUS(S1); // 現在の距離 if (d < d_min){ d_min = d; // 仮の最小値を更新 tacho_min = MotorTachoCount(OUT_B); // 仮の最小値を更新したときのモータの回 転角度 } } OnFwdSyncEx(OUT_BC,SPEED_SLOW,100,RESET_NONE); until(MotorTachoCount(OUT_B) <= tacho_min || SensorUS(S1) <= d_min); Wait(14); // 微調整 Off(OUT_BC);Wait(500); return d_min; OnFwd(OUT_C,30); OnRev(OUT_B,30); Wait(200); } task main() { int msg,frg1=1,frg2=1; while(frg1){ ReceiveRemoteNumber(MAILBOX1,true,msg); // MAILBOX1の値を受け取りmsgに格納 if(msg==11){ SetSensorLowspeed(S1); // 缶の方向を探した後、近づいて10cm手前で停止 int d = searchDirection(120); if (d > 10) { fwdDist(d-10.0); } OnFwd(OUT_B,30); OnFwd(OUT_C,30); Wait(500); Off(OUT_BC); Off(OUT_A); OnFwd(OUT_B,30); OnFwd(OUT_C,30); Wait(400); Off(OUT_BC); OnRev(OUT_A,30); Wait(1000); OnRev(OUT_BC,30); Wait(1000); Off(OUT_BC); SendResponseNumber(MAILBOX1,12); frg1=0; } } while(frg2){ ReceiveRemoteNumber(MAILBOX1,true,msg); // MAILBOX1の値を受け取りmsgに格納 if(msg==13){ turn_left1; Wait(600); Off(OUT_BC); OnFwd(OUT_B,40); OnFwd(OUT_C,40); Wait(3500); Off(OUT_BC); turn_right1; Wait(1000); Off(OUT_BC); OnFwd(OUT_BC,30); Wait(1000); Off(OUT_BC); OnFwd(OUT_A,30); Wait(500); Off(OUT_A); OnRev(OUT_BC,30); Wait(1000); Off(OUT_BC); turn_right1; Wait(800); Off(OUT_BC); OnFwd(OUT_B,30); OnFwd(OUT_C,30); Wait(500); Off(OUT_BC); turn_left1; Wait(1000); Off(OUT_BC); OnFwd(OUT_BC,30); Wait(2000); Off(OUT_BC); turn_left0; Wait(1000); Off(OUT_BC); OnRev(OUT_A,30); Wait(1000); OnRev(OUT_BC,30); Wait(1000); Off(OUT_BC); turn_right1; Wait(2000); Off(OUT_BC); go_forward; Wait(3500); Off(OUT_BC); OnFwd(OUT_A,30); Wait(1000); Off(OUT_A); SendResponseNumber(MAILBOX1,14); frg2=0; } } }
二段目を掴むロボットがずれてアルミ缶を倒してしまい、その後の動きが全て上手くいかず0点となった。
今度は二段目を掴むロボットは缶を掴むことができたが、もう片方のロボットがうまくいかず2点という結果に終わった。
技術点は平均12.2点で合計14.2点、順位は13組中7位となった。
グループメンバーの予定がうまく合わず、二つのロボットの動きを合わせる時間が少なく最高の出来とは、言えないが、時間のない中では最大限頑張れたと思う。可能であれば、もっと動きの検証をしたかった。 [#ycf14342]
この講義が私の初めてのプログラミングで、わからないことも多く、コンパイルに失敗しては何度も原因は何かと頭を悩ませた。ほんの少しの、それこそ一字の間違いでプログラムが動かなかったり、完璧だと思ったプログラムが動いたとしても望み通りの動きをしなかったりと、プログラミングの難しさをよく知ることができた。今回の経験を今後のプログラミングにぜひ生かしていきたいと思う。