[[2019a/Member]]
目次
#contents
*課題3について [#ib163b7f]
今回の課題は&size(30){ボール運搬ロボット};です.
ピンポン玉または青と赤のボールを運搬して、所定の容器の中に入れる。
#ref(./s_2019a-mission3 .png,70%,課題3説明図)
:フィールドの説明|
--フィールドは課題2で使用した紙を使用する。
--生協のお弁当の四角いプラ容器2つをそれぞれ円内に置き、片方に玉を2個入れる。
--残りの2個の玉は課題2と同じ位置に置く。その際、ゴムタイヤやプレートの上に置いてもよい。
--プラ容器には色をつけたり文字や記号を書いてもよい。
--プラ容器は両面テープ等でフィールドに固定してもよい。
--2枚の紙の境界にはそれぞれ幅1cm、合計2cmの黒線を描いてもよい。
:基本ルール|
--競技時間は審判が続行不能と判断するまで、あるいはリタイアするまで。
--図のA地点または(および)A'地点からスタートする。ただし接地している部分はそれぞれの領域内に収-まるものとする(線上はOK)。上空部分は領域からはみ出していてもよい。
--開始の合図から5秒以内にスタートボタンを押す作業を完了すること。
--競技が終了するまで、ロボットに触ったり人間が遠隔で操作してはならない。
--途中でうまく動かなくなった場合、1回限り再スタートすることができる(再スタートの際に別プログラムで起動してよい)。
--競技終了後、ロボットが、ゴールのプラ容器に触れていてはいけない。
--競技終了後、もともと玉が入っていたプラ容器が、ゴールのプラ容器に触れていてはいけない。
課題3について詳しくは[[こちら>2019a/Mission3]]をご覧ください.
*ロボットについて [#zc20deca]
ロボットの全体像は以下の写真のようです.今回は,今までよりも大型化してしまいました.ピンポン玉を4つ拾い集める機構とRISを2つ乗せたことが要因です.
#ref(./s_zentai1.jpg,70%,ロボット全体1)
#ref(./s_zentai2.jpg,70%,ロボット全体2)
また,2台のRISは通信を行えるように赤外線を送受信するところを向かい合わせにしています.
#ref(./s_RIS.jpg,70%,RISの位置)
**アーム [#lf980dbe]
ピンポン玉をつかんで,移動する間にためておき,リリパックに入れるための機構です.
#ref(./s_arm1.jpg,60%,アーム全体)
***シーソー部分 [#ba55c924]
シーソーのようにアーム全体が上下移動するための機構です.
#ref(./s_seesaw.jpg,80%,シーソー1)
このアーム部分は重いのでモーターのパワーを出すためにギアを6枚使いパワーアップに成功しました.
#ref(./s_スライド1.JPG,60%,シーソーギア)
取り付けたギアは下の図のようについています.
#ref(./s_スライド2.JPG,80%,ギア図)
***キャッチアーム部分 [#od9e948d]
ピンポン玉をキャッチするための&color(#ffa07a){アーム部分};です.&color(#4169e1){動力源のモーター};が後ろについているのはアーム全体のバランスをとるためです.
#ref(./s_catch_arm_kyori.jpg,70%,キャッチアーム1)
アーム拡大図
#ref(./s_catch_arm.jpg,60%,キャッチアーム2)
動力の伝達は最初は輪ゴムとプーリーの組み合わせでやっていました.これは,モーターの回転方向とアームの回転方法が一致しており簡単に作ることができました.しかし,輪ゴムが滑って思うように動きませんでした.
#ref(./s_syogouki.jpg,60%,キャッチアーム初号機)
そのため,棒を直接つなぐ方法に変更しました.2か所で回転軸を直角に回転させています.
#ref(./s_gear_catch_arm1.jpg,60%,直角ギアアーム部)
#ref(./s_gear_catch_arm2.jpg,60%,直角ギアモーター部)
また,アームを上げるにはパワーが必要だったのでギアの枚数を増やしました.
#ref(./s_catch_arm_motor.jpg,60%,モーターギア)
キャッチする部分は,ピンポン玉が逃げないように突起がついています.
#ref(./s_arm_sentan.jpg,60%,アーム先端)
***ベルトコンベアー部分 [#yc6659a9]
拾ったピンポン玉を上部に上げる役割を担っています.
#ref(./s_conveyor.jpg,60%,ベルトコンベアー全体)
ベルトコンベアーは片方のみが回転すればピンポン玉を運ぶことができるので回転するのは片方のみです.また,下の画像の→部分があることによってピンポン玉をコンベアに押し付けることできます.これで,ピンポン玉が上げる途中で止まってしまうのを防ぎました.
#ref(./s_osituke.jpg,60%,ベルトコンベアー押し付け)
ここも思ったよりパワーが必要だったのでギアの組み合わせを調整しました.モーターの固定にはビームの穴とプレートの穴を使って固定しました.
&ref(./s_gear_old.jpg,60%,ギア前);
→
&ref(./s_gear_new.jpg,60%,ギア);
&ref(./s_setuzoku1.jpg,60%,接続1);
&ref(./s_setuzoku3.jpg,60%,接続2);
&ref(./s_setuzoku2.jpg,60%,接続3);
***アームの動き [#gec82bf7]
アームの動きイメージです.
#ref(./GIF1.gif,150%,アーム動きキャッチ)
ピンポン玉をつかんでアームが上がった後キャッチアームが上がるのは,キャッチアームの突起がコンベアーに引っかっかて動かなくなることを防ぐためです.
#ref(./GIF2.gif,150%,アーム動きリリース)
**足まわり [#a7d901de]
課題2と同様に,タイヤは3輪で前の二輪が駆動輪,後ろの1輪は支えるためについています.摩擦を少なくするためにホイールだけをつけています.
#ref(./s_ashimawari1.jpg,60%,足回り)
裏側
#ref(./s_ashimawari2.jpg,60%,足回り裏)
光センサーは地面から近すぎず,遠すぎずの位置につけました.
#ref(./s_ashimawari3.jpg,60%,センサー前から)
*作戦 [#jce63a37]
車体が重たく,ガタガタ揺れると壊れてしまう可能性があったので,ライントレースをできるだけしないようなルートをくみました.
**1つ目のピンポン玉を入れるまで [#x3f31e06]
#ref(./s_keiro1.JPG,70%,経路説明1)
スタート後2本の黒線を横切って,3本目の黒線の手前で停止します.そこから,ライントレースをしてピンポン玉との距離を調整し,ピンポン玉をキャッチ.その場で90°回転しリリパックにピンポン玉を入れます.
**2つ目のピンポン玉を取るまで [#ia6438b5]
#ref(./s_keiro2.JPG,70%,経路説明2)
リリパックに当たらないように少し下がってから90°回転し,3本の黒線を横切り,右へ方向転換します.4本目の黒線を横切った後,ライントレースをしてピンポン玉に近づきキャッチします.
**リリパックの中のピンポン玉を取るまで [#z03ae177]
#ref(./s_keiro3.JPG,70%,経路説明3)
まず90°回転して向きを合わせます.しかし,そのままではキャッチアームがリリパックに引っ掛かりうまくピンポン玉を取れないので少し後ろに下がってから,ピンポン玉をつかみます.
**3つのピンポン玉をいれるまで [#v8b09cbb]
#ref(./s_keiro4.JPG,70%,経路説明4)
さらに下がって90°回転します.2本目の黒い線の手前で停止して,少し前進してリリパックにピンポン玉を入れます.
*プログラム [#c77b3647]
アームと足を2台のRISを使って通信しながらロボットを動かしたので,2つのメインプログラムがあります.
**アームのプログラム [#nc51bc9b]
***接続 [#hf0fa996]
A:キャッチアーム
B:シーソー
C:コンベアー
***マクロ [#q6601f5e]
通信に使う値です.
#define signal_catch 1
#define signal_release 2
#define signal_end 3
***サブルーチン [#m2d3fb40]
ボールを一度に複数個運べるようにプログラムを書きました.
ボールをつかむサブルーチン
sub CATCH()
{
ClearMessage();
until(Message()==signal_catch);//signal_catchが送られるまで待機
// アームを下げる
OnFwd(OUT_B);
Wait(30);
Off(OUT_B);
Wait(100);
SetPower(OUT_A,2);
// つかむ
OnRev(OUT_A);
Wait(90);
Off(OUT_A);
Wait(100);
// 上げる
OnRev(OUT_B);
Wait(50);
Off(OUT_B);
Wait(100);
// 手を元に戻す
OnFwd(OUT_A);
Wait(90);
Off(OUT_A);
Wait(100);
// コンベアーで奥へ送る
OnFwd(OUT_C);
Wait(200);
Off(OUT_C);
Wait(100);
SendMessage(signal_end);//動作終了を足のRISに送信
}
SendMesssge(signal_end)はアームの動作が終わってから足のプログラムを再開させるためのメッセージです.足のプログラムにはuntil(Message()==signal_end)が入っていて,アームが動き終わってから足が動き始めます.
ボールをリリパックに入れるサブルーチン
sub release()
{
ClearMessage();
until(Message()==signal_release); //signal_releaseが送られてくるまで待機
// アーム下げる
OnFwd(OUT_B);
Wait(30);
Off(OUT_B);
Wait(100);
// コンベアーで前へ送る
OnRev(OUT_C);
Wait(200);
Off(OUT_C);
Wait(100);
// アーム上げる
OnRev(OUT_B);
Wait(50);
Off(OUT_B);
Wait(100);
SendMessage(signal_end);//動作終了を足のRISに送信
}
アームの動きは上のアニメーションを見てください.
***メインプログラム [#sd74fbd5]
task main()
{
ClearMessage();
CATCH();//L'でつかむ��
release();//J'でリリース��
CATCH();//Lでつかむ��
CATCH();//Jでリリパックからつかむ��
CATCH();
ClearMessage();
until(Message()==signal_release);//��
// 下がる
OnFwd(OUT_B);
Wait(30);
Off(OUT_B);
Wait(100);
// 前へ送る
OnRev(OUT_C);
Wait(200);
Off(OUT_C);
Wait(100);
// 上がりながら送る
OnRev(OUT_BC);
Wait(50);
Off(OUT_BC);
Wait(100);
SendMessage(signal_end);
}
最後の「下がる」「前へ送る」はサブルーチン「release」と同じです.ですがサブルーチン「release」を使うと,ボールを箱に入れる前に動作が終わってしまいました.それを防ぐために,「上がりながら送る」を入れ,アームを上げるのと同時にコンベアーも動かしています.
**足 [#d6b7665a]
足のプログラムは動く順序に沿って作られています.時間制御ではバッテリーレベルによって動きが変わるので,大部分を光センサーで制御しています.
***接続 [#f1b9eb35]
A:右車輪
C:左車輪
2:光センサー
***マクロ・グローバル変数 [#v0515351]
光センサーの値,基本的な動作,メッセージの値を定義します.
#define black 40
#define gray_black 44
#define gray 47
#define gray_white 50
#define white 60
#define go_ahead OnFwd(OUT_AC);
#define turn_left OnFwd(OUT_A);Off(OUT_C);
#define turn_right OnFwd(OUT_C);Off(OUT_A);
#define circling_left OnRev(OUT_C);OnFwd(OUT_A);
#define circling_right OnRev(OUT_A);OnFwd(OUT_C);
#define signal_catch 1
#define signal_release 2
#define signal_end 3
グローバル変数を定義します.
int t;
***サブルーチン [#d6459bf3]
ライントレースのサブルーチンです.基本的な仕組みは課題2と同じです.詳しくは[[課題2のレポート>2019a/Member/tamuqtt/Mission2]]を見てください.今回は交差点を認識する必要がないので,グローバル変数tで指定した時間の間動き続けます.
sub follow_line()// 右側トレース
{
SetSensor(SENSOR_2,SENSOR_LIGHT);
ClearTimer(0);
while(FastTimer(0)<t)
{
if(SENSOR_2<black)
{
circling_right;
}
else if(SENSOR_2<gray_black)
{
turn_right;
}
else if(SENSOR_2<gray)
{
go_ahead;
}
else if(SENSOR_2<gray_white)
{
turn_left;
}
else if(SENSOR_2<white)
{
circling_left;
}
}
Off(OUT_AC);
Wait(100);
}
***メインプログラム [#b7dd221b]
メインプログラムは上の作戦に書かれている順序で進むように組んであります.
:A'をスタートして1つ目のピンポン玉を入れるまで|
task main()
{
ClearMessage();
//白なら直進 ※1
while(SENSOR_2>gray)
{OnFwd(OUT_AC);}
Off(OUT_AC);
Wait(100);
//黒なら直進
while(SENSOR_2<gray)
{OnFwd(OUT_AC);}
Off(OUT_AC);
Wait(100);
while(SENSOR_2>gray)
{OnFwd(OUT_AC);}
Off(OUT_AC);
Wait(100);
while(SENSOR_2<gray)
{OnFwd(OUT_AC);}
Off(OUT_AC);
Wait(100);
while(SENSOR_2>gray)
{OnFwd(OUT_AC);}
Off(OUT_AC);
Wait(100);//K'付近に到達
t=90;follow_line();//※2
Wait(100);
SendMessage(signal_catch);// L'でつかむ命令を送る��
ClearMessage();
until(Message()==signal_end);//アームの動作が終わるまで待機
//90°左旋回��
circling_left;
Wait(102);
Off(OUT_AC);
// ボールをリリパックに入れる命令を送る��
SendMessage(signal_release);
ClearMessage();
until(Message()==signal_end);
:2つ目のピンポン玉を取るまで|
//後ろに下がる
OnRev(OUT_AC);
Wait(30);
Off(OUT_AC);
//90°左旋回��
circling_left;
Wait(102);
Off(OUT_AC);
//白なら直進 ※1
while(SENSOR_2>gray)
{OnFwd(OUT_AC);}
Off(OUT_AC);
Wait(100);
//黒なら直進
while(SENSOR_2<gray)
{OnFwd(OUT_AC);}
Off(OUT_AC);
Wait(100);
while(SENSOR_2>gray)
{OnFwd(OUT_AC);}
Off(OUT_AC);
Wait(100);
while(SENSOR_2<gray)
{OnFwd(OUT_AC);}
Off(OUT_AC);
Wait(100);
while(SENSOR_2>gray)
{OnFwd(OUT_AC);}
Off(OUT_AC);
Wait(100);
turn_right;//右に回転
Wait(100);
//白なら直進 ※1
while(SENSOR_2>gray)
{OnFwd(OUT_AC);}
Off(OUT_AC);
Wait(100);
//黒なら直進
while(SENSOR_2<gray)
{OnFwd(OUT_AC);}
Off(OUT_AC);
Wait(100);
t=150;follow_line();//※2
SendMessage(signal_catch);// Lでつかむ命令を送る��
ClearMessage() ;
until(Message()==signal_end);
:リリパックの中のピンポン玉を取るまで|
//90°左旋回��
circling_left;
Wait(102);
Off(OUT_AC);
//後ろに下がる��
OnRev(OUT_AC);
Wait(23);
Off(OUT_AC);
SendMessage(signal_catch);// リリパックでつかむ命令1��
ClearMessage();
until(Message()==signal_end);
Wait(100);
SendMessage(signal_catch);// リリパックでつかむ命令2
ClearMessage();
until(Message()==signal_end);
:3つのピンポン玉を入れるまで|
//後ろに下がる
OnRev(OUT_AC);
Wait(90);
Off(OUT_AC);
//90°左旋回��
circling_left;
Wait(102);
Off(OUT_AC);
//白なら直進 ※1
while(SENSOR_2>gray)
{OnFwd(OUT_AC);}
Off(OUT_AC);
Wait(100);
//黒なら直進
while(SENSOR_2<gray)
{OnFwd(OUT_AC);}
Off(OUT_AC);
Wait(100);
while(SENSOR_2>gray)
{OnFwd(OUT_AC);}
Off(OUT_AC);
Wait(100);
SendMessage(signal_release);//ボールをリリパックに入れる命令を送る��
ClearMessage();
until(Message()==signal_end);
//リリパックから離れるために後ろに下がる
OnRev(OUT_AC);
Wait(100);
Off(OUT_AC);
}
プログラム中の〇数字は作戦の図に対応しています.
※1 この一連の動作は,ラインまで進み,ラインを越え,またラインまで進むという動作をしています.数を調整することで任意の黒線の手前または奥で止まることができます.
※2 follow_lineの後にはボールをつかむプログラム,90°回転するプログラムがあります.その2つは位置が正確でないとうまく機能しません.そのため,ライントレースをすることによって,ロボットをできるだけ黒線と平行にしています.
*まとめ [#f75eac0f]
今回も様々な問題が発生しました.本番では完ぺきとはいかないものの,かなり上手く動いたそうなので本当によかったです.