[[2013b/Member]] #contents *a メンバ紹介 [#t323fb9c] +おのくん 蚕学部化材系の人です。基本プログラム担当。 + 工学部の人。ロボットとプログラム担当。 *課題1について [#g128978a] http://yakushi.shinshu-u.ac.jp/robotics/?2013b%2FMission1 に詳しくあります。 *ロボットの説明 [#kcf75790] **99.9999999999999999%は相方が作っています。 [#mc2c3d8b] + ロボットの開発は全て相方に任せてしまいました。課題2では自分も開発に携わろうと思います。 + ロボットについてはこちらを参照してください。→http://yakushi.shinshu-u.ac.jp/robotics/?2013b%2FMember%2FRedcicudu%2FMission1 *プログラムの説明 [#s556e4c0] **プログラムの内容 [#j973254a] **プログラムの内容 [#s727f7b9] ライントレースと缶を丁重にどかして元の位置に戻す処理。 **pianomanの書いたプログラムの特徴。 [#e4a94d3b] このプログラムの最大の特徴はライン状をジグザグに走行する点と、またそのために交差点処理がない点です。出来るだけ多くのコースに対応できて、しかも簡単なロジックでコード量が少ないプログラムになるよう目指してみました。 一方缶の処理は時間をかけることが出来なかったためテキトーです。 (図説) **コードの解説 [#m127ce42] 1.プリプロセッサの部分 #define black 37 // この値より小さいと黒と判定します。 #define white 50 // この値より大きいと白と判定します。 #define ct1 150 // 缶をつかむときのモータの回転角です。 #define distance 20 #define go OnFwdSync(OUT_AB,p,0) // 前進。左右のタイヤが同期するようにしているのでまっすぐ進みます。 #define back OnRevSync(OUT_AB,p,0) // 後進 #define go_slowly OnFwdSync(OUT_AB,p,0) #define turn_fa OnFwdSync(OUT_AB,p,cd) // 一回目の回転です。 #define turn_fb OnFwdSync(OUT_AB,p,-cd) // 判定失敗時に機体の方向を元に戻します。 #define turn_sa turn_fb // 二回目の回転です。 #define turn_sb turn_fa // 判定失敗時。 2.変数 long t0,t1; int cd = 100; int cdp,cdm,pcd; int TurnLevel = 0; long TurnTime = 0; int p = 35; それぞれ後で解説します。 3.main関数 task main() { while(true) { SetSensorLight(S1); // 光センサの有効化 SetSensorLowspeed(S2); // 超音波センサの有効化 if(SensorUS(S2) > 20) {lt();} // 機体前20cm以内に何もない時はライントレースします。 else if(SensorUS(S2) <= 20) {ct();} // 機体前20cm以内に缶がある場合は缶の処理をします。 } } 4.lt関数 sub lt() { while(SensorUS(S2) > distance) { if(SENSOR_1 < black) // 黒線上は直進 { go; } if(SENSOR_1 >= black || SENSOR_1 <= white) { go_slowly; // 際では徐行 } if(SENSOR_1 > white) { decide(); // 色い領域に出たら黒線を探します。 } } } 図 5.decideサブルーチン sub decide() { while(SENSOR_1 > white) { fix(); // 白線領域に大きくはみ出して黒線を検出できなくなった時の対処です。 turn(); // ターンし始める方向を決定します。 curve(); // curve mode turntime(); // get turntime t0 = CurrentTick(); turn_fa; // turn()で決定した方向に回転します。回転時間はTurnTime間ですが、黒線を検出するとdecide()を抜けて再び直進します。 until(SENSOR_1 < black || CurrentTick()-t0 == TurnTime); if(SENSOR_1 <black) { pcd = cd; TurnLevel = 0; } else { turn_fb; Wait(TurnTime); t0 = CurrentTick(); turn_sa; until(SENSOR_1 < black || CurrentTick()-t0 == TurnTime); if(SENSOR_1 < black) { pcd = -cd; TurnLevel = 0; } else { turn_sb; Wait(TurnTime); TurnLevel ++; } } } } このサブルーチンは黒線を探すプログラムです。 まず最初に片側にTurnTimeに代入した時間だけ回転します。もし回転中に黒線を検出したらそこでmainプログラムの先頭へジャンプし、またまっすぐ走行します。 回転中に黒線を検出できなかったらロボットの方向をまた元に戻し、今度は逆の方向へTurnTime分を回転します。ここでも同様に回転中に黒線を検出したらmainの先頭に戻ります。検出できなかったらまたロボットの方向を元に戻しTurnLevelの値を増やして再度黒線の検出を再開します。 ここではいくつかの変数が出てきます。 +TurnLevel ~これはTurnTimeの値を決定するのに使われます。黒線の検出に失敗したら値が増え,それに応じてTurnTimeの値が増えていきます。黒線の検出に成功したら0にろセットされます。 +TurnTime ~回転する時間を決めます。時間に応じてロボットの回転角が変化します。turntime()で値を計算します。 +TurnResult ~これは次にロボットが黒線を探すときに、どの方向から曲がり始めるかを決める値として使われます。 +Curve_f,Curve_s ~これは連続して何回同じ方向にカーブして黒線を検出したのかを記録します。curve mode のスイッチ役です。 次にturntimeルーチンを見てみます sub turntime() { switch(TurnLevel) { case 0: TurnTime = 500; break; case 1: TurnTime = 1000; break; default: TurnTime = 1500; } } 見ての通り、TurnLevelの値に応じてTurnTimeを代入しています。defaultではTurnLevelが0でも1でもない時の値を設定しています。 次はturnresultルーチンです。 sub turnresult() { switch(TurnResult) { case 1: f = 1; s = 0; break; case 0: f = 0; s = 1; break; } } ここではロボットがdecide動作に入った時にどの方向から回転し始めるかを設定しています。冒頭に、 #define turn_fa OnFwd(f,fp);OnRev(s,sp) #define turn_fb OnRev(f,fp);OnFwd(s,sp) #define turn_sa OnFwd(s,sp);OnRev(f,fp) #define turn_sb OnRev(s,sp);OnFwd(f,fp) と定義してあるので、fとsに代入してある値によってタイヤの回転方向を制御しています。 次にcurveルーチンです。 sub curve() { fp = 40; sp = 35; if(Curve_f > 3) TurnResult = s; if(Curve_s > 3) TurnResult = f; if(Curve_s > 3 || Curve_f >3) fp = 50; sp = 45; } これによって連続で同じ方向へ曲がる動作をさせています。3回同じ方向に黒線を検出できたらTurenresultの値を強制して書き換えることで動作させています。 spとfpは変数でモータの出力を決めています。カーブモード時には値を上げてカーブでの走行をなめらかにしています。 fixルーチン sub fix() { if(TurnTime == 1500) { PlaySound(SOUND_UP); back; Wait(1000); turn_fa; until(SENSOR_1 < black); TurnLevel = 0; } } コースから外れすぎた時のための処置です。バックしてまた黒線を探し始めます。 ***11月4日 [#i19242bd] 空き缶をどかして元の位置に戻す処理を新しく追加しました。相方の書いたプログラムです。 sub catch_can() { while(SensorUS(S2) <= 20) { RotateMotorEx(OUT_AB,speed_ab,100,0,true,true); //掴む位置まで移動 ARM1; //缶を掴む Off(OUT_C); Wait(500); RotateMotorEx(OUT_AB,speed_ab,600,0,true,true); //回頭位置まで移動 RotateMotorEx(OUT_AB,speed_ab,410,100,true,true); //180度回頭 ARM2; //缶を離す Off(OUT_C); Wait(500); RotateMotorEx(OUT_AB,-speed_ab,300,0,true,true); //缶から離れる RotateMotorEx(OUT_AB,speed_ab,410,100,true,true); //回頭して前を向く } } 詳細は http://yakushi.shinshu-u.ac.jp/robotics/?2013b%2FMember%2FRedcicudu%2FMission1 にあります。 以下のように超音波センサの値を缶を掴んで元の位置に戻す処理のスイッチにしています。 task main() { while(true) { SetSensorLight(S1); SetSensorLowspeed(S2); if(SensorUS(S2) > 20) // 障害物が20cm以内にないとき {lt();} else if(SensorUS(S2) <= 20) // 障害物が20cm以内にあるとき {catch_can();} } } ***まとめ [#q5642c1f] ~ライントレースに関しては、なんか妙にねらったのとは違う動きをするけど、うまくいったので満足している。普通のコースはだいたい上手く走れると思う。交差点処理が無いという点で面白いものが出来たと自分の中では思っている。ただ交差点を検出することが出来ないので、課題によっては難しかったり不利になったりするかもしれない。他と比べて無駄な動きも多い。 ~コードに関しては少なくて見やすい様に心掛けた。ただ初心者の自分には変数の動きを追うのが難しい書き方になってしまったと思う。実際想定外の動きをしてしまっているがどこが原因なのか今でも分からない。 **感想・反省など [#pc070408] ・コード書くのは楽しいけど修正作業がつらい ・自分の頭の中の構想と自分が書いたコードが一致してないのでうまく動かなくて作業がはかどらない。 ・相方は神 *コメント [#raad2c5f] どんなことでも良いので皆さん是非書いてくださいね(^ω^) - ううぇーい -- [[ぴあのまん]] &new{2013-12-06 (金) 02:24:57}; #comment