[[2019a/Member]]

*課題について [#j84d3ca0]
詳しくはリンクを参照2019a/Mission3

*ロボットについて [#facc07ea]
今回のロボットは,2つのNXTを通信させることでモーターを4つ使用できるようにし,2つを移動用,2つをボールをキャッチするアーム用とすることでスムーズに動くように工夫した.
全体図は以下の通り



&ref(2019a/Member/Asahi/Mission3/IMG_1866.JPG,50%,�ゝ々�);




&ref(2019a/Member/Asahi/Mission3/IMG_1864.JPG,50%,�ゝ々�);



**センサーの取り付け位置について [#sb6dc43f]
センサーを取り付ける際,タイヤから離れすぎないようにした.軸から遠すぎるとライントレースを行う際,支障が出るからだ.さらに,センサーがしっかりと認識できるように垂直に取り付けた.

**アームについて [#y1753b87]
今回はボールをつかむための方法として,アームを採用した.1つのモーターをアームを閉じたり,開いたりすることに使い,もう一つのモーターでアームの上下を調節した.この時,大きいギアと小さいギアを組み合わせることによってアームを上げた際,アーム自体の重さで下がるということを防いだ.

*プログラムについて [#i014699a]
このロボットは,2つのNXT(マスター側とスレイブ側)で通信を行い,マスター側は機体の移動,スレイブ側はアームの開閉・上下をそれぞれ担当している.

**マスターのプログラム [#j6999681]
***定義 [#tbc2f6b5]
まず,以下のように定義した.
 #define black 30                                         //完全に黒のときの値
 #define white 50                                         //完全に白のときの値
 #define speedH 60                                        //速いスピード
 #define speedL 30                                        //遅いスピード
 #define speedM 20                                        //逆回転ときのスピード
 #define mae OnFwd(OUT_BC,speedH);                        //前進の動作
 #define ushiro OnRev(OUT_BC,speedH);                     //後退の動作
 #define turnRRR OnFwd(OUT_C,speedH);OnRev(OUT_B,speedM); //一番キツい右曲がり
 #define turnLLL OnFwd(OUT_C,speedH);OnRev(OUT_C,speedM); //一番キツい左曲がり
 #define turnRR OnFwd(OUT_C,speedH);Off(OUT_B);           //右曲がり
 #define turnLL OnFwd(OUT_B,speedH);Off(OUT_C);           //左曲がり
 #define turnR OnFwd(OUT_C,speedH);OnFwd(OUT_B,speedL);   //緩めの右曲がり
 #define turnL OnFwd(OUT_B,speedH);OnFwd(OUT_C,speedL);   //緩めの左曲がり
 #define step 1                                           //ライントレースの動作時間
 #define jikan 100                     //完全に黒で居続けられる時間の最大値(しきい値)
 #define teishi Off(OUT_BC);Wait(300);                    //一時停止
 #define CONN 1                                           //スレイブの番号
 #define SIGNAL1 11                                       //スレイブに送る信号の番号
 #define SIGNAL2 12                                       //同上
 #define SIGNAL3 13                                       //同上
 #define SIGNAL4 14                                       //同上
 #define curveL OnFwd(OUT_B,20);OnRev(OUT_C,10);          //左に回転してカーブする動作

***直線のライントレース(交差点に差し掛かるとループから抜ける)のサブルーチン [#g929b9c4]
光センサーが指定した時間以上,黒と測定したら止まるようにプログラムされている.
void linetraceS()                      //完全に黒がjikan以上だったら外れる
{
    long t0=0,t_black=0,t_max=jikan;

    t0=CurrentTick();                  
    while(t_black<t_max){        //t_blackがt_maxの値より大きくなったらループから抜ける
        if(SENSOR_3>white){            //完全に白のとき
         turnRR;                       //右曲がり
        } else if(SENSOR_3>white-5){   //白よりの灰色のとき
         turnR;                        //緩い右曲がり
        } else if(SENSOR_3>black+5){   //灰色のとき
         mae;                          //前進
        } else if(SENSOR_3>black){     //黒寄りの灰色のとき
         turnL;                        //緩い左曲がり
        } else{                        //完全に黒のとき
         turnLL;                       //左曲がり
         t0=CurrentTick();             //現在時間をt0とする(時間を測り始める)
         until((SENSOR_3<black+5)&&(SENSOR_3>black));//黒寄りの灰色になるまで測り続ける
         t_black=CurrentTick()-t0;     //現在時刻からt0の値を引いたもの
        }
     Wait(step);
    }
}
***カーブのときのライントレース(交差点に差し掛かるとループから抜ける)のサブルーチン [#zf0d28b1]
基本的には直線の時のサブルーチンと似ているが,カーブの時に直線のサブルーチンで行うと曲がるのがきつすぎて上手くライントレース出来なかったので,曲がるときにタイヤに逆回転を加えたのをこの時のライントレースとした.

void linetraceS()                      //完全に黒がjikan以上だったら外れる
{
    long t0=0,t_black=0,t_max=jikan;

    t0=CurrentTick();                  
    while(t_black<t_max){        //t_blackがt_maxの値より大きくなったらループから抜ける
        if(SENSOR_3>white){            //完全に白のとき
         turnRRR;                      //キツい右曲がり
        } else if(SENSOR_3>white-5){   //白よりの灰色のとき
         turnRR;                       //右曲がり
        } else if(SENSOR_3>black+5){   //灰色のとき
         mae;                          //前進
        } else if(SENSOR_3>black){     //黒寄りの灰色のとき
         turnLL;                       //左曲がり
        } else{                        //完全に黒のとき
         turnLLL;                      //キツい左曲がり
         t0=CurrentTick();             //現在時間をt0とする(時間を測り始める)
         until((SENSOR_3<black+5)&&(SENSOR_3>black));//黒寄りの灰色になるまで測り続ける
         t_black=CurrentTick()-t0;     //現在時刻からt0の値を引いたもの
        }
     Wait(step);
    }
}

***交差点を直進して突破するサブルーチン [#o8048ad6]
交差点で止まり.を突破するために,まず白よりの灰色になるまで前進しその後黒寄りの灰色になるまで右曲がりを続けるというプログラムを組んだ.
 void crossline()
 {
     mae;                    //前進
     until(SENSOR_3>white-5);//白よりのグレーまで
     turnRR;                 //右曲がり
     until(SENSOR_3<black);  //黒寄りのグレーまで
 }

***交差点を曲がるサブルーチン [#x185dbc5]
・右に曲がるときのサブルーチン
 void Rcurve()
 {
     turnRRR;                //キツい右曲がり       
     until(SENSOR_3>white);  //完全に白になるまで
 }

・左に曲がるときのサブルーチン
 void Lcurve()
 {
     curveL;                 //左曲がり
     until(SENSOR_3>white);  //完全に白になるまで
 }

***回転するサブルーチン [#a4669234]
コースのL・L'の地点において,ボールを掴んだあと道を引き返す際回転するサブルーチン
 void kaiten()
 {
     mae;                               
     Wait(900);                         
     OnFwd(OUT_C,20);OnRev(OUT_B,10);   
     until(SENSOR_3<black+5);          
 } 


***ボールを掴む・離す際のサブルーチン(マスター側) [#w18c5592]
・ボールを掴む際のサブルーチン
掴む際マスターとスレイブでやり取りする信号をmsg1としてそこにSIGNAL1(ここではボール前についたことを知らせる信号),SIGNAL2(ここでは掴む動作が終了したことを知らせる信号)を代入し,それをMAILBOX1を通してやり取りしている.
 void catch()
 {
    int msg1;                                    //msg1を定義する

    SendRemoteNumber(CONN,MAILBOX1,SIGNAL1);     //CONN(ここではスレイブ1)にMAILX1を通 
                                                   してSIGNAL1(ここではボール前についた 
                                                    ことを知らせる信号)を送信する
    while(msg1!=SIGNAL2){                        //msg1の値がSIGNAL2(ここでは掴む動作が 
                                                   終了したことを知らせる信号)になった 
                                                   らループを抜ける
        ReceiveRemoteNumber(MAILBOX1,true,msg1); //MAILBOX1でスレイブから信号を受け取る
        Off(OUT_BC);                             //ループの間(掴む動作が終了したことを 
                                                   知らせる信号がスレイブから帰ってくる 
                                                   まで)機体を停止させる
     
 }

・ボールを離す際のサブルーチン

離す際マスターとスレイブでやり取りする信号をmsg2としてそこにSIGNAL3(ここではゴールの箱の前についたことを知らせる信号),SIGNAL4(ここではボールを離す動作が終了したことを知らせる信号)を代入し,それをMAILBOX2を通してやり取りしている.
 void release()
 {
    int msg2;                                   //msg2を定義する

    SendRemoteNumber(CONN,MAILBOX2,SIGNAL3);    //スレイブにMAILBOX2を通してSIGNAL3(こ 
                                                  こではゴールの箱の前についたことを知 
                                                  らせる信号)を送信する
    while(msg2!=SIGNAL4){                       //msg2の値がSIGNAL4(ここではボールを離 
                                                  す動作が終了したことを知らせる信号)に 
                                                  なったらループを抜ける
        ReceiveRemoteNumber(MAILBOX2,true,msg2);//MAILBOX2でスレイブから信号を受け取る
        Off(OUT_BC);                            //ループの間(離す動作が終了したことを 
                                                   知らせる信号がスレイブから帰ってくる 
                                                   まで)機体を停止させる
     }  
 }


*プログラム全体 [#f6a316a5]
今回の課題では,箱の中のボールを1つ,L,L'の地点の ボールをそれぞれ取ることにした.
 task main()
 {
     SetSensorLight(S3);


     mae;       //前進
     Wait(300);
     linetraceC();    //M to K
     Lcurve();    //箱の方に向きを変える
     linetraceC();    //K to J
     OnRev(OUT_C,speedL);    //向きの微調整
     Wait(500);    //上に同じ
     catch();    //ボールを掴む
     linetraceC();    //J to I
     Lcurve();    //Iの方に向きを変える
     linetraceC();    //I to C
     Lcurve();    //Bの方に向きを変える
     linetraceS();    //C to B
     Rcurve();    //中央の線の方に向きを変える
     linetraceC();    //B to 中央の線
     Rcurve();    //A'の方に向きを変える
     linetraceS();    //to A'
     Lcurve();    //B'の方に向きを変える
     linetraceC();    //to B'
     Lcurve();    //C'の方に向きを変える
     linetraceS();    //B' to D'
     Rcurve();    //H'の方に向きを変える
     linetraceC();    //D' to H'
     OnRev(OUT_C,speedL);    //向きの微調整
     Wait(500);    //上に同じ
     release();    //ボールをはなす
     ushiro;//2つ目のボール
     Wait(2000);
     OnFwd(OUT_C,20);OnRev(OUT_B,10);
     until(SENSOR_3>white-5);
     linetraceC(); //C' to D'
     crossline(); //交差点を渡る
     linetraceS();//B' to C'
     Lcurve(); //左に曲がる
     linetraceS();//M' to B'
     Rcurve();//右に曲がる
     linetraceS();//M' to B'
     Lcurve(); //向きを変える
     linetraceC();// K' to M'
     crossline();//交差点を渡る
     OnFwd(OUT_BC,30);Wait(2900);Off(OUT_BC);//L' to K'
     catch();//L'のボールを掴む
     OnRev(OUT_BC,30);Wait(2900);Off(OUT_BC);//K' to L'
     Lcurve();//J'の方に向きを変える
     linetraceS();//J' to K'
     release();//L'のボールを離す
     ushiro;//3つ目のボール
     Wait(2000);
     OnFwd(OUT_C,20);OnRev(OUT_B,10);
     until(SENSOR_3>white-5);
     linetraceC();//M' to K'
     Rcurve();//向きを変える
     linetraceS();//B' to M'
      Rcurve();//向きを変える
     linetraceS();//B' to M'
     Lcurve();//向きを変える
     linetraceS();//B' to M'
     crossline();//交差点を渡る
     linetraceS();//紙の境界まで進む
     Lcurve();//向きを変える
     linetraceC();//to B
     crossline(); //  K   
     linetraceS();  //K to L      
     Wait(2900);          
     catch(); //Lでボールを掴む             
     kaiten();//Lで回転            
     linetraceC();//L to M
     Rcurve();//M
     linetraceS();//toBとMの間の角
     Lcurve();//BとMの間の角
     linetraceS(); //to二枚の間の線に差し掛かるところ
     Rcurve();//二枚の間の線に差し掛かるところ
     linetraceS();//間の線上
     Lcurve();//間の先から左のコートに抜けるところ
     linetraceS();//toB
     Lcurve();//B'
     linetraceS();//B'toD'
     Rcurve(); //D'
     linetraceS(); //D'toH'
     release();//H'でボールを離す
 }

**スレイブ側のプログラム [#l93ce642]
***定義 [#b6b83cff]
 #define SIGNAL1 11  //マスターとやり取りする信号の番号
 #define SIGNAL2 12  //同上
 #define SIGNAL3 13  //同上
 #define SIGNAL4 14  //同上
 #define tukamu OnRev(OUT_A,20);Wait(800);//ボールを掴む
 #define hanasu OnFwd(OUT_A,20);Wait(300);//ボールを落とす
 #define up OnFwd(OUT_B,50);Wait(1800);//アームを上げる
 #define down OnRev(OUT_B,50);Wait(900);//アームを下ろす

***プログラム全体 [#ie6ec132]
 task main ()
 {
    int msg1;  // 受け取った値を格納する変数
    int msg2;  // 同上
    while(true){
        ReceiveRemoteNumber(MAILBOX1,true,msg1);//MAILBOX1で受け取った信号をmsg1に格納
        ReceiveRemoteNumber(MAILBOX2,true,msg2);//MAILBOX2で受け取った信号をmsg2に格納
        if(msg1==SIGNAL1){                      //msg1にSIGNAL1が入っていたなら
            down;   
            tukamu;
            up;
            Off(OUT_AB);                        //モーターを停止させる
            SendResponseNumber(MAILBOX1,SIGNAL2);//マスター側のMAILBOX1にSIGNAL2を送る
        }
        if(msg2==SIGNAL3){                      //msg2にSIGNAL3が入っていたなら
            hanasu;
            Off(OUT_A);                         //モーターを停止
            SendResponseNumber(MAILBOX2,SIGNAL4);//マスター側のMAILBOX2にSIGNAL4を送る
        }
    }   
 }

*まとめ [#n4876335]
結論からいって,ロボットはうまく動かなかった.

考えられる理由としては,

・試行回数が足りなかった

・プログラムを手分けして作った際に,意思疎通が出来ていなかった

などがあげられる.

ロボット自体はかなりの自信作だったために残念だった.

トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS