今天,正運(yùn)動(dòng)小助手給大家分享一下EtherCAT運(yùn)動(dòng)控制卡的自定義運(yùn)動(dòng)曲線,主要介紹一下如何通過(guò)在線命令封裝自己想使用的Basic指令到上位機(jī)接口中供上位機(jī)調(diào)用。
一、ECI2828運(yùn)動(dòng)控制卡的硬件介紹
ECI2828系列控制卡支持最多達(dá)16軸直線插補(bǔ)、任意圓弧插補(bǔ)、空間圓弧、螺旋插補(bǔ)、電子凸輪、電子齒輪、同步跟隨、虛擬軸、機(jī)械手指令等。采用優(yōu)化的網(wǎng)絡(luò)通訊協(xié)議可以實(shí)現(xiàn)實(shí)時(shí)的運(yùn)動(dòng)控制。
ECI2828系列運(yùn)動(dòng)控制卡支持以太網(wǎng),232通訊接口和電腦相連,接收電腦的指令運(yùn)行,可以通過(guò)EtherCAT總線和CAN總線去連接各個(gè)擴(kuò)展模塊,從而擴(kuò)展輸入輸出點(diǎn)數(shù)或運(yùn)動(dòng)軸。
ECI2828系列運(yùn)動(dòng)控制卡的應(yīng)用程序可以使用 VC、VB、VS、C++、C#等多種高級(jí)語(yǔ)言來(lái)開(kāi)發(fā),程序運(yùn)行時(shí)需要?jiǎng)討B(tài)庫(kù)zmotion.dll。調(diào)試時(shí)可以把ZDevelop軟件同時(shí)連接到控制器,從而方便調(diào)試、方便觀察。
ECI2828控制卡本身的硬件接口也十分豐富。具有8個(gè)本地脈沖軸,每個(gè)軸帶獨(dú)立編碼器,最多16個(gè)虛擬軸。板上自帶24個(gè)通用輸入口(其中4路是高速輸入口可以作為高速鎖存使用),16個(gè)通用輸出口(其中4路是高速輸出口可以實(shí)現(xiàn)4路的PSO),2路AD和DA。
自帶1個(gè) RS232串口,1個(gè)以太網(wǎng)接口。帶一個(gè)CAN總線接口,支持通過(guò)ZCAN協(xié)議來(lái)連接擴(kuò)展模塊。帶一個(gè)CANOPEN接口(功能需要軟件版本支持)。帶一個(gè)EtherCAT總線接口可擴(kuò)展數(shù)字模擬IO以及脈沖定位模塊等,帶一個(gè)手輪接口。
二、運(yùn)動(dòng)控制卡的Qt開(kāi)發(fā)流程 1.新建Qt 項(xiàng)目
圖 1-1新建Qt項(xiàng)目
圖 1-2選擇項(xiàng)目路徑
?
圖 1-3選擇Qt編譯套件(kits)
圖1-4選擇基類
(1)將函數(shù)庫(kù)相關(guān)的文件復(fù)制到新建的項(xiàng)目中。
圖1-5庫(kù)文件復(fù)制
(2)向新建的項(xiàng)目里面添加函數(shù)庫(kù)的靜態(tài)庫(kù)。(zmotion.lib)
圖1-6添加函數(shù)庫(kù)1
圖1-7添加函數(shù)庫(kù)2
圖 1-8添加函數(shù)庫(kù)3
(3)添加函數(shù)庫(kù)相關(guān)的頭文件到項(xiàng)目中(zmcaux.cpp、zmcaux.h、Zmotion.h)。
圖 1-9添加頭文件
(4)聲明相關(guān)頭文件,并定義連接句柄。
圖1-10聲明頭文件
2.PC函數(shù)介紹
(1)PC函數(shù)手冊(cè)也在光盤資料里面,具體路徑如下:“光盤資料8.PC函數(shù)函數(shù)庫(kù)2.1Motion函數(shù)庫(kù)編程手冊(cè)V2.1.pdf”。
(2)PC編程一般需要建立上位機(jī)和控制器之間的鏈接。和控制卡的連接一般習(xí)慣使用網(wǎng)口方式進(jìn)行鏈接,具體接口說(shuō)明如下。
指令7 | ZAux_OpenEth |
指令原型 | int32 __stdcall ZAux_OpenEth(char *ipaddr, ZMC_HANDLE * phandle) |
指令說(shuō)明 | 以太網(wǎng)鏈接控制器。 |
輸入參數(shù) | 輸入?yún)?shù)1個(gè),詳細(xì)見(jiàn)下面說(shuō)明。 |
ipaddr | 鏈接的IP地址。 |
輸出參數(shù) | 輸出參數(shù)1個(gè),詳細(xì)見(jiàn)下面說(shuō)明。 |
Phandle | 返回的鏈接句柄。 |
返回值 | 詳細(xì)見(jiàn)錯(cuò)誤碼說(shuō)明。 |
(3)如果想將Basic指令封裝成上位機(jī)可以直接調(diào)用的接口就必須使用在線命令這個(gè)接口進(jìn)行函數(shù)封裝,在線命令接口說(shuō)明如下。
指令 | 說(shuō)明 |
ZAux_Execute | 直接發(fā)送指令(當(dāng)控制器沒(méi)有緩沖時(shí)自動(dòng)阻塞) |
ZAux_DirectCommand | 直接發(fā)送指令(用于調(diào)試,只支持少數(shù)命令暫時(shí)不支持) |
指令1 | ZAux_Execute |
指令原型 | int32 __stdcall ZAux_Execute(ZMC_HANDLE handle, const char *pszCommand, char *psResponse, uint32 uiResponseLength) |
指令說(shuō)明 | 發(fā)送字符串命令到控制器(當(dāng)控制器沒(méi)有緩沖時(shí)自動(dòng)阻賽)。 |
輸入?yún)?shù) | 共有3個(gè)輸入?yún)?shù),見(jiàn)下方說(shuō)明。 |
handle | 鏈接句柄。 |
pszCommand | 發(fā)送的命令字符串。 |
uiResponseLength | 返回的字符長(zhǎng)度。 |
輸出參數(shù) | 共有1個(gè)輸出參數(shù),見(jiàn)下方說(shuō)明。 |
psResponse | 返回的字符串。 |
返回值 | 見(jiàn)錯(cuò)誤碼詳細(xì)說(shuō)明。 |
指令2 | ZAux_DirectCommand |
指令原型 | int32 __stdcall ZAux_DirectCommand(ZMC_HANDLE handle, const char *pszCommand,char *psResponse, uint32 uiResponseLength) |
指令說(shuō)明 | 發(fā)送字符串命令到控制器(用于調(diào)試,只支持少數(shù)命令,暫時(shí)不支持)。 |
輸入?yún)?shù) | 共有3個(gè)輸入?yún)?shù),見(jiàn)下方說(shuō)明。 |
handle | 鏈接句柄。 |
pszCommand | 發(fā)送的命令字符串。 |
uiResponseLength | 返回的字符長(zhǎng)度。 |
輸出參數(shù) | 共有1個(gè)輸出參數(shù),見(jiàn)下方說(shuō)明。 |
uiResponseLength | 返回的字符串。 |
返回值 | 見(jiàn)錯(cuò)誤碼詳細(xì)說(shuō)明。 |
(4)Basic指令SPEED的封裝示例。
3.Qt進(jìn)行Move_Pt指令的封裝,實(shí)現(xiàn)自定義曲線的運(yùn)動(dòng)。
(1)自定義曲線運(yùn)動(dòng)例程Qt界面如下。
(2)通過(guò)Qt的connect將【連接按鈕】的單擊事件綁定一個(gè)槽函數(shù)進(jìn)行鏈接控制器的操作。
//定義一個(gè)定時(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])); //獲取各個(gè)軸的運(yùn)動(dòng)情況 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;//運(yùn)動(dòng)中 } else { MotionStatus=0; } } }(3)通過(guò)定時(shí)器更新控制器各個(gè)軸的位置和速度信息。
//定義一個(gè)定時(shí)器 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])); //獲取各個(gè)軸的運(yùn)動(dòng)情況 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;//運(yùn)動(dòng)中 } else { MotionStatus=0; } } }
(4)Basic指令Move_Pt的介紹。
(5)Move_Pt的接口封裝。
A.通過(guò)在線命令ZAux_DirectCommand()進(jìn)行接口封裝。
/************************************************************* Description: 單位時(shí)間距離 Input: 卡鏈接handle 運(yùn)動(dòng)軸數(shù)、軸列表 運(yùn)動(dòng)時(shí)間 ticks單位, 1ticks≈1ms 運(yùn)動(dòng)距離 units單位 Output: 無(wú) Return: 錯(cuò)誤碼 *************************************************************/ 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; //生成指令選擇運(yùn)動(dòng)的軸......Basic指令BASE(0,1,2,3)表示選擇軸0、軸1、軸2、軸3 //通過(guò)字符串拼接指令封裝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, " "); //生成單位時(shí)間運(yùn)動(dòng)距離指令,......Basic指令通過(guò)Move_PT(ticks, dis1,dis2…)實(shí)現(xiàn) sprintf(tempbuff, "Move_PT(%d,",iTime); strcat(cmdbuff, tempbuff); //封裝各個(gè)軸的運(yùn)動(dòng)距離 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()。
//啟動(dòng)Move_Pt運(yùn)動(dòng) 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ù)接口進(jìn)行MOVE_PT運(yùn)動(dòng) 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)在運(yùn)行中......"); } }C.示波器波形抓取。
(6)封裝一個(gè)API可以下發(fā)多個(gè)move_ptabs指令進(jìn)行加工。 A.一次下發(fā)多個(gè)move_ptabs指令的封裝。
/************************************************************* Description: 一次發(fā)送多個(gè)單位時(shí)間距離指令 Input: 卡鏈接handle 運(yùn)動(dòng)軸數(shù)、軸列表 運(yùn)動(dòng)時(shí)間 ticks單位, 1ticks≈1ms 運(yùn)動(dòng)距離 units單位 Output: 無(wú) Return: 錯(cuò)誤碼 *************************************************************/ 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;//時(shí)間列表空 if(NULL==pfDisList)returnERR_AUX_PARAERR;//運(yùn)動(dòng)距離列表空 if((ApiNum<0)||(ApiNum>50))returnERR_AUX_PARAERR;//Api數(shù)目不對(duì) //生成指令選擇運(yùn)動(dòng)的軸......Basic指令BASE(0,1,2,3)表示選擇軸0、軸1、軸2、軸3 //通過(guò)字符串拼接指令封裝Basic選擇軸指令BASE(piAxisList[0],piAxisList[1],.....piAxisList[i]) strcpy(cmdbuff,"BASE("); for(inti=0;i0) { //生成單位時(shí)間運(yùn)動(dòng)距離指令,......Basic指令通過(guò)Move_PT(ticks,dis1,dis2…)實(shí)現(xiàn) sprintf(tempbuff,"Move_PtAbs(%d,",iTime[j]); strcat(cmdbuff,tempbuff); //封裝各個(gè)軸的運(yùn)動(dòng)距離 for(inti=0;i
B.Qt例程調(diào)用剛封裝的接口MyApi::ZAux_Direct_MovePtAbsS()。
//獲取軸運(yùn)動(dòng)緩沖剩余情況 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抓取軸運(yùn)動(dòng)的位置數(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ā)送在線命令啟動(dòng)示波器 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) { //實(shí)例化一個(gè)畫家this指繪圖設(shè)備 QPainterPainter(WaveformFigure); Painter.translate(0,(int)(ImgH/2)); //設(shè)置畫筆 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的位置曲線。
本次,正運(yùn)動(dòng)技術(shù)EtherCAT運(yùn)動(dòng)控制卡的自定義運(yùn)動(dòng)曲線,就分享到這里。
審核編輯:劉清
-
以太網(wǎng)
+關(guān)注
關(guān)注
40文章
5374瀏覽量
171101 -
CAN總線
+關(guān)注
關(guān)注
145文章
1936瀏覽量
130628 -
上位機(jī)
+關(guān)注
關(guān)注
27文章
930瀏覽量
54730 -
EtherCAT總線
+關(guān)注
關(guān)注
5文章
70瀏覽量
5366
原文標(biāo)題:EtherCAT運(yùn)動(dòng)控制卡的自定義運(yùn)動(dòng)曲線
文章出處:【微信號(hào):伺服與運(yùn)動(dòng)控制,微信公眾號(hào):伺服與運(yùn)動(dòng)控制】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論