[[2014a/Member]] *目次 [#nf1ce3c8] #contents *メンバー紹介 [#q3b25128] [[suiden>http://yakushi.shinshu-u.ac.jp/robotics/?2014a%2FMember%2Fsuiden%2FMission2]] [[kiyomizu>http://yakushi.shinshu-u.ac.jp/robotics/?2014a%2FMember%2Fkiyomizu%2FMission2]] kowhich [[ryu-abe>http://yakushi.shinshu-u.ac.jp/robotics/?2014a%2FMember%2Fryu-abe%2FMission2]] ※席順 *要求・リスク分析 [#pd9009e4] まず、要求・リスク分析の結果を図に示す。ユースケース図を採用した。ユースケース図(UML2.0)とは、システムがどのような機能を提供するかを示す図で、今回提供する機能を具体化するのに適切だと判断したため、ユースケース図を利用した。また、今回のユースケース図はUML2.0に準拠し記述する。 それに加えて、ミスユースケースというものも記述した。これはシステムに対する脅威を示したもので、今回は赤色のものがミスユースケースとなっている。右側のアクターがその脅威の原因を示したものである。 ※UML2.0・・・Unified Modeling Languageの略称。大雑把に言うとシステムの仕組みなどを図で表す 表現方法である。2.0はそのバージョン。 #ref(uc1.PNG) まず、第一に提供する機能として、課題をクリアする というユースケース(機能)があると考えた。ここから細分化していき、実装すべき機能はなにかを探っていく。 課題をクリアするユースケースは、「光センサ・ライン閾値キャリブレーション」、「走行する」 「紙コップを運ぶ」という3つのユースケースから成り立っていると考えた。 まず、「走行する」ユースケースから見ていきたい。「走行する」と言っても、様々な手段がある。 第一に「ライントレース走行」これはラインに沿って走行する方法である(実現方法は後に示す) 次に、「ライン無視走行」これは、NXCで提供されているOnFwd(),Off()などのみで走行するものである。また、これにはモーターには個体差があり、指定したとおりに動作できないことがある。なので、左右モータを同期して走行することも求められるので、拡張機能とした。 次に紙コップを運ぶことについて見ていく。「紙コップを置く」「紙コップをつかむ」「紙コップを検知する」「どの紙コップか判断する」のユースケースで構成されている。これらは、すべて紙コップの位置がずれたりすると、課題の成功にかなり影響するので、それの解決策としてバンパーを設置した。これにより、機体の衝突などにより紙コップの位置がなくなるだろうと考えたからだ。 時間帯によって、窓から差し込む光が時間によって変化していくと考えた。それにより、手動で値を設定していてはそれの時間もかかり、不安定なので、光センサ値・閾値キャリブレーションによりそれを防ぐことを考えた。なので、今回キャリブレーションを実装するに至った。 図に、番号が振ってあるのは後の説明とユースケースと実現方法のトレーサビリティを確立するためである。 *紙コップのデザインについて [#m850ba72] 光センサで判断するために、紙コップにデザインを施した。光センサは反射してきた明るさを計測するので、青や緑などの色を使っても判断がしづらいと思ったので、白と黒のみでデザインを施すことにした。デザインに求められるのは美しさではなく、光センサで測定した値それぞれに差があるかどうかが一番大切である。デザインによっても検知の性能が左右されるので、手を抜いてはいけないと感じた。測定場所は授業教室(10番教室) #ref(cop.PNG) **�疑燭湛� [#k1ae08ed] 光センサで測定したところ、値は約37。 **�郷燭断� [#cfe18d71] 光センサで測定したところ、値は約65。 **�啓福� [#idb27ee5] 3個目に一番迷ったが、結局この形になった。本来は灰色でやろうと思ったが、黒ペン一本では限界があった。 なので、黒線と白を混ぜれば灰色として認識するのではないかという仮説のもと、このデザインにした。 光センサで測定したところ、値は約47。 この値の差ならば、どの紙コップかを判断するかもスムーズに行えるのではないかと結論づけた。 *機体の紹介 [#e9fd4c76] まず、モータで歯車を動かす(1)。これにより、アームが閉じる(2) #ref(robo1.PNG) 続いて、更にモータに力を加え、紙コップをつかむ。 #ref(./IMG_0946.JPG,30%,aaa) そして、さらに力を加えると、閉じる方向に力は行かず、真上にいくので持ち上がるという仕組みだ。 そして、これがコップの位置ずれを防ぐために設置されたバンパーである(ユースケース図��参照)。 そして、これがコップの位置ずれを防ぐために設置されたバンパーである(ユースケース図�┿仮�)。 #ref(robo2.PNG) 機体は一度ダイエットをし、非常に軽量化された。なぜダイエットを行ったかというと、重心が機体上部にあり、カーブすると転倒してしまうことが多々あったからである。 (残念ながら、その時の写真はないですごめんなさい) *プログラムについて [#r71a1af9] 今回私は独自にプログラムの作成を行っていた。関数を作り、できるだけ操作を部品化しようと試みた。しかし、作戦変更により、使わなくなったので、このプログラムは実際には利用しなかった。 なので、他のメンバーのページを見ていただければ、実際に使ったプログラムについての説明を閲覧することが出来る。 [#q3b25128] **変数名について [#cbc77a37] m_がついてるものはグローバル変数とした。それ以外はローカル変数とするようにした。 そうすることにより、値の代入ミスなどを防ぐことが出来ると考えたからだ。 **定義 [#we70a57f] /*変数宣言*/ int m_black=0; int m_white=0; int m_border=0; int m_cop_A = 0; int m_cop_B = 0; int m_gap=0; int m_kP =0; int m_kD =0; int m_old_value =0; int m_current_value =0; SetSensorLight(S3); SetSensorTouch(S1); SetSensorLight(S2); **キャリブレーション 関数名:lightCalibration() 型:void [#zbe4bc9c] int nb=0; int nw=0; ////↓黒値取得///// while(!SENSOR_1){//押している間光センサの値を取得するという意味 m_black += SENSOR_3;//押された間の値を蓄積して記録しておく Wait(1); nb++; //何度取得したかをカウントしておく } m_black = m_black/nb;//蓄積した値を何度取得したかの回数で割って平均を求めて、黒ラインの 値として設定する。 Wait(500); ////↑黒値取得//////↓白値取得////// while(!SENSOR_1){ m_white += SENSOR_3; Wait(1); nw++; } m_white = m_white/nw; Wait(500); ////↑白値取得/////↓境界値算出////// m_border =(m_white+m_black)/2 //境界値(閾値)は黒値と白値の平均値とする まず、タッチセンサが押されてる間,その場所の光センサの値を蓄積する。蓄積している間、何度蓄積したかをカウントする。そして、その蓄積した値を蓄積した回数で割る。それがその場所の光センサの値となる。これを、白の場所、黒ラインの場所両方で行う。その後、m_borderにその平均値を代入する。これがライン閾値となる。これによりキャリブレーションを実現した。 **ライントレース�� [#p8f48759] ***直線用 関数名:forwardLineTrace(スピード:int) 型:void [#u029b328] int d; int speedL; int speedR; int speed; speed = スピード; m_current_value = m_old_value; m_old_value = SENSOR_3; d=(m_old_value - m_current_value)*m_kD; m_gap = (m_border - SENSOR_3)*m_kP + d if(m_gap >= 0){ speedL = speed; speedR = speed - m_gap; } else{ speedL = speed + m_gap; speedR = speed; } OnFwd(OUT_B,speedL); OnFwd(OUT_C,speedR); まず、この関数はPD制御によって動いている。I制御を入れると、さらに綺麗にライントレース出来るのだが、PDだけでも綺麗にライントレース出来るので、今回はこれで行った。 まず、簡単に説明をすると、P制御とは、目標の値に近づけるために、制御量に応じて操作量を増やすような制御のこと。 そして、D制御とは、その操作を行う反応速度のことである。 ***カーブ用ライントレース 関数名:curveLineTrace(スピード:int) 型:void [#qacb9694] int speed; speed = スピード; if(m_border < SENSOR_3){ OnFwd(OUT_B,speed); Off(OUT_C); } else{ OnFwd(OUT_C,speed); Off(OUT_B); } Wait(2); ON/OFF制御によって実現されている。センサの値のほうが閾値よりも大きかったら右、そうでなかったら、左というように実装されている。 **�↓�ライン無視走行 [#i6e1c56d] OnFwd(port,speed); OnRev(port.speed); OnFwdSync(port,speed,0~100);//�ず険Ε癲璽燭鯑唄�させる などの元から提供されているAPIを利用して走行をする。つまり、直にモーターに命令して走行する。 **�ぅ灰奪廚鮹屬� 関数名:removeCop() 型:void [#lea8c0bb] OnRev(OUT_A,75); Wait(1000); モータ逆回転で一定の時間回す必要がある。この値は適宜調整が必要なので、成功率にばらつきが出てしまうことが考えられる。それも今後の課題としておきたい。 **�ゥ灰奪廚鬚弔�む 関数名 catchCop() 型:void [#aa13e149] OnFwd(OUT_A,75); Wait(1000); 置くのと同様である。置くのとは逆回転で実装されている。 **��紙コップを検知する 関数名:detectCop(検知したいコップの明るさ数値) 型:bool [#z0d324fb] if(SENSOR_2 < 検知したいコップの明るさ数値){ return true; } 検知したいコップの明るさ数値を関数に渡して、それが検知されたらtrueを返すといったもの。 わざわざ値を入力して渡す必要があるので、使用する際非常に面倒なのが欠点。関数内でキャストをすべきだとのちになって感じた。また、検知の感度が悪かった。これは、前回の交差点検知と同様に、なんど検知したかをカウントして、その値をもとに検知するという方が精度が高くなっただろうとのちになって感じた。 **�Г匹了罐灰奪廚�判断する 関数名:judgeCop() 型:int [#ldf95edc] if(SENSOR_3 < 37){ return 3; } if(SENSOR_3 < 65){ return 1; } if(SENSOR_3 < 40){ return 2; } それぞれの値に応じて1,2,3の値を返して判断を行う。これも先ほどのコップ検知ど同様に、精度が低かった。何度検知したかをカウントし、それに応じて判断するといった仕組みのほうが精度は高くなった可能性がある。 *感想・反省 [#z750df4d] 今回、私はプログラムをより組みやすいように心がけた。しかし、作戦変更により使われなく鳴ってしまったのは残念だった。機体が変更にあっても作戦が変更されてもプログラムが使えるようにする必要があると感じた。さらに、部品化したのはいいが、サブルーチンを一切作らず組んでしまったので、main()内のプログラムが非常に煩雑になり、わかりにくくなってしまった。部品化するだけではなく、見やすいようにするのも大切だと感じた。 今回、期末試験と時間がかぶり、集まれる時間が取れなかった。さらに、実家に帰らなければいけない予定があったため、最終調整に行くことが出来ず、非常に残念であった。調整が出来ないことも多々あったし、自分の作業が雑になってしまったというのも多々見られた。今後はこのようなことが無いように、計画を立て、十分が時間をとれるようにすべきだと感じた。