2009

課題2 ライントレースロボットを作る

A11R タイラー/ピーチクパーチク

ロボット

車体

main.JPG

車輪は基本的にローヴァーロボットの幅をつめたもの。
ローヴァーロボットとの最大の違いは、ギアを縦に組んだこと。
車高を高くすることで安定感が失われるが、光センサーを仕込みやすくコンパクトな仕上がりとなった。
前方に伸びた拡張パーツに、センサーやアームを装着する仕組み。

タッチセンサー

bamp1.JPG

説明書26pのシングルバンパーをほぼそのまま使用したところ、反応しなかった。
そのため、テコの原理を利用して長いアームのセンサーを作成。

bamp2.JPG
bamp3.JPG

交差点上の牛乳パックをこれで感知する。

光センサー

車輪のすぐ前方に装着。センサーを真下に向けることで正確な場所感知を可能に。

light.JPG

アーム

arm1JPG.JPG

ギアとモーターを直接繋いだアーム。牛乳パックをこれで移動させる。
白ギアの装着により、アームに負荷がかかってもモーターに悪影響を与えない仕組み。
しかしシンプルな構造だが脆い。車体への取り付けも不安定。

arm2.JPG

キャスター

重くなる前方部分を支えるためのキャスター。
p46のキャスターや、回転軸と固定位置を同じにしたキャスターを作ってみた。
が、安定性の問題でうまくいかず、先輩の意見をもとに車輪でなく支え棒を作成。
しかし、ロボット自体の重さゆえ堅牢性に欠ける。
そんなわけでシンプルなキャスターを二つ作った。それぞれを拡張パーツの左右に装着。

cas1.JPG
cas2.JPG

調整

bamp5.JPG
cas3.JPG

タイヤが大きすぎて不安定だったので小さくした。
そのためキャスターもゴムを取り外しコンパクト化。小回りが利くようになった。

完成

comp.JPG

なんだかカブトムシにクワガタムシを足したような外見になった。

再調整

・カスタムアーム

arm5.JPG

最大の改造点は強度。
基本構造そのままに棒を通すことで、かなりの強度を誇っている。
また、アーム自体を二段に。
牛乳パックを逃さず捕らえるようになった。


・カスタムタッチセンサー

bamp6.JPG

地面に接触して反応してしまうのと、アームとの兼ね合いでバンパーパーツを外した。
牛乳パックを見つけにくくはなったが、タッチセンサーとしての効果は十分。


・完成

comp4.JPG

ロボットらしく、無骨で巨大なフォルム。
虫らしさがほぼ消え去った。

コース

コース1

course1.JPG

交差点:3
紙の端や交差点が狭い。

コース2

course2.JPG

交差点:3
コース1の改良版。
交差点や紙の端など細かいところを改良。

プロブラム

1:紙パックをもとの位置に戻したのちコースに戻って進む

作成:ピーチクパーチク

牛乳パックをよけて進むのはコース的に難しそうだったので、
アームを使ってパックを退かす方向性でプログラムを組んだ。

プログラム1:失敗

#define gs(t) OnFwd(OUT_A+OUT_C);Wait(t);Float(OUT_A+OUT_C); //(t)だけ直進
#define gb(t) OnRev(OUT_A+OUT_C);Wait(t);Float(OUT_A+OUT_C); //(t)だけ後退
#define gs2 OnFwd(OUT_A+OUT_C); //直進
#define close OnRev(OUT_B);Wait(40);Off(OUT_B); //アームを閉じる
#define open OnFwd(OUT_B);Wait(40);Off(OUT_B); //アームを開く
#define THRESHOLD 40 //しきい値
int x = 0; //変数xを定義
 
