今天,正運動小助手給大家分享一下EtherCAT運動控制卡的自定義運動曲線,主要介紹一下如何通過在線命令封裝自己想使用的Basic指令到上位機接口中供上位機調用。
一、ECI2828運動控制卡的硬件介紹
ECI2828系列控制卡支持最多達16軸直線插補、任意圓弧插補、空間圓弧、螺旋插補、電子凸輪、電子齒輪、同步跟隨、虛擬軸、機械手指令等。采用優化的網絡通訊協議可以實現實時的運動控制。
ECI2828系列運動控制卡支持以太網,232通訊接口和電腦相連,接收電腦的指令運行,可以通過EtherCAT總線和CAN總線去連接各個擴展模塊,從而擴展輸入輸出點數或運動軸。
ECI2828系列運動控制卡的應用程序可以使用 VC、VB、VS、C++、C#等多種高級語言來開發,程序運行時需要動態庫zmotion.dll。調試時可以把ZDevelop軟件同時連接到控制器,從而方便調試、方便觀察。

ECI2828控制卡本身的硬件接口也十分豐富。具有8個本地脈沖軸,每個軸帶獨立編碼器,最多16個虛擬軸。板上自帶24個通用輸入口(其中4路是高速輸入口可以作為高速鎖存使用),16個通用輸出口(其中4路是高速輸出口可以實現4路的PSO),2路AD和DA。
自帶1個 RS232串口,1個以太網接口。帶一個CAN總線接口,支持通過ZCAN協議來連接擴展模塊。帶一個CANOPEN接口(功能需要軟件版本支持)。帶一個EtherCAT總線接口可擴展數字模擬IO以及脈沖定位模塊等,帶一個手輪接口。
二、運動控制卡的Qt開發流程 1.新建Qt 項目
圖 1-1新建Qt項目

圖 1-2選擇項目路徑
?
圖 1-3選擇Qt編譯套件(kits)

圖1-4選擇基類
(1)將函數庫相關的文件復制到新建的項目中。

圖1-5庫文件復制
(2)向新建的項目里面添加函數庫的靜態庫。(zmotion.lib)

圖1-6添加函數庫1

圖1-7添加函數庫2

圖 1-8添加函數庫3
(3)添加函數庫相關的頭文件到項目中(zmcaux.cpp、zmcaux.h、Zmotion.h)。

圖 1-9添加頭文件
(4)聲明相關頭文件,并定義連接句柄。

圖1-10聲明頭文件
2.PC函數介紹
(1)PC函數手冊也在光盤資料里面,具體路徑如下:“光盤資料8.PC函數函數庫2.1Motion函數庫編程手冊V2.1.pdf”。

(2)PC編程一般需要建立上位機和控制器之間的鏈接。和控制卡的連接一般習慣使用網口方式進行鏈接,具體接口說明如下。
| 指令7 | ZAux_OpenEth |
| 指令原型 | int32 __stdcall ZAux_OpenEth(char *ipaddr, ZMC_HANDLE * phandle) |
| 指令說明 | 以太網鏈接控制器。 |
| 輸入參數 | 輸入參數1個,詳細見下面說明。 |
| ipaddr | 鏈接的IP地址。 |
| 輸出參數 | 輸出參數1個,詳細見下面說明。 |
| Phandle | 返回的鏈接句柄。 |
| 返回值 | 詳細見錯誤碼說明。 |
(3)如果想將Basic指令封裝成上位機可以直接調用的接口就必須使用在線命令這個接口進行函數封裝,在線命令接口說明如下。
| 指令 | 說明 |
| ZAux_Execute | 直接發送指令(當控制器沒有緩沖時自動阻塞) |
| ZAux_DirectCommand | 直接發送指令(用于調試,只支持少數命令暫時不支持) |
| 指令1 | ZAux_Execute |
| 指令原型 | int32 __stdcall ZAux_Execute(ZMC_HANDLE handle, const char *pszCommand, char *psResponse, uint32 uiResponseLength) |
| 指令說明 | 發送字符串命令到控制器(當控制器沒有緩沖時自動阻賽)。 |
| 輸入參數 | 共有3個輸入參數,見下方說明。 |
| handle | 鏈接句柄。 |
| pszCommand | 發送的命令字符串。 |
| uiResponseLength | 返回的字符長度。 |
| 輸出參數 | 共有1個輸出參數,見下方說明。 |
| psResponse | 返回的字符串。 |
| 返回值 | 見錯誤碼詳細說明。 |
| 指令2 | ZAux_DirectCommand |
| 指令原型 | int32 __stdcall ZAux_DirectCommand(ZMC_HANDLE handle, const char *pszCommand,char *psResponse, uint32 uiResponseLength) |
| 指令說明 | 發送字符串命令到控制器(用于調試,只支持少數命令,暫時不支持)。 |
| 輸入參數 | 共有3個輸入參數,見下方說明。 |
| handle | 鏈接句柄。 |
| pszCommand | 發送的命令字符串。 |
| uiResponseLength | 返回的字符長度。 |
| 輸出參數 | 共有1個輸出參數,見下方說明。 |
| uiResponseLength | 返回的字符串。 |
| 返回值 | 見錯誤碼詳細說明。 |
(4)Basic指令SPEED的封裝示例。

3.Qt進行Move_Pt指令的封裝,實現自定義曲線的運動。
(1)自定義曲線運動例程Qt界面如下。

(2)通過Qt的connect將【連接按鈕】的單擊事件綁定一個槽函數進行鏈接控制器的操作。
//定義一個定時器 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
運動軸數、軸列表
運動時間 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];
//輸入參數判斷
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);
//換行繼續封裝Basic指令
strcat(cmdbuff, "
");
//生成單位時間運動距離指令,......Basic指令通過Move_PT(ticks, dis1,dis2…)實現
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);
//調用命令執行函數
//printf("%s",cmdbuff);
return ZAux_DirectCommand(handle, cmdbuff, cmdbuffAck, 2048);
}
B.Qt例程調用剛剛封裝的接口MyApi::ZAux_Direct_MovePt()。
//啟動Move_Pt運動
voidWidget::on_PtStartButton_clicked()
{
if(0==MotionStatus)
{
intbuffNum=0;
//獲取0軸剩余緩沖區數目,緩沖區數目足夠才下發指令
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();
}
//調用自己封裝的函數接口進行MOVE_PT運動
myapi->ZAux_Direct_MovePt(g_handle,AxisNum,AxisList,(int)(DisList[i][0]),&DisList[i][1]);
}
}
else
{
QMessageBox::warning(this,"warning","軸緩沖區剩余不足");
}
}
else
{
QMessageBox::warning(this,"warning","系統在運行中......");
}
}
C.示波器波形抓取。

(6)封裝一個API可以下發多個move_ptabs指令進行加工。 A.一次下發多個move_ptabs指令的封裝。
/*************************************************************
Description: 一次發送多個單位時間距離指令
Input: 卡鏈接handle
運動軸數、軸列表
運動時間 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];
//輸入參數判斷
if((0>iAxisNum||iAxisNum>MAX_AXIS_AUX))returnERR_AUX_PARAERR;//軸數不正確
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數目不對
//生成指令選擇運動的軸......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…)實現
sprintf(tempbuff,"Move_PtAbs(%d,",iTime[j]);
strcat(cmdbuff,tempbuff);
//封裝各個軸的運動距離
for(inti=0;i
B.Qt例程調用剛封裝的接口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;iCanvas->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];
//發送在線命令啟動示波器
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);
}
C.Qt抓取軸運動的位置數據,產生位置波形圖。
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);
//發送觸發示波器抓取的命令
if((CurTriggerNum>=SingTriggerNum))
{
qDebug()<<"觸發示波器"<::iteratoriet;
for(inti=0;i0))
{
Painter.drawLine(StartPoint,StopPoint);
}
}
}
}
D.抓波形圖查看效果。
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運動控制卡的自定義運動曲線,就分享到這里。
審核編輯:劉清
-
以太網
+關注
關注
41文章
5997瀏覽量
180806 -
CAN總線
+關注
關注
145文章
2043瀏覽量
135214 -
上位機
+關注
關注
27文章
1002瀏覽量
57048 -
EtherCAT總線
+關注
關注
5文章
93瀏覽量
5943
原文標題:EtherCAT運動控制卡的自定義運動曲線
文章出處:【微信號:伺服與運動控制,微信公眾號:伺服與運動控制】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
分享一下EtherCAT運動控制卡的自定義運動曲線
評論