フィールドの説明
フィールドは上図のようになっている(2012b/ロボコンから引用)
フィールドはMission1で使用したコースを2枚つなぎ合わせたもので、つなぎ目に断面が3cm×4cmの角材が付けてある。
白い紙パックと黒い紙パックがそれぞれ体格のゴールに置かれている。紙パックは図のように前1個、後2個の2列に配列されている。
基本ルール
図の白い紙パックと黒い紙パックを入れ替える。
スタート時のロボットは2個を越えてはならない。
競技が終了するまで、ロボットに触ったり人間が遠隔で操作してはならない。
最終的にゴールに運び込まれた紙パックの数で点数を計算する。
得点計算
運びこまれた紙パックに1個つき5点。
紙パックが半分以上ゴールからはみ出している場合は1個1点、はみ出している部分が半分未満の場合は1個3点。
一部がゴールの外にはみ出た出た紙パックの上に積み上げられた紙パックは、何段目であっても各3点とする。
技術点の計算方法
以下の動作の精度・スピード・確実性などを含めた技術的な工夫や芸術性について他の全てのチーム(5チーム)が20点満点で採点し、その平均点を求める。
得点の目安:
紙パックまでたどり着く動作 (3点)
紙パックを運ぶ動作(2点)
障害物を越える動作 (4点)
2台以上のロボット、あるいは単体のロボットの場合は2台のRCX,NXTの連携の良さ(3点)
自立型のロボットとしての形や動作の美しさ、斬新さ(3点)
その他 (4点)
今回の課題では、私達はロボットを2台使用することにした。
こちらの本体には手を加えてないので2012b/Member/vocalist/Mission2を参照。
左上の写真が2台目のロボットの全体図である。
その隣の画像は某漫画のキャラクターである。このロボットがこのキャラクターに似ているということを言われたので載せた。
Aモーターがアームの開閉を制御し、Bモーターが右のタイヤ、Cモーターが左のタイヤを制御している。
初期状態ではアームは閉じた状態である。
こちらのロボットのベースは私が作成し、手前のアームやその他細かい部分は他の二人に改善してもらった。
このロボットは前方にあるアームで紙パックを挟むだけの構造となっている。
何故このような簡素な造りになっているのか。その理由は、もう一方のロボットがこちら側の所定の位置にある紙パックを自分のフィールドの方へ引きずり込むからだ。
このためこちら側のロボットは紙パックを送る構造を省くことができた。
上の写真では前方のアームを外して撮影している。
Mission1の時に反省した点を活かし、タイヤと光センサーの位置をできるだけ近くにした。
光センサーの前を囲っている部分は、壁に当ててズレを修正するための壁当て部分である。
これを付けていない場合、光センサーにあたってしまうということで実装した。
紙パックが1個の場合、上の図のように挟んで取る。
アーム先端にはゴムを付け、摩擦をおこすことで紙パックが動かないようにしている。
練習時には輪ゴムを付けて動かしていたが、実際ロボコンではパーツに入っているゴムを使用する。
また、プログラムの方でも説明するが、挟んだ状態で動くときはモーターで締め付けて遠心力等で離れないようにしている。
もし2個倒れた紙パックを取る場合でも、1個で倒れていない時と比べれば安定性は劣るものの、運ぶことができる。
上の写真を見てわかるかと思うが、アームには左右それぞれ2個のゴムを使用している。
紙パックが倒れてしまった場合でも下のゴムが当たるので離れていくとこはない。
機体1のプログラムには手を加えていないので2012b/Member/j-abc/Mission2を参照。
機体2のプログラムは私が作成したので以下で説明する。
機体2では赤で囲った方のフィールドを使用する。
機体2のプログラムの大まかな流れ
スタート地点からライントレースをし、壁側の交差点まで行き、壁当てをする
ゴールの紙パックを手前から順にスタート地点に隔離する(この時前2個、後1個になっている)。
この時1回置きに行く度に最初に壁に当てた場所に戻り、壁当てをしてズレを修正する。
無効のロボットと通信を行い準備ができ次第向こうの紙パックを受け取り、ゴールに持っていく。この時も壁当てはする。
スタート地点に残っている紙パックを所定の位置に持っていく。(この時も向こうのロボットと通信を行いタイミングを図る)
#define THRESHOLD 40//閾値 #define SPEED 40//通常時の速度 #define SPEED_L 25//低速時の速度
閾値と速度の定義。
この時の閾値は40であった。
通常は40のスピードで動作するが、ライントレースをする時など安定性を求める場合、通常時より遅いスピードで動作させる。
#define STEP 1//1回の判断で動作させる時間 #define nMAX 200//通常のカーブとして許容できる繰り返しの最大値 #define turn_left OnRL_(SPEED_L,-SPEED_L);//左旋回 #define turn_right OnRL_(-SPEED_L,SPEED_L);//右旋回
上の定義はライントレースを行うのに使用する。
#define B90(speed) RotateMotor(OUT_B,speed,337);Off(OUT_B);//右タイヤのみで本体を90°左右に旋回 #define C90(speed) RotateMotor(OUT_C,speed,337);Off(OUT_C);//左タイヤのみで本体を90°左右に旋回 #define OnRL(speed,angle) RotateMotor(OUT_BC,speed,angle);Off(OUT_BC);//速度と角度指定で前進or後退 #define OnRL_(speedR,speedL) OnFwd(OUT_B,speedR);OnFwd(OUT_C,speedL);//左右の速度指定で基本前進or後退 #define A(speedA) OnFwd(OUT_A,speedA);//速度指定でAモータの動作を決定
今回のプログラムにおいて上の5つは重要な定義である。
上3つは角度での制御を行う。角度制御は時間制御よりも正確なので、今回はこちらを主に使用した。
ただし、時間制御を使用する方が良い場合もあるということで下2つの定義で時間制御をしている。
サブルーチンは4つに大別される。
sub get1()//自分のゴールにある紙パックをスタート地点に隔離する(手前の1個) { OnRL(-SPEED,390);//ここから手前の紙パックを回収しに行く C90(-SPEED); A(SPEED); Wait(350); Off(OUT_A); OnRL(SPEED,400); A(SPEED); Wait(600);//ここで回収終了 C90(-SPEED);//ここからスタート地点に持っていく B90(SPEED); OnRL(SPEED,500); Off(OUT_ABC); A(-SPEED); Wait(1000); Off(OUT_A);//ここで処理終了 OnRL(-SPEED,530);//開始した地点に戻る B90(SPEED); OnRL_(SPEED,SPEED); Wait(2000); Off(OUT_BC);//壁に当ててズレを修正 } sub get2()//自分のゴールにある紙パックをスタート地点に隔離する(残りの2個) { OnRL(-SPEED,390);//ここから残りを回収しにいく C90(-SPEED); A(SPEED); Wait(350); Off(OUT_A); OnRL(SPEED,650); A(SPEED); Wait(600);//ここで回収終了 C90(-SPEED);//ここからスタート地点に持っていく B90(SPEED); OnRL(SPEED,580); Off(OUT_ABC); A(-SPEED); Wait(1000); Off(OUT_A);//ここで処理終了 OnRL(-SPEED,340);//開始した地点に戻る B90(SPEED); OnRL_(SPEED,SPEED); Wait(2000);//壁に当ててズレを修正 Off(OUT_BC); Wait(500); OnRL(-SPEED,390); Off(OUT_BC); A(SPEED); Wait(350); Off(OUT_A);//向こうの紙パックを受けられる状態で待機 }ここではおおまかな流れの2番を2つに分けて行っている。
始めに向こうの紙パックを受けるので、ゴールを空けるためにこの処理を行う。
sub car1()//反対側のロボットから紙パックを受け取って所定の位置に置きに行く(受け取る紙パックは1個) { OnRL(SPEED,140); A(SPEED);//受け取った後掴み直す Wait(800); OnRL(-SPEED,90); A(-SPEED); Wait(1000); Off(OUT_A); OnRL(SPEED,50); A(SPEED); Wait(1000); OnRL(-SPEED,90);//紙パックを受け取って所定の位置に置きに行く C90(-SPEED); OnRL(SPEED,570); A(-SPEED); Wait(1000); Off(OUT_A);//開始した地点に戻る C90(-SPEED); B90(SPEED); OnRL(SPEED,160); B90(SPEED); OnRL_(SPEED,SPEED); Wait(2000);//壁に当ててズレを修正 Off(OUT_BC); Wait(500); OnRL(-SPEED,390); Off(OUT_BC); A(SPEED); Wait(350); Off(OUT_A);//向こうの紙パックを受けられる状態で待機 } sub car2()//反対側のロボットから紙パックを受け取って所定の位置に置きに行く(受け取る紙パックは2個) { OnRL(SPEED,140); A(SPEED);//受け取った後掴み直す Wait(800); OnRL(-SPEED,90); A(-SPEED); Wait(1000); Off(OUT_A); OnRL(SPEED,50); A(SPEED); Wait(1000); OnRL(-SPEED,90);//紙パックを受け取って所定の位置に置きに行く C90(-SPEED); OnRL(SPEED,390); A(-SPEED); Wait(1000); Off(OUT_A);//開始した地点に戻る C90(-SPEED); B90(SPEED); OnRL(SPEED,170); C90(-SPEED); OnRL_(SPEED,SPEED); Wait(3000);//壁に当ててズレを修正 Off(OUT_BC); Wait(500); }大まかな流れ3番を2つに分けて行っている。
向こうから渡される回数は2回なので置きに行く時の進む距離などを細かく分けて指定してある。
sub pass1()//隔離した紙パックを渡しにいく(紙パック2個) { OnRL(-SPEED,390);//スタート地点に最後に置いた紙パックを回収に行く Off(OUT_BC); B90(-SPEED); A(SPEED); Wait(350); Off(OUT_A); OnRL(SPEED,400); Off(OUT_BC); Wait(500); A(SPEED); Wait(600);//受け渡し場所に持っていく OnRL(-SPEED,210); C90(-SPEED); OnRL_(SPEED,SPEED); Wait(2000); Off(OUT_ABC); Wait(500); A(-SPEED); Wait(1000); Off(OUT_A); OnRL(-SPEED_L,170); } sub pass2()//隔離した紙パックを渡しにいく(紙パック1個) { B90(-SPEED);//残りの紙パックを回収しに行く OnRL(SPEED,580); Off(OUT_BC); Wait(500); A(SPEED); Wait(600);//受け渡し場所に持っていく OnRL(-SPEED,330); C90(-SPEED); OnRL_(SPEED,SPEED); Wait(2000); Off(OUT_ABC); Wait(500); A(-SPEED); Wait(1000); Off(OUT_A); OnRL(-SPEED_L,170); }最後のここでも2つに分けている。
受け渡し場所に持っていき、低速で離れることによって反動で紙パックの位置がずれないようにしている。
sub connect_slave1() { int msg=0;//受け取った数値を格納するための変数 int flag=0;//処理を終了してwhile文を抜けるための変数 while(flag!=1){ ReceiveRemoteNumber(MAILBOX1,true,msg);//MAILBOX1に格納されてる数値を読み込む if(msg==1){//もし読み込んだ数値が1(相手が所定の一に到達した)なら SendResponseNumber(MAILBOX2,1);//MAILBOX2に1という数値(こちらも到達した事を通知する)を送る }else if(msg==2){//もし読み込んだ数値が2(相手に通知された)なら repeat(30){ SendResponseNumber(MAILBOX2,2);//MAILBOX2に2という数値(終了宣言)を送る } flag=1;//whileを抜けるための数値を入れる } } } sub connect_slave2() { int msg=0;//受け取った数値を格納するための変数 int flag=0;//処理を終了してwhile文を抜けるための変数 while(flag!=1){ ReceiveRemoteNumber(MAILBOX3,true,msg);//MAILBOX3に格納されてる数値を読み込む if(msg==1){//もし読み込んだ数値が1(相手が所定の一に到達した)なら SendResponseNumber(MAILBOX4,1);//MAILBOX4に1という数値(こちらも到達した事を通知する)を送る }else if(msg==2){//もし読み込んだ数値が2(相手に通知された)なら repeat(30){ SendResponseNumber(MAILBOX4,2);//MAILBOX4に2という数値(終了宣言)を送る } flag=1;//whileを抜けるための数値を入れる } } } sub connect_slave3() { int msg=0;//受け取った数値を格納するための変数 int flag=0;//処理を終了してwhile文を抜けるための変数 while(flag!=1){ ReceiveRemoteNumber(MAILBOX5,true,msg);//MAILBOX5に格納されてる数値を読み込む if(msg==1){//もし読み込んだ数値が1(相手が所定の一に到達した)なら SendResponseNumber(MAILBOX6,1);//MAILBOX6に1という数値(こちらも到達した事を通知する)を送る }else if(msg==2){//もし読み込んだ数値が2(相手に通知された)なら repeat(30){ SendResponseNumber(MAILBOX6,2);//MAILBOX6に2という数値(終了宣言)を送る } flag=1;//whileを抜けるための数値を入れる } } } sub connect_slave4() { int msg=0;//受け取った数値を格納するための変数 int flag=0;//処理を終了してwhile文を抜けるための変数 while(flag!=1){ ReceiveRemoteNumber(MAILBOX7,true,msg);//MAILBOX7に格納されてる数値を読み込む if(msg==1){//もし読み込んだ数値が1(相手が所定の一に到達した)なら SendResponseNumber(MAILBOX8,1);//MAILBOX8に1という数値(こちらも到達した事を通知する)を送る }else if(msg==2){//もし読み込んだ数値が2(相手に通知された)なら repeat(500){ SendResponseNumber(MAILBOX8,2);//MAILBOX2に8という数値(終了宣言)を送る Wait(1); } flag=1;//whileを抜けるための数値を入れる } } }これらは通信をするためのプログラムである。
4つあるのは1つのプログラムを使いまわした時に上手く動作しなかったためである。
サブルーチンの名前から分かるよう、こちらのロボットがslave側だ。
task main() { int gain;//センサの値と閾値の差分を入れる変数 int flag=0;//処理を終了してwhile文を抜けるための変数 int nOnline=0;//黒線を読んだ数 SetSensorLight(S4); OnRL_(SPEED,SPEED); Wait(500); while(flag!=1){ if(nOnline>nMAX){//交差点と判断 OnRL_(SPEED,0);//ラインに平行になるよう修正 Wait(350); Off(OUT_BC); OnRL(SPEED,130); B90(-SPEED); Off(OUT_BC); OnRL_(SPEED,SPEED); Wait(1200);//壁に当ててズレを修正 Off(OUT_BC); /*これ以下のプログラムはほぼサブルーチンを参照*/ get1(); get2(); connect_slave1(); Wait(3000); car1(); connect_slave2(); Wait(3000); car2(); pass1(); connect_slave3(); Wait(30000); pass2(); connect_slave4(); flag=1;//whileを抜けるための数値を入れる }else{ if(SENSOR_4<=THRESHOLD-10){//センサーの値が30以下の場合 turn_right; nOnline++;//カウンタを増やす }else if(SENSOR_4>=THRESHOLD+10){//センサーの値が50以上の場合 turn_left; nOnline=0;//カウンタをリセット }else{//それ以外の場合は比例制御 gain=THRESHOLD-SENSOR_4;//差分計算 OnRL_(SPEED_L+gain,SPEED_L-gain); nOnline=0;//カウンタをリセット } } Wait(STEP); } }本体はライントレースが主体となっている。
交差点を判断した後はサブルーチンを処理し、終了する。
connect_slaveの後にWaitが入っているが、これらは一方のロボットとのタイミングを合わせたりする為に入れてある。
前回の反省も活かすことができた。
角度制御にすることにより、時間制御よりも安定性が増した。しかし、それでもバッテリーによって差が出たりしてしまった。
通信や角度制御についてもう少し学んでから挑みたかった。