*物体情報の取得とデータ処理 [#d815c7cd]
サンプルプログラムをダウンロード・コンパイル・実行してください.

[[サンプルプログラム>http://www.er.ams.eng.osaka-u.ac.jp/kawai/CP2017/main2.c]]をダウンロード・コンパイル・実行してください.
~
このプログラムでは,一つの物体の位置へアームを移動させ,物体を把持し,その重量を計測します.

~
物体の見た目の情報(位置,色,半径)は天井の視覚センサ(カメラ)で,物体の重量はグリッパの力覚センサで計測できると仮定します.

~
ただし,簡単化のため,カメラ画像処理は省いており,物体番号を渡すとその位置,色,または,半径を返す関数が用意されています.
~
また,これらのセンサ値にはノイズはないと仮定します.

まずは,その物体情報を格納するObject構造体を定義しましょう.
 typedef struct{
      int index;
      Position position;
      ColorRGB color;
      double radius;
      double weight;
 } Object;
indexは物体の番号を表すものとします.

get_object_position関数を用いて,1番目の物体の位置情報を取得できます.
 Position temp;
 temp = get_object_position(0);
ここで,関数の引数0は1番目の物体を意味します.
get_object_position関数を用いて,object_index番目の物体の位置情報を取得できます.
 Position get_object_position(int object_index);
例えば,引数0は1番目の物体を意味します.

同様にして,色,半径,重量は以下で取得できます.
 object.color = get_object_color_rgb(0);
 object.radius = get_object_radius(0);
 object.weight = get_object_weight(0);
同様にして,色,半径,重量を以下の関数で取得できます.
 ColorRGB get_object_color_rgb(int object_index);
 double get_object_radius(int object_index);
 double get_held_object_weight();

ただし,これらのセンサ値にはノイズが含まれています.
ただし,重量値は物体を把持しているときのみ取得可能です.

例えば,誤差の大きな位置をアームの目標位置としてしまうと,その後の把持動作に失敗してしまいます.

このノイズを除去するために,MEASUREMENT_STEP回センサ値を取得して,データを平均化しています.

まず,位置を初期化します.
 object.position.x = 0;

ループ中で,MEASUREMENT_STEP回,センサデータを加算します.
 object.position.x += temp.x

そして,MEASUREMENT_STEP + 1回目のループで,それを計測回で除算することで,比較的正確な平均値を得ます.
 object.position.x /=  MEASUREMENT_STEP;

y軸方向も同様です.

*把持動作と重量情報の取得 [#m423d4e9]
MEASUREMENT_STEP + 2回目以降のループでは,取得した位置情報を元に,その物体の重量を計測します.

ループの中で,取得した位置情報を元に,その物体の重量を計測します.
~
この処理は煩雑になるため,また,後で繰り返し使えるように,
 approach_and_weight(object.position, get_arm_state(), get_gripper_state());
 void approach_and_weigh(Object *object, int n);
に関数化しています.
~
ここでのnは重量計測する物体の番号です.

この関数には,アームとグリッパの状態も渡しています.
アームが動いているときに指令を与えてもアームの動作の邪魔になるだけなので,
 if(get_arm_state() == ARM_STATE_STOP)
の条件をつけて,アームが止まっているときに限りapproach_and_weigh関数が処理されるようにします.

まず,アームが動いているときに指令を与えてもアームの動作の邪魔になるだけなので,
 if(arm_state != ARM_STATE_STOP) return;
の条件をつけて,以降の処理をアームが止まっているときに限ります.
approach_and_weigh関数では,課題の状態遷移に応じた場合分けをしています.
~
今回,位置測定 (MEASURE),アームの移動 (APPROACH),把持 (PICKUP),重量測定と解放 (RELEASE),終了 (FINISH) の5つの状態を仮定します.
~
現在どの状態にあるのかはtask_stateに書いておきます.
~
task_stateをわかりやすくするために,プログラムの上に,enum型としてのTaskState型を次のように定義しています.
 typedef enum{
   MEASURE,
   APPROACH,
   PICKUP,
   RELEASE,
   FINISH
 } TaskState;

次に,この関数ではアームは移動,把持,重量測定と解放の三つの動作をする必要があるので,その三つの場合に分けます.

現在,どの処理段階にあるのかはtask_stateに書いておきます.

はじめ,
 TaskState task_state = APPROACH;
 TaskState task_state = MEASURE;
であるので,
 set_command_move_arm_to(object.position);
 object[n].index = n + 1;
 object[n].position = get.object_position(n);
で(n + 1)番目の物体の位置を取得します(今回はn = 0なので,1番目).

次に,APPROACHに状態遷移し,
 set_command_move_arm_to(object[n].position);
で,物体位置までアームを移動させます.

そして,PICKUPでは,
 set_command_pick_up_object();
で物体を把持します.

最後に,RELEASEでは重量を測定して,と行きたいところですが,上記の把持動作は失敗することがあります.
最後に,RELEASEでは重量を測定して,物体を離します.

グリッパの状態を確認して,物体を把持していなければ,再試行します.
 if(gripper_state == GRIPPER_STATE_EMPTY){
      task_state = PICKUP;
 }
状態がFINISHになると,main関数で物体情報を表示し,whileループをbreakすることで処理を終了します.

把持していれば,重量を測定して,物体を離します.
 if(gripper_state == GRIPPER_STATE_HOLDING){
      weight = get_hold_object_weight();
      set_command_release_object();
      task_state = STOP;
      return(weight);
 }
このような,状態に応じた場合分けをすることで,状態ごとの処理がわかりやすくなり,見通しの良いプログラムになります.

STOPの処理には何も書いてありませんので,ロボットは停止します.

*練習 [#kc380b0f]
5個すべての物体の重量を計測・表示するプログラムを作成してください.

ただし,重量のセンサ値はガウスノイズを含んでいるので,ノイズ除去をしてください.

**ヒント [#w391efea]
approach_and_weight関数が重量を返したときに,次の物体の処理へ進めましょう.
状態がFINISHになったときに,次の物体の処理へ進めましょう.

*課題 [#wace50e8]
N個すべての物体の位置・重量・色・半径をファイル出力するプログラムを作成してください.
N個すべての物体の位置・重量・色・半径,ならびに,課題の遂行にかかった時間をファイル(txtやcsv)出力するプログラムを作成してください.

各センサ値はガウスノイズを含んでいるので,ノイズ除去後の値をtxtファイルやcsvファイルなどに書き出してください.
-物体数Nはプログラム実行後にキーボード入力します.
-アームの軌道をグラフ化してください.
~
(物体位置はランダムに決まるので,一回の実行結果を提出してください)
-このグリッパは把持に失敗することがあります.そのときに再度把持をするようにしてください.
-適宜コメントを入れたり,関数化したりして,他人にもわかりやすいプログラムになるように心がけてください.全くコメントのないものは減点します.
-他人のプログラムを写したことが判明した場合は,両者とも0点になります.課題内容に対応していないプログラムにも点をつけません.

物体数Nはプログラム実行後にキーボード入力します.

**発展課題1 [#oa9e0c6d]
上記の課題中のアームの軌道をグラフ化してください.

アームの位置の取得には,関数
 get_arm_position()
**ヒント [#v54df241]
シミュレーションの経過時間の取得には,関数
 double get_system_time_in_sec();
を用います.

グラフ描画ツールには例えば,gnuplot,R,python,Microsoft Excel,OpenOffice Calcがあります.

**発展課題2 [#c35f472d]
最短で移動を終了させるためにはどのようにすればよいか考え,可能ならばプログラムを作成してください.

*発展課題 [#c35f472d]
より短い(最短の)アームの移動で課題を終了させるためにはどのようにすればよいか考え,そのプログラムを作成してください.
~
提案した発展課題プログラムの実行時間と,課題プログラムの実行時間を比較し,どれだけ実行時間を短縮できたかを示してください.
~
この課題はセールスマン巡回問題と関連し,難問ですので,後回しでもよいです.

** 提出物 [#k17aaedc]
提出物一式を入れるファイルの名前は学生番号にしてください.
- プログラムファイル(TAがUSBメモリで回収)
- 状態遷移図(手書きでもプリントアウトでもOK)
提出物一式を入れるフォルダの名前は学生番号にしてください(ログインIDではない!).
- 課題プログラムファイル
- 出力した物体・時間情報ファイル
- アーム軌道の図
- 発展課題プログラムファイル(発展課題)
- 高速化のアイデアを書いたテキスト(発展課題)

** 提出日 [#lc267e66]
次の授業中に提出してもらいます.
そのときに提出プログラムが正しく実行できていることをTAが直接確認します.
2週間後の24:00までに,上記を入れたフォルダをzipに圧縮したものをCLEで提出してください.

- 1・2組:1/20
- 3・4組:1/16
- 1・2組:1/19
- 3・4組:1/9


トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS