今回の課題は、 &br;「半径1m以内にある空き缶を探して、25cmの距離からボールを転がしてその空き缶に当てるロボットを製作しなさい。ただし25cm以内に空き缶がある場合には、30cmまで離れること。」である。 結果を述べた後、解説を加えていく。 #Contents *結果 [#s6d27242] **目標の達成度 [#w9b64a9a] 無事に成功した。 **ロボットの画像 [#o4181f65] 注)これらの画像は時計回りに90度回転させて見てほしい。決して壁に張り付いているわけではない。 &ref(2015a/Member/ko-rusuro-/Mission3/kadai3-3.jpg,25%,zoom); &ref(2015a/Member/ko-rusuro-/Mission3/kadai3-1.jpg,25%,zoom); &ref(2015a/Member/ko-rusuro-/Mission3/kadai3-2.jpg,25%,zoom); 前についてある超音波センサーで缶との距離を測定している。モーターAでマシーンの一番高いところについてあるモーターを回して、二つの棒の間でボールを転がして射出する。モーターB,Cはマシーンの車輪に使用した。 **作成時間 [#x270801d] +マシーンの組み立て・・・10分 +プログラムの作成・・・2時間半 +レポートの作成・・・4時間 マシーンは大体完成していたのでどの端子がどのモーターについているかの確認と、超音波センサーの端子の変更だけで作業を終えた。そのため時間がここまで短縮された。 **プログラム [#afd28acb] 先生が配布した紙に書いてあったプログラムをオマージュして作り上げたので説明する必要があるかどうか分からないが、理解した範囲で説明をする。 ***定義と変数値の確定 [#l9a215e4] #define SPEED 50 #define SPEED_SLOW 30 const float diameter = 5.45; //タイヤの直径(cm) const float track = 12; //タイヤのトレッド幅(cm) const float pi = 3.1415; //円周率 ***サブルーチン [#h3a378d3] -d(cm)前進するプログラム void fwdDist(float d){ //距離d(cm)前進 long angle; angle = d/(diameter*pi)*360.0; //角度を計算する RotateMotorEx(OUT_BC, SPEED_SLOW, angle, 0, true, true); } このプログラムは進みたい距離を設定するだけで、プログラムが回転させるべきタイヤの回転角度を計算して電池の残量に依らず一定の距離を進むことが出来る。 -旋回するプログラム void turnAng(long ang){ // 角度ang度の時計回りの旋回 long angle; angle = track/diameter * ang; RotateMotorEx(OUT_BC, SPEED_SLOW, angle, 100, true, true); } このプログラムも回転したい角度を設定するだけで旋回を始めるプログラムである。 -缶を探して、缶の方向を向き、缶までの距離の値を返すプログラム このプログラムは他のプログラムと比べて長いので細かく説明を挟んでいく int searchDirection(long ang){ //現在の方向を中心にang度の範囲で探し //障害物までの距離を返す long angle, tacho_min=0, tacho_corr; int d_min; d_min=300; //仮の最小値 ここまででlong型の変数値が三つ,int型の変数値が一つ用意された。また、ここの"d_min"はマシーンと障害物の距離で、ここでは缶とマシーンの距離の値が最終的に代入される。初めから"d_min"が300と置かれたのは最小の値が100以内であると分かっていて、100以上の値を設定することが必要であるからである。 angle = (track/diameter)*ang; //旋回角度からタイヤの回転を計算 turnAng(ang/2); //指定された角度の半分を旋回 ResetTachoCount(OUT_BC); //角度計測をリセット OnFwdSync(OUT_BC,SPEED_SLOW,-100); while(MotorTachoCount(OUT_B)<=angle){ if(SensorUS(S1)<d_min){ d_min=SensorUS(S1); //仮の最小値を更新 tacho_min=MotorTachoCount(OUT_B); } } ここのマシーンの動きは、初めに設定したマシーンの回転角度の半分を旋回し、その後設定した分だけマシーンが逆に旋回する動きを始めるというものである。その間マシーンは障害物との最小の距離を更新し続け、その時までに回転したタイヤの角度も記録する。 OnFwdSyncEx(OUT_BC,SPEED_SLOW,100,RESET_NONE); until(MotorTachoCount(OUT_B)<=tacho_min||SensorUS(S1)<=d_min); Wait(14); //微調整 Off(OUT_BC);Wait(500); return d_min; //ここで値を返す } 上から二行目のプログラムは一番近い障害物の方を向くまで旋回を続けるというものです。条件が二つあるのは正確性を重視したもので、タイヤの回転角度と障害物との距離のどちらかが先ほどのプログラムで更新した回転角度または距離を下回ることで止まる二段構えの制御構文となっています。&br;最後に"return d_min;"で一番近い障害物との距離をメインプログラムに返して終了します。 ***メインプログラム [#k2d82e57] task main(){ SetSensorLowspeed(S1); // 缶の方向を探したあと、近づいて10cm手前で停止 int d = searchDirection(360); if (d > 25) { fwdDist(d-25.0); } RotateMotor(OUT_A,30,150); } 上で説明を加えたものに球を射出するプログラムを付け足したものです。缶との距離が25cm以上ならばそこまで近づき球を射出するようになっています。 *考察と感想 [#kb4fc5ae] プリントを配られた後、なかなかプログラムが理解できずに困った。"int"からはじまるプログラムでなぜ動き出してしまうのか、"return d_min;"このプログラムは何を意味するのか、そもそもトレッド幅はどこなのか、など様々な疑問が出てきた。 疑問を少しずつ解消していくのは時間が掛かるが、有意義な時間を過ごせたと思う。