<nobr id="zkazv"></nobr>

      午夜精品一区二区三区成人,中文字幕av一区二区,亚洲AVAV天堂AV在线网阿V,肥臀浪妇太爽了快点再快点,国产网友愉拍精品视频手机,国产精品无码a∨麻豆,久久中文字幕一区二区,a级国产乱理伦片在线观看al
      首頁 新聞 工控搜 論壇 廠商論壇 產品 方案 廠商 人才 文摘 下載 展覽
      中華工控網首頁
        P L C | 變頻器與傳動 | 傳感器 | 現場檢測儀表 | 工控軟件 | 人機界面 | 運動控制
        D C S | 工業以太網 | 現場總線 | 顯示調節儀表 | 數據采集 | 數傳測控 | 工業安全
        電 源 | 嵌入式系統 | PC based | 機柜箱體殼體 | 低壓電器 | 機器視覺
      PCIe EtherCAT實時運動控制卡PCIE464的CAD導圖與刀向跟隨應用
      深圳市正運動技術有限公司
      收藏本文     查看收藏

      一.硬件介紹

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

      PCIE464運動控制卡.png

      PCIE464運動控制卡適合于多軸點位運動、插補運動、軌跡規劃、手輪控制、編碼器位置檢測、IO控制、位置鎖存等功能的應用。

      PCIE464運動控制卡適用于3C電子加工、檢測設備、半導體設備、SMT加工、激光加工、光通訊設備、鋰電及光伏設備、以及非標自動化設備等高速高精應用場合。

      PCIE464運動控制卡接線.png

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

      API.png


       

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

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

      二.接線參考

      1.IN數字量輸入接口

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

      IN數字量輸入接口.png

      2.OUT數字量輸出接口

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

      OUT數字量輸出接口.png

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

      單端脈沖接線圖.png

      單端脈沖接線圖

      差分脈沖接線圖.png

      差分脈沖接線圖

      單端編碼器接線圖.png

      單端編碼器接線圖

      差分編碼器接線圖.png

      差分編碼器接線圖

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

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

      CAD解析.png

      1.CAD圖紙解析

      正運動技術提供開放的ZmotionCadEx庫,可導入DXF、Ai、Plt、Dst圖紙,可以生成運動坐標數據轉G代碼、zbasic運動指令、或直接PC函數執行運動。

      CAD圖紙解析.png

      2.刀向跟隨計算

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

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

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

      刀向跟隨計算.png

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

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

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

      四.MFC與C++編程實現

      1.首先打開Visual Studio 2022,點擊創建新項目。

      創建新項目.png

      2.選擇開發語言為“Visual C++”和程序類型“MFC應用程序”。

      選擇開發語言.png

      3.點擊下一步即可。

      1.png

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

      2.png

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

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

      PC函數庫.png

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

      下載.png

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

      函數庫另存為.png

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

      3.png

      6.將廠商提供的C++庫文件和相關頭文件復制到新建的項目里。

      4.png

      7.在項目中添加靜態庫和相關頭文件。

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

      5.png

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

      6.png

      8.聲明用到的頭文件。

      7.png

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

      五.查看PC函數手冊,熟悉相關函數接口

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

      PC函數手冊.png

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

      PC指令.png

      3.查看ZmotionCadEx.h中關于CAD圖處理的函數接口。

      CAD圖處理函數接口.png

      六.MFC實現CAD導入與刀向跟隨

      1.例程界面如下。

      MFC實現CAD導入與刀向跟隨.png

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

      BOOL CZCadToolFollowDemoDlg::OnInitDialog()
      {
          CDialogEx::OnInitDialog();
          // 設置此對話框的圖標。  當應用程序主窗口不是對話框時,框架將自動
          //  執行此操作
          SetIcon(m_hIcon, TRUE);     // 設置大圖標
          SetIcon(m_hIcon, FALSE);    // 設置小圖標
          // TODO: 在此添加額外的初始化代碼
          m_DlgRect.SetRect(0, 0, 0, 0);//初始化對話框大小存儲變量
          CRect rect;
          GetClientRect(&rect); //取客戶區大小
          Old.x = rect.right - rect.left;
          Old.y = rect.bottom - rect.top;
          GetClientRect(&m_DlgRect);
          GetDlgItem(IDC_PIC_VIEW)->GetClientRect(m_rcView);
          /*--------------------控制器連接--------------------*/
          char str_ip[] = "192.168.0.11";
          int m_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
                  {
                      HANDLE hProcessHandle;
                      ULONG nProcessID;
                      HWND TheWindow;
                      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 (int i = 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坐標用于顯示與刷新繪制圖像。

      void CZCadToolFollowDemoDlg::OnTimer(UINT_PTR nIDEvent)
      {
          // 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.消息傳遞函數中響應手動運動按鈕代碼。

      BOOL CZCadToolFollowDemoDlg::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); }
          }
          else if (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); }
          }
          return CDialogEx::PreTranslateMessage(pMsg);
      }




      5.繪圖函數。

      void CZCadToolFollowDemoDlg::OnDraw(CDC *pDC)
      {
          CDC dcMem;
          CBitmap bmp;
          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());
          //實際顯示的區域,預留邊距(不完全撐滿)
          double WinWidth = m_rcView.Width() - 65;
          double WinHeight = m_rcView.Height() - 65;
          // 實際的區域
          double ObjectPixWidth = 0.0, ObjectPixHeight = 0.0;
          //需要更新初始化顯示比例
          if (!m_bInitZoomTran)
          {
              //根據視圖范圍、圖形范圍,計算顯示比例及偏移
              if ((NULL != m_pVectGroup) || (NULL != m_pDib))
              {
                  float fLeft = 0.0, fBottom = 0.0, fWidth = 0.0, fHeight = 0.0;
                  double dScale = 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文件
      void CZCadToolFollowDemoDlg::OnBnClickedBtnOpenCad()
      {
          CString gReadFilePathName;
          CFileDialog fileDlg(true, _T("dxf"), _T("*.dxf"), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T("DXF Files (*.dxf)|*.dxf|AI File(*.ai)|*.ai|PLT File(*.plt)|*.plt|DST Files (*.dst)|*.dst|All Files (*.*)|*.*||"), NULL);
          if (fileDlg.DoModal() == IDOK)    //彈出對話框
          {
              gReadFilePathName = fileDlg.GetPathName();//得到完整的文件名和目錄名拓展名
              CString filename = fileDlg.GetFileName();
              // 取得擴展名
              CString strExtName = 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代碼并生成運動數據鏈表
              CString m_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代碼
      CString CZCadToolFollowDemoDlg::VectToNcCode(Struct_ZCad_VectGroup *pVectGroup)
      {
          if (!pVectGroup)
          { //圖形數據為空
              AfxMessageBox(L"數據為空!");
              return L"";
          }
          CncLinkedList_ClearMyList(m_pCncData);
          m_pCncData=CncLinkedList_CreatList();
          CString strOut, strSingleLen; //輸出的G代碼
          strOut.Format(L"M3\r\nG90\r\nG0 X0.000 Y0.000\r\n"); //默認絕對運行
          CncLinkedList_StringToLink(L"G0 X0.000 Y0.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"G0 X%.4lf Y%.4lf\r\n", pEffectSeg->x1, pEffectSeg->y1);
                  CncLinkedList_StringToLink(strSingleLen, m_pCncData);
                  strOut += strSingleLen;
                  if (ZCAD_ITEMTYPE_VECTArc == pVectHead->m_itemtype)
                  { //圓/圓弧的情況下//不會進入此if,全部轉小線段處理
                      CString strSide; //圓的方向
                      double dX0 = min(pVectHead->m_pLine->x1, pVectHead->m_pLine->x2) + fabs(pVectHead->m_pLine->x1 - pVectHead->m_pLine->x2) / 2;
                      double dY0 = min(pVectHead->m_pLine->y1, pVectHead->m_pLine->y2) + fabs(pVectHead->m_pLine->y1 - pVectHead->m_pLine->y2) / 2; //圓心的絕對坐標
                      double dR = fabs(pVectHead->m_pLine->x1 - pVectHead->m_pLine->x2) / 2.0; //半徑
                      if (pVectHead->m_pLine->x1 m_pLine->x2 && pVectHead->m_pLine->y1 m_pLine->y2)
                      { //逆時針G03
                          strSide = "G3";
                      }
                      else
                      { //順時針G02
                          strSide = "G2";
                      }
                      strSingleLen.Format(L"%s X%.4lf Y%.4lf I%.4lf J%.4lf\r\n", 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"G1 X%.4lf Y%.4lf\r\n", 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;
          return strOut;
      }



      8.計算直線向量角度函數。

      //第一條直線起點,終點;第二條直線起點終點
      double GetLineVectorArg(double line1StartX, double line1StartY, double line1EndX, double line1EndY)
      {
          float a[4];// 存放第一個向量的起點和重點
          float b[4];// 存放第二個向量的起點和重點
          a[0] = line1StartX;
          a[1] = line1StartY;
          a[2] = line1EndX;
          a[3] = line1EndY;
          if (a[0] == a[2] && a[1] == a[3])
          {
              return 0;
          }
          b[0] = 0;
          b[1] = 0;
          b[2] = 1000;
          b[3] = 0;
          float vector1x = a[0] - a[2];
          float vector1y = a[1] - a[3];
          float vector2x = b[0] - b[2];
          float vector2y = b[1] - b[3];
          CString  TRACEtest;
          float ang = 0;
          //θ=acos(v1⋅v2/||v1||||v2||)
          float tmp = ((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)    double tmp2 = (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代碼字符串轉數據鏈表函數。

      void CZCadToolFollowDemoDlg::CncLinkedList_StringToLink(CString FileContentLine, struct_CncData * CncData)
      {
          FileContentLine.TrimRight();//去掉右邊的空格
          FileContentLine.TrimLeft();//去掉左邊的空格
          FileContentLine.Replace(_T(" "), _T(""));
          struct_MoveData movepara;
          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;
              }
              CString str_tmp = FileContentLine.Right(FileContentLine.GetLength() - FileContentLine.Find('G') - 1);//剩余G后字符串
              int num_tmp = _tstof(str_tmp);
              CString str_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)
              {
                  case CNC_TRACK_LINE_SEEK://0定位
                      cncData_lastNode->m_movepara.m_type = CNC_TRACK_LINE_SEEK;
                      break;
                  case CNC_TRACK_LINE://1直線
                      cncData_lastNode->m_movepara.m_type = CNC_TRACK_LINE;
                      break;
                  case CNC_TRACK_ARC://2圓弧
                      cncData_lastNode->m_movepara.m_type = CNC_TRACK_ARC;
                      break;
                  case CNC_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;
                  }
              }
              //獲取起點坐標
              float startx, 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;
                  int liv_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)
              {
                  case CNC_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;
                  case CNC_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;
                  }
                  case CNC_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;
                      float m_c_x = startx + cncData_lastNode->m_movepara.m_center.x;//圓心絕對坐標
                      float m_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;
                  }
                  case CNC_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;
                      float m_c_x = startx + cncData_lastNode->m_movepara.m_center.x;//圓心絕對坐標
                      float m_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;
              }
              CString str_tmp = FileContentLine.Right(FileContentLine.GetLength() - FileContentLine.Find('M') - 1);//剩余M后字符串
              int num_tmp = _tstof(str_tmp);
              switch (num_tmp)
              {
                  case 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_START;
                      break;
                  case 9:  //下刀
                      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;
                  case 10: //抬刀
                      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;
                  case 4:   //切割結束
                  case 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 = 4;
                      break;
                  case 30: //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.運動線程函數。

      int CZCadToolFollowDemoDlg::CncLinkedList_Move(struct_CncData * List)
      {
          if (NULL == List)
          {
              return-1;
          }
          struct_CncData *ptr = List->m_pnext;
          CString m_ShowData = L"";
          float fX = 0.0f, fY = 0.0f, fC = 0.0f, fI = 0.0f, fJ = 0.0f;
          int axislist[3] = { 0,1,2 };  //運動軸列表,其中軸1為主軸
          float circ_endc = 0.0f, circ_stratc = 0.0f;
          float poslist[3] = { 0.0f };
          int m_liv_ZmcMoveRe = 0;
          float lfv_SpeedG00 = 1000;
          float lfv_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)
              {
                  case CNC_TRACK_START://切割開始
                  {
                      break;
                  }
                  case CNC_TRACK_LINE_SEEK://0定位
                  {
                      m_ShowData.Format(_T("G00 X%f Y%f \r\n"), fX, fY);
                      TRACE(m_ShowData);
                      struct_CncData *cncData_lastNode_next = ptr;
                      int liv_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;
                  }
                  case CNC_TRACK_LINE://1直線//直線不用轉刀,但是如果G01與G01,不是G00與G01,運動結束后需要轉刀
                  {
                      m_ShowData.Format(_T("G01 X%f Y%f  \r\n"), 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("\r\n");
                      }
                      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;
          }
          return 0;
      }

      七.效果演示

      效果演示1.png

      效果演示2.png

      效果演示3.png

      效果演示4.png

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


       

      完整代碼獲取地址

      二維碼.png

      本次,正運動技術PCIe EtherCAT實時運動控制卡PCIE464的CAD導圖與刀向跟隨應用,就分享到這里。

      更多精彩內容請關注“正運動小助手”公眾號,需要相關開發環境與例程代碼,請咨詢正運動技術銷售工程師:400-089-8936。

      本文由正運動技術原創,歡迎大家轉載,共同學習,一起提高中國智能制造水平。文章版權歸正運動技術所有,如有轉載請注明文章來源。

       

      二維碼.png

      正運動技術專注于運動控制技術研究和通用運動控制軟硬件產品的研發,是國家級高新技術企業。正運動技術匯集了來自華為、中興等公司的優秀人才,在堅持自主創新的同時,積極聯合各大高校協同運動控制基礎技術的研究,是國內工控領域發展最快的企業之一,也是國內少有、完整掌握運動控制核心技術和實時工控軟件平臺技術的企業。主要業務有:運動控制卡_運動控制器_EtherCAT運動控制卡_EtherCAT控制器_運動控制系統_視覺控制器__運動控制PLC_運動控制_機器人控制器_視覺定位_XPCIe/XPCI系列運動控制卡等。


       

      狀 態: 離線

      公司簡介
      產品目錄

      公司名稱: 深圳市正運動技術有限公司
      聯 系 人: 戴德弟
      電  話: 0755-32976042
      傳  真: 0755-2606 6955
      地  址: 深圳市寶安區西鄉洲石路陽光工業園A1棟5樓
      郵  編: 518100
      主  頁:
       
      該廠商相關技術文摘:
      強實時運動控制內核MotionRT750(七):us級高速交互之Qt,為智能裝備提速
      【2025上海工博會】高速高精運動控制卡應用預覽(一)
      強實時運動控制內核MotionRT750(六):us級高速交互之C++,為智能裝備提速
      解鎖光未來!9月 CIOE 2025,正運動邀您相聚深圳,共赴光電盛宴!
      機器視覺運動控制一體機在線路板跟隨灌膠上的應用
      強實時運動控制內核MotionRT750(五):EtherCAT總線冗余讓生產制造更可靠
      深圳·EelE智博會:智控賦能,驅動未來制造
      機器視覺運動控制一體機在喇叭跟隨點膠上的應用
      強實時運動控制內核MotionRT750(四):高速貼裝應用中的拱形運動
      聚焦深圳國際電子展 | 正運動攜熱門產品和方案!等您來體驗!
      超高速EtherCAT實時運動控制卡在高速半導體固晶機上的應用
      強實時運動控制內核MotionRT750(三):us級高速交互之C#,為智能裝備提速
      更多文摘...
      立即發送詢問信息在線聯系該技術文摘廠商:
      用戶名: 密碼: 免費注冊為中華工控網會員
      請留下您的有效聯系方式,以方便我們及時與您聯絡

      關于我們 | 聯系我們 | 廣告服務 | 本站動態 | 友情鏈接 | 法律聲明 | 不良信息舉報
      工控網客服熱線:0755-86369299
      版權所有 中華工控網 Copyright©2022 Gkong.com, All Rights Reserved

      主站蜘蛛池模板: 一 级做人爱全视频在线看| 免费观看欧美猛交视频黑人| 日韩人妻精品中文字幕| 国产AV影片麻豆精品传媒| 国产亚洲综合区成人国产| 国产香蕉一区二区三区在线视频| 99riav精品免费视频观看| 国产蜜臀在线一区二区三区| 好爽毛片一区二区三区四| 精品一精品国产一级毛片| 韩国美女福利视频一区二区| 免费无码肉片在线观看| 亚洲熟妇自偷自拍另欧美| 国产成人精品午夜在线观看| 亚洲精品日本一区二区| 成人午夜视频一区二区无码 | 国产在线一区二区不卡| 久热这里只有精品12| 国产精品自产拍在线播放| 日本大片免A费观看视频三区| 国内精品免费久久久久电影院97| 亚洲真人无码永久在线| 中文字幕精品av一区二区五区| 日韩精品一区二区亚洲av| 国产福利深夜在线播放| 亚洲AV成人片在线观看| 羞羞影院午夜男女爽爽免费视频| 亚洲精品麻豆一二三区| 精品国产午夜福利在线观看| 日韩黄色av一区二区三区| 人妻精品动漫H无码中字| 国产av无码国产av毛片| 毛片网站在线观看| 丰满人妻熟妇乱又仑精品| 无码国内精品久久人妻蜜桃| 91老肥熟女九色老女人| 国产精品自在自线视频| 亚洲国产成人va在线观看天堂| 国产精品高清中文字幕| 国产情侣激情在线对白| 国产午夜精品在人线播放|