2018b/Member

課題3

ボール運搬ロボット

青と赤のボールを運搬して、それぞれ所定の350㎖缶の上に乗せる。

コース

経路図ロボットを動かす。

2018b-mission3.png

私たちのグループでは、上の図のように

  1. Xからスタート
  2. Gで赤いボールを取る
  3. Fを通過しEを直進
  4. Dで缶を探しボールを置く
  5. ボールを置いたらDに戻る
  6. Eを右折
  7. Iを直進して青いボールを取る
  8. 缶を探しボールを置く

という経路でロボットを動かした。

ロボットの説明

ロボットの全体

KIMG0103.jpg

今回のミッションではNXTの本体が2つ使えたので、NXTの本体を1つずつ使って2つのロボットを作るか、2つのNXTを通信して1つのロボットを作るか選択できた。2つのロボットを作ると、移動・ボールの掴み・ボールの持ち上げに4つのモータが必要になり、数が足りなかった。先生に3つのモータでも動かせるロボットの組み立て方を教えてもらったが、1つのロボットを作った方が簡単だという結論に至り、私たちのグループでは2つのNXTを通信して1つのロボットを作ることに決めた。 また、2つのNXTを横に並べることと、後ろのタイヤ(駆動輪)を2つつけることでタイヤ1つにかかる重さを分散させて、急カーブなど曲がりやすくしたところを工夫した。

アーム

KIMG0096_LI.jpg

アームはモータを回すことで、図のような動きをするようにした。また、つかむ部分をとても工夫し、ボールを落としずらく、つかみやすい形にした。

その他

ほかの部分は基本的に第2の課題と構造は変わっていない。ただ唯一変えたことは、超音波センサを下に取り付けたことである。これによって、ボールの位置もわかるようにした。

プログラミング

ボールを持つプログラミング

#define UP OnFwd(OUT_B,20);Wait(4750);Off(OUT_BC);   //腕上げ
#define DOWN OnRev(OUT_B,20);Wait(2600);Off(OUT_BC);  //腕下げ
#define CATCH OnRev(OUT_C,15);Wait(725);Off(OUT_BC);  //手掴み

task main()
{
DOWN
CATCH
UP
}

ボールを離すプログラミング

#define LOST OnFwd(OUT_C,15);Wait(685);Off(OUT_C);  //手離す
task main()
{      //ボールを持って腕は上がっている状態
LOST 
}

ライントレースのプログラミング

IMG_1130.jpg

プログラミング内容はほとんど変わっていない。今回もこのような動きをするようにした。プログラムは、

#define turn_l1 OnFwd(OUT_B,33);OnRev(OUT_C,33);  //左旋回
#define turn_r1 OnFwd(OUT_C,33);OnRev(OUT_B,33);  //右旋回
#define turn_l0 OnFwd(OUT_B,30);Off(OUT_C);  //左折
#define turn_r0 Off(OUT_B);OnFwd(OUT_C,30);  //右折
#define go_s OnFwd(OUT_BC,30); //直進
SetSensorLight(S1); //1番に繋がっている光センサを使う
if(SENSOR_1>58){  //もし光センサが58以上の値を測定したら
   turn_r1;   //右旋回                        
}else if(SENSOR_1>53){  //もし光センサが53以上57以下の値を測定したら
   turn_r0; //右折
}else if(SENSOR_1>44){ //もし光センサが44以上52以下の値を測定したら
   go_s;   //直進                                                  
}else if(SENSOR_1>34){ //もし光センサが34以上43以下の値を測定したら
   turn_l0; //左折                                         
}else{ //もし光センサが33以下の値を測定したら
   turn_l1; //左旋回
   }
}

交差点も前回と同様である。プログラミングは、

