曰本美女∴一区二区特级A级黄色大片, 国产亚洲精品美女久久久久久2025, 页岩实心砖-高密市宏伟建材有限公司, 午夜小视频在线观看欧美日韩手机在线,国产人妻奶水一区二区,国产玉足,妺妺窝人体色WWW网站孕妇,色综合天天综合网中文伊,成人在线麻豆网观看

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

PCIe EtherCAT實時運動控制卡PCIE464的CAD導(dǎo)圖與刀向跟隨應(yīng)用

正運動技術(shù) ? 來源:正運動技術(shù) ? 作者:正運動技術(shù) ? 2025-05-08 14:42 ? 次閱讀

一.硬件介紹

PCIE464運動控制卡是正運動推出的一款EtherCAT總線+脈沖型、PCIE接口式的運動控制卡,可選6-64軸運動控制,支持多路高速數(shù)字輸入輸出,可輕松實現(xiàn)多軸同步控制和高速數(shù)據(jù)傳輸。

wKgZPGgcUkmAKA_zAAJpkhm7bi0398.png

PCIE464運動控制卡適合于多軸點位運動、插補運動、軌跡規(guī)劃、手輪控制、編碼器位置檢測、IO控制、位置鎖存等功能的應(yīng)用。PCIE464運動控制卡適用于3C電子加工、檢測設(shè)備、半導(dǎo)體設(shè)備、SMT加工、激光加工、光通訊設(shè)備、鋰電及光伏設(shè)備、以及非標自動化設(shè)備等高速高精應(yīng)用場合。

wKgZPGgcUkmANiqIAANvpLLwIRY040.png

PCIE4系列控制卡的應(yīng)用程序可以使用VC,VB,VS,C++,C#等軟件開發(fā),程序運行時需要動態(tài)庫zmotion.dll,調(diào)試時可以將RTSys軟件同時連接控制器,從而方便調(diào)試、方便觀察。

wKgZO2gcUkqAEX14AAD97IAHdVM762.png

PCIE464產(chǎn)品視頻介紹可點擊→“【EtherCAT同步周期快至100us】超高實時性PCIe EtherCAT控制卡PCIE464”查看。

更多關(guān)于PCIE464的詳情介紹,點擊“PCIE464 — 高速高精,超高實時性的PCIe EtherCAT實時運動控制卡”查看。


二.接線參考

1.IN數(shù)字量輸入接口

數(shù)字輸入分布在J400(IN0-IN7)和X400(IN8-IN39)信號接口中。

wKgZPGgcUkqAEWcKAAGNseUtDZ0196.png

2.OUT數(shù)字量輸出接口

數(shù)字輸出分布在J400(OUT0-7)和X400(OUT8-OUT39)信號接口中。

wKgZO2gcUkqABdrUAAHcGLxmeDQ236.png

3.單端編碼器及單端脈沖接線

wKgZPGgcUkqAL1brAAD_3blXtNk263.png

單端脈沖接線圖

wKgZO2gcUkuASuvwAADtk54wOTE786.png

差分脈沖接線圖

wKgZPGgcUkuAFW97AADRCWK_4dI107.png

單端編碼器接線圖

wKgZO2gcUkuARhTxAAE1UDn6qn0900.png

差分編碼器接線圖

注:PCIE464的J400接口中有一個差分脈沖軸接口和三個單端脈沖軸接口,兩個差分編碼器接口(其中一個與差分脈沖軸接口復(fù)用,取決于固件設(shè)定)和兩個單端編碼器接口,具體引腳定義參見PCIE464硬件手冊。

三.CAD解析及刀向跟隨計算技巧解釋

wKgZPGgcUkuANM85AAIt8vP_1Fs588.png

1.CAD圖紙解析

正運動技術(shù)提供開放的ZmotionCadEx庫,可導(dǎo)入DXF、Ai、Plt、Dst圖紙,可以生成運動坐標數(shù)據(jù)轉(zhuǎn)G代碼、zbasic運動指令、或直接PC函數(shù)執(zhí)行運動。

wKgZO2gcUkyAJDY6AARpicc-_fw614.png

2.刀向跟隨計算

刀向跟隨,是在插補運動的過程中,使非插補軸隨著插補運動的合成位移的變化而變化,從而實現(xiàn)在加工過程中,刀具始終處于合適的加工方向和位置的工藝。

非插補軸(如旋轉(zhuǎn)軸或獨立軸)能夠根據(jù)插補軸的合成位移實時調(diào)整,使刀具始終沿預(yù)定路徑或方向運動。例如,在砂輪磨削中,通過調(diào)整砂輪的角度,確保其與工件切向方向一致;在布料裁切中,通過調(diào)整刀具朝向,始終指向行進方向。

本例中通過計算小線段的向量方向,以3軸插補形式運行實現(xiàn),基本原理如下圖所示。

wKgZPGgcUkyAK9bBAAI-If7HOsI332.png

已知線段起點A坐標,終點B坐標,在起點A上做與X軸平行向量AC,通過數(shù)學計算得到向量AB與向量AC的夾角α,即線段AB與X軸正方向夾角。將夾角α與終點坐標XY做三軸插補來作為刀向跟隨。

在某些場合需要A軸先抬刀轉(zhuǎn)到加工角度,再下刀加工:比如加工矩形輪廓四條邊,那么應(yīng)該先抬刀轉(zhuǎn)到加工方向,再下刀進行加工,不應(yīng)在工件上轉(zhuǎn)刀,此時可以通過判斷線段的長度,小于設(shè)定值時三軸插補,大于設(shè)定值時應(yīng)抬刀→轉(zhuǎn)刀→下刀再加工。

本例中主要用到了下面幾個函數(shù)接口:

wKgZO2gcUkyALINLAAGw7qoqIao431.pngwKgZPGgcUkyAddAuAAG1damNV1g232.pngwKgZO2gcUk2AKjcWAAHNrsnrN_g067.png


四.MFC與C++編程實現(xiàn)

1.首先打開Visual Studio 2022,點擊創(chuàng)建新項目。

wKgZPGgcUk2AayP0AADiYUq9tCI769.png

2.選擇開發(fā)語言為“Visual C++”和程序類型“MFC應(yīng)用程序”。

wKgZO2gcUk2AT5aCAAFb2OqTa8A708.png

