今天,正運動小助手給大家分享一下EtherCAT運動控制卡的自定義運動曲線,主要介紹一下如何通過在線命令封裝自己想使用的Basic指令到上位機接口中供上位機調(diào)用。
一、ECI2828運動控制卡的硬件介紹
ECI2828系列控制卡支持最多達16軸直線插補、任意圓弧插補、空間圓弧、螺旋插補、電子凸輪、電子齒輪、同步跟隨、虛擬軸、機械手指令等。采用優(yōu)化的網(wǎng)絡通訊協(xié)議可以實現(xiàn)實時的運動控制。
ECI2828系列運動控制卡支持以太網(wǎng),232通訊接口和電腦相連,接收電腦的指令運行,可以通過EtherCAT總線和CAN總線去連接各個擴展模塊,從而擴展輸入輸出點數(shù)或運動軸。
ECI2828系列運動控制卡的應用程序可以使用 VC、VB、VS、C++、C#等多種高級語言來開發(fā),程序運行時需要動態(tài)庫zmotion.dll。調(diào)試時可以把ZDevelop軟件同時連接到控制器,從而方便調(diào)試、方便觀察。
ECI2828控制卡本身的硬件接口也十分豐富。具有8個本地脈沖軸,每個軸帶獨立編碼器,最多16個虛擬軸。板上自帶24個通用輸入口(其中4路是高速輸入口可以作為高速鎖存使用),16個通用輸出口(其中4路是高速輸出口可以實現(xiàn)4路的PSO),2路AD和DA。
自帶1個 RS232串口,1個以太網(wǎng)接口。帶一個CAN總線接口,支持通過ZCAN協(xié)議來連接擴展模塊。帶一個CANOPEN接口(功能需要軟件版本支持)。帶一個EtherCAT總線接口可擴展數(shù)字模擬IO以及脈沖定位模塊等,帶一個手輪接口。
二、運動控制卡的Qt開發(fā)流程 1.新建Qt 項目
圖 1-1新建Qt項目
圖 1-2選擇項目路徑
?
圖 1-3選擇Qt編譯套件(kits)
圖1-4選擇基類
(1)將函數(shù)庫相關的文件復制到新建的項目中。
圖1-5庫文件復制
(2)向新建的項目里面添加函數(shù)庫的靜態(tài)庫。(zmotion.lib)
圖1-6添加函數(shù)庫1
圖1-7添加函數(shù)庫2
圖 1-8添加函數(shù)庫3
(3)添加函數(shù)庫相關的頭文件到項目中(zmcaux.cpp、zmcaux.h、Zmotion.h)。
圖 1-9添加頭文件
(4)聲明相關頭文件,并定義連接句柄。
圖1-10聲明頭文件
2.PC函數(shù)介紹
(1)PC函數(shù)手冊也在光盤資料里面,具體路徑如下:“光盤資料8.PC函數(shù)函數(shù)庫2.1Motion函數(shù)庫編程手冊V2.1.pdf”。
(2)PC編程一般需要建立上位機和控制器之間的鏈接。和控制卡的連接一般習慣使用網(wǎng)口方式進行鏈接,具體接口說明如下。
指令7 | ZAux_OpenEth |
指令原型 | int32 __stdcall ZAux_OpenEth(char *ipaddr, ZMC_HANDLE * phandle) |
指令說明 | 以太網(wǎng)鏈接控制器。 |
輸入參數(shù) | 輸入?yún)?shù)1個,詳細見下面說明。 |
ipaddr | 鏈接的IP地址。 |
輸出參數(shù) | 輸出參數(shù)1個,詳細見下面說明。 |
Phandle | 返回的鏈接句柄。 |
返回值 | 詳細見錯誤碼說明。 |
(3)如果想將Basic指令封裝成上位機可以直接調(diào)用的接口就必須使用在線命令這個接口進行函數(shù)封裝,在線命令接口說明如下。
指令 | 說明 |
ZAux_Execute | 直接發(fā)送指令(當控制器沒有緩沖時自動阻塞) |
ZAux_DirectCommand | 直接發(fā)送指令(用于調(diào)試,只支持少數(shù)命令暫時不支持) |
指令1 | ZAux_Execute |
指令原型 | int32 __stdcall ZAux_Execute(ZMC_HANDLE handle, const char *pszCommand, char *psResponse, uint32 uiResponseLength) |
指令說明 | 發(fā)送字符串命令到控制器(當控制器沒有緩沖時自動阻賽)。 |
輸入?yún)?shù) | 共有3個輸入?yún)?shù),見下方說明。 |
handle | 鏈接句柄。 |
pszCommand | 發(fā)送的命令字符串。 |
uiResponseLength | 返回的字符長度。 |
輸出參數(shù) | 共有1個輸出參數(shù),見下方說明。 |
psResponse | 返回的字符串。 |
返回值 | 見錯誤碼詳細說明。 |
指令2 | ZAux_DirectCommand |
指令原型 | int32 __stdcall ZAux_DirectCommand(ZMC_HANDLE handle, const char *pszCommand,char *psResponse, uint32 uiResponseLength) |
指令說明 | 發(fā)送字符串命令到控制器(用于調(diào)試,只支持少數(shù)命令,暫時不支持)。 |
輸入?yún)?shù) | 共有3個輸入?yún)?shù),見下方說明。 |
handle | 鏈接句柄。 |
pszCommand | 發(fā)送的命令字符串。 |
uiResponseLength | 返回的字符長度。 |
輸出參數(shù) | 共有1個輸出參數(shù),見下方說明。 |
uiResponseLength | 返回的字符串。 |
返回值 | 見錯誤碼詳細說明。 |
(4)Basic指令SPEED的封裝示例。
3.Qt進行Move_Pt指令的封裝,實現(xiàn)自定義曲線的運動。
(1)自定義曲線運動例程Qt界面如下。
(2)通過Qt的connect將【連接按鈕】的單擊事件綁定一個槽函數(shù)進行鏈接控制器的操作。
//定義一個定時器 QTimer *UpData = new QTimer(this); connect(UpData,&QTimer::timeout,this,[=](){ if(g_handle!=0) { //獲取軸位置信息 ZAux_Direct_GetAllAxisPara(g_handle,"DPOS",AxisNum,Dpos); ui->DposX->setText(QString("%1").arg(Dpos[0])); ui->DposY->setText(QString("%1").arg(Dpos[1])); ui->DposZ->setText(QString("%1").arg(Dpos[2])); ui->DposU->setText(QString("%1").arg(Dpos[3])); //獲取軸速度信息 ZAux_Direct_GetAllAxisPara(g_handle,"MSPEED",AxisNum,Mspeed); ui->MspeedX->setText(QString("%1").arg(Mspeed[0])); ui->MspeedY->setText(QString("%1").arg(Mspeed[1])); ui->MspeedZ->setText(QString("%1").arg(Mspeed[2])); ui->MspeedU->setText(QString("%1").arg(Mspeed[3])); //獲取各個軸的運動情況 floatidle[4]={0}; ZAux_Direct_GetAllAxisPara(g_handle,"idle",AxisNum,idle); idle[0]=idle[0]+idle[1]+idle[2]+idle[3]; if(idle[0]>(-4)) { MotionStatus=1;//運動中 } else { MotionStatus=0; } } }(3)通過定時器更新控制器各個軸的位置和速度信息。
//定義一個定時器 QTimer*UpData =newQTimer(this); connect(UpData,&QTimer::timeout,this,[=](){ if(g_handle!=0) { //獲取軸位置信息 ZAux_Direct_GetAllAxisPara(g_handle,"DPOS",AxisNum,Dpos); ui->DposX->setText(QString("%1").arg(Dpos[0])); ui->DposY->setText(QString("%1").arg(Dpos[1])); ui->DposZ->setText(QString("%1").arg(Dpos[2])); ui->DposU->setText(QString("%1").arg(Dpos[3])); //獲取軸速度信息 ZAux_Direct_GetAllAxisPara(g_handle,"MSPEED",AxisNum,Mspeed); ui->MspeedX->setText(QString("%1").arg(Mspeed[0])); ui->MspeedY->setText(QString("%1").arg(Mspeed[1])); ui->MspeedZ->setText(QString("%1").arg(Mspeed[2])); ui->MspeedU->setText(QString("%1").arg(Mspeed[3])); //獲取各個軸的運動情況 floatidle[4]={0}; ZAux_Direct_GetAllAxisPara(g_handle,"idle",AxisNum,idle); idle[0]=idle[0]+idle[1]+idle[2]+idle[3]; if(idle[0]>(-4)) { MotionStatus=1;//運動中 } else { MotionStatus=0; } } }
(4)Basic指令Move_Pt的介紹。
(5)Move_Pt的接口封裝。
A.通過在線命令ZAux_DirectCommand()進行接口封裝。
/************************************************************* Description: 單位時間距離 Input: 卡鏈接handle 運動軸數(shù)、軸列表 運動時間 ticks單位, 1ticks≈1ms 運動距離 units單位 Output: 無 Return: 錯誤碼 *************************************************************/ int32 MyApi::ZAux_Direct_MovePt(ZMC_HANDLE handle, int iAxisNum, int *piAxisList, int iTime, float *pfDisList) { char cmdbuff[2048],tempbuff[2048]; char cmdbuffAck[2048]; //輸入?yún)?shù)判斷 if((0 > iAxisNum || iAxisNum > MAX_AXIS_AUX)) return ERR_AUX_PARAERR; if(NULL == piAxisList) return ERR_AUX_PARAERR; if(iTime<=0) return ERR_AUX_PARAERR; if(NULL == pfDisList) return ERR_AUX_PARAERR; //生成指令選擇運動的軸......Basic指令BASE(0,1,2,3)表示選擇軸0、軸1、軸2、軸3 //通過字符串拼接指令封裝Basic選擇軸指令BASE(piAxisList[0],piAxisList[1],.....piAxisList[i]) strcpy(cmdbuff, "BASE("); for(int i = 0; i< iAxisNum-1; i++) { sprintf(tempbuff, "%d,",piAxisList[i]); strcat(cmdbuff, tempbuff); } sprintf(tempbuff, "%d)",piAxisList[iAxisNum-1]); strcat(cmdbuff, tempbuff); //換行繼續(xù)封裝Basic指令 strcat(cmdbuff, " "); //生成單位時間運動距離指令,......Basic指令通過Move_PT(ticks, dis1,dis2…)實現(xiàn) sprintf(tempbuff, "Move_PT(%d,",iTime); strcat(cmdbuff, tempbuff); //封裝各個軸的運動距離 for(int i = 0; i< iAxisNum-1; i++) { sprintf(tempbuff, "%f,",pfDisList[i]); strcat(cmdbuff, tempbuff); } sprintf(tempbuff, "%f)",pfDisList[iAxisNum-1]); strcat(cmdbuff, tempbuff); //調(diào)用命令執(zhí)行函數(shù) //printf("%s",cmdbuff); return ZAux_DirectCommand(handle, cmdbuff, cmdbuffAck, 2048); }B.Qt例程調(diào)用剛剛封裝的接口MyApi::ZAux_Direct_MovePt()。
//啟動Move_Pt運動 voidWidget::on_PtStartButton_clicked() { if(0==MotionStatus) { intbuffNum=0; //獲取0軸剩余緩沖區(qū)數(shù)目,緩沖區(qū)數(shù)目足夠才下發(fā)指令 ZAux_Direct_GetRemain_LineBuffer(g_handle,0,&buffNum); if(buffNum>3) { intAxisList[4]={0,1,2,3}; floatDisList[3][5]; for(inti=0;i<3;i++) ?????????{ ????????????for(intj=0;j<5;j++) ????????????{ ???????????????DisList[i][j]=LineData[i][j]->text().toFloat(); } //調(diào)用自己封裝的函數(shù)接口進行MOVE_PT運動 myapi->ZAux_Direct_MovePt(g_handle,AxisNum,AxisList,(int)(DisList[i][0]),&DisList[i][1]); } } else { QMessageBox::warning(this,"warning","軸緩沖區(qū)剩余不足"); } } else { QMessageBox::warning(this,"warning","系統(tǒng)在運行中......"); } }C.示波器波形抓取。
(6)封裝一個API可以下發(fā)多個move_ptabs指令進行加工。 A.一次下發(fā)多個move_ptabs指令的封裝。
/************************************************************* Description: 一次發(fā)送多個單位時間距離指令 Input: 卡鏈接handle 運動軸數(shù)、軸列表 運動時間 ticks單位, 1ticks≈1ms 運動距離 units單位 Output: 無 Return: 錯誤碼 *************************************************************/ int32 MyApi::ZAux_Direct_MovePtAbsS(ZMC_HANDLE handle, int iAxisNum, int *piAxisList, int ApiNum,int *iTime, float *pfDisList) { charcmdbuff[2048*128],tempbuff[2048]; charcmdbuffAck[2048]; //輸入?yún)?shù)判斷 if((0>iAxisNum||iAxisNum>MAX_AXIS_AUX))returnERR_AUX_PARAERR;//軸數(shù)不正確 if(NULL==piAxisList)returnERR_AUX_PARAERR;//軸列表空 if(iTime==0)returnERR_AUX_PARAERR;//時間列表空 if(NULL==pfDisList)returnERR_AUX_PARAERR;//運動距離列表空 if((ApiNum<0)||(ApiNum>50))returnERR_AUX_PARAERR;//Api數(shù)目不對 //生成指令選擇運動的軸......Basic指令BASE(0,1,2,3)表示選擇軸0、軸1、軸2、軸3 //通過字符串拼接指令封裝Basic選擇軸指令BASE(piAxisList[0],piAxisList[1],.....piAxisList[i]) strcpy(cmdbuff,"BASE("); for(inti=0;i0) { //生成單位時間運動距離指令,......Basic指令通過Move_PT(ticks,dis1,dis2…)實現(xiàn) sprintf(tempbuff,"Move_PtAbs(%d,",iTime[j]); strcat(cmdbuff,tempbuff); //封裝各個軸的運動距離 for(inti=0;i
B.Qt例程調(diào)用剛封裝的接口MyApi::ZAux_Direct_MovePtAbsS()。
//獲取軸運動緩沖剩余情況 ZAux_Direct_GetRemain_LineBuffer(g_handle,0,&buffNum); if((buffNum>ApiNum*2)&&(SendNum*1<(4*ui->HorizoScale->text().toFloat()))) { Num = (float) 4*ui->HorizoScale->text().toFloat(); switch (RunType) { //((-sin(PI*2*i/T)/(PI*2))+i/T)*500 case 0: for(int i=0;iC.Qt抓取軸運動的位置數(shù)據(jù),產(chǎn)生位置波形圖。Canvas->StartPoint.setX(0); ui->Canvas->StartPoint.setY(-DisList[0]*EquivalentY); ui->Canvas->StopPoint.setX(0); ui->Canvas->StopPoint.setY(-DisList[0]*EquivalentY); TimerWaveform->start(10); QString Str; char buff[1204]; //發(fā)送在線命令啟動示波器 Str=QString("%1%2%3%4%5").arg("SCOPE(ON,1,").arg(0).arg(",").arg(3500).arg(",DPOS(0))"); ZAux_Execute(g_handle,Str.toLatin1().data(),buff,1024); ZAux_Trigger(g_handle); QThread::msleep(1); } myapi->ZAux_Direct_MovePtAbsS(g_handle,1,&AxisList,ApiNum,TimeList,DisList); } oidDraw::paintEvent(QPaintEvent*event) { if(DrawFlag!=0) { //實例化一個畫家this指繪圖設備 QPainterPainter(WaveformFigure); Painter.translate(0,(int)(ImgH/2)); //設置畫筆 QPenPen(QColor(255,0,0)); Pen.setWidth(4); Pen.setStyle(Qt::SolidLine); Painter.setPen(Pen); //發(fā)送觸發(fā)示波器抓取的命令 if((CurTriggerNum>=SingTriggerNum)) { qDebug()<<"觸發(fā)示波器"<D.抓波形圖查看效果。::iteratoriet; for(inti=0;i 0)) { Painter.drawLine(StartPoint,StopPoint); } } } }
a.Y=((-sin(PI*2*i/T)/(PI*2))+i/T)*500速度和位置曲線。
b.Qt抓取Y=((-sin(PI*2*i/T)/(PI*2))+i/T)*500的位置曲線。
本次,正運動技術EtherCAT運動控制卡的自定義運動曲線,就分享到這里。
審核編輯:劉清
-
以太網(wǎng)
+關注
關注
40文章
5343瀏覽量
170797 -
CAN總線
+關注
關注
145文章
1911瀏覽量
130560 -
上位機
+關注
關注
27文章
930瀏覽量
54696 -
EtherCAT總線
+關注
關注
5文章
68瀏覽量
5359
原文標題:EtherCAT運動控制卡的自定義運動曲線
文章出處:【微信號:伺服與運動控制,微信公眾號:伺服與運動控制】歡迎添加關注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關推薦
評論