2017b/Member

目次

課題について

今回の課題は、課題2と同様のコースを用いて紙コップとその中に入ったピンポン球を移動させるものだった。これまでの課題と違い順路が決られておらず、そこから考えていくのが難しかった。

コース

ロボットについて

構想

まずロボットの作成において、用いる本体は1台か2台か、また別々に動かすか一緒に動かすか、をどのようにするかが最初の難関であった。私たちは次の3つの構想を立てた。

〇罐灰奪廚鯆呂狷虻遒半紊欧詁虻1台だけで行うロボット

各動作を別々のロボットで行うもの

K楝里2台用いて各動作を1つロボットで行うもの

製作

,,をもとにロボットの製作にあたった。

 Г海譴論萓犬提示してくださった機構を用いるものだが、これが最も軽量かつ小型で課題に適したものだと考えられた。しかし、機構がいまいち分からずこれの製作を断念した。

◆Щ罐灰奪廚鯆呂爛蹈椒奪箸肇團鵐櫂鶺紊鮟犬瓩襯蹈椒奪箸鯤漫垢貌阿すもので、コースの都合上ロボットを別のところに置かなければならなかった。しかし、同じ場所に集めるために複雑な順路を進ませなければならず、このロボットの製作を断念した。

:最終的にこのロボットの製作に当たり次のロボットが完成した。

全体

各部の説明

アーム部分

このようにギヤを用いたのだが、しっかりとかみ合っていなかったのか遊びがあり掴んでも掴みきれなかったことがあった。これは、少し強めに掴ませることで改善することができた。

アーム裏側

実際に掴む動作は次のようになる。4か所にタイヤを用いることでグリップ力を高めた。またタイヤは自由に回転できるようにしたので、ずれたときに掴もうとしてもしっかりと掴めるようになっている。

掴む1 掴む2 掴む3

上げる機構

このように掴む機構をそのまま持ち上げるようになっている。ギヤを用いることで安定してあげられるようにしている。

上げる機構1

掴む機構は2本の部品で支えているがそれらは矢印の部品を用いることで支えている。

上げる機構2

センサー等

課題2と同様に光センサーとタイヤの間を遠すぎず近すぎないところに取り付けている。また、距離センサーは光センサーの真横につけたが、紙コップを掴む機構と干渉しないようにつけることに少し苦労した。

センサー横から センサー前から

その他について

本体を2台用いたためにモーターに大きな負荷がかかってしまった。本体の横に取り付けたのも悪かったのかもしれない。また、片方に重心が偏ってしまい画像のように車体が傾いてしまった。

前から

しかし、次のように私たちのロボットは分解することができる。私たちのグループはこれまで組み立てやすさ、分解のしやすさをモットーにやってきたのでその点は十分クリアできたように思える。

ロボットの開き

プログラムについて

上側の本体をマスター、下側の本体をスレーブとしている。また、配線は次のようになっている。しっかりとつかめたかどうかを判断させるセンサーを用いたかったのだが時間がなかった。距離センサープログラム側で距離センサ

マスター側出力:A→右側車輪、B→左側車輪

マスター側入力:1→距離センサー、2→光センサー

スレーブ側出力:A→掴む機構、B→上げる機構

順路

順路

ロボットの順路は図のようにしている。Q-S間へ行った後はほとんどその場にいるまま作業することができる。次のように動かす予定だった。

1,点Sを認識する。

2,下の方に向き、紙コップを持ち直す。

3,Xの方へ向き、ピンポン球を置く。

4,反転してYの手前まで行き、紙コップを置く。(実際はここで認識することができなかった。)

5,下の方に向き、紙コップの手前まで行き掴む。

6,3,4と同様。

7、上の方に向き、紙コップの手前まで行き掴む。

8,3,4と同様。

マスター側定義,サブルーチン

安定のために

これまでは安定のためにWait():をその都度書いてたのだが、今回はこれを定義することで見やすくすることができた。

#define adjust Off(OUT_AB);Wait(50);  //微調整

ライントレースの定義

私たちはA-B間やQ-S間など直進するところはライントレースさせた。課題2と同様に比例制御を用いた。

比例制御とは

#define sensor SENSOR_2 //センサーの値
#define black 30 //黒の値
#define white 60 //白の値
#define threshold (black+white)*0.5 //閾値(前述の明るさの中間値)
#define deflection (sensor-threshold) //センサーの値と閾値(中間値)との差

ライントレースのサブルーチン

この2つは課題2と同様にトレースするためのサブルーチンである。課題2ではin,outとしていたがわかりにくかったので、今回はright,leftとして改善した。

sub linetrase_right(int x)  //ライントレース(進行方向右側))
{
    OnFwd(OUT_A,40+deflection*x);
    OnFwd(OUT_B,40-deflection*x);
}
sub linetrase_left(int x)  //ライントレース(進行方向左側)
{
    OnFwd(OUT_A,40-deflection*x);
    OnFwd(OUT_B,40+deflection*x);
}

この2つも同様に交差点認識するためのサブルーチンである。進行方向右側左側とともにセンサーが 黒線を認識する時間が一定以上の時に交差点認識するようになっている。各定数は実験的に出した。

sub intertify_right()  //交差点識別(進行方向右側)
{
    long t = CurrentTick();

    while(CurrentTick()-t<100){
     if(sensor_light>white-5){
      linetrase_right(1.5);
      t = CurrentTick();
     }else if(sensor_light>black+5){
      linetrase_right(1.5);
      t = CurrentTick();
     }else{
      linetrase_right(1.5);
     }
    }
    adjust;
}
sub intertify_left()  //交差点識別(進行方向左側)
{
    long t = CurrentTick();

    while(CurrentTick()-t<100){
     if(sensor_light>white-5){
      linetrase_left(1.5);
      t = CurrentTick();
     }else if(sensor_light>black+5){
      linetrase_left(1.5);
      t = CurrentTick();
     }else{
      linetrase_left(1.5);
     }
    }
    adjust;
}

これは開始点からライントレースできるようにするサブルーチンである。ロボットのサイズ上、センサーは確実に黒線上に来るので確実にこれを機能させることができた。

sub escape_A()  //点A脱出
{
    while(sensor_light<white-5){
     OnFwd(OUT_B,50);
     OnFwd(OUT_A,30);
     }
    adjust;
}

紙コップ認識の定義

参考資料を元に定義した。

#define ultrasonic SensorUS(S1)  //超音波センサー
const float diameter = 5.45; //タイヤの直径(cm)
const float track = 17.5; //タイヤのトレッド幅(cm)
const float pi = 3.1415; //円周率

紙コップ認識のサブルーチン

安定のためにすべてに adjust を入れている。

紙コップのところまで行き、その距離だけ戻す動作もさせたかったので2つめのサブルーチンを作った。

void approach(float d)  //dcm進む
{
    long angle = d/(diameter*pi)*360.0;  //必要なタイヤの回転角
    RotateMotorEx(OUT_AB,50,angle,0,true,true);
    adjust;
}
void back(float d)  //dcm後退する 
{
    long angle = d/(diameter*pi)*360.0;  //必要なタイヤの回転角 
    RotateMotorEx(OUT_AB,-50,angle,0,true,true);
    adjust;
}

同様に反時計回りもさせたかったので2つめのサブルーチンを作った。

void spinAng(long ang)  //今の方向を中心にang度旋回(反時計回り)
{
    long angle = track/diameter*ang;  //必要なタイヤの回転角
    RotateMotorEx(OUT_AB,50,angle,100,true,true);
    adjust;
}
void spinAng_opposite(long ang)  //今の方向を中心にang度旋回(時計回り)
{
    long angle = track/diameter*ang;  //必要なタイヤの回転角
    RotateMotorEx(OUT_AB,-50,angle,100,true,true);
    adjust;
}

はじめ、【返す】という意味が分からなかったが、使っていくうちに分かった。初めの方に分かっていればもっと応用できたプログラムが作れたかもしれない。

