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

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

3天内不再提示

分享一下EtherCAT运动控制卡的自定义运动曲线

伺服与运动控制 来源:正运动技术 作者:正运动技术 2022-10-09 10:12 次阅读

今天,正运动小助手给大家分享一下EtherCAT运动控制卡的自定义运动曲线,主要介绍一下如何通过在线命令封装自己想使用的Basic指令到上位机接口中供上位机调用。

一、ECI2828运动控制卡的硬件介绍

ECI2828系列控制卡支持最多达16轴直线插补、任意圆弧插补、空间圆弧、螺旋插补、电子凸轮、电子齿轮、同步跟随、虚拟轴、机械手指令等。采用优化的网络通讯协议可以实现实时的运动控制。

ECI2828系列运动控制卡支持以太网,232通讯接口和电脑相连,接收电脑的指令运行,可以通过EtherCAT总线和CAN总线去连接各个扩展模块,从而扩展输入输出点数或运动轴。

ECI2828系列运动控制卡的应用程序可以使用 VC、VB、VS、C++C#等多种高级语言来开发,程序运行时需要动态库zmotion.dll。调试时可以把ZDevelop软件同时连接到控制器,从而方便调试、方便观察。

ab26015a-4279-11ed-96c9-dac502259ad0.png

ECI2828控制卡本身的硬件接口也十分丰富。具有8个本地脉冲轴,每个轴带独立编码器,最多16个虚拟轴。板上自带24个通用输入口(其中4路是高速输入口可以作为高速锁存使用),16个通用输出口(其中4路是高速输出口可以实现4路的PSO),2路AD和DA。

自带1个 RS232串口,1个以太网接口。带一个CAN总线接口,支持通过ZCAN协议来连接扩展模块。带一个CANOPEN接口(功能需要软件版本支持)。带一个EtherCAT总线接口可扩展数字模拟IO以及脉冲定位模块等,带一个手轮接口。

二、运动控制卡的Qt开发流程 1.新建Qt 项目

ac022ebe-4279-11ed-96c9-dac502259ad0.png

图 1-1新建Qt项目

ac1d2688-4279-11ed-96c9-dac502259ad0.png

图 1-2选择项目路径

ac357af8-4279-11ed-96c9-dac502259ad0.png 

图 1-3选择Qt编译套件(kits)

ac444f42-4279-11ed-96c9-dac502259ad0.png

图1-4选择基类

(1)将函数库相关的文件复制到新建的项目中。

ac5e7c8c-4279-11ed-96c9-dac502259ad0.png

图1-5库文件复制

(2)向新建的项目里面添加函数库的静态库。(zmotion.lib)

ac7cb9fe-4279-11ed-96c9-dac502259ad0.png

图1-6添加函数库1

ac977852-4279-11ed-96c9-dac502259ad0.png

图1-7添加函数库2

aca9bc4c-4279-11ed-96c9-dac502259ad0.png

图 1-8添加函数库3

(3)添加函数库相关的头文件到项目中(zmcaux.cpp、zmcaux.h、Zmotion.h)。

acba3c34-4279-11ed-96c9-dac502259ad0.png

图 1-9添加头文件

(4)声明相关头文件,并定义连接句柄。

ace2f084-4279-11ed-96c9-dac502259ad0.png

图1-10声明头文件

2.PC函数介绍

(1)PC函数手册也在光盘资料里面,具体路径如下:“光盘资料8.PC函数函数库2.1Motion函数库编程手册V2.1.pdf”。

acfe81fa-4279-11ed-96c9-dac502259ad0.png

