[[2018b/Member]]


目次
#contents

*課題 [#i2a04507]
課題2でも使用した下図のようなコースを走行し、所定の位置に設置してあるボールを運搬し350mlの缶の上に乗せるというのが今回の課題である。缶の位置についてはスタート直前にサイコロを振り、出た目とリンクする位置に設置。青ボールは下図の青丸1〜6のいずれかに設置した缶に乗せ、赤ボールは赤丸1〜6のいずれかに設置した缶に乗せる。
#ref(./2018b-mission3.png,10)

**ルール [#y7690416]
基本点と技術点をつけて各チームで競い合う。

基本得点の計算方法

ボールを一つ乗せればそれぞれ10点、二つとも乗せればボーナス点としてさらに10点。

ダミーの缶を設置した上で、正しい缶に乗せれば、それぞれさらに6点加点する。

ボールを目的の缶に当てることができれば、それぞれ4点。

ボールを同じ領域内の間違った缶に乗せた場合は、それぞれ6点。

ボールを同じ領域内の間違った缶に当てた場合は、それぞれ2点。

ボールを違う領域内の缶に乗せた場合は、それぞれ2点。

ボールを違う領域内の缶に当てた場合は、0点。

目的の缶をもとの位置(直径7cmの円)から少し出してしまった場合は1点減点、半分以上出してしまった場合は2点または取得した得点の半分のいずれか少ないほうを減点、その缶を完全にだしてしまったときは点数を半分にする。

ダミーの缶がもとの位置から移動しても減点はしない。

技術点の計算法は以下画像を参照↓

#ref(./21228.jpg)

その他詳しいルールは[[こちら:http://yakushi.shinshu-u.ac.jp/robotics/?2018b%2FMission3]]

**今回通ったルート [#yf0c72d3]

今回の課題で通ったルートは以下の画像のようなルートにした。
#ref(./2018b-mission3v2.png)

    1,QからスタートしIまで進む
    2,青ボールをつかみ缶を探知
    3,缶の上にボールを置きIまで戻る
    4,IからFを通り急カーブの途中で赤ボールを探知
    5,赤ボールをつかみ缶を探知
    6,缶の上にボールを置く
    7,終了


*ロボットの概要 [#wb3b59a9]
**ロボットの全体像 [#c881d168]
NXT本体を二つ使用している。この二つはBluetoothで通信している。
#ref(./21232.jpg)
このロボットは走行機構とアーム機構の二つに分けられ、この二つの機構それぞれをNXT本体で操作している。

#ref(./21243_LI.jpg)
以下でそれぞれの機構について説明していく。
**走行機構 [#yb6cca0c]
***土台とタイヤと歯車と [#yf2756ce]
まず、長方形の土台となるものを作り、その上にタイヤを動かすモーターを置くという機構にした。この土台がないと、後に説明するアーム機構の重さに耐えきれず壊れてしまう可能性があった為土台を作った。

まず、前輪について説明する。

アーム機構が想像以上に重い為、モーターにタイヤを直接つけると常にフルパワーでモーターを動かす必要があった。従って、タイヤとモーターの間に歯車を噛ませることにより、小さな力で動かせるようにした。ちなみに、モータの負担が6分の一減った。

#ref(./21689.jpg)

土台にタイヤとモーター(BC)を付けたものが下の画像。試作段階のもの↓↓
#ref(./S__21610507.jpg)

ちなみに、歯車を噛ませると両タイヤの間が空いてしまい、ロボットが不安定になる。これを防ぐために、間に大きめのタイヤを付けた。↓画像(画像だと見えづらいですね。すみません。)
#ref(./21239_LI.jpg)
#ref(./image2 (5)_LI.jpg)

これまで前輪について説明してきたが、後輪は自由に回る小さめのタイヤを取り付けた。一つだけだと不安だったので二つ取り付けた。↓画像
#ref(./21234.jpg)

***センサー [#jc0d8f87]

上記で説明した土台の進行方向に超音波センサーとカラーセンサーを取り付けた。↓画像
#ref(./21241 (2).jpg)
超音波センサーでコース上にあるボールを探知し、カラーセンサーでライントレースをする。

**アーム機構 [#l620a4ec]
アーム機構は二つに分けられ、ボールをつかむ機構と持ち上げる機構の二つに分けられる。
***ボールをつかむ機構 [#d3fde447]
アームの部分は↓画像のようになっている。
#ref(./image1(3).jpeg)

歯車を回してアーム部分を開閉してボールをつかむ。
#ref(./image1(3)_LI.jpg)



***持ち上げる機構 [#ea30ba06]
持ち上げる機構は、マジックハンドのような機構にした。電池の消費等を考えてしまい、持ち上げる機構がなかなか出来ず、私がマジックハンドの案を提案したところ、そのまま採用された。
#ref(./S__21610501.jpg)

持ち上がる原理としては↓図参照
#ref(./121679.jpg)


画像の下二つのモーター(BC)を同期させてマジックハンドの曲げ伸ばしを行い、上にあるモーター(A)で上記のアームを動かすための歯車を回すようにした。

#ref(./1S__12263440.jpg)

***アーム機構全体図 [#n2606bad]
マジックハンド部分の上部に超音波センサーをつけて、缶を探知する。

後ろから↓
#ref(./121238 (2).jpg)
前から↓
#ref(./S__21610506.jpg)



*プログラムの概要 [#c9858ccb]

今回はNXT本体を二つ用いているので片方をマスター、もう片方をスレーブとしてBluetoothでつなげて連携を取りながら動作をする。スレーブ側のNXTには「アームを上げる」「アームを下げる」「ボールをつかむ」「ボールを離す」の四つの簡単なプログラムが入っている。マスター側にはマクロやライントレースをする関数等の複雑なプログラムが入っている。

なお、マスター側のプログラム内に「RemoteStartProgram(conn,"X.rxe")」を入れればスレーブ側のNXTに入っているプログラムが動作する(この時のXはスレーブ側のNXTに入っているプログラム名が入る)。

**スレーブ側のプログラム [#ib0d0192]
***アームを上げる [#v6163d6f]
プログラム名は「arm_up」
    task main(){
         RotateMotor(OUT_BC,-40,90);
    }

***アームを下げる [#xf34094a]
プログラム名は「arm_down」
    task main(){
        RotateMotor(OUT_BC,10,90);//BCを10のパワーで90度回転
        Wait(300);
        Off(OUT_BC);
        ResetTachoCount(OUT_BC);//角度リセット
    }

***ボール掴む [#h8846e3c]
プログラム名は「hand_close」
    task main(){
        RotateMotor(OUT_A,-30,320);//Aを30のパワーで320度回転.
        Wait(300);
        RotateMotor(OUT_BC,-40,15);//BCを40のパワーで15度回転.ハンド部分が地面と擦れないようにしている.
        Off(OUT_ABC);
    }

***ボールを離す [#t965da7b]
プログラム名は「hand_open」
    task main(){
        RotateMotor(OUT_A,30,320);//Aを30のパワーで320度回転.
    }


**マスター側のプログラム [#o4f0355a]
***定義したマクロ [#s1af7c6b]
    #define conn 1  //Bluetoothのスレーブ番号
    #define fw Off(OUT_BC);OnFwd(OUT_BC,30); // 直進
    #define lt Off(OUT_BC);OnFwd(OUT_B,35);  // 左回
    #define rt Off(OUT_BC);OnFwd(OUT_C,35);  // 右回
    #define rrt Off(OUT_BC);OnFwd(OUT_C,20);OnFwd(OUT_B,-60); // 右旋回
    #define llt Off(OUT_BC);OnFwd(OUT_B,20);OnFwd(OUT_C,-60); // 左旋回
    #define wait_sec Off(OUT_BC);Wait(1000); //一時停止
    #define mini_go Off(OUT_BC);OnFwd(OUT_BC,30);Wait(1500);Off(OUT_BC); //少し直進
    #define def_arm_up until(BluetoothStatus(conn)==NO_ERR);\   //スレーブ側NXTと通信
                       RemoteStartProgram(conn,"arm_up.rxe");\  //スレーブ側の「arm_up」のプログラムを実行
                       Wait(4000);
    #define def_arm_down until(BluetoothStatus(conn)==NO_ERR);\   //スレーブ側NXTと通信
                         RemoteStartProgram(conn,"arm_down.rxe");\  //スレーブ側の「arm_down」のプログラムを実行
                         Wait(4000);
    #define def_hand_open until(BluetoothStatus(conn)==NO_ERR);\   //スレーブ側NXTと通信
                          RemoteStartProgram(conn,"hand_open.rxe");\  //スレーブ側の「hand_open」のプログラムを実行
                          Wait(4000);
    #define def_hand_close until(BluetoothStatus(conn)==NO_ERR);\   //スレーブ側NXTと通信
                           RemoteStartProgram(conn,"hand_close.rxe");\  //スレーブ側の「hand_close」のプログラムを実行
                           Wait(4000);

***定義した定数 [#m5439305]
    const float tire_diameter = 5.75;    //タイヤの直径
    const float tire_axis = 17.7;           //タイヤ間の距離
    const int gear_ratio = 6;                //ギア比
    const float pi=3.14159;                 //円周率
    const int en=360;                          //円 360度


***定義した関数 [#b1ec4623]



****缶を探知してボールを缶の上に置く関数 [#c4cbda2c]


d_minは距離の最小値を示していて、この関数ではd_minよりも短い距離が探知出来たらd_minを更新する。

side_selectで右旋回か左旋回かを入力し、rotate_angleは旋回する角度を入力する。

今回、歯車を噛ましているのでタイヤがモーターの6分の一しか回転しなことを考慮に入れて、{タイヤ間の距離(tire_diameter)/(タイヤの直径(tire_axis)×ギア比(gear_ratio))×タイヤの回転角度(モーターの回転角度)}の式で旋回の角度が答えで出る。


缶を探知するときの探知の範囲は↓図参照

#ref(./12018b-mission3.png)
薄青が青ボールをつかんだ時の探知範囲で、薄赤が赤ボールをつかんだ時の探知範囲。


    void search_throw(string side_select,float rotate_angle){ 
        SetSensorLowspeed(S2);                //センサーS2に超音波センサーを設置
        int d_min=1000,d_gosa=11,side_flag=0;               //それぞれの変数に数字を代入
        long ang_min=0,angle=0,d_angle=0;            //定義
        if (side_select=="right"){              //side_selectがrightの時
           side_flag=1;                          //side_flagに1を代入
        }else if(side_select=="left"){             //side_selectがleftの時
             side_flag=-1;                       //side_flagに-1を代入
        }
        ResetTachoCount(OUT_BC);              //モーターBCをリセット
        OnFwdSync(OUT_BC,30,100*side_flag);                     //モーターBCを出力30で100×side_flag度分進む
        while(((tire_diameter/(tire_axis*gear_ratio))*MotorTachoCount(OUT_C)*side_flag)<=rotate_angle){
            if(d_min>SensorUS(S2)){
                d_min=SensorUS(S2);             //最小値を更新する
                angle=MotorTachoCount(OUT_C);      //モーターCの角度を変数angleに代入
            }
        }
        ang_min=MotorTachoCount(OUT_C)-angle;         //距離の最小値を更新した場所を記録
        Off(OUT_BC);
        Wait(1000);
        ResetTachoCount(OUT_BC);                       //モーターBCをリセット
        RotateMotorEx(OUT_BC, 40, ang_min, -100*side_flag, true, true);//物体の方を向く
        Off(OUT_BC);
        ResetTachoCount(OUT_BC);
        if(7<SensorUS(S2)){                   //距離が7cmまで
            OnFwd(OUT_BC,40);                 //前に進む
            while(7<SensorUS(S2) || 40>(pi*tire_diameter*MotorTachoCount(OUT_C))/en*gear_ratio){            //缶までの距離が7cm以上or40cm直進するまでモーターの回転数を記録
                d_angle=MotorTachoCount(OUT_C);
            }
            Off(OUT_BC);
           RotateMotor(OUT_BC,30,en*2*gear_ratio/(pi*tire_diameter));
        }
        def_arm_up;                           //アームを上げる
        RotateMotor(OUT_BC,30,en*d_gosa*gear_ratio/(pi*tire_diameter));      //少し前進
        Wait(700);
        def_hand_open;                        //ボールを離す
        RotateMotor(OUT_BC,-30,en*d_gosa*gear_ratio/(pi*tire_diameter)+d_angle);     //少し後進
        def_arm_down;                         //アームを下げる
        ResetTachoCount(OUT_BC);              //モーターBCをリセット
        RotateMotorEx(OUT_BC, 40, angle, -100*side_flag, true, true);//元の向きへ戻す
        Off(OUT_BC);
    }






****交差点判断をする関数 [#vaa20f4a]
blk_selectが0の時は止まり、1の時に進む。

この関数は次項目の「ライントレースする関数」で使われる関数である。

    void blk_selection(int blk_select){
        if(blk_select!=1){
            wait_sec;
        }
        if(blk_select!=0){
            mini_go;
        }
    }



****ライントレースする関数 [#l8626394]

この関数で使用する変数の説明は以下の通り

・bw_timeは右左折から旋回になるまでの時間を入力。

・min_tは交差点判断をしない時間を入力。また、-1を入力した場合交差点判断をしない。

・blk_cntは交差点判断したときに止まるか否かを決める。1を入力で交差点判断したらライントレースをやめる。0を入力で交差点を直進した後にライントレースをやめる。-1の時は何もしない。

・invert_infoは"on"か"off"を入力し、トレースする左右の境目を決める。("on"の時に右の境界、"off"で左の境界)

・sensor_switchは"on"か"off"を入力し、16cm以内に障害物(ボール)を認識したときに止まるか否かを決める。("on"でライントレースをやめ、"off"で何もしない。)


その他詳しい説明は[[前回の課題2:http://yakushi.shinshu-u.ac.jp/robotics/?2018b%2FMember%2Ftomflat14%2FMission2]]を参照


    void follow_line(int bw_time,long min_t,int blk_cnt,string invert_info,string 
    sensor_switch){
        SetSensorLowspeed(S3);       //超音波センサー定義
        int bb_cnt;                  
        int B_cnt=0;
        long t0,t1,start_t; // t0,t1,start_t 時間変数の定義
        SetSensorLight(S1); // 光センサー定義
        t1=CurrentTick(); // 白or黒を探知した時間
        t0=CurrentTick(); // 右左折の開始時間
        start_t=CurrentTick(); // 追尾初期時間
        int right_var;        // 光センサ値用変数
        while(t1-start_t<min_t || min_t<0){
            if(sensor_switch=="on"){
                 if(SensorUS(S3)<16){
                      break;
                 }
            }
    /*----------------↓繰り返し↓-----------------*/
            right_var = SENSOR_1; // 光センサ値代入
            if(invert_info=="on"){  // ラインの右か左か "off"で左,"on"で右
                 right_var = right_var*(-1)+91;}
            if (right_var>50){
         /*********右回り↓********/
                if (t1-t0>bw_time){ // 右回でbw_time[ms]以上のとき右旋回
                      if (blk_cnt>=0 && blk_cnt<=2 && invert_info=="on"){
                             blk_selection(blk_cnt);
                             break;                   //whileの繰り返しから抜け出す
                       }else{
                           rrt;}
                }else{        // 右回
                      rt;}
         /**********直進↓********/
            }else if (right_var>40){
                fw;
                t0=CurrentTick(); // カーブ初期時間の更新
         /*********左回り↓*******/
            }else{
                if (t1-t0>bw_time){   // 左回で bw_taime[ms]  以上のとき左旋回
                      if (blk_cnt>=0 && blk_cnt<=2 && invert_info!="on") {
                             blk_selection(blk_cnt);
                             break;                             //whileの繰り返しから抜け出す
                       }else{
                           llt;}
                }else{            // 左回
                      lt;}}
        t1=CurrentTick();    //右左折が終わったので時間を更新
    /*----------------↑繰り返し↑-----------------*/
        }Off(OUT_BC);
    }



***実際のプログラム [#n4417516]
    task main(){
    //   -Y-
        string invert_str="off";
        int b_tyokusin=10,r_back=22;         //前進と後進の距離を定義
    //blue-ball
        follow_line(1200, -1,1,invert_str,"off");        //Y〜Lまで進む
        follow_line(800, -1,0,invert_str,"off");         //L〜Iまで進む
        def_hand_close;                                  //青のボールを掴む
        ResetTachoCount(OUT_BC);                         //モーターをリセット
        RotateMotor(OUT_BC,30,en*b_tyokusin*gear_ratio/(pi*tire_diameter));       //HIJK円内に進入
        Off(OUT_BC);                             //円の中心付近で止まる
        search_throw("right",55.0);              //55度の範囲で右旋回をし探知
        Wait(2000);
        RotateMotor(OUT_BC,-30,en*b_tyokusin*gear_ratio/(pi*tire_diameter));      //直進して円から出る
        Off(OUT_BC);
    //red_ball
        def_arm_up;                             //アームを上げる
        RotateMotor(OUT_BC,-30,en*r_back*gear_ratio/(pi*tire_diameter));     //Eまで戻る
        follow_line(600,1200000,-1,invert_str,"on");                        //EからF通過し急カーブの途中まで進む
        RotateMotor(OUT_BC,-30,en*3*gear_ratio/(pi*tire_diameter)); //3センチ下がる
        def_arm_down;                                   //アームを下げる
        def_hand_close;                                 //赤ボールをつかむ
        search_throw("left",270);                       //270度の範囲で左旋回をし探知
        Wait(1000);Off(OUT_BC);
    }


*まとめ [#ufcc61b5]
**結果 [#pffa9e05]
各グループの結果は以下の画像のようになった。

#ref(./S__21643268.jpg)

E3E4のグループがベルトコンベア式の装置を駆使しぶっちぎりの1位に輝いた。

我がグループは3位になった。

**考察 [#ebc3f3d2]
・ボールをつかんだ後、離すことが出来なかった。規定した角度まで回転できずエラーしてしまったことが原因と考えられる。解決策としては、アームの機構を動かす前にめいいっぱい開いた後にモーターの回転角をリセットするとエラーにはならないと考えられる。

・缶を探知した後に、探知した缶まで進むのだが、遠くにある缶の時は缶から逸れてしまった。缶にある程度近づいた後にもう一度缶を探知すれば、逸れたとしても缶のところまでたどり着けるであろう。

・機体が大きくなり非常に重くなってしまったので歯車を噛ませたりして工夫を施したが、やはり電池の消費が激しくなり本番中に電池切れになってしまった。たとえ工夫をしていて性能的に良くても、電池の消費が激しいので軽量化することが大事だと感じた。






**感想 [#k91415ff]
機体を作るのに時間をかけすぎた。しかし、マジックハンドの機構がグループ内で採用されたのがうれしかった。また、機体の外見はとても気に入っており性能的にもそこまで悪くないと感じる。最後の発表に間に合わせることが出来てよかった。司会も下手だとは思うが楽しくできた。発表自体は残念になったが機体に対する技術点が高くとてもうれしく感じる。

とても学べることが多い講義だった。今後学んだことを生かせる場面があれば、今回の講義を思い出して学んだことを活かしていきたい。後期の間お疲れ様でした。ありがとうございました。

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