Share this

C# Delta Parallel Robotic Arm for Visual Synchronous Sorting

2026-04-06 05:47:14 · · #1

In the previous two lessons, we introduced how to build the forward and inverse kinematics of a Delta parallel robot and how to perform matching and positioning using vision. This lesson will share how to develop a forward-motion Delta parallel robot with conveyor belt synchronization using the C# language.

VPLC711 Hardware Introduction

The VPLC711 is a high-performance machine vision EtherCAT motion controller from Zheng Motion, based on the x86 platform and Windows operating system. It boasts powerful computing capabilities and flexibility. It features excellent real-time performance, multiple high-speed hardware inputs and multiple high-speed PSO outputs, enabling precise control of multi-axis synchronous motion and high-speed communication with external devices using multiple protocols.

The VPLC711 supports multiple hardware interfaces and communication protocols, facilitating connection and integration with other devices. In addition, the VPLC711 features vision processing capabilities, enabling real-time processing of image data for applications such as visual inspection, measurement, and positioning.

The VPLC711 incorporates the Windows motion control real-time kernel MotionRT7, forming an open IPC-type real-time soft controller/soft PLC, providing users with a flexible and integrated motion control + vision solution.

VPLC711 Hardware Specifications

1. Employing a high-performance x86 CPU, EtherCAT supports 1ms 64-axis synchronous operation;

2. Onboard hardware interfaces include RS232, RS485, EtherNet*5, EtherCAT, and USB3.0*4;

3. Onboard 20DI, including 4 high-speed color mark latches and 2 sets of high-speed single-ended encoders;

4. Onboard 20DO, including 4 high-speed single-ended pulse axes and 4 sets of high-speed PWM;

5. Supports DVI-D and HDMI displays, and supports different IP settings for dual network ports.

Developing a Delta parallel robotic arm in C#: Adding motion and vision libraries

1. In VS2010, go to "File" → "New" → "Project" to start the Project Creation Wizard.

2. Select "Visual C#" as the development language and .NET Framework 4 as the Windows Forms application.

3. Locate the C# function library in the CD-ROM provided by the manufacturer. The path is as follows (taking the 32-bit library as an example).

1) Go to the CD-ROM provided by the manufacturer, find the "04PC Functions" folder, and click to enter.

2) Select the "Function Library 2.1" folder.

3) Select the "Windows Platform" folder.

4) Select the corresponding function library as needed; here, we choose the 32-bit library.

5) Unzip the C# compressed package, which contains the corresponding C# function library.

6) The specific path to the function library is as follows.

4. Copy the C# library files and related files provided by the manufacturer to the newly created project (note that the PC function library provided here is the motion library by default. If you want to use the vision function, you also need to obtain the vision library. You can obtain the vision library from the relevant sales or technical personnel of the manufacturer).

1) Copy the Zmcaux.cs (motion library) and Zvision.cs (vision library) files into the newly created project.

2) Place the zauxdll.dll, zmotion.dll, and zvision.dll files into the bin\debug folder.

5. Open the newly created project file in Visual Studio. In the Solution Explorer on the right, click "Show all files," then right-click the Zmcaux.cs and Zvision.cs files and click "Include in project."

6. Double-click Form1 in Form1.cs to open the code editing interface. At the beginning of the file, write using cszmcaux, using ZVision, and declare the controller handle g_handle.

PC function introduction

1. Link controller, obtain link handle.

2. Belt synchronization command.

Basic script quick verification command usage

1. Write a Basic test script to test the usage of the MoveSync command.

·

Background: Assume a pair of through-beam photoelectric sensors are fixed at both ends of a production line to monitor the product's position in real time. MOVESYNC command parameter instructions: 'syncposition: The position of the belt shaft when the object reaches the sensing point. This position needs to be recorded using an encoder latch.' 'pos1: The position from the origin of shaft 1 to the photoelectric sensor's sensing point; this is fixed for each product.' '****************************************************************************************** GLOBAL CONST BeltAxis=4 'Belt shaft is shaft 4 GLOBAL CONST FollowAxis1=0 'Following shaft 1 is shaft 0 GLOBAL CONST InducPos1=30 'Position from the origin of following shaft 1 to the photoelectric sensor sensing point GLOBAL CONST StandbyPos1=50 'Standby position of following shaft 1 GLOBAL CONST EmptyPos1=400 'Discharge position of following shaft 1' Stop all shafts RAPIDSTOP(2) WAIT IDLE 'Initialize the shaft parameters of the relevant shafts BASE(FollowAxis1, BeltAxis) ATYPE = 1,1 UNITS = 1000,1000 SPEED = 50,100 DPOS = 0,0' Trigger oscilloscope to acquire waveform TRIGGERDELAY(1000)' Follow axis moves to standby position BASE(FollowAxis1) MOVEABS(StandbyPos1)' Belt shaft starts moving VMOVE(1) AXIS(BeltAxis)' Assuming the belt moves to position 200, a product is detected BASE(FollowAxis1) Wait UNTIL MPOS(BeltAxis)> 200 MOVESYNC(0, 2000, 200, BeltAxis, InducPos1)' Follow axis accelerates synchronization segment. After this instruction is executed, the product will be synchronized MOVE_OP(0, ON)' After synchronization, turn on vacuum suction MOVESYNC(0, 1000, 200, BeltAxis, InducPos1)' Continue synchronization for 1s MOVESYNC(-1, 0, 0, -1, EmptyPos1) 'Move to the discharge position MOVE_OP(0, OFF) 'Turn off the vacuum suction after reaching the discharge position.'

2. Observe the waveform using the oscilloscope in RTSys software and analyze the synchronization process.

Based on oscilloscope data analysis

1. When the product is first inspected, the belt position is 200 and the follower shaft position is 50.

2. When the follower shaft catches up with the product and maintains speed synchronization with the belt shaft, the belt position is 40° and the follower shaft 1 position is 23°.

3. As can be seen from 1 and 2, the product moved forward by 200 (400-200) during the synchronization process.

4. Since the position InducPos1 from the origin of the follower axis 1 to the sensing point of the photoelectric sensor is 30, when the follower axis 1 and the belt are parallel, after the belt carries the product forward by 200, the actual distance from the origin of the follower axis 1 to the photoelectric product is 230 (200+30).

5. The result of the calculation in point 4 is consistent with the actual position of the following axis 1 after the synchronization in point 2 is completed, so the pipeline synchronization command test is normal.

C# Example of Visual Pipeline Synchronous Sorting

1. Detailed introduction of key parameters of belt synchronization command. ZAux_Direct_MoveSync(ZMC_HANDLE handle, float imode, int synctime, float syncposition, int syncaxis, int imaxaxises, int *piAxislist, float *pfDisancelist). (1) Parameter imode: imode = 0+angle, which indicates the synchronization mode. If the belt is parallel to the X-axis, fill in 0.

imode = -1 indicates the end of synchronization mode, allowing movement to a specified absolute position. It is generally used to move to the unloading position after the material has been grabbed in synchronization.

(2) Parameter synctime: Synchronization time, in milliseconds. The motion is completed within the specified time, and the axis and the object on the belt axis maintain the same speed upon completion. 0 indicates that the synchronization time is estimated based on the velocity and acceleration of the motion axis.

(3) Parameter syncposition: The position information of the belt at this moment when the vision or sensor recognizes the product.

(4) Parameter pfDisancelist: If it is a product for visual positioning, this parameter can be filled with the world coordinates of the product when the product is visually recognized.

When using a photoelectric sensor to detect a product, this parameter is fixed: the absolute coordinates of the product's current position when the sensor just detects it. Position information can be obtained by manually moving the axis to locate the product at that moment.

2. Visual assembly line synchronous sorting flowchart.

(1) Visual matching and positioning code details.

·