(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的封装示例。

ad1d8d3e-4279-11ed-96c9-dac502259ad0.png

3.Qt进行Move_Pt指令的封装,实现自定义曲线的运动。

(1)自定义曲线运动例程Qt界面如下。

ad4404d2-4279-11ed-96c9-dac502259ad0.png

(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的介绍。

ad5ca618-4279-11ed-96c9-dac502259ad0.png

(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()。

ad924c96-4279-11ed-96c9-dac502259ad0.png
//启动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.示波器波形抓取。

ada8abe4-4279-11ed-96c9-dac502259ad0.png

(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;i< iAxisNum-1; i++)
   {
      sprintf(tempbuff, "%d,",piAxisList[i]);
      strcat(cmdbuff, tempbuff);
   }
   sprintf(tempbuff, "%d)",piAxisList[iAxisNum-1]);
   strcat(cmdbuff, tempbuff);
   //换行继续封装Basic指令
   strcat(cmdbuff, "
");
   for(int j=0;j0)
{
//生成单位时间运动距离指令,......Basic指令通过Move_PT(ticks,dis1,dis2…)实现
sprintf(tempbuff,"Move_PtAbs(%d,",iTime[j]);
strcat(cmdbuff,tempbuff);
//封装各个轴的运动距离
for(inti=0;i< iAxisNum-1; i++)
         {
            sprintf(tempbuff, "%.5f,",pfDisList[i+j*iAxisNum]);
            strcat(cmdbuff, tempbuff);
         }
         sprintf(tempbuff, "%.5f)",pfDisList[iAxisNum-1+j*iAxisNum]);
         strcat(cmdbuff, tempbuff);
         strcat(cmdbuff, "
");
      }
   }
   //调用命令执行函数
   return ZAux_DirectCommand(handle, cmdbuff, cmdbuffAck, 2048);
}

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速度和位置曲线。

addf4514-4279-11ed-96c9-dac502259ad0.png

b.Qt抓取Y=((-sin(PI*2*i/T)/(PI*2))+i/T)*500的位置曲线。

adf8f400-4279-11ed-96c9-dac502259ad0.png

本次,正运动技术EtherCAT运动控制卡的自定义运动曲线,就分享到这里。



审核编辑:刘清

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

    关注

    40

    文章

    5079

    浏览量

    166251
  • CAN总线
    +关注

    关注

    145

    文章

    1812

    浏览量

    129600
  • 上位机
    +关注

    关注

    26

    文章

    861

    浏览量

    54053
  • EtherCAT总线
    +关注

    关注

    5

    文章

    62

    浏览量

    5290

原文标题:EtherCAT运动控制卡的自定义运动曲线

文章出处:【微信号:伺服与运动控制,微信公众号:伺服与运动控制】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    EtherCAT运动控制卡自定义运动曲线

    今天,正运动小助手给大家分享一下EtherCAT运动控制卡自定义
    的头像 发表于 09-27 11:19 1431次阅读
    <b class='flag-5'>EtherCAT</b><b class='flag-5'>运动</b><b class='flag-5'>控制卡</b>的<b class='flag-5'>自定义</b><b class='flag-5'>运动</b><b class='flag-5'>曲线</b>

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

    轨迹的小线段前瞻,各种机器人与自定义机器人算法的控制,多种PSO控制等,满足多样化的工业应用需求。正运动提供自主自研IDE-RTSys开发编程软件,PCIE464
    发表于 01-24 09:48

    运动控制卡

    本人对运动控制卡无所知,想问一下运动控制是不是也像数据采集
    发表于 06-05 00:45

    运动控制卡

    有没有高手懂得弄运动控制卡?可以教一下小白我,怎么入门,用什么软件去编程他。
    发表于 06-13 10:50

    运动控制卡的问题

    本人小白,用的是凌华的运动控制卡,后面接1伺服电机,3步进电机,带动三自由度的滚柱丝杠,想请问一下:已经实现了基本功能(如:插补,回零等),后面还能做什么,也就是在这基础上的后续工作大概都有
    发表于 12-10 17:01

    如何利用FPGA设计运动控制卡

    作者:李木国 彭平良0 引言传统的运动控制卡多采用单片机作为微处理器, 通过些大规模集成电路实现对伺服电机的控制。由于其结构较为复杂,因此在工作时,存在高频响应慢、
    发表于 07-30 06:07

    分享通用运动控制卡资料

    分享通用运动控制卡资料,喜欢可以顶一下
    发表于 11-15 09:44

    ACS运动控制卡 精选资料分享

    简介: ACS是款以色列的运动控制卡控制直线电机,运动精度到u级别。常用在工业领域。1.使用:运动
    发表于 09-01 07:31

    分享一下运动控制卡应用开发教程之Python

    与大家分享一下运动控制卡应用开发教程之Python。 、ECI2828硬件介绍ECI2828系列运动
    发表于 09-01 08:36

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

    今天,正运动技术给大家分享一下EtherCAT运动控制卡之ECI2820如何使用C#实现运动暂停
    发表于 09-01 06:24

    PLC控制好还是运动控制卡控制

    什么是运动控制卡运动控制卡与驱动器有什么不同?PLC控制好还是运动
    发表于 10-09 07:56

    EtherCAT运动控制器进行自定义API封装例程

    本节课程我们主要讲解一下运动API函数封装原理以及自定义API封装例程。 正运动技术运动控制
    发表于 10-26 15:11

    EtherCAT运动控制卡的总线轴参数设置和轴运动

    EtherCAT运动控制卡的总线轴参数设置和轴运动设定
    的头像 发表于 11-08 16:34 2071次阅读
    <b class='flag-5'>EtherCAT</b><b class='flag-5'>运动</b><b class='flag-5'>控制卡</b>的总线轴参数设置和轴<b class='flag-5'>运动</b>

    EtherCAT运动控制卡的硬件接线与C#的单轴运动控制

    EtherCAT运动控制卡实现C#的单轴运动控制的例程
    的头像 发表于 10-22 16:07 1932次阅读
    <b class='flag-5'>EtherCAT</b><b class='flag-5'>运动</b><b class='flag-5'>控制卡</b>的硬件接线与C#的单轴<b class='flag-5'>运动</b><b class='flag-5'>控制</b>

    EtherCAT运动控制边缘控制器功能简介和自定义API封装例程

    上节课程我们介绍了全国产EtherCAT运动控制边缘控制器ZMC432H的硬件接口与功能,本节课程我们主要讲解一下
    的头像 发表于 08-28 15:08 749次阅读
    <b class='flag-5'>EtherCAT</b><b class='flag-5'>运动</b><b class='flag-5'>控制</b>边缘<b class='flag-5'>控制</b>器功能简介和<b class='flag-5'>自定义</b>API封装例程