void tuuzyou()
{
   SetSensorLight(S1);  //1番に繋がっている光センサを使う
   long t0;              //long型のt0を定義                                                   
   t0=CurrentTick();   //現在の時間を記録
   while(CurrentTick()-t0<90){   //現在の時間とt0の差が0.09秒以下の時、以下のプログ 
ラムを繰り返す
       if(SENSOR_1>58){  //もし光センサが58以上の値を測定したら
           turn_r1;   //右旋回    
           t0=CurrentTick(); //t0を更新する                   
       }else if(SENSOR_1>53){  //もし光センサが53以上57以下の値を測定したら
           turn_r0; //右折
           t0=CurrentTick(); //t0を更新する
       }else if(SENSOR_1>44){ //もし光センサが44以上52以下の値を測定したら
           go_s;   //直進       
           t0=CurrentTick(); //t0を更新する                                           
       }else if(SENSOR_1>34){ //もし光センサが34以上43以下の値を測定したら
           turn_l0; //左折   
           t0=CurrentTick(); //t0を更新する                                      
       }else{ //もし光センサが33以下の値を測定したら
           turn_l1; //左旋回
}

また、前回同様急カーブがあるので、そのプログラミングは

void special()
{
   SetSensorLight(S1);   //1番に繋がっている光センサを使う                                                       
   long t1;                  //long型のt1を定義する                                                     
   t1=CurrentTick() //現在の時間を記録
   while(CurrentTick()-t1<23500){ //現在の時間とt1の差が23,5秒以下の時、以下のプログ 
ラムを繰り返す  
       if(SENSOR_1>58){  //もし光センサが58以上の値を測定したら
           turn_r1;   //右旋回                        
       }else if(SENSOR_1>53){  //もし光センサが53以上57以下の値を測定したら
           turn_r0; //右折
       }else if(SENSOR_1>44){ //もし光センサが44以上52以下の値を測定したら
           go_s;   //直進                                                  
       }else if(SENSOR_1>34){ //もし光センサが34以上43以下の値を測定したら
           turn_l0; //左折                                         
       }else{ //もし光センサが33以下の値を測定したら
           turn_l1; //左旋回
           }
   }                                              
}

Dの直角を認識するプログラミング

Dの位置でボールを探そうとしていたので、Dの直角で止まらなければならない。このためにはDの直角を認識したら終わるプログラムが必要である。しかし、「tuuzyou」のプログラムは「真っ黒」の時間が長いときに終わるプログラムなので、左に曲がる直角でなければ終わらない。なので、真っ白を検知したら止まるプログラミングを作る。前回のプログラムの応用として

void sirotuuzyou()
{
   SetSensorLight(S1); //1番に繋がっている光センサを使う
   long t2;         //long型のt2を定義                                                          
   t2=CurrentTick();  //現在の時間を記録
   while(CurrentTick()-t2<90){ //現在の時間とt2の差が0.9秒以下の時に以下のプログラム 
を繰り返す
       if(SENSOR_1>58){  //もし光センサが58以上の値を測定したら 
           turn_r1;   //右旋回                        
       }else if(SENSOR_1>53){  //もし光センサが53以上57以下の値を測定したら
           turn_r0; //右折
           t2=CurrentTick(); //t2を更新する
       }else if(SENSOR_1>44){ //もし光センサが44以上52以下の値を測定したら
           go_s;   //直進   
           t2=CurrentTick(); //t2を更新する                                               
       }else if(SENSOR_1>34){ //もし光センサが34以上43以下の値を測定したら
           turn_l0; //左折                
           t2=CurrentTick(); //t2を更新する                         
       }else{ //もし光センサが33以下の値を測定したら
           turn_l1; //左旋回
           t2=CurrentTick(); //t2を更新する
           }
   }   
}

缶を探して缶に置くプログラミング

ロボットからの距離が最小のものを探すプログラム

コンテストではダミーの缶も置けたが、私たちのグループはダミーの缶を置かず、ボールを置かなければいけない缶を必ずロボットとの距離を1番近い物体にした。これにより、缶を探すプログラムは超音波センサを使って、ロボットとの距離が最小の物体の方向を向くプログラムを使う。それは以下のとおりである。

まず

#define speed 70
#define speed_s 50
const float diameter=5.54;  //タイヤの直径(cm)                                              
const float track=10.35; //タイヤのトレッド幅(cm)
const float pi=3.1415; //円周率

と定義する。

void fwdDist(float d)
{
   long angle;                                                         
   angle= d/(diameter*pi)*360.0;
   RotateMotorEx(OUT_BC,speed_s,angle,0,true,true);                      
}
void turnAng(long ang) //角度ang度の時計回りの旋回をする
{
   long angle;
   angle=track/diameter*ang;
   RotateMotorEx(OUT_BC,speed_s,angle,100,true,true);
}                                                                     
int searchDirection(long ang)  //現在の方向を中心にang度の範囲で探す                                      
                                                //障害物までの距離を返す
{
   long angle,tacho_min=0,tacho_corr;
   int d_min;
   d_min=300; //仮の最小値
   angle=(track/diameter)*ang;  //旋回角度からタイヤの回転を計算する                                                
   turnAng(ang/2); //指定された角度の半分を旋回する
   ResetTachoCount(OUT_BC);       //角度計測をリセット                                       
   OnFwdSync(OUT_BC,speed_s,-100); //反時計回りに旋回する
   while(MotorTachoCount(OUT_B)<=angle){
       if(SensorUS(S4)<d_min){
           d_min=SensorUS(S4); //仮の最小値を更新する
           tacho_min=MotorTachoCount(OUT_B);
       }
   }             kono                                                              
   OnFwdSyncEx(OUT_BC,speed_s,100,RESET_NONE);
   until(MotorTachoCount(OUT_B)<=tacho_min||SensorUS(S4)<=d_min);             
   Wait(14); //微調整
   Off(OUT_BC);Wait(500);
   return d_min;
}

このプログラムを図にするとこうである。

IMG_1053.jpg

缶の近くに移動する

あらかじめ超音波センサを用いて缶にボールを置くのに適している距離を測定して、缶とロボットが13.5cm離れているとボールを乗せることができるということがわかった。その結果を用いて以下のプログラムを作った。

SetSensorLowspeed(S4); //4番に繋いだ超音波センサを使う
int d=searchDirection(360); //int型でdを定義し、ロボットを360°回転させて距離を測定 
してその最小値を探す
if (d>13.5){                    //もし見つけた最小値の距離が13.5cmより大きかったら
   fwdDist(d-13.5); //缶とロボットの距離が13.5cmになるまで近づく
}

缶から同じ場所に戻ってくるプログラム

void sagasu()
{
   SetSensorLowspeed(S4); //4番に繋いだ超音波センサを使う
   int d=searchDirection(360); //int型でdを定義し、ロボットを360°回転させて距離を 
測定してその最小値を探す
   if (d>13.5){                    //もし見つけた最小値の距離が13.5cmより大きかった 
ら
       long t3,t4;  //long型のt3,t4を定義する
       t3=CurrentTick(); //ロボットが缶に近づく前の時間をt3に記録
       fwdDist(d-13.5); //缶とロボットの距離が13.5cmになるまで近づく
       t4=CurrentTick(); //ロボットが缶に近づいた後の時間をt4に記録
       stoop; //親機はボールを置く際に動かないのでモータの動きを一旦止める
       RemoteStartProgram(CONN,"lost.rxe");   //親機が子機に命令してボール置く
       Wait(2000); //子機がボールを置いている時間、親機は待つ
       OnRev(OUT_BC,30); //元の位置(直角D)に戻るためにロボットを後退させる
       Wait(t4-t3);  //t4-t3の時間後退させる...                                      
   }
}

,t3はロボットが缶に近づく前の時間で、t4はロボットが缶に近づいた後の時間である。これよりt4-t3とは、ロボットが缶に近づくために動いた時間だけ後退させる。これにより、どの位置に缶があっても元の位置に戻ってこられる。

メインプログラム

task main()
{
   go_s;       //Xから赤いボールの方向に直進                                                     
   Wait(1000); //1秒間直進
   stoop; //ボールを掴むためロボットの動きを一旦止める
   tukamu(); //赤いボールを掴んで持ち上げる
   go_s; //交差点Dを直進
   Wait(2000); //2秒間直進
   special(); //D-F間の急カーブとFの直角があっても止まらなでライントレース
   tuuzyou(); //F-E間ライントレースをしてEの交差点を認識する
   massugu();    //Eの交差点は直進                                          
   sirotuuzyou(); //Dの直角で終わるプログラム
   sagasu(); //缶を探して、缶に近づいて、赤いボールを缶に置いて元の位置(直角D)に 
戻る
   gyakuspe(); //D-E間の走行でEの直角があっても終わらないプログラム
   gyakutuuzyou(); //E-I間の走行で、Iの交差点で終わるプログラム
   go_s; //直進して青いボールを撮れる距離まで移動する
   Wait(700); //0.7秒間直進
   stoop; //ボールを掴むためロボットの動きを一旦止める
   tukamu();    //ボールを掴んで持ち上げる                         
   sagasu2(); //缶を探して、缶に近づいて、青いボールを缶に乗せて終了
}

まとめと感想

今回はロボットの組み立てからやり直したので、とても苦労した。 また、今までのプログラムをいろいろと改良しないといけなかった点も苦労した一つである。通信は、理解するまで時間が少しかかったが、慣れてしまえば便利な武器として使えるようになった。


添付ファイル: fileIMG_1053.jpg [詳細] fileIMG_1130.jpg [詳細] fileKIMG0103.jpg [詳細] fileKIMG0101.jpg [詳細] fileKIMG0093.jpg [詳細] fileKIMG0096_LI.jpg 1件 [詳細] file2018b-mission3.png [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2019-02-14 (木) 21:39:42 (5d)