int search_distance(long ang)  //現在の方向を中心にang度の範囲で探しその距離を返す
{
    long tacho_min;  //最も近い距離を実現するタイヤの回転数 
    int d_min = 300;  //最も近い距離の仮の最小値

    long angle = (track/diameter)*ang; //旋回角度からタイヤの回転角度を計算 

    spinAng(ang/2);  //指定された角度の半分旋回
    ResetTachoCount(OUT_AB);  //角度計算をリセット

    OnFwdSync(OUT_AB,50,-100);  //反時計回りに旋回
    while(MotorTachoCount(OUT_A)<=angle){
     if(ultrasonic<d_min){                  //現在の距離が仮の最小値より小さいとき
      d_min = ultrasonic;                   //仮の最小値を更新し
      tacho_min = MotorTachoCount(OUT_A);   //タイヤの回転数を更新
     }
    }

    //タイヤの回転数、または距離センサーが仮の最小値以下になるまで旋回
    OnFwdSyncEx(OUT_AB,50,100,RESET_NONE);  //時計回りに旋回
    until(MotorTachoCount(OUT_A)<=tacho_min || ultrasonic<=d_min);

    adjust;
    Wait(500);
    return d_min;
}

各移動のサブルーチン

これは参考資料を応用して作った黒線の中心を向くようなサブルーチンであるが、黒線に斜めに向いていると意図しない方向に向いてしまう。作った後に気づき、今回は用いられることはなかった。

// 現在の方向を中心にang度の範囲で黒線の中心を向く
sub search_light_center(long ang) 
{
    long tacho_min;   //最も近い距離を実現するタイヤの回転数
    int light_min = 300; //最も暗い明るさの仮の最小値

    long angle = (track/diameter)*ang; //旋回角度からタイヤの回転角を計算
    spinAng(ang/2);              //指定した角度の半分旋回
    ResetTachoCount(OUT_AB);     //角度計算をリセット

    OnFwdSync(OUT_AB,50,-100);
    while(MotorTachoCount(OUT_A)<=angle){
     if(sensor_light<light_min){
      light_min = sensor_light;
      tacho_min = MotorTachoCount(OUT_A);
     }
    }
    OnFwdSyncEx(OUT_AB,50,100,RESET_NONE);  //時計回りに旋回
    until(MotorTachoCount(OUT_A)<=tacho_min || sensor_light<=light_min);

    adjust;
    Wait(500);
}

これらは各地点まで移動するサブルーチンである。センサーがある値になるまでタイヤを動かすようになっている。。しかし、ロボットを動かしていくうちに動作しなくなることがあり、これらは直接本文に書き込み訂正してきてしまったため、これらも用いられることはなかった。

sub go_P()  //左上の紙コップからPまで
{
    while(sensor_light>black+5){
     OnFwdSync(OUT_AB,50,-100);
    }
    adjust;

    while(sensor_light<white-5){
     OnFwd(OUT_A,50);
    }
    adjust;

    while(sensor_light>black+5){
     OnFwdSync(OUT_AB,50,0);
    }
    adjust;

    while(sensor_light<white-5){
     OnFwdSync(OUT_AB,50,0);
    }
    adjust;

    while(sensor_light>black+5){
     OnFwd(OUT_A,50);
    }
    adjust;
}

sub go_P_Q()  //PからQまで
{
    while(sensor_light<white-5){
     OnFwdSync(OUT_AB,50,0);
    }
    adjust;

    while(sensor_light>black+5){
     OnFwdSync(OUT_AB,50,0);
    }
    adjust;

    long t1 = CurrentTick();
    while(CurrentTick()-t1<1500){
     OnFwdSync(OUT_AB,50,0);
    }
}

sub go_S_C()  //SからCまで
{
    while(sensor_light<white-5){
     OnFwdSync(OUT_AB,50,0);
    }
    adjust;

    while(sensor_light>black+5){
     OnFwdSync(OUT_AB,50,0);
    }
    adjust;
}

通信のための定義

通信ための定義は次のように定義した。

