[[2018b/Member]]
目次
#contents
*課題3の概要 [#qcf667ae]
課題:ボール運搬ロボット †

青と赤のボールを運搬して、それぞれ所定の350ml缶の上に乗せる。
ロボコンのフィールド平面図

&ref(2018b-mission3.png);

フィールドの説明
フィールドは課題2で使用した紙を使用する。
350ml缶(中が入っていても空でよい)は逆さまにして使い、ロボットのスタート直後にサイコロを振って出た目の番号の位置に置く。
その番号の次の番号のところにもダミーの缶を置くことができる。ただし6の目が出た場合は6の位置 と25cm以上離れていない場所ならどこに置いてもよいものとする。距離は缶と缶のもっとも近い部分で測る。
空き缶には色をつけたり文字や記号を書いてもよい。あるいは周囲に紙を張ってもよい。
赤と青のボールは、図のように所定の場所に置いておく。その際、キットに含まれない小さな輪ゴムを使用するものとする。

ルール 

基本ルール
競技時間は審判が続行不能と判断するまで、あるいはリタイアするまで。
図のX地点または(および)Y地点からスタートする。ただし接地している部分はそれぞれの領域内に 収まるものとする(線上はOK)。上空部分は領域からはみ出していてもよい。
赤いボールを図のピンクのいずれかに置いた缶に、青いボールを図の水色のいずれかに置いた缶に、それぞれ乗せる。
開始の合図から5秒以内にスタートボタンを押す作業を完了すること。
競技が終了するまで、ロボットに触ったり人間が遠隔で操作してはならない。
途中でうまく動かなくなった場合、1回限り再スタートすることができる(再スタートの際に別プログラムで起動してよい)。

基本得点の計算方法
ボールを一つ乗せればそれぞれ10点、二つとも乗せればボーナス点としてさらに10点。
ダミーの缶を設置した上で、正しい缶に乗せれば、それぞれさらに6点加点する。
ボールを目的の缶に当てることができれば、それぞれ4点。
ボールを同じ領域内の間違った缶に乗せた場合は、それぞれ6点。
ボールを同じ領域内の間違った缶に当てた場合は、それぞれ2点。
ボールを違う領域内の缶に乗せた場合は、それぞれ2点。
ボールを違う領域内の缶に当てた場合は、0点。
目的の缶をもとの位置(直径7cmの円)から少し出してしまった場合は1点減点、半分以上出してし まった場合は2点または取得した得点の半分のいずれか少ないほうを減点、その缶を完全にだしてし まったときは点数を半分にする。
ダミーの缶がもとの位置から移動しても減点はしない。

技術点の計算方法
以下の動作の精度・スピード・確実性などを含めた技術的な工夫や芸術性について他の全てのチーム(5チーム)が20点満点で採点し、その平均点を求める。 

得点の目安:
・ボール探し取りにいくまでの動作 (3点) 
・ボール掴む動作 (3点) 
・ボールを運ぶ動作 (2点)
・ボールを缶に置く動作 (2点) 
・2台のNXT、EV3の連携の良さ(2点) 
・自立型のロボットとしての形や動作の美しさ、斬新さ(2点) 
・その他 (3点)
*ロボットの説明 [#m6bb6146]
***ハンド部分の構造 [#r68fdc4a]
&ref(Inkedimage1(3)_LI.jpg);

課題2とは違いボールを拾うところからスタートするので,ギアで開け閉めを行うハンド部分を製作.
***ハンド部分の開け閉めの為のギア部分 [#wbd83842]
&ref(image2(2).jpeg);

モーターAからアームを伝わってきた回転は以下のように変換されハンド部分に伝わる.

&ref(image1 (15)_LI.jpg);

缶の高さまでアームをあげなければなら無いためとても大きなものになった.このギアでハンド部分に力をつたえて,ハンドの開け閉めを行う.
***上の二つを合体したもの [#hf1f248d]
&ref(image3(1).jpeg);

かなり重量のある機構になってしまった.個人的には見た目がかなりカッコいいので気に入ってはいるのだが,やはりできるだけ軽量化に勤しむことも重要だと実感した.
***超音波センサ [#q340c516]
&ref(image2 (6)_LI.jpg);

二か所に設置.アームに付いているものは缶を見つけるもので,カラーセンサの横についているものは赤いボールを探すために取り付けた.カラーセンサ横のものはアームを挙げなければ機能しないので,必ずボールを探す際はアームが上がっているようプログラムする必要があった.
***カラーセンサ [#a4548907]
&ref(image1 (5).jpeg);

機体部分の前方に設置.機体の近くに設置することによりライントレースの精度を少しでも上げる.
***その他工夫部分 [#cda26c7b]
&ref(image1 (10)_LI.jpg);

非常に重量のあるアーム部分に耐えるための工夫その1.
直接モーターでタイヤを回すと非常に大きな負荷がかかってしまう.であるからギアを間に挟むことにより機体の出せる速度は遅くなってしまうがモーターにかかる負荷を大幅に減らした

&ref(image2 (5)_LI.jpg);

常に重量のあるアーム部分に耐えるための工夫その2.
歯車を噛ませると両タイヤの間が空いてしまう.そこでロボットを安定させるため機体の中心部に大きなタイヤ2つを取り付けた.


***全体像 [#q7902aea]
&ref(image2 (6).jpeg);

カッコいい・・・のだが,やはり重量も大きさも物凄い大きく旋回や回転した際に缶やボールを吹き飛ばすことが多発.それによりプログラムに工夫を凝らす必要性が増えてしまった.機体の軽量化の偉大さをsることが出来た.

*プログラムの説明 [#r513be7f]
&ref(kidsプレゼンテーション.jpg);

今回は青→黄→赤色の順番で移動していく.各センサーはS1はライントレースのためのカラーセンサ,S2は缶を探すための超音波センサでS3はボールを探すための超音波センサでである.

**アーム部分のプログラム [#l7b9c53b]
モーターA→ハンド部分を開閉するためのモーター

モーターBC→アーム部分の上げ下げをするためのモーター
***アームを挙げるプログラム [#ne0831ee]
 task main(){
     RotateMotor(OUT_BC,-40,90);//BCを40のパワーで90度回転
 }

***アームを下げる [#ebe84960]
 task main(){
     RotateMotor(OUT_BC,10,90);//BCを10のパワーで90度回転
     Wait(300);
     Off(OUT_BC);
     ResetTachoCount(OUT_BC);//角度リセット
 }
 
***ボールを掴む [#m53a2d5f]
 task main(){
     RotateMotor(OUT_A,-30,320);//Aを30のパワーで320度回転.
     Wait(300);
     RotateMotor(OUT_BC,-40,15);//BCを40のパワーで15度回転.ハンド部分が地面と擦れないようにしている.
     Off(OUT_ABC);
 }

***ボールを放す [#de1aa89a]
 task main(){
     RotateMotor(OUT_A,30,320);//Aを30のパワーで320度回転.
 }

**機体部分のプログラム [#u00bdfff]

モーターBは左の車輪で,モータC右の車輪.
センサS1は光センサで,

また,Bluetoothを通してアームを上げ下げを行っている.

また,今回はラインをトレースする際にラインの右左をside_selectで指定すればどちらでもトレースができるようになっている.例えば,side_select="left"の時,side_flagが‐1となりside_flagを回転角度にかけるため,サーチするところの回転方向が右回りから左周りになり缶の方向を向くところも同様に反転できるといったようにして,場合によって回転方向を変換できるようにした.

***マクロの説明 [#r5d7b0b2]
 #define conn 1  //Bluetoothのスレーブ番号
 #define fw Off(OUT_BC);OnFwd(OUT_BC,30); // BCを30の力で動かし直進
 #define lt Off(OUT_BC);OnFwd(OUT_B,35);  // Bのみ35の力で動かし左回
 #define rt Off(OUT_BC);OnFwd(OUT_C,35);  // Cのみ35の力で動かし右回
 #define rrt Off(OUT_BC);OnFwd(OUT_C,20);OnFwd(OUT_B,-60); // Cを25,Bを反対方向に60の力で動かし右旋回
 #define llt Off(OUT_BC);OnFwd(OUT_B,20);OnFwd(OUT_C,-60); // Bを25,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);\   //Bluetoothで通信している本体のプログラムを起動しアームを上げる
                   RemoteStartProgram(conn,"arm_up.rxe");\
                   Wait(4000);
 #define def_arm_down until(BluetoothStatus(conn)==NO_ERR);\   //Bluetoothで通信している本体のプログラムを起動しアームを下げる
                     RemoteStartProgram(conn,"arm_down.rxe");\
                     Wait(4000);
 #define def_hand_open until(BluetoothStatus(conn)==NO_ERR);\   //Bluetoothで通信している本体のプログラムを起動しボールを放す
                      RemoteStartProgram(conn,"hand_open.rxe");\
                      Wait(4000);
 #define def_hand_close until(BluetoothStatus(conn)==NO_ERR);\   //Bluetoothで通信している本体のプログラムを起動しボールを掴む
                       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度
 
***ボールを乗せるプログラム [#fc43759d]

 void search_throw(string side_select,float rotate_angle){ 
     SetSensorLowspeed(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_flag=1;
    }else if(side_select=="left"){
          side_flag=-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){     //(タイヤ直径/前輪間の距離)*タイヤの回転角度=ロボットの旋回角度
        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)){
        OnFwd(OUT_BC,40);
        while(7<SensorUS(S2) || 40>(pi*tire_diameter*MotorTachoCount(OUT_C))/en*gear_ratio){
            d_angle=MotorTachoCount(OUT_C);
        }
        Off(OUT_BC);
        RotateMotor(OUT_BC,30,en*2*gear_ratio/(pi*tire_diameter));//缶に向かって近づく
    }
    def_arm_up;//ageru   //アームを挙げる
    RotateMotor(OUT_BC,30,en*d_gosa*gear_ratio/(pi*tire_diameter));  //丁度アームを下げた時にボールが缶に乗る位置まで少し前進.
    Wait(700);//少し停止
    def_hand_open;//hanasu   //アームを離す.
    RotateMotor(OUT_BC,-30,en*d_gosa*gear_ratio/(pi*tire_diameter)+d_angle);//アームを下げても平気な位置まで下がる.
    def_arm_down;//sageru   //アームを下げる.
    ResetTachoCount(OUT_BC);/モーターの角度を初期化
    RotateMotorEx(OUT_BC, 40, angle, -100*side_flag, true, true);//元の向きへ戻す
    Off(OUT_BC);//停止.
 }
***交差点判断時に止まるか進むかの条件分け [#v5c3aba7]
この関数は機体が交差点判断した際止まるか直進するかを選択できるように作成したものである.blk_select!が1の時停止して,0の時進むようにプログラムされている.
 void blk_selection(int blk_select){
    if(blk_select!=1){
        wait_sec;//停止
    }
    if(blk_select!=0){
        mini_go;//少し進む
    }
 }
***ライントレースプログラム [#wd759a75]
&ref(image1 (14).jpeg);

上の写真の図のような原理でライントレースしている.
センサの値が40未満で左回り,40から50で直進,それ以上で右回するようにプログラムしている.動作開始時間であるstart_tを定義することによりt1-start_tが動作を行っている時間となり,こちらが指定したt_min間だけ動かすことが可能である.t1は動作を行っている間常に更新が入るのでt1は機体が旋回や回転をしているその瞬間であり,t0は白or黒の探知し始めた時間を記録しているから,t1-t0はセンサーが白or黒を連続で探知し続けた時間である.この時間が一定数超えたら旋回するようにプログラムしている.

#ref(image1 (20).jpeg);

交差点の見極め方は交差点にロボが進入した際カラーセンサが黒を探知する時間が長くなる.故に上の図にもあるように一定時間(bw_time)をt1-t0(曲がるor旋回時間)が超えた場合交差点だと判断している.

また,その他の関数としてはinvert_info,sensor_switchとblk_cntが下のプログラムに使われており,
invert_infoにoffを指定した場合は何も行わず左の境目をトレースして,onを指定した場合は光センサの値を反転させることで右の境目をトレースして,sensor_switchにonを指定すると、S3に接続された超音波センサが16儖米發両祿科(ボール)を発見した時ライントレースを終了する。offを指定した場合はたとえS3の超音波センサが障害物を発見しても何もしない.blk_cntは値に1を指定すると交差点判断をした際停止しライントレース終了。0を指定した時は交差点を直進して通り過ぎた後ライントレース終了。-1を指定した時は何もしない.

 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(); // 動作を行っている瞬間
    t0=CurrentTick(); // 白or黒の探知し始めた時間
    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;
                   }else{
                       rrt;}
            }else{        // 右回
                  rt;}
     /**********直進↓********/
        }else if (right_var>40){
            fw;
            t0=CurrentTick(); // カーブ初期時間の更新
     /*********左回り↓*******/
        }else{
            if (t1-t0>bw_time){   // 左回で bw_time[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);
 }
***実際のプログラム [#rfc40b2a]
 task main(){
 //   -Y-
    string invert_str="off";
    int b_tyokusin=10,r_back=22;
 //青ボールをつかむプログラム
    follow_line(1200, -1,1,invert_str,"off");//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);//青ボールを乗せる.
    Wait(2000);
    RotateMotor(OUT_BC,-30,en*b_tyokusin*gear_ratio/(pi*tire_diameter));//位置調整
    Off(OUT_BC);//停止
//赤いボールを掴むプログラム
    def_arm_up;//アームをあげる
    RotateMotor(OUT_BC,-30,en*r_back*gear_ratio/(pi*tire_diameter));
    follow_line(600,1200000,-1,invert_str,"on");//Fを過ぎてすぐのカーブまで行く.
    RotateMotor(OUT_BC,-30,en*3*gear_ratio/(pi*tire_diameter)); //3センチ下がりボールを掴める位置に移動.
    def_arm_down;//アームを下げる
    def_hand_close;//ボールを掴む
    search_throw("left",270);//赤ボールを缶に乗せる.
    Wait(1000);Off(OUT_BC);//停止
 }
**反省 [#fe363569]
&ref(S__21643268.jpg);

我々の班はN1N2であり,上の写真からわかる通り我々の班は結果としては三位であったが,基本点は取ることが出来無かった.ボールを離すことが出来なくなってしまうというトラブルが起きてしまったのと,缶に向かって機体が移動する際に缶からズレてしまった為である.先生から頂いたアドバイスで超音波センサで缶を探す動作を二段階にすることで誤差を減らすという方法があったと聞きとても参考になった.機体作成の時間をかけすぎてしまった感じは否めないが,それでも機体の出来は見た目性能共に素晴らしいものだと自負できるものに仕上げることが出来たと思う.そのおかげからか他の班からの評価が高かったのは非常に喜ばしいことだった.
今回失敗してしまった原因は前述の通り超音波センサで缶を探す動作を精密に出来ずに缶の位置によっては誤差が大きくなってしまったこと,ボールを掴む際のハンド部分の角度の指定ミスとうが挙げられる.これらを改善するためには缶を探す動作を二段階で行い,ハンド部分はボールを掴む前にプログラムでハンド部分を限界まで開いておく等の工夫が必要であったと考えた.悔しい結果に終わったがとても勉強になった講義であった.


トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS