正运动技术
正运动技术

协助伙伴成功,是我们的价值所在

The value of Zmotion is to bring customers more success!

首页 / 支持与服务 / 技术分享

Technical support

技术分享

EtherCAT运动控制卡开发教程之python

    

  众所周知,Python作为一门面向对象的新兴开发语言,具有非常完善的基础代码库,更注重实用,同时代码可读极强,编写完程序即可直接运行,被越来越多的人广泛将它用于机器视觉和自动化控制。

  今天正运动技术与大家分享一下运动控制卡应用开发教程之Python。

  一 ECI2828硬件介绍

  

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

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

  

  1.jpg

  

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

  

  2.jpg

  

  二 Python语言开发流程

  

  Python语言的使用环境

  操作系统环境:win7_64x

  Python开发运行环境:PyCharm2019.2

  Python解释器版本:Python 3.7.4(32bit)

  1、新建项目。

  打开Pycharm软件进行操作,点击Create New Project新建项目。

  

  3.jpg

  

  2、设置Python项目存放路径。

  选择Python项目→选择Python项目将存放的路径→创建Python项目。

  

  4.jpg

  

  3、新建Python文件。

  在Python项目中新建Python文件,右键CratPython文件夹,选择“New→PythonFile”,创建新的Python 文件。

  

  5.jpg

  

  4、将Python动态库复制到Python项目中。

  

  6.jpg

  

  5、模块导入并加载动态链接库。

  首先把Python中的两个模块导入(platform和ctypes模块),其中ctypes模块提供和C语言兼容的数据类型,能够很方便地调用动态链接库中输出的C接口函数。

              import platform

              import ctypes

              import os

              #运行环境判断

              systype = platform.system()

              if systype == 'Windows':

              if platform.architecture()[0] == '64bit':

              zauxdll = ctypes.WinDLL('./zauxdll64.dll')

              print('Windows x64')

              else:

              zauxdll = ctypes.WinDLL('./zauxdll.dll')

              print('Windows x86')

              elif systype == 'Darwin':

              zmcdll = ctypes.CDLL('./zmotion.dylib')

              print("macOS")

              elif systype == 'Linux':

              zmcdll = ctypes.CDLL('./libzmotion.so')

              print("Linux")

              else:

              print("Not Supported!!")

  6、通过加载导入的动态库链接库,调用ZMotion PC函数手册中的函数。

  1)使用操作。

  首先根据控制器连接方式用连接函数连接控制器,输出控制器句柄,利用控制器的句柄我们就可以对库函数进行操作。

  即“打开PC函数手册→搜索想要的函数功能→查看函数说明→通过刚才加载的动态链接库返回的zauxdll对象进行调用”。

  

  7.jpg

  

  2)通过ip连接函数接口返回的控制器句柄handle,对控制器的句柄handle操作。

  

  8.jpg

  

              

            #####控制器连接#####

                def connect(self, ip, console=[]):

                    if self.handle.value is not None:

                        self.disconnect()

                    ip_bytes = ip.encode('utf-8')

                    p_ip = ctypes.c_char_p(ip_bytes)

                    print("Connecting to", ip, "...")

                    ret = zauxdll.ZAux_OpenEth(p_ip, ctypes.pointer(self.handle))

                    msg = "Connected"

                    if ret == 0:

                        msg = ip + " Connected"

                        self.sys_ip = ip

                        self.is_connected = True

                    else:

                        msg = "Connection Failed, Error " + str(ret)

                        self.is_connected = False

                    console.append(msg)

                    console.append(self.sys_info)

                    return ret

            

                # 断开连接

                def disconnect(self):

                    ret = zauxdll.ZAux_Close(self.handle)

                    self.is_connected = False

                    return ret

  3)我们会提供EtherCAT总线初始化的basic代码,可以通过指令ZAux_BasDown()将总线初始化的basic代码下载到控制器中,从而实现EtherCAT总线轴的初始化。

  

  9.jpg

  

            ********************ECAT总线初始化****************

            global CONST BUS_TYPE = 0           '总线类型。

            global CONST MAX_AXISNUM = 16       '最大轴数

            global CONST Bus_Slot  = 0          '槽位号0

            global CONST Bus_AxisStart   = 0    '总线轴起始轴号

            

            global Bus_InitStatus               '总线初始化完成状态

            Bus_InitStatus = -1

            global  Bus_TotalAxisnum            '检查扫描的总轴数

            delay(3000)                         '延时3S等待驱动器上电

            Ecat_Init()

            end

            

            global sub Ecat_Init()

               '初始化还原轴类型

               for i=0 to MAX_AXISNUM - 1              

                  AXIS_ENABLE(i) = 0

                  ATYPE(i)=0  

               next

                  '扫描总线  

                  Bus_InitStatus = -1

                  Bus_TotalAxisnum = 0  

                  SLOT_STOP(Bus_Slot)

                  DELAY(200)

                  SLOT_SCAN(Bus_Slot)

                  '如果扫描成功                      

                  if return then      

                     ?"总线扫描成功","连接设备数:"NODE_COUNT(Bus_Slot)    

                     ?"开始映射轴号"

                     '遍历总线下所有从站节点

                     for i=0 to NODE_COUNT(Bus_Slot)-1            

                        '判断当前节点是否有电机

                        if NODE_AXIS_COUNT(Bus_Slot,i) <>0 then      

                        for j=0 to NODE_AXIS_COUNT(Bus_Slot,i)-1

                           '映射轴号

                           AXIS_ADDRESS(Bus_AxisStart+i)=Bus_TotalAxisnum+1

                           '设置控制模式 65-位置 66-速度 67-转矩       

                           ATYPE(Bus_AxisStart+i)=65

                           '设置PROFILE功能                

                           DRIVE_PROFILE(Bus_AxisStart+i)= 4

                           '每轴单独分组            

                           DISABLE_GROUP(Bus_AxisStart+i)              

                           '映射驱动器上的IO起始地址

                           DRIVE_IO(Bus_AxisStart+i) = 128 + (Bus_AxisStart+i)*16  

                          '总轴数+1      

                          Bus_TotalAxisnum=Bus_TotalAxisnum+1                

                      next

                    endif

               next      

                  ?"轴号映射完成","连接总轴数:"Bus_TotalAxisnum

                  WA 2000

                  '总线开启

                  SLOT_START(Bus_Slot)            

                  if return then 

                     ?"总线开启成功"            

                     ?"开始清除驱动器错误(根据驱动器数据字典设置)"

                     for i= Bus_AxisStart to Bus_AxisStart + Bus_TotalAxisnum - 1              

                        DRIVE_CONTROLWORD(i)=128          '根据驱动器数据字典

                        wa 100

                        DRIVE_CONTROLWORD(i)=6

                        wa 100

                        DRIVE_CONTROLWORD(i)=15

                        wa 100      

                     next        

                        ?"驱动器错误清除完成"

                        wa 100    

                        ?"清除控制器错误"

                        DATUM(0)

                        DRIVE_CLEAR(0)

                        ?"控制器错误清除完成"

                        wa 100              

                        ?"轴使能准备"

                        for i= Bus_AxisStart to Bus_AxisStart + Bus_TotalAxisnum - 1

                           base(i)

                           AXIS_ENABLE=1

                        next

                           '使能总开关

                            WDOG=1                      

                            Bus_InitStatus  = 1

                            ?"轴使能完成"

                     else

                        ?"总线开启失败"

                        Bus_InitStatus = 0

                     endif

                  

                 else

                    ?"总线扫描失败"

                    Bus_InitStatus = 0

                 endif

            end sub

  4)轴参数设置。

  

            #####轴参数设置####

                # 设置轴类型

                def set_atype(self, iaxis, iValue):

                    ret = zauxdll.ZAux_Direct_SetAtype(self.handle, iaxis, iValue)

                    if ret == 0:

                        print("Set Axis (", iaxis, ") Atype:", iValue)

                    else:

                        print("Set Axis (", iaxis, ") Atype fail!error:",ret)

                    return ret

            

                # 设置脉冲当量

                def set_units(self, iaxis, iValue):

                    ret = zauxdll.ZAux_Direct_SetUnits(self.handle, iaxis, ctypes.c_float(iValue))

                    if ret == 0:

                        print("Set Axis (", iaxis, ") Units:", iValue)

                    else:

                        print("Set Axis (", iaxis, ") Units fail!error:",ret)

                    return ret

            

                # 设置轴加速度

                def set_accel(self, iaxis, iValue):

                    ret = zauxdll.ZAux_Direct_SetAccel(self.handle, iaxis, ctypes.c_float(iValue))

                    if ret == 0:

                        print("Set Axis (", iaxis, ") Accel:", iValue)

                    else:

                        print("Set Accel (", iaxis, ") Accel fail!")

                    return ret

            

                # 设置轴减速度

                def set_decel(self, iaxis, iValue):

                    ret = zauxdll.ZAux_Direct_SetDecel(self.handle, iaxis, ctypes.c_float(iValue))

                    if ret == 0:

                        print("Set Axis (", iaxis, ") Decel:", iValue)

                    else:

                        print("Set Axis (", iaxis, ") Decel fail!error:",ret)

                    return ret

            

                # 设置轴运行速度

                def set_speed(self, iaxis, iValue):

                    ret = zauxdll.ZAux_Direct_SetAccel(self.handle, iaxis, ctypes.c_float(iValue))

                    if ret == 0:

                        print("Set Axis (", iaxis, ") Speed:", iValue)

                    else:

                        print("Set Axis (", iaxis, ") Speed fail!error:",ret)

                    return ret

  5)轴参数读取。

              

            ####################轴参数读取##################################

                # 读取轴脉冲当量

                def get_untis(self, iaxis):

                    iValue = (ctypes.c_float)()

                    ret = zauxdll.ZAux_Direct_GetUnits(self.handle, iaxis, ctypes.byref(iValue))

                    if ret == 0:

                        print("Get Axis (", iaxis, ") Units:", iValue.value)

                    else:

                        print("Get Axis (", iaxis, ") Units fail! error:",ret)

                    return ret

            

                # 读取轴加速度

                def get_accel(self, iaxis):

                    iValue = (ctypes.c_float)()

                    ret = zauxdll.ZAux_Direct_GetAccel(self.handle, iaxis, ctypes.byref(iValue))

                    if ret == 0:

                        print("Get Axis (", iaxis, ") Accel:",  iValue.value)

                    else:

                        print("Get Axis (", iaxis, ") Accel fail! error:",ret)

                    return ret

            

                # 读取轴减速度

                def get_decel(self, iaxis):

                    iValue = (ctypes.c_float)()

                    ret = zauxdll.ZAux_Direct_GetDecel(self.handle, iaxis, ctypes.byref(iValue))

                    if ret == 0:

                        print("Get Axis (", iaxis, ") Decel:",  iValue.value)

                    else:

                        print("Get Axis (", iaxis, ") Decel fail! error:",ret)

                    return ret

            

                # 读取轴运行速度

                def get_speed(self, iaxis):

                    iValue = (ctypes.c_float)()

                    ret = zauxdll.ZAux_Direct_GetSpeed(self.handle, iaxis, ctypes.byref(iValue))

                    if ret == 0:

                        print("Get Axis (", iaxis, ") Speed:",  iValue.value)

                    else:

                        print("Get Axis (", iaxis, ") Speed fail! error:",ret)

                    return ret

  6)单轴运动。

  

            # 直线运动

                def move(self, iaxis, iValue):

                    ret = zauxdll.ZAux_Direct_Single_Move(self.handle, iaxis, ctypes.c_float(iValue))

                    if ret == 0:

                        print("Axis (", iaxis, ") Move:", iValue)

                    else:

                        print("Axis (", iaxis, ") Move Fail! error:",ret)

                    return ret

            

             # 持续运动

                def vmove(self, iaxis, idir):

                    ret = zauxdll.ZAux_Direct_Single_Vmove(self.handle, iaxis, idir)

                    if ret == 0:

                        print("axis (", iaxis, ")Vmoving!")

                    else:

                        print("Vmoving fail! error:",ret)

                    return ret

  7)运行程序,输出结果。

            ######################功能使用####################

            zaux = ZMCWrapper()

            # 连接控制器ip   默认192.168.0.11

            zaux.connect("192.168.0.11")

            

            # 加载EtherCat总线初始化bas文件

            filename =os.getcwd()+"\ECAT_INIT.bas"

            zaux.BasDown(filename,1)

            

            # 设置轴0参数

            zaux.set_units(0, 100)

            zaux.set_accel(0, 1000)

            zaux.set_decel(0, 1000)

            zaux.set_speed(0, 1000)

            

            # 获取轴0参数

            zaux.get_untis(0)

            zaux.get_accel(0)

            zaux.get_decel(0)

            zaux.get_speed(0)

            

            # 单轴运动

            zaux.move(0,100)  # 轴0直线运动移动100位置

  

  10.jpg

  

  运行并输出程序运行结果

  本次,正运动技术EtherCAT运动控制卡开发教程之python,就分享到这里。

  更多精彩内容请关注“正运动小助手”公众号,需要相关开发环境与例程代码,请咨询正运动技术销售工程师:400-089-8936。

  本文由正运动技术原创,欢迎大家转载,共同学习,一起提高中国智能制造水平。文章版权归正运动技术所有,如有转载请注明文章来源。

  

  33.png

  

邮箱留言

Copyright © 2013 正运动技术有限公司 Design by Zmotion 版权所有   粤ICP备13037187号    Powered by www.zmotion.com.cn 运动控制器-运动控制卡

在线咨询