2018b/Member 目次

課題3

  今回の課題は・・・

のボールを運搬して、
それぞれ所定の350ml缶の上に乗せる
・・・だ!     

コース

フィールドの説明

3図_コース.png

ルール

基本ルール

基本得点の計算方法

技術点の計算方法

ロボット

今回作ったロボットはこれだ!! ☞☞☞3図_ロボ.jpeg

・・・前回同様、アームと車体で構成した。    

アーム

 この課題では、ボールを拾って缶に乗せる。その為、ボールを拾った後に缶の高さまで持ち上げる必要があり、更に、ボールを掴むという動作にモータを一つ使うことになる。
 私達のチームでは、電池の消耗という点からボールを掴むモータを持ち上げるのは難しいという結論に至った。この問題を解決するに当たって、チームメンバーからマジックハンドという案が挙がり、採用された。
 これが実際にできたものである。3図_アームハンド.jpeg

ハンドパーツ

 こちらは、ボールを掴むハンドパーツだ。3図_ハンド.jpeg

 上部にあるギアが回ることで、下の二つのギアがそれぞれ逆方向に回り、開閉する仕組みとなっている。

 下図はハンドパーツを上から見たものである。上部にあったギアの方向に回すと、その下のギアの方向に回る。その為、ハンドパーツが開く。

3図1_ハンド2.png ➡ 3図1_ハンド3.png

アームパーツ

 こちらは、ハンドを上下させるアームパーツだ。3図_アーム.jpeg

 写真の下側のモータがアームを上下させるようになっている。  実際に動かすと、アームの動きは下の図のようになる。黒いパーツがハンドを取りつけるもので、黄緑のパーツがモータの回転によって動くパーツである。

3図1_アーム2.png3図1_アーム3.png3図1_アーム4.png

 モータ一つだと負担が大きいので、二つ並べて使用し負荷を軽減している。



 また、ハンドへ動力を伝える為に、軸となるパーツにギアを取り付けた。このギアを通して、ハンドの開閉を行うことができる。

車体

 車体はブロックでフレームを製作し、そこにモータやタイヤを取り付け、頑丈になるようにした。

3図_車体1.JPG

 しかし、アームが予想以上に重く、車体を支える為アームの下近くに大きなタイヤを二つ追加し、計四つも使用することになった。

3図1_車体2.png



 また、モータへの負担を軽減するため、ここにもギアを使用した。

3図_車体3.jpeg

 ここのギアの配置は次にようになっている。

横から上から
3図1_タイヤ1.png3図1_タイヤ2.png
(この図はギア4とタイヤが、ギア3の左側に設置してあります)       
 


 モータとギア1ギア2ギア3ギア4とタイヤが直結している。各ギアの歯数は次の通り。

ギア歯数
ギア18
ギア216
ギア38
ギア424

 表から、ギア比は、次の式に歯数を代入することで求められる。

3図_ギア1.png
 ここで、ギア2とギア3は直結していて、回転数が等しいので、式は次のようになる。
3図_ギア2.png
 よって、ギア比は6となった。

 つまり、モータにかかる負担が6分の1になったことになる。

センサ

 今回は、缶だけでなくボールも探さないといけないので、超音波センサを二つ使用した。

 一つ目二つ目
場所アームの先端アームの下
写真3図_センサ1.jpeg3図_センサ2.jpeg
役割缶の探索ボールの探索




 また、ライントレースに使用する光センサもアームの下に付けてある。

3図_センサ3.jpeg

プログラム

 このロボットではハンドに一つ、アームに二つ、タイヤに二つモータを使用している。NXT一つではモータを三つまでしか制御できないが、二つのNXTをBluetoothで通信させることで動かす。  Bluetoothを使用する時、片方を"master"、もう片方を"slave"として動作させる。



 ライントレース等、前回の課題のプログラムを流用しているので、新たに追加したり、変更した部分のみ説明する。



 通るコースは次のようにした。

3図1_コース2.png


  1. Yから出てIまで進む。
  2. ボールを取って、円の中心まで進む。
  3. を探して乗せて、戻る。
  4. 円の中心からIまで戻る。
  5. IからEとLの間まで戻る。
  6. Eで曲がり、Fを超えてボールが見つかるまで進む。(Fの先一つ目の急カーブを曲がった辺りで見つけられる。)
  7. ボールを掴む。
  8. その位置のままを探して乗せて、戻る。

車体(master)

マクロ

 Bluetoothの通信はマクロでまとめた。

BluetoothStatus(slave番号)は通信ができているかどうかを示す関数。

