目次
2019b/Mission3を参照 自分たちの班はC>E>Fとボールをとり、F`>E`>C`とボールを置こうとした
今回の課題では、前回の課題で得られたすべての機構はロボットの進行方向と同一にしたほうが正確性が高いというのをもとに、アーム、レーン、センサーのすべてを進行方向に設置した。 コントロールユニットは2つ使用しており、片方がライントレース用、もう片方がボールの確保と設置用となっている。お互いに通信させている。
これが今回ボールを確保する機構である。今回の課題では空き缶の上においてあるボールを確保する必要があった。そこで出る問題は、空き缶の軽さである。これによって、ボールを水平方向から確保するには抑えのような機構が必要になる。しかし、それでは必要になる機構が多くなってしまうので結果としてボールに対して鉛直方向からの力での確保が必須と考えたのでこの形となった。この機構は、レーンの下に輪ゴムを使ってボールを支えることで、ボールの自重では下に落ちず、ロボットの力で落とすことができるようになっている。
ボールをキャッチする機構をそのまま缶の上に押さえつけ、、その上にある機構の出っ張りによりボールが一つずつ出てくるようになっている。
このアームには、直接ボールを掴むなどの機構などはなく先ほど説明したレーンとの組み合わせによりボールを缶の上に置くようになっている。具体的には、レーンの上のボールの下に缶があればアームでボールを上から押さえつけ、その状態でレーンを上げることによってボールを設置するという輪ゴムの性質を活かした機構となっている。
今回のライントレースでは、光センサーを2つ使用して首振りによる確保したボールの落下を防いで、正確性を向上させた。
前々から薄々きづいていたのだがこの超音波センサーの精度はお世辞にも良いものとは言えない。そこで今回は缶とボールに対して鉛直方向から観測することで、缶とボールがそこに存在するかどうかについての判断をさせた。
今回、自分はプログラムの作成が本番に間に合わなかった。そこで、本番に使用したプログラミングをを載せておく。
今回の課題では2つのコントロールユニットを使用するので完全に通信してしているかや、正確性(超音波センサー、アームやレーンの初期位置など)の確保のためのプログラムを作成した。
void m_con(){//接続
int x; while(x!=4){ ReceiveRemoteNumber(MAILBOX1,false,x); } PlayTone(700,200);
} これはマスター側のプログラムで、これを押してスレイブからの反応があれば音がなるようになっている。
#define con 4 void s_con(){//接続 SendResponseNumber(MAILBOX1,con);PlayTone(700,200); }
返す番号は4でこれをマスターの1のメールボックスにかえす。これにより接続が完了しているか否かについて知ることができる。
void reset(){//初期位置 ResetTachoCount(OUT_BC); OnFwd(OUT_B,20);Wait(800); OnFwd(OUT_C,45);Wait(1200); RotateMotor(OUT_B,-20,10); OnFwd(OUT_C,-20);Wait(1700); OnFwd(OUT_B,-20);Wait(400); Off(OUT_BC); }
これによって、アームやレーンのセッティングのし忘れが起きたときのリスクをなくしている。 アーム、レーンをともに最初に目一杯後ろにそらしたあと、その療法を適切な位置に前方方向に倒している。
#define st 2 #define t 52 #define sp 40 int y; void gf (long x,long y){ OnFwd(OUT_B,x);OnFwd(OUT_C,y); } void line_trace(long t_min) {//止まる命令が来るまでライントレース SetSensorLight(S1); SetSensorLight(S2); long t_start=CurrentTick();PlayTone(700,200); while(y!=st){ ReceiveRemoteNumber(MAILBOX1,true,y); if(SENSOR_1<t-7){ if(SENSOR_2<t-7){ if((CurrentTick()-t_start)<t_min){gf(sp,sp);} else{break;} } else if(SENSOR_2<t+7){ gf(0,sp); } else { gf(-sp,sp); } }//if1 else if(SENSOR_1<t+7){ if(SENSOR_2<t-7){ gf(sp,0); } else if(SENSOR_2<t+7){ gf(sp,sp); } else { gf(0,sp); } }//if2 else{ if(SENSOR_2<t-7){ gf(sp,-sp); } else if(SENSOR_2<t+7){ gf(sp,sp); } else { gf(sp,sp); } }//if3 }//while gf(0,0); PlayTone(1400,200); } //trace
これが本番で使用したライントレースである。これは自分が作成しようとしていた比例制御を用いたものではなく、課題2のときに培われたノウハウを用いて作成している。課題2のときとは違い、センサーが2つあることによりさらに細かな判断を行うようになっている。右のセンサーに対して3つの、更に左のセンサーに対しても3つの合計3✕3の9つの判断を行うようにしている。 交差点前の時間計測を無視するために引数としてt_minを用いている。これはスレイブ側のプログラムなので、マスターからのgoの指示で動き、stopの指示で停止するようにしている。
#define go 1 #define st 2 void observe(){ int c=0; long sum=0; float a; SendRemoteNumber(1,MAILBOX1,go);//go命令 SetSensorLowspeed(S4); while(c!=10){ sum=sum+SensorUS(S4); c=c+1; } a=sum/10;//十回平均 while(SensorUS(S4)>0.5*a){ }//while SendRemoteNumber(1,MAILBOX1,st);//stop命令 }//void
今回は、超音波センサーの仕様にあたって一つの懸念があった。それはセンサーの制度の問題である。 そこで今回は、超音波センサーの値は平均をとり、それを利用してレーン上のボールがあるかどうかの判断を行うようにしている。また、先ほど説明した、スレイブにgoとstopのコマンドを送るかどうかの判断はここで行っており、アームとレーンの初期位置ついての準備が完了すれば、goの1を、超音波センサーの地面との距離が計測し続けていた値の半分付近に達すると、空き缶上のボール、または空き缶を発見したとして、stopの2を送るようにしている。
#define go 1 int y; void waiting(){ while(y!=go){ReceiveRemoteNumber(MAILBOX1,true,y);} }
スレイブ側がマスターからのgoの指示が来るまで待つためのものである。
#define sp 40 void move_can(){ OnFwdSync(OUT_BC,sp,0);Wait(3500); OnFwdSync(OUT_BC,-sp,0);Wait(2900); }
ボールをとった以降にコース上にある缶ははっきり言って邪魔である。そこで、ライントレースをする前にその邪魔な缶を排除するためのプログラムがこれである。
#define spd 30 #define go 1 void put_ball(){ OnFwd(OUT_B,spd);Wait(1000);//キャッチ機構を後ろに傾ける OnFwd(OUT_C,2 * spd);//アーム機構を後ろへ RotateMotor(OUT_B,4 * spd,-5);Wait(8000);//キャッチを少し前え倒し、この反動でボールの引っ掛かりをなくす Off(OUT_BC); RotateMotor(OUT_B,spd,-120);Wait(600);//空き缶の上にキャッチ機構をセット RotateMotor(OUT_C,spd,-65);Wait(400);//ボールを突く RotateMotor(OUT_B,spd + 10,50);Wait(500);//アームでボールを抑えたままキャッチ機構を上げる OnFwd(OUT_C,2 * spd);Wait(1000);//アーム機構を後ろに倒す RotateMotor(OUT_B,spd,70);//キャッチの機構も後ろへ RotateMotor(OUT_C,spd,-40);//アームの機構を前へ RotateMotor(OUT_B,spd,-30);//キャッチの機構を少し前へ SendRemoteNumber(1,MAILBOX1,go);//スレイブにgoの指示 }
C`,F`,E`の点上にある缶の上にボールを設置するためのプログラミング
これがマスター側のメインプログラムである。
#define tt 700//四半回転時間 #define bt 1500//半回転時間 task main(){ m_con();//スレーブとの接続を確認 reset();//アーム、レーンを初期位置にセット observe();//go命令を出し、C上のボールを観測したらstopの指示を与える catch();//C地点のボールをつかみ、goの指示を与える Wait(7000);//C地点の缶の排除の完了まで待機 observe();//goの指示、E上のボールを観測したらstopの指示 catch();//E地点のボールをつかみ、goの指示 Wait(7000);//E地点の缶の排除の完了まで待機 observe();//goの指示、F上のボールを観測したらstopの指示 catch();//F地点のボールをつかみ、goの指示を出す Wait(7000);//F地点の缶の排除の完了まで待機 SendRemoteNumber(1,MAILBOX1,go);//goの指示 Wait(10000);//少し待つ observe();//F’地点の缶を観測したらstop指示 put_ball();//F’地点の缶にボールを置く observe();//E’地点の缶を観測したらstop指示 put_ball();//E’地点の缶にボールを置く observe();//C’地点の缶を観測したらstop指示 put_ball();//C’地点の缶にボールを置く }
これはスレイブ側のプログラミングである。
task main(){ s_con();//マスターとの接続を確認 waiting();//go命令待ち line_trace(10000);//C地点までライントレース waiting();//マスターがC地点のボールを取りgo指示が来るまで待つ move_can();//C地点の缶の排除 waiting();//goの指示を待つ line_trace(20000);//E地点の缶までライントレース waiting();//マスターがE地点のボールを取りgoの指示が来るまで待つ move_can();//E地点の缶の排除 waiting();//goの指示を待つ gf(sp,sp);Wait(400);turn_r();//E地点の缶を排除し、線に戻る line_trace(8000);//F地点の缶までトレース waiting();//マスターがF地点のボールを取りgoの指示が来るまで待つ move_can();//F地点の缶を排除 waiting();//go待ち gf(sp,sp);Wait(400);turn_r();//F地点の缶を排除後、線に戻る line_trace(3000);//交差点Gまでライントレース turn_l();line_trace(1500);//G-H turn_l();line_trace(1000);//H-H' turn_r();line_trace(1000);//H'-G' gf(sp,sp);Wait(300);turn_r();line_trace(5000);//G'-F' waiting();//マスターがF'地点にボールを置きgoの指示が来るまで待つ OnFwdSync(OUT_BC,-sp,0);Wait(1000);gf(-sp,sp);Wait(tt);;line_trace(1000);//F'-G'-D' turn_r();line_trace(1000);//D'-E' waiting();//マスターがE'地点にボールを置きgoの指示が来るまで待つ OnFwdSync(OUT_BC,-sp,0);Wait(bt);//E'-D' gf(sp,sp);Wait(300);gf(sp,-sp);Wait(tt*2);line_trace(10000);//D'-C' }
今回の課題ではまず、ロボットをコンパクトにしすぎたことがあげられる。これにより、ロボットの作成途中でパーツに負荷がかかりすぎたことによる破損やモーターの回転が何らかの障害により阻害されるなどの問題が発生した。 また、そのほかにもボールを同時に3つ運ぼうと欲張ったことで、プログラミングの難化、設計にボールをためておく場所の工夫など考慮しなければいけない問題が増えた気がした。ボールを1つづつ運べば、コース取りや正確性に気を使う必要はなかったかもしれない。
この講義を通して、いかにロボットの制御や設計が難しいか学ぶことができ、それと同時に班員と協力し、一つの大きな課題に向き合うことの楽しさを味わうことができた。紆余曲折はあったが非常に有意義な授業であったと思う。