#contents
[[2017b/Member]]
*課題3 [#b9fd6f1e]
課題2で使用したコースにピンポン玉が入った紙コップが指定された場所においてあり、それらを別々に回収してピンポン玉はX地点に、紙コップはY地点に運ぶ。さらに障害物としても紙コップが置いてありそれらを動かしてはならない。
#ref(2017b/Member/cyanomelana/Mission3/2017b-mission3.png,80%,課題3)
今回の課題3は作業内容がとても多いので、チーム内でロボットを作る作業とプログラムを作る作業とで、分担して作業を行った。私は主にロボットの機体を作成したのでプログラムについての詳細は大谷風吾、カデンエン、チョウカイドウのレポートを参考にして下さい。(「チームメンバー」の項目にリンクがあります)
***ルールの詳細 [#f899a952]
ルールの詳細はこちらのリンクにありますので参考にしてください。~
http://yakushi.shinshu-u.ac.jp/robotics/?2017b%2FMission3#red46b61
***チームメンバー [#oa518bc5]
横川 友也~
大谷 風吾http://yakushi.shinshu-u.ac.jp/robotics/?cmd=edit&page=2017b%2FMember%2Fwaitu%2FMission3&refer=2017b%2FMember
カ デンエンhttp://yakushi.shinshu-u.ac.jp/robotics/?2017b%2FMember%2Fyan%2FMission3
チョウ カイドウhttp://yakushi.shinshu-u.ac.jp/robotics/?2017b%2FMember%2FAlex%2FMission3~
(他のメンバーのレポートも参考にしてください。)
*作成したロボット[#sd56a80b]
作成したロボットは一体で、コップを見つける、つかむ、重ねる、ピンポン玉を指定位置まで運ぶ動作、すべての動作を一体でこなせるようなロボットを作成した。(詳細は下のロボットの画像を参照)~
#ref(2017b/Member/cyanomelana/Mission3/robo2.PNG,50%,ロボットの詳細1)
#ref(2017b/Member/cyanomelana/Mission3/robo3.PNG,70%,ロボットの詳細2)
**ロボットの詳細 [#jbd98e7d]
このロボットは前輪駆動となっており、ロボットの車体がとても重いので、ロボットの作成マニュアル本にあるロボットの後輪の車輪を二つ作り、ロボットの後ろに取り付けることでロボットの重量を支え、スムーズに動けるよう工夫した。
#ref(2017b/Member/cyanomelana/Mission3/foto1.PNG,80%,課題3のロボット)
***ロボットの骨組み [#ea7693eb]
このロボットは一体でミッションをこなすためにロボットにNXT本体を二台積まなければならなかったので、ロボット本体の強度を強くする必要があった。そこで、ロボットの後ろと前の間に筋交いを設けることで、少しだけ強度を上げることが出きた。さらに直線走行、回転するときにロボットのモーターが前後に動いてしまう問題もこれで解決することが出きた
#ref(2017b/Member/cyanomelana/Mission3/roboex3.gif,80%,ロボットが動くとモーターが動いてしまう)
#ref(2017b/Member/cyanomelana/Mission3/kaizen.PNG,80%,改善)
#ref(2017b/Member/cyanomelana/Mission3/katamukahen.PNG,80%,モーターが傾かなくなった)
***各種センサーの取り付け位置 [#md272077]
光センサー
下の画像のようにロボットの左右両方に光センサーを取り付け、光センサーを使い分けることで紙に描かれた線の読み取り方が増えた。その結果、複雑な動きをすることができるようになった。
#ref(2017b/Member/cyanomelana/Mission3/hikari.PNG,80%,光センサーの位置)
超音波センサー
コップを見つける超音波センサーはロボット前側中央に取り付け、さらにセンサーを縦にして使うことで測定した紙コップまでの距離をより正確に測ることができるように工夫した。(画像参照)~
しかし、「主なプログラミングによる動作の流れ」の項目で詳しく説明するが、このロボットは紙コップをロボットの中に取り込むので、超音波センサーに、下の動く画像のようにモーターを取り付けて超音波センサーが動けるようにし、紙コップをロボットの内部に取り込めるようにした。
#ref(2017b/Member/cyanomelana/Mission3/tyouonn.PNG,80%,超音波センサーの位置)
#ref(2017b/Member/cyanomelana/Mission3/tooreru.gif,80%,紙コップの取り込み)
***紙コップをつかむ機構 [#hefd249c]
紙コップをつかむ機構は片方の腕を固定し、もう片方の腕をモーターで動かすことで紙コップをつかむようにした。また、紙コップをつかみやすいようタイヤを取り付けた。さらに、つかんだ時に紙コップを少し浮かせることでX地点の割りばしを超えてピンポン玉を枠内に運べるように工夫した。
上から見た図
#ref(2017b/Member/cyanomelana/Mission3/torutoru.gif,80%,紙コップをつかむ機構)
横から見た図
#ref(2017b/Member/cyanomelana/Mission3/ccc.gif,80%,紙コップをつかむ機構)
***紙コップを上げ下げする機構 [#hcce8a0e]
紙コップを上げ下げするモーターに紙コップをつかむモーターをとりつけて紙コップをつかみ、上げ下げできるようにした。
#ref(2017b/Member/cyanomelana/Mission3/bbb.gif,80%,紙コップを上げ下げする機構)
*ロボットの紙コップを取得するときの一連の動きは「主なプログラミングによる動作の流れ」の項目で説明する。
*作成したプログラミング [#ye49cd86]
課題3のプログラミングは2機のNXT間でBluetouthを介して通信を行うプログラムを使用しており、超音波センサーを用いて紙コップを認識した後、親機からの信号を受信し子機の紙コップをつかむプログラムが起動するプログラムである。
**基本的な動作のプログラミング [#t1b7bd8d]
課題3に必要な主なプログラミングは「紙コップを見つけるプログラミング」と「ライントレースするプログラミング」である。
***紙コップを見つけて近づくプログラミング [#s55f5497]
どのようにロボットから一番近い紙コップを見つけるのか
ロボットから一番近い紙コップを見つけるためにはセンサーが指定された任意の角度を回り、その後回っている途中で一番紙コップに近かった角度を随時記憶(紙コップとセンサーの距離の最小値を随時置き換えする)していく。指定された角度を回り終えると一番紙コップに近い角度に向くためにvoid turnAng(long ang)を用いてタイヤを回転させる。(画像参照)
#ref(2017b/Member/cyanomelana/Mission3/ggg.gif,50%,ロボットから一番近い紙コップを見つける)
紙コップを見つけて近づくプログラムは次の1〜4の手順が行われている。
��int searchDirection(long ang)によってどれくらいの角度の範囲を調べるかを指定する
�∋慊蠅靴審囘戮魏鵑襪燭瓩砲呂匹里�らいタイヤを回せばよいか void turnAng(long ang)で計算してタイヤを回す
��紙コップに一番近い位置の角度を記憶したらその角度にロボットが向く
��int searchDirection(long ang)によって一番近い紙コップまでの距離を確認したら任意の距離まで近づく。この際に近づく距離はvoid fwdDist(float d)をつかい、どのくらいタイヤを回せばよいかを計算してタイヤを回す。
const float diameter = 5.45; //タイヤ直径
const float track = 10.35; //タイヤトレッド幅
const float pi = 3.1415; //円周率
void fwdDist(float d) //距離 dcm前進 //
{
long angle = d/(diameter*pi)*360.0; //必要なタイヤの回転角度
RotateMotorEx(OUT_AC, SPEED_SLOW, angle, 0, true ,true);
}
void turnAng(long ang) //角度ang度の時計回りの旋回
{
long angle = track/diameter * ang;
RotateMotorEx(OUT_AC, SPEED_SLOW, angle, 100, true, true);
}
int searchDirection(long ang) //現在の方向を中心にang度の範囲で探し
//障害物までの距離を返す
{
long tacho_min; //最も近い距離を実現するタイヤの回転数
int d_min = 300; //最も近い距離の仮の最小値(十分大きくとっておく)
long angle = (track/diameter)*ang; //旋回角度からタイヤの回転を計算
turnAng(ang/2); //指定された角度の半分を旋回
ResetTachoCount(OUT_AC); //角度計測をリセット
OnFwdSync(OUT_AC,SPEED_SLOW,-100); //半時計回りに旋回
while(MotorTachoCount(OUT_A)<=angle)
{
if (SensorUS(S1)<d_min)
{ //現在の距離が借りの最小値より小さい場合
d_min = SensorUS(S1); //仮の最小値を更新
tacho_min = MotorTachoCount(OUT_A); //この時のタイヤの回転数を記録
}
}
OnFwdSyncEx(OUT_AC,SPEED_SLOW,100,RESET_NONE);
until(MotorTachoCount(OUT_A)<=tacho_min || SensorUS(S1)<=d_min);
Wait(14); //微調整
Off(OUT_AC);Wait(500);
return d_min;
}
***ライントレースをするプログラム [#i76f8301]
ライントレースするプログラムの詳細は課題2のレポートで詳しく説明しているのでそちらを参考にして下さい。
http://yakushi.shinshu-u.ac.jp/robotics/#g9f1eef7
**主なプログラミングによる動作の流れ [#se4a2410]
ロボットの基本的な動作の流れはつぎのとおりである。
�〇罐灰奪弩�つける
�〇罐灰奪廚鮓�つける
�▲札鵐機爾鮠紊欧�
��紙コップをつかむ
��X地点に向かう
�セ罐灰奪廚鮖�ち上げる
�Ε札鵐機爾魏爾欧�
�Щ罐灰奪廚鮓�つける
***�仝�つける [#kbfb3162]
ライントレースを使い、紙コップの近くに到着しすると、センサーを起動して「紙コップを見つけるプログラミング」を使用して、一番近い紙コップを見つける。
#ref(2017b/Member/cyanomelana/Mission3/sensorvartical2.jpg,30%,ロボットの動き)
***�▲札鵐機爾鮠紊欧� [#if283a49]
一番近い紙コップを見つけ次第その紙コップの方向にロボットの向きを変えてセンサーを上げる。
#ref(2017b/Member/cyanomelana/Mission3/age.gif,70%,ロボットの動き)
***��紙コップをつかむ [#j837269e]
センサーを上げた後、紙コップをつかめる位置まで紙コップに向かって直進し、つかむ。
#ref(2017b/Member/cyanomelana/Mission3/firstcatch.jpg,30%,ロボットの動き)
***��X地点に向かう [#n6742972]
紙コップをつかんだ後、ライントレースして、X地点まで紙コップを運ぶ。
***�セ罐灰奪廚鮖�ち上げる [#w2231491]
X地点の中に紙コップが入ると、紙コップを上げて紙コップの中のピンポン玉を開放する。
#ref(2017b/Member/cyanomelana/Mission3/fff.gif,80%,ロボットの動き)
***�Ε札鵐機爾魏爾欧� [#r88dd3f2]
ピンポン玉を開放したら、後ろに進みながらX地点の枠を出て、ピンポン玉に触れない位置までロボットが出ると超音波センサーを下ろして二つ目の紙コップを探しに行く。
#ref(2017b/Member/cyanomelana/Mission3/eee.gif,80%,ロボットの動き)
***�Ц�つける [#t73e2e58]
紙コップを一個取得した次の動作として、センサーで2つ目の紙コップを見つけてから紙コップを重ねる動作がある。そして最後に重ねた紙コップをY地点に置く。
**プログラミングの全体 [#k9f91207]
まず親機、子機のdefineを次のように定義した。
親機
#define SPEED 100
#define SPEED_SLOW 60
#define turn_left1 OnFwd(OUT_A,80 * x); OnRev(OUT_C,35 * x);//kituku
#define turn_left2 OnFwd(OUT_A,100 * x); OnFwd(OUT_C,40 * x);//yuruku
#define turn_left3 OnFwd(OUT_A,80 * x); OnRev(OUT_C,90 * x);//sonoba
#define turn_left5 OnFwd(OUT_A,80 * x); OnRev(OUT_C,1 * x);//右の車輪だけを前に回して左に回る
#define go_forward OnFwd(OUT_A,80 * x); OnFwd(OUT_C,87 * x);//前に進む
#define go_back OnRev(OUT_A,100 * x); OnRev(OUT_C,85 * x);//後ろに進む
#define turn_right1 OnRev(OUT_A,35 * x); OnFwd(OUT_C,80 * x);//きつく右に回る
#define turn_right2 OnFwd(OUT_A,30 * x); OnFwd(OUT_C,100 * x);//ゆるく右に回る
#define turn_right3 OnRev(OUT_A,80 * x); OnFwd(OUT_C,80 * x);//その場で右に回る
#define AD SendRemoteNumber(1,MAILBOX1,01);//アームを閉じて締める
#define AU SendRemoteNumber(1,MAILBOX1,02);//アームを上げる
#define TD OnRev(OUT_B,45 * x); Wait(1000);//超音波センサーを下げる
#define TU OnFwd(OUT_B,45 * x); Wait(1000);//超音波センサーを上げる
#define CupOff SendRemoteNumber(1,MAILBOX1,03); //コップを離す
#define turn_right4 OnRev(OUT_A,80 * x); OnFwd(OUT_C,60 * x);//その場で右に回る
#define turn_right5 OnRev(OUT_A,80 * x); OnFwd(OUT_C,1 * x);//右の車輪だけを後ろに回して右に回る
#define turn_right6 OnRev(OUT_A,1 * x); OnFwd(OUT_C,80 * x);//左の車輪だけを回して右に回る
#define DO 523//音の高さ
#define x 0.65//かけ数
子機
#define ArmDown OnRev(OUT_A,50); Wait(500);//紙コップをおろす
#define ArmDown OnRev(OUT_A,50); Wait(500);//紙コップを下げる
#define ArmUp OnFwd(OUT_A,70); Wait(300);//紙コップを上げる
#define ArmClose OnRev(OUT_C,70); Wait(1000);//紙コップをつかむ
#define ArmOpen OnFwd(OUT_C,30); Wait(500);//紙コップを離す
#define ArmStay OnRev(OUT_AC,1);//コップを強くつかみ続ける
#define ArmStay OnRev(OUT_AC,1);//紙コップを強くつかみ続ける
ライントレースするプログラムはsubルーチンにした。
sub IKK() //ロボットの左の光センサーが線の右側に沿ってライントレース
{
int BP = 0;
while (BP < 125)
{
if (SENSOR_2 < 45)
{
turn_right1;
BP++;
}
else
{
if (SENSOR_2 < 49 )
{
turn_right2;
}
else if (SENSOR_2 < 56 )
{
go_forward;
}
else if (SENSOR_2 < 58)
{
turn_left2;
}
else
{
turn_left1;
}
BP = 0;
}
Wait(1);
}
Off(OUT_AC);
PlayTone(DO,100); Wait(100);
Wait(10);
BP = 0;
}
sub DKK()//ロボットの左側の光センサーが線の左側に沿ってライントレースする。
{
int BP = 0;
while (BP < 170)
{
if (SENSOR_2 < 45)
{
turn_left1;
BP++;
}
else
{
if (SENSOR_2 < 49 )
{
turn_left2;
}
else if (SENSOR_2 < 54 )
{
go_forward;
}
else if (SENSOR_2 < 55)
{
turn_right3;
}
else
{
turn_right4;
}
BP = 0;
}
Wait(1);
}
Off(OUT_AC);
PlayTone(DO,100); Wait(100);
BP = 0;
}
sub DKK2()//ロボットの右側の光センサーが線の左側に沿ってライントレースする。
{
int BP = 0;
while (BP < 170)
{
if (SENSOR_3 < 45)
{
turn_left1;
BP++;
}
else
{
if (SENSOR_3 < 49 )
{
turn_left2;
}
else if (SENSOR_3 < 54 )
{
go_forward;
}
else if (SENSOR_3 < 55)
{
turn_right3;
}
else
{
turn_right4;
}
BP = 0;
}
Wait(1);
}
Off(OUT_AC);
PlayTone(DO,100); Wait(100);
BP = 0;
}
子機のプログラミング
task main ()
{
int msg;
while(true)
{
ReceiveRemoteNumber(MAILBOX1,true,msg);
if (msg == 01)
{
Off(OUT_AC);
ArmDown;
ArmClose;
ArmDown;//紙コップを下げる
ArmClose;//紙コップをつかむ
msg = 04;
}
if (msg == 02)
{
ArmStay;
ArmUp;
ArmStay;//紙コップをつかみ続ける
ArmUp;//紙コップを上げる
msg = 04;
}
if (msg == 03)
{
Off(OUT_AC);
ArmUp;
ArmOpen;
ArmUp;//紙コップを上げる
ArmOpen;//紙コップを離す
}
if (msg == 04)
{
ArmStay;
ArmStay;//紙コップを強くつかみ続ける
Off(OUT_A);
}
}
}
課題3のプログラミングはできるだけ獲得スコアを得るためにD地点に近い(αとβ)二つの紙コップとピンポン玉(図参照)の回収を優先し、残り一つの紙コップの回収は断念した。~
α、βの紙コップの回収のプログラムをそれぞれ次のように分ける。
#ref(2017b/Member/cyanomelana/Mission3/giveup.PNG,80%,回収する紙コップ)
***紙コップの回収の流れ [#d465f118]
1 C地点まで直進した後左折して、そこからF地点までライントレースする。
2 F地点で交差点を認識した後、超音波センサーが作動してαの紙コップを見つける。
3 αの紙コップをつかむ
4 QS間の線を認識するまで後退。
5 X地点まで紙コップを運ぶ
6 αの紙コップを上げてピンポン玉を枠内に収める
7 ロボットをβの紙コップの方向に向ける
8 センサーを下ろしたあと、超音波センサーが作動してβの紙コップを見つける
9 βの紙コップを取る
10 QS間の線を認識するまで後退し、X地点まで運ぶ。
11 Y地点に紙コップを置く
***1C地点まで直進した後左折して、そこからF地点までライントレースする。 [#rd3b5909]
SetSensorLowspeed(S1);
SetSensorLight(S2);
SetSensorLight(S3);
go_forward;
Wait(500); //少し前進
turn_left3;
Wait(200);
while (SENSOR_2 > 45)
{
turn_left3;
}
turn_right1;
Wait(100);
IKK(); //左のセンサーを使ってF地点までライントレース
turn_left3;その場で左に回る
> Wait(1000); //左向く
***2 F地点で交差点を認識した後、超音波センサーが作動してαの紙コップを見つける[#t9bc943e]
int d = searchDirection(70);//コップ探す
if (d > 10)
{
fwdDist(d-10.0);//コップに近づく
}
TU; //超音波センサーをあげる
go_forward;
Wait(2900);
***3 αの紙コップをつかむ[#d998d7dc]
AD; //コップを取る
Off(OUT_AC);
Wait(3000);
***4 QS間の線を認識するまで後退。[#i3dc1092]
go_back;
Wait(500);
turn_left3;
Wait(700);
while (SENSOR_2 > 45)
{
go_back;
}
go_back;
Wait(250);
Off(OUT_AC);
Wait(200);
while (SENSOR_2 > 45)
{
go_back;
}
go_back;
Wait(450);
Off(OUT_AC);
Wait(450);
while (SENSOR_2 > 45)
{
go_back;
}
go_back;
Wait(250);
Off(OUT_AC);
Wait(200);
turn_right5;
Wait(700);
while (SENSOR_3 > 45)
{
turn_right5;
}
***5 X地点まで紙コップを運ぶ[#m92b020b]
DKK2(); //Sを左折
//Qに到着
turn_right6;
Wait(1100);
while (SENSOR_2 > 45)
{
turn_right6;
}
turn_right6;
Wait(300);
Off(OUT_AC);
Wait(1000);
***6 αの紙コップを上げてピンポン玉を枠内に収める[#p031a658]
go_forward; //Xに入る
Wait(2500);
AU; //Xでコップを上げる
Off(OUT_AC);
Wait(3000);
***7 ロボットをβの紙コップの方向に向ける[#q56fdff8]
go_back;
Wait(1200);
Off(OUT_AC);
Wait(2000);
while (SENSOR_2 > 45)
{
go_back;
}
go_back;
Wait(500);
while (SENSOR_2 > 45)
{
go_back;
}
Off(OUT_AC);
Wait(1000);
turn_right5;
Wait(500);
while (SENSOR_3 > 45)
{
turn_right5;
}
turn_right5;
Wait(600);
while (SENSOR_3 > 45)
{
turn_right5;
}
Off(OUT_AC);
Wait(1000);
go_forward;
Wait(1000);
while (SENSOR_2 > 45)
{
go_forward;
}
Off(OUT_AC);
Wait(1000);
while (SENSOR_3 > 45)
{
turn_left5;
}
turn_left5;
Wait(300);
go_forward;
Wait(500);
***8 センサーを下ろしたあと、超音波センサーが作動してβの紙コップを見つける[#i8f9defb]
TD; //超音波下げる
Off(OUT_AC);
Wait(2000);
d = searchDirection(120);//コップ探す
***9 βの紙コップを取る[#i6e93fd1]
if (d > 10)
{
fwdDist(d-10.0);//コップに近づく
}
TU; //超音波センサーをあげる
Off(OUT_AC);
Wait(1000);
go_forward;
Wait(1300);
Off(OUT_AC);
Wait(1000);
turn_left3;
Wait(1400);
Off(OUT_AC);
Wait(2000);
go_forward;
Wait(2300);
go_back;
Wait(100);
Off(OUT_AC);
Wait(500);
AD; //コップを取る(重ねる)
Off(OUT_AC);
Wait(3000);
***10 QS間の線を認識するまで後退しX地点まで運ぶ[#n1af9102]
go_back;
Wait(1900);
turn_right3;
Wait(1400);
go_back;
Wait(1300);
while (SENSOR_2 > 45)
{
go_back;
}
turn_left5;
Wait(1200);
while (SENSOR_3 > 45)
{
turn_left5;
}
turn_right5;
Wait(300);
go_forward;
Wait(1000);
while (SENSOR_2 > 45)
{
go_forward; //Xまで直進
}
***11 Y地点に紙コップを置く[#ycea5f4d]
AU; //Xでコップを上げる
turn_left3;//少し方向を調整する
Wait(200);
go_back;
Wait(300);
CupOff;//紙コップをY地点に置く
*結果・感想・反省点 [#vc8eefe7]
**結果 [#d82c4f75]
結果は0点。動いてほしい方向にロボットは動かなかった。超音波センサーが動かしてはいけない紙コップを感知して動かしてしまった。実際はー2点である。
**反省点 [#m7a72ca1]
***ロボットについて [#x1cc9378]
・NXT本体の取り付け位置を地面から高い位置にしてしまったので走行が不安定になってしまった。~
・ロボットの後輪を二つ取り付けることでスムーズに動けるよう工夫したが、車体が重すぎてロボットの走行に支障が出てしまった。~
・ロボットの縦方向に筋交いを取り付けたことで少し強度をつけることができたが、紙コップを上げ下げする機構との接触を避けるためにロボットの横方向の補強ができなかった。そのためロボットが回転したときに大きくゆがんでしまい、その結果、前輪の車軸に大きな負担がかかってしまい回転がスムーズにできなかった。やはり強度を持たせるために横方向の補強も必要であったと考える。
***プログラムについて [#t7817fca]
・ロボットの作成に多くの時間を割いてしまったためしっかりとしたプログラミングを作れなかった。
**感想 [#j5b18dd1]
・どのようなロボットを作成すれば効率よく紙コップを回収できるかを考えるのが難しかった。実際、完成したロボットは効率よく動いたとは言えなかった。~
・課題1〜3のロボットとプログラミングを作成して、プログラミングをできるだけ短く、書いたとおりに動かすにはロボットに工夫が必要で、またプログラミングを書いたとしても、書いたとおりにはほとんど動かず、調整が必要不可欠ということが分かった