一.硬件介紹
PCIE464運動控制卡是正運動推出的一款EtherCAT總線+脈沖型、PCIE接口式的運動控制卡,可選6-64軸運動控制,支持多路高速數(shù)字輸入輸出,可輕松實現(xiàn)多軸同步控制和高速數(shù)據(jù)傳輸。
PCIE464運動控制卡適合于多軸點位運動、插補運動、軌跡規(guī)劃、手輪控制、編碼器位置檢測、IO控制、位置鎖存等功能的應(yīng)用。PCIE464運動控制卡適用于3C電子加工、檢測設(shè)備、半導(dǎo)體設(shè)備、SMT加工、激光加工、光通訊設(shè)備、鋰電及光伏設(shè)備、以及非標自動化設(shè)備等高速高精應(yīng)用場合。
PCIE4系列控制卡的應(yīng)用程序可以使用VC,VB,VS,C++,C#等軟件開發(fā),程序運行時需要動態(tài)庫zmotion.dll,調(diào)試時可以將RTSys軟件同時連接控制器,從而方便調(diào)試、方便觀察。
PCIE464產(chǎn)品視頻介紹可點擊→“【EtherCAT同步周期快至100us】超高實時性PCIe EtherCAT控制卡PCIE464”查看。
更多關(guān)于PCIE464的詳情介紹,點擊“PCIE464 — 高速高精,超高實時性的PCIe EtherCAT實時運動控制卡”查看。
二.接線參考
1.IN數(shù)字量輸入接口
數(shù)字輸入分布在J400(IN0-IN7)和X400(IN8-IN39)信號接口中。
2.OUT數(shù)字量輸出接口
數(shù)字輸出分布在J400(OUT0-7)和X400(OUT8-OUT39)信號接口中。
3.單端編碼器及單端脈沖接線
單端脈沖接線圖
差分脈沖接線圖
單端編碼器接線圖
差分編碼器接線圖
注:PCIE464的J400接口中有一個差分脈沖軸接口和三個單端脈沖軸接口,兩個差分編碼器接口(其中一個與差分脈沖軸接口復(fù)用,取決于固件設(shè)定)和兩個單端編碼器接口,具體引腳定義參見PCIE464硬件手冊。
三.CAD解析及刀向跟隨計算技巧解釋
1.CAD圖紙解析
正運動技術(shù)提供開放的ZmotionCadEx庫,可導(dǎo)入DXF、Ai、Plt、Dst圖紙,可以生成運動坐標數(shù)據(jù)轉(zhuǎn)G代碼、zbasic運動指令、或直接PC函數(shù)執(zhí)行運動。
2.刀向跟隨計算
刀向跟隨,是在插補運動的過程中,使非插補軸隨著插補運動的合成位移的變化而變化,從而實現(xiàn)在加工過程中,刀具始終處于合適的加工方向和位置的工藝。
非插補軸(如旋轉(zhuǎn)軸或獨立軸)能夠根據(jù)插補軸的合成位移實時調(diào)整,使刀具始終沿預(yù)定路徑或方向運動。例如,在砂輪磨削中,通過調(diào)整砂輪的角度,確保其與工件切向方向一致;在布料裁切中,通過調(diào)整刀具朝向,始終指向行進方向。
本例中通過計算小線段的向量方向,以3軸插補形式運行實現(xiàn),基本原理如下圖所示。
已知線段起點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ù)接口:
四.MFC與C++編程實現(xiàn)
1.首先打開Visual Studio 2022,點擊創(chuàng)建新項目。
2.選擇開發(fā)語言為“Visual C++”和程序類型“MFC應(yīng)用程序”。
3.點擊下一步即可。
4.選擇類型為“基于對話框”,下一步或者完成。
5.前往正運動官網(wǎng)下載PC函數(shù)庫,路徑如下(本文采用64位函數(shù)庫為例)。
(1)進入官網(wǎng),選擇支持與服務(wù),打開下載中心選擇庫文件,就能找到所有的PC函數(shù)庫。
(2)點擊下載Windows C++(64位),可按需求另存為想要保存的路徑下。
(3)函數(shù)庫另存為具體路徑如下。
(4)如需處理CAD圖,可與技術(shù)工程師聯(lián)系獲取ZmotionCadEx庫。
6.將廠商提供的C++庫文件和相關(guān)頭文件復(fù)制到新建的項目里。
7.在項目中添加靜態(tài)庫和相關(guān)頭文件。
(1)打開解決方案資源管理器,點擊顯示全部文件。
(2)選中.h與.lib文件,右鍵包括在項目中。
8.聲明用到的頭文件。
9.至此項目新建完成,可進行MFC項目開發(fā)。
五.查看PC函數(shù)手冊,熟悉相關(guān)函數(shù)接口
1.PC函數(shù)手冊也可以在正運動官網(wǎng)“支持與服務(wù)”→“下載中心”→“編程手冊”中找到。
2.鏈接控制器,獲取鏈接句柄。
3.查看ZmotionCadEx.h中關(guān)于CAD圖處理的函數(shù)接口。
六.MFC實現(xiàn)CAD導(dǎo)入與刀向跟隨
1.例程界面如下。
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(fWidth?0.0001?&&?fHeight??0.0001) ????????????{ ????????????????fLeft?=?0.0; ????????????????fBottom?=?0.0; ????????????????fWidth?=?100.0; ????????????????fHeight?=?100.0; ????????????} ????????????//根據(jù)圖形范圍、顯示視圖范圍計算顯示比例 ????????????if?(fabs(fWidth)??0.0001) ????????????{ ????????????????ObjectPixHeight?=?WinHeight; ????????????????ObjectPixWidth?=?ObjectPixHeight?*?fWidth?/?fHeight; ????????????????dScale?=?ObjectPixHeight?/?fHeight; ????????????} ????????????else?if?(fabs(fWidth)??>0.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?line1EndY)?{ ????????????ang?=?90; ????????} ????????else?{ ????????????ang?=?270; ????????} ????if?(fabs(ang?-?tmp2)?<=?1e-3) ????{ ????????ang?=?360?-?ang; ????} ????return?ang; }
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; }
七.效果演示
視頻講解可點擊→“PCIe EtherCAT實時運動控制卡PCIE464的CAD導(dǎo)圖與刀向跟隨應(yīng)用”查看。
完整代碼獲取地址
▼
本次,正運動技術(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)載請注明文章來源。
審核編輯 黃宇
-
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
發(fā)布評論請先 登錄
【正運動】高速高精,超高實時性的PCIe EtherCAT實時運動控制卡 | PCIE464

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


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

PCIe EtherCAT實時運動控制卡PCIE464的CAD導(dǎo)圖與刀向跟隨應(yīng)用#正運動技術(shù) #運動控制卡
EtherCAT運動控制卡之ECI2820如何使用
超高速PCIe實時運動控制卡解決方案

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

評論