[[2019a/Member]]
#contents
*課題・方針 [#tf80aef5]
**ポリシー [#q02baee2]
まず、課題やロボットが具体的に明らかになる前に、決めていたことがある。~
それは、作動速度は遅くても、正確に動作するロボットを作ろうということである。~
**課題 [#s6a09795]
今回の課題3は…~
課題2で使用した紙を使用し2つを上下逆になるように組み合わせてフィールドとする。~
生協のお弁当の四角いプラ容器2つをそれぞれ円内に置き、片方に玉を2個入れる。~
残りの2個の玉は課題2と同じ位置に置く。~
それらの玉を、空の容器の方に入れる。~
フィールド(Z,Z'および2枚の境界のラインはルールに則って付け加えた)~
&ref(コース.jpeg);
**方針 [#f59d202b]
ラインをたどってボール間を移動、その合間にボールの補足、解放をしてミッションを達成する。
*ハード [#t554702d]
2台連携ではタイミングよく連携を取れるかどうかにおいて不確定かと感じたので、一体型にし、代わりにスペック向上を目指した。
**ルールに従うために [#q9277dd4]
ロボットはAの四角い枠に入らなくてはいけないので、できるだけコンパクトになるようにした。~
その際、課題1で作成したロボットの『移動用モーターを上から吊り下げる』というアイデアを参考にした。~
**構成案 [#w9d2426c]
-ギアを使ってモーター一つで左右から同時に挟めるクレーンゲームのようなアームをつければよいのでは~
-そのアームを上下させる機構が必要ではないか~
-やはり移動のモーターは安定性のためにギアが必要ではないか~
-色覚センサーを2つ搭載してライントレースを左右の端を決めずにできるようにした方が安定するのでないか~
-超音波センサーを使ってボールとの距離を測れば良いのではないか~
などの案が出た
**構成案実現のために [#a9abcc92]
分担をしてパーツごとで組むことにした。~
それを持ち寄って、互いに改良していけば更に高度なものができ、効率化にも繋がると考えたためである。~
**概形完成後のテコ入れ [#ie60f14f]
その『持ち寄り』の先で、完成後も新たに変更した点についてである。
***直上型モーター配置 [#a46f5c41]
先述の通り、コンパクト型にするために課題1でのロボットを参考にこの構造をとった。~
そのほかにも、横置き型のモーター配置で設計したところ、全体に不安定なロボットになってしまい、その改善という理由がある。
参考:課題1のロボット
&ref(v1robot.jpeg);
そのほかにも、横置き型のモーター配置で設計したところ、全体に不安定なロボットになってしまい、その改善という理由がある。~
参考:課題1のロボット~
&ref(v1robot.jpeg);~
***クレーン先 [#h553004e]
クレーン先のアームはクレーンゲームのように緻密な操作でなくても、確実に細くできるものとしなくてはならない。したがって、背後に壁を設けたり、前後の補足範囲を広くしたり、逆にプラ容器に収まるように横幅を極限まで削ったりした。
***クレーン関連のギア [#u52477b9]
-当初は同じものをアームじゅうにつたわせて、シンプルな構造にしていたが、若干ガクガクしたりで不安定だったため、ギアが最も噛む構造を探して新しい組み合わせに変更した。
-両側からギアで挟むことで、アームの連動性も上がった。
***クレーン上下用モーターの周辺ギア [#fc3d87c8]
クレーンをもちあげるのはたった一つのモーターなので、速さよりも圧倒的にパワーが必要となった。~
なので、比重の大きいギアを採用した。
***ダブルカラーセンサー [#q9283bdb]
課題2と同様、色覚センサーの位置にこだわった。作成したプログラムの都合上、ラインの横幅よりも少しだけ短いくらいの横幅がちょうど良い。前後関係も、前回同様、移動のモーターよりわずかに前方というふうにした。
**最終的な構成 [#b8e6a18c]
プログラムの組みやすさを考えると以下の通りとなった。超音波センサーは時間がなかったため不採用。~
&ref(system.jpeg);
**完成系 [#p574c054]
クレーンの系~
&ref(clane.jpeg);
&ref(clane.jpeg);~
それ以外の(ライントレーサー)~
&ref(tracer.jpeg);
&ref(tracer.jpeg);~
全体像~
&ref(v3robot.jpeg);
&ref(v3robot.jpeg);~
**まとめ [#i8c2d495]
-確実にボールを捉えることができ
-安定して走破でき~
るための工夫を凝らした。
*プログラム [#ub2b3db5]
**連携 [#p8edf9fd]
二台はbluetoothで連携している。ラグの考慮として、short_break(小休憩)などを使ってつりあいをとる。
**注意した点 [#ee2b0939]
効率にも目を向けて、作業中も注釈文やビープ音を使って修正箇所を発見しやすくした。~
**ルート [#ma530ef8]
黒いラインを辿ることのみの移動とし全ての行程を確実なものにした。~

**SLAVE [#pc3ef195]
SLAVEのなす操作は、ボールをホールド、リリースしたり、クレーンを上昇・下降したりと理論上は単純なものばかりである。~
~
まずメールボックス用のナンバーを定義して…~
 #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){                          //メッセージがball_releaseならば
   OnFwd(OUT_A,50);Wait(500);Off(OUT_A);Wait(500);//(ボールを放す動作)
   SendResponseNumber(MAILBOX1,completed);       //completedというメッセージを
 masterに送る(以下これに倣う)
  }                                               //ボールをリリースする動作
  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);                                      //小休憩(ラジコンの課題の時
 これがなければカクカクした動作となり、ちょっとずつしか動かないということで入れた。そ 
 の名残。今はif文の中の動作でwaitが使われているので必要がなかったかもしれない)
  msg=0;                                          //メッセージをリセット!
  }                                               //while閉
 }                                                //task main閉
**MASTER [#ib2e4e7e]
***defineとサブルーチン [#he52402a]
説明の前段階として定義とサブルーチンを紹介しておく~
-defineの紹介~
 #define KOSATEN 37                     //色覚センサー黒のしきい値。交差点判別用
 #define completed 15                   //slaveから送られる実行済みというメッセージ
 #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)                             //ブレーキ
define_その他説明~
--何故逆回転の右回転がパワー100なのかは今考えると不明。(ミスかもしれない)
--それぞれの動作のパワーの大きさは、内側に行く動きの大きさに比例させた。このことでタイマーを使う時に違和感がなくなる。
--break(小休憩)とbrake(ブレーキ)は綴りが似ているが意味は異なる。その意味に合わせて合わせて使い分けた。
-subの説明~
  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);
  }
  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);
  }
 sub chokusinL()                       //直進左
 {
 go_left;Wait(500);                    //Waitは調整
 }
 sub chokusinR()                       //直進右
 {
  go_right;Wait(500);                  //同上
 }
 sub sasetsu()                         //左折
 {
  turn_left;Wait(500);                 //左回転と左前方直進の合わせ技
  go_left;Wait(500);                   //同上
 }
 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()                     //玉を掴む(slaveの動作)
 {
  int msg;
  SendRemoteNumber(1,MAILBOX1,12);
  while(msg==completed){
   ReceiveRemoteNumber(MAILBOX1,true,msg);
  }
 }
 sub ball_release()                   //玉を放す(slaveの動作)
 {
  int msg;
  SendRemoteNumber(1,MAILBOX1,11);
  while(msg==completed){
   ReceiveRemoteNumber(MAILBOX1,true,msg);
  }
 }
 sub arm_up()                         //アームを上げる(slaveの動作)
 {
  int msg;
  SendRemoteNumber(1,MAILBOX1,13);
  while(msg==completed){
   ReceiveRemoteNumber(MAILBOX1,true,msg);
  }
 }
 sub arm_down()                       //アームを下げる(slaveの動作)
  {
  int msg;
  SendRemoteNumber(1,MAILBOX1,14);
  while(msg==completed){
  ReceiveRemoteNumber(MAILBOX1,true,msg);
  }
 }
 sub up_catch()                       //アームを上げながら閉じる(slaveの動作)
 {
  int msg;
  SendRemoteNumber(1,MAILBOX1,16);
  while(msg==completed){
  ReceiveRemoteNumber(MAILBOX1,true,msg);
  }
 }
 sub down_release()                   //アームを下げながら開く(slaveの動作)
 {
  int msg;
  SendRemoteNumber(1,MAILBOX1,17);
  while(msg==completed){
  ReceiveRemoteNumber(MAILBOX1,true,msg);
  }
 }
sub_その他の説明
-masterが行う右折・左折・直進右・直進左・直進などは交差点や曲がり角など、色覚センサーで調整がつきにくいところを原始的に動作の時間調整だけで解決できるようにカスタマイズしたものである。defineで使ったものを2重に定義するというかたちになるが、defineのほうはライントレースのif文内でも使っているので仕方がない。
***新ライントレース (左右2つのカラーセンサーを用いて)[#ae0b0223]
色覚センサーが二つになったので、正確に、ラインの端ではなく中央を走ることができるようになった。~
しきい値を使った方法もあり得るのだが、研究した結果、シンプルで美しい、『左右比較型』を基本形とすることにした。~
左右を比べて、値が小さい方に動けば、黒色を辿ることができるだろうというアイデアである。~
例)左の方が右より小さければ左前方へ進む~
具体的には以下のような形…~
 int d=SENSOR_1-SENSOR_2;//differenceの頭文字をとって
 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;          //左に(左右逆での)回転
   }
-距離の測り方 ~
サブルーチンの紹介で明らかになっているが、もう一度示しておく~
 sub follow_line2(int followtime)        //followtimeの関数付きサブルーチンなので
 汎用性が高い。
  {
   long t0=CurrentTick();                //この時点での時刻をt0とする
   while(CurrentTick()-t0<followtime){   //関数followtimeよりも『実行時の時刻-t0』が
 小さいときのみ繰り返す。
    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;
    }
   }                                     //while閉
   PlaySound(SOUND_CLICK);               //whileが終わり次の動作へ移行することを告げる
   brake;Wait(200);                      //小休憩
  }

-交差点の識別 ~
こちらもサブルーチンは上で紹介したが、もう一度示す。
 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;
    }
   }                                     //while閉
   PlaySound(SOUND_CLICK);               //whileが終わり次の動作へ移行することを告げる
   brake;Wait(200);                      //小休憩 
  }
ある条件について~
意味的には、左右両方黒とならない。ことなのだが、~
論理積でなく論理和を用いた。高校数学�気能�うことだが、~
ド・モルガンの定理:「”条件A”または”条件B”の否定」は「”条件Aの否定”かつ”条件Bの否定”」等しい~
という定理があった。~
ここではSENSOR_1もSENSOR_2も”黒でない”という否定の条件の積集合を取りたいので、論理和を用いた。
***task main(全体の行程の説明) [#i1552100]
下準備は整ったので、予定したコースに従っていく。(参照のアルファベッドをプログラムの説明部分に示す)~
予定のルート~
&ref(ルート.jpeg);
 task main()
 {
  SetSensorLight(S1);           //右カラーセンサー
  SetSensorLight(S2);           //左カラーセンサー
  arm_up();                     //クレーン上昇(以下同コマンド説明略)
  short_break;                  //※1
  ball_release();               //ボールをリリース(アーム開)(以下同コマンド説明略)
  go_straight;Wait(2000);       //Mまで直進
  follow_line();                //交差点判別付きライントレース(以下同コマンド説明略)
  chokusinR();                  //K
  follow_line2(1500);           //KL間を時間を測りながらライントレース
  short_break;                  //L
  arm_down();                   //クレーン降下(以下同コマンド説明略)
  short_break;                  //※1
ここより1球目
  ball_catch();                 //ボールキャッチ(アーム閉)(以下同コマンド説明略)
  short_break;                  //※1
  arm_up();                     
  short_break;                  //※1
  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();               //リリース
1球目終了、2球目(L')まで移動
  short_break;
  backleft();                   //K'
  follow_line2(3700);
  short_break;                  //L'
  arm_down();
  short_break;                  //※1
ここより2球目  
  ball_catch();                 //ボールキャッチ
  short_break;                  //※1
  arm_up();
  short_break;                  //※1
  turn_behind();
  OnFwd(OUT_AB,30);Wait(100);
  follow_line();
  usetsu(500);                  //K'
  follow_line2(500);
  short_break;                  //J'
  ball_release();               //リリース
2球目終了。3・4球目(I)まで移動
  short_break;                  //※1
  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
ここより3・4球目
  arm_down();
  short_break;                  //※1
  ball_catch();                 //ボールキャッチ
  short_break;                  //※1
  up_catch();                   
  short_break;                  //※1
  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;                  //※1
  arm_up();
  short_break;                  //※1
  backright();                  //K'
 }
※1 slaveが動作する間、masterが動かないようにする
*感想 [#r59f5759]
急ピッチで仕上げたので2台での連携でもっと発展的なことができた、もしくはプログラムを洗練させることができたという思いもあります。しかし、ある程度のものは完成しうれしいです。
チームメイト3人の協力で、特に私以外の2人の力が大きくて、今回のロボットを制作出来ました。個人的にはロボコンで1位をとれたのは副産物程度にしか思っていません。~
皆さんの協力だけでなく、説明のなかにも、『課題1』、『課題2』という言葉が使われていますがこれまで頑張ってきた部分をたくさん応用できたこともとてもよかったです。~
達成感がものすごくて、充実した前期を過ごすことができたと感じました。ありがとうございました。~

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