0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

PCIe EtherCAT实时运动控制卡PCIE464的CAD导图与刀向跟随应用

正运动技术 来源:正运动技术 作者:正运动技术 2025-05-08 14:42 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

一.硬件介绍

PCIE464运动控制卡是正运动推出的一款EtherCAT总线+脉冲型、PCIE接口式的运动控制卡,可选6-64轴运动控制,支持多路高速数字输入输出,可轻松实现多轴同步控制和高速数据传输。

wKgZPGgcUkmAKA_zAAJpkhm7bi0398.png

PCIE464运动控制卡适合于多轴点位运动、插补运动、轨迹规划、手轮控制、编码器位置检测、IO控制、位置锁存等功能的应用。PCIE464运动控制卡适用于3C电子加工、检测设备、半导体设备、SMT加工、激光加工、光通讯设备、锂电及光伏设备、以及非标自动化设备等高速高精应用场合。

wKgZPGgcUkmANiqIAANvpLLwIRY040.png

PCIE4系列控制卡的应用程序可以使用VC,VB,VS,C++C#等软件开发,程序运行时需要动态库zmotion.dll,调试时可以将RTSys软件同时连接控制器,从而方便调试、方便观察。

wKgZO2gcUkqAEX14AAD97IAHdVM762.png

PCIE464产品视频介绍可点击→“【EtherCAT同步周期快至100us】超高实时性PCIe EtherCAT控制卡PCIE464”查看。

更多关于PCIE464的详情介绍,点击“PCIE464 — 高速高精,超高实时性的PCIe EtherCAT实时运动控制卡”查看。


二.接线参考

1.IN数字量输入接口

数字输入分布在J400(IN0-IN7)和X400(IN8-IN39)信号接口中。

wKgZPGgcUkqAEWcKAAGNseUtDZ0196.png

2.OUT数字量输出接口

数字输出分布在J400(OUT0-7)和X400(OUT8-OUT39)信号接口中。

wKgZO2gcUkqABdrUAAHcGLxmeDQ236.png

3.单端编码器及单端脉冲接线

wKgZPGgcUkqAL1brAAD_3blXtNk263.png

单端脉冲接线图

wKgZO2gcUkuASuvwAADtk54wOTE786.png

差分脉冲接线图

wKgZPGgcUkuAFW97AADRCWK_4dI107.png

单端编码器接线图

wKgZO2gcUkuARhTxAAE1UDn6qn0900.png

差分编码器接线图

注:PCIE464的J400接口中有一个差分脉冲轴接口和三个单端脉冲轴接口,两个差分编码器接口(其中一个与差分脉冲轴接口复用,取决于固件设定)和两个单端编码器接口,具体引脚定义参见PCIE464硬件手册。

三.CAD解析及刀向跟随计算技巧解释

wKgZPGgcUkuANM85AAIt8vP_1Fs588.png

1.CAD图纸解析

正运动技术提供开放的ZmotionCadEx库,可导入DXF、Ai、Plt、Dst图纸,可以生成运动坐标数据转G代码、zbasic运动指令、或直接PC函数执行运动。

wKgZO2gcUkyAJDY6AARpicc-_fw614.png

2.刀向跟随计算

刀向跟随,是在插补运动的过程中,使非插补轴随着插补运动的合成位移的变化而变化,从而实现在加工过程中,刀具始终处于合适的加工方向和位置的工艺。

非插补轴(如旋转轴或独立轴)能够根据插补轴的合成位移实时调整,使刀具始终沿预定路径或方向运动。例如,在砂轮磨削中,通过调整砂轮的角度,确保其与工件切向方向一致;在布料裁切中,通过调整刀具朝向,始终指向行进方向。

本例中通过计算小线段的向量方向,以3轴插补形式运行实现,基本原理如下图所示。

wKgZPGgcUkyAK9bBAAI-If7HOsI332.png

已知线段起点A坐标,终点B坐标,在起点A上做与X轴平行向量AC,通过数学计算得到向量AB与向量AC的夹角α,即线段AB与X轴正方向夹角。将夹角α与终点坐标XY做三轴插补来作为刀向跟随。