/************************************************************************************'Task Number: None'Function: Visual positioning of products'Input: None'Output: None'Return Value: Sub-thread--Perform visual positioning **************************************************************************************/public void RunSubTaskVisua(){ int TempArrid = 0; float TempVar = 0; WriteLog("Vision function started normally"); while (SysRunFlag > 0) { //When the pause button is not pressed while (SysRunFlag == 1) { //Acquire image VisuaOper.CameAcquisition(); //Perform template matching RTDisplay.Image = VisuaOper.ShapeFind(); if (MainWindows.BeltMpos != 0)//If the belt encoder position is obtained normally when acquiring the photo { //Locking is done on MoveSyncBuff data while (true) { if (MainWindows.SetMoveSyncFlag == 0) { MainWindows.SetMoveSyncFlag = 1; break; } } // Find the starting index of the array where data can be stored int ArrId = 0; for (int i = 0; i < 50; i++) { if (MainWindows.MoveSyncBuff[i, 0] == 0) { ArrId = i; break; } } // Start storing data, matching a maximum of 10 results at a time TempArrid = ArrId; for (int i = 0; i < 10; i++) { // If the score meets the requirements if (MainWindows.VisionRst[i, 0] >= MainWindows.VisionScore) { int j; // If there are duplicate targets, they need to be removed for (j = 0; j < TempArrid; j++) { TempVar = MainWindows.VisionRst[i, 1] - MainWindows.BeltMpos - MainWindows.MoveSyncBuff[j, 1] + MainWindows.MoveSyncBuff[j, 4]; if (((TempVar) <= 10) && (TempVar >= -10)) { j = -10; break; } } if (j >= 0) { MainWindows.MoveSyncBuff[ArrId, 0] = 1; MainWindows.MoveSyncBuff[ArrId, 1] = MainWindows.VisionRst[i, 1]; // Store the X coordinate of the matching result MainWindows.MoveSyncBuff[ArrId, 2] = MainWindows.VisionRst[i, 2]; // Store the Y coordinate of the matching result MainWindows.MoveSyncBuff[ArrId, 3] = MainWindows.VisionRst[i, 3]; // Store the angle offset of the matching result MainWindows.MoveSyncBuff[ArrId, 4] = MainWindows.BeltMpos; // Store the position information of the conveyor belt when matching the product ArrId = ArrId + 1; IdentiNum.Text = (Convert.ToInt32(IdentiNum.Text) + 1).ToString(); WriteLog("Visual target:" + "(" + MainWindows.VisionRst[i, 1].ToString("0,0") + "," + MainWindows.VisionRst[i, 2].ToString("0,0") + ")"); } } // Clear score MainWindows.VisionRst[i, 0] = 0; } // Unlock MainWindows.SetMoveSyncFlag = 0; } } Thread.Sleep(100); }}

(2) Details of synchronous sorting code for assembly line.

·

/************************************************************************************'Task Number: None'Function Function: Pipeline Synchronous Sorting'Input: None'Output: None'Return Value: None ******************************************************************************************/public void RunSubTaskMotion(){ float[] MoveSyncTemp = new float[5]; float TempMpos = 0; while (SysRunFlag > 0) { while (SysRunFlag == 1) { if (MainWindows.MoveSyncBuff[0, 0] == 1) { MainWindows.ZauxErr = zmcaux.ZAux_Direct_GetMpos(MainWindows.g_Handle, MainWindows.ConveyorAxisId, ref TempMpos); //If the encoder position is captured correctly if (0 == MainWindows.ZauxErr) { //How much has the encoder moved forward TempMpos = TempMpos - MainWindows.MoveSyncBuff[0, 4];

// Check if it is in the synchronization start area if (((MainWindows.MoveSyncBuff[0, 1] + TempMpos) >= MainWindows.SyncReX[0]) && ((MainWindows.MoveSyncBuff[0, 1] + TempMpos) <= MainWindows.SyncReX[1])) { WriteLog("Start synchronization capture"); // Get a set of data MoveSyncTemp[0] = MainWindows.MoveSyncBuff[0, 1] ; //X MoveSyncTemp[1] = MainWindows.MoveSyncBuff[0, 2] ; //Y MoveSyncTemp[2] = MainWindows.GetBinHigt; // Material capture height MoveSyncTemp[3] = MainWindows.MoveSyncBuff[0, 3]; //Aanle MoveSyncTemp[4] = MainWindows.MoveSyncBuff[0, 4]; //Mpos //Issue the synchronous motion command//0. Reset the output port zmcaux.ZAux_Direct_MoveOp(MainWindows.g_Handle, MainWindows.gVAxisList[0], MainWindows.VacSucIo, 0); //1. Synchronize the upper conveyor belt zmcaux.ZAux_Direct_MoveSync(MainWindows.g_Handle, 0, 0, MainWindows.MoveSyncBuff[0, 4], MainWindows.ConveyorAxisId, 4, MainWindows.gVAxisList, MoveSyncTemp); //2. Synchronize for a period of time (joint axis has lag) 50ms zmcaux.ZAux_Direct_MoveSync(MainWindows.g_Handle, 0, 50, MainWindows.MoveSyncBuff[0, 4], MainWindows.ConveyorAxisId, 4, MainWindows.gVAxisList, MoveSyncTemp); //3. Open the vacuum nozzle zmcaux.ZAux_Direct_MoveOp(MainWindows.g_Handle, MainWindows.gVAxisList[0], MainWindows.VacSucIo, 1); //4. Synchronize for a period of 1500ms zmcaux.ZAux_Direct_MoveSync(MainWindows.g_Handle, 0, 700, MainWindows.MoveSyncBuff[0, 4], MainWindows.ConveyorAxisId, 4, MainWindows.gVAxisList, MoveSyncTemp); //5. During the synchronization segment, raise the Z-axis to a safe height and select the axis to the feeding angle MoveSyncTemp[2] = MainWindows.StandPos[2]; //Feeding height zmcaux.ZAux_Direct_MoveSync(MainWindows.g_Handle, 0, 100, MainWindows.MoveSyncBuff[0, 4], MainWindows.ConveyorAxisId, 4, MainWindows.gVAxisList, MoveSyncTemp); //4, Unsynchronize to release point MoveSyncTemp[0] = MainWindows.EmptPos[0]; //X MoveSyncTemp[1] = MainWindows.EmptPos[1]; //Y MoveSyncTemp[2] = MainWindows.EmptPos[2]; //Release height MoveSyncTemp[3] = MainWindows.EmptPos[3]; //Aanle zmcaux.ZAux_Direct_MoveSync(MainWindows.g_Handle, -1, 0, 0, -1, 4, MainWindows.gVAxisList, MoveSyncTemp); //5, Close vacuum nozzle release, Delay100ms zmcaux.ZAux_Direct_MoveOp(MainWindows.g_Handle, MainWindows.gVAxisList[0], MainWindows.VacSucIo, 0); zmcaux.ZAux_Direct_MoveDelay(MainWindows.g_Handle, MainWindows.gVAxisList[0], 100); //6. Go to the safe height MoveSyncTemp[0] = MainWindows.EmptPos[0]; //X MoveSyncTemp[1] = MainWindows.EmptPos[1]; //Y MoveSyncTemp[2] = MainWindows.StandPos[2]; //Mainwind height MoveSyncTemp[3] = MainWindows.EmptPos[3]; //Aanle zmcaux.ZAux_Direct_MoveAbs(MainWindows.g_Handle, 4, MainWindows.gVAxisList, MoveSyncTemp);

//Operation MoveSyncBuff data is first locked while (true) { if (MainWindows.SetMoveSyncFlag == 0) { MainWindows.SetMoveSyncFlag = 1; break; } } //Visual matching buffer data is overwritten forward for (int k = 0; k < 49; k++) { MainWindows.MoveSyncBuff[k, 0] = MainWindows.MoveSyncBuff[k + 1, 0]; MainWindows.MoveSyncBuff[k, 1] = MainWindows.MoveSyncBuff[k + 1, 1]; MainWindows.MoveSyncBuff[k, 2] = MainWindows.MoveSyncBuff[k + 1, 2]; MainWindows.MoveSyncBuff[k, 3] = MainWindows.MoveSyncBuff[k + 1, 3]; MainWindows.MoveSyncBuff[k, 4] = MainWindows.MoveSyncBuff[k + 1, 4]; } //Unlock MainWindows.SetMoveSyncFlag = 0; //Wait for the output port to open int TimeOut = 10000; TimeOut = 100000; //Wait for the axis to stop int AxisIdle = 0; //Axis stopped state while (TimeOut > 0) { zmcaux.ZAux_Direct_GetIfIdle(MainWindows.g_Handle, MainWindows.gVAxisList[0], ref AxisIdle); if (AxisIdle == (-1)) { break; } Thread.Sleep(10); TimeOut = TimeOut - 10; } if (TimeOut <= 0) { //Timeout should report an error and the program should stop WriteLog("Wait for axis to stop timeout"); //Thread.Sleep(100); SysRunFlag = 0; break; } SortNum.Text = (Convert.ToInt32(SortNum.Text) + 1).ToString(); WriteLog("Successfully released"); // Exit while single loop continue; } else if ((MainWindows.MoveSyncBuff[0, 1] + TempMpos) > MainWindows.SyncReX[1]) { // Lock MoveSyncBuff data before operation while (true) { if (MainWindows.SetMoveSyncFlag == 0) { MainWindows.SetMoveSyncFlag = 1; break; } } // Overwrite the data in the visual matching buffer for (int k = 0; k < 49; k++) { MainWindows.MoveSyncBuff[k, 0] = MainWindows.MoveSyncBuff[k + 1, 0]; MainWindows.MoveSyncBuff[k, 1] = MainWindows.MoveSyncBuff[k + 1, 1]; MainWindows.MoveSyncBuff[k, 2] = MainWindows.MoveSyncBuff[k + 1, 2]; MainWindows.MoveSyncBuff[k, 3] = MainWindows.MoveSyncBuff[k + 1, 3]; MainWindows.MoveSyncBuff[k, 4] = MainWindows.MoveSyncBuff[k + 1, 4]; } //Unlock MainWindows.SetMoveSyncFlag = 0; //If the visual matching buffer has no data if (MainWindows.MoveSyncBuff[0, 0] == 0) { //Delta to standby position zmcaux.ZAux_Direct_MoveAbs(MainWindows.g_Handle, 4, MainWindows.gVAxisList, MainWindows.StandPos); WriteLog("Going to standby position"); } } } } else { //Delta to standby position zmcaux.ZAux_Direct_MoveAbs(MainWindows.g_Handle, 4, MainWindows.gVAxisList, MainWindows.StandPos); } Thread.Sleep(50); } //Stop the conveyor belt zmcaux.ZAux_Direct_Single_Cancel(MainWindows.g_Handle, MainWindows.ConveyorAxisId, 2); }}

Demo video

That concludes our presentation on visual synchronous sorting using the Delta parallel robotic arm in C# for positive motion technology.

For more exciting content, please follow the "Zheng Motion Assistant" WeChat official account. For related development environment and example code, please contact Zheng Motion's technical sales engineer: 400-089-8936.

This article is original content from Zheng Motion Technology. We welcome everyone to reprint it for mutual learning and to jointly improve China's intelligent manufacturing level. Copyright belongs to Zheng Motion Technology. Please indicate the source if you reprint this article.

Read next

CATDOLL 130CM Kiki

Height: 130cm Weight: 27kg Shoulder Width: 31cm Bust/Waist/Hip: 64/60/72cm Oral Depth: 3-5cm Vaginal Depth: 3-15cm Anal...

Articles 2026-02-22