3.點擊下一步即可。

wKgZPGgcUk6AFPQAAAFGByboKaY848.png

4.選擇類型為“基于對話框”,下一步或者完成。

wKgZO2gcUk6Aflu6AAFZIuxrrj8723.png

5.前往正運動官網(wǎng)下載PC函數(shù)庫,路徑如下(本文采用64位函數(shù)庫為例)。

(1)進入官網(wǎng),選擇支持與服務(wù),打開下載中心選擇庫文件,就能找到所有的PC函數(shù)庫。

wKgZPGgcUk6AUWIzAAFv7N927HI592.png

(2)點擊下載Windows C++(64位),可按需求另存為想要保存的路徑下。

wKgZO2gcUk6AOQ-OAAEbA93HWCs239.png

(3)函數(shù)庫另存為具體路徑如下。

wKgZPGgcUk-ANOUAAAEp8wO9KEY169.png

(4)如需處理CAD圖,可與技術(shù)工程師聯(lián)系獲取ZmotionCadEx庫。

wKgZO2gcUk-ABC2rAACsrMchFrI699.png

6.將廠商提供的C++庫文件和相關(guān)頭文件復(fù)制到新建的項目里。

wKgZPGgcUk-ACuemAARicIY6GCQ735.png

7.在項目中添加靜態(tài)庫和相關(guān)頭文件。

(1)打開解決方案資源管理器,點擊顯示全部文件。

wKgZO2gcUk-AIR9IAALqmWAH2uo442.png

(2)選中.h與.lib文件,右鍵包括在項目中。

wKgZPGgcUlCAeX9MAAMsi0KpF8c287.png

8.聲明用到的頭文件。

wKgZO2gcUlCAX1CaAAIl3G2pWlg658.png

9.至此項目新建完成,可進行MFC項目開發(fā)。

五.查看PC函數(shù)手冊,熟悉相關(guān)函數(shù)接口

1.PC函數(shù)手冊也可以在正運動官網(wǎng)“支持與服務(wù)”→“下載中心”→“編程手冊”中找到。

wKgZPGgcUlCAVPvXAAML0KMocMc075.png

2.鏈接控制器,獲取鏈接句柄。

wKgZO2gcUlGAcMTSAAFzGU7AO_c975.png

3.查看ZmotionCadEx.h中關(guān)于CAD圖處理的函數(shù)接口。

wKgZPGgcUlGAN7kuAAWUfcLr3LY378.png


六.MFC實現(xiàn)CAD導(dǎo)入與刀向跟隨

1.例程界面如下。

wKgZO2gcUlGAQ3iQAALmJqY-sts477.png

2.初始化連接到控制器。

BOOLCZCadToolFollowDemoDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
//設(shè)置此對話框的圖標。當應(yīng)用程序主窗口不是對話框時,框架將自動
//執(zhí)行此操作
SetIcon(m_hIcon,TRUE);//設(shè)置大圖標
SetIcon(m_hIcon,FALSE);//設(shè)置小圖標
//TODO:在此添加額外的初始化代碼
m_DlgRect.SetRect(0,0,0,0);//初始化對話框大小存儲變量
CRectrect;
GetClientRect(&rect);//取客戶區(qū)大小
Old.x=rect.right-rect.left;
Old.y=rect.bottom-rect.top;
GetClientRect(&m_DlgRect);
GetDlgItem(IDC_PIC_VIEW)->GetClientRect(m_rcView);
/*--------------------控制器連接--------------------*/
charstr_ip[]="192.168.0.11";
intm_liv_ZmcMoveRe=ZMC_SearchAndOpenEth(str_ip,800,&g_handle);
if(ERR_OK!=m_liv_ZmcMoveRe)
{
if(MessageBox((L"控制器連接失敗,是否打開仿真版運行?"),(L"溫馨提示"),MB_YESNO|MB_ICONQUESTION)==IDYES)
{
if(!IsProccessRunning(_T("ZSimu.exe")))
{
ShellExecute(NULL,L"open",_T("\仿真器\ZSimu.exe"),NULL,NULL,SW_SHOWNORMAL);
}
else
{
HANDLEhProcessHandle;
ULONGnProcessID;
HWNDTheWindow;
TheWindow=::FindWindow(NULL,_T("ZSimu.exe"));
::GetWindowThreadProcessId(TheWindow,&nProcessID);
hProcessHandle=::OpenProcess(PROCESS_TERMINATE,FALSE,nProcessID);
::TerminateProcess(hProcessHandle,4);
ShowWindow(nProcessID);
}
strcpy_s(str_ip,"127.0.0.1");
m_liv_ZmcMoveRe=ZAux_OpenEth(str_ip,&g_handle);
if(m_liv_ZmcMoveRe!=ERR_OK)
{
Sleep(1000);
m_liv_ZmcMoveRe=ZAux_OpenEth(str_ip,&g_handle);
if(m_liv_ZmcMoveRe!=ERR_OK)
{
Sleep(1000);
m_liv_ZmcMoveRe=ZAux_OpenEth(str_ip,&g_handle);
if(m_liv_ZmcMoveRe!=ERR_OK)
{
Sleep(1000);
m_liv_ZmcMoveRe=ZAux_OpenEth(str_ip,&g_handle);
if(m_liv_ZmcMoveRe!=ERR_OK)
{
MessageBox(L"仿真器連接失敗(請給予仿真器權(quán)限)");
}
}
}
}
}
}
if(NULL!=g_handle)
{
SetTimer(0,1,NULL);
//初始化軸參數(shù)
for(inti=0;i<=3;?i++)
????????{
????????????ZAux_Direct_SetAtype(g_handle,?i,?0);//軸類型??虛擬軸
????????????ZAux_Direct_SetUnits(g_handle,?i,?10000);//脈沖當量?1000?脈沖為單位
????????????ZAux_Direct_SetSpeed(g_handle,?i,?100);//速度UNITS?/?S
????????????ZAux_Direct_SetAccel(g_handle,?i,?1000);//加速度
????????????ZAux_Direct_SetDecel(g_handle,?i,?1000);//減速度
????????????ZAux_Direct_SetSpeedRatio(g_handle,?i,?1);//速度比例
????????}
????????m_strSpeedRatio.Format(L"速度:%0.2f%%",?1?*?100.0);
????????UpdateData(false);
????}
????return?TRUE;??//?除非將焦點設(shè)置到控件,否則返回?TRUE
}