在某些场合需要A轴先抬刀转到加工角度,再下刀加工:比如加工矩形轮廓四条边,那么应该先抬刀转到加工方向,再下刀进行加工,不应在工件上转刀,此时可以通过判断线段的长度,小于设定值时三轴插补,大于设定值时应抬刀→转刀→下刀再加工。

本例中主要用到了下面几个函数接口:

wKgZO2gcUkyALINLAAGw7qoqIao431.pngwKgZPGgcUkyAddAuAAG1damNV1g232.pngwKgZO2gcUk2AKjcWAAHNrsnrN_g067.png


四.MFC与C++编程实现

1.首先打开Visual Studio 2022,点击创建新项目。

wKgZPGgcUk2AayP0AADiYUq9tCI769.png

2.选择开发语言为“Visual C++”和程序类型“MFC应用程序”。

wKgZO2gcUk2AT5aCAAFb2OqTa8A708.png

3.点击下一步即可。

wKgZPGgcUk6AFPQAAAFGByboKaY848.png

4.选择类型为“基于对话框”,下一步或者完成。

wKgZO2gcUk6Aflu6AAFZIuxrrj8723.png

5.前往正运动官网下载PC函数库,路径如下(本文采用64位函数库为例)。

(1)进入官网,选择支持与服务,打开下载中心选择库文件,就能找到所有的PC函数库。

wKgZPGgcUk6AUWIzAAFv7N927HI592.png

(2)点击下载Windows C++(64位),可按需求另存为想要保存的路径下。

wKgZO2gcUk6AOQ-OAAEbA93HWCs239.png

(3)函数库另存为具体路径如下。

wKgZPGgcUk-ANOUAAAEp8wO9KEY169.png

(4)如需处理CAD图,可与技术工程师联系获取ZmotionCadEx库。

wKgZO2gcUk-ABC2rAACsrMchFrI699.png

6.将厂商提供的C++库文件和相关头文件复制到新建的项目里。

wKgZPGgcUk-ACuemAARicIY6GCQ735.png

7.在项目中添加静态库和相关头文件。

(1)打开解决方案资源管理器,点击显示全部文件。

wKgZO2gcUk-AIR9IAALqmWAH2uo442.png

(2)选中.h与.lib文件,右键包括在项目中。

wKgZPGgcUlCAeX9MAAMsi0KpF8c287.png

8.声明用到的头文件。

wKgZO2gcUlCAX1CaAAIl3G2pWlg658.png

9.至此项目新建完成,可进行MFC项目开发。

五.查看PC函数手册,熟悉相关函数接口

1.PC函数手册也可以在正运动官网“支持与服务”→“下载中心”→“编程手册”中找到。

wKgZPGgcUlCAVPvXAAML0KMocMc075.png

2.链接控制器,获取链接句柄。

wKgZO2gcUlGAcMTSAAFzGU7AO_c975.png

3.查看ZmotionCadEx.h中关于CAD图处理的函数接口。

wKgZPGgcUlGAN7kuAAWUfcLr3LY378.png


六.MFC实现CAD导入与刀向跟随

1.例程界面如下。

wKgZO2gcUlGAQ3iQAALmJqY-sts477.png

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

BOOLCZCadToolFollowDemoDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
//设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
//执行此操作
SetIcon(m_hIcon,TRUE);//设置大图标
SetIcon(m_hIcon,FALSE);//设置小图标
//TODO:在此添加额外的初始化代码
m_DlgRect.SetRect(0,0,0,0);//初始化对话框大小存储变量
CRectrect;
GetClientRect(&rect);//取客户区大小
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"仿真器连接失败(请给予仿真器权限)");
}
}
}
}
}
}
if(NULL!=g_handle)
{
SetTimer(0,1,NULL);
//初始化轴参数
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;  // 除非将焦点设置到控件,否则返回 TRUE
}

3.定时器获取轴DPOS坐标用于显示与刷新绘制图像。