task main()
{ 
	SetSensor(SENSOR_2,SENSOR_TOUCH);
	SetSensor(SENSOR_1, SENSOR_LIGHT);
	SetSensor(SENSOR_3, SENSOR_LIGHT); //センサー定義	
	SetPower(OUT_A,5);
	SetPower(OUT_C,5); //トルク調整

     while (true) {
	gs2 //前進
	OnFwd(OUT_B); //常にアーム開き続ける

    //ライントレースプログラム
    //前進中、左右のセンサーが黒線(コース)を捉えるとセンサー側に曲がる
        if (SENSOR_1 < THRESHOLD) { //右センサ 右に曲がる
            OnRev(OUT_A);
            Wait(2);
            OnFwd(OUT_A);
        } else if (SENSOR_3 < THRESHOLD) { //左センサ 左に曲がる
            OnRev(OUT_C);
             Wait(2);
            OnFwd(OUT_C);
    //交差点(両方のセンサが黒線を捉える)
        } else if ((SENSOR_1 < THRESHOLD) && (SENSOR_3 < THRESHOLD)) {
            gs(20)
      x = x + 1; //xにx+1を代入

    //障害物の感知
    //戻ってから進むことで他の車を回避する仕組み
        }else if (SENSOR_2 == 1) {
                	ClearTimer(0); //タイマーのセット
        		gb(110)
        		gs(70)
 
        //障害物が牛乳パックだったとき
    // =タイマーが5,5秒以内だったとき
        } else if (( Timer(0) <= 55) && (SENSOR_2 == 1)) {
        	Float(OUT_A+OUT_C+OUT_B); 
        	close //アームを閉じる
        	OnRev(OUT_B);
		gs(120) //前進
		OnFwd(OUT_C);OnRev(OUT_A); //回転
		Wait(160);
		Float(OUT_A+OUT_C);
		Off(OUT_B);
		open //アームを開く
		gb(70); //後退
		OnFwd(OUT_C);OnRev(OUT_A); //回転
		Wait(130);
 
    //三周したら自動的に止まる
      // =交差点を7回通る (交差点を通る回数ーパックを運ぶ回数+調整値=7)
        } else if ((SENSOR_1 < THRESHOLD) && (SENSOR_3 < THRESHOLD) && (x == 7)){
       	Float(OUT_A+OUT_C);
       	break; //while文を終了
       }
        }
}


問題点:パックを掴んでからの回転・移動が直線的すぎてコースから外れてしまう



プログラム2
主な変更点

上記のプログラムで説明したものについては、割愛したものがあります。

#define gs(t) OnFwd(OUT_A+OUT_C);Wait(t);Float(OUT_A+OUT_C);//tだけ前進
#define gb(t) OnRev(OUT_A+OUT_C);Wait(t);Float(OUT_A+OUT_C);//tだけ後退
#define gs2 OnFwd(OUT_A+OUT_C);//前進
#define gb2 OnRev(OUT_A+OUT_C);//後退
#define close OnFwd(OUT_B);Wait(40);Off(OUT_B);//アームを開く
#define open OnRev(OUT_B);Wait(40);Off(OUT_B);//アームを閉じる
#define T 40//しきい値1
#define R 35//しきい値2
int x = 0;//変数x
int y = 0;//変数y
int turna = 0;//回転タスクで使用する変数
int turnc = 0;
int halfa = 0;
int halfc = 0;

//メインタスク
task main()
{
	SetSensor(SENSOR_2,SENSOR_TOUCH);
	SetSensor(SENSOR_1, SENSOR_LIGHT);
	SetSensor(SENSOR_3, SENSOR_LIGHT);	
	SetPower(OUT_A,5);
	SetPower(OUT_C,5);
	while(y = 0){ //y=0の間(=三周するまで)繰り返す

        //障害物にぶつかるまでライントレース
	OnRev(OUT_B);
	       start trace;//トレースタスクスタート
	       until(SENSOR_2  == 1);//障害物を感知
	       stop trace;
        //障害物にぶつかったとき
        	Float(OUT_A+OUT_C+OUT_B);
        	close; //掴む
        	OnFwd(OUT_B);
        	ClearTimer(0);//タイマーセット 
        	start trace;//ライントレースタスク スタート
        	until(FastTimer(0) > 250);//2.5秒進む
        	stop trace;//トレースタスクエンド
		turnaround();//回転タスク
		Float(OUT_A+OUT_C+OUT_B);
		open; //離す
		ClearTimer(2);//タイマー(2)セット
		start btrace;//後ろ向きにのライントレースタスクスタート
		until(FastTimer(2) > 80);//0.8秒下がる
		stop btrace;//トレースタスクエンド
		close; //閉じる
		turnaround();//回転タスク、もとのレーンにもどる
		}
}

//ライントレースタスク
//メインタスクで呼び出された時に開始
//プログラム1とほぼ同様のプログラムなので変更点だけ説明します。
task trace()
{
    while (true) {
	gs2;
        if ((SENSOR_1 < R) && (SENSOR_3 > T)){ //右センサが黒、左センサが白を感知したとき
            OnRev(OUT_A);
        } else if ((SENSOR_3 < R)  && (SENSOR_1 > T)) { //左センサが黒、右センサが白を感知したとき
            OnRev(OUT_C);
        } else if ((SENSOR_1 < T)  && (SENSOR_3 < T)) { //交差点
            gs(20);
            x = x + 1;
    //3周したら停止=交差点を七回通ったとき
        } else if (((SENSOR_1 < T) || (SENSOR_3 < T))&& (x == 7)){
        	Float(OUT_A+OUT_C);
    y = 1;
        	break;
        }
}
}

