上节课程我们介绍了全国产ethercat运动控制边缘控制器zmc432h的硬件接口与功能,本节课程我们主要讲解一下正运动api函数封装原理以及自定义api封装例程。
一、功能简介
全国产ethercat运动控制边缘控制器zmc432h是正运动的一款软硬件全国产自主可控,运动控制接口兼容ethercat总线和脉冲型的独立式运动控制器,最多支持32轴运动控制,同时支持正运动远程hmi功能,能提供网络组态显示,可实时监控和调整参数配置。
zmc432h具备丰富的硬件接口和控制功能模块,能实现高效稳定的运动控制和实时数据采集,以满足工业控制协同工业互联网的应用需求。zmc432h内置了linux系统,可以使用本地的local接口进行连接,可以做到更快速的指令交互,单条指令与多条指令一次性交互时间为40us左右。
二、统一的api接口
所有的控制器和控制卡均使用同一套api函数,均支持c、c++、c#、labview、python、delphi等开发语言,支持vc6.0、vb6.0、qt、.net等平台,支持windows、linux、wince、imac等操作系统。
各个开发语言都有各自所对应的函数库,所调用的api均一致,这大大提高了可移植性。各个开发语言库的调用方式可参考“zmotion pc函数库编程手册 v2.1.1”。
文档参考路径:光盘资料4pc函数zmotion pc函数库编程手册及例程源码。
以下为各个功能部分api指令一览表;
1、控制器连接
zaux_opencom 串口连接控制器
zaux_setcomdefaultbaud 串口通讯参数设置
zaux_openeth 以太网连接控制器
zaux_openpci pci卡连接
zaux_close 关闭控制器连接
zaux_setlp 设置控制ip
zaux_searchethlist 搜索当前网段下控制器的ip
zaux_searchandopencom 快速与控制器建立连接
zaux_searcheth 快速检索ip列表
zaux_getmaxpcicards 读取pci的控制卡个数
zaux_fastopen 与控制器建立连接,指定连接的等待时间motionrt7用此方式连接
2、控制器信息获取
zaux_getcontrollerinfo 获取控制器卡信息
zaux_getsysspecification 获取控制器最大规格数
zaux_getrtctime 读取控制器rtc时间
zaux_setrtctime 设置控制器rtc时间
3、基本轴参数设置
zaux_direct_setatype 设置轴类型
zaux_direct_getatype 读取轴类型
zaux_direct_setunits 设置脉冲当量(units)
zaux_direct_getunits 读取脉冲当量(units)
zaux_direct_setaccel 设置加速度,单位为units /s/s
zaux_direct_getaccel 读取加速度,单位为units/s/s
zaux_direct_setdecel 设置减速度,单位为units/s/s
zaux_direct_getdecel 读取减速度,单位为units/s/s
zaux_direct_setspeed 设置轴速度,单位为units/s
zaux_direct_getspeed 读取轴速度,单位为units/s
zaux_direct_setdpos 设置轴的规划位置,单位为units
zaux_direct_getdpos 读取轴的规划位置,单位为units
zaux_direct_setmpos 设置反馈位置,单位为units
zaux_direct_getmpos 读取反馈位置,单位为units
zaux_direct_getencoder 获取控制器接收的脉冲数
zaux_direct_setfastdec 设置快速减速度,单位为units/s/s
zaux_direct_getfastdec 读取快速减速度,单位为units/s/s
zaux_direct_setlspeed 设置轴起始速度,单位为units/s
zaux_direct_getlspeed 读取轴起始速度,单位为units/s
zaux_direct_setsramp 设置s曲线设置。0-梯形加减速
zaux_direct_getsramp 读取s曲线设置。0-梯形加减速
zaux_direct_getmspeed 读取反馈速度,单位为units/s
zaux_direct_getvpspeed 读取当前轴运行的命令速度,单位为units/s
zaux_direct_getifidle 读取轴是否运动结束
zaux_direct_getaxisstatus 读取轴的告警状态
zaux_direct_getaxisstopreason 读取轴历史异常停止原因
4、基本运动控制
zaux_direct_single_move 单轴相对运动
zaux_direct_single_moveabs 单轴绝对运动
zaux_direct_single_vmove 单轴连续运动
zaux_direct_setjogspeed 设置jog时速度
zaux_direct_getjogspeed 读取jog时速度
zaux_direct_getfastjog 读取jog速度输入in,有输入时,速度由speed参数给出。如果没有输入,速度由jogspeed参数给出
zaux_direct_setfastjog 设置jog速度输入in,有输入时,速度由speed参数给出。如果没有输入,速度由jogspeed参数给出
zaux_direct_setfwdjog 设置正向jog输入对应的输入编号-1无效。
zaux_direct_getfwdjog 读取正向jog输入对应的输入编号-1无效。
zaux_direct_setrevjog 设置负向jog输入对应的输入编号-1无效。
zaux_direct_getrevjog 读取负向jog输入对应的输入编号-1无效。
5、vr寄存器
zaux_direct_setvrf 设置vr寄存器
zaux_direct_getvrf 读取vr寄存器
zaux_direct_getvrint 整型方式读取vr寄存器
6、table寄存器
zaux_direct_settable 设置系统table寄存器
zaux_direct_gettable 读取系统table寄存器
7、modbus寄存器
zaux_modbus_set0x 设置modbus位寄存器
zaux_modbus_get0x 读取modbus位寄存器
zaux_modbus_set4x 设置modbus寄存器(reg)
zaux_modbus_get4x 读取modbus寄存器(reg)
zaux_modbus_set4x_long modbus4x寄存器写操作(long)
zaux_modbus_get4x_long modbus4x寄存器读操作(long)
zaux_modbus_set4x_string modbus字寄存器操作(ascii)
zaux_modbus_get4x_string modbus字寄存器操作(ascii)
zaux_modbus_set4x_float 设置modbus寄存器(float类型)
zaux_modbus_get4x_float 读取modbus寄存器(float类型)
8、flash/文件读写
zaux_writeufile 向u盘中写文件
zaux_readufile 从u盘中读取文件
zaux_flashwritef 写控制器flash空间
zaux_flashreadf 读控制器flash空间
更多api接口详情可以参考“zmotion pc函数库编程手册 v2.1.1”。
三、在线命令的机制
zaux_execute或zaux_directcommand可对basic指令进行封装。如果使用到没有封装的命令或者想封装自己的函数,可以通过zaux_execute发送或zaux_directcommand,或是参照已有代码修改增加相应的函数。发送字符串命令有两种方式,缓冲方式和直接方式。具体如图所示:
直接方式:直接执行单个变量/数组/参数相关命令,此时所有传递的参数必须是具体的数值,不能是表达式;
缓冲方式:可以执行所有命令,并支持表达式作为参数,但是速度慢一些;
以zmcaux.cpp中对已封装的设置运动速度的函数zaux_direct_setspeed()与获取当前编码器反馈位置的函数zaux_direct_getmpos为例。
程序如下:
#include zmotion.h #include zauxdll2.h int zaux_direct_setspeed(zmc_handle handle, int iaxis, float fvalue) { char cmdbuff[2048]; char cmdbuffack[2048]; if (iaxis > max_axis_aux) //max_axis_aux为zuaxdll2.h中定义的宏,zuaxdll2.h为正运动库头文件 { return err_aux_paraerr; } sprintf(cmdbuff,speed(%d)=%f,iaxis,fvalue);//生成对应命令的字符串 zaux_directcommand(handle,cmdbuff,cmdbuffack,2048); } int zaux_direct_getmpos(zmc_handle handle, int iaxis, float fvalue) { char cmdbuff[2048]; char cmdbuffack[2048]; if (iaxis > max_axis_aux) { return err_aux_paraerr; } sprintf(cmdbuff,mpos(%d)=%f,iaxis,fvalue);//生成对应命令的字符串 zaux_directcommand(handle,cmdbuff,cmdbuffack,2048); }
四、自定义api封装介绍及例程
1、自定义api封装
自定义封装api的原理实际上是利用了在线命令的机制,上位机生成由各种zbasic指令来达到自己想要的功能。
zaux库便是直接利用zbasic命令通过zaux_execute方式或zaux_directcommand方式发送到控制器上,相应函数可以参考zbasic手册对应的命令介绍。
zaux库是完全开源库,源代码皆可从官网下载,可以在源代码中添加用户自定义的函数,用户也可以新增库进行封装。
2、实用封装例程
(1)直接获取多种类型数据
用户若想要获取多种数据,如轴的命令位置,轴的反馈位置,板卡上的io点等等,往往都是通过多种单独独立的函数获取不同的数据,这样堆积,会导致读写次数的上位,导致程序的卡顿。为了提升一个上位程序读取控制器数据的速度,往往可以通过自定义一个函数,快速的把数据传输到上位程序上面来,而不是通过多次循环来获取不同类型的数据。
例:假设有一个简易的三轴平台,需要读取轴0,轴1,轴2的命令位置,反馈位置,以及控制器板卡上的输入口0,输入口32,输出口0,输出口33,以及三个轴的状态。
获取数据程序如下:
// test1.cpp : 定义控制台应用程序的入口点。 #include stdafx.h #include #include zmotion.h #include zauxdll2.h void commandcheckhandler(const char *command, int ret) { if (ret)//非0则失败 { printf(%s fail!return code is %dn, command, ret); } } /************************************************************* description: //我的自定义直接获取数据函数 input: //handle 卡链接 iaxisnum 轴的总数量 iaxislist 轴号列表 fdposlist 输出的命令位置值 fmposlist 输出的反馈位置值 iaxisstatuslist 输出的轴状态位置值,按位对应 startin 要获取起始的in编号 endin 要获取结束的in编号 iin 输出的in状态,按位对应 startout 要获取起始的out编号 endout 要获取结束的out编号 iout 输出的out状态,按位对应 output: // return: //错误码 *************************************************************/ int demo_direct_mygetdata(zmc_handle handle,int iaxisnum, int* iaxislist, float* fdposlist,float* fmposlist,int32* iaxisstatuslist,int startin , int endin,int *iin,int startout , int endout,int *iout) { char cmdbuff[2048]; char tempbuff[2048]; char cmdbuffack[20480]; //若传进来的地址为空,则退出 if(null == iaxislist || null == fdposlist || null == fmposlist || null == iaxisstatuslist || null == iin || null == iout) { return err_aux_paraerr; } //若传进来的结束编号小于起始编码,则退出 if ((endin< startin) || (endout1000) { return err_aux_paraerr ; //参数错误,字符串拼接过长 } } temp2=endout-startout+1; if (temp2%32 == 0) { temp2=temp2/32; } else { temp2=temp2/32+1; } //拼接out for (i=0;iendout) { oend=endout; } //生成命令 sprintf(tempbuff, out(%d,%d), ostart,oend); strcat(cmdbuff, tempbuff);//字符串拼接 if (i1000) { return err_aux_paraerr; //参数错误,字符串拼接过长 } } printf(拼接的字符串:n,cmdbuff); printf(%sn,cmdbuff); ret=zaux_directcommand(handle,cmdbuff,cmdbuffack,2048); if(err_ok != ret) { return ret; } //printf(%sn,cmdbuffack); //printf(%dn,strlen(cmdbuffack)); // if(0 == strlen(cmdbuffack)) { return err_noack; } float ftempbuff[200]; int itempbuff[200]; zaux_transstringtofloat(cmdbuffack,iaxisnum*2,ftempbuff);//字符串转换为浮点数 //dpos输出 for(i=0;i< iaxisnum;i++) { //printf(%fn,ftempbuff[i]); fdposlist[i]=ftempbuff[i]; } //mpos输出 for(i=0;i< iaxisnum;i++) { //printf(%fn,ftempbuff[i+iaxisnum]); fmposlist[i]=ftempbuff[i+iaxisnum]; } zaux_transstringtoint(cmdbuffack,iaxisnum*3+temp2+temp,itempbuff);//字符串转换为整形 //axisstatus输出 for(i=0;i< iaxisnum;i++) { //printf(%dn,itempbuff[i+iaxisnum*2]); iaxisstatuslist[i]=itempbuff[i+iaxisnum*2]; } //in输出 for(i=0;i< temp;i++) { //printf(%dn,itempbuff[i+iaxisnum*3]); iin[i]=itempbuff[i+iaxisnum*3]; } //out输出 for(i=0;i< temp2;i++) { //printf(%dn,itempbuff[i+iaxisnum*3+temp]); iout[i]=itempbuff[i+iaxisnum*3+temp]; } return err_ok; } int _tmain(int argc, _tchar* argv[]) { char *ip_addr = (char *)127.0.0.1; //控制器ip地址 zmc_handle handle = null; //连接句柄 int ret = zaux_openeth(ip_addr, &handle); //连接控制器 if (err_success != ret) { printf(控制器连接失败!n); handle = null; sleep(2000); return -1; } printf(控制器连接成功!n); int axis[4]={0,1,2,4}; float d_dpos[4]; float d_mpos[4]; int32 d_axis_status[4]; int d_in[10]; int d_out[10]; ret=demo_direct_mygetdata(handle,3,axis,d_dpos,d_mpos,d_axis_status,0,32,d_in,0,33,d_out); int i; printf(获取到的轴命令位置:n); for (i=0;i< 3;i++) { printf(t轴%d :%f,i,d_dpos[i]); } printf(n); printf(获取到的轴反馈位置:n); for (i=0;i< 3;i++) { printf(t轴%d :%f,i,d_mpos[i]); } printf(n); printf(获取到的轴状态(按位对应):n); for (i=0;i>(i-32*j); printf( in(%d):%d,i,tempval &(0x01)); if (((i%8)==0)&&(i >0) ) { printf(n); } } printf(n); printf(获取到的输出口状态:n); j=0; for (i=0;i0) ) { j++; } //转换成位 tempval=d_out[j] >>(i-32*j); printf( out(%d):%d,i,tempval &(0x01)); if (((i%8)==0)&&(i >0) ) { printf(n); } } printf(n); sleep(20000); ret = zaux_close(handle); //关闭连接 commandcheckhandler(zaux_close, ret) ;//判断指令是否执行成功 printf(connection closed!n); handle = null; return 0; }
(2)一行命令执行多条不同类型缓冲指令
一般点胶行业、木工行业用的较多的是连续轨迹,连续轨迹之间有插入缓冲输出,如果把运动和连续轨迹分开发送的话,难免会有局限性,可以通过自己单独封装运动函数,来达到一行命令执行多个函数的效果。
例:假设控制一个xy两轴平台,从坐标点(0,0),(100,0)(输出口0输出50ms) → (100,100)(输出口0输出50ms) → (0,100)(输出口0输出50ms) → (0,0)(输出口0输出50ms)的轨迹,则可以通过自己封装,用一条函数,快速发送下去。
一行命令执行多个函数程序如下:
// test1.cpp : 定义控制台应用程序的入口点。 // #include stdafx.h #include #include zmotion.h #include zauxdll2.h void commandcheckhandler(const char *command, int ret) { if (ret)//非0则失败 { printf(%s fail!return code is %dn, command, ret); } } /************************************************************* description: //我的自定义运动函数 input: //handle 卡链接 imovelen 填写的运动长度 iaxisnum 参与运动总轴数 iaxislist 轴号列表 fposlist 距离列表 iout 缓冲输出口 outlist 缓冲输出列表(每条运动,决定是否输出,0为不输出,1为在运动后输出) outtime 缓冲输出时间 output: // return: //错误码 *************************************************************/ int demo_direct_mymoveabs(zmc_handle handle,int imovelen,int iaxisnum, int* iaxislist, float* fposlist,int iout,int *outlist,int outtime) { char cmdbuff[2048]; char tempbuff[2048]; char cmdbuffack[20480]; //若传进来的地址为空,则退出 int ret=0; int i; //先读取剩余直线缓冲 int ibufflen = 0; ret = zaux_direct_getremain_linebuffer(handle,iaxislist[0],&ibufflen); if(ibufflen <= imovelen*2) { return 1002; //运动缓冲不够 } //生成命令 sprintf(cmdbuff, base(); //拼接运动轴列表 for (i=0;i1000) { return err_aux_paraerr; //参数错误,字符串拼接过长 } } sprintf(tempbuff,%d)n,iaxislist[i]);//生成对应命令的字符串 strcat(cmdbuff,tempbuff); //拼接运动 for (i=0;i1000) { return err_aux_paraerr; //参数错误,字符串拼接过长 } ret=zaux_directcommand(handle,cmdbuff,cmdbuffack,2048); return ret; } int _tmain(int argc, _tchar* argv[]) { char *ip_addr = (char *)127.0.0.1; //控制器ip地址 zmc_handle handle = null; //连接句柄 int ret = zaux_openeth(ip_addr, &handle); //连接控制器 if (err_success != ret) { printf(控制器连接失败!n); handle = null; sleep(2000); return -1; } printf(控制器连接成功!n); ret =zaux_direct_setatype(handle,0,1);//设置轴0轴类型为1 commandcheckhandler(zaux_direct_setatype, ret) ;//判断指令是否执行成功 ret =zaux_direct_setatype(handle,1,1);//设置轴1轴类型为1 commandcheckhandler(zaux_direct_setatype, ret) ;//判断指令是否执行成功 ret =zaux_direct_setunits(handle,0,100);//设置轴0脉冲当量为100 commandcheckhandler(zaux_direct_setunits, ret) ;//判断指令是否执行成功 ret =zaux_direct_setunits(handle,1,100);//设置轴1脉冲当量为100 commandcheckhandler(zaux_direct_setunits, ret) ;//判断指令是否执行成功 ret =zaux_direct_setaccel(handle,0,500);//设置轴0加速度 commandcheckhandler(zaux_direct_setaccel, ret) ;//判断指令是否执行成功 ret =zaux_direct_setaccel(handle,1,500);//设置轴1加速度 commandcheckhandler(zaux_direct_setaccel, ret) ;//判断指令是否执行成功 ret =zaux_direct_setdecel(handle,0,500);//设置轴0减速度 commandcheckhandler(zaux_direct_setdecel, ret) ;//判断指令是否执行成功 ret =zaux_direct_setdecel(handle,1,500);//设置轴1减速度 commandcheckhandler(zaux_direct_setdecel, ret) ;//判断指令是否执行成功 ret =zaux_direct_setdpos(handle,0,0);//设置轴0 dpos清0 commandcheckhandler(zaux_direct_setdpos, ret) ;//判断指令是否执行成功 ret =zaux_direct_setdpos(handle,1,0);//设置轴1 dpos清0 commandcheckhandler(zaux_direct_setdpos, ret) ;//判断指令是否执行成功 ret =zaux_direct_setspeed(handle,0,100);//设置轴0速度 commandcheckhandler(zaux_direct_setdecel, ret) ;//判断指令是否执行成功 ret =zaux_direct_setspeed(handle,1,100);//设置轴1速度 commandcheckhandler(zaux_direct_setdecel, ret) ;//判断指令是否执行成功 ret =zaux_direct_setmerge(handle,0,1);//设置开启连续插补(开启主轴的即可,如轴0,轴1插补,轴0为主轴,主轴号取决于连续插补运动指令轴列表的第一个轴号) int axis[2]={0,1}; float pos[12]={0,0,0,100,100,100,100,0,0,0}; int otlist[5]={0,1,1,1,1}; zaux_trigger(handle);//触发示波器 ret = demo_direct_mymoveabs(handle,5,2,axis,pos,0,otlist,50);// commandcheckhandler(demo_direct_mymoveabs, ret) ;//判断指令是否执行成功 sleep(20000); ret = zaux_close(handle); //关闭连接 commandcheckhandler(zaux_close, ret) ;//判断指令是否执行成功 printf(connection closed!n); handle = null; return 0; }
示波器采样波形如图所示:
本次,正运动技术全国产ethercat运动控制边缘控制器(二):统一的上位机api接口,就分享到这里。
更多精彩内容请关注“正运动小助手”公众号,需要相关开发环境与例程代码,请咨询正运动技术销售工程师。
本文由正运动技术原创,欢迎大家转载,共同学习,一起提高中国智能制造水平。文章版权归正运动技术所有,如有转载请注明文章来源。
怎样使用毛刺滤波器来滤除毛刺和反弹?
苹果宣布对Harlem Capital进行1000万美元投资
100%国产化FPGA核心板!骨折价——限时仅售299元!
新冠肺炎疫情影响谷歌和微软加速将生产工作从中国转移
台积电关注量子计算机 3倍薪资挖量子人才
全国产EtherCAT运动控制边缘控制器(二):统一的上位机API接口
利用I/O模拟多路复用器PSoC简化传感器控制设计
RFID对于汽车制造业会有怎样的影响
锂电行业大起底:三大问题和两大需求
功率电感在升压电路中起什么作用,为什么要加电感?
机智云生活电器智能化软硬件一体化解决方案提高企业管理效率
沃尔玛或将销售一款运行Comcast软件的电视机
提高企业服务器安全防护的八点建议
微信支付宝后,移动支付新人崛起:云闪付3年获3亿用户!
VR告别“野蛮”生长期 新一轮产业洗牌期将至
京东方量产Micro OLED面板,积极寻求合作商
谷歌AI相机面世_放了哪些大招
介绍最合适替代的开关电源芯片U6215
安防市场的规模不断扩大 融入公共安全体系已成趋势
服务器误删除邮件数据的数据恢复案例