本文導讀
上節(jié)課程我們講述了如何建立Delta并聯(lián)機械手正逆解,本節(jié)課程我們主要講解如何通過C#語言開發(fā)正運動Delta并聯(lián)機械手視覺流水線同步分揀的視覺部分。
VPLC711硬件介紹
VPLC711是正運動推出的一款基于x86平臺和Windows操作系統(tǒng)的高性能機器視覺EtherCAT運動控制器,具備強大的運算能力和靈活性。它具有出色的實時性能和多路高速硬件輸入與多路高速PSO輸出,能夠精準控制多軸同步運動,并與外部設(shè)備實現(xiàn)多協(xié)議的高速通信。
VPLC711支持多種硬件接口和通信協(xié)議,方便與其他設(shè)備的連接和集成。除此之外,VPLC711還具備視覺處理功能,能夠?qū)崟r處理圖像數(shù)據(jù),實現(xiàn)視覺檢測、測量和定位等應用。
VPLC711內(nèi)置Windows運動控制實時內(nèi)核MotionRT7,形成一種開放式IPC形態(tài)實時軟控制器/軟PLC,為用戶提供靈活集成的運動控制+視覺一體化解決方案。
VPLC711硬件參數(shù)
1.采用x86高性能CPU,EtherCAT可支持1ms 64軸同步運行;
2.板載RS232,RS485,EtherNet*5,EtherCAT,USB3.0*4硬件接口;
3.板載20DI,其中4個高速色標鎖存,2組高速單端編碼器;
4.板載20DO,其中4個高速單端脈沖軸,4組高速PWM;
5.支持DVI-D,HDMI顯示,支持雙網(wǎng)口不同IP設(shè)置。
想要了解更多關(guān)于VPLC711的詳情介紹,可以點擊“x86平臺實時Windows機器視覺EtherCAT運動控制器VPLC711”查看。
一、C#語言進行Delta并聯(lián)機械手的開發(fā)之運動庫和視覺庫的添加
1.在VS2010菜單“文件”→“新建”→“項目”,啟動創(chuàng)建項目向?qū)А?/p>
2.選擇開發(fā)語言為“Visual C#”和.NET Framework 4以及Windows窗體應用程序。
3.找到廠家提供的光盤資料里面的C#函數(shù)庫,路徑如下(32位庫為例)。
1)進入廠商提供的光盤資料找到“04PC函數(shù)”文件夾,并點擊進入。
2)選擇“函數(shù)庫2.1”文件夾。
3)選擇“Windows平臺”文件夾。
4)根據(jù)需要選擇對應的函數(shù)庫,這里選擇32位庫。
5)解壓C#壓縮包,里面有C#對應的函數(shù)庫。
6)函數(shù)庫具體路徑如下。
4.將廠商提供的C#庫文件以及相關(guān)文件復制到新建的項目中(注意這里面的PC函數(shù)庫默認提供的是運動庫,如果使用視覺功能還需要獲取視覺庫,視覺庫可以找廠商的相關(guān)銷售或技術(shù)人員獲取)。
1)將Zmcaux.cs(運動庫)和Zvision.cs(視覺庫)文件復制到新建的項目里面中。
2)將zauxdll.dll、zmotion.dll和zvision.dll文件放入bindebug文件夾中。
5.用vs打開新建的項目文件,在右邊的解決方案資源管理器中點擊顯示所有文件,然后鼠標右擊Zmcaux.cs與 Zvision.cs文件,點擊包括在項目中。
6.雙擊Form1.cs里面的Form1,出現(xiàn)代碼編輯界面,在文件開頭寫入using cszmcaux,using ZVision并聲明控制器句柄g_handle。
二、PC函數(shù)介紹
1.PC函數(shù)手冊可在光盤資料查看,具體路徑如下。
2.鏈接控制器,獲取鏈接句柄。
3.相機掃描接口說明。
4.相機采集圖像。
5.用圖像創(chuàng)建模板。
6.形狀匹配并輸出輪廓狀態(tài)。
三、C#例程建設(shè)之視覺相機標定與形狀匹配
1.視覺配置文件的下載
因為正運動的視覺算法是在控制器里面執(zhí)行的,所以上位機開發(fā)前需要先在控制器里面定義好視覺處理的相關(guān)變量。正運動控制器里面的視覺變量統(tǒng)一使用ZVOBJECT來修飾,我們可以新建一個.bas的文件,然后輸入“GLOBAL ZVOBJECT ZVOBJ(1000)”進行視覺變量數(shù)組的定義,保存后通過上位機接口在上位機系統(tǒng)初始化的時候把這個.bas文件下載到控制器即可。
//下載相關(guān)腳本到控制器,進行視覺變量的定義 string BasPath = ""; BasPath = string.Format(@"{0}", Application.StartupPath) + @"Icon視覺變量定義.bas"; //.bas文件下載到控制器 zmcaux.ZAux_BasDown(g_Handle,BasPath,0);
2.相機標定
1)相機標定操作步驟
2)相關(guān)功能代碼
/************************************************************************************ '任務(wù)編號:無 '函數(shù)功能:視覺提取標定板上實心圓的像素坐標,獲取標定板圓心的像素坐標的矩陣 'Input:無 'Output:無 '返回值:無 **************************************************************************************/ private void GetPictureMark() { float[] temp_thresh = new float[2]; int Err = 0; //提取圓心圖像坐標,得到像素坐標矩陣Inppts Err = Zvision.ZV_CALGETSCAPTS(form.g_Handle, grabimg, inppts, Convert.ToUInt32(C_CalibThresh.Text), Convert.ToUInt32(C_CalibPolar.Text), Convert.ToUInt32(C_CalibMinArea.Text), Convert.ToUInt32(C_CalibMaxArea.Text)); int[] inppts_info = { 0, 0, 0 }; //獲取矩陣行數(shù)和列數(shù),行數(shù)表示識別到實心圓的個數(shù) Err = Zvision.ZV_MATINFO(form.g_Handle, inppts, inppts_info); int row, col; row = (int)inppts_info[0]; col = (int)inppts_info[1]; //視覺識別到9個實心圓和標定板的實心圓數(shù)目一致 if (row == 9) { Err = Zvision.ZV_GRAYTORGB(form.g_Handle, grabimg, calibshowimg); //inppts排好序輸出排好序的像素坐標矩陣ppts Err = Zvision.ZV_CALGETPTSMAP(form.g_Handle, inppts, ppts, wpts, Convert.ToSingle(C_CalibDis.Text)); Err = Zvision.ZV_MATINFO(form.g_Handle, ppts, inppts_info); row = (int)inppts_info[0]; col = (int)inppts_info[1]; if (row >= 9) { uint i; DataGridView1.Rows.Clear(); for (i = 0; i < row; i++) { //像素坐標在WinFrom的UI界面是顯示出來 string[] tempstr = new string[4]; float[] outvalue = { 0, 0 }; Zvision.ZV_MATGETROW(form.g_Handle, wpts, i, 2, outvalue); tempstr[2] = "0"; tempstr[3] = "0"; Zvision.ZV_MATGETROW(form.g_Handle, ppts, i, 2, outvalue); tempstr[0] = outvalue[0].ToString(); tempstr[1] = outvalue[1].ToString(); DataGridView1.Rows.Add(tempstr); //在原圖是畫出識別到的實心圓,并標記,然后在Ui界面上顯示出圖像 Zvision.ZV_MARKER(form.g_Handle, calibshowimg, outvalue[0], outvalue[1], 0, 40, 0, 255, 0); Zvision.ZV_TEXT(form.g_Handle, calibshowimg, i.ToString(), outvalue[0] - 20, outvalue[1] - 20, 40, 0, 255, 0); Zvision.ZV_LATCHCLEAR(form.g_Handle, 0); Zvision.ZV_LATCHSETSIZE(form.g_Handle, 0, Convert.ToUInt32(pictureBox5.Width), Convert.ToUInt32(pictureBox5.Height)); pictureBox5.Image = Zvision.ZV_LATCH(form.g_Handle, calibshowimg, 0); } } else { MessageBox.Show("提取mark點失敗!", "提示"); } } else { MessageBox.Show("提取mark點失敗!", "提示"); } } /************************************************************************************ '任務(wù)編號:無 '函數(shù)功能:相機標定 'Input:無 'Output:無 '返回值:無 '備注:計算像素坐標和世界坐標的轉(zhuǎn)換關(guān)系 '備注:標定板圓心的世界坐標可以通過示教的方式獲取 **************************************************************************************/ private void CamCalib() { //矩陣行和式 uint row, col; row = 9; col = 2; //從Ui界面上獲取世界坐標的矩陣數(shù)據(jù) float[] wPontsValue = new float[row * col]; for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { wPontsValue[col * i + j] = float.Parse(DataGridView1.Rows[i].Cells[j + 2].Value.ToString()); } } //重新生成世界坐標矩陣 Zvision.ZV_MATGENDATA(form.g_Handle, wpts, row, col, wPontsValue); //圖像坐標矩陣數(shù)據(jù) float[] pPontsValue = new float[row * col]; for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { pPontsValue[col * i + j] = float.Parse(DataGridView1.Rows[i].Cells[j].Value.ToString()); } } //重新生成圖像坐標矩陣 Zvision.ZV_MATGENDATA(form.g_Handle, ppts, row, col, pPontsValue); float[] outimginfo = { 0, 0, 0, 0, 0 }; //獲取圖像信息 Zvision.ZV_IMGINFO(form.g_Handle, grabimg, outimginfo); //進行相機標定 Zvision.ZV_CALCAM(form.g_Handle, ppts, wpts, ZmotionCalPara, (ushort)outimginfo[0], (ushort)outimginfo[1], (uint)Convert.ToInt32(C_CalibType.Text)); float[] outcaliberror = { 0, 0, 0 }; //獲取標定誤差 Zvision.ZV_CALERROR(form.g_Handle, ZmotionCalPara, ppts, wpts, outcaliberror); //平均誤差小于0.5內(nèi)算是優(yōu),0.5--1為良,1--1.5為一般,1.5以上建議重新標定 if (outcaliberror[0] >= 1.5) { MessageBox.Show("標定平均誤差過大請重新標定"); } else { //保存標定參數(shù) Zvision.ZV_CALWRITE(form.g_Handle, ZmotionCalPara, form.CalFileDir); } }
3)形狀匹配后根據(jù)標定系數(shù)可獲得匹配到目標點的實際世界坐標。
3.形狀匹配
1)形狀匹配操作步驟
2)相關(guān)功能代碼
/************************************************************************************ '任務(wù)編號:無 '函數(shù)功能:通過相機采集圖像 'Input:無 'Output:無 '返回值:無 **************************************************************************************/ public Image CameAcquisition() { float Temp = 0; Image ImageBuff = null; Zvision.CAM_COUNT(form.g_Handle, ref Cam_Num); //選擇相機 Zvision.CAM_SEL(form.g_Handle, 0); //采集一張圖像 Zvision.CAM_TRIGGER(form.g_Handle); //更新皮帶位置 zauxBrr = zmcaux.ZAux_Direct_GetMpos(form.g_Handle, form.ConveyorAxisId, ref Temp); form.BeltMpos = Temp; //從相機緩存取里面獲取剛剛采集的圖像 Zvision.CAM_GET(form.g_Handle, grabimg, 0); //RGB轉(zhuǎn)灰度 Zvision.ZV_RGBTOGRAY(form.g_Handle, grabimg, grabimg); //鎖存數(shù)據(jù)清空 Zvision.ZV_LATCHCLEAR(form.g_Handle, 0); //設(shè)置鎖存的大小為圖片顯示控件的大小 Zvision.ZV_LATCHSETSIZE(form.g_Handle, 0, Convert.ToUInt32(ImgShow1.Width), Convert.ToUInt32(ImgShow1.Height)); //獲取鎖存中的圖像 ImgShow1.Image = Zvision.ZV_LATCH(form.g_Handle, grabimg, 0); //導出獲取到的圖像信息 return ImgShow1.Image; } /************************************************************************************ '任務(wù)編號:無 '函數(shù)功能:創(chuàng)建形狀模版 'Input:無 'Output:無 '返回值:無 **************************************************************************************/ private void CreateTemplate() { //通過圖像創(chuàng)建模板 Zvision.ZV_SHAPECREATERE(form.g_Handle, SubImg, mod_re, shape_mod, Convert.ToInt32(modStartAngle.Text), Convert.ToInt32(modEndAngle.Text), Convert.ToInt32(modMinScale.Text), Convert.ToInt32(modMaxScale.Text), Convert.ToUInt32(modThresh.Text), Convert.ToUInt32(modNum_Level.Text), Convert.ToUInt32(modPt_Reduce.Text), Convert.ToInt32(modAngle_Step.Text), Convert.ToInt32(modScale_Step.Text), 20); //獲取模板輪廓 Zvision.ZV_SHAPECONTOURS(form.g_Handle, shape_mod, modconlist, 0); //灰度轉(zhuǎn)rgb Zvision.ZV_GRAYTORGB(form.g_Handle, cutimg, modimg); float[] getimginfo = { 0, 0, 0, 0, 0 }; //圖像信息 Zvision.ZV_IMGINFO(form.g_Handle, modimg, getimginfo); //剛性變換 Zvision.ZV_GETRIGIDVECTOR(form.g_Handle, mod_matrigid, 0, 0, 0, getimginfo[0] / 2, getimginfo[1] / 2, 0); //仿射變換 Zvision.ZV_CONTAFFINE(form.g_Handle, modconlist, mod_matrigid, tsmodconlist); //繪制輪廓到圖像上 Zvision.ZV_CONTLIST(form.g_Handle, modimg, tsmodconlist, 0, 255, 0, 1); //清空控制器的鎖存緩沖區(qū) Zvision.ZV_LATCHCLEAR(form.g_Handle, 1); //設(shè)置鎖存緩沖區(qū)大小,設(shè)置鎖存通道大小和顯示控件picgbox控件一樣大 Zvision.ZV_LATCHSETSIZE(form.g_Handle, 1, Convert.ToUInt32(pictureBox2.Width), Convert.ToUInt32(pictureBox2.Height)); //顯示圖像 pictureBox2.Image = Zvision.ZV_LATCH(form.g_Handle, modimg,1); //截取圖像顯示到ui上 pictureBox3.Image = pictureBox2.Image; //清空控制器的鎖存緩沖區(qū) Zvision.ZV_LATCHCLEAR(form.g_Handle, 1); //設(shè)置鎖存緩沖區(qū)大小 Zvision.ZV_LATCHSETSIZE(form.g_Handle, 1, Convert.ToUInt32(pictureBox4.Width), Convert.ToUInt32(pictureBox4.Height)); //設(shè)置鎖存通道大小和picgbox控件一樣大 //顯示圖像 pictureBox4.Image = Zvision.ZV_LATCH(form.g_Handle, modimg, 1);//截取圖像顯示到Ui上 } /************************************************************************************ '任務(wù)編號:無 '函數(shù)功能:形狀匹配,在圖像是查找模板 'Input:無 'Output:無 '返回值:無 **************************************************************************************/ public Image ShapeFind() { //結(jié)果數(shù)組清空 for (int m = 0; m < 10; m++) { for (int n = 0; n < 5; n++) { form.VisionRst[m, n] = 0; } } //形狀模板匹配 Zvision.ZV_SHAPEFIND(form.g_Handle, shape_mod, grabimg, find_outlist, Convert.ToInt32(findminscore.Text), Convert.ToUInt32(findnum.Text), Convert.ToInt32(findmindis.Text), Convert.ToInt32(findthresh.Text), Convert.ToUInt32(findaccuracy.Text), Convert.ToInt32(findspeed.Text), Convert.ToUInt32(findpolar.Text)); int[] mat_info = { 0, 0, 0 }; //輸出信息 Zvision.ZV_MATINFO(form.g_Handle, find_outlist, mat_info); //生成繪制彩圖 Zvision.ZV_GRAYTORGB(form.g_Handle, grabimg, show_img); //匹配到目標了 if ((int)mat_info[0] > 0) { for (uint i = 0; i < (int)mat_info[0]; i++) { float[] rst_value = { 0, 0, 0, 0, 0 }; Zvision.ZV_MATGETROW(form.g_Handle, find_outlist, i, 5, rst_value); rstScore.Text = rst_value[0].ToString(); rstPixX.Text = rst_value[1].ToString(); rstPixY.Text = rst_value[2].ToString(); rstAngle.Text = rst_value[3].ToString(); rstScale.Text = rst_value[4].ToString(); //分數(shù)篩選 if (rst_value[0] >= form.VisionScore) { //輸出結(jié)果 for (int k = 0; k < 5; k++) { form.VisionRst[i, k] = rst_value[k]; } float[] outworldpos = { 0, 0 }; //像素轉(zhuǎn)世界坐標 Zvision.ZV_CALTRANSW(form.g_Handle, ZmotionCalPara, rst_value[1], rst_value[2], outworldpos); rstWorldX.Text = outworldpos[0].ToString(); rstWorldY.Text = outworldpos[1].ToString(); //輸出世界坐標 for (int k = 1; k < 3; k++) { form.VisionRst[i, k] = outworldpos[k - 1]; } //顯示匹配結(jié)果 string RstWorldStr; RstWorldStr = "OK_坐標(" + rstWorldX.Text + "," + rstWorldY.Text + ")"; Zvision.ZV_TEXT(form.g_Handle, show_img, RstWorldStr, rst_value[1], rst_value[2], 50, 0, 255, 0); //計算剛性變換矩陣 Zvision.ZV_GETRIGIDVECTOR(form.g_Handle, find_matrigid, 0, 0, 0, rst_value[1], rst_value[2], rst_value[3]); //輪廓序列仿射變換 Zvision.ZV_CONTAFFINE(form.g_Handle, modconlist, find_matrigid, tsmodconlist2); //繪制輪廓數(shù)列 Zvision.ZV_CONTLIST(form.g_Handle, show_img, tsmodconlist2, 0, 255, 0, 1); Zvision.ZV_TEXT(form.g_Handle, show_img, i.ToString(), rst_value[1], rst_value[2], 40, 255, 0, 0); } } } else { //顯示匹配結(jié)果 string RstWorldStr; RstWorldStr = "NG"; Zvision.ZV_TEXT(form.g_Handle, show_img, RstWorldStr, 20, 120, 100, 0, 255, 0); } //清空緩沖區(qū)顯示圖片 Zvision.ZV_LATCHCLEAR(form.g_Handle, 0); Zvision.ZV_LATCHSETSIZE(form.g_Handle, 0, Convert.ToUInt32(ImgShow1.Width), Convert.ToUInt32(ImgShow1.Height)); //設(shè)置鎖存通道大小和picgbox控件一樣大 ImgShow1.Image = Zvision.ZV_LATCH(form.g_Handle, show_img, 0);//截取圖像顯示到圖像上 return ImgShow1.Image; }
本次,正運動技術(shù)C#之Delta并聯(lián)機械手的視覺相機標定與形狀匹配,就分享到這里。
更多精彩內(nèi)容請關(guān)注“正運動小助手”公眾號,需要相關(guān)開發(fā)環(huán)境與例程代碼,請咨詢正運動技術(shù)銷售工程師。
本文由正運動技術(shù)原創(chuàng),歡迎大家轉(zhuǎn)載,共同學習,一起提高中國智能制造水平。文章版權(quán)歸正運動技術(shù)所有,如有轉(zhuǎn)載請注明文章來源。
審核編輯 黃宇
-
運動控制器
+關(guān)注
關(guān)注
2文章
408瀏覽量
24809 -
機器視覺
+關(guān)注
關(guān)注
162文章
4405瀏覽量
120731 -
機械手
+關(guān)注
關(guān)注
7文章
339瀏覽量
29751
發(fā)布評論請先 登錄
相關(guān)推薦
評論