目次
#contents
*課題 [#ee25234f]
今回の課題はピンポン玉&紙コップ回収ロボットの作成である。

決められた場所にあるコップとピンポン玉を指定された別の場所に移動されるというルール。

詳しくは[[こちら:http://yakushi.shinshu-u.ac.jp/robotics/?2017b%2FMission3]]をご覧ください。

*ロボットについて [#p0ad5ff6]
私たちのグループのロボットは一度完成させた後にアームの構造を大きく変えたパターンのロボットに作り直したので、試作機1と完成機の2パターンのロボットを説明する。
**試作機1 [#u6f2b651]
#ref(./DSC_0181.JPG,50%,車体横)
横から見るとこのような感じでホイールベースが非常に長くなった。

#ref(./DSC_0183.JPG,50%,車体上)
NXT本体を二つ並べて設置した。この画像ではUSBポートが車体前方側を向いているが、アームを回すモーターが干渉してしまい写真右側の本体にUSBがさせなかったので本体の向きを180°回転させた。

#ref(./DSC_0185.JPG,50%,光センサ)
ホイールベースが長くなってしまった分車体とセンサを近づけ小回りきくようにしたが、結局光センサは使わなかった。

&ref(./アーム1.png,30%,アーム1);&ref(./アーム2.png,30%,アーム2);&ref(./アーム3.png,30%,アーム3);&ref(./DSC_0182.JPG,50%,正面);

また、アームの構造はモーターを二つ使い片方はポップをつかむ役割、もう片方はコップをつかんだモーターを持ち上げる役割である。この構造の弱点は一番右の写真を見てわかるようにアームの幅が狭く、コップがモーターの正面に来ないとうまくコップをつかめないことである。したがってコップをつかむ際のミスが多かった。これを受けて多少誤差で狙いがずれてもコップをつかめるように完成機ではアームの構造が改善されている。

**完成機 [#dea458c0]
#ref(./1518254325726.jpg,70%,完成機)
全体像はこのような感じ

試作機と大きく異なる点はアームと後輪の二点である。

#ref(./1518254323032.jpg,50%,アーム改)
アームの構造をクワガタのような形にしてコップを挟み持ち上げるようにした。こうすることでシビアだったコップをつかむ際の位置も、多少ずれが生じてもしっかり掴むようになった。

&ref(./DSC_0184_LI.jpg,50%,後輪);&ref(./1518254329194.jpg,50%,後輪改);

後輪は試作機では車輪一個であったがそれではこの重い機体を支えきれなかったり写真赤丸の部分が外れてしまうことが多かった。したがって、写真右のように車輪を二個使うことで安定性が増した。初めは車輪にゴムを付けていたがそれでは車体が旋回したとき摩擦が大きくうまく回れなかったので外し、滑らすようにして旋回させることで改善できた。

その他の部分は試作機と同様。

*作戦[#xfe9bc53]
時間や技術的なことを考えて完璧を目指すつもりは初めからなかったので、初めの一個は確実にクリアしようと努力した。区間� 繕茣岫い吠�けて説明する

#ref(./2017b-mission3_LI (2).jpg,60%,コース作戦)

区間�� 一個目のコップを取りに行く。スタート地点から直進するだけでたどり着くのでライントレースや超音波センサーも使わずに適切な距離前進しコップをつかみに行った。

区間�� 車体が大きいのでコップをつかんでからほぼ90°右に旋回するだけで地点Xの方向に向くそこから少し前進しアームを上げピンポン玉を入れる。

区間�� 少し後退してから左に旋回し地点Yのほうへ向く。

区間�� そのまま直進し地点Yまで行きコップを置く。トレースできる黒線や超音波センサーも使えそうになかったのでここも前進するプログラムを書いて動かした。

基本的に前進、後退、旋回などの動作は電池消費による影響を防ぐため時間で指定するのではなく距離で指定できるプログラムにした。詳しくは下のプログラムの欄で。

*プログラム [#kea5af38]
直接プログラムを書いたのは自分ではないがわかる限り詳しく説明する
**マクロ マスター側(タイヤを動かす方) [#wb9a2135]
定義したが結局使わなかったものもあるので使ったものを説明
 #define SPEED 55
 #define SPEED_SLOW 45
 #define SPEED_CURVE 45
 #define SPEED_FAST 55
 #define THRESHOLD 38
 #define OnRL(speedR,speedL) OnFwd(OUT_B,speedR);OnFwd(OUT_C,speedL);
 #define go_forward OnRL(SPEED_FAST,SPEED_FAST);
 #define turn_right_high OnRL(-30,SPEED_CURVE);
 #define turn_right_low OnRL (0,SPEED_CURVE);
 #define turn_left_high OnRL(SPEED_CURVE,-30);
 #define turn_left_low OnRL (SPEED_CURVE,0);
 #define CONN 1   
 #define SIGNAL_CATCH 11      //コップをつかむ
 #define SIGNAL_RELEASE 12     //コップを離す
 #define SIGNAL_UP 13      // アームを上げる 
 #define SIGNAL_UP1 14      //アームを上げる
 #define SIGNAL_DOWN 15     //アームを下げる

**空き缶を探すプログラム [#u0f10117]
これは授業で先生からもらったプリントを参考にした
 const float diameter = 5.45;       //タイヤの直径
 const float track = 10.35;        //タイヤのドレッド幅
 const float track = 10.35;        //タイヤのトレッド幅
 const float pi = 3.1415;         //円周率
 
 void fwdDist(float d)         //距離d前進
 {
     long angle = d/(diameter*pi)*360.0;   //角度を計算する
     RotateMotorEx(OUT_BC, SPEED_SLOW, angle, 0, true, true);   //角度を指定してモーターを回転
 }
 
 void turnAng(long ang)   //角度ang度時計回り旋回
 {
    long angle = track/diameter * ang;    //必要なタイヤの回転角度
     RotateMotorEx(OUT_BC, SPEED_SLOW, angle, 100, true,true);   
 }
 
 int searchDirection(long ang)       //現在の方向を中心にang度の範囲で探し障害物までの距離を返す
   
 {
     long tacho_min;    //最も近い距離を実現するタイヤの回転数
     int d_min = 300;    //最も近い距離の仮の最小値
     long angle = (track/diameter)*ang;  //旋回角度からタイヤの回転を計算
     turnAng(ang/2);            //指定された角度の半分を旋回
     ResetTachoCount(OUT_BC);        //角度計算をリセット
     OnFwdSync(OUT_BC,SPEED_SLOW,-100);   //反時計回りに旋回
     while(MotorTachoCount(OUT_B)<=angle){
      if(SensorUS(S3)<d_min){        //現在の距離が仮の最小値より小さい場合
       d_min = SensorUS(S3);        //仮の最小値を更新
       tacho_min = MotorTachoCount(OUT_B);  //この時のタイヤの回転数を記録
       }
      }
     OnFwdSyncEx(OUT_BC,SPEED_SLOW,100,RESET_NONE);
     until(MotorTachoCount(OUT_B)<=tacho_min || SensorUS(S3)<=d_min);
     Wait(14);
     Off(OUT_BC);
     Wait(500);
     return d_min;
 }

**区間�△濃藩僂垢襯泪�ロ [#be1537a4]
90°旋回する時に使用した。
 #define Ninety  15.9/(diameter*pi)*360.0     //90°旋回をNinetyと命名
 #define usetu RotateMotorEx(OUT_BC,40,Ninety,100,true,false);    //90°旋回するようタイヤを回転

**メインタスク マスター側 [#h4bbed47]
 task main()
 {
     SetSensorLight(S2);
     RotateMotor(OUT_BC,35,315);           
     Wait(1000);                   //区間�,良�分、スタート地点からコップまで移動
     RotateMotor(OUT_BC,35,320);
     Wait(1000);
     SendRemoteNumber(CONN,MAILBOX1,SIGNAL_CATCH);   //コップをつかむ指令を送る
     Wait(2000);
     Wait(1000);
     RotateMotor(OUT_C,55,180);           //区間�△良�分、90°程右に旋回する
     RotateMotor(OUT_B,-55,310);
     Wait(1000);
     RotateMotor(OUT_BC,35,260);           //地点Xにピンポン玉を置くために前進
     SendRemoteNumber(CONN,MAILBOX1,SIGNAL_UP);    //アームを上げる指令を送る
      Wait(2000);
   ↓地点Xから地点Yへ移動(区間���い良�分)
     RotateMotor(OUT_C,-55,360);          
     RotateMotor(OUT_BC,55,600);
     RotateMotor(OUT_B,-55,330);
     RotateMotor(OUT_C,55,50);
     RotateMotor(OUT_BC,55,900);

     SendRemoteNumber(CONN,MAILBOX1,SIGNAL_DOWN);   //アームを下げる指令を送る
      Wait(1500);
     SendRemoteNumber(CONN,MAILBOX1,SIGNAL_RELEASE);  //コップを離す指令を送る
     Wait(2000);

これで区間� 繕茣岫い泙能�了。以降二個目のコップを運ぶわけですができなかったので中途半端なプログラムとなってしまっているのであまり気にしないでください。
     SendRemoteNumber(CONN,MAILBOX1,SIGNAL_UP);
     Wait(2000);
     RotateMotor(OUT_BC,-55,100);
     OnFwd(OUT_B,55);
     OnFwd(OUT_C,55);
     Wait(1000);
     Off(OUT_BC);
     SetSensorLowspeed(S3);
      int d = searchDirection(60);
     if (d > 5){
        fwdDist(d-5.0);
       }
      
 }

**マクロ スレーブ側(アームを)動かす方 [#c94fe07a]
マスター側と同じ
 #define SIGNAL_CATCH 11   
 #define SIGNAL_RELEASE 12   
 #define SIGNAL_UP 13  
 #define SIGNAL_UP1 14  
 #define SIGNAL_DOWN 15 

マスター側からメッセージが送られてきたときif文を使ってスレーブ側の行動を整理した
 task main()
 {
     int msg;
     while(true){
     ReceiveRemoteNumber(MAILBOX1,true,msg);  
     if (msg == SIGNAL_CATCH) {    //コップをつかむ
         OnFwd(OUT_C,40);
          Wait(800);
          Off(OUT_C);
       }else{
      if (msg == SIGNAL_RELEASE) {  //コップを離す
         RotateMotor(OUT_C,-20,38);
        }else if 
       (msg == SIGNAL_UP) {     //アームを上げる
          RotateMotor(OUT_B,-45,120);
       }else if
        (msg == SIGNAL_DOWN) {   //アームを下げる
        RotateMotor(OUT_B,45,94);
      }else if
         (msg == SIGNAL_UP1) {   //アームを上げる
         OnFwd(OUT_B,-50);
          Wait(1000);
          Off(OUT_B);
     }
 }
 }
 } 

*反省と感想 [#a749baa3]
プログラムの大体はぎりぎりに完成したというわけではないので調整などにそこそこの時間を充てられたと思うがなかなか安定して成功することができないまま本番を迎えた。本番では1,2回目では初めのコップをつかむ時点で失敗してしまい何もできなかった。しかし泣きの3回目ではうまくコップを掴みピンポン玉を運べた。残念ながら一個しかはいらなかったがコップはちゃんと置くことができた。練習でもピンポン玉がうまく落ち着かず割りばしの囲いから出てしまうことのほうが多かったのでそこも改善できたらよかった。また、超音波センサーがうまく機能せず、応用できていなかったのがチームの実力不足を感じた。もっと時間をかけてできない原因を探ることが出ればよかったが、なかなか時間的にも厳しかった。

今までの課題を振り返って感じたことは正確なロボットを作るにはプログラミングを何とかするよりも、どれほど良いロボットをつくるかが重要だと感じた。なぜなら、どれほどまともなプログラムをかいて何度も微調整してもロボットがもろかったり、物理的に動かしにくかったり、そもそもその機構でよいプログラムが書けなかったりなどといったロボットを作ってしまった場合、どれほど頑張ってプログラムを書いてもうまくいかず時間の無駄だと思うからだ。最初のロボット作りでそのあとの課題の目標達成に大きく影響が出ると思う。とはいってももちろんプログラミングも重要で、わかりやすくコンパクトにしていくことが肝であった。これはこれからの生活の中でモノを覚えるとき、伝えるとき、整理するときなどさまざまな場面につながってくると思った。

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  
 
 
 
  
 
 
 
  
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  

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