Today, Zheng Motion Assistant will share with you how to develop a multi-segment continuous interpolation motion control application using C#.
We will start by explaining how to create a new project and add function libraries, then learn how to use PC functions, and finally use a project practice example—a continuous interpolation motion routine—to familiarize everyone with its project development.
Before we begin our formal learning, let's first understand the motion control cards ECI2418 and ECI2618 from Zheng Motion Technology. These two products are 4-axis and 6-axis motion control cards, respectively.
The ECI2418 supports 4-axis pulse input and encoder feedback, with 24 onboard inputs, 16 onboard outputs, 2 AD, 2 DA, and a handwheel interface. Some output ports support high-speed PWM control.
The ECI2618 supports 6-axis pulse input and encoder feedback, with 24 onboard inputs, 16 onboard outputs, 2 AD converters, 2 DA converters, and a handwheel interface. Some output ports support high-speed PWM control.
Both ECI2418 and ECI2618 use the same set of API functions and support development languages such as C, C++, C#, LabVIEW, Python, and Delphi. They also support platforms such as VC6.0, VB6.0, Qt, and .Net, and operating systems such as Windows, Linux, WinCE, and iMac.
The following is C#
Development process
01 Create a new MFC project and add function libraries.
1. In VS2015, 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 (for a 64-bit library):
1) Go to the CD-ROM data and find the PC function folder.
2) Select function library 2.1.
3) Windows platform.
4) Select the corresponding function library as needed. Here, we choose the 64-bit library.
5) Unzip the C++ compressed file, which contains the corresponding C# function library.
6) The specific path to the function library is shown in the following figure.
4. Copy the C# library files and related files provided by the vendor into the newly created project.
1) Copy the zmcaux.cs file into the newly created project.
2) Place the zaux.dll and zmotion.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". Then, right-click the zmcaux.cs file 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 and declare the controller handle g_handle.
The project is now complete.
02. Consult the PC function manual to learn how to use it.
1. The PC function manual is also included in the CD-ROM materials; the specific path is as follows.
2. PC programming generally begins by selecting the appropriate connection function based on the controller's connection method to connect to the controller and return a controller handle. Then, the returned controller handle is used to control the controller.
3. For example, to connect to the controller via the network port, first use ZAux_OpenEth() to connect to the controller and obtain the controller handle.
Project application screenshots
4. Using the obtained controller handle, perform single-axis motion control on the controller.
5. Perform multi-axis absolute interpolation motion using the obtained controller handle.
int [] axislist = { 0, 1, 2, 3 }; // Axis list
float [] destdis = { 100, 100, 200, 100 }; // List of movement distances
zmcaux.ZAux_Direct_MoveAbs(g_handle, 4 , axislist, destdis);
6. Obtain the remaining buffer quantity in the controller buffer using the obtained controller handle.
03 Project Practice: Explanation of Continuous Interpolation Motion Routine
1. The routine aims to establish the connection of the board and perform the processing of 4 continuous trajectories.
2. Simplified flowchart of the routine.
3. Connect to the controller via the network port and obtain the controller connection handle.
//Connect controller
private void button_link_Click ( object sender, EventArgs e)
{
if (g_handle != (IntPtr) 0 )
{
zmcaux.ZAux_Close(g_handle); // Disconnect
g_handle = (IntPtr) 0 ;
}
zmcaux.ZAux_OpenEth(comboBox_IpList.Text, out g_handle); // Connect to the controller
if (g_handle != (IntPtr) 0 )
{
this.Text = " Connected ";
timer1.Enabled = true ;
// Initialize axis parameters
for ( int i = 0 ; i < 4 ; i++)
{
zmcaux.ZAux_Direct_SetAtype(g_handle, i, 1); // Axis type: Pulse axis
zmcaux.ZAux_Direct_SetUnits(g_handle, i, 1); // Pulse equivalent
}
}
else
{
MessageBox.Show(" Controller connection failed, please check your IP address!", "Warning" );
}
}
4. Update the position and speed information of controller axes 0-3 through timer 1.
//Timer refresh
private void timer1_Tick ( object sender, EventArgs e)
{
int runstate = 0 ;
float [] curpos = new float [ 4 ];
float vspeed = 0 ;
int remin_buff = 0 ;
int curmark = 0 ;
//Get axis position
for ( int i = 0 ; i < 4 ; i++)
{
zmcaux.ZAux_Direct_GetDpos(g_handle, i, ref curpos[i]);
}
//Get axis motion status
zmcaux.ZAux_Direct_GetIfIdle(g_handle, 0 , ref runstate);
//Get the resultant velocity of the interpolated motion
zmcaux.ZAux_Direct_GetVpSpeed(g_handle, 0 , ref vspeed);
// Check the remaining buffer for storing lines
zmcaux.ZAux_Direct_GetRemain_LineBuffer(g_handle, 0 , ref remin_buff);
//Determine which movement the current movement has reached.
zmcaux.ZAux_Direct_GetMoveCurmark(g_handle, 0 , ref curmark);
label_pos.Text = " X: " + curpos[ 0 ] + " Y: " + curpos[ 1 ] + " Z: " + curpos[ 2 ] + " U: " + curpos[ 3 ];
label_state.Text = Convert.ToString(runstate == 0 ? " Running status: Running " : " Running status: Stopped ");
label_vspeed.Text = "Current speed: " + vspeed;
label_buff.Text = "Remaining Buffer: " + remin_buff;
label_mark.Text = "Current Mark: " + curmark;
}
5. Initiate the interpolation motion using the event handler function of the start button.
//Start button
private void button_start_Click ( object sender, EventArgs e)
{
int [] axislist = { 0, 1, 2, 3 }; // Axis list
float [] destdis = { 0, 0, 0, 0 }; // List of movement distances
int corner_mode = 0 ; // Corner mode
int merge_flag = 0 ; // Continuous interpolation
int iresult = 0 ; // Return value of PC function
int remin_buff = 0 ; // Remaining number of line buffers
if (checkBox1.Checked)
{
corner_mode = corner_mode + 2 ;
}
if (checkBox2.Checked)
{
corner_mode = corner_mode + 8 ;
}
if (checkBox3.Checked)
{
corner_mode = corner_mode + 32 ;
}
if (checkBox4.Checked)
{
merge_flag = 1 ;
}
//Set interpolation speed
zmcaux.ZAux_Direct_SetSpeed(g_handle, axislist[ 0 ], Convert.ToSingle(textBox_sp.Text));
//Set interpolation acceleration
zmcaux.ZAux_Direct_SetAccel(g_handle, axislist[ 0 ], Convert.ToSingle(textBox_acc.Text));
//Set interpolation deceleration
zmcaux.ZAux_Direct_SetDecel(g_handle, axislist[ 0 ], Convert.ToSingle(textBox_dec.Text));
//Set continuous interpolation
zmcaux.ZAux_Direct_SetMerge(g_handle, axislist[ 0 ], merge_flag);
//S-curve time
zmcaux.ZAux_Direct_SetSramp(g_handle, axislist[ 0 ], Convert.ToSingle(SRAMP.Text));
//Set SP speed
zmcaux.ZAux_Direct_SetForceSpeed(g_handle, axislist[ 0 ], Convert.ToSingle(textBox_for_sp.Text));
//Set corner mode
zmcaux.ZAux_Direct_SetCornerMode(g_handle, axislist[ 0 ], corner_mode);
//Start deceleration angle, convert to radians
zmcaux.ZAux_Direct_SetDecelAngle(g_handle, axislist[ 0 ], (float)(Convert.ToSingle(textBox_ang1.Text) * 3.14 / 180));
//Stop deceleration angle, convert to radians
zmcaux.ZAux_Direct_SetStopAngle(g_handle, axislist[ 0 ], (float)(Convert.ToSingle(textBox_ang2.Text) * 3.14 / 180));
// Radius of the smaller circle
zmcaux.ZAux_Direct_SetFullSpRadius(g_handle, axislist[ 0 ], Convert.ToSingle(textBox_radio.Text));
// Chamfer
zmcaux.ZAux_Direct_SetZsmooth(g_handle, axislist[ 0 ], Convert.ToSingle(textBox_zsmooth.Text));
// Set MARK = 0 to determine the current execution level by reading CURMARK.
zmcaux.ZAux_Direct_SetMovemark(g_handle, axislist[ 0 ], 0 );
//Select base axis
zmcaux.ZAux_Direct_Base(g_handle, 4 , axislist);
zmcaux.ZAux_Trigger(g_handle);
//Calculate the remaining number of linear buffers
zmcaux.ZAux_Direct_GetRemain_LineBuffer(g_handle, 0, ref remin_buff);
while (remin_buff< 4 )
{
zmcaux.ZAux_Direct_GetRemain_LineBuffer(g_handle, 0, ref remin_buff);
System.Threading.Thread.Sleep(1); // 1 millisecond
}
//First segment of interpolation movement
destdis[ 0 ] = Convert.ToSingle(destdis1_X.Text);
destdis[ 1 ] = Convert.ToSingle(destdis1_Y.Text);
destdis[ 2 ] = Convert.ToSingle(destdis1_Z.Text);
destdis[ 3 ] = Convert.ToSingle(destdis1_U.Text);
iresult = zmcaux.ZAux_Direct_MoveAbs(g_handle, 4 , axislist, destdis); // 4-axis interpolation command
//If the function returns a non-zero value, it means the transmission failed, the buffer may be full, and you should resend.
while (iresult != 0 )
{
iresult = zmcaux.ZAux_Direct_MoveAbs(g_handle, 4 , axislist, destdis);
System.Threading.Thread.Sleep( 1 ); // 1 millisecond
}
//Second segment interpolation movement
destdis[ 0 ] = Convert.ToSingle(destdis2_X.Text);
destdis[ 1 ] = Convert.ToSingle(destdis2_Y.Text);
destdis[ 2 ] = Convert.ToSingle(destdis2_Z.Text);
destdis[ 3 ] = Convert.ToSingle(destdis2_U.Text);
iresult = zmcaux.ZAux_Direct_MoveAbs(g_handle, 4 , axislist, destdis); // 4-axis interpolation command
//If the function returns a non-zero value, it means the transmission failed, the buffer may be full, and you should resend.
while (iresult != 0 )
{
iresult = zmcaux.ZAux_Direct_MoveAbs(g_handle, 4, axislist, destdis);
System.Threading.Thread.Sleep(1); // 1 millisecond
}
//Third segment interpolation motion
destdis[ 0 ] = Convert.ToSingle(destdis3_X.Text);
destdis[ 1 ] = Convert.ToSingle(destdis3_Y.Text);
destdis[ 2 ] = Convert.ToSingle(destdis3_Z.Text);
destdis[ 3 ] = Convert.ToSingle(destdis3_U.Text);
iresult = zmcaux.ZAux_Direct_MoveAbs(g_handle, 4 , axislist, destdis); // 4-axis interpolation command
//If the function returns a non-zero value, it means the transmission failed, the buffer may be full, and you should resend.
while (iresult != 0 )
{
iresult = zmcaux.ZAux_Direct_MoveAbs(g_handle, 4 , axislist, destdis);
System.Threading.Thread.Sleep(1); // 1 millisecond
}
//Fourth segment interpolation movement
destdis[ 0 ] = Convert.ToSingle(destdis4_X.Text);
destdis[ 1 ] = Convert.ToSingle(destdis4_Y.Text);
destdis[ 2 ] = Convert.ToSingle(destdis4_Z.Text);
destdis[ 3 ] = Convert.ToSingle(destdis4_U.Text);
iresult = zmcaux.ZAux_Direct_MoveAbs(g_handle, 4 , axislist, destdis); // 4-axis interpolation command
//If the function returns a non-zero value, it means the transmission failed, the buffer may be full, and you should resend.
while (iresult != 0)
{
iresult = zmcaux.ZAux_Direct_MoveAbs(g_handle, 4 , axislist, destdis);
System.Threading.Thread.Sleep( 1 ); // 1 millisecond
}
}
6. Stop the interpolation motion by using the event handler function of the stop button.
//Stop moving
private void button_stop_Click ( object sender, EventArgs e)
{
//Cancel spindle motion
zmcaux.ZAux_Direct_Single_Cancel(g_handle, 0, 2);
}
7. Zero the axis coordinates.
//Reset coordinates
private void button_zero_Click ( object sender, EventArgs e)
{
if (g_handle == (IntPtr) 0 )
{
MessageBox.Show( "Not linked to controller!", "Prompt" );
}
else
{
for ( int i = 0 ; i < 4 ; i++)
{
zmcaux.ZAux_Direct_SetDpos(g_handle, i, 0 );
}
}
}
8. Compile and run the demonstration.
Compile and run the teaching examples, and simultaneously connect to the controller via ZDevelop software to monitor the axis parameters of motion control.
9. Position waveform with continuous interpolation and automatic chamfering.
10. Speed waveform without continuous interpolation.
11. Speed waveform with continuous interpolation and appropriate corner deceleration.
This concludes our tutorial on "Motion Control Card Application Development Tutorial in C#" for Zheng Motion Technology. For more learning videos and articles, please follow our WeChat Official Account "Zheng Motion Assistant".
This article was originally created by Zheng Motion Assistant. We welcome everyone to reprint it for mutual learning and to improve China's intelligent manufacturing capabilities. Copyright belongs to Zheng Motion Technology. Please indicate the source if you reprint this article.