voidCZCadToolFollowDemoDlg::OnTimer(UINT_PTRnIDEvent)
{
//TODO:在此添加消息处理程序代码和/或调用默认值
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.消息传递函数中响应手动运动按钮代码。

BOOLCZCadToolFollowDemoDlg::PreTranslateMessage(MSG*pMsg)
{
//TODO:在此添加专用代码和/或调用基类
//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.绘图函数。

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());
//实际显示的区域,预留边距(不完全撑满)
doubleWinWidth=m_rcView.Width()-65;
doubleWinHeight=m_rcView.Height()-65;
//实际的区域
doubleObjectPixWidth=0.0,ObjectPixHeight=0.0;
//需要更新初始化显示比例
if(!m_bInitZoomTran)
{
//根据视图范围、图形范围,计算显示比例及偏移
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;
            }
            //根据图形范围、显示视图范围计算显示比例
            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图处理函数。

//打开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图数据转G代码并生成运动数据链表
CStringm_strGcode=VectToNcCode(m_pVectGroup);
//打印运动数据到输出窗口
CncLinkedList_Printf(m_pCncData);
//刷新G代码显示窗口
GetDlgItem(IDC_EDIT_GCODE)->SetWindowText(m_strGcode);
//刷新视图
InvalidateRect(m_rcView,false);
//设置刷新状态
m_bInitZoomTran=false;
//更新当前文件名
m_strCurFileName=filename;
}
}

7.CAD图层数据转G代码函数。

