Today, ZhengMotion Assistant will share with you how to use Python + QT to implement single-axis homing motion control development for the domestically produced EtherCAT motion control edge controller ZMC432H.
01. Function Introduction
The ZMC432H, a fully domestically produced EtherCAT motion control edge controller, is a positive motion device with domestically produced and independently controllable hardware and software. Its motion control interface is compatible with EtherCAT bus and pulse-type standalone motion controllers, supporting up to 32-axis motion control. It also supports positive motion remote HMI functionality, providing network configuration display and real-time monitoring and adjustment of parameter settings.
The ZMC432H features a rich set of hardware interfaces and control function modules, enabling efficient and stable motion control and real-time data acquisition to meet the application needs of industrial control and the Industrial Internet. The ZMC432H has a built-in Linux system and can connect via a local LOCAL interface, allowing for faster command interaction; the interaction time for a single command or multiple commands is approximately 40µs.
02. Development of motion control using Python + QT
I. Configure the Python + Qt development environment and install the necessary tools. 1. Download the Python interpreter. 2. Install pyside2 or pyside6, depending on the Python interpreter version. Higher versions use pyside6. There are two ways to install pyside2: Method 1: Open the Run dialog box using Win+R, then type cmd (you need to configure the environment variables according to the installation wizard when installing the Python interpreter, otherwise the subsequent commands will not execute successfully), then run `pip install pyside2 -i https://pypi.douban.com/simple/`. Method 2: Install it in PyCharm. 3. After installing PyCharm Community Edition, click the "+" sign in the following interface to install the necessary tools, such as pyside2.
4. Configure a custom tool in PyCharm (for editing the Qt interface). (1) Open the Tool editing box as shown in the figure.
(2) Customize Pyside2-uic: a. Program: Python installation directory\Scripts\pyside2-uic.exe; b. Arguments: $FileName$ -o $FileNameWithoutExtension$.py; c. Working directory: $FileDir$.
(3) Custom QtDesigner: a. Program: Python installation directory\Scripts\pyside2-designer.exe; b. Working directory: $ProjectFileDir$.
Once the custom tools are configured, they can be used directly from the PyCharm menu. 1. Click Tools → Qt → Qtdesigner to enter the UI design interface.
2. Right-click the ui file, click Qt → Pyside2-uic to generate the py file of the ui file.
II. Create a new Python project and add function libraries
1. Open a new folder using PyCharm Community Edition 2022, or create a new directory after entering PyCharm Community Edition 2022, and add Python files to the directory.
2. Locate the CD-ROM provided by the manufacturer. The path is as follows: A. Go to the CD-ROM provided by the manufacturer, find the "04.PC Functions" folder, and click to enter.
B. Select the "PC Function Library V2.1.1" folder.
C. Select the "Windows Platform" folder.
D. Select the "Library Files and Examples" folder.
E. Select the "PYTHON Examples" folder.
F. Unzip the compressed file corresponding to the bit version.
G. The result after decompression is shown in the image below.
3. For Windows systems, simply add the zauxdll.dll, zmotion.dll, and zauxdllPython.Py files to the created folder.
3. Review the PC function manual and familiarize yourself with the relevant function interfaces.
1. The PC function manual is also included in the CD-ROM materials. The specific path is as follows: "CD-ROM materials\04.PC functions\ZMotionPC function library programming manual and its example source code\ZMotionPC function library programming manual V2.1.1.pdf".
2. Connect to the controller and obtain the connection handle.
(1) ZAux_OpenEth() interface description:
(2) Configuration of IO signal point corresponding function interface description:
For detailed information on the interface, please refer to the PC function manual. (3) The following is the zero-return motion call interface and a detailed description of the zero-return mode: Adding 10 means that after encountering the limit, it will reverse and stop without encountering the limit. For example, 13 = mode 3 + limit reverse search 10, which is used when the origin is in the middle.
IV. Example of developing a single-axis homing controller using Python + Qt.
1. The example interface is as follows.
2. The program example is as follows.
(1) Loading Qt UI files in Python;
·
from PySide2.QtWidgets import QMessageBoxfrom PySide2.QtCore import QFile, QTimerfrom PySide2.QtUiTools import QUiLoaderq_state_file = QFile("mainweiget.ui")q_state_file.open(QFile.ReadOnly)self.ui = QUiLoader().load(q_state_file)q_state_file.close()
Note: Here, self.ui refers to the ui in Qt.
(2) In the event handling function of the link button, the interface function ZAux_OpenEth() of the link controller is called to link with the controller. After the link is successfully linked, timer 1 is started to monitor the status of the controller.
·
def on_btn_open_clicked(self): strtemp = self.ui.comboBox.currentText() print("Current IP is:", strtemp) if self.Zmc.handle.value is not None: self.Zmc.close() self.time1.stop() self.ui.setWindowTitle("Single axis returns to zero") iresult = self.Zmc.open_eth(strtemp) if 0 != iresult: QMessageBox.warning(self.ui, "Prompt", "Connection failed") else: QMessageBox.warning(self.ui, "Prompt", "Connection successful") str_title = self.ui.windowTitle() + strtemp self.ui.setWindowTitle(str_title) self.Up_State() self.time1.start(100)
(3) Monitor the controller status through a timer.
·
def Up_State(self): idlelist = [ctypes.c_int(-1) for i in range(0, 4)] fdposlist = [ctypes.c_float(0) for i in range(0, 4)] for i in range(0, 4): self.Zmc.get_target_pos(i, fdposlist[i]) # Get the current axis position self.Zmc.get_idle(i, idlelist[i]) # Determine the current axis state str1 = " {} {} ".format("Stopped" if idlelist[0].value else "Running", round(fdposlist[0].value, 2)) self.ui.lineEdit_X.setText(str1) str1 = " {} {} ".format("Stopped" if idlelist[1].value else "Running", round(fdposlist[1].value, 2)) self.ui.lineEdit_Y.setText(str1) str1 = " {} {} ".format("Stopped" if idlelist[2].value else "Running", round(fdposlist[2].value, 2)) self.ui.lineEdit_Z.setText(str1) str1 = " {} {} ".format("Stopped" if idlelist[3].value else "Running", round(fdposlist[3].value, 2)) self.ui.lineEdit_R.setText(str1)
(4) Use the event handling function of the return-to-zero button to initialize the parameters before the return-to-zero movement and call the corresponding return-to-zero mode to perform the return-to-zero movement.
·
def on_btn_run_clicked(self): if self.Zmc.handle.value is None: QMessageBox.warning(self.ui, "Warning", "Controller not connected") return ifidle = ctypes.c_int(0) self.Zmc.get_idle(self.axis_Num,ifidle) if 0 == ifidle: QMessageBox.warning(self.ui, "Prompt", "Motion not stopped") return # Set axis type 7 - Pulse axis type + encoder Z signal can be set to 1 without EZ zeroing self.Zmc.set_axis_type(self.axis_Num,7 if self.mode < 3 else 1) # Set pulse mode and logical direction (pulse + direction) self.Zmc.set_invert_step(self.axis_Num,0) # Set equivalent str_tmp = self.ui.edit_Units.text() float_tmp = float(str_tmp) self.Zmc.set_units(self.axis_Num,float_tmp) # Set the crawl speed str_tmp = self.ui.edit_CLSpeed.text() float_tmp = float(str_tmp) self.Zmc.set_creep(self.axis_Num,float_tmp) # Set the speed str_tmp = self.ui.edit_Speed.text() float_tmp = float(str_tmp) self.Zmc.set_speed(self.axis_Num,float_tmp) # Set acceleration str_tmp = self.ui.edit_Accel.text() float_tmp = float(str_tmp) self.Zmc.set_acceleration(self.axis_Num,float_tmp) # Set deceleration str_tmp = self.ui.edit_Decel.text() float_tmp = float(str_tmp) `self.Zmc.set_deceleration(self.axis_Num,float_tmp)` # Sets the origin switch. `str_tmp = self.ui.edit_zeroIO.text()` `float_tmp = int(str_tmp)` `self.Zmc.set_datum_in(self.axis_Num,float_tmp)` # Inverts the input. ZMC series assumes the origin signal (normally closed) is encountered when OFF. If it's a normally open sensor, the input port needs to be inverted. ECI series does not need to be inverted. `if float_tmp != -1:` `self.Zmc.set_invert_in(float_tmp,1)` # Sets the positive limit input signal switch. `str_tmp = self.ui.edit_FWDIO.text()` `float_tmp = int(str_tmp)` `self.Zmc.set_fwd_in(self.axis_Num,float_tmp)` `if float_tmp != -1:` self.Zmc.set_invert_in(float_tmp,1) # Set the negative limit input signal switch str_tmp = self.ui.edit_REVIO.text() float_tmp = int(str_tmp) self.Zmc.set_rev_in(self.axis_Num, float_tmp) if float_tmp != -1: self.Zmc.set_invert_in(float_tmp, 1) # Single-axis datum self.Zmc.single_datum(self.axis_Num,self.mode)
(5) Stop the current motion by using the event handler function of the stop motion button.
·
def on_btn_stop_clicked(self): if self.Zmc.handle.value is None: QMessageBox.warning(self.ui,"Warning","Controller not connected") return #No action needed if already stopped isidle = ctypes.c_int(-1) self.Zmc.get_idle(self.axis_Num,isidle) if isidle: return self.Zmc.single_cancel(self.axis_Num,2)
(6) The coordinates of the current axis are cleared by using the event handling function of the coordinate clearing button.
·
The code snippet defines a `on_btn_clear_clicked` function. It checks if the `handle` value is None, then calls a `QMessageBox` to warn users if the controller is not connected. The function returns `isidle` equal to `ctypes.c_int(-1)`. It then calls `self.Zmc.get_idle(self.axis_Num, isidle)`. If `isidle` is not found, it calls `QMessageBox.warning(self.ui,"Warning","Motion not paused, cannot be cleared")` and returns `self.Zmc.set_target_pos(self.axis_Num, 0)`.
03
Debugging and monitoring
Compile and run the routines, and simultaneously monitor the controller status by connecting to the controller through the RtSys software.
Explanation of a single-axis zero-return motion routine using Python and QT.