#define ultrasonic SensorUS(S1)  //超音波センサー
#define master 0
#define slave 1
#define mail MAILBOX1
#define cup_age_little 20    //紙コップちょっと上げる
#define cup_age 30    //紙コップ上げる
#define cup_sage 40   //紙コップ下げる
#define cup_re 50    //紙コップ持ち直す
#define fin 9  //終わり

スレーブ側定義,サブルーチン

通信のための定義

マスター側と同様である。

#define master 0
#define slave 1
#define mail MAILBOX1
#define cup_age_little 20    //紙コップちょっと上げる
#define cup_age 30    //紙コップ上げる
#define cup_sage 40   //紙コップ下げる
#define cup_re 50    //紙コップ持ち直す
#define fin 9  //終わり

サブルーチン

スレーブ側は掴むモーターと上げ下げするモーターをつけているため、これらのサブルーチンを作った。動かす角度は実験的に出した。

sub tukamu()  //掴む
{
    RotateMotor(OUT_A,50,440);
    adjust;
}
sub hanasu()  //離す
{
   RotateMotor(OUT_A,50,-440);
   adjust;
}
sub up_little()  //少し上げる
{
    RotateMotor(OUT_B,60,-180);
    adjust;
}
sub ageru()  //上げる
{
    RotateMotor(OUT_B,60,-720);
    adjust;
}
sub down_little()  //少し下げる
{
    RotateMotor(OUT_B,60,180);
    adjust;
}
sub sageru()  //下げる
{
    RotateMotor(OUT_B,60,720);
    adjust;
}

マスター側本文

この通りであるが、無駄が多いものになってしまった。通信に関するプログラムはサブルーチンなどでまとめた方が確実に良かった。

task main()
{
    SetSensorLowspeed(S1);
    SetSensorLight(S2);

    //AからBまで行く
    escape_A();
    intertify_right();


    //紙コップを探しその5cm手前まで行く
    int d1 = search_distance(90);

    if(d1>10){
     approach(d1-5);
    }


    //通信(左上の紙コップを少し上げる) //
    int msg1;

    while(msg1!=fin){
     ReceiveRemoteNumber(mail,true,msg1);
     SendRemoteNumber(slave,mail,cup_age_little);
    }
    //通信//


    //進んだ分だけ戻る
    back(d1-5);


    //Bで方向転換してPまで行く//
    spinAng(80);  //Pの方へ向く

    while(sensor_light>black+5){
     OnFwdSync(OUT_AB,50,0);
    }
    adjust;

    while(sensor_light<white-5){
     OnFwd(OUT_B,50);
    }
    adjust;

    intertify_right();

点Pでは5度だけ旋回させたが、これは、Q-S間で確実に黒線の左側にセンサーを持って行きたかったからである。

    //PからSまで行く//
    spinAng(5);  //
    approach(26);

    while(sensor_light>black+5){
     OnFwd(OUT_A,50);
    }
    adjust;

    while(sensor_light<white-5){
     OnFwd(OUT_B,50);
    }
    adjust;

    intertify_right();

    spinAng(90);


    //通信(紙コップ持ち直す)//
    int msg2; 

    while(msg2!=fin){
     ReceiveRemoteNumber(mail,true,msg2);
     SendRemoteNumber(slave,mail,cup_re);
    }


    //Xの方に向く//
    while(sensor_light>black+5){
     OnFwdSync(OUT_AB,50,100);
    }
    adjust;

    while(sensor_light<white-10){
     OnFwd(OUT_A,50);
    }
    adjust;

    intertify_left();
    intertify_left();


    //通信(Xで紙コップ上げる)//
    int msg3;

    while(msg3!=fin){
     ReceiveRemoteNumber(mail,true,msg3);
     SendRemoteNumber(slave,mail,cup_age);
    }
    adjust;
    }


    //Yの方に向く
    spinAng(160);

