[[2013b/Member]] #contents *メンバー紹介 [#g1ae963c] **chikuwa [#ja65a7a5] このページの執筆者。その辺に転がってる普通の大学生。謎のプログラムを書く。~ chikuwaの前回の課題ページはこちら~ [[2013b/Member/chikuwa/Mission1]] **Pianoman [#x9575e2d] 主にプログラム担当。Macを自由自在に操り、華麗にプログラムを打ち込んでいく。~ 簡潔で無駄のないプログラムを書く技術に定評がある。~ Pianoman氏の今回の課題のページはこちら~ [[2013b/Member/Pianoman/Mssion2]] **Redcicudu [#jbf12d61] 主にハード担当。ロボットの半分は彼の優しさでできています。~ 尚、ロボットの作成や練習には彼の部屋を度々使用させてもらった。本当にありがたいことである。~ Redcicudu氏の今回の課題のページはこちら~ [[2013b/Member/Redcicudu/Mission2]] *はじめに [#ha42c211] 前回の失敗を踏まえ、今回はクリアしなければいけない課題を細かく分けてひとつずつクリアさせ~ 最終的にそれらを統合して課題の解決を目指す。 具体的には今回の課題の難点は次のように分類できる。 ・ライントレース ・缶の発見 ・缶の積み上げ ・缶を積んだ状態での移動 ・2つのNXTの連携 まずはこれらを一つずつつぶしていく。 *ロボットの制作 [#u1e286d7] **大まかな指針 [#z62c2ee3] ***まず缶をどのように積むか?~ [#zdbc83cb] →クレーン式?フォークリフト式?アームの上げ下げ式?2台に分けて作業分担?~ 結論:アームの上げ下げ式。因みにアームは水平移動しない。~ 理由:いろいろと試した結果、ほかの方法ではパーツが足りない。また缶を掴む際にしっかり掴めない。~ ***主に使う部品~ [#ld4fdd44] モーター数:4つ~ (タイヤ:2つ、缶の上げ下げ:1つ、缶を掴む,離す:1つ) NXT本体:2つ(←モーターを4つ使うため) 用いるセンサ:光センサ、超音波センサ~ (光センサ⇀ライントレースに使用、超音波センサ⇀缶の発見に使用) **試作機 [#y7066b49] 1/12頃に作成 &ref(2013b/Member/chikuwa/Mission2/試作機.jpg,70%,試作機); ↑NXTが不安定なうえに、前が重くなりがち...~ この頃はドライブベースはchikuwa、アームの上げ下げ部はRedcicudu氏、~ (写っていないが)アームのキャッチ部はPianoman氏が担当している。~ &ref(2013b/Member/chikuwa/Mission2/ball.jpg,30%,ball); ↑こんな風に後輪の代わりにボールを使う方法も最初は考えていた。~ しかしボールを転がすというより引きずる感じになってしまったので、この案は却下となった。~ ***問題点 [#qf0ecd9e] 上図ではまだアームの掴む部分をつけていないが、もしこの状態でそれをつけると重みで本体が前に傾く可能性がある。~ また中央部がスカスカなのでもう一台NXTをつけると重みで機体が沈む。 ***改善 [#ja4a9a5a] そこで土台の隙間をさらにうめて、NXTを倒した状態で2つくっつけてみた。~ 重心を前回より後方にすることで安定度が向上するようにしてみた。 そして次のような完成品が出来上がった。 **完成品 [#vce5cfa4] Φ全体 &ref(2013b/Member/chikuwa/Mission2/完成品.jpg,70%,完成品); ↑アームをつけた状態で前に倒しても前のめりになることは無かった。~ 超音波センサは縦に取り付けた方が感度が正確になるらしので、縦に取り付けてみた。~ ちなみに、主な製作者はRedcicudu氏である。~ NXT本体2つは通信させながら使用する。~ 役割分担としては~ Masater側がタイヤ、光センサ、超音波センサを司り、~ Slave側が缶のキャッチ、上げ下げを司る。 Φ後部 &ref(2013b/Member/chikuwa/Mission2/後ろ.jpg,50%,後ろ); ↑赤丸で示したように小さなタイヤ二つをつけた。これはきちんと360°回転する。~ 四輪駆動も試してみたが、カーブが曲がり切れなかったため最終的にこの方法を採用した。~ 試しに動かしてみたところ、ゆっくりではあるがきちんと機体は一回転した。 Φアーム部 &ref(2013b/Member/chikuwa/Mission2/アーム部.jpg,50%,アーム部); &ref(2013b/Member/chikuwa/Mission2/アーム部の正面.jpg,50%,アーム部の正面); ↑初めは、キャッチしても缶の重みでアームをすり抜けてしまうことが多かったが、~ ゴムをつけると安定して掴めるようになった。 *缶を積む動作 [#t3bcde97] **まずはアームだけで非常に簡単な動作を [#f1901ba7] 最初は二台のNXTの通信がうまく行くかどうか確かめる目的も兼ねて、~ アームを動かす練習をしてみる。 とりあえずは アームを下ろす→前進→缶をキャッチ→アームを上げる という非常に単純な動作をさせてみる。 アームを下ろしたあと機体を前進させたのは、機体と缶の間にできる隙間をなくすためである。 また予め、モーターの角度を測るプログラムを用いてアームの上げ下げ、缶のキャッチ・リリースに~ 必要な角度を計算しておき、命令"RotateMotor"を用いてみた。 ***ソースコード [#b3c744af] ✡マスター(M)側 #define CONN 1 #define SIGNALON 11 task main() { RotateMotor(OUT_B,75,4270);//アームを下げる SendRemoteNumber(CONN,MAILBOX1,SIGNALON); /*Sのメールボックス1にSIGNALON(1)を送信*/ Off(OUT_AB);Wait(3000);//3秒間待機 RotateMotor(OUT_A,85,-110);//缶をキャッチ RotateMotor(OUT_B,75,-4270);//アームを上げる } ✡スレイブ(S)側 #define SIGNALON 11 task main() { int msg; while(true){ ReceiveRemoteNumber(MAILBOX1,true,msg); /*Mからメールボックス1にメッセージを受信*/ if(msg==SIGNALON){//もし受け取ったメッセージがSIGNALON(11)なら OnFwd(OUT_AB,60);Wait(1000);//1秒前進 }else{//そうでないなら Off(OUT_AB);//停止 } } } ***結果 [#ee77c618] うん。きちんと通信して、プログラム通りに動いてくれた。~ 通信がうまく行ったようだ。~ Δ下ろし中~ &ref(2013b/Member/chikuwa/Mission2/下ろし中_加工済み.png,30%,下ろし中_加工済み); モーター回転部(黄色の丸)は、おおよそ赤色で示したような軌跡を描く。~ Δ下ろし終わり~ &ref(2013b/Member/chikuwa/Mission2/下ろし終わり_加工済み.png,30%,下ろし終わり_加工済み); 赤丸で示したようにこのままだと隙間ができてしまう。~ Δ前進~ &ref(2013b/Member/chikuwa/Mission2/前進します_加工済み.png,30%,前進します_加工済み); 隙間を埋めるため少しだけ前進。~ Δキャッチ~ &ref(2013b/Member/chikuwa/Mission2/キャッチします.PNG,30%,キャッチします); 離さない様かなり強めの出力でキャッチ。~ Δ上げ終わり &ref(2013b/Member/chikuwa/Mission2/上げ終わりました.PNG,30%,上げ終わりました); ずり落ちることもなく、缶は上部へ~ ***わかった事 [#k56bf0ae] ・"RotateMotor"がとても便利、モーターの出力を変えるたびに、~ わざわざ動かす時間を変更しなくても良い。 ・モーターに直接ギアをつけるのではなく、いくつか歯車を経由してるので、~ 動きが意外と遅かった。 ・二台の通信に少し時間がかかる。 ここまでは1/18(土)までに終わらせた。 **次に超音波センサを用いて... [#cb057c59] 次は超音波センサの有効範囲確認のため、そしてスレイブ側からマスター側に値を送る練習のため、 前進→缶を発見→アームを下ろす→前進→缶を掴む→缶を上げる→前進 という前回より少しだけ手間のかかる動作を出来るようにする。~ 計4回も通信するので少し不安だが、テキストを参考に見様見真似で作ってみた。 計4回の内訳は~ M側からS側へ・・・2回~ S側からM側へ・・・2回~ 各NXTが出す指令をまとめると次のようになる。 &ref(2013b/Member/chikuwa/Mission2/flowchart.PNG,55%,flowchart); ***ソースコード [#nf18e47f] ✡マスター側 #define CONN 1 #define SIGNAL_A 11 #define SIGNAL_B 12 #define SIGNAL_C 13 #define SIGNAL_D 14 #define go_forward OnFwd(OUT_AB,60); task main() { SetSensorLowspeed(S1);//超音波センサーを用意 int msg; int msg_2;//スレイブから送られた値を格納する関数 go_forward; if(SensorUS(S4)<10){//もし10センチ以内に缶を発見したら SendRemoteNumber(CONN,MAILBOX1,SIGNAL_A); /*Sのメールボックス1にSIGNAL_Aを送信*/ ReceiveRemoteNumber(MAILBOX2,true,msg); /*Sからメールボックス2にメッセージを受信*/ if(msg==SIGNAL_B){ //もしSIGNAL_Bを受信したら OnFwd(OUT_AB,60);Wait(1000);//1秒間前進 SendRemoteNumber(CONN,MAILBOX3,SIGNAL_C); /*Sのメールボックス3にメッセージを送信*/ ReceiveRemoteNumber(MAILBOX4,true,msg_2); /*Sからメールボックス4にメッセージを受信*/ if(msg_2==SIGNAL_D){//もしメッセージがSIGNAL_Dなら go_forward;Wait(2000);//2秒前進 } } } } ✡スレイブ側 #define CONN 1 #define SIGNAL_A 11 #define SIGNAL_B 12 #define SIGNAL_C 13 #define SIGNAL_D 14 task main() { int msg; int msg_2; ReceiveRemoteNumber(MAILBOX1,true,msg); /*Mからメールボックス1にメッセージを受信*/ if(msg==SIGNAL_A){//もしメッセージがSIGNAL_Aなら RotateMotor(OUT_B,75,4270);//アームを下ろす SendResponseNumber(MAILBOX2,SIGNAL_B); /*Mのメールボックス2にSIGNAL_Bを送信*/ Off(OUT_AB);Wait(1000);//1秒間待機 ReceiveRemoteNumber(MAILBOX3,true,msg_2); /*Mからメールボックス3にメッセージを受信*/ if(msg_2==SIGNAL_C){//もしメッセージがSIGNAL_Cなら RotateMotor(OUT_A,85,-110);//缶を掴む RotateMotor(OUT_B,75,-4270);//アームを上げる SendResponseNumber(MAILBOX4,SIGNAL_D); /*Mのメールボックス4にSIGNAL_Dを送信*/ } } } ***結果(その1) [#s68379b6] 進む→缶を見つける までは良かったのだがその後、進みながらアームを下ろし、缶をつかめなかった。~ 更に自分のアームを缶だと勘違いし、さらにアームを下ろそうとしたのでこれはまずいと思い、~ そこでストップさせた。 ***考察 [#p4794545] それぞれの、相手のNXTに値を送る命令"SendRemoteNumber","SendResponseNumber"~ の時間を設定していなかったので、送るタイミング,受け取るタイミングがバラバラになってしまい~ 最初のM→Sの通信一回しかできなかった。結局それぞれ独立してプログラムを実行してしまった。~ ***その他のトラブル [#gc75130f] その後少しプログラムをいじったのだが、何度やってもS側からM側に命令が送れなかった。~ このままだと埒があかないので再びピアサポートセンターへ...(授業の関係で、Redcicudu氏~ に頼む形となってしまった。非常に面目ない。)~ ***改善 [#se7c0557] "while(true)"を用いて、常に相手のNXTから命令を受け取るようにしてみた。~ また、"SendRemote/ResponseMessage"の数を減らした。~ そこで出来上がったのが、次のプログラム。~ ***ソースコード(その2) [#gee1e52a] ✡マスター側 #define CONN 1 #define SIGNAL_A 11 #define SIGNAL_B 12 #define SIGNAL_C 13 #define SIGNAL_D 14 #define go_forward OnFwd(OUT_AB,60);//出力60%で前進 task main() { SetSensorLowspeed(S4); int msg; int msg_2; int hakken=0;//←缶を発見した回数をカウントする関数 while(hakken==0){//hakkenが0の時 go_forward; if(SensorUS(S4)<=20){//もし20センチ以内に缶を発見したら hakken++;//hakkenをカウントする SendRemoteNumber(CONN,MAILBOX1,SIGNAL_A); /*SのメールボックスにSIGNAL_Aを送信(これにより、S側でアームを下ろす)*/ PlaySound(SOUND_UP);//目印として音を鳴らす } } /*ここでhakkenの値が1になっているので、次の"while(hakken==1)"に移項*/ while(hakken==1){//hakkenの値が1の時 ReceiveRemoteNumber(MAILBOX2,true,msg); /*Sからメールボックス2にメッセージを受信する*/ if(msg==SIGNAL_B){//もしSIGNAL_Bを受信したら OnFwd(OUT_AB,60);Wait(1000);//1秒間前進(←隙間を埋めるため) SendRemoteNumber(CONN,MAILBOX3,SIGNAL_C); /*Sのメールボックス3にメッセージを送信(これによりS側で缶をつかみ、アームを上げる)*/ Off(OUT_AB);//機体停止 } if(msg==SIGNAL_D){//もしSIGNAL_Dを受信したら go_forward;Wait(2000);//2秒前進 Off(OUT_AB); Wait(5000);//5秒待機 } Wait(100);//0.1秒に一回受信する }//while(hakken==1) }//task main ✡スレイブ側 #define CONN 1 #define SIGNAL_A 11 #define SIGNAL_B 12 #define SIGNAL_C 13 #define SIGNAL_D 14 task main() { while(true){ int msg; ReceiveRemoteNumber(MAILBOX1,true,msg); /*Mからメールボックス1にメッセージを受信*/ if(msg==SIGNAL_A){//もしメッセージがSIGNAL_Aなら RotateMotor(OUT_B,75,4100);//アームを下ろす SendResponseNumber(MAILBOX2,SIGNAL_B); /*MのメールボックスにSIGNAL_Bを送信*/ } if(msg==SIGNAL_C){//もしメッセージがSIGNAL_Cなら RotateMotor(OUT_A,85,-110);//缶を掴む RotateMotor(OUT_B,75,-4100);//アームを上げる SendResponseNumber(MAILBOX4,SIGNAL_D); /*MのメールボックスにSIGNAL_Dを送信*/ } }//while(true) }//task main ***結果(その2) [#pc77be68] う〜ん、うまく行かない...~ 何度やっても、S側からM側へ値が送れない...~ 困った。~ ***改善案(その2) [#m65b569f] もうこの際、S側からM側へ命令を送るのは諦めて、M側からS側へ送るだけにしてみる。~ 具体的には、MがSへ命令を送ったあとに待機させておく。 そして次のようなプログラムができた。~ なお、これは缶を発見したら一回上へ持って行き、後はひたすら見つけた缶を2個、3個、4個...~ と積んでいくプログラムである。 ***ソースコード(その3) [#eab3658f] ✡マスター側 #define CONN 1 #define SIGNAL_A 11 #define SIGNAL_B 12 #define SIGNAL_C 13 #define SIGNAL_D 14 #define go_forward OnFwd(OUT_AB,60); task main() { SetSensorLowspeed(S4); int hakken=0;//発見した回数 while(hakken==0){ go_forward; if(SensorUS(S4)<=8){//もし8センチ以内に缶を発見したら SendRemoteNumber(CONN,MAILBOX1,SIGNAL_A); /*SのメールボックスにSIGNAL_Aを送信*/ Off(OUT_AB);Wait(22000); /*22秒停止(この間アームが下りて缶をキャッチ、そしてアームを上げる)*/ hakken++;//hakkenをカウントする }//(if_20) }//while(hakken==0) /*hakkenの値が1となり次のwhile(hakken==1)に移行*/ while(hakken==1){//hakken=1の時 go_forward; if(SensorUS(S4)<=7){//もし7センチ以内に缶を発見したら SendRemoteNumber(CONN,MAILBOX1,SIGNAL_B); /*Sのメールボックス1にSIGNAL_Bを送信*/ Off(OUT_AB);Wait(9000); /*9秒待機(この間に缶を載せ、缶を離し、アームを上に)*/ OnRev(OUT_AB,60);Wait(700);//0.7秒バック SendRemoteNumber(CONN,MAILBOX1,SIGNAL_A); /*Sのメールボックス1にSIGNAL_Aを送信(再び缶を掴み、上部へ)*/ Off(OUT_AB);Wait(20000); /*20秒待機(この間に再びS側が缶を掴み上部へ)*/ }//(if_25) }//while(hakken==1) }//task ✡スレイブ側 #define CONN 1 #define SIGNAL_A 11 #define SIGNAL_B 12 #define SIGNAL_C 13 #define SIGNAL_D 14 task main() { while(true){ int msg; ReceiveRemoteNumber(MAILBOX1,true,msg); /*Mからメールボックス1にメッセージを受信*/ if(msg==SIGNAL_A){//もしメッセージがSIGNAL_Aなら RotateMotor(OUT_B,65,4300);//アームを下ろす OnRev(OUT_A,63);Wait(900);//缶を掴む RotateMotor(OUT_B,65,-4300);//アームを一番上まで上げる }//if(msg==SIGNAL_A) if(msg==SIGNAL_B){//もしメッセージがSIGNAL_Bなら RotateMotor(OUT_B,75,1400);//缶を載せる RotateMotor(OUT_A,30,170);//缶を離す RotateMotor(OUT_B,75,-1400);//アームを一番上まで上げる }//if(msg==SIGNAL_B) }//while(true) }//task main **最新プログラム [#ib35f3c5] ✡マスター側 #define CONN 1 #define SIGNAL_A 11 #define SIGNAL_B 12 #define SIGNAL_C 13 #define SIGNAL_D 14 #define SIGNAL_E 15 #define SIGNAL_F 16 #define SIGNAL_G 17 #define go_forward OnFwd(OUT_AB,50);//出力50%で前進 #include "koushin.nxc" task main() { SetSensorLowspeed(S4); int hakken=0;//発見した回数をカウント while(hakken==0){ go_forward; if(SensorUS(S4)<=12){//もし12センチ以内に缶を発見したら SendRemoteNumber(CONN,MAILBOX1,SIGNAL_A); /*Sのメールボックス1にSIGNAL_Aを送信*/ Off(OUT_AB); /*停止(この間アームが下りて缶をキャッチ、そしてアームを上げる)*/ receive(MAILBOX2,"SIGNAL_C");//Sからメールボック2にSIGNAL_Cを受信 go_forward;Wait(500);Off(OUT_AB);//0.5秒前進 sendmsg(CONN,MAILBOX1,MAILBOX2,"SIGNAL_D","SIGNAL_E"); /*Sのメールボックス1にSIGNAL_Dを送信*/ hakken++;//hakkeをカウント }//(if_12) }//while(hakken==0) /*hakkenの値が1となり次のwhile(hakken==1)に移行*/ while(hakken==1,2,3){//hakken=1,2,3の時 TextOut(0,LCD_LINE2,"while(hakken==1,2,3)"); go_forward; if(SensorUS(S4)<=8){//もし8センチ以内に缶を発見したら SendRemoteNumber(CONN,MAILBOX1,SIGNAL_B); /*Sのメールボックス1にSIGNAL_Bを送信*/ Off(OUT_AB);//モータAB停止 receive(MAILBOX2,"SIGNAL_F");//Sからメールボックス2にSIGNAL_Fを受信 OnRev(OUT_AB,50);Wait(1500);//1.5秒後退 Off(OUT_AB);//モータAB停止 SendRemoteNumber(CONN,MAILBOX1,SIGNAL_A); /*Sのメールボックス1にSIGNAL_Aを送信(再び缶を掴み、上部へ)*/ Off(OUT_AB);//モータAB停止 receive(MAILBOX2,"SIGNAL_C");//Sからメールボックス2にSIGNAL_Cを受信 OnFwd(OUT_AB,40);Wait(1000);//1秒前進 Off(OUT_AB);Wait(3000);//3秒停止 sendmsg(CONN,MAILBOX1,MAILBOX2,"SIGNAL_D","SIGNAL_E"); /*Sのメールボックス1にSIGNALDを送信*/ hakken++;//hakkenをカウント }//(if_9) }//while(hakken==1,2,3) /*hakkenの値が4になり、次のwhile(hakken==4)に移行*/ while(hakken==4){//hakken==4の時 TextOut(0,LCD_LINE2,"while(hakken==4):"); Off(OUT_AB);//モータAB停止 SendRemoteNumber(CONN,MAILBOX1,SIGNAL_G); /*Sのメールボックス1にSIGNAL_Gを送信*/ hakken++;//hakkenをカウント }//while(hakken==2) }//task ✡スレイブ側 #define CONN 1 #define SIGNAL_A 11 #define SIGNAL_B 12 #define SIGNAL_C 13 #define SIGNAL_D 14 #define SIGNAL_E 15 #define SIGNAL_F 16 #define SIGNAL_G 17 #include "koushin.nxc" task main() { while(true){ int msg; ReceiveRemoteNumber(MAILBOX1,true,msg); /*Mからメールボックス1にメッセージを受信*/ if(msg==SIGNAL_A){//もしメッセージがSIGNAL_Aなら RotateMotor(OUT_B,65,4300);//アームを下ろす respond(MAILBOX2,"SIGNAL_C");//Mのメールボックス2にSIGNAL_Cを送信 PlaySound(SOUND_UP);//音を鳴らす(UP) receive(MAILBOX1,"SIGNAL_D");//Mからメールボックス1にSIGNAL_Dを受信 PlaySound(SOUND_DOWN);//音を鳴らす(DOWN) Off(OUT_AB);Wait(2000);//2秒待機 RotateMotor(OUT_A,50,-180);//缶を掴む Off(OUT_A);//モータAを停止 RotateMotor(OUT_B,65,-4300);//アームを一番上まで上げる respond(MAILBOX2,"SIGNAL_E");//Mのメールボックス2にSIGNAL_Eを送信 }//if(msg==SIGNAL_A) if(msg==SIGNAL_B){//もしメッセージがSIGNAL_Bなら RotateMotor(OUT_B,60,1350);//缶を載せる RotateMotor(OUT_A,30,170);//缶を離す RotateMotor(OUT_B,60,-1350);//アームを一番上まで上げる respond(MAILBOX2,"SIGNAL_F");//Mのメールボックス2にSIGNAL_Fを送信 }//if(msg==SIGNAL_B) if(msg==SIGNAL_G){//もしメッセージがSIGNAL_Gなら RotateMotor(OUT_B,60,4300);//アームを動かし、缶を地面まで下ろす RotateMotor(OUT_A,30,170);//缶を離す RotateMotor(OUT_B,60,-4300);//アームを一番上へ上げる }//if(msg==SIGNAL_G) }//while(true) }//task main **トラブル発生? [#pec92f86] NXTに文法は合っているのにプログラムが送れないとうい事態が発生!!!~ ピアサポートセンターに行って直接先生にお聞きしてみたところ、NXTの容量がいっぱいになっているとご指摘いただきました。~ どうせもう使わないだろうし、一応USBにプログラムは入っているのでデータすべて削除!~ 改めて送信してみると...ピッ。~ ちゃんと遅れました。一安心です。(1/20(月)) *缶をどうやって見つけるか? [#g7b05218] *ライントレースはどうする? [#k30a9f9a] *それぞれの動きを一つのプログラムに [#k9b438c5] *作戦 [#he6efb51] **ルート決め [#o108ae07] **狙う缶はお前だ! [#g0c1bf86] *プログラム、ハードの再確認 [#u9170ed6] *リハーサル [#e20b40a7] *忍びくる魔の手 [#y120fa93] *心を一つに [#c48c4f12] *そして本番へ [#i4d35266] *天国か地獄か [#v48459b0] *全体を振り返って [#eb8f9122]