#author("2020-02-15T19:19:33+09:00","kurisuke","kurisuke") #author("2020-02-15T20:46:35+09:00","kurisuke","kurisuke") [[2019b/Member]] 目次 #contents *課題3 [#lb8d38cc] 赤丸の中に片面は缶を置いて,もう片面に缶の上にボールを乗せた状態で設置する.片面に乗っている空き缶をもう片面の空き缶へ運ぶ.AまたはA'からスタートし,ボールを缶の上に置くことで8点加算され,すべて運び終えたら終了. &ref(2019b/Member/kurisuke/Mission3/Inked課題3 コース_LI.jpg,100%,コース図); 詳しいルールは[[2019b/Mission3]]を参照. **今回のポイント [#bc27d36f] 缶をとる機構と缶に乗せる機構を考える必要がある.また,ロボットを二つにするか一つにするかもそれに応じて考えなければならない. *ロボットの説明 [#cc1875ac] **ロボットを動かす機構 [#f07f0a13] &ref(2019b/Member/kurisuke/Mission3/初期位置.jpg,35%,機体の全体図); &ref(2019b/Member/kurisuke/Mission3/後輪.jpg,35%,後輪); ロボットを動かす機構は上の写真のようにボールをつかむ機構,ボールをためておく橋,ボールを押すのに使う骨組みからなっている.後ろは初めタイヤをつけず,突起物で支える形であったが,摩擦が大きそうだったのでタイヤをつけた.ライントレースは,初め光センサを二つ使ってプログラムを作っていたが,うまく作ることができなかったので基本一つの光センサを使い交差点認識をするときだけ二つ使うようにした.詳しくは,ライントレースのプログラムで説明します.缶の位置は,骨組みに付けた超音波センサで感知するような仕組みにした. **ボールをとる機構 [#g9635885] 初めに考えたのがアームの機構でボールをキャッチする方法であったが,もっと工夫したとり方がよいということで下の図のような輪ゴムを使ったとり方にした. &ref(2019b/Member/kurisuke/Mission3/Inked掴む機構.jpg,35%,ボールキャッチ); &ref(2019b/Member/kurisuke/Mission3/とる機構.jpg,35%,とる機構); ボールをとるには,モータを軸にして輪ゴムを掛けた掴む部分をボールの上に降す.そして,ボールをのっけた状態で,とる機構を180度近く回転させ後ろにあるボールをためる橋に転がしておく方法である.この機構の良いところは,機体が缶の前より少しずれて止まったとしても輪ゴムの伸縮性によりボールをキャッチしてくれるところです.これにより,ライントレースにかなりの正確性を求めなくても済むことになり,ライントレースのプログラムが簡単にれるようになった. **ボールを缶に乗せる機構 [#e81f0973] 初めは,車体の前でボールをキャッチして後ろでボールを置こうと考えていたが,ライントレースの方法が難しくなったり,車体が大きくなりすぎたりといろいろと大変なことが多いので,下の図のようにボールのキャッチと置く動作をどちらも前で行う機構を作った. &ref(2019b/Member/kurisuke/Mission3/置く機構説明_LI.jpg,40%,置く機構説明); &ref(2019b/Member/kurisuke/Mission3/置く機構.jpg,35%,置く機構); 写真の�,里茲Δ妨紊蹐縫癲璽燭撚爾欧襪函き△里茲Δ縫棔璽襪鬚燭瓩討�く橋が支えの棒が下がることで下がる,そして��のように掴む機構を缶の上に下げることによってボールが一時的に缶の上に乗り,もう一つの写真のように�,撚爾欧森�組みで輪ゴムに引っかかっているボールを押して落とすようになっている.この時,ボールを橋からとる機構にうまく運ぶために橋に下のような工夫が施している. &ref(2019b/Member/kurisuke/Mission3/キャッチのストッパー.jpg,35%,ストッパー); &ref(2019b/Member/kurisuke/Mission3/置く機構の工夫.png,50%,置く機構の工夫); 上の写真のように,橋とボールをとる機構の間にはストッパーがついている.仕組みは隣の図を参考にしてほしい.橋の初期位置は少し傾いており,ボールは下にたまるようになっている.とる機構が下りると同時にストッパーは上がり,そのたまったボールを一つだけすくい上げてとる機構に転がして運ぶ.また,ストッパーが上がることにより後ろにあるボールがとる機構に落ちないようにせき止める役割も兼ねている. 上の写真のように,橋とボールをとる機構の間にはストッパーがついている.仕組みは隣の図を参考にしてほしい.橋の初期位置は少し傾いており,ボールは下にたまるようになっている.とる機構が下りると同時にストッパーは上がり,そのたまったボールを一つだけすくい上げてとる機構に転がして運ぶ.また,ストッパーが上がることにより後ろにあるボールがとる機構に落ちないようにせき止める役割も兼ねている.また,橋が初期位置の時に傾いており,ボールが自然にストッパーの上にたまるようになっている. *プログラムの説明 [#sdb892ed] **ライントレースのプログラム [#ka9e2cb4] #define turn_right OnFwd(OUT_B,38); OnFwd(OUT_C,-25);//右折 #define turn_left OnFwd(OUT_C,38); OnFwd(OUT_B,-25);//左折 #define around_right OnFwd(OUT_B,43); OnFwd(OUT_C,-50);//右旋回 #define around_left OnFwd(OUT_C,35); OnFwd(OUT_B,-25);//左旋回 #define go_straight OnFwdSync(OUT_BC,43,0);//直進 #define black 25 //黒の値は25 #define gray 46 //グレーの値は46 #define white 52 //白の値は52 #define INBOX MAILBOX1 //受信用のメールボックス #define c 13 //モータBCを止まるメッセ 上のように,ロボットの動きとライントレース時の閾値の値を設定する. void follow_line(long tmin,long tmax) //左ライントレース { SetSensorLight(S1); //左の光センサー SetSensorLight(S2); //右の光センサー long t = CurrentTick(); long t_start = CurrentTick(); while((CurrentTick()-t<70 || CurrentTick()-t_start<tmin) && (CurrentTick()- t_start<tmax) && (msg != c)){ ReceiveRemoteNumber(INBOX,true,msg);//メッセが送られていないか if(SENSOR_1<black){ if(SENSOR_2<black){ go_straight;} else{ turn_left; t = CurrentTick(); } } else if(SENSOR_1<gray){ go_straight; t = CurrentTick();} else if(SENSOR_1<white){ turn_right; t = CurrentTick(); } else if(SENSOR_1>=white){ around_right; t = CurrentTick();} } Off(OUT_BC); Wait(1000); } void line_follow(long tmin,long tmax) //右ライントレース { SetSensorLight(S1); //左の光センサー SetSensorLight(S2); //右の光センサー long t = CurrentTick(); long t_start = CurrentTick(); while((CurrentTick()-t<70 || CurrentTick()-t_start<tmin) && (CurrentTick()- t_start<tmax) && (msg != c)){ ReceiveRemoteNumber(INBOX,true,msg); if(SENSOR_2<black){ if(SENSOR_1<black){ go_straight;} else{ turn_right; t = CurrentTick(); } } else if(SENSOR_2<gray){ go_straight; t = CurrentTick();} else if(SENSOR_2<white){ turn_left; t = CurrentTick(); } else if(SENSOR_1>=white){ around_left; t = CurrentTick();} } Off(OUT_BC); Wait(1000); } ライントレースのプログラムは,ほとんど課題2と同じである.whileの継続条件にmsgというメッセージを受け取る関数に超音波センサが缶を認識したときに送られるcというモータBCが止まるようなメッセが送られるまではライントレースを続けるという条件を付けくわえた.また,ライントレースを開始するときには必ずcというメッセがを繰られていないか確認するようにした.ロボットの機体のところでも説明したが,初めは光センサを二つ付けてライントレースをしようと試みたがなかなかうまくいかなかったので基本はひとつの光センサでライントレースをし交差点認識の時だけ二つ使った.交差点認識の仕組みは単純に,二つの光センサが黒の閾値をとったときに交差点と認識するようにした. &ref(2019b/Member/kurisuke/Mission3/交差点.png,40%,交差点説明); **ライントレースを始める前の動作 [#o11cbdad] ここで使う,文字の値. #define P 40 #define I 40 #define D 90 #define speed2 40 long d; long wa = 0; ライントレースの初めにアームの初期位置を決めておく.ここを基準にして,アームの動く動作を決める.ここで用いた,RotateMotorPIDは動く角度を正確にするために用いている. void first_set() //アームを初期位置にする { Wait(1000); OnFwd(OUT_B,speed2); OnFwd(OUT_C,speed2); Wait(2000); Off(OUT_BC); RotateMotorPID(OUT_C,-speed2,60,P,I,D); RotateMotorPID(OUT_B,speed2,-40,P,I,D); } また,超音波センサの値が変化しても対応できるように50回床との距離を測って,その平均をセンサの距離として設定する. void search() //超音波センサの値を確認する { SetSensorLowspeed(S4);//端子4に超音波センサー while(i < 51){ wa = wa + SensorUS(S4); i++; } d = wa / i; //50回測ったの床との平均距離 } **ボールをとるプログラム [#c2c9fd2c] これが,ボールキャッチのプログラムである.下の3行のプログラムで初期位置に戻している. void ball_catch() { Wait(100); OnFwd(OUT_B,25);//とる機構を下まで下げる Wait(1000); Off(OUT_B); OnFwd(OUT_C,40);Wait(1000);//超音波センサのついている骨組みを限界まで下げる Off(OUT_C); OnFwd(OUT_B,-20);Wait(2000);//とる機構を缶の上に置く Off(OUT_B); RotateMotor(OUT_B,20,150);//とる機構を後ろに戻してボールを橋に落とす Off(OUT_B); OnFwd(OUT_C,-35);Wait(700); Off(OUT_BC); RotateMotor(OUT_B,-20,30); } **ボールを乗せるプログラム [#i93a26be] これが,ボールを缶に乗せるプログラムである.ボールが完全にストッパーまで転がるまで待つ時間はボールが最後の一個の時でも対応できるように長くとってある. #define speed1 20 //スピード void put_ball() //ボールを置く { RotateMotor(OUT_B,speed1,30);//とる機構を少し下げてストッパーにボールが引っかかりやすくする OnFwd(OUT_C,2 * speed1);//超音波センサのついた骨組みを限界まで下げる Wait(1000); RotateMotor(OUT_C,speed1,-5);//橋の角度を少し傾けてボールをストッパーの上に来るようにする Wait(8000);//ボールが完全に転がるまで待つ RotateMotor(OUT_B,speed1,-120);//空き缶の上にとる機構をセット Wait(600); RotateMotor(OUT_C,speed1,-30); //超音波センサのついた骨組みでボールを突く Wait(400); RotateMotor(OUT_B,speed1 + 10,50); //センサを下ろしたままとる機構を上げ,ボールを落とす Wait(500); OnFwd(OUT_C,2 * speed1);//ここから,初期位置に戻すプログラム Wait(1000); RotateMotor(OUT_B,speed1,70); RotateMotor(OUT_C,speed1,-40); RotateMotor(OUT_B,speed1,-30); } **その他の動作のプログラム [#n3a2b99e] ボールをとった後に缶をどかす動作のプログラム.OnFwdSyncを使うことで正確に真っ直ぐ進むようにした. void poi(long ts, long tb) { OnFwdSync(OUT_BC,40,0); //BとCのパワーを同じにして直進させる Wait(ts); Off(OUT_BC); OnFwdSync(OUT_BC,-40,0); Wait(tb); Off(OUT_BC); } スレイブでの動作が完了するまで,マスターの動きを止めるプログラム.bが12という値であり,スレイブ側からbというメッセが送られるまで繰り返す. #define b 12 void wait() { while(b != 12){ ReceiveRemoteNumber(INBOX,true,b);} b = b - 12; } **メインプログラム [#q873a5c8] ここで,用いる文字の値. #define OUTBOX MAILBOX2 //送信信用のメールボックス #define INBOX MAILBOX1 //受信用のメールボックス #define a 11 //tminが0のライントレースを開始するメッセ #define b 12 //ボールキャッチのプログラムを起動させるメッセ #define c 13 //モータBCを止まるメッセ #define f 15 //缶をどかすメッセ #define g 17 //tminが5000のライントレースを開始するメッセ #define j 18 //左折のメッセ #define k 19 //右折のメッセ #difine l 20 //バックのメッセ #define m 21 //右トレースのメッセ int msg; //受け取った値を格納する変数 long t = 0; [マスターのプログラム] ボールをとるところは,繰り返しを使って簡単にしようと思ったが,考える時間がなかったため長くなってしまった.節目の動作の後は音が鳴るようにしている.メッセを送って動作を促すような仕組みにしたがごちゃごちゃして長くなってしまった. task main() { SetSensorLowspeed(S4);//端子4に超音波センサー first_set(); search(); PlaySound(SOUND_CLICK); //1個目のボールをとる SendRemoteNumber(CONN,OUTBOX,a); while(SensorUS(S4) > (d*3/4)){ t++;}//缶との距離が測った距離の3/4の値になるまで待つ PlaySound(SOUND_CLICK); SendRemoteNumber(CONN,OUTBOX,c);//whileから抜け出せたら,ライントレースを終わりにするメッセを送る wait(); ball_catch(); SendRemoteNumber(CONN,OUTBOX,f);//缶を遠くへどかす wait(); //2個目のボールをとる search(); PlaySound(SOUND_CLICK); SendRemoteNumber(CONN,OUTBOX,g);//Eまでライントレース while(SensorUS(S4) > (d*3/4)){ t++;} PlaySound(SOUND_CLICK); SendRemoteNumber(CONN,OUTBOX,c); wait(); ball_catch(); SendRemoteNumber(CONN,OUTBOX,f); wait(); //3個目のボールをとる search(); PlaySound(SOUND_CLICK); SendRemoteNumber(CONN,OUTBOX,g);//Fまでライントレース while(SensorUS(S4) > (d*3/4)){ t++;} PlaySound(SOUND_CLICK); SendRemoteNumber(CONN,OUTBOX,c); wait(); ball_catch(); SendRemoteNumber(CONN,OUTBOX,f); wait(); SendRemoteNumber(CONN,OUTBOX,a);//F-G wait(); SendRemoteNumber(CONN,OUTBOX,j);//左折 wait(); PlaySound(SOUND_CLICK); SendRemoteNumber(CONN,OUTBOX,a);//G-H wait(); SendRemoteNumber(CONN,OUTBOX,j);//左折 PlaySound(SOUND_CLICK); SendRemoteNumber(CONN,OUTBOX,m);//H-H' wait(); SendRemoteNumber(CONN,OUTBOX,k);//右折 //1個目のボールを置く SendRemoteNumber(CONN,OUTBOX,m);//H'-G' wait(); SendRemoteNumber(CONN,OUTBOX,k);//右折 wait(); SendRemoteNumber(CONN,OUTBOX,m);//G'-F' while(SensorUS(S4) > (d*3/4)){ t++;} PlaySound(SOUND_CLICK); SendRemoteNumber(CONN,OUTBOX,c);//ライントレース終了 wait(); put_ball(); //2個目のボールを置く SendRemoteNumber(CONN,OUTBOX,l);//G'までバック wait(); SendRemoteNumber(CONN,OUTBOX,j);//左折 wait(); SendRemoteNumber(CONN,OUTBOX,m);//G'-D' wait(); SendRemoteNumber(CONN,OUTBOX,k);//右折 wait(); SendRemoteNumber(CONN,OUTBOX,m);//D'-E' while(SensorUS(S4) > (d*3/4)){ t++;} PlaySound(SOUND_CLICK); SendRemoteNumber(CONN,OUTBOX,c);//ライントレース終了 wait(); put_ball(); //3個目のボールを置く SendRemoteNumber(CONN,OUTBOX,l);//バック wait(); SendRemoteNumber(CONN,OUTBOX,j);//左折 wait(); SendRemoteNumber(CONN,OUTBOX,m);//D'-C' while(SensorUS(S4) > (d*3/4)){ t++;} PlaySound(SOUND_CLICK); SendRemoteNumber(CONN,OUTBOX,c);//ライントレース終了 wait(); put_ball(); //終了 } [スレイブのプログラム] 基本は,マスターからメッセを受け取り,そのメッセに合った動作をしてからマスターに終了メッセを送る流れになっている. task main() { while(true){ ReceiveRemoteNumber(INBOX,true,msg); if(msg == a){ //左ライントレース follow_line(0,400000); SendResponseNumber(OUTBOX,b); } if(msg == f){//缶を移動 poi(3000,3000); SendResponseNumber(OUTBOX,b); } if(msg == g){//左ライントレース(交差点無視あり) follow_line(50000,400000); SendResponseNumber(OUTBOX,b); } if(msg == j){//左折 around_left; Wait(2000); Off(OUT_BC); SendResponseNumber(OUTBOX,b); } if(msg == k){//右折 around_right; wait(2000); Off(OUT_BC); SendResponseNumber(OUTBOX,b); } if(msg == l){//バック OnFwdSync(OUT_BC,-40,0); //BとCのパワーを同じにする Wait(1000); Off(OUT_BC); SendResponseNumber(OUTBOX,b); } if(msg == m){//右ライントレース line_follow(0,500000); SendResponseNumber(OUTBOX,b); } } } *課題3の反省と感想 [#d08b4e71] 結果は失敗した.ライントレースの値を超音波センサのように閾値を測ってからトレースするようにすれば,電池の残量が多くても少なくても関係なく動いてくれたのかなと思う.また,プログラムをもっと簡単にできたのではないかと後悔している.時間がなかったのと自分のプログラムの技術不足であった.この講義のおかげで,プログラムやロボットの扱いにはなれることができたので,この経験を生かして頑張っていきたい.