3.定時器獲取軸DPOS坐標用于顯示與刷新繪制圖像。

voidCZCadToolFollowDemoDlg::OnTimer(UINT_PTRnIDEvent)
{
//TODO:在此添加消息處理程序代碼和/或調(diào)用默認值
ZAux_GetModbusDpos(g_handle,3,gfarr_ListDpos);
if(gfarr_ListDposLast[0]!=gfarr_ListDpos[0]||gfarr_ListDposLast[1]!=gfarr_ListDpos[1]||gfarr_ListDposLast[2]!=gfarr_ListDpos[2])
{
GetDlgItem(IDC_EDIT_DPOS_X)->SetWindowText(L"X:"+FloatToCString(gfarr_ListDpos[0]));
GetDlgItem(IDC_EDIT_DPOS_Y)->SetWindowText(L"Y:"+FloatToCString(gfarr_ListDpos[1]));
GetDlgItem(IDC_EDIT_DPOS_A)->SetWindowText(L"A:"+FloatToCString(gfarr_ListDpos[2]));
gfarr_ListDposLast[0]=gfarr_ListDpos[0];
gfarr_ListDposLast[1]=gfarr_ListDpos[1];
gfarr_ListDposLast[2]=gfarr_ListDpos[2];
InvalidateRect(m_rcView,false);//刷新繪圖
}
CDialogEx::OnTimer(nIDEvent);
}

4.消息傳遞函數(shù)中響應(yīng)手動運動按鈕代碼。

BOOLCZCadToolFollowDemoDlg::PreTranslateMessage(MSG*pMsg)
{
//TODO:在此添加專用代碼和/或調(diào)用基類
//MFC界面按鈕檢測
if(pMsg->message==WM_LBUTTONDOWN)
{
if(pMsg->hwnd==GetDlgItem(IDC_BTN_X_A)->m_hWnd){ZAux_Direct_Single_Vmove(g_handle,0,1);}
if(pMsg->hwnd==GetDlgItem(IDC_BTN_X_B)->m_hWnd){ZAux_Direct_Single_Vmove(g_handle,0,-1);}
if(pMsg->hwnd==GetDlgItem(IDC_BTN_Y_A)->m_hWnd){ZAux_Direct_Single_Vmove(g_handle,1,1);}
if(pMsg->hwnd==GetDlgItem(IDC_BTN_Y_B)->m_hWnd){ZAux_Direct_Single_Vmove(g_handle,1,-1);}
if(pMsg->hwnd==GetDlgItem(IDC_BTN_A_A)->m_hWnd){ZAux_Direct_Single_Vmove(g_handle,2,1);}
if(pMsg->hwnd==GetDlgItem(IDC_BTN_A_B)->m_hWnd){ZAux_Direct_Single_Vmove(g_handle,2,-1);}
}
elseif(pMsg->message==WM_LBUTTONUP||WM_LBUTTONDBLCLK==pMsg->message)//判斷是否有MFC界面按鈕彈起
{
if(pMsg->hwnd==GetDlgItem(IDC_BTN_X_A)->m_hWnd){ZAux_Direct_Single_Cancel(g_handle,0,2);}
if(pMsg->hwnd==GetDlgItem(IDC_BTN_X_B)->m_hWnd){ZAux_Direct_Single_Cancel(g_handle,0,2);}
if(pMsg->hwnd==GetDlgItem(IDC_BTN_Y_A)->m_hWnd){ZAux_Direct_Single_Cancel(g_handle,1,2);}
if(pMsg->hwnd==GetDlgItem(IDC_BTN_Y_B)->m_hWnd){ZAux_Direct_Single_Cancel(g_handle,1,2);}
if(pMsg->hwnd==GetDlgItem(IDC_BTN_A_A)->m_hWnd){ZAux_Direct_Single_Cancel(g_handle,2,2);}
if(pMsg->hwnd==GetDlgItem(IDC_BTN_A_B)->m_hWnd){ZAux_Direct_Single_Cancel(g_handle,2,2);}
}
returnCDialogEx::PreTranslateMessage(pMsg);
}

5.繪圖函數(shù)。

