#contents
ホーム[[2017b/Member]]
*1課題 [#k51f0fe3]

以下は[[2017b/Mission3]]のからの引用です。
-------
* 課題:ピンポン玉&紙コップ回収ロボット [#hedbc5a6]

ピンポン玉と紙コップを別々に回収して所定の場所に運ぶ。

#ref(2017b/Mission3/2017b-mission3.png,80%,ロボコンのフィールド平面図)

:フィールドの説明 |
--フィールドは課題2で使用した紙を使用する。
--図のマジェンタの円に逆さまにした紙コップを置き、その中にピンポン玉を2つずつ入れておく。
--図の黄色い円に紙コップを通常の向きに置き、障害物とする。直径6cmの円の外周をペンまたは鉛筆でマークしておく。
--紙コップには色をつけたり文字や記号を書いてもよい。
--%%RISのチームに限り図の緑ラインを引いてもよい。%%
--割り箸を使って一辺が14cmの正方形を作り、X地点を中心とした円に接するように置く。

* ルール [#k6b5fbc8]
:基本ルール |
--競技時間は審判が続行不能と判断するまで、あるいはリタイアするまで。
--図のA地点または(および)D地点からスタートする。ただし接地している部分はそれぞれの領域内に収まるものとする(線上はOK)。上空部分は領域からはみ出していてもよい。
--ピンポン玉をX地点に運び、割り箸で正方形に囲まれた領域に入れる。
--紙コップをY地点がある黒線に囲まれた領域に運ぶ。
--開始の合図から5秒以内にスタートボタンを押す作業を完了すること。
--競技が終了するまで、ロボットに触ったり人間が遠隔で操作してはならない。
--途中でうまく動かなくなった場合、1回限り再スタートすることができる(再スタートの際に別プログラムで起動してよい)。
:基本得点の計算方法 (片道) |
--運んだピンポン玉の数×3点
--運んだ紙コップの数×3点
--紙コップを2つ重ねて置くことができた場合はさらに3点加算、3つ重ねて置くことができた場合は6点加算
--障害物の紙コップに接触して一部を円の外に移動した場合は各1点減点、全部を円の外に移動した場合は各2点減点
--例:ピンポン玉を4個運び、紙コップを3個運んだ場合で、そのうち2つの紙コップを重ねることができた場合:(4x3点) + (3x3点 + 3点) = 24点

:技術点の計算方法|
以下の動作の精度・スピード・確実性などを含めた技術的な工夫や芸術性について他の全てのチーム(5チーム)が20点満点で採点し、その平均点を求める。
得点の目安: 
--紙コップとピンポン玉を探し取りにいくまでの動作 (2点)
--紙コップを掴む動作 (2点)
--紙コップを運ぶ動作 (2点)
--紙コップを置く (2点)
--ピンポン玉を拾う動作(2点)
--ピンポン玉を運ぶ動作(2点)
--ピンポン玉を目的に入れる動作(2点)
--2台のRCXまたはNXT、EV3の連携の良さ(2点)
--自立型のロボットとしての形や動作の美しさ、斬新さ(2点)
--その他 (2点)

*2ロボットの紹介 [#hfe78483]

基本のロボットに光センサーとアーム、起動スイッチを付けた構造になっています。

**ロボットの形 [#n402669d]

&ref(2017b/Member/Yoshi/Mission2/rosoku.JPG,60%,ロボの全体像(前));
&ref(2017b/Member/Yoshi/Mission2/rozennpou.JPG,60%,ロボ全体像(横));
&ref(2017b/Member/Yoshi/Mission2/robokouhou.jpg,45%,ロボ全体像(後));

左の写真がロボットの全体を横から見た図、真ん中の写真が前方から見た図、右の写真が後方から見た図です。

NXに付属している冊子のロボットを基にして光センサーと接触センサーを取り付けました。

パーツの中でも最も重量のある電池ボックス(兼制御部)の位置を少しだけでも下げるために元は斜めに設置して合ったものを、倒してなるべく水平に設置するよう改良しました。これにより重心が下がりロボットの走行時、旋回時の安定性が向上します。配線の都合上、元の形とは上下を入れ替えています。

*3ロボット作成で工夫した点 [#r3f47f32]

&ref(2017b/Member/Yoshi/Mission2/rozenn.JPG,60%,ロボの全体像(前2));
&ref(2017b/Member/Yoshi/Mission2/lightsenn.jpg,80%,ロボの光センサー);

光センサーは最初に試作した時から安定して明るさが読み取れたのでそのまま変更せずに使用しました。念のため取り付ける位置を上下にずらして見ましたが、下にずらすと紙面に密着して光が十分に反射せず、上にずらすと紙面からの光が広がってしまいどちらの場合も望んでいた光の変化が得られなかったのでこの位置が最適だと判断しました。

またロボットの左側に接触センサーを取り付け、起動ボタンとして活用しました。場所は特に制約もないので押しやすいところに設置しました。

アームは軽量化の為にシンプルな構造にしました。紙コップより若干大きい形とにして余裕を持たせています。

*4プログラム [#t1f283c1]
**定義した定数 [#o1329b1a]

プログラムを簡略化し、開発しやすくするためにいくつか定数を定義しました。

以下はその抜粋です

 #define Apower 37
 #define Bpower 34  //直進するのに必要な出力
 #define ttime 950  //90度曲がるのに必要な時間
 #define kanndo 30 //感度、ライントレースの反応の度合い
まず上二つが移動用モーターの出力です。数値を左右で変えてまっすぐ先進するようにしました。

3つめは旋回時に90°回転するための待ち時間です。

最後の『kanndo』はライントレースの感度です。

**定義した変数 [#vb60d72c]

プログラムを読み取りやすくし、また調整しやすくするためにいくつか変数を使いましたそれを紹介します。

-c,float,サブ関数その1[[#n49e72fe]]のturnLとturnRで使用。旋回角度を指定するために使います。1で901度回転するようになっています
-d,float,サブ関数その2[[#zb1341d5]]で使用。定数のkanndoと合わせて使うことで明るさの目標値とのずれに応じてモータの出力を変化させる。0〜1の範囲で変化する。
-t,int,サブ関数その3[[#n4b63b7c]]で使用。ロボットの向きを変えた後に前進する時間(ms)を入力する。
-lsw,サブ関数その6、7[[#d46bbd32]][[#mb31891c]]で使用。自動取得した紙面上(白色)での明るさ。生データなのでおおよそ600台を示す。lightsensorwhiteの略。
-lsb,サブ関数その6、7[[#d46bbd32]][[#mb31891c]]で使用。サブ関数のcyariにて自動取得した黒線上での明るさ。生データなのでおおよそ300台を示す。lightsensorblackの略。

**定義したサブ関数 [#m9587eea]

定数と同様にいくつかサブ関数を定義しました。これにより可読性を高め、他人が見てもわかりやすくなります。

サブ関数の中には中にサブ関数を使用しているところがあるので分けて説明します。

***サブ関数その1 (基本動作)[#n49e72fe]

 sub go_for()
 {
     OnFwd(OUT_A,Apower);
     OnFwd(OUT_B,Bpower);
 }
 sub go_back() 
 {
     OnFwd(OUT_A,-Apower);
     OnFwd(OUT_B,-Bpower);
 }
 sub turnL(float c)
 {
     OnFwd(OUT_A,Apower);OnFwd(OUT_B,-Bpower);
     Wait(c*ttime);
     Float(OUT_AB);  //左に曲がる(c×90)度
 }
 sub turnR(float c)
 {
     OnFwd(OUT_A,-Apower);OnFwd(OUT_B,Bpower);
     Wait(c*ttime);
     Float(OUT_AB);  //右に曲がる(c×90)度 
 }

使用した変数
-c,float,旋回角度を指定するために使います。1で901度回転するようになっています

ここで上げたサブ関数はロボットを動かす基本動作です。先進、後進、左旋回、右旋回のためのサブ関数です。前進、後進は開始のみ、旋回は回転する角度を指定して旋回します。

***サブ関数その2(ライントレース用) [#zb1341d5]

 sub turnR2(float d)
 {
     OnFwd(OUT_A,Apower-d*kanndo);OnFwd(OUT_B,Bpower+d*kanndo);
 }
 sub turnL2(float d)
 {
     OnFwd(OUT_A,Apower+d*kanndo);OnFwd(OUT_B,Bpower-d*kanndo);
 }
 sub turnR1(float d)
 {
     OnFwd(OUT_A,-d*kanndo);OnFwd(OUT_B,Bpower+d*kanndo);
 }
 sub turnL1(float d)
 {
     OnFwd(OUT_A,Apower+d*kanndo);OnFwd(OUT_B,-d*kanndo);
 }  

使用した変数
-d,float,定数のkanndoと合わせて使うことで明るさの目標値とのずれに応じてモータの出力の変化量を決める。0〜1の範囲で変化する。

ここで上げたサブ関数はライントレースをする際に使います。『d』に応じて左右のタイヤの出力を調節して境界の方向に向かいます。

関数が4つあるのは、黒線の右側を走るときと左側を走る為に必要だからです。

***サブ関数その3(右折、左折用関数) [#n4b63b7c]

 sub sennkaiL(int t)
 {
     Off(OUT_AB);
     go_for();
     Wait(t);
     turnL(1);
 }
 sub sennkaiR(int t)
 {
     Off(OUT_AB);
     go_for();
     Wait(t);
     turnR(1);
 }

使用した変数
-t,int,サブ関数その3[[#n4b63b7c]]で使用。ロボットの向きを変えた後に前進する時間(ms)を入力する。

ロボットが右折、左折をするときには黒線の太さがあるためにただ旋回をするだけでなく、太さ分を移動する必要があります。その動きをサブ関数にしました。前進する時間を変更できるようにしたのは曲線を走行した後はロボットの向きが直線と比べて向きが違うのでそのずれを修正するためにしました。

***サブ関数その4(黒線の端から反対側への移動) [#c60ca96a]

 sub hennkouRL()
 {
     turnL(1);
     go_for();
     Wait(300);
     turnR(0.9);
 }
 sub hennkouLR()
 {
     turnR(0.9);
     go_for();
     Wait(300);
     turnL(1);
 }

この二つの関数は、ロボットが走る場所を移す関数です。黒線の右側から左に移ったり、左から右に移ったりします。

交差点の存在を検知するために、ロボットを黒線の右側と左側の変更しながら走る必要があったのでこのプログラムを作りました。

***サブ関数その5(アームの制御) [#u2c92213]

 sub armdown()
 {
     RotateMotor(OUT_C, 20,120);
     Wait(1000);
     Off(OUT_C);
 }
 sub armup()
 {
     RotateMotor(OUT_C, -20,120);
     Wait(1000);
     Off(OUT_C);
 }

このサブ関数は紙コップを捕まえて離すためのプログラムです。RetateMotorを使うことで角度を指定して動かしてずれが起きないようにしました。

***サブ関数その6(黒線の明るさの自動取得) [#d46bbd32]

 int cyari(int lsw)
 {
     ResetTachoCount(OUT_C);
     SetSensorLight(S1);
     SetSensorMode(S1,SENSOR_MODE_RAW);//明るさセンサを生データに
     SetSensorTouch(S4);
     int i=1;
     int lsb=SENSOR_1;
     int lsb2=SENSOR_1-1;
     while (i==1){
         go_for();
         lsb2=SENSOR_1;
         NumOut(80,LCD_LINE4,lsb2);
         if (lsb>lsb2) {
             lsb=lsb2;
             }
         if (lsb+10<lsb2) {
             i=10;
             }
         if (lsb>lsw-150) {
             i=1;
             }    
         }
     Off(OUT_AB);
     NumOut(80,LCD_LINE1,lsw);
     NumOut(80,LCD_LINE2,lsb);
     return lsb;
 }

使用した変数
-lsw,int,自動取得した紙面上(白色)での明るさ。生データなのでおおよそ600台を示す。lightsensorwhiteの略。
-lsb,int,サブ関数のcyariにて最終的に黒線上での明るさになる。生データなのでおおよそ300台を示す。lightsensorblackの略。
-lsb2,int,サブ関数のcyariにてロボットが移動しているときの最新の明るさセンサーの数値を示す。生データなのでおおよそ300台を示す。lightsensorblackの略。
-i,int,黒線の明るさの計測が終わったか表す数値。1なら計測中、それ以外なら終了を表す。

黒線の明るさの最低値を自動取得っするプログラムです。進みながら明るさを取得し比較し記録します。紙面の白色部分から動き始めて黒線を通過するように通過します。

事前に取得した紙面の明るさ『lsw』

***サブ関数その7(ライントレースのプログラム。) [#mb31891c]

 sub linecomonn(int nL,int nR,int lsw,int lsb,int wall2,int point,int ftime,int waitt,int kankaku)
 {
    int deruta=(lsw-lsb)/2; //102
    float wall1=lsb+deruta;  //348+102
    int n=0;
    int ls=0;
    int kauntL=0;
    int kauntR=0;
    long told=0;
    long t0=CurrentTick();
    long tsub=0;
    while (n==0){
        ls=SENSOR_1;
        NumOut(80,LCD_LINE4,ls);
        if (ls>wall1) {
            if (lsw-ls<wall2) {
                turnL1((ls-wall1)/deruta);
                //PlaySound(SOUND_CLICK);
                if ((CurrentTick()-told>=kankaku)&&(CurrentTick()-t0>waitt)) {
                    kauntL=kauntL+1;
                    told=CurrentTick();
                    }
                turnL1((ls-wall1)/deruta);
                //PlaySound(SOUND_CLICK);
                }
            else{
                turnL2((ls-wall1)/deruta);
                }
            ls=SENSOR_1;
            }
        if (ls<=wall1) {
            if (ls-lsb<wall2) {
                if ((CurrentTick()-told>=kankaku)&&(CurrentTick()-t0>waitt)) {
                    kauntR=kauntR+1;
                    told=CurrentTick();
                    }
                turnR1((wall1-ls)/deruta);
                //PlaySound(SOUND_CLICK);
                }
            else{
                turnR2((wall1-ls)/deruta);
                }
            ls=SENSOR_1;
            }
        if(kauntL>=nL){
            n=1;
            }
        if(kauntR>=nR){
            n=1;
            }
        if ((n==1)&&(point==1)) {
            tsub=CurrentTick();
            point=2;
            n=0;
            }
        if ((n==1)&&(point==2)) {
            n=0;
            }
        if((point==2)&&(CurrentTick()-tsub>ftime)) {
            n=1;
            }
        NumOut(0,LCD_LINE1,kauntL);
        NumOut(0,LCD_LINE2,kauntR);
        }
 }

 sub linecomonn2(int nL,int nR,int lsw,int lsb,int wall2,int point,int ftime,int waitt,int kankaku)
 {
    int deruta=(lsw-lsb)/2; //102
    float wall1=lsb+deruta;  //348+102
    int n=0;
    int ls=0;
    int kauntL=0;
    int kauntR=0;
    long told=0;
    long t0=CurrentTick();
    long tsub=0;
    while (n==0){
        ls=SENSOR_1;
        NumOut(80,LCD_LINE4,ls);
        if (ls>wall1) {
            if (lsw-ls<wall2) {
                if ((CurrentTick()-told>=kankaku)&&(CurrentTick()-t0>waitt)) {
                    kauntR=kauntR+1;
                    told=CurrentTick();
                    //PlaySound(SOUND_CLICK);
                    }
                turnR1((ls-wall1)/deruta);
                //PlaySound(SOUND_CLICK);
                }
            else{
                turnR2((ls-wall1)/deruta);
                }
            ls=SENSOR_1;
            }
        if (ls<=wall1) {
            if (ls-lsb<wall2) {
                if ((CurrentTick()-told>=kankaku)&&(CurrentTick()-t0>waitt)) {
                    kauntL=kauntL+1;
                    told=CurrentTick();
                    }
                turnL1((wall1-ls)/deruta);
                //PlaySound(SOUND_CLICK);
                }
            else{
                turnL2((wall1-ls)/deruta);
                }
            ls=SENSOR_1;
            }
        if(kauntL>=nL){
            n=1;
            }
        if(kauntR>=nR){
            n=1;
            }
        if ((n==1)&&(point==1)) {
            tsub=CurrentTick();
            point=2;
            n=0;
            }
        if ((n==1)&&(point==2)) {
            n=0;
            }
        if((point==2)&&(CurrentTick()-tsub>ftime)) {
            n=1;
            }
        NumOut(0,LCD_LINE1,kauntL);
        NumOut(0,LCD_LINE2,kauntR);
        }
 }

ライントレースをするためのプログラムです。黒線の右側を走る用のものと、左側を走る用のものと二つ作りました。構造は後述します。

**実行するプログラム [#t144e1c4]

ここまでで定義したものを使って指定のルート通るために以下のようにtask mainを作りました

 task main ()
 {
    ResetTachoCount(OUT_C);
    SetSensorLight(S1);
    SetSensorMode(S1,SENSOR_MODE_RAW);
    SetSensorTouch(S4);
    armup();
    int lsw=SENSOR_1;
    int lsb=cyari(lsw);
    while(SENSOR_4==0) {}
    linecomonn(50,2,lsw,lsb,30,0,0,1000,2000);
    PlaySound(SOUND_UP);
    sennkaiR(200);
    linecomonn(1,50,lsw,lsb,30,1,2000,1500,2000);
    PlaySound(SOUND_UP);
    hennkouRL();
    linecomonn2(50,1,lsw,lsb,30,1,2000,1500,2000);
    PlaySound(SOUND_UP);
    hennkouLR();
    linecomonn(50,1,lsw,lsb,30,0,0,1000,2000);
    PlaySound(SOUND_UP);
    sennkaiR(0);
    hennkouRL();
    linecomonn2(1,1,lsw,lsb,80,0,0,1000,1000);
    PlaySound(SOUND_UP);
    Off(OUT_AB);
    Wait(2000);                //円
    sennkaiL(200);
    linecomonn2(1,50,lsw,lsb,20,1,700,1000,1500);
    Off(OUT_AB);
    turnR(1);
    armdown();
    turnL(0.9);
    linecomonn2(1,50,lsw,lsb,20,0,0,1000,1500);
    PlaySound(SOUND_UP);
    sennkaiL(500);
    linecomonn(50,1,lsw,lsb,30,0,0,1000,1000);//円2
    Off(OUT_AB);
    PlaySound(SOUND_UP);
    Wait(2000);
    linecomonn(50,1,lsw,lsb,30,0,0,1000,800);
    turnR(2.7);
    armup();
    turnR(1.7);
    PlaySound(SOUND_UP);
    Wait(2000);
    go_for();
    Wait(200);
    Float(OUT_AB);
    linecomonn(1,1,lsw,lsb,40,0,0,800,800);  //sf
    Off(OUT_AB);
    PlaySound(SOUND_UP);
    Wait(2000);
    sennkaiL(400);
    linecomonn(50,1,lsw,lsb,30,0,0,1000,2000);
    Off(OUT_AB);
    PlaySound(SOUND_UP);
    Wait(2000);
    turnR(1);
    go_for();
    Wait(2100);
    Off(OUT_AB);
    while(SENSOR_4==0) {
    PlaySound(SOUND_UP);
    Wait(1500);
 }
 }

特出して書くことはないと思いますが、「埼」から「玉」に移動する際にY軸の位置をレールの端に合わせてずれにくいようにしています

*5実行結果 [#yce51899]

こうして作ったロボットとプログラムを動かしてみた。まず倍率を0.8倍にして動かした。
&br;
その結果

&ref(2017b/Member/Yoshi/Mission2/Video.gif,120%,滑らか);
&br;
のように最後の一画が少しはみ出た。なので今度は倍率を0.5倍にして動かした。
&br;
その結果

&ref(2017b/Member/Yoshi/Mission1/kekka2.jpg,87%,埼玉1);
&br;
となりはみ出ずに書くことができた。

トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS