2018a/Member

目次

課題3:空き缶運搬ロボット

空き缶を分別して所定の場所に運ぶ。

2018a-mission3.png

フィールドの説明

・フィールドは課題2で使用した紙を使用する。

・2種類の空き缶(Aタイプ,Bタイプ)をそれぞれ3個ずつ用意し、円XにABA、円YにBABとなるように3段ずつ積み上げる。

・空き缶には色をつけたり文字や記号を書いてもよい。あるいは周囲に紙を張ってもよい。

ミッション

Aタイプの空き缶を円Y内に、Bタイプの空き缶を円X内に運ぶロボットを作成せよ。

ロボットの説明

今回は2つのペアでそれぞれロボットを作り、Bluetoothの通信を用いて、連携して缶を運ぶという方法を採用した。缶が3段積み上がっているので、1つ目のロボット(Master)が2段目の缶を抑えて下に落とす役割を行い、もう一つのロボット(Slave)が1段目と3段目の缶を掴んで移動させる役割を行った。

Master側ロボット

Master側ロボットは、二段目の缶を固定して一段目と三段目が移動した後に円内に落とすという役割をしている。ロボットの全体像は以下の写真の通りである。

図7.jpg

動力(タイヤ)部分

移動方法は通常のロボットと同じで、二つのモーターを利用して回転したり前後に進んだりすることが可能である。光センサーや超音波センサーなどは用いずに、すべて時間で動きを制御している。

最終課題 資料写真_6.jpg

缶を掴む部分

4つの直角に曲がっている部品を用いて、確実に二段目の缶を固定できるようにした。歯車を用いて、片側が回転したのと同じ分だけ逆側も回転して缶を掴む構造となっている。

最終課題 資料写真_7.jpg

Slave側ロボット

Slave側ロボットは、一段目と三段目の缶を掴み所定の円の中に持っていく役割をしている。ロボットの全体像は以下の写真の通りである。

動力(タイヤ)部分

Master側ロボットと同様の構造をしている。一段目を掴むために、操作ボックスをできるだけ下に置く必要があったため、モーターが操作ボックスの横に置かれロボット全体の幅が大きくなった。後ろのタイヤもそれぞれのモーターごとに一つつけるようにした。このことによって重心がかなり安定し、倒れるなどのトラブルをなくすことができた。操作ボックスは、電源を入れるのを簡単にするため裏返しの状態にした。

また、超音波センサーを用いて、Master側が二段目の缶を掴んだタワーを発見し近くまでいけるようにした。仮にMaster側が三段目の缶を落としたとしてもタワーを見分けられるように、超音波センサーの位置を二段目の缶がある高さにおいた。

最終課題 資料写真_2.jpg

缶を掴む部分

Master側とほぼ同様の方法で缶を掴む構造にした。一段目と三段目の缶を掴まなければならないが、モーターが一段目を掴む部分の近くにあるために、三段目の方が掴む力が弱くなってしまうという問題があった。これを解決するため、三段目には小さなタイヤをつけて缶をタイヤのゴムの摩擦で押さえるようにし、一段目はタイヤをつけずに缶全体を囲むことができるような構造にした。

また、一段目と三段目の缶を掴む部分をつなぐ十時の棒がかなり長いため、斜めになってしまったり、左右が同じように回転しないなどの問題が起きた。そこで、後ろ側に大きな支えの棒をつけ、途中に歯車でモーターの回転を逆側に伝える部分を増やしたりした。

図6.jpg

メインプログラムへの準備

今回のプログラムでは、課題3のヒントであった超音波センサーを用いて缶の位置を特定するプログラムを用いたり、Bluetoothを用いてMasterとSlaveでメッセージを送り合うことでそれぞれのプログラムを動作させたりした。

超音波センサーを用いて缶の位置を特定し、缶の手前まで移動するプログラム

2018a/Mission3のヒントにあったプログラムの例を少し改良して用いた。モーターかセンサーの調子が悪く、全体的に方向が缶の右側によってしまうことがわかったので、向きを左に少し動かす命令を最後に入れている。Master側のみ利用した。以下用いたプログラム

#define SPEED 50
#define SPEED_SLOW 30
const float diameter = 5.45;  // タイヤの直径(cm)
const float track = 10.35;    // タイヤのトレッド幅(cm)
const float pi = 3.1415;      // 円周率