//图形转G代码
CStringCZCadToolFollowDemoDlg::VectToNcCode(Struct_ZCad_VectGroup*pVectGroup)
{
if(!pVectGroup)
{//图形数据为空
AfxMessageBox(L"数据为空!");
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代码字符串转入链表中
Struct_ZCad_VectGroup*pGroupHead=pVectGroup;
while(pGroupHead)
{
Struct_ZCad_Vect*pVectHead=pGroupHead->m_pVect;
Struct_ZCad_Seg*pEffectSeg=NULL;//有效数据
while(pVectHead)
{
if(ZCAD_ITEMTYPE_VECTLine!=pVectHead->m_itemtype&&!pVectHead->m_pLineSeg)
{//曲线全部转为小线段处理
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,全部转小线段处理
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.计算直线向量角度函数。

//第一条直线起点,终点;第二条直线起点终点
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代码字符串转数据链表函数。voidCZCadToolFollowDemoDlg::CncLinkedList_StringToLink(CStringFileContentLine,struct_CncData*CncData)
{
FileContentLine.TrimRight();//去掉右边的空格
FileContentLine.TrimLeft();//去掉左边的空格
FileContentLine.Replace(_T(""),_T(""));
struct_MoveDatamovepara;
CncLinkedList_InsertNodebyTail(CncData,movepara);
//找到最后一个节点
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://切割结束
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.运动线程函数。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);//设置G00定位速度
ZAux_Direct_SetSpeed(g_handle,0,lfv_SpeedG01);//设置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直线//直线不用转刀,但是如果G01与G01,不是G00与G01,运动结束后需要转刀
{
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导图与刀向跟随应用”查看。

完整代码获取地址

wKgZO2gcUlOAf79aAAFWabRTPOo862.png

本次,正运动技术PCIe EtherCAT实时运动控制卡PCIE464的CAD导图与刀向跟随应用,就分享到这里。

更多精彩内容请关注“正运动小助手”公众号,需要相关开发环境与例程代码,请咨询正运动技术销售工程师:400-089-8936。

本文由正运动技术原创,欢迎大家转载,共同学习,一起提高中国智能制造水平。文章版权归正运动技术所有,如有转载请注明文章来源。

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • CAD
    CAD
    +关注

    关注

    18

    文章

    1134

    浏览量

    76188
  • 运动控制
    +关注

    关注

    5

    文章

    793

    浏览量

    34278
  • 运动控制卡
    +关注

    关注

    7

    文章

    126

    浏览量

    16043
  • 正运动技术
    +关注

    关注

    0

    文章

    135

    浏览量

    847
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    PCIe EtherCAT实时运动控制卡PCIE464的IO与编码器读写应用

    C#进行PCIe EtherCAT运动控制卡的项目开发和快速读取多个IO和轴编码器位置的例程。
    的头像 发表于 07-17 14:47 1904次阅读
    <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与编码器读写应用

    【正运动】高速高精,超高实时性的PCIe EtherCAT实时运动控制卡 | PCIE464

    产品摘要正运动技术PCIE464运动控制卡,提供高效的工业运动控制解决方案。用户可直接将
    发表于 01-24 09:48

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

    控制卡PCIe
    正运动技术
    发布于 :2024年01月31日 14:31:05

    PCIe EtherCAT实时运动控制卡PCIE464的IO与编码器读写应用# 正运动技术# 运动控制卡

    编码器运动控制卡
    正运动技术
    发布于 :2024年07月23日 09:37:31

    EtherCAT运动控制卡之ECI2820如何使用

    轴直线插补、任意圆弧插补、空间圆弧、螺旋插补、电子凸轮、电子齿轮、同步跟随、虚拟轴、机械手指令等;采用优化的网络通讯协议可以实现实时运动控制。  ECI2828系列
    发表于 09-01 06:24

    不止10倍提速!PCIe EtherCAT实时运动控制卡XPCIE1032H 等您评测!

    PCIe实时运动控制卡助力EtherCAT高速高精运动控制应用!
    的头像 发表于 06-26 10:14 8275次阅读
    不止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超高速实时运动控制卡在六面外观视觉检测上的应用

    超高速视觉筛选机PCIe实时运动控制卡XPCIE1028
    的头像 发表于 08-22 09:31 1603次阅读
    <b class='flag-5'>PCIE</b>超高速<b class='flag-5'>实时运动</b><b class='flag-5'>控制卡</b>在六面外观视觉检测上的应用

    高速视觉筛选机PCIe实时运动控制卡XPCIE1028简介

    本次的深圳慕尼黑华南电子展正运动技术将携高速视觉筛选机PCIe实时运动控制卡XPCIE1028亮相。此外,我们还为您准备了的新互动模式,您将有机会赢得超值礼品!
    的头像 发表于 11-06 16:00 1092次阅读
    高速视觉筛选机<b class='flag-5'>PCIe</b><b class='flag-5'>实时运动</b><b class='flag-5'>控制卡</b>XPCIE1028简介

    PCIE464 — 高速高精,超高实时性的PCIe EtherCAT实时运动控制卡

    运动高速高精运动控制卡家族迎来新成员!
    的头像 发表于 01-17 16:29 1771次阅读
    <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

    运动技术PCIE464运动控制卡,提供高效的工业运动控制解决方案。用户可直接将
    发表于 01-26 14:39 2276次阅读

    PCIE464M — 高速高精,超高速PCIe EtherCAT实时运动控制卡

    运动“高速高精运动控制卡”家族再添一员猛将!
    的头像 发表于 05-31 11:17 1309次阅读
    <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实时运动控制卡的双盘视觉筛选机上位机开发应用

    PCIe实时运动控制卡的双盘视觉筛选机上位机开发应用
    的头像 发表于 10-10 10:15 1184次阅读
    <b class='flag-5'>PCIe</b><b class='flag-5'>实时运动</b><b class='flag-5'>控制卡</b>的双盘视觉筛选机上位机开发应用

    PCIe EtherCAT实时运动控制卡PCIE464同步跟随/皮带跟随加工应用

    MOVESYNC指令实现同步/皮带跟随应用
    的头像 发表于 06-04 11:17 637次阅读
    <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>同步<b class='flag-5'>跟随</b>/皮带<b class='flag-5'>跟随</b>加工应用

    全球首创!PCIe实时6通道EtherCAT运动控制卡上市!

    PCle超实用6通道EtherCAT运动控制卡助您实现更极速精准的运动控制
    的头像 发表于 07-18 10:32 658次阅读
    全球首创!<b class='flag-5'>PCIe</b>超<b class='flag-5'>实时</b>6通道<b class='flag-5'>EtherCAT</b><b class='flag-5'>运动</b><b class='flag-5'>控制卡</b>上市!