Today, Zmotion shares "how to do synchronous sorting in assemble line through C# for Delta robotic arm".
Also, we combine our "vision motion controller" with C# to achieve that.
"Vision Motion Controller" -- "VPLCXXX" -- "VPLC711"
PART ONE:
Delta Parallel Robotic Arm by C# | How to Do Kinematic and Manual
PART TWO:
Delta Parallel Robotic Arm by C# | How to Do Camera Calibration & Shape Matching
01
How to Add Motion and Vision Libraries for Delta Robotic Arm by C#
Here, use VS2010.
Step 1: Build One Project
--click "File" - "New" - "Project"--
--select "Visual C#", .Net Framework 4 and Windows program--
Step 2: Obtain Zmotion C# Library
--method 1: find corresponding library in Zmotion website "download", then download by yourself--
--method 2: contact us, send the corresponding library to you--
Step 3: Develop by Zmotion C# Library File
Note: the downloaded library is "motion control library", if you need vision function, please obtain vision library from us.
--copy "Zmcaux.cs" (motion library) and "Zvision.cs" (vision library) files into new built project--
--put zauxdll.dll, zmotion.dll, and zvision.dll files into folder of bin\debug--
--open the file, and click "show all files" in the "solution resource manager", and right click "Zmcaux.cs" and "Zvision.cs" files, then click "include in project".
Step 4: Edit
--double click "Form 1" of "Form 1.cs"--
--edit "using cszmcaux" and "using ZVision" at the beginning--
--state controller handle "g_handle"--
0 2
Main PC Commands for Delta
In "PC Function Library Programming Manual”, you can check all encapsulated commands. It can be downloaded here or contact us directly.
Here, it will show Delta Synchronous Sorting related commands.
(1) Connect to Controller -- ZAux_OpenEth
(2) Synchronize -- ZAux_Direct_MoveSync
03
How to Use Basic Command to Check MoveSync
(1) Edit Basic to Test MoveSync Usage
'************************************************************************************** 'if there are one pair of “through-beam photoelectric sensor” fixed at two sides of assemble line to real-time detect the product position on the assemble line. 'how to fill in MOVESYNC command parameters: 'syncposition: the belt axis position when the object arrived at induction position, it needs to record product position through encoder latching. 'pos1: the position from following axis 1 origin to photoelectric sensor induction position is fixed for each product. '************************************************************************************** GLOBAL CONST BeltAxis=4 'belt axis is axis 4 GLOBAL CONST FollowAxis1=0 'following axis 1 is axis 0 GLOBAL CONST InducPos1=30 'the position from following axis 1 origin to photoelectric sensor induction point GLOBAL CONST StandbyPos1=50'following axis 1’ standby position GLOBAL CONST EmptyPos1=400 'following axis 1’s unloading position 'stop all axes RAPIDSTOP(2) WAIT IDLE 'initialize axis parameters of corresponding axes BASE(FollowAxis1, BeltAxis) ATYPE = 1,1 UNITS = 1000,1000 SPEED = 50,100 DPOS = 0,0 'trigger SCOPE to capture data waveform TRIGGER DELAY(1000) 'following axis moves to standby at first BASE(FollowAxis1) MOVEABS(StandbyPos1) 'belt axis starts to move VMOVE(1) AXIS(BeltAxis) 'if there is one product detected when belt moved at 200 BASE(FollowAxis1) Wait UNTIL MPOS(BeltAxis)> 200 MOVESYNC(0, 2000, 200, BeltAxis, InducPos1) 'when the command (following axis accelerates to synchronize) executed, it will synchronize with the product MOVE_OP(0, ON) 'synchronized, ON vacuum suction MOVESYNC(0, 1000, 200, BeltAxis, InducPos1) 'keep synchronizing 1s MOVESYNC(-1, 0, 0, -1, EmptyPos1) 'move to unloading position MOVE_OP(0, OFF) 'arrive unloading position, off vacuum suction
(2) Check Data Waveform
Obtain corresponding waveform through RTSys (ZDevelop) -- SCOPE, then analyze synchronization process.
According above scope data we can know:
- a. when product is detected, the belt position is 200, following axis position is 50.
- b. following axis follows with the product, and keeps the same speed, when it synchronized with belt axis, belt position is 400, following axis 1 position is 230.
- c. it can be know the product moves forward 200 (400-200) while synchronizing from "a" and "b".
- d. the data from following axis 1 origin to photoelectric sensor's sense point position "InducPos1" is 30, so when axis 1 is parallel with belt, belt makes product move forward 200, then now the real distance becomes 230 (200+30).
- e. therefore, the result of "d" is consistent with following axis 1 real position after synchronized, that is, assemble synchronous command is OK.
04
One Routine: How C# Do Vision Synchronous Sorting in Assemble Line
(1) Belt Synchronized Command Key Parameters
ZAux_Direct_MoveSync(ZMC_HANDLE handle,float imode,int synctime, float syncposition, int syncaxis, int imaxaxises, int piAxislist, float *pfDisancelist)
*--imode--**
Select synchronized mode.
imode=0+angle: synchronous mode, if belt and axis X are parallel, fill in 0.
imode =-1: end mode, move to the specified absolute position, it is usually used at the unloading position after synchronized and captured the material.
--synctime--
Synchronization time, in ms unit. The movement is completed within the specified time. When completed, axis speed and object speed (on the belt axis) keep same. 0 indicates that the synchronization time is estimated according to motion axis' speed and acceleration.
--syncposition--
When vision or sensor sensed product on the belt, now belt position is MPOS (measurement position).
--pfDistancelist--
If locates the product by vision, this parameter is "world coordinate" of the product when vision recoginized the product.
If it uses photoelectric sensor to detect the product, this parameter is fixed, when the sensor feels the product, product current position absolute coordinate. Now, it can move slave axis manually to positioning the product to get the position.
(2) Vision Synchronous Sorting Steps
A. Codes Details of Vision Matching & Positioning
/************************************************************************************ 'Task No.: / 'Function of this function: vision positioning 'Input: / 'Output: / 'returned value: sub thread – do vision positioning **************************************************************************************/ public void RunSubTaskVisua() { int TempArrid = 0; float TempVar = 0; WriteLog("Vision Function ON"); while (SysRunFlag > 0) { //when pause button is not pressed while (SysRunFlag == 1) { //capture the image VisuaOper.CameAcquisition(); //do template matching RTDisplay.Image = VisuaOper.ShapeFind(); if (MainWindows.BeltMpos != 0)//if gets the belt encoder position normally when capturing the image { //operate MoveSyncBuff data, please lock at first while (true) { if (MainWindows.SetMoveSyncFlag == 0) { MainWindows.SetMoveSyncFlag = 1; break; } } //find array starting subscript that can save data int ArrId = 0; for (int i = 0; i < 50; i++) { if (MainWindows.MoveSyncBuff[i, 0] == 0) { ArrId = i; break; } } //start to save the data, 10 results can be matched at most TempArrid = ArrId; for (int i = 0; i < 10; i++) { //if the score is OK if (MainWindows.VisionRst[i, 0] >= MainWindows.VisionScore) { int j; //if there is repeated target, delete repeated one 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]; //save matched X coordinate MainWindows.MoveSyncBuff[ArrId, 2] = MainWindows.VisionRst[i, 2]; //save matched Y coordinate MainWindows.MoveSyncBuff[ArrId, 3] = MainWindows.VisionRst[i, 3]; //save matched angle offset MainWindows.MoveSyncBuff[ArrId, 4] = MainWindows.BeltMpos; //save belt position when product is matched ArrId = ArrId + 1; IdentiNum.Text = (Convert.ToInt32(IdentiNum.Text) + 1).ToString(); WriteLog("Vision Target:" + "(" + MainWindows.VisionRst[i, 1].ToString("0,0") + "," + MainWindows.VisionRst[i, 2].ToString("0,0") + ")"); } } //clear scores MainWindows.VisionRst[i, 0] = 0; } //unlock MainWindows.SetMoveSyncFlag = 0; } } Thread.Sleep(100); } }
B. Codes Details of Vision Sorting in Assemble Line
/************************************************************************************ 'Task No.: / 'Function of this function: assemble line synchronous sorting 'Input: / 'Output: / 'returned value: / **************************************************************************************/ 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 gets the encoder position correctly if (0 == MainWindows.ZauxErr) { //how far the encoder moves forward TempMpos = TempMpos - MainWindows.MoveSyncBuff[0, 4]; //check whether it is at synchronization starting area if (((MainWindows.MoveSyncBuff[0, 1] + TempMpos) >= MainWindows.SyncReX[0]) && ((MainWindows.MoveSyncBuff[0, 1] + TempMpos) <= MainWindows.SyncReX[1])) { WriteLog("Start to Synchronize to Capture"); //get one group of data MoveSyncTemp[0] = MainWindows.MoveSyncBuff[0, 1] ; //X MoveSyncTemp[1] = MainWindows.MoveSyncBuff[0, 2] ; //Y MoveSyncTemp[2] = MainWindows.GetBinHigt; //capture height MoveSyncTemp[3] = MainWindows.MoveSyncBuff[0, 3]; //Aanle MoveSyncTemp[4] = MainWindows.MoveSyncBuff[0, 4]; //Mpos //send synchronous motion command //0, reset OUT zmcaux.ZAux_Direct_MoveOp(MainWindows.g_Handle, MainWindows.gVAxisList[0], MainWindows.VacSucIo, 0); //1, synchronize with transfer belt at first zmcaux.ZAux_Direct_MoveSync(MainWindows.g_Handle, 0, 0, MainWindows.MoveSyncBuff[0, 4], MainWindows.ConveyorAxisId, 4, MainWindows.gVAxisList, MoveSyncTemp); //2, synchronize a certain time, (there is lag of joint axis) 50ms zmcaux.ZAux_Direct_MoveSync(MainWindows.g_Handle, 0, 50, MainWindows.MoveSyncBuff[0, 4], MainWindows.ConveyorAxisId, 4, MainWindows.gVAxisList, MoveSyncTemp); //3, open vacuum nozzle zmcaux.ZAux_Direct_MoveOp(MainWindows.g_Handle, MainWindows.gVAxisList[0], MainWindows.VacSucIo, 1); //4, synchronize a certain time, 1500ms zmcaux.ZAux_Direct_MoveSync(MainWindows.g_Handle, 0, 700, MainWindows.MoveSyncBuff[0, 4], MainWindows.ConveyorAxisId, 4, MainWindows.gVAxisList, MoveSyncTemp); //5, in synchronization, move axis Z up to safe height, select axis unloading angle MoveSyncTemp[2] = MainWindows.StandPos[2]; //capture height zmcaux.ZAux_Direct_MoveSync(MainWindows.g_Handle, 0, 100, MainWindows.MoveSyncBuff[0, 4], MainWindows.ConveyorAxisId, 4, MainWindows.gVAxisList, MoveSyncTemp); //4, release “synchronize to unloading point” MoveSyncTemp[0] = MainWindows.EmptPos[0]; //X MoveSyncTemp[1] = MainWindows.EmptPos[1]; //Y MoveSyncTemp[2] = MainWindows.EmptPos[2]; //unloading 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 to place material, delay 100ms 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, move to safe height MoveSyncTemp[0] = MainWindows.EmptPos[0]; //X MoveSyncTemp[1] = MainWindows.EmptPos[1]; //Y MoveSyncTemp[2] = MainWindows.StandPos[2]; //unloading height MoveSyncTemp[3] = MainWindows.EmptPos[3]; //Aanle zmcaux.ZAux_Direct_MoveAbs(MainWindows.g_Handle, 4, MainWindows.gVAxisList, MoveSyncTemp); //operate MoveSyncBuff data, please lock at first while (true) { if (MainWindows.SetMoveSyncFlag == 0) { MainWindows.SetMoveSyncFlag = 1; break; } } //in vision matching buffer, data are covered 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; //until OUT opens int TimeOut = 10000; TimeOut = 100000; //until axis stops 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) { //if timeout, report an error, program stops WriteLog("Timeout Waiting for Axis to Stop "); //Thread.Sleep(100); SysRunFlag = 0; break; } SortNum.Text = (Convert.ToInt32(SortNum.Text) + 1).ToString(); WriteLog("Unloading Succeeded "); //exit while, cycle once continue; } else if ((MainWindows.MoveSyncBuff[0, 1] + TempMpos) > MainWindows.SyncReX[1]) { //operate MoveSyncBuff data, please lock at first while (true) { if (MainWindows.SetMoveSyncFlag == 0) { MainWindows.SetMoveSyncFlag = 1; break; } } //in vision matching buffer, data are covered 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 there is no data in the vision matching buffer area if (MainWindows.MoveSyncBuff[0, 0] == 0) { //Delta moves to standby position zmcaux.ZAux_Direct_MoveAbs(MainWindows.g_Handle, 4, MainWindows.gVAxisList, MainWindows.StandPos); WriteLog("To Standby"); } } } } else { //Delta moves to standby position zmcaux.ZAux_Direct_MoveAbs(MainWindows.g_Handle, 4, MainWindows.gVAxisList, MainWindows.StandPos); } Thread.Sleep(50); } //stop transfer belt zmcaux.ZAux_Direct_Single_Cancel(MainWindows.g_Handle, MainWindows.ConveyorAxisId, 2); } }
Top comments (0)