void fwdDist(float d) // 距離 d cm 前進
{
   long angle;
   angle = d/(diameter*pi)*360.0;      // 角度を計算する
   RotateMotorEx(OUT_BC, SPEED_SLOW, angle, 0, true, true);
}

void turnAng(long ang) // 角度 ang 度の時計回りの旋回
{
   long angle;
   angle = track/diameter * ang;
   RotateMotorEx(OUT_BC, SPEED_SLOW, angle, 100, true, true);
}

int searchDirection(long ang)  // 現在の方向を中心にang度の範囲で探し
                              // 障害物までの距離を返す
{
   long angle,tacho_min=0, tacho_corr ;
   int d, d_min;

   d_min = 300;           // 仮の最小値

   angle = (track/diameter)*ang;  // 旋回角度からタイヤの回転を計算
   turnAng(ang/2);                // 指定された角度の半分を旋回
   ResetTachoCount(OUT_BC);       // 角度計測をリセット

   OnFwdSync(OUT_BC,SPEED_SLOW,-100);   // 反時計回りに旋回
   while(MotorTachoCount(OUT_B)<=angle){

       d = SensorUS(S1);  // 現在の距離

       if (d < d_min){
           d_min = d;        // 仮の最小値を更新
           tacho_min = MotorTachoCount(OUT_B);  // 仮の最小値を更新したときのモータの回転角度
       }
   }
   OnFwdSyncEx(OUT_BC,SPEED_SLOW,100,RESET_NONE);
   until(MotorTachoCount(OUT_B) <= tacho_min || SensorUS(S1) <= d_min);

   Wait(14);  // 微調整
   Off(OUT_BC);Wait(500);
   return d_min;
   OnFwd(OUT_C,30);
   OnRev(OUT_B,30);
   Wait(200);
}

Bluetoothでメッセージを送受信し、受信時にプログラムを動かすプログラム

NXTでは、Bluetoothを用いて複数のロボットを連動させて動かすことが可能である。今回はこれを用いて、Master側が二段目の缶を掴んだら、Slave側が一段目と三段目の缶を掴んで所定の場所に移動するという方法で連携して三段の缶を移動させる方法を考えた。

Master側からSlave側にメッセージを送ると、Slave側が動き出すプログラム

Master側

task main()
{
      SendRemoteNumber(1,MAILBOX1,11); //Slave側のMAILBOX1に11という文字を送る
}

Slave側

task main()
{
   int msg,frg1=1;
   while(frg1){
         ReceiveRemoteNumber(MAILBOX1,true,msg);   // MAILBOX1の値を受け取りmsgに格納
   if(msg==11){                                    //もしmsgにある数字が11ならば下の命令を行う
         (動かしたい命令);
          frg1=0;
              }
    }
}

Slave側からMaster側にメッセージを送ると、Master側が動き出すプログラム

Slave側

task main()
{
      SendResponseNumber(MAILBOX1,12); //Master側のMAILBOX1に12という文字を送る
}

Master側

task main()
{
    int msg,frg1=1;
   while(frg1){
         ReceiveRemoteNumber(MAILBOX1,true,msg);   // MAILBOX1の値を受け取りmsgに格納
   if(msg==12){                  //もしmsgにある数字が12ならば下の命令を行う
         (動かしたい命令);
          frg1=0;
              }
    }
}

この2つのプログラムを交互に行うことで、片方が動いている間はもう片方は静止しているので、2つのロボットの衝突などを避けられるようにした。

命令の定義

前進、左折、右折、旋回などの命令やスピードの値を定義することで、メインプログラムが少しでも簡潔になるようにした。Slave側のみ利用している。

#define SPEED_H 30
#define SPEED_L 35
#define OnRL(speedR,speedL) OnFwd(OUT_B,speedR);OnFwd(OUT_C,speedL);
#define go_forward  OnRL(SPEED_H, SPEED_H);    // 前進

ロボットを前進させるためのプログラム

サブルーチンや命令の定義を使って前進する命令、時間、電源を切る命令をひとまとめにした。

Master側