voidCZCadToolFollowDemoDlg::OnDraw(CDC*pDC)
{
CDCdcMem;
CBitmapbmp;
GetDlgItem(IDC_PIC_VIEW)->GetClientRect(m_rcView);
dcMem.CreateCompatibleDC(pDC);
bmp.CreateCompatibleBitmap(pDC,m_rcView.Width(),m_rcView.Height());
dcMem.SelectObject(&bmp);
//繪制背景,默認黑色背景
dcMem.FillSolidRect(m_rcView,RGB(0,0,0));
//顯示當前加載的文件名
SetTextColor(dcMem.m_hDC,RGB(125,125,125));
TextOut(dcMem.m_hDC,5,5,m_strCurFileName,m_strCurFileName.GetLength());
//實際顯示的區(qū)域,預(yù)留邊距(不完全撐滿)
doubleWinWidth=m_rcView.Width()-65;
doubleWinHeight=m_rcView.Height()-65;
//實際的區(qū)域
doubleObjectPixWidth=0.0,ObjectPixHeight=0.0;
//需要更新初始化顯示比例
if(!m_bInitZoomTran)
{
//根據(jù)視圖范圍、圖形范圍,計算顯示比例及偏移
if((NULL!=m_pVectGroup)||(NULL!=m_pDib))
{
floatfLeft=0.0,fBottom=0.0,fWidth=0.0,fHeight=0.0;
doubledScale=0.0;
//顯示圖形還是位圖,同時只顯示一種
Struct_ZCad_Item*pShowData=m_pVectGroup?(Struct_ZCad_Item*)m_pVectGroup:(Struct_ZCad_Item*)m_pDib;
//獲取當前圖形范圍
ZMotionCad3_GetRange((Struct_ZCad_Item*)pShowData,&fLeft,&fBottom,&fWidth,&fHeight,0.05);
if(fWidth0.0001&&fabs(fHeight)<=?0.0001)
????????????{
????????????????ObjectPixWidth?=?WinWidth;
????????????????ObjectPixHeight?=?ObjectPixWidth?*?fHeight?/?fWidth;
????????????????dScale?=?ObjectPixWidth?/?fWidth;
????????????}
????????????else
????????????{
????????????????if?(fWidth*WinHeight?BitBlt(m_rcView.left,?m_rcView.top,?m_rcView.Width(),?m_rcView.Height(),?&dcMem,?0,?0,?SRCCOPY);
????DeleteObject(dcMem);?//清理資源
????DeleteObject(bmp);
}

6.打開CAD圖處理函數(shù)。

//打開CAD文件
voidCZCadToolFollowDemoDlg::OnBnClickedBtnOpenCad()
{
CStringgReadFilePathName;
CFileDialogfileDlg(true,_T("dxf"),_T("*.dxf"),OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,_T("DXFFiles(*.dxf)|*.dxf|AIFile(*.ai)|*.ai|PLTFile(*.plt)|*.plt|DSTFiles(*.dst)|*.dst|AllFiles(*.*)|*.*||"),NULL);
if(fileDlg.DoModal()==IDOK)//彈出對話框
{
gReadFilePathName=fileDlg.GetPathName();//得到完整的文件名和目錄名拓展名
CStringfilename=fileDlg.GetFileName();
//取得擴展名
CStringstrExtName=filename.Mid(filename.ReverseFind(_T('.'))+1);//文件擴張名
strExtName.MakeLower();
//清除之前加載的
if(NULL!=m_pVectGroup)
{
ZMotionCad3_ItemDelete((Struct_ZCad_Item*)m_pVectGroup);
m_pVectGroup=NULL;
}
if(NULL!=m_pDib)
{
ZMotionCad3_ItemDelete((Struct_ZCad_Item*)m_pDib);
m_pDib=NULL;
}
//加載文件
if((strExtName=="dxf")||(strExtName=="ai")||(strExtName=="dst")||(strExtName=="plt"))
{
//圖形文件
m_pVectGroup=ZMotionCad3_ImportVectGraph(CW2A(gReadFilePathName),1016.0,ZCAD_IMPORTVECT_SEGES,0.05,false);
}
else
{
//其他格式按位圖文件處理
m_pDib=ZMotionCad3_ImportImage(CW2A(gReadFilePathName),ZCAD_IMPORT_IMAGE_OPTION_NONE);
}
//CAD圖數(shù)據(jù)轉(zhuǎn)G代碼并生成運動數(shù)據(jù)鏈表
CStringm_strGcode=VectToNcCode(m_pVectGroup);
//打印運動數(shù)據(jù)到輸出窗口
CncLinkedList_Printf(m_pCncData);
//刷新G代碼顯示窗口
GetDlgItem(IDC_EDIT_GCODE)->SetWindowText(m_strGcode);
//刷新視圖
InvalidateRect(m_rcView,false);
//設(shè)置刷新狀態(tài)
m_bInitZoomTran=false;
//更新當前文件名
m_strCurFileName=filename;
}
}

7.CAD圖層數(shù)據(jù)轉(zhuǎn)G代碼函數(shù)。

//圖形轉(zhuǎn)G代碼
CStringCZCadToolFollowDemoDlg::VectToNcCode(Struct_ZCad_VectGroup*pVectGroup)
{
if(!pVectGroup)
{//圖形數(shù)據(jù)為空
AfxMessageBox(L"數(shù)據(jù)為空!");
returnL"";
}
CncLinkedList_ClearMyList(m_pCncData);
m_pCncData=CncLinkedList_CreatList();
CStringstrOut,strSingleLen;//輸出的G代碼
strOut.Format(L"M3rnG90rnG0X0.000Y0.000rn");//默認絕對運行
CncLinkedList_StringToLink(L"G0X0.000Y0.000",m_pCncData);//G代碼字符串轉(zhuǎn)入鏈表中
Struct_ZCad_VectGroup*pGroupHead=pVectGroup;
while(pGroupHead)
{
Struct_ZCad_Vect*pVectHead=pGroupHead->m_pVect;
Struct_ZCad_Seg*pEffectSeg=NULL;//有效數(shù)據(jù)
while(pVectHead)
{
if(ZCAD_ITEMTYPE_VECTLine!=pVectHead->m_itemtype&&!pVectHead->m_pLineSeg)
{//曲線全部轉(zhuǎn)為小線段處理
ZMotionCadEx_CurveSmooth((Struct_ZCad_Item*)pVectHead,0.05,false,true);
}
pEffectSeg=pVectHead->m_pLineSeg?pVectHead->m_pLineSeg:pVectHead->m_pLine;
//快速定位
strSingleLen.Format(L"G0X%.4lfY%.4lfrn",pEffectSeg->x1,pEffectSeg->y1);
CncLinkedList_StringToLink(strSingleLen,m_pCncData);
strOut+=strSingleLen;
if(ZCAD_ITEMTYPE_VECTArc==pVectHead->m_itemtype)
{//圓/圓弧的情況下//不會進入此if,全部轉(zhuǎn)小線段處理
CStringstrSide;//圓的方向
doubledX0=min(pVectHead->m_pLine->x1,pVectHead->m_pLine->x2)+fabs(pVectHead->m_pLine->x1-pVectHead->m_pLine->x2)/2;
doubledY0=min(pVectHead->m_pLine->y1,pVectHead->m_pLine->y2)+fabs(pVectHead->m_pLine->y1-pVectHead->m_pLine->y2)/2;//圓心的絕對坐標
doubledR=fabs(pVectHead->m_pLine->x1-pVectHead->m_pLine->x2)/2.0;//半徑
if(pVectHead->m_pLine->x1m_pLine->x2&&pVectHead->m_pLine->y1m_pLine->y2)
{//逆時針G03
strSide="G3";
}
else
{//順時針G02
strSide="G2";
}
strSingleLen.Format(L"%sX%.4lfY%.4lfI%.4lfJ%.4lfrn",strSide,pEffectSeg->m_prev->x2,pEffectSeg->m_prev->y2,dX0-pEffectSeg->x1,dY0-pEffectSeg->y1);
CncLinkedList_StringToLink(strSingleLen,m_pCncData);
strOut+=strSingleLen;
}
else
{
Struct_ZCad_Seg*pHeadSeg=pEffectSeg;
while(pHeadSeg)
{//直線插補
strSingleLen.Format(L"G1X%.4lfY%.4lfrn",pHeadSeg->x2,pHeadSeg->y2);
CncLinkedList_StringToLink(strSingleLen,m_pCncData);
strOut+=strSingleLen;
pHeadSeg=pHeadSeg->m_pnext;
if(pHeadSeg==pEffectSeg)
{
break;
}
}
}
pVectHead=pVectHead->m_pnext;
if(pVectHead==pGroupHead->m_pVect)
{
break;
}
}
pGroupHead=pGroupHead->m_pnext;
if(pGroupHead==pVectGroup)
{
break;
}
}
strSingleLen.Format(L"M2");
CncLinkedList_StringToLink(strSingleLen,m_pCncData);
strOut+=strSingleLen;
returnstrOut;
}

8.計算直線向量角度函數(shù)。

//第一條直線起點,終點;第二條直線起點終點
doubleGetLineVectorArg(doubleline1StartX,doubleline1StartY,doubleline1EndX,doubleline1EndY)
{
floata[4];//存放第一個向量的起點和重點
floatb[4];//存放第二個向量的起點和重點
a[0]=line1StartX;
a[1]=line1StartY;
a[2]=line1EndX;
a[3]=line1EndY;
if(a[0]==a[2]&&a[1]==a[3])
{
return0;
}
b[0]=0;
b[1]=0;
b[2]=1000;
b[3]=0;
floatvector1x=a[0]-a[2];
floatvector1y=a[1]-a[3];
floatvector2x=b[0]-b[2];
floatvector2y=b[1]-b[3];
CStringTRACEtest;
floatang=0;
//θ=acos(v1?v2/||v1||||v2||)
floattmp=((vector1x)*(vector2x)+(vector1y)*(vector2y))/(sqrt(pow(vector1x,2)+pow(vector1y,2))*sqrt(pow(vector2x,2)+pow(vector2y,2)));
//θ=atan2(v2.y,v2.x)?atan2(v1.y,v1.x)doubletmp2=(atan2(vector2y,vector2x)-atan2(vector1y,vector1x))*(180/PI);ang=acos(tmp)*(180/PI);
if(int(ang)==90)
if(line1StartY
9.G代碼字符串轉(zhuǎn)數(shù)據(jù)鏈表函數(shù)。voidCZCadToolFollowDemoDlg::CncLinkedList_StringToLink(CStringFileContentLine,struct_CncData*CncData)
{
FileContentLine.TrimRight();//去掉右邊的空格
FileContentLine.TrimLeft();//去掉左邊的空格
FileContentLine.Replace(_T(""),_T(""));
struct_MoveDatamovepara;
CncLinkedList_InsertNodebyTail(CncData,movepara);
//找到最后一個節(jié)點
struct_CncData*cncData_lastNode=CncData;
while(cncData_lastNode->m_pnext!=CncData)
{
cncData_lastNode=cncData_lastNode->m_pnext;//往下走
}
if(FileContentLine.Find('G')!=-1)
{
if(cncData_lastNode->m_pprev!=NULL)
{
cncData_lastNode->m_movepara.m_length=cncData_lastNode->m_pprev->m_movepara.m_length+1;
}
CStringstr_tmp=FileContentLine.Right(FileContentLine.GetLength()-FileContentLine.Find('G')-1);//剩余G后字符串
intnum_tmp=_tstof(str_tmp);
CStringstr_tmp90,str_tmpX,str_tmpY,str_tmpZ,str_tmpI,str_tmpJ,str_tmpD;
AfxExtractSubString(str_tmpX,(LPCTSTR)FileContentLine,1,'X');
AfxExtractSubString(str_tmpY,(LPCTSTR)FileContentLine,1,'Y');
AfxExtractSubString(str_tmpI,(LPCTSTR)FileContentLine,1,'I');
AfxExtractSubString(str_tmpJ,(LPCTSTR)FileContentLine,1,'J');
AfxExtractSubString(str_tmpD,(LPCTSTR)FileContentLine,1,'D');
/****************************G運動類型賦值*******************************************/
switch(num_tmp)
{
caseCNC_TRACK_LINE_SEEK://0定位
cncData_lastNode->m_movepara.m_type=CNC_TRACK_LINE_SEEK;
break;
caseCNC_TRACK_LINE://1直線
cncData_lastNode->m_movepara.m_type=CNC_TRACK_LINE;
break;
caseCNC_TRACK_ARC://2圓弧
cncData_lastNode->m_movepara.m_type=CNC_TRACK_ARC;
break;
caseCNC_TRACK_ARC_CCW://3圓弧
cncData_lastNode->m_movepara.m_type=CNC_TRACK_ARC_CCW;
break;
default:
cncData_lastNode->m_movepara.m_type=CNC_TRACK_OTHER;
break;
}
/****************************G運動坐標賦值*******************************************/
{
if(str_tmpX.GetLength()>0)
{
cncData_lastNode->m_movepara.m_end.x=_tstof(str_tmpX);
}
else
{
cncData_lastNode->m_movepara.m_end.x=CNC_XYZIJ_NULL;
}
if(str_tmpY.GetLength()>0)
{
cncData_lastNode->m_movepara.m_end.y=_tstof(str_tmpY);
}
else
{
cncData_lastNode->m_movepara.m_end.y=CNC_XYZIJ_NULL;
}
if(str_tmpI.GetLength()>0)
{
cncData_lastNode->m_movepara.m_center.x=_tstof(str_tmpI);
}
else
{
cncData_lastNode->m_movepara.m_center.x=CNC_XYZIJ_NULL;
}
if(str_tmpJ.GetLength()>0)
{
cncData_lastNode->m_movepara.m_center.y=_tstof(str_tmpJ);
}
else
{
cncData_lastNode->m_movepara.m_center.y=CNC_XYZIJ_NULL;
}
}
//獲取起點坐標
floatstartx,starty,endx,endy;
startx=CNC_XYZIJ_NULL;
starty=CNC_XYZIJ_NULL;
endx=cncData_lastNode->m_movepara.m_end.x;
endy=cncData_lastNode->m_movepara.m_end.y;
if(CNC_XYZIJ_NULL==endx&&CNC_XYZIJ_NULL==endy)
{
return;
}
if(CNC_TRACK_LINE==cncData_lastNode->m_movepara.m_type||CNC_TRACK_ARC==cncData_lastNode->m_movepara.m_type||CNC_TRACK_ARC_CCW==cncData_lastNode->m_movepara.m_type)
{
struct_CncData*cncData_lastNode_prev=cncData_lastNode;
intliv_type=-1;
while(true)
{
cncData_lastNode_prev=cncData_lastNode_prev->m_pprev;
liv_type=cncData_lastNode_prev->m_movepara.m_type;
if((0==liv_type||1==liv_type||2==liv_type||3==liv_type))
{
break;
}
}
startx=cncData_lastNode_prev->m_movepara.m_end.x;
starty=cncData_lastNode_prev->m_movepara.m_end.y;
if(startx!=CNC_XYZIJ_NULL&&startx!=CNC_XYZIJ_NULL)
{
cncData_lastNode->m_movepara.m_start.x=startx;
cncData_lastNode->m_movepara.m_start.y=starty;
}
else
{
AfxMessageBox(L"cncData_lastNode->m_movepara.m_start.x=CNC_XYZIJ_NULL;");
cncData_lastNode->m_movepara.m_start.x=CNC_XYZIJ_NULL;
cncData_lastNode->m_movepara.m_start.y=CNC_XYZIJ_NULL;
}
}
switch(num_tmp)
{
caseCNC_TRACK_LINE_SEEK://0定位
if(cncData_lastNode->m_pprev!=NULL)
{
cncData_lastNode->m_movepara.m_length=cncData_lastNode->m_pprev->m_movepara.m_length+1;
}
cncData_lastNode->m_movepara.m_type=CNC_TRACK_LINE_SEEK;
break;
caseCNC_TRACK_LINE://1直線
{
if(cncData_lastNode->m_pprev!=NULL)
{
cncData_lastNode->m_movepara.m_length=cncData_lastNode->m_pprev->m_movepara.m_length+1;
}
cncData_lastNode->m_movepara.m_type=CNC_TRACK_LINE;
cncData_lastNode->m_movepara.m_angleStart=GetLineVectorArg(startx,starty,endx,endy);
cncData_lastNode->m_movepara.m_angleEnd=GetLineVectorArg(startx,starty,endx,endy);
break;
}
caseCNC_TRACK_ARC://2圓弧
{
if(cncData_lastNode->m_pprev!=NULL)
{
cncData_lastNode->m_movepara.m_length=cncData_lastNode->m_pprev->m_movepara.m_length+1;
}
cncData_lastNode->m_movepara.m_type=CNC_TRACK_ARC;
floatm_c_x=startx+cncData_lastNode->m_movepara.m_center.x;//圓心絕對坐標
floatm_c_y=starty+cncData_lastNode->m_movepara.m_center.y;
cncData_lastNode->m_movepara.m_angleStart=GetCircVectorArgG02(startx,starty,m_c_x,m_c_y);
cncData_lastNode->m_movepara.m_angleEnd=GetCircVectorArgG02(cncData_lastNode->m_movepara.m_end.x,cncData_lastNode->m_movepara.m_end.y,m_c_x,m_c_y);
if(cncData_lastNode->m_movepara.m_angleStart==cncData_lastNode->m_movepara.m_angleEnd)
{
cncData_lastNode->m_movepara.m_angleEnd+=360;
}
if(cncData_lastNode->m_movepara.m_angleEnd-cncData_lastNode->m_movepara.m_angleStart>180)
{
cncData_lastNode->m_movepara.m_angleEnd-=360;
}
break;
}
caseCNC_TRACK_ARC_CCW://3圓弧
{
if(cncData_lastNode->m_pprev!=NULL)
{
cncData_lastNode->m_movepara.m_length=cncData_lastNode->m_pprev->m_movepara.m_length+1;
}
cncData_lastNode->m_movepara.m_type=CNC_TRACK_ARC_CCW;
floatm_c_x=startx+cncData_lastNode->m_movepara.m_center.x;//圓心絕對坐標
floatm_c_y=starty+cncData_lastNode->m_movepara.m_center.y;
cncData_lastNode->m_movepara.m_angleStart=GetCircVectorArgG03(startx,starty,m_c_x,m_c_y);
cncData_lastNode->m_movepara.m_angleEnd=GetCircVectorArgG03(cncData_lastNode->m_movepara.m_end.x,cncData_lastNode->m_movepara.m_end.y,m_c_x,m_c_y);
if(cncData_lastNode->m_movepara.m_angleStart==cncData_lastNode->m_movepara.m_angleEnd)
{
cncData_lastNode->m_movepara.m_angleEnd+=360;
}
break;
}
default:
if(cncData_lastNode->m_pprev!=NULL)
{
cncData_lastNode->m_movepara.m_length=cncData_lastNode->m_pprev->m_movepara.m_length+1;
}
cncData_lastNode->m_movepara.m_type=CNC_TRACK_OTHER;
break;
}
}
else//M
{
if(cncData_lastNode->m_pprev!=NULL)
{
cncData_lastNode->m_movepara.m_length=cncData_lastNode->m_pprev->m_movepara.m_length+1;
}
CStringstr_tmp=FileContentLine.Right(FileContentLine.GetLength()-FileContentLine.Find('M')-1);//剩余M后字符串
intnum_tmp=_tstof(str_tmp);
switch(num_tmp)
{
case3://開始切割
if(cncData_lastNode->m_pprev!=NULL)
{
cncData_lastNode->m_movepara.m_length=cncData_lastNode->m_pprev->m_movepara.m_length+1;
}
cncData_lastNode->m_movepara.m_type=CNC_TRACK_START;
break;
case9://下刀
if(cncData_lastNode->m_pprev!=NULL)
{
cncData_lastNode->m_movepara.m_length=cncData_lastNode->m_pprev->m_movepara.m_length+1;
}
cncData_lastNode->m_movepara.m_type=CNC_TRACK_TOOL_DOWN;
break;
case10://抬刀
if(cncData_lastNode->m_pprev!=NULL)
{
cncData_lastNode->m_movepara.m_length=cncData_lastNode->m_pprev->m_movepara.m_length+1;
}
cncData_lastNode->m_movepara.m_type=CNC_TRACK_TOOL_UP;
break;
case4://切割結(jié)束
case2:
if(cncData_lastNode->m_pprev!=NULL)
{
cncData_lastNode->m_movepara.m_length=cncData_lastNode->m_pprev->m_movepara.m_length+1;
}
cncData_lastNode->m_movepara.m_type=4;
break;
case30://M代碼(固定)
if(cncData_lastNode->m_pprev!=NULL)
{
cncData_lastNode->m_movepara.m_length=cncData_lastNode->m_pprev->m_movepara.m_length+1;
}
cncData_lastNode->m_movepara.m_type=24;
break;
default:
break;
}
}
//free(cncData_lastNode);
}
10.運動線程函數(shù)。intCZCadToolFollowDemoDlg::CncLinkedList_Move(struct_CncData*List)
{
if(NULL==List)
{
return-1;
}
struct_CncData*ptr=List->m_pnext;
CStringm_ShowData=L"";
floatfX=0.0f,fY=0.0f,fC=0.0f,fI=0.0f,fJ=0.0f;
intaxislist[3]={0,1,2};//運動軸列表,其中軸1為主軸
floatcirc_endc=0.0f,circ_stratc=0.0f;
floatposlist[3]={0.0f};
intm_liv_ZmcMoveRe=0;
floatlfv_SpeedG00=1000;
floatlfv_SpeedG01=300;
ZAux_Direct_SetForceSpeed(g_handle,0,lfv_SpeedG00);//設(shè)置G00定位速度
ZAux_Direct_SetSpeed(g_handle,0,lfv_SpeedG01);//設(shè)置G01直線速度
while(ptr!=List){
fX=ptr->m_movepara.m_end.x;
fY=ptr->m_movepara.m_end.y;
fC=ptr->m_movepara.m_angleEnd;
switch(ptr->m_movepara.m_type)
{
caseCNC_TRACK_START://切割開始
{
break;
}
caseCNC_TRACK_LINE_SEEK://0定位
{
m_ShowData.Format(_T("G00X%fY%frn"),fX,fY);
TRACE(m_ShowData);
struct_CncData*cncData_lastNode_next=ptr;
intliv_type=-1;
while(true)
{
cncData_lastNode_next=cncData_lastNode_next->m_pnext;
liv_type=cncData_lastNode_next->m_movepara.m_type;
if((0==liv_type||1==liv_type||2==liv_type||3==liv_type)){break;}
}
circ_stratc=cncData_lastNode_next->m_movepara.m_angleStart;
circ_endc=cncData_lastNode_next->m_movepara.m_angleEnd;
poslist[0]=fX;
poslist[1]=fY;
poslist[2]=circ_stratc;
do
{
m_liv_ZmcMoveRe=ZAux_Direct_MovePara(g_handle,0,"MERGE",0,0);
if(m_liv_ZmcMoveRe)
{
Sleep(10);
if(h_ThreadMovePorc)return-1;
}
}while(m_liv_ZmcMoveRe);
do
{
m_liv_ZmcMoveRe=ZAux_Direct_MoveAbsSp(g_handle,3,axislist,poslist);
if(m_liv_ZmcMoveRe)
{
Sleep(10);
if(h_ThreadMovePorc)return-1;
}
}while(m_liv_ZmcMoveRe);
break;
}
caseCNC_TRACK_LINE://1直線//直線不用轉(zhuǎn)刀,但是如果G01與G01,不是G00與G01,運動結(jié)束后需要轉(zhuǎn)刀
{
m_ShowData.Format(_T("G01X%fY%frn"),fX,fY);
TRACE(m_ShowData);
do{
m_liv_ZmcMoveRe=ZAux_Direct_MovePara(g_handle,0,"MERGE",0,1);
if(m_liv_ZmcMoveRe)
{
Sleep(10);
if(h_ThreadMovePorc)return-1;
}
}while(m_liv_ZmcMoveRe);
if(ptr->m_pprev->m_movepara.m_type==CNC_TRACK_LINE||ptr->m_pprev->m_movepara.m_type==CNC_TRACK_ARC||ptr->m_pprev->m_movepara.m_type==CNC_TRACK_ARC_CCW)
{
poslist[0]=fX;
poslist[1]=fY;
poslist[2]=ptr->m_movepara.m_angleEnd;
do
{
m_liv_ZmcMoveRe=ZAux_Direct_MoveAbs(g_handle,3,axislist,poslist);
if(m_liv_ZmcMoveRe)
{
Sleep(10);
if(h_ThreadMovePorc)return-1;
}
}while(m_liv_ZmcMoveRe);
TRACE("rn");
}
else
{
fX=ptr->m_movepara.m_end.x;
fY=ptr->m_movepara.m_end.y;
poslist[0]=fX;
poslist[1]=fY;
do
{
m_liv_ZmcMoveRe=ZAux_Direct_MoveAbs(g_handle,2,axislist,poslist);
if(m_liv_ZmcMoveRe)
{
Sleep(10);
if(h_ThreadMovePorc)return-1;
}
}while(m_liv_ZmcMoveRe);
}
break;
}
}
ptr=ptr->m_pnext;
}
return0;
}


七.效果演示

wKgZO2gcUlKAJaTMAALdI7ep4Mk777.pngwKgZPGgcUlKAI5F9AALiuz9qL6o252.pngwKgZO2gcUlKACV07AALwp31bNpU968.pngwKgZPGgcUlOAeyqKAALw0TY9HbQ982.png

視頻講解可點擊→“PCIe EtherCAT實時運動控制卡PCIE464的CAD導(dǎo)圖與刀向跟隨應(yīng)用”查看。

完整代碼獲取地址

wKgZO2gcUlOAf79aAAFWabRTPOo862.png

本次,正運動技術(shù)PCIe EtherCAT實時運動控制卡PCIE464的CAD導(dǎo)圖與刀向跟隨應(yīng)用,就分享到這里。

更多精彩內(nèi)容請關(guān)注“正運動小助手”公眾號,需要相關(guān)開發(fā)環(huán)境與例程代碼,請咨詢正運動技術(shù)銷售工程師:400-089-8936。

本文由正運動技術(shù)原創(chuàng),歡迎大家轉(zhuǎn)載,共同學習,一起提高中國智能制造水平。文章版權(quán)歸正運動技術(shù)所有,如有轉(zhuǎn)載請注明文章來源。

審核編輯 黃宇

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • CAD
    CAD
    +關(guān)注

    關(guān)注

    18

    文章

    1106

    瀏覽量

    73682
  • 運動控制
    +關(guān)注

    關(guān)注

    4

    文章

    624

    瀏覽量

    33310
  • 運動控制卡
    +關(guān)注

    關(guān)注

    7

    文章

    118

    瀏覽量

    15715
  • 正運動技術(shù)
    +關(guān)注

    關(guān)注

    0

    文章

    114

    瀏覽量

    583
收藏 人收藏

    評論

    相關(guān)推薦
    熱點推薦

    PCIe EtherCAT實時運動控制卡PCIE464的IO與編碼器讀寫應(yīng)用

    C#進行PCIe EtherCAT運動控制卡的項目開發(fā)和快速讀取多個IO和軸編碼器位置的例程。
    的頭像 發(fā)表于 07-17 14:47 ?1219次閱讀
    <b class='flag-5'>PCIe</b> <b class='flag-5'>EtherCAT</b><b class='flag-5'>實時運動</b><b class='flag-5'>控制卡</b><b class='flag-5'>PCIE464</b>的IO與編碼器讀寫應(yīng)用

    【正運動】高速高精,超高實時性的PCIe EtherCAT實時運動控制卡 | PCIE464

    產(chǎn)品摘要正運動技術(shù)PCIE464運動控制卡,提供高效的工業(yè)運動控制解決方案。用戶可直接將
    發(fā)表于 01-24 09:48

    EtherCAT超高速實時運動控制卡XPCIE1032H驅(qū)動安裝# 運動控制卡# 正運動技術(shù)# PCIE

    人工智能運動控制卡
    正運動技術(shù)
    發(fā)布于 :2023年11月10日 15:44:03

    EtherCAT同步周期快至100us】超高實時性PCle EtherCAT控制卡PCIE464

    控制卡PCIe
    正運動技術(shù)
    發(fā)布于 :2024年01月31日 14:31:05

    PCIe EtherCAT實時運動控制卡PCIE464的IO與編碼器讀寫應(yīng)用# 正運動技術(shù)# 運動控制卡

    編碼器運動控制卡
    正運動技術(shù)
    發(fā)布于 :2024年07月23日 09:37:31

    EtherCAT運動控制卡之ECI2820如何使用

    軸直線插補、任意圓弧插補、空間圓弧、螺旋插補、電子凸輪、電子齒輪、同步跟隨、虛擬軸、機械手指令等;采用優(yōu)化的網(wǎng)絡(luò)通訊協(xié)議可以實現(xiàn)實時運動控制?! CI2828系列
    發(fā)表于 09-01 06:24

    不止10倍提速!PCIe EtherCAT實時運動控制卡XPCIE1032H 等您評測!

    PCIe實時運動控制卡助力EtherCAT高速高精運動控制應(yīng)用!
    的頭像 發(fā)表于 06-26 10:14 ?7887次閱讀
    不止10倍提速!<b class='flag-5'>PCIe</b> <b class='flag-5'>EtherCAT</b><b class='flag-5'>實時運動</b><b class='flag-5'>控制卡</b>XPCIE1032H 等您評測!

    PCIE超高速實時運動控制卡在六面外觀視覺檢測上的應(yīng)用

    超高速視覺篩選機PCIe實時運動控制卡XPCIE1028
    的頭像 發(fā)表于 08-22 09:31 ?1129次閱讀
    <b class='flag-5'>PCIE</b>超高速<b class='flag-5'>實時運動</b><b class='flag-5'>控制卡</b>在六面外觀視覺檢測上的應(yīng)用

    超高速PCIe實時運動控制卡解決方案

    搭載Windows運動控制實時內(nèi)核MotionRT7,完美解決傳統(tǒng)PCI/PCle運動控制卡在Windows環(huán)境下
    發(fā)表于 09-16 10:16 ?1169次閱讀
    超高速<b class='flag-5'>PCIe</b><b class='flag-5'>實時運動</b><b class='flag-5'>控制卡</b>解決方案

    高速視覺篩選機PCIe實時運動控制卡XPCIE1028簡介

    本次的深圳慕尼黑華南電子展正運動技術(shù)將攜高速視覺篩選機PCIe實時運動控制卡XPCIE1028亮相。此外,我們還為您準備了的新互動模式,您將有機會贏得超值禮品!
    的頭像 發(fā)表于 11-06 16:00 ?742次閱讀
    高速視覺篩選機<b class='flag-5'>PCIe</b><b class='flag-5'>實時運動</b><b class='flag-5'>控制卡</b>XPCIE1028簡介

    PCIE464 — 高速高精,超高實時性的PCIe EtherCAT實時運動控制卡

    運動高速高精運動控制卡家族迎來新成員!
    的頭像 發(fā)表于 01-17 16:29 ?1065次閱讀
    <b class='flag-5'>PCIE464</b> — 高速高精,超高<b class='flag-5'>實時</b>性的<b class='flag-5'>PCIe</b> <b class='flag-5'>EtherCAT</b><b class='flag-5'>實時運動</b><b class='flag-5'>控制卡</b>

    超高實時性的EtherCAT運動控制卡——PCIE464

    運動技術(shù)PCIE464運動控制卡,提供高效的工業(yè)運動控制解決方案。用戶可直接將
    發(fā)表于 01-26 14:39 ?1585次閱讀

    PCIE464M — 高速高精,超高速PCIe EtherCAT實時運動控制卡

    運動“高速高精運動控制卡”家族再添一員猛將!
    的頭像 發(fā)表于 05-31 11:17 ?763次閱讀
    <b class='flag-5'>PCIE464</b>M — 高速高精,超高速<b class='flag-5'>PCIe</b> <b class='flag-5'>EtherCAT</b><b class='flag-5'>實時運動</b><b class='flag-5'>控制卡</b>

    PCIe實時運動控制卡的雙盤視覺篩選機上位機開發(fā)應(yīng)用

    PCIe實時運動控制卡的雙盤視覺篩選機上位機開發(fā)應(yīng)用
    的頭像 發(fā)表于 10-10 10:15 ?631次閱讀
    <b class='flag-5'>PCIe</b><b class='flag-5'>實時運動</b><b class='flag-5'>控制卡</b>的雙盤視覺篩選機上位機開發(fā)應(yīng)用