//バックライントレースタスク
// 光センサーの位置の問題で、少し進んで回転という動作を行っている。
// メインタスクに呼び出されたとき開始。
// 逆向きに進むだけで前進ライントレースとほとんど同様のプログラムなので説明を割愛。
task btrace()
{
    while (true) {
	gb2;
        if ((SENSOR_1 < R) && (SENSOR_3 > T)){
            OnFwd(OUT_A+OUT_C);
            Wait(1);
            OnRev(OUT_C);
            Wait(2);
        } else if ((SENSOR_3 < R)  && (SENSOR_1 > T)) {
            OnFwd(OUT_A+OUT_C);
            Wait(1);
            OnRev(OUT_A);
            Wait(2);
        } else if ((SENSOR_1 < T)  && (SENSOR_3 < T)) {
            gb(20);
        }
}
}

//回転プログラム
//相方のものを教えてもらって搭載。
// メインタスクに呼び出されたとき開始。

// 左右のセンサが黒線を通り過ぎた後、両方のセンサが白の上に来ると止まる。
void turnaround()
{
  Off(OUT_A+OUT_C);

  while ((turna == 0)||(turnc == 0)){
     OnFwd(OUT_A);
     OnRev(OUT_C);
     Wait(10);
     Off(OUT_A+OUT_C);     //常に反時計周りに回転するプログラム
     
     if (SENSOR_1 < T){ //センサ1が黒の上のとき
        halfa = 1;
     } else if (SENSOR_3 < T){ //センサ3が黒の上のとき
        halfc = 1;

   //両方が一度でも黒の上に載ったことがあるとき
   // =半回転したとき
     } else if ((halfa == 1)&&(halfc == 1)){
        if (SENSOR_1 > T){ //センサ1が白のとき
           turna = 1;
        } else {
         turna = 0;
        }
        if (SENSOR_3 > T){ //センサ3が白のとき
           turnc = 1;
        }else{
        turnc = 0;
        }
     }
    //両方のセンサが白の上にある=黒い線をまたいでいる
  }
  OnFwd(OUT_A);
  OnRev(OUT_C);
  Wait(8);
  Off(OUT_A+OUT_C);//回転
  turna = 0;//変数の初期化
  turnc = 0;
  halfa = 0;
  halfc = 0;
 }
フローチャート
メインタスク開始
 ↓
前方ライントレース開始
 ↓          ↑
障害物に ぶつかる ぶつからない
       ↓
障害物を掴むプログラム開始
 ↓
掴んだら前方ライントレース
 ↓
回転タスクを実行、後方ライントレース
 ↓
回転タスクを実行して障害物を離す
 ↓
一番始めに戻る

調整が大変だったが、なんとかプログラムの完成にはこぎつけた。
しかし、必ず成功するプログラムではないので、もっと精度を高める必要がある。

2:紙パックを次の交差点まで運んで行き、その交差点に紙パックを残してさらに黒い線に沿って進む

作成:タイラー

#define THOLD 40 //しきい値
#define JAW_SPEED  1 //アーム作動速度
#define DRIVE_SPEED  3 //作動速度
#define turnWait 4 //回転時待機時間
 //PlaySound(0);
int bite = 0; 
int iTurnA = 0;  //回転プログラムに使用する変数
int iTurnC = 0;
int halfwayA = 0;
int halfwayC = 0; //ここまで
int adju = 0;

int intersFakeBool1 = 0;
int intersFakeBool2 = 0;
int intersFakeBool3 = 0;
int waiter1 = 0;

int wlCnt = 0;

//回転プログラム
// 常に回転し、左右のセンサーがそれぞれ黒線を感知した後、両方が白を感知すると止まる。
// =コースに対して逆走方向を向く
void turnAround()
{
  Off(OUT_A+OUT_C);

  while ((iTurnA == 0)||(iTurnC == 0))
  {
     OnFwd(OUT_A);
     OnRev(OUT_C);
     Wait(10);
     Off(OUT_A+OUT_C);
           
      if (SENSOR_1 < THOLD)
     {
        halfwayA = 1;
     }
     if (SENSOR_3 < THOLD)
     {
        halfwayC = 1;
     }

     if ((halfwayA == 1)&&(halfwayC == 1))
     {
        if (SENSOR_1 > THOLD)
        {
           iTurnA = 1;
        }
        else
        {
          iTurnA = 0;
        }

        if (SENSOR_3 > THOLD)
       {
           iTurnC = 1;
        }
        else
        {
        iTurnC = 0;
        }
     }
  }
  OnFwd(OUT_A);
  OnRev(OUT_C);
  Wait(8);
  Off(OUT_A+OUT_C);
  iTurnA = 0;
  iTurnC = 0;
  halfwayA = 0;
  halfwayC = 0;
 }
 //End turnAround()


//ライントレースプログラム
// 変数backorFwdを変化させることで前方に進む、後方に進むの二通りの動作をこなす。
// 後ろ向きに進むとき、センサの位置の問題で動き方が違うものになる。
// 後退して、左センサが黒を感知したとき、黒を感知するまで右回転し、また後退。
// 車体をそのつどカーブに合わせるようにして進む。
void adjust(int backOrFwd)
{//If foward backOrFwd = 0: if backward  backOrFwd = 1

  //両方のセンサが黒にいるとき
    if((SENSOR_1 < THOLD) && (SENSOR_3 < THOLD))//=============================
    {//Drive Straight if you meet an intersection.
       if(backOrFwd == 0) //前進時
       {
          Float(OUT_A+OUT_C);
          OnFwd(OUT_A+OUT_C);
          Wait(turnWait);
          Float(OUT_A+OUT_C);
       }
       else if(backOrFwd == 1) //後退時
       {
          Float(OUT_A+OUT_C);
          OnRev(OUT_A+OUT_C);
          Wait(turnWait+5);
          Float(OUT_A+OUT_C);
       }
    }
  //右側が黒を感知したとき
    else if(SENSOR_1 < THOLD)//================================================
    {
        //Right sensor tripped turn left
        if(backOrFwd == 0) //前進時
        {
          Off(OUT_A+OUT_C);
          OnFwd(OUT_C);
          Wait(turnWait);
          Off(OUT_C);
          Wait(2);
        }
        else if(backOrFwd == 1) //後退時
        {
          //Right sensor tripped turn left
          //Reverse opposite until seeing the black line
         Off(OUT_A+OUT_C);
         until(SENSOR_3 < THOLD)
         {
           OnFwd(OUT_C);
         }
         Off(OUT_C);
         //Reverese concerning side unti seeing black line
         until(SENSOR_1 < THOLD)
         {
           OnFwd(OUT_A);
         }
         OnRev(OUT_A+OUT_C);
         Wait(15);
         Off(OUT_A+OUT_C);
       }
   }
  //左側センサが黒を感知したとき
   else if(SENSOR_3 < THOLD)//==============================================
   {
       if(backOrFwd == 0) //前進時
       {
          //Left sensor tripped turn right
          Off(OUT_A+OUT_C);
          OnFwd(OUT_A);
          Wait(turnWait);
          Off(OUT_A);
          Wait(2);
       }
       else if(backOrFwd == 1) //後退時
       {
         Off(OUT_A+OUT_C);
         until(SENSOR_1 < THOLD)
         {
           OnFwd(OUT_A);
         }
         Off(OUT_A);
         //Reverese concerning side unti seeing black line
         until(SENSOR_3 < THOLD)
         {
           OnFwd(OUT_C);

         }
         OnRev(OUT_A+OUT_C);
         Wait(15);
         Off(OUT_A+OUT_C);
       }
   }
   else
   {
     if(backOrFwd == 0)
     {
        //PlaySound(0);
        OnFwd(OUT_A+OUT_C);
        Wait(5);
        Float(OUT_A+OUT_C);
     }
     else if(backOrFwd == 1)
     {
        //PlaySound(0);
        OnRev(OUT_A+OUT_C);
        Wait(5);
        Float(OUT_A+OUT_C);
     }
   }
 }

//=============================================================================
//=============================================================================

//メインタスク
task main()
{

  SetSensor(SENSOR_1,SENSOR_LIGHT); //Right 右光センサ
  SetSensor(SENSOR_2,SENSOR_TOUCH);//Touch Sensor
  SetSensor(SENSOR_3,SENSOR_LIGHT);//Left 左光センサ

  SetPower(OUT_A,DRIVE_SPEED);
  SetPower(OUT_B,DRIVE_SPEED);
  SetPower(OUT_C,DRIVE_SPEED); //トルク変更

adju = 0;
while(true)
{

//adjust(1);
  //タッチセンサーが反応するか変数biteが1のとき
  if (SENSOR_2 == 1 || bite == 1)
  {
     if(bite == 0) // biteが0のとき
     {//If first touch milk carton 最初にパックに触ったとき、
      //Stop and bite, 止まって掴む。
       Off(OUT_A+OUT_C);
       Wait(40);
       OnFwd(OUT_B);
       bite = 1;//Let program know bite has occured 変数biteを1に。次のプログラムへ
     }
     else if(bite == 1) //biteが1のとき
     {//Run Normally plus keep biting //パックを掴んだまま通常運転
        OnFwd(OUT_B);
        adjust(adju);
        
        //IF both sensors 交差点にさしかかったとき=両方のセンサが黒を感知し、後述する位置補正プログラムが実行されたとき
    // 進み、回転し、パックを離し、後退し、回転し、通常運転に戻る。
        if(SENSOR_1 < THOLD && SENSOR_3 < THOLD && intersFakeBool2 == 1)
        {
           PlaySound(4); //音を鳴らす

           while(wlCnt < 36) //変数wlcntが36になるまで前進
           {
             adjust(0); //一度前進プログラムを動かすたびに変数wlcntに+1する。
             wlCnt = wlCnt + 1;
           }
           wlCnt = 0;
           
           PlaySound(3);//音を鳴らす
           
           turnAround();
           
           OnRev(OUT_B);//パックを離す

           while(wlCnt < 20) //20回前進プログラムを動かす
           {
             adjust(1);
             wlCnt = wlCnt + 1;
           }
           wlCnt = 0;
           PlaySound(4); //音を鳴らす
           Off(OUT_A+OUT_B);
           Wait(80);
           turnAround(); //回転プログラムの実行
           
           
           OnRev(OUT_B);
           intersFakeBool2 = 0;
           intersFakeBool1 = 0;
           bite = 0;  //通常運行に戻るため、タスク内ルーチンの変数を初期化
           
        }
    //両方が黒を感知したとき、位置調整プログラムを実行する
        else if(SENSOR_1 < THOLD && SENSOR_3 < THOLD)
        {
           intersFakeBool1 = 1;
           PlaySound(3);
           
           while(wlCnt < 15) //変数wlcntが15になるまで前進プログラムを動かす
           {
            adjust(adju);
            wlCnt = wlCnt + 1;
           }
           wlCnt = 0;
        }
        else if(intersFakeBool1 == 1)
        {
           //PlaySound(1);
           
           intersFakeBool2 = 1; //位置調整プログラム実行終了を表すため変数intersfakebool2を1に
        }
     }
  }
 //通常運行=ライントレース
  else  //Run Normally ===============================================
  {
     adjust(adju); //ライントレースプログラムを動かす
  }

 }
}
フローチャート
メインタスク開始
 ↓
障害物にぶつかるまでライントレース、ぶつからなかったらそのままライントレース
 ↓
障害物をにぶつかったらそれを掴む、次の交差点までライントレース
 ↓
交差点に差し掛かったら回転できる長さまでライントレース
回転し、パックを離し、回転できる長さまで後退ライントレース
 ↓
回転して、通常運行(ライントレース)に戻る

感想

ピーチクパーチク:
 ただライントレースさせればいいだけだ、と簡単に思っていたが、
 さまざまな問題点が浮き彫りになってとても苦労した。
 他グループのメンバーにも多少なり手伝っていただいたので、ここでお礼を申し上げておきます。ありがとうございました。

タイラー:
 もしもう一度このロボットを作る機会があったら、もっといいものが作れたと思う。
 

コメント



添付ファイル: filecomp4.JPG 411件 [詳細] filebamp6.JPG 496件 [詳細] filearm5.JPG 447件 [詳細] filecourse2.JPG 430件 [詳細] filecourse1.JPG 462件 [詳細] filemain.JPG 439件 [詳細] filelight.JPG 416件 [詳細] filecomp.JPG 468件 [詳細] filecas3.JPG 570件 [詳細] filecas2.JPG 456件 [詳細] filecas1.JPG 432件 [詳細] filebamp5.JPG 491件 [詳細] filebamp3.JPG 519件 [詳細] filebamp2.JPG 459件 [詳細] filebamp1.JPG 606件 [詳細] filearm2.JPG 396件 [詳細] filearm1JPG.JPG 424件 [詳細]

トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2009-08-10 (月) 00:49:04