RemoteStartProgram(slave番号,実行形式のプログラムファイル名)は指定したslaveの指定プログラムを起動する関数。

/************************************************************
   ライントレ____@('ω' )@彡_____ス・プログラム
*************************************************************/

/*マクロ*/
#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);\   //アームを上げる
                   RemoteStartProgram(conn,"arm_up.rxe");\
                   Wait(4000);
#define def_arm_down until(BluetoothStatus(conn)==NO_ERR);\   //アームを下げる
                     RemoteStartProgram(conn,"arm_down.rxe");\
                     Wait(4000);
#define def_hand_open until(BluetoothStatus(conn)==NO_ERR);\   //放す
                      RemoteStartProgram(conn,"hand_open.rxe");\
                      Wait(4000);
#define def_hand_close until(BluetoothStatus(conn)==NO_ERR);\   //掴む
                       RemoteStartProgram(conn,"hand_close.rxe");\
                       Wait(4000);
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度

ボール探索

 基本は課題2のプログラムと同じ

void search_throw(string side_select,float rotate_angle){//最初の一周の部分で、旋回方向と角度を指定する引数を追加した。

    SetSensorLowspeed(S2);
    int d_min=1000,d_gosa=11,side_flag=0;//side_flagは旋回方向を変更する為の変数 d_gosaはアームを上げた後に進む距離[cm]
    long ang_min=0,angle=0,d_angle=0;//d_angleは、缶との距離が遠い場合に近づいた距離を格納
    if (side_select=="right"){     //右旋回なら
       side_flag=1;              //1を旋回角度にかける
    }else if(side_select=="left"){  //左旋回なら
          side_flag=-1;         //-1を旋回角度にかける

    }
    ResetTachoCount(OUT_BC);
    OnFwdSync(OUT_BC,30,100*side_flag);
    while(((tire_diameter/(tire_axis*gear_ratio))*MotorTachoCount(OUT_C)*side_flag)<=rotate_angle){//rotate_angleまで旋回する
        if(d_min>SensorUS(S2)){
            d_min=SensorUS(S2);
            angle=MotorTachoCount(OUT_C);
        }
    }
    ang_min=MotorTachoCount(OUT_C)-angle;
    Off(OUT_BC);
    Wait(1000);
    ResetTachoCount(OUT_BC);
    RotateMotorEx(OUT_BC, 40, ang_min, -100*side_flag, true, true);//物体の方を向く
    Off(OUT_BC);
    ResetTachoCount(OUT_BC);

    if(7<SensorUS(S2)){         //缶との距離が7センチより遠い時
        OnFwd(OUT_BC,40);       //パワー40で進む
        while(7<SensorUS(S2) || 40>(pi*tire_diameter*MotorTachoCount(OUT_C))/en*gear_ratio){//缶との距離が7センチ以下になるか、進んだ距離が40センチになるまで続ける
            d_angle=MotorTachoCount(OUT_C);   //モータCの回転角を更新
        }
        Off(OUT_BC);//停止
        RotateMotor(OUT_BC,30,en*2*gear_ratio/(pi*tire_diameter));//2センチ進む
    }
    
    def_arm_up;//アームを上げる

    RotateMotor(OUT_BC,30,en*d_gosa*gear_ratio/(pi*tire_diameter));//d_gosaの分だけ進む
    Wait(700);

    def_hand_open;//ボールを放す

    RotateMotor(OUT_BC,-30,en*d_gosa*gear_ratio/(pi*tire_diameter)+d_angle);//d_gosaとd_angleの分だけ戻る

    def_arm_down;//アームを下げる

    ResetTachoCount(OUT_BC);
    RotateMotorEx(OUT_BC, 40, angle, -100*side_flag, true, true);//元の向きへ戻す
    Off(OUT_BC);
}

ライントレース

 基本は課題2のプログラムと同じ

void blk_selection(int blk_select){
    if(blk_select!=1){
        wait_sec;
    }
    if(blk_select!=0){
        mini_go;
    }
}
void follow_line(int bw_time,long min_t,int blk_cnt,string invert_info,string sensor_switch){//sensor_switchはセンサの値が一定以下の時ループから抜けるかどうかを決める引数
    SetSensorLowspeed(S3);
    int bb_cnt;//消し忘れた変数
    int B_cnt=0;//上に同じ
    long t0,t1,start_t; // t0,t1,start_t 時間変数の定義
    SetSensorLight(S1); // 光センサ定義
    t1=CurrentTick(); // 経過時間
    t0=CurrentTick(); // カーブ初期時間
    start_t=CurrentTick(); // 追尾初期時間
    int right_var;        // 光センサ値用変数
    while(t1-start_t<min_t || min_t<0){
        if(sensor_switch=="on"){//sensor_switchがonの時
             if(SensorUS(S3)<16){//超音波センサ2の値が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_taime[ms]以上のとき右旋回
                  if (blk_cnt>=0 && blk_cnt<=2 && invert_info=="on"){
                         blk_selection(blk_cnt);
                         break;
                   }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;
                   }else{
                       llt;}
            }else{            // 左回
                  lt;}}
    t1=CurrentTick();    //経過時間 
/*----------------↑繰り返し↑-----------------*/
    }Off(OUT_BC);
}