実際にきれいに動いたのはここまでである。反転して黒線を認識するまで進ませたかったのだが、認識することなく、直進してしまった。もっと細かに移動させられたら成功していたかもしれない。

   while(sensor_light>black+5){
     OnFwdSync(OUT_AB,50,0);
    }
    adjust;


    //通信(紙コップ置く)//
    int msg4;
 
    while(msg4!=fin){
     ReceiveRemoteNumber(mail,true,msg4);
     SendRemoteNumber(slave,mail,cup_sage);
    }
    adjust;


    //下の紙コップの方に向く 
    while(sensor_light<white-5){
     OnFwdSync(OUT_AB,-50,0);
    }
    adjust;

    while(sensor_light>black+5){
     OnRev(OUT_A,50);
    }
   adjust;

    spinAng(90);

    int d2 = search_distance(90);

    if(d2>10){
     approach(d2-5);
    }


    //通信(紙コップ少し上げる)//
    int msg5;
 
    while(msg5!=fin){
     ReceiveRemoteNumber(mail,true,msg5);
     SendRemoteNumber(slave,mail,cup_age_little);
    }


    //進んだ分だけ戻る 
    back(d2-5);  


    //Xの方に向く 
    while(sensor_light>black+5){
     OnFwdSync(OUT_AB,50,100);
    }
    adjust;

    while(sensor_light<white-5){
     OnFwd(OUT_A,50);
    }
    adjust; 

    intertify_left();


    //通信(紙コップを上げる)//
    int msg6;

    while(msg6!=fin){
     ReceiveRemoteNumber(mail,true,msg6);
     SendRemoteNumber(slave,mail,cup_age);
    }
    adjust;


    //Yの手前に行く
    spinAng(320);

    while(sensor_light>black+5){
     OnFwdSync(OUT_AB,50,0);
    }
    adjust;


    //紙コップを置く//
    int msg7;

    while(msg7!=fin){
     ReceiveRemoteNumber(mail,true,msg7);
     SendRemoteNumber(slave,mail,cup_sage);
    }


    //残りの紙コップの手前まで行く 
    spinAng_opposite(90);
    
    int d3 = search_distance(90); 

    if(d3>10){
     approach(d3-5);
    } 


    //通信(紙コップを少し上げる)//
    int msg8;  

    while(msg8!=fin){
    ReceiveRemoteNumber(mail,true,msg8); 
     SendRemoteNumber(slave,mail,cup_age_little);
    }


    //進んだ分だけ戻る
    back(d3-5);


    //Xの方に向く
    while(sensor_light>black+5){
    OnFwdSync(OUT_AB,-50,100);
    }
    adjust;

    intertify_right(); 


     //通信(紙コップを少し上げる) //
    int msg9;  

    while(msg9!=fin){
    ReceiveRemoteNumber(mail,true,msg9);
     SendRemoteNumber(slave,mail,cup_age);
    }
    adjust;


    //Yの手前まで行く
    spinAng(320); 
 
    while(sensor_light>black+5){
     OnFwdSync(OUT_AB,50,0);
    }
    adjust;


    //通信(紙コップ置く)//
    int msg10;
 
    while(msg10!=fin){
     ReceiveRemoteNumber(mail,true,msg10);
     SendRemoteNumber(slave,mail,cup_sage);
    }
}

スレーブ側本文

このように同じようにプログラムが続いている。

