[[2014a/MemberOnly/進行状況]] 目次 #contents #contents *今回の課題 [#l61f0491] 紙コップ収集、分別ロボット 詳しくは課題2を参考にしてください。 http://yakushi.shinshu-u.ac.jp/robotics/?2014a%2FMission2#p66feff7 http://yakushi.shinshu-u.ac.jp/robotics/?2014a%2FMission2#p66feff7 *メンバー [#bf535eab] hodaka:農学部なのにこのとても情報系な授業をとってしまった人。このページの執筆者。ほとんど役に立つことができず、チームに迷惑をかけてばかりだった。 saborijini:我が班のエース。彼がいなければこの班の発表はとんでもないことになっていただろう。ソフト、ハードの両方でかなり活躍した。 snowdrop:この授業をとっていた2人の女の子の一人。一つひとつのパーツが正常に動作するかの簡単なチェックを行うプログラムなどを組んだ。 bosso:コップを持ち上げるアームについて様々なアイデアを生み出した。 *ロボット本体について [#e18ceba0] ロボットの本体を考えるとき最初に参考にしたのは2013年後期の空き缶積み上げロボである。 しかし、多くが上に大きくなっており、重量オーバーにってしまい、移動に向かないと判断した。 さらに、アルミ缶は丈夫だが、紙コップは簡単に変形してしまう。 そこでつかむためのモーターを持ち上げるためのモーターで持ち上げることにした。 しかし、一個のモーターの出力は大きくなく、持ち上げることができなかったため、輪ゴムの補助を付けた。 これでモーターをモーターで持ち上げるアームが完成した。 http://yakushi.shinshu-u.ac.jp/robotics/?plugin=ref&page=2014a%2FMember%2Fsaborijini%2FMission2&src=IMG_0245.JPG ↑アームを上げた状態。これで移動する。 http://yakushi.shinshu-u.ac.jp/robotics/?plugin=ref&page=2014a%2FMember%2Fsaborijini%2FMission2&src=IMG_0248.JPG ↑このようにコップをつかむ。 次に問題となったのは紙コップの識別である。そこで、赤外線センサーと光センサーを紙コップの識別に用いた。 http://yakushi.shinshu-u.ac.jp/robotics/?plugin=ref&page=2014a%2FMember%2Fsaborijini%2FMission2&src=IMG_0244.JPG ↑超音波センサー。これで紙コップまでの距離を測定できる。 移動はライントレースを行わず、用紙のライントレース用の黒線を目印に、ロボに自分の位置を確認させ、次の動きを行うようにさせた。 http://yakushi.shinshu-u.ac.jp/robotics/?plugin=ref&page=2014a%2FMember%2Fsaborijini%2FMission2&src=IMG_0243.JPG ↑自身の位置を確認するための光センサー。 *プログラムについて [#o7bc46f1] saborijiniのページを参考にしていただきたい。 http://yakushi.shinshu-u.ac.jp/robotics/?2014a%2FMember%2Fsaborijini%2FMission2#w0ae5ed8 **親機のプログラム [#b1f9e184] #define black 36 #define speed 35 #define A 38 #define B 65 定数の定義をしています。電池の種類・消耗次第でスピードが、照明次第でセンサーの感度が変わってくるのでよく調整する数値は代わりとなる文字に置き換えて作業を効率良くしています。 上から順に黒線と白紙の境界値・ロボットの移動速度(モーターの速度)・黒コップと茶コップの境界値・茶コップと白コップの境界値を定義しています。 task main() { SetSensorLight(S1); SetSensorLight(S4); SetSensorLowspeed(S3); センサーの定義をしています。1にはライントレース用の光センサー、3にはコップ認識用の光センサー、4にはコップとの距離認識用の光センサーをつないだことを示しています。2には配線するのが困難であったため使っていません。 int msg; msgという変数を用いることを示しています。これは後で使います。 until(BluetoothStatus(1) == NO_ERR); RemotePlayTone(1,440,1000); 子機との通信が出来ているか確認して上手くいっているとピーっと音を鳴らすようにしています。実行前にセッティングは済ませていましたが、念のため組み込むました。もし通信が切れていたらロボットはこれ以降の動作を実行しません。個人的にはロボットの起動音みたいで気に入っています。 Off(OUT_BC); Wait(1200); ピーっと鳴らしている間はロボットは止まっているようにして、すぐには動き出しません。急に動き出すと、起動ボタンは下の親機にあるため指が引っかかる可能性があるからです。 OnFwdSync(OUT_BC,speed,0); until(SENSOR_1 < black); PlaySound(SOUND_CLICK); ここからロボットが動き出します。OnFwdSyncを用いて直進しています。モーター2つの力が等しいとは限らないので、2つを同期させることで真っ直ぐ進めるようになります。 また今回ロボットの移動にWait();を使うのを控えました。これは先にも述べたように電池の状態次第で移動時間を調節する必要があるからです。そこでuntilを用いて移動時間を決めました。「黒線に当たるまで」というようにしました。これならどんなスピードでも決まった距離を進めます。 Off(OUT_BC);Wait(500); OnFwdSync(OUT_BC,speed,0); Wait(400); PlaySound(SOUND_CLICK); スタート位置の黒線の枠を横断します Off(OUT_BC);Wait(500); OnFwdSync(OUT_BC,speed,0); until(SENSOR_1 < black); PlaySound(SOUND_CLICK); 次の黒線に当たるまで直進します Off(OUT_BC);Wait(500); OnFwdSync(OUT_BC,speed,0); Wait(500); PlaySound(SOUND_CLICK); 黒線の枠を横断します。ここでロボットは枠内に半分ほど入ります。 Off(OUT_BC);Wait(500); OnFwd(OUT_B,speed); OnRev(OUT_C,speed); until(SENSOR_1 < black); PlaySound(SOUND_CLICK); ロボットが黒線上にいる状態で方向転換(左へ旋回)します。この旋回を始めWait();を使い調節して動かそうとしていました。しかしいくら時間を費やしても成功せず、その上電池の消耗で安定しなくなりました。そこでここにもuntilを用いました。黒線に当たるまで旋回させると、ほぼ90度旋回に成功しました。 Off(OUT_BC);Wait(700); OnFwd(OUT_B,speed); OnRev(OUT_C,speed); Wait(180); PlaySound(SOUND_CLICK); 前の動作でほぼ旋回できているのでここでは微調整として少し旋回させています。1秒もしない時間ならWait();を使っても誤差は感じられません。 Off(OUT_BC);Wait(500); OnFwdSync(OUT_BC,speed,0); Wait(1100); PlaySound(SOUND_CLICK); 旋回が終わるとロボットは黒線の枠上にあるので光センサーを再び使うために黒線から出るくらいの距離を前進します。ここをuntilにしても良かったのですが、必ずしもロボットが黒線上にいるとは限らないので使っていません。 Off(OUT_BC);Wait(500); OnFwdSync(OUT_BC,speed,0); until(SENSOR_1 < black); PlaySound(SOUND_CLICK); Off(OUT_BC);Wait(500); OnFwdSync(OUT_BC,speed,0); Wait(500); PlaySound(SOUND_CLICK); Off(OUT_BC);Wait(500); OnFwdSync(OUT_BC,speed,0); until(SENSOR_1 < black); PlaySound(SOUND_CLICK); Off(OUT_BC);Wait(500); OnFwdSync(OUT_BC,speed,0); Wait(600); PlaySound(SOUND_CLICK); Off(OUT_BC);Wait(500); 図から分かるように旋回した地点からすると、コップは黒線2本目のところにあります。そのため黒線まで直進、横断を2回しています。 OnFwd(OUT_B,speed); OnRev(OUT_C,speed); until(SENSOR_1 < black); PlaySound(SOUND_CLICK); Off(OUT_BC);Wait(500); ここは前述の方向転換と同じです。これでコップがロボットの目の前にあるところまで来ました。 OnRevSync(OUT_BC,speed,0); Wait(2000); ここで一旦バックして下がります。あまりにもコップとの距離が近すぎるからです。 OnFwdSync(OUT_BC,speed,0); until(SensorUS(S3) <= 12); コップとの距離が12cm以下になるまで前進します。この12cmは別に練習プログラムを組んでベストな位置を測りました。 Off(OUT_BC); Wait(100); RemoteStartProgram(1,"z_slave.rxe"); ベストポジションに来たので親機からプログラム「z_slave.rxe」を子機に実行するように命令します。この命令を始め親機が子機に数字を送ってやろうとしていました。この場合、子機はifを用いてそれぞれの数字ごとの行動をプログラムしなければなりません。しかしプログラムを指定して子機にそれを起動させる通信方法はプログラミングする方にも作業が簡単になる利点があります。なのでその方法を採用しました。 while(msg != 11){ ReceiveRemoteNumber(MAILBOX1,true,msg); } PlaySound(SOUND_CLICK); 子機から「11」というメッセージが来るまで待ちます。このメッセージは子機が親機の命令を終えたことを知らせるために送ります。親機はMAILBOX1にメッセージを受け取り、それをmsgに置き換えます。trueは受け取ったらMAILBOX1を空にすることを示します。この後にもメッセージをもらうので空にさせました。始めはuntilを使って「11」が来るまで、をプログラムしました。しかし上手くいきませんでした。until()内の条件文が出来ていなかったからだと思います。ここではwhile(msg != 11)を採用しました。これはmsgが11でないならば受け取り続ける(待ち続ける)ことを示しています。whileまたはuntilで繰り返さないと、メッセージを受け取らなくてもプログラムが進んでしまいます。 ルールにあるようにコップはランダムに置かれます。コップはA1/B2/C3のよう対になっています。 if(SENSOR_4 < A){ OnFwdSync(OUT_BC,speed,0); until(SensorUS(S3) <= 18); Off(OUT_BC); Wait(100); RemoteStartProgram(1,"z_slave-2.rxe"); while(msg != 12){ ReceiveRemoteNumber(MAILBOX1,true,msg); } PlaySound(SOUND_CLICK); もしコップがAだとしたら1まで運ぶのでコップとの距離18cm以下になるまで前進して、親機がプログラム「z_slave2.rxe」を子機に起動させます。子機からのメッセージを受け取り次第ピッと鳴らして終了。2個目以降は戻って掴んで認識、重ねるを繰り返すつもりでした。 }else if(SENSOR_4 < B){ OnFwdSync(OUT_BC,speed,0); Wait(2000); PlaySound(SOUND_CLICK); Off(OUT_BC);Wait(500); OnFwd(OUT_B,speed); OnRev(OUT_C,speed); until(SensorUS(S3) < 18); PlaySound(SOUND_CLICK); Off(OUT_BC); Wait(100); RemoteStartProgram(1,"z_slave-2.rxe"); while(msg != 12){ ReceiveRemoteNumber(MAILBOX1,true,msg); } PlaySound(SOUND_CLICK); もしコップがBだとしたら超音波センサーでコップを認識するまで左に旋回、コップまで前進、以降はAの場合と同じです。 }else{ OnFwdSync(OUT_BC,speed,0); Wait(6000); OnFwd(OUT_B,speed); OnRev(OUT_C,speed); until(SensorUS(S3) < 30); PlaySound(SOUND_CLICK); Off(OUT_BC); Wait(100); OnFwdSync(OUT_BC,speed,0); until(SensorUS(S3) <= 18); Off(OUT_BC); Wait(100); RemoteStartProgram(1,"z_slave-2.rxe"); Off(OUT_BC); Wait(100); RemoteStartProgram(1,"z_slave-2.rxe"); while(msg != 12){ ReceiveRemoteNumber(MAILBOX1,true,msg); } PlaySound(SOUND_CLICK); } } もしコップがCだとしたらコップ3が真横に来るように前進、右に旋回、コップまで前進、以降はAの場合と同じです。 ↑ **スラーブ(子機)のプログラム [#m107801c] task main() { PlaySound(SOUND_CLICK); OnFwd(OUT_A,70);Wait(2800);Off(OUT_A); OnRev(OUT_C,20);Wait(800);Off(OUT_C); OnRev(OUT_A,60);Wait(2800);Off(OUT_A); SendResponseNumber(MAILBOX1,11); Wait(1000); PlaySound(SOUND_CLICK); } アームを下げて掴んでアームを上げます。そして親機にメッセージを送ります。 task main() { PlaySound(SOUND_CLICK); OnFwd(OUT_A,60);Wait(900);Off(OUT_A); OnFwd(OUT_C,20);Wait(700);Off(OUT_C); OnRev(OUT_A,80);Wait(1800);Off(OUT_A); SendResponseNumber(MAILBOX1,12); Wait(1000); PlaySound(SOUND_CLICK); } アームを下げて離してアームを上げます。そして親機にメッセージを送ります。 * 感想・反省 [#s098dcfb] 何よりも、全員で協力して作業する時間が圧倒的に足りなかったと思う。saborijiniはこのメンバーのなかでもとても活躍してくれて、本当に助かった。 結果は9チーム中4位という上位半分以上に入賞することができた。やはり、自分の力不足を痛感した。結果として、この講座は楽しく学ぶことができたと思う。