[[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%,アーム部の正面); ↑初めは、キャッチしても缶の重みでアームをすり抜けてしまうことが多かったが、~ ゴムをつけると安定して掴めるようになった。 *プログラムを書くにあたって [#g5ccd221] 上のメンバー紹介でも少し触れたが、ハードができた後は~ それぞれ担当のプログラムを割り振って、作業の効率化を図った。~ *缶を積む動作 [#t3bcde97] ・主にchikuwa担当 **まずはアームだけで非常に簡単な動作を [#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] そもそもメールボックスとはM側、S側にそれぞれ独立して存在しているのではなく~ 共有しあうものらしい。つまり、M側から命令を送る場合とS側から命令を送る場合でメールボックスを 使い分ける必要があるようだ。~ そこでPianoman氏がその点を考慮し、S側からも命令を送れる次のようなプログラムを作成して下さった。~ このプログラムのおかげで我々の使える技術は飛躍的に増加した。 ↓"koushin.nxc" /* sm.h */ /* 送信と確認 */ sub sendmsg(int conn,int mb1,int mb2,string msg,string rps) { SendRemoteString(conn,mb1,msg); string rmsg = ""; while(rmsg == "") { ReceiveRemoteString(mb2,true,rmsg); TextOut(0,LCD_LINE1,"Wait until slave /n completes tasks..."); Wait(1000); } } sub btcheck(int conn) { while(!BluetoothStatus(conn) == NO_ERR) { ResetScreen(); TextOut(0,LCD_LINE1,"Something wrong"); Wait(1000); } } sub receive(int mb1,string rd) { string msg; while(msg != rd) { ReceiveRemoteString(mb1,true,msg); ResetScreen(); TextOut(0,LCD_LINE1,"Receiving..."); Wait(1000); } ResetScreen(); TextOut(0,LCD_LINE1,"I got it!!"); Wait(1000); } sub respond(int mb2,string reply) { SendResponseString(mb2,reply); ResetScreen(); TextOut(0,LCD_LINE1,"Responded"); Wait(1000); } 実際にこれを使用するときは"koushin.nxc"という名前をつけて保存し~ includeを使用して呼び出した。これによりプログラムがすっきりした。 ***結果(その3) [#l2447b16] これのおかげで上のフローチャートで示したような、動きが可能になった。~ **缶を積んでいく [#ib35f3c5] さてそれでは次に缶を2,3,4と積んでいく動きをさせてみる。(因みに4個目を積み終わったら地面に下ろす)~ 1個目を掴んで持ち上げた後の、2〜4個目を積む動作は同じである。~ 具体的には2個目以降の缶を見つたら、 缶を載せる→アームを離す→アームを上に→後退→アームを最下部へ→缶を掴む→アームを上に という動きをひたすら繰り返させれば良い。~ そして出来上がったのが次のプログラム。今回から"koushin.nxc"は毎回使用した。 ✡マスター側 #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 *缶をどうやって見つけるか [#g2109a6d] ・主にPianoman氏担当 *近くにある3つの缶を積み上げるプログラム [#s84d665c] 上で紹介した、Pianoman氏の缶を見つけるプログラムと、chikuwaの缶を積み上げるプログラムを~ 合わせたプログラム。スタート地点付近にある3つの缶をまずはこのプログラムで積めるかどうか、~ 検証してみる。 ✡マスター側 #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" #define tr OnFwdSync(OUT_AB,60,100); #define tl OnFwdSync(OUT_AB,60,-100); #define go OnFwdSync(OUT_AB,75,0) #define unko 60 #define direction 13 #define measure_time 10 sub find_direction() {//缶を見つけるサブルーチン int takatyan; int zxc[unko]; int min; int sumofangle; /* ready */ tl; Wait(1000); ResetTachoCount(OUT_AB); Wait(1000); /* measure distance between a can and the machine */ for(int i = 0;i <=unko-1;i ++) { tr; Wait(measure_time); zxc[i] = SensorUS(S4); sumofangle += MotorTachoCount(OUT_A); } PlaySound(SOUND_UP); /* find minimum distance */ min = 40; for(int j = 0;j <=unko-1; j++) { if(min > zxc[j]) { min = zxc[j]; takatyan = j; } } for(int j = 0;j <= unko-1; j++) { if(zxc[j] == 0){zxc[j] = 100; } } float angleR = sumofangle/unko*(unko-takatyan); int angle = trunc(angleR); Off(OUT_AB); PlaySound(SOUND_UP); TextOut(0,LCD_LINE1,"takatyan ="); NumOut(0,LCD_LINE2,zxc[takatyan]); NumOut(0,LCD_LINE4,angle); Wait(1000); /* turn to right direction */ ResetTachoCount(OUT_AB); tl; until( SensorUS(S4) <= zxc[takatyan] ); PlaySound(SOUND_UP); Off(OUT_AB); ResetScreen(); NumOut(0,LCD_LINE1,MotorTachoCount(OUT_A)); Wait(1000); /* approach a can */ go; until(SensorUS(S4) <= direction); Off(OUT_AB); } sub can_mochiage() {//一個目の缶を持ち上げるサブルーチン 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を送信(これにより缶を掴む)*/ /*Sからメールボックス2にSIGNAL_Eが来るまで待機*/ } sub can_tsumu() {//缶を積み、持ち上げるサブルーチン 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を送信*/ } task main() { SetSensorLowspeed(S4);//センサー4を設定 int hakken=0;//発見した回数をカウントする変数 while(hakken==0){//hakken==0の時 find_direction();//缶を探して前進 hakken++;//hakkenをカウント }//while(hakken==0) /*hakkenの値が1となり次のwhile(hakken==1)へ移行*/ while(hakken==1){//hakken=1の時 TextOut(0,LCD_LINE2,"while(hakken==1)"); can_mochiage();//一個目の缶を持ち上げる hakken++;//hakkeをカウント }//while(hakken==1) /*hakkenの値が2となり次のwhile(hakken==2)に移行*/ while(hakken==2){//hakken=2の時 TextOut(0,LCD_LINE2,"while(hakken==2)"); find_direction();//缶を探し前進 hakken++;//hakkenをカウント }//while(hakken==2) /*hakkenの値が3となり次のwhile(hakken==3)へ移行*/ while(hakken==3){//hakken=3の時 TextOut(0,LCD_LINE2,"while(hakken==3)"); can_tsumu();//缶を二個積む hakken++;//hakkenをカウントする }//while(hakken==3) /*hakkenの値が4となり次のwhile(hakken==4)へ移行*/ while(hakken==4){//hakken=4の時 TextOut(0,LCD_LINE2,"while(hakken==4)"); find_direction();//缶を探して前進 hakken++;//hakkenをカウント }//while(hakken==4) /*hakkenの値が5となり次のwhile(hakken==5)へ移行*/ while(hakken==5){ TextOut(0,LCD_LINE2,"while(hakken==5)"); can_tsumu();//缶を三個積む hakken++;//hakkenをカウント }//while(hakken==5) }//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() { int msg; while(true){ 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,-185);//缶を掴む 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を送信(1.5秒後退)*/ }//if(msg==SIGNAL_B) }//while(true) }//task main **結果 [#r58b4840] ちょっと流石に遠すぎたか...?? *トラブル発生? [#pec92f86] NXTに文法は合っているのにプログラムが送れないとうい事態が発生!!!~ ピアサポートセンターに行って直接先生にお聞きしてみたところ、NXTの容量がいっぱいになっているとご指摘いただきました。~ どうせもう使わないだろうし、一応USBにプログラムは入っているのでデータすべて削除!~ 改めて送信してみると...ピッ。~ ちゃんと遅れました。一安心です。(1/20(月)) *ライントレースはどうする? [#k30a9f9a] *それぞれの動きを一つのプログラムに [#k9b438c5] *作戦 [#he6efb51] **ルート決め [#o108ae07] **狙う缶はお前だ! [#g0c1bf86] *プログラム、ハードの再確認 [#u9170ed6] *リハーサル [#e20b40a7] *忍びくる魔の手 [#y120fa93] *心を一つに [#c48c4f12] *そして本番へ [#i4d35266] *天国か地獄か [#v48459b0] *全体を振り返って [#eb8f9122]