task main()
{
    //紙コップを少し上げる
    int msg1;
    until(msg1==cup_age_little)
    ReceiveRemoteNumber(mail,true,msg1);
    while(msg1==cup_age_little){
     sageru();
     tukamu();
     up_little();
     SendResponseNumber(mail,fin);
     Wait(500);
     msg1 = "";  
    }

     //紙コップを持ち直す
    int msg2;
    until(msg2==cup_re)
    ReceiveRemoteNumber(mail,true,msg2);
    while(msg2==cup_re){
     down_little();
     hanasu();
     tukamu();
     up_little();
     SendResponseNumber(mail,fin);
     Wait(500);
     msg2 = "";  
    }

    //紙コップを上げる
    int msg3;
    until(msg3==cup_age)
    ReceiveRemoteNumber(mail,true,msg3);
    while(msg3==cup_age){
     down_little();
     ageru();
     SendResponseNumber(mail,fin);
     Wait(500);
     msg3 = "";  
    }

    //紙コップを置く
    int msg4;
    until(msg4==cup_sage)
    ReceiveRemoteNumber(mail,true,msg4);
    while(msg4==cup_sage){
     sageru(); 
     hanasu();
     ageru();
     SendResponseNumber(mail,fin);
     Wait(500);
     msg4 = "";  
    }

実際に動いたのはここまでである。

    //下の紙コップを少し上げる
    int msg5;
    until(msg5==cup_age_little)
    ReceiveRemoteNumber(mail,true,msg1);
    while(msg5==cup_age_little){
     sageru();
     tukamu();
     up_little();
     SendResponseNumber(mail,fin);
     Wait(500);
     msg5 = "";  
    }

    //紙コップを上げる
    int msg6;
    until(msg6==cup_age)
    ReceiveRemoteNumber(mail,true,msg6);
    while(msg6==cup_age){
     down_little();
     ageru();
     SendResponseNumber(mail,fin);
     Wait(500);
     msg6 = "";  
    }

    //紙コップを置く
    int msg7;
    until(msg7==cup_sage)
    ReceiveRemoteNumber(mail,true,msg7);
    while(msg7==cup_sage){
    sageru();
     hanasu();
     ageru();
     SendResponseNumber(mail,fin);
     Wait(500);
     msg7 = "";  
    }

    //残りの紙コップを少し上げる
    int msg8;
    until(msg8==cup_age_little)
    ReceiveRemoteNumber(mail,true,msg1);
   while(msg8==cup_age_little){
     sageru();
     tukamu();
     up_little();
     SendResponseNumber(mail,fin);
     Wait(500);
     msg8 = "";  
    }

    //紙コップを少し上げる
    int msg9;
    until(msg9==cup_age)
    ReceiveRemoteNumber(mail,true,msg9);
    while(msg9==cup_age){
     down_little();
     ageru();
     SendResponseNumber(mail,fin);
     Wait(500);
     msg9 = "";  
    }

    //紙コップを置く
    int msg10;
    until(msg10==cup_sage)
    ReceiveRemoteNumber(mail,true,msg10);
    while(msg10==cup_sage){
     sageru();
     hanasu();
     ageru();
     SendResponseNumber(mail,fin);
     Wait(500);
     msg10 = "";  
    }
}

まとめ

結果

プログラムは3つの紙コップを置くところまで作ったのだが、実際は一つ目の紙コップのピンポン球を置くところまでしかきれいに動かなかった(1つしか枠内に入らなかったが)。その後は、反転して点Sまで行きたかったのだが、交差点を識別できなくて続行不能となってしまった。

感想

まず、今回の課題は私がほとんど一人で作ってきてしまった。期末テストのため時間がなかったということとプログラムがグループで1つだったということが大きいと思う。しかし、本番では3位となることができて結果として良いものになったと思う。もっと時間があれば協力してさらに良いものが作れたかもしれない。ロボティクス入門ゼミを通して、当初自分ができるとは思ってなかったことができるようになっていて、とても達成感を感じることができた。最後に、各課題においてメンバーと話し合い1つのものを作り上げていくという、これまではあまり経験してこなかったことができて本当に良かったと思う。最後はあまりコミュニケーションを取ることができなかったのだが、やはりコミュニケーションは大事なのだと学ぶことができた。これを将来に生かしていきたいと思う。


添付ファイル: file順路.png 58件 [詳細] fileコース.png 47件 [詳細] file上げる機構2.png 57件 [詳細] fileロボットの開き.jpg 47件 [詳細] file前から.jpg 56件 [詳細] file光センサー.jpg 52件 [詳細] fileセンサー.jpg 48件 [詳細] file上げる機構1.jpg 58件 [詳細] fileアーム裏側.jpg 52件 [詳細] file掴む3.jpg 50件 [詳細] file掴む2.jpg 52件 [詳細] file掴む1.jpg 57件 [詳細] file全体.jpg 56件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2018-02-13 (火) 23:50:20 (550d)