#author("2020-02-13T18:40:25+09:00","minami","minami")
#author("2020-02-13T18:44:01+09:00","minami","minami")
#contents

*課題3 [#l02d9c43]
ボールを運搬して空き缶の上に乗せる。詳しい説明は以下の通りである。

**ルート [#tf993658]
課題2で作ったフィールドを利用する。
&ref(2019b/Member/minami/Mission3/コース.jpg,500x400,コース);~



**ルール [#a214e4f1]
&size(18){基本ルール};
--競技時間は審判が続行不能と判断するまで、あるいはリタイアするまで。
--図のA地点または(および)A'地点からスタートする。ただし接地している部分はそれぞれの領域内に収まるものとする(線上はOK)。上空部分は領域からはみ出していてもよい。
--開始の合図から5秒以内にスタートボタンを押す作業を完了すること。
--競技が終了するまで、ロボットに触ったり人間が遠隔で操作してはならない。
--途中でうまく動かなくなった場合、1回限り再スタートすることができる(再スタートの際に別プログラムで起動してよい)。
--競技終了後、ロボットが、空き缶に触れていてはいけない。~

&size(18){基本得点の計算方法};
--ボールを1個運べば8点。3つとも運べば24点。
--競技終了後、ゴールの空き缶が半分以上円からはみ出しまった場合、3点減点。
--競技終了後、ゴールの空き缶が完全に円から出しまった場合、4点減点。
--競技終了後、空き缶にロボットが触れていれば、もとの基本点の3減点。~

&size(18){技術点の計算方法};~
~
以下の動作の精度・スピード・確実性などを含めた技術的な工夫や芸術性について他の全てのチーム(5チーム)が20点満点で採点し、その平均点を求める。 ~
得点の目安:~
--ボールを探し取りにいくまでの動作 (3点)
--ボールを掴む動作 (3点)
--ボールを運ぶ動作 (2点)
--ボールを容器の中に入れる動作 (2点)
--2台のNXT、EV3の連携の良さ(2点)
--自立型のロボットとしての形や動作の美しさ、斬新さ(2点)
--その他 (3点)

*ロボットの説明 [#m518eec6]
**全体 [#mcf224e4]
前回、前々回との課題とは異なり、今回は2台分の部品を使うことが出来た。~
モーターは合計4つ使い、センサは超音波センサ1つ、光センサを2つ使った。~
工夫した点は、左右対称にしたところだ。左右対称にすることでぶれることなく安定したロボットとなった。
**超音波センサ [#a110e6a8]

#ref(超音波センサ.gif,right,around,70%)
~
~
~
~
~
~
~
超音波センサは缶を見つけるために使った。~
缶との距離が5cm以内になると止まるプログラムを作ったが、近づきするとセンサが反応しなくなったので10cmに変えることで対応した。
#clear
**光センサ [#fd21cc8f]
#ref(センサ.jpg,right,around,30%);
~
~
~
~
~
~
~
~
~
~
今回は光センサを2つ使うことが出来た。~
2つ使うことで交差点認識やライントレースが簡単になった。詳しい説明はプログラミングの説明の方で行う。~
#clear

**タイヤのモーター [#f9861e37]

#ref(タイヤ.jpg,right,around,30%);
~
~
~
~
~
~
~
~
~
今回は前輪に2つのタイヤを用いて後輪は作らなかった。~
4輪にすると上手く回転できなかったので後ろはブロックで補助的に支えた。~
余計摩擦がかかり滑らないのではないかと考えたが良い具合になった。
#clear
**アームのモーター [#ma612831]
&ref(2019b/Member/minami/Mission3/arm.gif,500x500,アーム);
&ref(2019b/Member/minami/Mission3/ボール.gif,500x500,ボール);~
缶を固定するためのアームとボールを回収・散逸するためのアームの2つを作った。~
左が固定、右が回収・散逸である。~
モーターを前回より多く使えるので、固定することでより安定してボールを回収・散逸出来ると考え、缶を固定するためのアームを作った。~
回収・散逸の機構は、3本の棒を用いてできる限り同じ長さ(半径)になるように工夫した。

*プログラミングの説明 [#ie284e8e]
**閾値と進行方向、右折と左折 [#k2871095]
 #define average 50                                            //閾値50
 #define go1 OnFwd(OUT_B,30);OnFwd(OUT_C,-20);         //go1の方向に進む
 #define go2 OnFwd(OUT_B,20);OnFwd(OUT_C,-10);                 //go2の方向に進む
 #define go3 OnFwd(OUT_BC,30);                                 //go3の方向に進む
 #define go4 OnFwd(OUT_B,-10);OnFwd(OUT_C,20);                 //go4の方向に進む
 #define go5 OnFwd(OUT_B,-20);OnFwd(OUT_C,30);            //go5の方向に進む
 
 #define left(s,t) OnFwd(OUT_B,s);Wait(t);Off(OUT_B);          //左折
 #define right(s,t) OnFwd(OUT_C,s);Wait(t);Off(OUT_C);         //右折

ここの部分は前回のプログラミングをそのまま使っているので前回のレポートを参考にしてほしい。~

**ライントレース [#vb986a8f]
缶を探す用と交差点の認識用のライントレースを作った。~



ライントレースの基本は前回と同じだが、今回は缶を見つけるライントレースと交差点を見つけるライントレースの2つを作った。


***缶を見つける [#o484d761]

缶を見つけるライントレースでは、超音波センサとの距離が10cm以内になるまでライントレースを続けるようにwhile文を作った。


 sub LeftSide()                                               //左側のライントレース(缶を見つけるまで)
 { 
     SetSensorLight(S1);                                      //光センサ起動
     SetSensorLowspeed(S4);                                   //超音波センサー起動
     while(true){                                             //trueの間
         if (SensorUS(S4)<=10){                               //超音波センサーと缶の距離が10cm以内なら
             Off(OUT_BC);                                     //モーターBCを止める
             PlaySound(SOUND_FAST_UP);                        //缶を見つけた合図として音を出す
             break;                                           //while文から抜ける
         }else if (SENSOR_1<average-11){                      //光センサの値がaverage-11未満なら
             go1;                                             //go1の方向に進む
         }else if (SENSOR_1<average-7){                       //光センサの値がaverage-7未満なら 
             go2;                                             //go2の方向に進む
         }else if (SENSOR_1<average+7){                       //光センサの値がaverage+7未満なら
             go3;                                             //go3の方向に進む
         }else if (SENSOR_1<average+11){                      //光センサの値がaverage+11未満なら
             go4;                                             //go4の方向に進む     
         }else {                                              //それ以外なら
             go5;                                             //go5の方向に進む
         }                                                    
     }
     Off(OUT_BC);                                             //モーターBCを止める
 }


***交差点を見つける [#k9543bdf]

#ref(crossroad.gif,left,around,70%);~
~
~
~
~
~

交差点を見つけるライントレースでは、2つの光センサを使い、両方が黒になるまでライントレースを続けるwhile文を作った。~
2つの条件を満たすようにプログラミングを書いたのは初めてだったが上手くいって良かった。~
#clear
&size(20){左側のライントレース};~
主として使った。

 sub crossroadLeft()                                          //左側のライントレース(交差点を見つけるまで)
 { 
     SetSensorLight(S1);                                      //光センサ起動
     SetSensorLight(S2);                                      //光センサ起動
     while(true){                                             //trueの間
         if ((SENSOR_1<average-11)&&(SENSOR_2<average-11)){   //2つの光センサの値がaverage-11未満なら
             Off(OUT_BC);                                     //モーターBCを止める 
             PlaySound(SOUND_FAST_UP);                        //交差点を見つけた合図として音をを出す
             break;                                           //while文から抜ける    
         }else if (SENSOR_1<average-11){                      //光センサの値がaverage-11未満なら
             go1;                                             //go1の方向に進む
         }else if (SENSOR_1<average-7){                       //光センサの値がaverage-7未満なら     
             go2;                                             //go2の方向に進む
         }else if (SENSOR_1<average+7){                       //光センサの値がaverage+7未満なら
             go3;                                             //go3の方向に進む
         }else if (SENSOR_1<average+11){                      //光センサの値がaverage+11未満なら
             go4;                                             //go4の方向に進む     
         }else {                                              //それ以外なら
             go5;                                             //go5の方向に進む
         }                                                    
     }
     Off(OUT_BC);                                             //モーターBCを止める
 }



&size(20){右側のライントレース};~

レース終盤の小回りで使った。

 sub crossroadRight()                                         //右側のライントレース(交差点を見つけるまで)
 { 
     SetSensorLight(S1);                                      //光センサ起動
     SetSensorLight(S2);                                      //光センサ起動
     while(true){                                             //trueの間
         if ((SENSOR_1<average-11)&&(SENSOR_2<average-11)){   //2つの光センサの値がaverage-11未満なら
             Off(OUT_BC);                                     //モーターBCを止める
             PlaySound(SOUND_FAST_UP);                        //交差点を見つけた合図として音をを出す
             break;                                           //while文から抜ける    
         }else if (SENSOR_1<average-11){                      //光センサの値がaverage-11未満なら
             go5;                                             //go5の方向に進む
         }else if (SENSOR_1<average-7){                       //光センサの値がaverage-11未満なら     
             go4;                                             //go4の方向に進む
         }else if (SENSOR_1<average+7){                       //光センサの値がaverage-11未満なら
             go3;                                             //go3の方向に進む
         }else if (SENSOR_1<average+11){                      //光センサの値がaverage-11未満なら
             go2;                                             //go2の方向に進む     
         }else {                                              //それ以外なら
             go1;                                             //go1の方向に進む
         }                                                    
     }
     Off(OUT_BC);                                             //モーターBCを止める
 }



**その他のサブルーチン [#h43533bb]
-&size(20){Cでボールを回収した後、缶をよけるためのプログラム};~
 sub avoid()
 {
     OnFwd(OUT_BC,-40);Wait(700);Off(OUT_BC);
     OnFwd(OUT_B,55);OnFwd(OUT_C,-25);Wait(800);Off(OUT_BC);
     OnFwd(OUT_BC,35);Wait(1200);Off(OUT_BC);
     OnFwd(OUT_C,35);OnFwd(OUT_B,-25);Wait(700);Off(OUT_BC);
     OnFwd(OUT_BC,35);Wait(1100);Off(OUT_BC);
     OnFwd(OUT_C,55);OnFwd(OUT_C,-25);Wait(600);Off(OUT_BC);
     OnFwd(OUT_BC,35);Wait(700);Off(OUT_BC);
     OnFwd(OUT_B,5);OnFwd(OUT_C,50);Wait(900);Off(OUT_BC);
     OnFwd(OUT_BC,50);Wait(1500);Off(OUT_BC);
 }

やたら長くなってしまい、綺麗なプログラミングにはほど遠いものになってしっまったのが反省点である。~
本来なら、下の画像の右側のように大きく円を描くように回る予定だったが、上手くいかなかった。~
ロボットの重さや大きさなどを考慮すればもう少し綺麗になったのではないかと考える。~
&ref(2019b/Member/minami/Mission3/回避.jpg,1000x400,回避);~


-&size(20){E,F,C',E',F'の後に一回転するためのプログラム};~
 sub kaitenn(int t)
 {
     OnFwd(OUT_BC,-50);Wait(400);Off(OUT_BC);
     OnFwd(OUT_B,90);OnFwd(OUT_C,90);Wait(t);Off(OUT_BC);        //tに入れた時間だけ回転する
 }
工夫したところは、一旦少しバックするところだ。そのまま回転しようとすると、どうしても缶にぶつかってしまうので少したがることで対応した。~
さらに、左右のタイヤを逆方向に回転させることで省スペースで回転できるように工夫した。~
このサブルーチンは何回か使うのでそれぞれで微調整しやすいようにモーターを回す時間を簡単に変えれるようにした。





**プログラム全体 [#za949d35]

&ref(2019b/Member/minami/Mission3/ルート.jpg,500x400,ルート);~
今回このルートで行く予定だったが、成功しなかった。
それぞれ個別で書いたプログラムでは全ての番号を実行出来たが通してみると出来なかった。~
ロボットの重さ、光の加減(光センサ)、タイヤの摩擦など小さい誤差が全体を通すと積み重なり失敗したのではないかと考えた。~
時間がなく、完走することは出来なかったが、1つでもボールを運ぼうと考え、1→2→3→4→5→6→9→10→11→12→13→14のルートでなんとか2つ運ぶところまではクリアした。
 
&size(20){マスター側のプログラム全体};~

マスター側は上で説明したプログラミングと
 #define CONN 1           //マスター側である
 #define SIGNALON 11                 //SIGNALONを11と定義
 #define SIGNALOFF 12                //SIGNALOFFを12と定義
この通信のためのプログラミングを、以下のtask mainの上に書いた。

○がついているところが最終的に通して成功したところである。~
×がついているところは通すと上手くいかないことがしばしばあったので、3つのボール全てを運搬することは諦め×のところを省いたプログラミングで2つのボールを運搬した。


 task main()
 {
     go3;Wait(500);OnFwd(OUT_BC);                         //○スタートの囲いから出る
     PlaySound(SOUND_UP);                                 //○スタートの合図として音を出す
     LeftSide();                                          //○1.缶を見つけるまでライントレース
     SendRemoteNumber(CONN,MAILBOX1,SIGNALON);            //○スレーブ側にボールを回収するよう命令を出す
     Wait(8000);                                          //○スレーブ側が動いている間静止する
     avoid();                                             //○2.缶に当たらないように缶を避ける
     crossroadLeft();                                     //○3.交差点を見つけるまでライントレース
     go3;Wait(300);Off(OUT_BC);                           //○交差点を直進
     LeftSide();                                          //○4.缶を見つけるまでライントレース
     SendRemoteNumber(CONN,MAILBOX1,SIGNALON);            //○スレーブ側にボールを回収するよう命令を出す
     Wait(8000);                                          //○スレーブ側が動いている間静止する
     kaiten(1150);                                        //○缶に当たらないように方向転換(回転)する
     crossroadLeft();                                     //○5.交差点を見つけるまでライントレース
     left(60,500);                                        //○交差点を左折
     crossroadLeft();                                     //○6.交差点を見つけるまでライントレース
     left(60,400);                                        //○交差点を左折
     LeftSide();                                          //×7.缶を見つけるまでライントレース
     SendRemoteNumber(CONN,MAILBOX1,SIGNALON);            //×スレーブ側にボールを回収するよう命令を出す
     Wait(8000);                                          //×スレーブ側が動いている間静止する
     kaiten(1600);                                        //×缶に当たらないように方向転換(回転)する
     crossroadLeft();                                     //×8.交差点を見つけるまでライントレース
     left(60,1200);                                       //×交差点を左折
     crossroadLeft();                                     //○9.交差点を見つけるまでライントレース
     left(60,1000);                                       //○交差点を左折
     crossroadLeft();                                     //○10.交差点を見つけるまでライントレース
     right(60,1100);                                      //○交差点を右折
     crossroadLeft();                                     //○11.交差点を見つけるまでライントレース
     left(60,1000);                                       //○交差点を左折
     LeftSide();                                          //○12.缶を見つけるまでライントレース
     SendRemoteNumber(CONN,MAILBOX1,SIGNALOFF);           //○スレーブ側にボールを逸脱するよう命令を出す
     Wait(7500);                                          //○スレーブ側が動いている間静止する
     kaiten(1200);                                        //○缶に当たらないように方向転換(回転)する
     crossroadLeft();                                     //○13.交差点を見つけるまでライントレース
     go3;Wait(300);Off(OUT_BC);              //○交差点を直進
     LeftSide();                                          //○14.缶を見つけるまでライントレース
     SendRemoteNumber(CONN,MAILBOX1,SIGNALOFF);           //○スレーブ側にボールを逸脱するよう命令を出す
     Wait(7500);                                          //○スレーブ側が動いている間静止する
     kaiten(1150);                                        //○缶に当たらないように方向転換(回転)する
     crossroadLeft();                                     //×15.交差点を見つけるまでライントレース
     right(60,500);                                       //×交差点を右折
     crossroadLeft();                                     //×16.交差点を見つけるまでライントレース
     right(60,500);                                       //×交差点を右折
     LeftSide();                                          //×17.缶を見つけるまでライントレース
     SendRemoteNumber(CONN,MAILBOX1,SIGNALOFF);           //×スレーブ側にボールを逸脱するよう命令を出す
     Wait(7500);                                          //×スレーブ側が動いている間静止する
     kaiten(1200);                                        //×缶に当たらないように方向転換(回転)する
     crossroadLeft();                                     //×18.交差点を見つけるまでライントレース
     left(60,500);                                        //×交差点を左折
     crossroadLeft();                                     //×19.交差点を見つけるまでライントレース
     right(60,550);                                       //×交差点を右折
     crossroadRight();                                    //×20.交差点を見つけるまでライントレース
     go3;Wait(500);Off(OUT_BC);                           //×21.ゴールへ
     PlaySound(SOUND_UP);                                 //×ゴールの合図として音を出す
 } 


&size(20){スレーブ側のプログラム全体};~
今回は2台とbluetoothで通信し連結させた。
今回は2台とbluetoothで通信し連結させた。~
そのためプログラムはマスター側とスレーブ側の2つを作った。~
これはスレーブ側のプログラムで、画像はdefineで定義したボールを回収逸脱する動きを模式化したものである。~
&ref(2019b/Member/minami/Mission3/アームの動き方.jpg,400x400,アームの動き方);~

 #define SIGNALON 11
 #define SIGNALOFF 12

 #define arm_fwd OnFwd(OUT_C,90);Wait(700);Off(OUT_C);        //缶を支える
 #define arm_rev OnRev(OUT_C,90);Wait(700);Off(OUT_C);        //缶を支えるのをやめる
 #define ball_fwd OnFwd(OUT_B,55);Wait(1000);Off(OUT_B);      //ボールを回収
 #define ball_rev OnRev(OUT_B,55);Wait(1000);Off(OUT_B);      //ボールを逸脱

 task main() 
 {
     int msg;
     while (true) {
         ReceiveRemoteNumber(MAILBOX1,true,msg);
         if (msg == SIGNALON){                                //ボールを回収するための工程
             arm_fwd;
             ball_fwd;
             arm_rev;
             break;
         }
         if (msg == SIGNALOFF){                               //ボールを逸脱するための工程
             arm_fwd;
             ball_rev;
             arm_rev;
             break;
         }
     }
 }

*感想 [#i7f7c240]
3つのボールを運ぶことができなかったのが残念だった。特に×も含め全てのプログラミングを個別で実行したときは上手くいったのに通すと失敗したのが悔しかった。~
また、離松で引っ越しがあり最後の発表に参加出来なかったのも大変悔しかった。~
~
通すと小さな誤差が積み重なり失敗に繋がることを思い知り、いかに正確な動きが出来るかが重要だと感じた。~
正確な動作には、ロボットの作りとプログラミングの両方が必要不可欠で両方を正確にしなくてはいけないと感じた。~
反省点としては、ハード:使っていると所々に緩み生じたこと。ソフト:電池残量や光の加減で出来が左右されたこと。が挙げられる。~
作ったときはきっちりはまっていても次第に歪みが生じると言うことは、ロボットが精巧に作れていなかったのかもしれない。~
しかし、プログラミングの内容がロボットが動ける範囲を超えてい、負荷をかけすぎていたの可能性もある。~
ソフトの部分は、プログラミングには同じ動作でも複数の書き方があるので場面に適した書き方を身につける必要があると感じた。~
~
初めてプログラミングを行った課題1から上手くかないことが多く苦戦していたが、使える構文が増え、上手くいかないときの改良なども出来るようになっていき~
非常に楽しく活動することが出来た。それでも課題3は今まで以上に大変で、発表会に参加出来ないことでモチベーションも上がらなかった。~
しかし集大成ともなる最終課題でなんとか全力を尽くしたいと思い、試験期間で余り時間に余裕はなかったが朝一からできる限りやり続けた。~
全てを運ぶことは出来なかったが自分としてはなかなかの出来になったとは思う。~

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