sub zen(int i)
{
    int t;
	t=i*50;
	OnFwd(OUT_B,50); OnFwd(OUT_C,49);
	Wait(t);
	Off(OUT_BC);
}
sub zeny(int i)
{
	int t;
	t=i*100;
	OnFwd(OUT_B,25); OnFwd(OUT_C,25);
	Wait(t);
	Off(OUT_BC);
}

Slave側

#define str(X) go_forward;Wait(X);Off(OUT_BC);

ロボットを後退させるプログラム

上と同様にひとまとめにした。

Master側

sub kou(int i)
{
	int t;
	t=i*50;
	OnRev(OUT_B,50);OnRev(OUT_C,49);
	Wait(t);
	Off(OUT_BC);
}

Slave側

#define Back(X) OnRev(OUT_BC,30);Wait(X);Off(OUT_BC);

ロボットを回転させるプログラム

片方のタイヤと同じ速度でもう片方のタイヤを逆に回転させる旋回と、片方のタイヤは止めておいてもう片方のタイヤだけ動かす右折、左折の方法の2つを採用した。

Master側

#define kail OnFwd(OUT_B,50);OnRev(OUT_C,50);Wait(500);Off(OUT_BC); //左旋回を0.5秒間行う
#define kair OnFwd(OUT_C,50);OnRev(OUT_B,50);Wait(500);Off(OUT_BC); //右旋回を0.5秒間行う

Slave側

#define turn_rt(X)  OnRL(SPEED_L, -SPEED_L);Wait(X);Off(OUT_BC);  // 右旋回
#define turn_right(X)  OnRL(SPEED_L, 0);Wait(X);Off(OUT_BC);      // 右折
#define turn_left(X) OnRL(0, SPEED_L);Wait(X);Off(OUT_BC);        // 左折
#define turn_lt(X) OnRL(-SPEED_L, SPEED_L);Wait(X);Off(OUT_BC);   // 左旋回

缶をつかむためのプログラム

Master側のみ利用していて、Slave側は直接メインプログラムに入力している。また、Master側とSlave側でモーターの向きが逆なので命令が逆になっている。

sub armc()
{
	OnFwd(OUT_A,30);
}

缶を離すためのプログラム

Master側のみ利用していて、Slave側は直接メインプログラムに入力している。

sub armo()
{
	OnRev(OUT_A,30);
}

メインプログラム

Master側

task main()
{
	int msg,frg1=1,frg2=1;       //ヾ愎frg1,frg2を定義
 	zen(51);              //2.55秒、50%の速さで前進
	kair;                //0.5秒右旋回
	zen(75);              //3.75秒、50%の速さで前進
	kair;                //0.5秒右旋回
	zeny(20);              //2秒、25%の速さで前進
	armc();               //二段目の缶を掴む Xに移動完了	
       SendRemoteNumber(1,MAILBOX1,11);//送信	//Slave側に11の数字を送信(一旦停止)
       while(frg1){
		ReceiveRemoteNumber(MAILBOX1,true,msg);//絢信		
       if(msg==12){
			armo();       //唄未鯲イ
			kou(20);      //1秒後退
			kair;        //0.5秒右旋回
			zen(44);      //20 2.2秒、50%の速さで前進
			kail;        //21 0.5秒左旋回
			zeny(20);      //22 0.5秒、25%の速さで前進
			armc();       //23 二段目の缶を掴む Yに移動完了		
                       frg1=0;       //関数frg1に0を代入
			SendRemoteNumber(1,MAILBOX1,13); //24 Slave側に13の数字を送信(一旦停止) 
                    }
	 }
	while(frg2){
		ReceiveRemoteNumber(MAILBOX1,true,msg); //43 受信		
       if(msg==14){
			armo();             //44 缶を離す
			frg2=0;       //関数frg2に0を代入(完全停止)
		}
	}
}

Slave側

