Today, Zheng Motion Technology will share with you how to develop a motion control application using C++ for multi-segment continuous interpolation.
We will start by creating a new MFC project and adding function libraries, then learn about the usage of PC functions, and finally use a project practice—a continuous interpolation motion routine—to familiarize everyone with C++ 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 "MFC Application" as the program type.
3. Proceed to the next step.
4. Select "Dialog-based" as the type, then click Next or Finish.
The next step is to continue configuring, and once completed, you can simply click "Finish". No further configuration is needed here; it's not crucial. Just ensure the correct type is selected; the rest can be edited within the project.
5. Locate the CD-ROM data provided by the manufacturer. The path is as follows (64-bit library as an example).
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 as follows.
6. Copy the C++ library files and related header files provided by the vendor into the newly created project.
7. Add static libraries and related header files to the project.
Static libraries: zauxdll.lib, zmotion.lib
Relevant header files: zauxdll2.h, zmotion.h
1) First, right-click the header file, then select: "Add" → "Existing Item".
2) In the pop-up window, add the static library and related header files in sequence.
3) Declare the header files used and define the controller connection 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.
The specific path is as follows:
2. PC Programming
First, select the corresponding connection function based on the controller connection method to connect to the controller and return the controller handle. Then, use the returned controller handle to control the controller.
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.
By obtaining the controller handle, single-axis motion control is performed on the controller.
By obtaining the controller handle, multi-axis motion control is performed on the controller.
//Multi-axis motion
int axislist[ 4 ] = { 0 , 1 , 2 , 3 }; // List of motion base axes
float dislist[ 4 ] = { 100,100,100,100 }; // List of movement distances
ZAux_Direct_Move(g_handle, 4 , axislist, dislist); // Multi-axis motion
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 3 consecutive trajectories.
2. Simplified flowchart of the routine.
// Related functions
ZAux_OpenEth(IP_buffer, &g_handle); // Connect to the controller
ZAux_Direct_GetAllAxisPara(g_handle, " DPOS ", 4, showpos); // Get the current axis position
ZAux_Direct_GetAllAxisPara(g_handle, " MSPEED ", 4, mspeed); // Update axis speed
ZAux_Direct_Single_Cancel(g_handle, 0, 2); // Stop the spindle motion
ZAux_Direct_Move(g_handle, 4, axislist, dislist1); // First multi-axis interpolation command
ZAux_Direct_Move(g_handle, 4, axislist, dislist2); // Second multi-axis interpolation command
ZAux_Direct_Move(g_handle, 4, axislist, dislist3); // The third multi-axis interpolation command
ZAux_Close(g_handle); // Disconnect
3. Connect to the controller via the network port and obtain the controller connection handle.
//Link button event handler function
void CMergeDlg::OnBnClickedButtonLink()
{
char buffer[256];
int32 iresult;
//If there was a controller connection previously, disconnect it first.
if (NULL != g_handle)
{
ZAux_Close(g_handle);
g_handle = NULL;
}
//Get IP from IP dropdown list
GetDlgItemText(IDC_COMBOX_IP, buffer, 255);
buffer[255] = '\0';
// Connect to the controller via the API function interface provided by the PC function library.
iresult = ZAux_OpenEth(buffer, &g_handle);
if (ERR_SUCCESS != iresult)
{
g_handle = NULL;
MessageBox(_T(" Connection failed "));
SetWindowText(" Unlinked ");
return ;
}
SetWindowText(" Linked ");
//Start the timer
SetTimer(1, 100, NULL);
SetTimer(2, 100, NULL);
// Initialize axis parameters
for ( int i = 0; i<4; i++)
{
ZAux_Direct_SetAtype(g_handle, i, 1); // Axis type
ZAux_Direct_SetUnits(g_handle, i, 1000); // Pulse equivalent
ZAux_Direct_SetSpeed(g_handle, i, 100); //Speed
ZAux_Direct_SetAccel(g_handle, i, 1000); //Acceleration
ZAux_Direct_SetDecel(g_handle, i, 1000); // Deceleration
ZAux_Direct_SetSramp(g_handle, i, 100); // S-curve time
}
}
4. Update the position and speed information of controller axes 0-3 using timer 1.
//Timer
void CMergeDlg::OnTimer(UINT_PTR nIDEvent)
{
if (NULL == g_handle)
{
MessageBox(_T(" Connection lost "));
return;
}
switch (nIDEvent)
{
Case 1: // Update the position and velocity information of controller axes 0-3
CString Xpos, Xmspeed;
CString Ypos, Ymspeed;
CString Zpos, Zmspeed;
CString Upos, Umspeed;
float showpos[4] = { 0 };
float mspeed[4] = { 0 };
int status = 0;
//Get current axis position
ZAux_Direct_GetAllAxisPara(g_handle, " DPOS ", 4, showpos);
Xpos.Format(" X: %.2f ", showpos[0]);
Ypos.Format(" Y: %.2f ", showpos[1]);
Zpos.Format(" Z: %.2f ", showpos[2]);
Upos.Format(" U: %.2f ", showpos[3]);
GetDlgItem(IDC_XPOS)->SetWindowText(Xpos);
GetDlgItem(IDC_YPOS)->SetWindowText(Ypos);
GetDlgItem(IDC_ZPOS)->SetWindowText(Zpos);
GetDlgItem(IDC_UPOS)->SetWindowText(Upos);
// Determine the state of the primary axis (i.e., the first axis of the base).
ZAux_Direct_GetIfIdle(g_handle, 0, &status);
if (status == -1)
{
GetDlgItem(IDC_RUNSTATUS)->SetWindowText(" Motion Status: Stopped ");
}
else
{
GetDlgItem(IDC_RUNSTATUS)->SetWindowText(" Motion Status: In Motion ");
}
//Update axis speed
ZAux_Direct_GetAllAxisPara(g_handle, " MSPEED ", 4, mspeed);
Xmspeed.Format(" X-axis speed: %.2f ", mspeed[0]);
Ymspeed.Format(" Y-axis speed: %.2f ", mspeed[1]);
Zmspeed.Format(" Z-axis speed: %.2f ", mspeed[2]);
Umspeed.Format(" U-axis speed: %.2f ", mspeed[3]);
GetDlgItem(IDC_SPEED_X)->SetWindowText(Xmspeed);
GetDlgItem(IDC_SPEED_Y)->SetWindowText(Ymspeed);
GetDlgItem(IDC_SPEED_Z)->SetWindowText(Zmspeed);
GetDlgItem(IDC_SPEED_U)->SetWindowText(Umspeed);
break
}
CDialogEx::OnTimer(nIDEvent);
}
5. Start the continuous interpolation motion by using the event handler function of the start button.
//Start button
void CMergeDlg::OnBnClickedButtonRun()
{
if (NULL == g_handle)
{
MessageBox(_T( "Connection lost" ));
return;
}
UpdateData(true); // Refresh parameters
int corner_mode = 0;
int axislist[4] = { 0,1,2,3 }; // List of motion base axes
float dislist1[4] = { 0 }; // List of movement distances
float dislist2[4] = { 0 };
float dislist3[4] = { 0 };
//Select the axes involved in the motion; the first axis is the master axis, and all interpolation parameters use the master axis parameters.
ZAux_Direct_SetSpeed(g_handle, axislist[0], M_Speed); //Speed
ZAux_Direct_SetAccel(g_handle, axislist[0], M_Accel); //Acceleration
ZAux_Direct_SetDecel(g_handle, axislist[0], M_Decel); // Deceleration
ZAux_Direct_SetSramp(g_handle, axislist[0], M_SRAMP); // S-curve time
//Set corner mode
if (m_mode1 == 1)
{
corner_mode = corner_mode + 2;
}
if (m_mode2 == 1)
{
corner_mode = corner_mode + 8;
}
if (m_mode3 == 1)
{
corner_mode = corner_mode + 32;
}
ZAux_Direct_SetCornerMode(g_handle, axislist[0], corner_mode);
//Set continuous interpolation
ZAux_Direct_SetMerge(g_handle, axislist[0], m_mode);
//Set SP speed
ZAux_Direct_SetForceSpeed(g_handle, axislist[0], SP_Speed);
//Set the start and end deceleration angles, converted to radians
ZAux_Direct_SetDecelAngle(g_handle, axislist[0], StartAngle * 3.14 / 180);
ZAux_Direct_SetStopAngle(g_handle, axislist[0], StopAngle * 3.14 / 180);
//Set the speed limit radius of the small circle
ZAux_Direct_SetFullSpRadius(g_handle, axislist[0], SP_Radius);
//Set corner radius
ZAux_Direct_SetZsmooth(g_handle, axislist[0], CornerRadius);
//In the SP command, set a large startmovespeed and endmovespeed in the automatic cornering mode.
ZAux_Direct_SetStartMoveSpeed(g_handle, axislist[0], 10000);
ZAux_Direct_SetEndMoveSpeed(g_handle, axislist[0], 10000);
//Update exercise data
dislist1[0] = DPOS_X_1; dislist1[1] = DPOS_Y_1;
dislist1[2] = DPOS_Z_1; dislist1[3] = DPOS_U_1;
dislist2[0] = DPOS_X_2; dislist2[1] = DPOS_Y_2;
dislist2[2] = DPOS_Z_2; dislist2[3] = DPOS_U_2;
dislist3[0] = DPOS_X_3; dislist3[1] = DPOS_Y_3;
dislist3[2] = DPOS_Z_3; dislist3[3] = DPOS_U_3;
//Start exercising
ZAux_Direct_Move(g_handle, 4, axislist, dislist1);
ZAux_Direct_Move(g_handle, 4, axislist, dislist2);
ZAux_Direct_Move(g_handle, 4, axislist, dislist3);
}
6. Stop the interpolation motion by using the event handler function of the stop button.
//Stop button
void CMergeDlg::OnBnClickedButtonStop()
{
if (NULL == g_handle)
{
MessageBox(_T("Connection lost"));
return;
}
ZAux_Direct_Single_Cancel(g_handle, 0, 2); // Stop one axis of the main spindle base.
}
7. Zero the axis coordinates.
//Reset coordinates
void CMergeDlg::OnBnClickedButtonClear()
{
if (NULL == g_handle)
{
MessageBox(_T("Connection lost"));
return;
}
for (int i = 0; i<4; i++)
{
ZAux_Direct_SetDpos(g_handle, i, 0); // Set DPOS to zero
}
}
8. Compile and run the demonstration.
1) Compile and run the teaching example.
2) Simultaneously, the same controller is connected via ZDevelop software to monitor the axis parameters of motion control.
A. Position waveform of continuous interpolation with automatic chamfering.
B. Speed waveform without continuous interpolation.
C. Speed waveform of continuous interpolation plus appropriate corner deceleration.
That concludes our discussion of C++ development for positive motion technology. For more learning videos and articles, please follow our WeChat official account, "Positive 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.