はじめに
こんにちは前回投稿の続きをやろうと思います。
脳死で組んだので香ばしいコードになってしまいましたがなんとなく動いてるのでヨシ!とします。
こんな感じで動きます。
なんちゃってロボットビジョン
— もととけ (@mototoke) May 3, 2020
作業用BGMめっちゃ入ってて笑う pic.twitter.com/hoFvPjVP82
開発環境
OS:windows10
.net framework4.7.2
使用ライブラリ:
OpenCvSharp4.Windows 4.3.0.20200421
HomographySharp 1.5.0
Newtonsoft.Json 12.0.3
必要な値を設定する
まずはロボットビジョンを行う為の設定をしていきます。
設定画面はこんな感じです。
キャリブレーションファイルを設定

キャリブレーションファイルのパスを設定します。
キャリブレーションファイルについてはこちら
射影変換用の4点を設定する

画像座標系からロボット座標系に変換する為のパラメータ各4点を設定します。
各4点は前回の値を使います。
高さ情報の設定

今回は緑のブロックをつかみに行きます。
少し分かりづらいですがロボット座標系のZ軸=0でサクションカップを付けた状態では
アーム先端と台座上面がだいたい同じ高さにきます。
台座の高さ幅が78mmくらいなのでZ軸=-78で床に先端が付きます。
一方、今回の緑ブロックの高さは25mmです。
サクションカップでくっつけようと思うとZ軸=-53あたりを指定するといい感じにくっつきます。
なのでZ軸=-53を計算させようってだけですね。
緑のブロックを見つける
動画にある緑のブロックを見つけます。
カメラ撮影画像をHSV変換し、HSVで閾値きってマスクをかけます。
私の環境では以下の値でだいたい緑のブロックを検出できます。
これは撮像環境によってものすごく値が変動するので場所を頻繁に移すような場合は照明環境が必要になります。
// 撮影画像の読み取りcamera.Read(src);if(src.Empty())returnnull;Matcalib=newMat();// 歪み補正Cv2.Undistort(src,calib,mtx,dist);// 画像処理vartmp=newMat();// OpenCVのカラーの並びに変換Cv2.CvtColor(calib,tmp,OpenCvSharp.ColorConversionCodes.RGB2BGR);// BGR画像をHSV画像に変換varhsv=newMat();Cv2.CvtColor(tmp,hsv,OpenCvSharp.ColorConversionCodes.BGR2HSV);// inRange関数で範囲指定2値化 -> マスク画像として使うvarmsk=newMat();Cv2.InRange(hsv,newScalar(obj.HueMin,obj.SaturationMin,obj.ValueMin),newScalar(obj.HueMax,obj.SaturationMax,obj.ValueMax),msk);持っていく場所を設定する
つかんだ緑のブロックを置く場所を設定します。
ロボットアームの届く範囲で設定します。
今回はmarker6の場所に設定しました。Z座標は良い感じにおける高さを設定します。
作業をコードで書く
上記の設定で緑のブロックの位置は分かるようになりました。
次は実際の動きをコーディングしていきます。
コメントでわかると思いますが動きはこんな感じです。
0,カメラを撮影して緑のブロック位置を検出
--- ロボットの動き ---
1,緑のブロックの上まで移動
2,緑のブロック上面までアームを下げる
3,吸引ONしてブロックをくっつける
4,そのまま上に持ち上げる
5,持っていく場所に移動する
6,吸引OFFしてブロックを放す(置く)
7,ブロック置いたところからちょっと上に上がる
/// <summary>/// 作業を開始します/// </summary>publicvoidWorkStart(doubletarget_x,doubletarget_y,SettingsObjobj){// 作業をクリアDobotDll.SetQueuedCmdClear();// コマンド開始DobotDll.SetQueuedCmdStartExec();// 現在位置を取得varpose=GetCurrentPose();// 対象の上部まで移動(Z座標は適当)varcmdIndex=ptp((byte)2,(float)target_x,(float)target_y,(float)0.0,pose.rHead);// 対象物のZ座標計算varobject_z=obj.PedestalZ+obj.ObjectHeight;// 対象の位置まで下がるcmdIndex=ptp((byte)2,(float)target_x,(float)target_y,(float)object_z,pose.rHead);// 下がったらサクションカップONしてつかむDobotDll.SetEndEffectorSuctionCup(true,true,true,refcmdIndex);// いったん上に持ち上げるcmdIndex=ptp((byte)2,(float)target_x,(float)target_y,(float)0.0,pose.rHead);// 持っていく場所に移動cmdIndex=ptp((byte)2,(float)obj.PlacePoseXCoordinate,(float)obj.PlacePoseYCoordinate,(float)obj.PlacePoseZCoordinate,pose.rHead);// 下がったらサクションカップOFFして放すDobotDll.SetEndEffectorSuctionCup(false,false,false,refcmdIndex);// 上がって終わりcmdIndex=ptp((byte)2,(float)obj.PlacePoseXCoordinate,(float)obj.PlacePoseYCoordinate,(float)0.0,pose.rHead);// コマンド終了DobotDll.SetQueuedCmdStopExec();}あとはこれを動かすだけです。
問題点
それなりに設定すれば動画のようにわりに動きはしますが
今回作ったプログラムは色々な問題があります。
・精度が悪い
→これはロボットの精度ではなく、画像処理の方です。
撮影環境にも影響をうけますがエイヤで緑ブロック検出を書いたので綺麗に検出できる時と一部欠けて検出できる場合があります。なので毎回絶対にブロックの中心位置にアームの先端を持っていきたいとかの場合はもうちょっと頑張らないといけません。
・クローズループ制御、フィードバック制御がない
→今回は撮影した1枚で取得した座標にいきなりロボットを動かしてます。
普通はロボットアームを動かしつつ、カメラでアーム位置を見ながらちゃんとブロック位置まで行けてるか見たりするような制御が必要だと思います。アーム先端にカメラをつけるとかもありだと思います。というかもっと精度が必要な場合は必須ですよね。
・ちゃんとつかめたかどうかわからない
→上と似た感じですが今回はつかめたかどうか確かめずに移動させています。
だいたいこういうのはちゃんと掴めてるかどうか別の固定カメラとか使ってやるみたいですね。それがあればつかんだ位置のずれも検出できそうです。
他にも色々問題はあると思いますが書き上げるとキリがないのでこれくらいにします。
もう少し改善したいところですが力尽きたので気が向いたらにします。
検出のところはDLに置き換えてみようかなぁ。
ソースはこちらに
参考URL・出典元
https://www.robotlab.com/dobot-customers-download
https://teratail.com/questions/20557