Share this

Motion Control Card Application Development Tutorial: Laser Galvanometer Control

2026-04-06 05:42:22 · · #1

Today, Zheng Motion Technology will share with you a routine for developing a motion control system for a laser galvanometer using C++.

We will start by explaining how to create a new MFC project and add function libraries, and finally use a practical project example—laser galvanometer marking—to familiarize everyone with its project development.

Before we begin our formal learning, let's first understand the ZMC420SCAN motion controller from Zhengdong Technology. This product is a 20-axis motion controller.

The ZMC420SCAN bus controller supports ECAT/RTEX bus connection and up to 20-axis motion control, including linear interpolation, arbitrary circular interpolation, spatial circular interpolation, helical interpolation, electronic cam, electronic gear, synchronous following, and virtual axis settings. It adopts an optimized network communication protocol to achieve real-time motion control.

The ZMC420SCAN bus controller supports mixed interpolation of pulse axis/bus axis/mirror axis.

The ZMC420SCAN supports 10 pulse outputs and encoder feedback, as well as 4 galvanometer axes. It has 24 onboard inputs, 12 onboard outputs, 2 AD converters, and 2 DA converters. All output ports support high-speed PWM control.

The wiring method is shown in Figure 1 below:

Figure 1

The ZMC420SCAN uses a single API function that supports development languages ​​such as C, C++, C#, LabVIEW, Python, and Delphi, as well as platforms such as VC6.0, VB6.0, Qt, and .Net, and operating systems such as Windows, Linux, WinCE, and iMac.

Figure 2

The PWM output of the ZMC420SCAN is controlled by the normal output function. PWM output can only be performed when the output port is in the "ON" state, which facilitates the control of laser energy.

The ZMC420SCAN has precise output functions for outputs 0-7. The precise output function of each output is independent of each other. The MOVEOP_DELAY and AXIS_ZSET are used to set whether each MOVE_OP command uses precise output and the delay of precise output, thereby realizing PSO control of the laser.

The ZMC420SCAN's outputs 0-7 support precise output and are independent of each other. The laser's on/off state, precise output switching, and delay can be controlled separately through the commands: MOVE_OP, AXIS_ZSET, and MOVEOP_DELAY, thereby achieving laser PSO control.

galvanometer axis:

The ZMC420SCAN supports the XY2-100 galvanometer protocol and enables motion control and galvanometer-based joint interpolation motion.

The host computer connects to the controller via the network port, obtains the handle of the corresponding controller, controls the galvanometer axis through the XY2-100 protocol, and controls the servo or stepper axis through the bus protocol or pulse mode.

Local axis numbers 4/5 can be configured as the first galvanometer with ATYPE=21, and local axis numbers 6/7 can be configured as the second galvanometer with ATYPE=21. The axis number can be configured via AXIS_ADDRESS.

The following is a laser galvanometer
Control the development process

Adding function libraries to a new MFC project

1. In VS2017, 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 "MFC/ATL".

3. Select "Dialog-based" as the type, then click Next or Finish. Clicking Next will continue configuring, while clicking Finish will complete the process. Once the type is selected, the rest can be edited within the project.

4. Locate the CD-ROM data provided by the manufacturer. The path is as follows (64-bit library example):

A. Go to the CD-ROM and find the PC function folder.

B. Select function library 2.1.

C. Windows platform.

D. Select the appropriate function library as needed; here, we choose the 64-bit library.

E. Unzip the C++ compressed file, which contains the corresponding C++ function library.

F. The specific path to the function library is as follows.

5. Copy the C++ library files and related header files provided by the vendor into the newly created project.

6. Add static libraries and relevant header files to the project.

Static libraries: zauxdll.lib, zmotion.lib

Relevant header files: zauxdll2.h, zmotion.h

A. First, right-click the header file, then select: "Add" → "Existing Item".

B. In the pop-up window, add the static library and related header files in sequence.

7. Declare the header files used and define the controller connection handle.

The project is now complete.

Second, consult the PC function manual to understand its usage.

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.

4. Using the obtained controller handle, set the laser galvanometer axis type for the controller.

The third parameter has the following mode options. To use a galvanometer axis, you need to select mode 21 for axis type. Setting the axis to galvanometer axis type will result in a much faster system cycle and refresh cycle than a normal axis.

5. By obtaining the controller handle, the controller's galvanometer axis can be controlled to perform multi-axis motion control, and mixed interpolation motion can be performed by combining the galvanometer axis with ordinary axes.

Three practical exercises: Laser galvanometer marking example

1. The example program establishes the connection of the board, sets the corner deceleration and speed parameters of the galvanometer axis, processes the internal motion trajectory, and completes the marking of the circle.

2. Simplified flowchart of the routine.