メイン

task main(){
//   -Y-
    string invert_str="off";
    int b_tyokusin=10,r_back=22;//b_tyokusinは円に入る時に進む距離 r_backはEとLの間まで戻る時の距離

//blue-ball
    follow_line(1200, -1,1,invert_str,"off");//Eまで進んでEを越える
    follow_line(800, -1,0,invert_str,"off");//Iまで進んで停止

    def_hand_close;//ボールを掴む

     ResetTachoCount(OUT_BC);
    RotateMotor(OUT_BC,30,en*b_tyokusin*gear_ratio/(pi*tire_diameter));//円の中心まで進む
    Off(OUT_BC);
     search_throw("right",55.0);//右旋回、55°で缶を探す
    Wait(2000); 
    RotateMotor(OUT_BC,-30,en*b_tyokusin*gear_ratio/(pi*tire_diameter));//Iまで戻る
    Off(OUT_BC);

//red_ball 

    def_arm_up;//アームを上げる

    RotateMotor(OUT_BC,-30,en*r_back*gear_ratio/(pi*tire_diameter)); //EとLの間まで戻る

    follow_line(600,1200000,-1,invert_str,"on");//1200秒経つか、センサーの値が一定以下になるまでライントレース
    
    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);
} 

アーム(slave)

 アーム側では四つの簡単なプログラムを容易して、マスター側から通信があった時、任意のプログラムが動作するようになっている。  モータAがハンドの操作、モータB・Cがアームの操作を担当している。

アームを上げる("arm_up.rxe")

task main(){
     RotateMotor(OUT_BC,-40,90);//モータB・Cをパワー40、90°で逆回転させる
}

アームを下げる("arm_down.rxe")

task main(){
     RotateMotor(OUT_BC,10,90);//モータB・Cをパワー10、90°で回転させる
     Wait(300);              //300[ms]待機
     Off(OUT_BC);            //モータB・Cを停止
     ResetTachoCount(OUT_BC);//モータB・Cの回転角をリセット
}

掴む("hand_close.rxe")

task main(){
     RotateMotor(OUT_A,-30,320);//モータAをパワー30、320°で逆回転させる。
     Wait(300);                 //300[ms]待機
     RotateMotor(OUT_BC,-40,15);//モータB・Cをパワー40、15°で逆回転させる
     Off(OUT_ABC);              //モータA・B・Cを停止
}

放す("hand_open.rxe")

task main(){
     RotateMotor(OUT_A,30,320);//モータAをパワー30、320°で回転させる。
}

結果・反省感想


添付ファイル: file3図1_コース2.png 216件 [詳細] file3図_コース2.png 90件 [詳細] file3図_センサ3.jpeg 207件 [詳細] file3図_センサ2.jpeg 176件 [詳細] file3図_センサ1.jpeg 208件 [詳細] file3図_ギア2.png 180件 [詳細] file3図_ギア1.png 160件 [詳細] file3図1_ギア2.png 81件 [詳細] file3図1_ギア1.png 79件 [詳細] file3図_車体3.jpeg 218件 [詳細] file3図1_車体2.png 188件 [詳細] file3図1_タイヤ2.png 189件 [詳細] file3図1_タイヤ1.png 136件 [詳細] file3図_車体1.JPG 170件 [詳細] file3図1_アーム4.png 199件 [詳細] file3図1_アーム3.png 179件 [詳細] file3図1_アーム2.png 168件 [詳細] file3図_アーム4.png 56件 [詳細] file3図_アーム3.png 48件 [詳細] file3図_アーム2.png 51件 [詳細] file3図1_ハンド3.png 185件 [詳細] file3図1_ハンド2.png 203件 [詳細] file3図_アーム.jpeg 202件 [詳細] file3図_ハンド.jpeg 143件 [詳細] file3図_アームハンド.jpeg 203件 [詳細] file3図_ロボ.jpeg 209件 [詳細] file3図_コース.png 167件 [詳細]

トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2019-02-14 (木) 09:34:49