task main()
{
   int msg,frg1=1,frg2=1;
   while(frg1){
   ReceiveRemoteNumber(MAILBOX1,true,msg);   //MAILBOX1の値を受け取りmsgに格納
   if(msg==11){ 
      SetSensorLowspeed(S1);  //缶の方向を探した後、近づいて10cm手前で停止

      int d = searchDirection(120);
      if (d > 10) {
                    fwdDist(d-10.0);
                     }
      str(500);            //0.5秒前進
      Off(OUT_A);           //モーターAの電源を切る
      str(400);            //0.4秒前進
      OnRev(OUT_A,30);         //一段目と三段目の缶を掴む Xに移動完了
      Wait(1000);           //1秒待つ
      Back(1000);           //1秒後退
      SendResponseNumber(MAILBOX1,12); //Master側に12の数字を送信(一旦停止)
      frg1=0;             //関数frg1に0を代入
         }
   }
   while(frg2){
    ReceiveRemoteNumber(MAILBOX1,true,msg);   //25 MAILBOX1の値を受け取りmsgに格納
    if(msg==13){   
   turn_lt(600);                       //26 0.6秒左旋回
   str(4000);             //27 4秒前進
   turn_rt(1000);           //28 1秒右旋回
   str(1000);             //29 1秒前進
   OnFwd(OUT_A,30);          //30 缶を離す  Yに移動完了
   Wait(500);             //0.5秒待つ
   Off(OUT_A);             //モーターAの電源を切る
   Back(1000);             //31 1秒後退
   turn_rt(800);            //32 0.8秒右旋回
   str(500);              //33 0.5秒前進
   turn_lt(1000);           //34 1秒左旋回
   str(2000);             //35 2秒前進
   turn_left(1000);          //36 1秒左折
   OnRev(OUT_A,30);          //37 一段目と三段目の缶を掴む
   Wait(1000);             //1秒待つ
   Back(1000);             //38 1秒後退
   turn_rt(2000);           //39 2秒右旋回
   str(4000);             //40 4秒前進
   OnFwd(OUT_A,30);          //41 缶を離す
   Wait(1000);             //1秒待つ
   Off(OUT_A);             //モーターAの電源を切る
   SendResponseNumber(MAILBOX1,14);    //42 Master側に14の数字を送る
   frg2=0;               //関数frg2に0を代入(完全停止)
   }
 }
}
図8.jpg

上のプログラムに説明として書かれている数字は、上の図の数字と連動している。本番はこの数字の順番で行った。図をわかりやすくするため、実際の大きさと上の図は異なる。矢印は前進や後退、丸は旋回や缶を掴むまたは離す運動、送受信を示している。赤い矢印や丸はMaster側のロボットの運動、青い矢印や丸はSlave側のロボットの運動を示している。

結果

一回目は、Master側が缶を掴むことができず、タワーを倒してしまい0点であった。二回目は、Master側は缶をつかめたものの、Slave側があまりいい位置に缶を運べずわずか2点であった。

技術点は、平均12.2点となり、全体合計で14.2点であった。順位は13チーム中7位という結果であった。

課題3の反省・感想

課題3は、テスト前ということもあってあまり時間がなく点を取る作戦などをしっかりと練ることができなかったが、チームの人達と協力して、今まで学んできたプログラミングなどを駆使して完成できたのでよかった。ロボコンでは、あまりいい点を取ることができなかったので残念だった。自分は主にSlave側のロボットの制作とプログラミングを行なったが、1段目と3段目の缶を掴むには今までとは違って大きいロボットが必要だっため、ロボット自体の設計からとても難しかった。大きくなったことで色々な問題点が出てきたが、チームの人と意見を出し合いながら解決することができてよかった。プログラミングでは、時間での制御だけでなく、回転やライントレースなども用いると、もう少し正確に缶を移動できたと思うので、自分のプログラミング力をもっとつけていきたいと思った。

この授業を通して初めてロボットをプログラミングで操作するという経験をしたが、プログラミング言語でロボットにやってほしいことを伝えるのは非常に難しいことだということがわかった。一方でロボットを自分の力で指示通り動かすことができる楽しさも知ることができた。本当に貴重な体験をさせてもらいました。ありがとうございました。


添付ファイル: file図8.jpg 40件 [詳細] file図7.jpg 44件 [詳細] file図6.jpg 42件 [詳細] file図5.jpg 19件 [詳細] file最終課題 資料写真_2.jpg 42件 [詳細] file最終課題 資料写真_7.jpg 35件 [詳細] file最終課題 資料写真_6.jpg 32件 [詳細] file2018a-mission3.png 37件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2018-08-12 (日) 18:29:10 (378d)