3. Connect to the controller via the network port and obtain the controller connection handle.

//IP connection

void CMarkDemoDlg::OnBnClickedButton2()

{

// TODO: Add control notification handler code here

char buffer[256];

char item[256] = {0};

float ftemp = 0.0;

char atemp[256] = {0}; // Stores the controller model

uint32 uitemp = 0;

int32 iresult;

if (NULL != g_handle)

{

ZMC_Close(g_handle);

g_handle = NULL;

}

GetDlgItemText(IDC_IP_COMBO, buffer, 255); // Get the IP address of the current text box.

buffer[255] = '\0';

iresult = ZMC_OpenEth(buffer, &g_handle); // Get the result of establishing a connection with the controller

if (ERR_SUCCESS != iresult)

{

g_handle = NULL;

MessageBox(_T("Connect Failed"));

SetWindowText(_T("ZControlTest-Connect Failed"));

return;

}

SetWindowText("succse");

//

CComboBox *m_pEthList;

m_pEthList = (CComboBox *)GetDlgItem(IDC_IP_COMBO); //Get IP address

if (NULL == m_pEthList)

{

return;

}

//

if(CB_ERR != m_pEthList->FindString(0, buffer))

{

return;

}

//join in

m_pEthList->AddString(buffer); // Add the IP address to the box.

}

4. Connect to the controller via serial port and obtain the controller connection handle.

void CMarkDemoDlg::OnBnClickedButton4()

{

// TODO: Add control notification handler code here

int32 iresult;

uint8 icomid;

float ftemp = 0.0;

char atemp[256] = {0}; // Stores the controller model

uint32 uitemp = 0;

int m_icombaud;

if (NULL != g_handle)

{

ZMC_Close(g_handle);

g_handle = NULL;

}

CComboBox *m_pParityList;

m_pParityList = (CComboBox *)GetDlgItem(IDC_COMBO_PARITY);

m_icombaud = GetDlgItemInt(IDC_BAUD_COMBO);

ZMC_SetComDefaultBaud(m_icombaud, 8, m_pParityList->GetCurSel(), ONESTOPBIT);

icomid = GetDlgItemInt(IDC_PORT_COMBO);

iresult = ZMC_OpenCom(icomid, &g_handle);

if (ERR_SUCCESS != iresult)

{

g_handle = NULL;

MessageBox(_T("Connect Failed"));

return;

}

SetWindowText("success");

CString Comname;

CComboBox *m_pComList;

m_pComList = (CComboBox *)GetDlgItem(IDC_PORT_COMBO);

if (NULL == m_pComList)

{

return;

}

Comname.Format("%d",icomid);

//

if(CB_ERR != m_pComList->FindString(0, Comname))

{

return;

}

//join in

m_pComList->AddString(Comname);

}

5. Use the generated handle to configure axis parameters, axis type, etc.

int axislist[2] = {4,5};

char cbuf[32] = {};

//Set spindle

ZAux_Direct_Base(g_handle, 2, axislist);

//Get the parameters to be set in the edit box

int MachSpeed ​​= GetDlgItemInt(IDC_EDIT_SPEED);

int MachAddSpeed ​​= GetDlgItemInt(IDC_EDIT_ADDSPEED);

int MachDecSpeed ​​= GetDlgItemInt(IDC_EDIT_DECSPEED);

float MachDecAngle = GetDlgItemInt(IDC_EDIT_DECANGLE) * 3.14 / 180;

float MachStopAngle = GetDlgItemInt(IDC_EDIT_STOPANGLE) * 3.14 / 180;

//Axis initialization

for (int i = 4; i <= 5; i++)

{

//Set the axis type to galvanometer axis type

ZAux_Direct_SetAtype(g_handle, i, 21);

//Set the number of pulses per revolution

ZAux_Direct_SetUnits(g_handle, i, 300);

//Set speed

ZAux_Direct_SetSpeed(g_handle, i, MachSpeed);

//Set acceleration

ZAux_Direct_SetAccel(g_handle, i, MachAddSpeed);

//Set deceleration

ZAux_Direct_SetDecel(g_handle, i, MachDecSpeed);

//Enable continuous interpolation of the galvanometer axis

ZAux_Direct_SetMerge(g_handle, i, 1);

//Set corner deceleration mode and automatic chamfer mode

ZAux_Direct_SetCornerMode(g_handle, i, 32+2);

//Set corner radius

ZAux_Direct_SetZsmooth(g_handle, i, 0.1);

//Set the speed limit radius of the small circle

ZAux_Direct_SetFullSpRadius(g_handle, i, 20);

//Set deceleration angle

ZAux_Direct_SetDecelAngle(g_handle, i, MachDecAngle);

//Set stop angle

ZAux_Direct_SetStopAngle(g_handle, i, MachStopAngle);

//Set SP speed

ZAux_Direct_SetForceSpeed(g_handle, i, 5000);

}

//Enable precise output function

ZAux_DirectCommand(g_handle, "AXIS_ZSET(4)=2", cbuf, 32);

ZAux_Direct_SetOp(g_handle, 11, 1);

ZAux_Direct_Base(g_handle, 2, axislist);

ZAux_Direct_SetOp(g_handle, 1, 1);

6. The trajectory movement data in this example is all input in the form of small line segments. During the operation, multiple small line segments are used to perform arc fitting to speed up the processing.

CAD trajectory diagram of a single circle:

The corresponding trajectory data and usage code are as follows:

//Single circle relative

double x1[] = {-0.038000, -0.113000, -0.184000, -0.250000, -0.308000, -0.357000, -0.395000, -0.421000, -0.434000, -0.434000, -0.421000, -0.395000, -0.357000, -0.308000, -0.250000, -0.184000, -0.113000, -0.038000, 0.038000, 0.113000, 0.184000, 0.250000, 0.308000, 0.357000, 0.395000, 0.421000, 0.434000, 0.434000, 0.421000, 0.395000, 0.357000, 0.308000, 0.250000, 0.184000, 0.113000, 0.038000};

double yh1[] = {0.434000, 0.421000, 0.395000, 0.357000, 0.308000, 0.250000, 0.184000, 0.113000, 0.038000, -0.038000, -0.113000, -0.184000, -0.250000, -0.308000, -0.357000, -0.395000, -0.421000, -0.434000, -0.434000, -0.421000, -0.395000, -0.357000, -0.308000, -0.250000, -0.184000, -0.113000, -0.038000, 0.038000, 0.113000, 0.184000, 0.250000, 0.308000, 0.357000, 0.395000, 0.421000, 0.434000};

Explanation of the function for converting a small line segment to an arc:

/*********************************************************

Description: //Small line segments become arcs

Input: //handle: The handle of the connected controller

//pXPos: The array of x-coordinates of the line segment

//pYPos: The y-coordinate array of the line segment

//nMaxNum: Maximum number of points

//nMaxFitNum: Maximum number of fitted segments (100~1000)

//nAbs: 1 = absolute; 0 = relative; indicates whether the passed x and y coordinate data are absolute or relative.

//refDistance: reference precision

Output: //

Return: //Error code

*************************************************************/

int __stdcall ZGraphProcess_SegFitArc(ZMC_HANDLE handle, double *pXPos, double *pYPos, int nMaxNum, int nMaxFitNum, int nAbs, double refDistance);

This function simplifies the process by fitting multiple small line segments into an arc, eliminating the need for separate interpolation operations for each segment. This is an internal function; please contact our motion technology engineers for support if needed.

The code uses a single circle to fit and perform marking by creating a horizontal and vertical cyclic marking array.

int axislist[2] = {4,5};

char cbuf[32] = {};

//Set spindle

ZAux_Direct_Base(g_handle, 2, axislist);

for (int k = 0; k < 1; k++)

{

for (int i = 0; i < 5; i++)

{

// Move to a specified location

ZAux_DirectCommand(g_handle, "MOVE (0, -15)", cbuf, 32);

for (int j = 0; j < 5; j++)

{

ZAux_DirectCommand(g_handle, "MOVE (-15, 0)", cbuf, 32);

ZAux_Direct_MoveOp(g_handle, 0, 1);

// Convert a small line segment to an arc

int err_seg = ZGraphProcess_SegFitArc(g_handle, x1, yh1, sizeof(x1)/sizeof(double), 1000, 0, 0.01);

ZAux_Direct_MoveOp(g_handle, 0, 0);

}

ZAux_DirectCommand(g_handle, "MOVE (75, 0)", cbuf, 32);

}

ZAux_DirectCommand(g_handle, "MOVE (0, 75)", cbuf, 32);

}

7. Compile and run the demonstration.

(1) Compile and run the teaching routine.

(2) At the same time, the same controller is connected through ZDevelop software to monitor the axis parameters of motion control.

The time taken to mark 25 circles and the oscilloscope display graph are as follows:

The timing of marking 25 circles and the graph displayed on the oscilloscope.

Real-life demonstration of positive motion technology laser galvanometer

This concludes our tutorial on laser galvanometer control for motion control card applications developed by Zheng Motion Technology. For more exciting content, please follow the "Zheng Motion Assistant" WeChat official account.

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 136CM Vivian (Customer Photos)

Height: 136cm Weight: 23.3kg Shoulder Width: 31cm Bust/Waist/Hip: 60/54/68cm Oral Depth: 3-5cm Vaginal Depth: 3-15cm An...

Articles 2026-02-22