As we all know, Python is a kind of development language that has excellent basic codes library. It lays emphasis on practical application, and codes are with extremely strong readability. You can run the program directly when edited. Therefore, it is used in machine vision and automation control increasingly.
Today, ZMOTION TECHNOLOGY shares application development of motion control card and Python.
I. ECI2828 Hardware introduction
ECI2828 series motion control cards support linear interpolation of up to 16 axes, including interpolation of any circular interpolation, spherical and helical, electronic cam, electronic gear, synchronous follow, virtual axis, robotic arm instruction, etc. What's more, real-time motion control can be achieved through optimized network communication protocol.
ECI2828 series motion control cards support connection of Ethernet, 232 communication interface and computer, and they will receive computer's instructions to run. Each expansion module can be connected through EtherCAT bus and CAN bus for expanding inputs, outputs or motion axes.
Application programs of ECI2828 series cards can be developed by VC, VB, VS, C++, etc. And "zmotion.dll" dynamic library is needed when running. When debugging, ZDevelop software can be connected to controller at the same time, which is convenient for debugging and observing.
Usage environment of Python:
a: Operation system environment: win7_64x
b: Python development running environment: PyCharm2019.2
c: Python interpreter version: Python 3.7.4(32bit)
→ Open "Pycharm" software to operate
→ click "Create New Project" to build new project.
→ Select "Pure Python" project
→ select the location where saves Python project
→ click "Create".
→ Build new Python file in Python project
→ right-click "CratPython" folder
→ select "New - PythonFile".
→ Import Python's two modules "platform and ctypes".
(ctypes module provides data types that are compatible with C language, and it can conveniently call C interface function that is output from dynamic link library)
import platform
import ctypes
import os
#running environment judge
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!!")
(1) usage operation
Firstly, use "connection function" to controller through controller connection method, then output controller handle, next operate library function using handle of controller.
Process in details: open PC function manual → search function you need → check function description → call zauxdll object returned from loaded dynamic link library.
(2) connect returned controller handle of function interface through ip, and operate "handle".
#####controller connection#####
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
#disconnect
def disconnect(self):
ret = zauxdll.ZAux_Close(self.handle)
self.is_connected = False
return ret
(3) we provide basic codes of EtherCAT bus initialization, and codes can be downloaded into controller through ZAux_BasDown(), then initialization of EtherCAT bus axis can be achieved.
********************ECAT bus initialization****************
global CONST BUS_TYPE = 0 'bus type
global CONST MAX_AXISNUM = 16 'max axes
global CONST Bus_Slot = 0 'slot number is 0
global CONST Bus_AxisStart = 0 'starting number of bus axis
global Bus_InitStatus 'bus initialization is in completion status
Bus_InitStatus = -1
global Bus_TotalAxisnum 'check scanned total axis numbers
delay(3000) 'delay 3s, wait drive power on
Ecat_Init()
end
global sub Ecat_Init()
'initialization recover the axis type
for i=0 to MAX_AXISNUM - 1
AXIS_ENABLE(i) = 0
ATYPE(i)=0
next
'scan the bus
Bus_InitStatus = -1
Bus_TotalAxisnum = 0
SLOT_STOP(Bus_Slot)
DELAY(200)
SLOT_SCAN(Bus_Slot)
'scan success
if return then
?"success to scan the bus", "connected device numbers:"NODE_COUNT(Bus_Slot)
?"start to map axis number"
'traverse all slave stations under bus
for i=0 to NODE_COUNT(Bus_Slot)-1
'judge whether the current node has motor
if NODE_AXIS_COUNT(Bus_Slot,i) <>0 then
for j=0 to NODE_AXIS_COUNT(Bus_Slot,i)-1
'map axis number
AXIS_ADDRESS(Bus_AxisStart+i)=Bus_TotalAxisnum+1
'set control mode, 65-position, 66-speed, 67-torque
ATYPE(Bus_AxisStart+i)=65
'set PROFILE function
DRIVE_PROFILE(Bus_AxisStart+i)= 4
'make group separately for each axis
DISABLE_GROUP(Bus_AxisStart+i)
'map IO start address on drive
DRIVE_IO(Bus_AxisStart+i) = 128 + (Bus_AxisStart+i)*16
'total axes +1
Bus_TotalAxisnum=Bus_TotalAxisnum+1
next
endif
next
?"axis number has been mapped", "connected axis numbers:"Bus_TotalAxisnum
WA 2000
'bus is on
SLOT_START(Bus_Slot)
if return then
?"bus is on"
?"start to clear drive errors (according to drive data dictionary configuration)"
for i= Bus_AxisStart to Bus_AxisStart + Bus_TotalAxisnum - 1
DRIVE_CONTROLWORD(i)=128 'according to drive data dictionary
wa 100
DRIVE_CONTROLWORD(i)=6
wa 100
DRIVE_CONTROLWORD(i)=15
wa 100
next
?"drive errors are cleared out "
wa 100
?"clear controller error"
DATUM(0)
DRIVE_CLEAR(0)
?"controller errors are cleared out"
wa 100
?"axis enable preparation"
for i= Bus_AxisStart to Bus_AxisStart + Bus_TotalAxisnum - 1
base(i)
AXIS_ENABLE=1
next
'enable switch
WDOG=1
Bus_InitStatus = 1
?"axis enable completion"
else
?"bus fails to be on"
Bus_InitStatus = 0
endif
else
?"bus fails to be scanned"
Bus_InitStatus = 0
endif
end sub
(4) axis parameters configuration
#####axis parameter configuration####
#set axis type
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
#set pulse amount
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
#set axis acceleration
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
#set axis deceleration
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
#set axis motion speed
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) axis parameters reading
#read axis pulse amount
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