[[2019a/Member]]
目次 [#p5af44b8]
#contents
*課題について [#b9d22da4]
ピンポン玉または青と赤のボールを運搬して、所定の容器の中に入れる。
#ref(2019a-mission3.png)
**フィールドの説明 [#c7515b2f]
~・フィールドは課題2で使用した紙を使用する。
~・生協のお弁当の四角いプラ容器2つをそれぞれ円内に置き、片方に玉を2個入れる。
~・残りの2個の玉は課題2と同じ位置に置く。その際、ゴムタイヤやプレートの上に置いてもよい。
~・プラ容器には色をつけたり文字や記号を書いてもよい。
~・プラ容器は両面テープ等でフィールドに固定してもよい。
~・2枚の紙の境界にはそれぞれ幅1cm、合計2cmの黒線を描いてもよい。
*方針 [#t8965617]
最初に、大まかにどんなロボットにするかを話し合って次のような条件のロボットにすることになった。
~・ライントレースの正確性を増すために光センサーを二つ使用する。
~・容器の中の玉も掴めるように上から挟んで掴むアームにする。
#br
~斬新なアイデアは出てこなかったため、愚直にライントレースをしていくことにした。これにあたり、不確定要素を減らすためルールに従い2枚の紙の境界に黒線を引いた。また、分かりやすくするために新しくできた交差点をそれぞれ �� , �勝任箸靴�(下図参照)。
#ref(sketch-1564132256515.png)
**ルート [#x03f66d4]
 �,泙�Aからスタートし、M,Kを通ってLで玉を掴む。
~ �⊃兇衒屬辰董⇒茲親擦鮹�りM>B>X>X'>B'>M'>K'>J'と進んでゴールに玉を入れる。
~ �8綢爐靴覆�ら向きを変え、L'まで進み玉を掴む。
~ �た兇衒屬辰�K'>J'と進んでゴールに玉を入れる。
~ �ジ綢爐靴覆�ら向きを変え、M'>B'>X'>X>B>C>Iと進んで容器の中の玉を掴む。
~ ��振り返ってC>B>X>X'>B'>C'>I'と進んでゴールに玉を入れて終了。
*ロボット [#c1065932]
**アーム [#g5ca7f05]
当初作ったアーム(下図左)では容器の中の玉を掴めなかったため、下図右のような形状に改良した。
#ref(Arm1.png)
この際、アームが開きすぎないようにストッパーをつけた(下図赤丸で囲った部分)。
#ref(stopper.png)
また、奥行きも追加して二つ同時に掴めるようにした。これによって移動距離と時間、プログラムが短縮された。
~アームの一番下の部分が一部繋がっていないのは、丁度いい長さの棒がなかったからである。特に意味はない。
**光センサー [#tccfb710]
黒線の幅に合うように調節して取り付けた。
#ref(DSC_0120.JPG)
**全体 [#vbe0b3cb]
#ref(DSC_0118.JPG)
横から見るとこのようになっている。アームが重いので、本体を後ろに配置してバランスをとった。
~正確性を増すため、センサーはタイヤにできるだけ近づけた。
----
#ref(DSC_0128.JPG)
コードは本体の間にまとめて通して見栄えを良くした。
*プログラム [#n0aab105]
**マスター側 [#a1cd1a54]
マスター側が移動とセンサーを担当する。
 #define KOSATEN 37      //黒かどうかの境界

 #define completed 15   //スレーブ側に動作の終了を伝える
 
 #define turn_left OnRev(OUT_A,70);OnFwd(OUT_B,70);     //左折
 #define go_left OnRev(OUT_A,85);Off(OUT_B);            //進みつつ左に曲がる
 #define go_straight OnRev(OUT_AB,70);                  //直進
 #define go_right OnRev(OUT_B,85);Off(OUT_A);           //進みつつ右に曲がる
 #define turn_right OnRev(OUT_B,100);OnFwd(OUT_A,100);  //右折
 #define short_break Off(OUT_AB);Wait(1000);            //小休止
 #define brake Off(OUT_AB)                              //停止

 sub follow_line()              //通常のライントレース
 {
   while((SENSOR_1>KOSATEN)||(SENSOR_2>KOSATEN)){
    int d=SENSOR_1-SENSOR_2;
     if (d<-6){
      turn_right;
    }else if (d<-3){
      go_right;
    }else if (d<=3){
      go_straight;
    }else if (d<=6){
      go_left;
    }else {
      turn_left;
    }
   }
   PlaySound(SOUND_CLICK);
   brake;Wait(200);
 } 
両方のセンサーが37以上の時、if以下の動作をする。今回は左右の数値の差で判断するようにした。
~両方の数値が37以下で交差点と判断し、停止する。停止するときに音が鳴るようにした。
~これによって交差点をちゃんと判断しているかどうか、あるいは違うところで交差点と判断していないかがわかりやすくなる。
 sub follow_line2(int followtime)        //タイマーを使うライントレース
 {
   long t0=CurrentTick();
   while(CurrentTick()-t0<followtime){
    int d=SENSOR_1-SENSOR_2;
     if (d<-6){
      turn_right;
    }else if (d<-3){
      go_right;
    }else if (d<=3){
      go_straight;
    }else if (d<=6){
      go_left;
    }else {
      turn_left;
    }
   }
   PlaySound(SOUND_CLICK);
   brake;Wait(200);
 } 
基本的には通常と同じ。K>Lに進むときなど、距離を調節する必要がある所で使う。
 sub chokusinL()                       //直進左
 sub chokusinL()                    //直進左
 {
  go_left;Wait(500);
 } 
 
 sub chokusinR()                       //直進右
 sub chokusinR()                    //直進右
 {
  go_right;Wait(500);
 }
 
 sub sasetsu()                        //左折
 sub sasetsu()                      //左折
 {
  turn_left;Wait(500);
  go_left;Wait(500);
 }
 
 sub usetsu(int migi)                        //右折
 sub usetsu(int migi)               //右折
 {
  turn_right;Wait(500);
  go_right;Wait(migi);
 }
 
 sub turn_behind()                  //振り向く
 {
  turn_left;Wait(1000);
  while(SENSOR_1>KOSATEN){
  turn_left;
  }
  Off(OUT_BC);
 }

 sub backleft()                     //後退し右を向く
 {
  OnFwd(OUT_A,100);Off(OUT_B);Wait(1500);
  turn_right;Wait(600);
  Off(OUT_AB);
 }
 
 sub backright()                    //後退し左を向く
 {
  OnFwd(OUT_B,100);Off(OUT_A);Wait(1400);
  turn_left;Wait(500);
  Off(OUT_AB);
 }

 sub ball_catch()                  //玉を掴む
 sub ball_catch()                   //玉を掴む
 {
  int msg;
  SendRemoteNumber(1,MAILBOX1,12);
  while(msg==completed){
   ReceiveRemoteNumber(MAILBOX1,true,msg);
  }
 } 
 
 sub ball_release()               //玉を放す
 sub ball_release()                 //玉を放す
 {
  int msg;
  SendRemoteNumber(1,MAILBOX1,11);
  while(msg==completed){
   ReceiveRemoteNumber(MAILBOX1,true,msg);
  }
 }

 sub arm_up()                    //アームを上げる
 sub arm_up()                       //アームを上げる
 {
  int msg;
  SendRemoteNumber(1,MAILBOX1,13);
  while(msg==completed){
   ReceiveRemoteNumber(MAILBOX1,true,msg);
  }
 }
 
 sub arm_down()                  //アームを下げる
 sub arm_down()                     //アームを下げる
 {
  int msg;
  SendRemoteNumber(1,MAILBOX1,14);
  while(msg==completed){
   ReceiveRemoteNumber(MAILBOX1,true,msg);
  }
 }

 sub up_catch()                //アームを上げながら閉じる
 sub up_catch()                     //アームを上げながら閉じる
 {
  int msg;
  SendRemoteNumber(1,MAILBOX1,16);
  while(msg==completed){
   ReceiveRemoteNumber(MAILBOX1,true,msg);
  }
 }
 
 sub down_release()                //アームを下げながら開く
 sub down_release()                 //アームを下げながら開く
 {
  int msg;
  SendRemoteNumber(1,MAILBOX1,17);
  while(msg==completed){
   ReceiveRemoteNumber(MAILBOX1,true,msg);
  }
 }

 task main()
 {
  SetSensorLight(S1);//右カラーセンサー
  SetSensorLight(S2);//左カラーセンサー
  arm_up();
  short_break;
  ball_release();
  go_straight;Wait(2000);
  follow_line();            //M
  chokusinR();              //K
  follow_line2(1500);
  short_break;              //L
  arm_down();
  short_break;
  ball_catch();             //ボールキャッチ
  short_break;
  arm_up();
  short_break;
  turn_behind();
  follow_line();
  chokusinL();              //K
  follow_line();
  usetsu(500);              //M
  follow_line();
  sasetsu();
  follow_line();
  chokusinL();              //B
  follow_line();
  usetsu(500);              //X
  follow_line();
  sasetsu();                //X'
  follow_line();
  chokusinR();              //B'
  follow_line();
  sasetsu();                //M'
  follow_line();
  sasetsu();                //K'
  follow_line2(1000);
  short_break;              //J'
  ball_release();           //リリース
  short_break;
  backleft();               //K'
  follow_line2(3700);
  short_break;              //L'
  arm_down();
  short_break;
  ball_catch();             //ボールキャッチ
  short_break;
  arm_up();
  short_break;
  turn_behind();
  OnFwd(OUT_AB,30);Wait(100);
  follow_line();
  usetsu(500);              //K'
  follow_line2(500);
  short_break;              //J'
  ball_release();           //リリース
  short_break;
  backright();
  follow_line();
  chokusinL();
  follow_line();
  usetsu(500);              //M'
  follow_line();
  chokusinL();              //B'
  follow_line();
  usetsu(500);              //X'
  follow_line();
  sasetsu();                //X
  follow_line();
  sasetsu();                //B
  follow_line();
  usetsu(400);              //C
  follow_line2(1650);
  short_break;              //I
  arm_down();
  short_break;
  ball_catch();             //ボールキャッチ
  short_break;
  up_catch();
  short_break;
  backleft();               //C
  follow_line();
  usetsu(500);              //B
  follow_line();
  usetsu(500);              //X
  follow_line();
  sasetsu();                //X'
  follow_line();
  sasetsu();                //B'
  follow_line();
  usetsu(700);
  follow_line2(900);
  short_break;              //J'
  down_release();           //リリース
  short_break;
  arm_up();
  short_break;
  backright();              //K'
 }                          //終了
**スレーブ側 [#jc329156]
スレーブ側がアームの上下と掴みを担当する。
 #define ball_release 11
 #define ball_catch   12
 #define arm_up       13
 #define arm_down     14
 #define completed    15
 #define up_catch   16
 #define down_release   17

 task main()
 {
  int msg;
 
  while(true){
   ReceiveRemoteNumber(MAILBOX1,true,msg);
   if(msg==ball_release){
    OnFwd(OUT_A,50);Wait(500);Off(OUT_A);Wait(500);    //玉を放す
    SendResponseNumber(MAILBOX1,completed);
   }
   if(msg==ball_catch){
    OnRev(OUT_A,50);Wait(600);Off(OUT_A);Wait(500);    //玉を掴む
    SendResponseNumber(MAILBOX1,completed);
   }
   if(msg==arm_up){
    OnFwd(OUT_B,50);Wait(600); OnFwd(OUT_B,5);Wait(500);   //アームを上げる
    SendResponseNumber(MAILBOX1,completed);
   }
   if(msg==arm_down){
    OnRev(OUT_B,30);Wait(600); OnFwd(OUT_B,5);Wait(500);   //アームを下げる
    SendResponseNumber(MAILBOX1,completed);
   }
   if(msg==up_catch){
    OnFwd(OUT_B,40);OnRev(OUT_A,15);Wait(300);        //掴みながら持ち上げる
    SendResponseNumber(MAILBOX1,completed);
   }
   if(msg==down_release){
    OnRev(OUT_B,10);OnFwd(OUT_A,20);Wait(150);        //下ろしながら放す
    SendResponseNumber(MAILBOX1,completed);
   }
   Wait(100);
   msg=0;
  }
 }                     //終了
*まとめと感想 [#s5ba3fd0]
特に捻ったアイデアもなく地味なものになったと思ったが、結果的にはそれが功を奏し、良い結果を出すことができた。三人グループだったため人数的に不利だと思ったが、うまく作業を分担して完成させられた。容器の中の玉を掴む所の調整が一番難しく、本番では運次第といった形になってしまった。ここだけは悔しさが残る。ただ、その前の二つはほぼ完璧に仕上げることができたので良かった。時間をかけた甲斐があった。

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