Share this

Open-source laser galvanometer motion controller: C++ for quick access to graphics library applications

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

Today, Zheng Motion Assistant will share with you an open-source laser galvanometer motion controller: C++ for quick graphics library calls. This article takes QR code marking, text marking, and vector graphics marking as examples to solve the errors that users may encounter when performing various complex operations and calling function libraries during laser marking.

01ZMC408SCAN Controller Introduction

The ZMC408SCAN is a high-performance bus-based dual-mirror motion controller launched by Zheng Motion Technology. It integrates two 100M Ethernet ports and supports EtherCAT, EtherNET, CAN, RS232, RS485, 24 general-purpose digital inputs, 20 general-purpose digital outputs, 2 general-purpose analog outputs, 2 general-purpose analog inputs, 4 local differential pulse axis interfaces, 1 MPG handwheel encoder interface, 2 galvanometer interfaces with feedback, 1 dedicated laser power supply interface, and 1 EXIO configurable expansion I/O interface.

The ZMC408SCAN controller supports EtherCAT bus connectivity, a refresh rate as fast as 500μs, and motion control of up to 16 axes. It supports linear interpolation, arbitrary circular interpolation, spatial circular interpolation, helical interpolation, electronic cams, electronic gears, synchronous following, and virtual axis settings. Utilizing an optimized network communication protocol, it enables real-time motion control. A single computer can support up to 256 ZMC controllers connected simultaneously.

(1) The ZMC408SCAN has a built-in high-precision PSO position synchronization output function, which can keep the laser output spacing constant even when deceleration adjustment is made when machining fillets and curves, in high-speed machining situations;

(2) Supports laser galvanometer control and galvanometer feedback, including 2 galvanometer interfaces, supporting 2D galvanometers and 3D galvanometers. With the MOVESCAN motion command without acceleration or deceleration, the galvanometer processing at corners is automatically delayed, achieving precise and efficient laser control and improving the productivity of laser processing equipment;

(3) The laser on/off delay can be flexibly adjusted during movement via commands, with fast response and precise control down to the microsecond level. The setup process is simple, greatly reducing the engineer's parameter tuning time. (4) It comes with a built-in LASER laser control interface, supporting IPG, YLR, YLS and other types of laser power supplies. It also has an EXIO expansion IO interface, which can flexibly control various mainstream lasers on the market through a customized adapter board. (5) It supports simultaneous control of 16 ZMC408SCAN controllers by PC, forming a laser processing of a galvanometer array.

(6) It has 4 high-speed differential pulse outputs on board and 4 high-speed differential encoder feedbacks. It supports EtherCAT bus driver control, 5-axis XYZAC interpolation, and mixed interpolation of galvanometer axis and motion axis.

1. Basic Specifications

2. Interface Definition

3. Reference Architecture

02 Labeling Library Description

1. The purpose is to solve the errors that easily occur when performing various complex operations and calling function libraries during laser marking. Users can more conveniently generate processing files via PC and perform graphic processing operations within the software. For example, to mark a QR code, simply set the parameters using the barcode command `ZmotionLaser_BarCode(int nTechnology, const char *pStrText, const char *pStrType, double dX, double dY, double dSizeX, double dSizeY, double dAngle)`, select the code type to be marked, and input the marking content. The program will then generate a 3D file of the trajectory, ready for marking to begin. To mark text, set the process parameters (size, rotation angle, etc.) using the corresponding text command `ZmotionLaser_Text(int nTechnology, const char *pStrText, double dX, double dY, double dAccuracy)`, and then input the text content to be marked. The marking will be performed in 3D file format.

We have corresponding interface commands for marking barcodes, QR codes, text in different font styles, vector graphics, bitmaps, etc., which enables rapid parameter tuning and development, saving engineers a lot of programming and process planning time.

2. Method

Add the ZmotionLaser.dll and ZmotionLaser.lib libraries to the program that needs to use them, and call the relevant functions in ZmotionLaser.h to generate the three-dimensional files that need to be processed. Run the three-dimensional files in the controller to perform the processing (requires the Zmotion library and ZMotionCad3 library).

3. The steps for using the three files are as follows:

(1) Start file generation first; (2) Perform various initializations and determine the axis and output port; (3) Set various machining parameters and adjust the machining effect; (4) Call the machining function and write the data to be processed; (5) Call the generation function to generate the machining file three times;

(6) Turn off file generation.

4. Advantages

It only requires a few instructions to fill in the corresponding parameters to achieve a type of marking, simplifying complex instruction programming. It can also dynamically append files and send strings to run even for complex machining trajectories and large files.

03 Instruction Description

I. Barcode

1. Function name: uint32 ZmotionLaser_BarCode(int nTechnology, const char *pStrText, const char *pStrType, double dX, double dY, double dSizeX, double dSizeY, double dAngle)

2. Explanation: This command processes barcode graphics. Using this command in conjunction with several other commonly used commands, we can easily select the type of barcode to be marked, as well as change the desired size and position within the marking area. II. Text and Status Settings

1. Text

(1) Function name: uint32 ZmotionLaser_Text(int nTechnology, const char *pStrText, double dX, double dY, double dAccuracy) (2) Description: This function is used to process text graphics. By combining this function with several other commonly used functions, we can easily achieve text marking. We only need to fill in the marking content in the corresponding parameter position and write the process parameters, marking coordinate position, etc. in the corresponding parameters.

2. Text Status Settings

(1) Function name: uint32 ZmotionLaser_SetTextStyle(const char * pStrFont, bool bThickness, bool bItalics, bool bUnderline, bool bDelete, double dHeight, double dWidthR, double dAngle, double dTilt)

(2) Explanation: To set the text status, you need to determine the font, style, size, angle, and slant of the text. Once this status is set, all subsequent text will follow this status and be used in conjunction with text commands for text marking.

III. Vector Graphics Parameter Settings

1. Function name: uint32 ZmotionLaser_SetVectPar(int nPower, double dFreq, double dMarkSp, double dJumpSp, double dOpenDelay, double dCloseDelay, double dJumpDelay, double dCorAngle, double dCorDelay, double dEndDelay, int nTechnology)

2. Description: Sets the processing parameters for a specific vector graphics process. This command is used for parameter settings during vector graphics processing. Given the complexity of vector graphics processing, pre-writing the parameters allows for a faster response during marking.

04 Examples of Laser Galvanometer Control

I. QR code labeling

1. QR code marking parameter settings interface

2. Operating Procedures

(1) After setting up the equipment, use a galvanometer calibration tool to calibrate the galvanometer (refer to the article "Open Laser Galvanometer Motion Controller: C++ Galvanometer Calibration Method and Implementation" in the Zheng Motion Assistant); (2) After calibration, as shown in the figure above, select the corresponding IP address to connect, select the corresponding laser type, set the motion parameters, select the filling process and set the parameters, select the barcode type to be marked, set the barcode size and marking position rotation angle, etc., and fill in the marking content in the content column;

(3) Once the preparation is complete, click "Mark" to begin marking. If any abnormalities are found during the process, click "Stop".

This routine allows us to mark various types of barcodes and QR codes, is suitable for various laser types, and allows us to adjust the marking content, size, position, and angle in the xy plane at any time. Furthermore, by adjusting the power, we can mark different items, such as flat product packaging, chargers, mobile phone cases, and some metal products.

We use the header file and define the controller handle to take the first step in connecting to the controller. We connect to the controller using the `ZAux_OpenEth(char *ipaddr, ZMC_HANDLE * phandle)` instruction and obtain the returned handle. To disconnect, we use `ZAux_Close(ZMC_HANDLE handle)`. Once connected, we can interactively control the controller.

The procedure is as follows:

//Connect controller void CZmc_laserDlg::OnBnClickedBtnConnet(){ char buffer[256]; int32 iresult; if(NULL != m_Handle) { ZAux_Close(m_Handle); m_Handle = NULL; } GetDlgItemText(IDC_IPLIST,buffer,255); buffer[255] = '\0'; iresult = ZAux_OpenEth(buffer, &m_Handle); if(ERR_SUCCESS != iresult) { m_Handle = NULL; MessageBox(_T("Connection failed")); SetWindowText("Not connected"); return; } SetWindowText("Connected"); for(int iAxis = 4;iAxis<=5;iAxis++) { iresult = ZAux_Direct_SetAtype(m_Handle,iAxis,21); iresult = ZAux_Direct_SetUnits(m_Handle,iAxis,500); } OnCbnSelchangeComboLaser();}//Disconnect the controller void CZmc_laserDlg::OnBnClickedBtnClose(){ if(NULL != m_Handle) { KillTimer(0); //Turn off the timer ZAux_Close(m_Handle); m_Handle = NULL; SetWindowText("Not connected"); }}

3. Select the laser type: Set the adapter board type using the command ZAux_SetExioType(ZMC_HANDLE handle, int iType). Different adapter board types correspond to different types of lasers (customization required). When using it, simply select the corresponding laser type, connect the cables according to the corresponding interface, and adjust the power (laser energy) and frequency.

The procedure is as follows:

//Modify laser type void CZmc_laserDlg::OnCbnSelchangeComboLaser(){ if(NULL == m_Handle) { MessageBox(_T("Controller not connected")); return; } UpdateData(TRUE); if(m_nLaserType == FIBER_408) //408 FIBER conversion? Board parameter settings{ int iret = ZAux_SetExioType(m_Handle,0); m_nEnableIO = 47; m_nLaserIO = 8; m_nRedIO = 48; m_nAout = 3; m_nPwmIo = 9; } else if(m_nLaserType == LASER_408) { int iret = ZAux_SetExioType(m_Handle,-1); m_nEnableIO = 31; m_nLaserIO = 8; m_nRedIO = 32; m_nAout = 2; m_nPwmIo = 9; } else if(m_nLaserType == YAG_408) //408 YAG converter board parameter settings { int iret = ZAux_SetExioType(m_Handle,1); m_nEnableIO = 47; m_nLaserIO = 8; m_nRedIO = 48; m_nAout = 3; m_nPwmIo = 9; } else if(m_nLaserType == FIBER_504) //504 { m_nEnableIO = 5; m_nLaserIO = 6; m_nRedIO = 28; m_nAout = 2; m_nPwmIo = 7; } UpdateData(FALSE);}

4. Set motion parameters and QR code size parameters

The motion parameters and filling process parameters are stored in variables and called during the subsequent marking process. This current value is an initial value and serves as a reference; specific parameters need to be adjusted through testing to better suit the corresponding machine and marking process. The idle movement speed is the speed used for the idle movement trajectory in the subsequent marking process. The switching delay is used to turn on the laser ahead of time and delay its shutdown. Setting an appropriate switching delay parameter can eliminate the "match head" effect that appears at the start of the motion, but if the switching delay parameter is set too large, it will cause the initial segment to have missing strokes. ZAux_Direct_MoveOpDelay can be set to a negative value, causing the marking laser to emit light earlier. Generally, the switching delay of fiber lasers is set to a negative value, while other lasers, such as end-pumped lasers, are set to a positive value. Setting an appropriate shutdown delay parameter can eliminate the incomplete closure phenomenon that appears at the end of the motion, but if the shutdown delay is set too large, it will cause the "match head" effect to appear at the end segment. After the shutdown command, the ZAux_Direct_MoveDelay command is called to set the corresponding delay time to achieve delay control. Setting appropriate corner delay parameters can eliminate rounded corners that appear when the motion trajectory is a right angle. However, if the corner delay is set too large, it will increase the marking time and cause a noticeable emphasis at the corner. To solve this problem, an automatic corner delay mode is introduced, which calculates the delay time based on the corner angle. The ZAux_Direct_SetCornerMode command is used to set the corner delay mode to 2. The ZAux_Direct_SetDecelAngle and ZAux_Direct_SetStopAngle commands are used to set the corner start and end delay angles, and ZAux_Direct_SetZsmooth is used to set the maximum corner delay time.

The actual corner delay is automatically calculated based on the actual angle of the trajectory. Within the set angle range, the delay time is linearly distributed.

The procedure is as follows:

CZmc_laserDlg::CZmc_laserDlg(CWnd* pParent /*=NULL*/) : CDialogEx(CZmc_laserDlg::IDD, pParent){ m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); m_nEnableIO = 47; m_nLaserIO = 8; m_nRedIO = 48; m_nAout = 3; m_nAoutVal = 128; m_nPwmIo = 9; m_nPwmFreq = 40000; m_dSpeed ​​= 1000; m_dEmpSpeed ​​= 1000; m_nStartDelay = 1000; m_nLastDelay = 1000; m_nCorDelay = 1000; m_nLaserType = 0; // Fill parameter initialization m_FillPara.m_bEnable = true; // Fill enable m_FillPara.m_bOutline = true; // Enable contour m_FillPara.m_bOutlineFirst = false; // Contour priority m_FillPara.m_bEdge = false; // Whether to go around the edge once m_FillPara.m_bAverage = true; // Whether to evenly distribute fill lines m_FillPara.m_nType = 1; // Fill type m_FillPara.m_nAngle = 0; // Fill line angle m_FillPara.m_nNum = 0; // Number of fill lines m_FillPara.m_dLineSpace = 0.1; // Line spacing m_FillPara.m_dMargin = 0; // Margin m_FillPara.m_dSOffset = 0; // Start offset m_FillPara.m_dEOffset = 0; // End offset m_FillPara.m_dLineIndent = 0; // Linear indentation // Text parameters m_dTextHigh = 30; // Text height m_dTextWidth = 30; // Text width m_dTextAngle = 0; // Text angle m_dTextXpos = 0; m_dTextYpos = 0; m_TextString = _T("");}

5. Set filling process parameters

The input content generates a QR code, and our QR code trajectory is divided into small line segments to generate three files, and filling process parameters are set into them.

Set the output port number using the command ZmotionLaser_SetOutput(int nAp, int nMO, int nRed) to prepare for marking.

Filling process: mainly involves some parameters of the instruction uint32 ZmotionLaser_SetFillParam(bool bEnable, bool bOutline, bool bOutlineFirst, bool bEdge, bool bAverage, int nType, int nAngle, int nNum, double dLineSpace, double dMargin, double dSOffset, double dEOffset, double dLineIndent, int nFillNum), which are displayed on the interface as variables.

bOutline Enable Outline: Whether to preserve the original graphic outline during fill. bOutlineFirst Outline Priority: When preserving the outline during fill, selecting outline priority will process the outline trajectory before the fill line; otherwise, the outline trajectory will be processed after the fill line (for more information on fill processes, please contact Zheng Motion's technical support engineers). Fill Type: The method of filling the graphic.

(1) Single-phase fill: The fill line always fills from left to right;

(2) Two-way fill: The fill line first moves from left to right, then from right to left, and the rest of the fill is done in a loop;

(3) Bow-shaped fill: Similar to two-way fill, but a connecting line will be generated between the ends of the fill lines;

(4) Optimize bow fill: Similar to bow fill, but blank areas of the object will still be filled.

The procedure is as follows:

void CZmc_laserDlg::OnEnChangeEditText(){ UpdateData(TRUE); // Open the marking library file 3 times int rtn = ZmotionLaser_OpenFile3(m_Handle); if(CheckError(rtn,"ZmotionLaser_OpenFile3")) return; rtn = ZmotionLaser_SetOutputLimits(55); // Set the maximum number limit of the output port if(CheckError(rtn,"ZmotionLaser_OpenFile3")) return; rtn = ZmotionLaser_SetScanAxis(4,5); // Set the galvanometer axis number if(CheckError(rtn,"ZmotionLaser_SetScanAxis")) return; rtn = ZmotionLaser_SetOutput(m_nLaserIO,m_nEnableIO,m_nRedIO); // Set the on/off light control if(CheckError(rtn,"ZmotionLaser_SetOutput")) return; rtn = ZmotionLaser_AoutInit(m_nAout, 255); // Set analog power settings if(CheckError(rtn,"ZmotionLaser_AoutInit")) return; rtn = ZmotionLaser_SetPowerEnable(false); // Disable dynamic power modification if(CheckError(rtn,"ZmotionLaser_SetPowerEnable")) return; rtn = ZmotionLaser_SetLightInstruct(1); if(CheckError(rtn,"ZmotionLaser_SetLightInstruct")) return; rtn = ZmotionLaser_SetLightString("MOVE_OP(8,ON)\n","MOVE_OP(8,OFF)\n"); if(CheckError(rtn,"ZmotionLaser_SetLightInstruct")) return; // Set machining process parameters int ipower = (int)(m_nAoutVal*100/256); rtn = ZmotionLaser_SetVectPar(ipower, m_nPwmFreq, m_dSpeed, m_dEmpSpeed, m_nStartDelay, m_nLastDelay, m_nLastDelay, 10, m_nCorDelay, m_nLastDelay, 1); if(CheckError(rtn,"ZmotionLaser_SetVectPar")) return; // Set fill parameters rtn = ZmotionLaser_SetFillObject(m_FillPara,1); if(CheckError(rtn,"ZmotionLaser_SetFillObject")) return; // Start filling rtn = ZmotionLaser_FillStart(); if(CheckError(rtn,"ZmotionLaser_FillStart")) return; // Process text characters CString strBarCode; m_ListBarCode.GetLBText(m_ListBarCode.GetCurSel(),strBarCode); rtn = `ZmotionLaser_BarCode(1,m_TextString,strBarCode,m_dTextXpos,m_dTextYpos,m_dTextHigh,m_dTextWidth,m_dTextAngle); if(CheckError(rtn,"ZmotionLaser_BarCode")) return; // End filling rtn = ZmotionLaser_FillEnd(); if(CheckError(rtn,"ZmotionLaser_FillEnd")) return; char* MoveStr = NULL; int nRow = 0; MoveStr = ZmotionLaser_GetProcessString(false); MoveStr = ZmotionLaser_GetProEndString(nRow); OnShowGraph(); // Display graph // Generate three-stage processing file rtn = ZmotionLaser_CreateFile3(".//ZscanLaser.z3p",true); if(CheckError(rtn,"ZmotionLaser_CreateFile3")) return; rtn = ZmotionLaser_CloseFile3();` if(CheckError(rtn,"ZmotionLaser_CloseFile3")) return;}

6. Marking

Download the file to the controller ROM three times using the Zpj file method, and then start a task that is either unused or has been confirmed to be stopped to run the file.

The procedure is as follows:

void CZmc_laserDlg::OnBnClickedBtnMark(){ if(NULL == m_Handle) { MessageBox(_T("Controller not connected")); return; } // Run the generated file 3 times int rtn = ZAux_Down3FileRom(m_Handle,".//ZscanLaser.z3p","Text123.z3p"); if(CheckError(rtn,"ZAux_Down3FileRom")) return; rtn = ZAux_Direct_StopTask(m_Handle,1); if(CheckError(rtn,"ZAux_Direct_StopTask")) return; rtn = ZAux_Run3FileRom(m_Handle,"Text123.z3p",1,0); // Run the file 3 times in Task 1 if(CheckError(rtn,"ZAux_Down3FileRom")) return;}

7. Complete the marking.

Stopping processing mainly involves halting the task, stopping all axis movements, and turning off the laser.

The procedure is as follows:

void CZmc_laserDlg::OnBnClickedBtnStop(){ int rtn = ZAux_Direct_StopTask(m_Handle,1); if(CheckError(rtn,"ZAux_Direct_StopTask")) return; rtn = ZAux_Direct_Rapidstop(m_Handle,3); if(CheckError(rtn,"ZAux_Direct_Rapidstop")) return; rtn = ZAux_Direct_SetOp(m_Handle,m_nLaserIO,0); //Turn off the light Sleep(10); rtn = ZAux_Direct_SetOp(m_Handle,m_nEnableIO,0); SetDlgItemTextA(IDC_BTN_LASER,"Laser (off)");}

8. QR code marking interface

9. Explanation of Interface Parameter Configuration & Demonstration of Marking Effect

II. Text Marking

1. Text Marking Parameter Settings Interface

This routine allows us to mark production dates on product packaging, metal components, and rigid plastic products. It can also mark commemorative messages on metal items, with a variety of font styles to choose from.

The operation process is similar to QR code marking. Connect the controller, select the corresponding laser type, and fill in the motion parameters, filling process, and marking text information (adjustments can be made based on actual marking test results). The program construction is similar, the only difference being the way the program is written for marking. QR code marking separates trajectory generation and marking execution, while text marking requires setting the parameters and determining the text content before clicking "mark" to generate three files, and then starting the task execution file.

The procedure is as follows:

// Mark void CZmc_laserDlg::OnBnClickedBtnMark(){ if(NULL == m_Handle) { MessageBox(_T("Controller not connected")); return; } UpdateData(TRUE); // Open the marking library 3 times file function int rtn = ZmotionLaser_OpenFile3(); if(CheckError(rtn,"ZmotionLaser_OpenFile3")) return; rtn = ZmotionLaser_SetOutputLimits(55); // Set the maximum number limit of the output port if(CheckError(rtn,"ZmotionLaser_OpenFile3")) return; rtn = ZmotionLaser_SetScanAxis(4,5); // Set the galvanometer axis number if(CheckError(rtn,"ZmotionLaser_SetScanAxis")) return; rtn = ZmotionLaser_SetOutput(m_nLaserIO,m_nEnableIO,m_nRedIO); // Set the on/off control if(CheckError(rtn,"ZmotionLaser_SetOutput")) return; rtn = ZmotionLaser_AoutInit(m_nAout,255); // Set the analog power setting if(CheckError(rtn,"ZmotionLaser_AoutInit")) return; rtn = ZmotionLaser_SetPowerEnable(false); // Disable dynamic power modification if(CheckError(rtn,"ZmotionLaser_SetPowerEnable")) return; rtn = ZmotionLaser_SetLightInstruct(1); if(CheckError(rtn,"ZmotionLaser_SetLightInstruct")) return; rtn = ZmotionLaser_SetLightString("MOVE_OP(8,ON)\n","MOVE_OP(8,OFF)\n"); if(CheckError(rtn,"ZmotionLaser_SetLightInstruct")) return; // Set processing parameters int ipower = (int)(m_nAoutVal*100/256); rtn = ZmotionLaser_SetVectPar(ipower, m_nPwmFreq, m_dSpeed, m_dEmpSpeed, m_nStartDelay, m_nLastDelay, m_nLastDelay, 10, m_nCorDelay,m_nLastDelay ,1); if(CheckError(rtn,"ZmotionLaser_SetVectPar")) return; // Set fill parameters rtn = ZmotionLaser_SetFillObject(m_FillPara,1); if(CheckError(rtn,"ZmotionLaser_SetFillObject")) return; // Set text font parameters CString strFont; m_ListFont.GetLBText(m_ListFont.GetCurSel(),strFont); rtn = ZmotionLaser_SetTextStyle(strFont,m_FontThickness,m_FontItalics,m_FontUnderline,m_FontDelete,m_dTextHigh,m_dTextWidth,m_dTextAngle,m_dTextTilt); if(CheckError(rtn,"ZmotionLaser_SetTextStyle")) return; //Start filling rtn = ZmotionLaser_FillStart(); if(CheckError(rtn,"ZmotionLaser_FillStart")) return; //Process text characters rtn = ZmotionLaser_Text(1,m_TextString,m_dTextXpos,m_dTextYpos,m_dTextAccuracy); if(CheckError(rtn,"ZmotionLaser_Text")) return; //End filling rtn = ZmotionLaser_FillEnd(); if(CheckError(rtn,"ZmotionLaser_FillEnd")) return; char* MoveStr = NULL; int nRow = 0; MoveStr = ZmotionLaser_GetProcessString(false); MoveStr = ZmotionLaser_GetProEndString(nRow); // Generate the file for three processing iterations rtn = ZmotionLaser_CreateFile3(".//ZscanLaser.z3p",true); if(CheckError(rtn,"ZmotionLaser_CreateFile3")) return; rtn = ZmotionLaser_CloseFile3(); if(CheckError(rtn,"ZmotionLaser_CloseFile3")) return; // Run the generated file for three iterations rtn = ZAux_Down3FileRom(m_Handle,".//ZscanLaser.z3p","Text123.z3p"); if(CheckError(rtn,"ZAux_Down3FileRom")) return; rtn = ZAux_Direct_StopTask(m_Handle,1); if(CheckError(rtn,"ZAux_Direct_StopTask")) return; rtn = ZAux_Run3FileRom(m_Handle,"Text123.z3p",1,0); // Run the file 3 times if(CheckError(rtn,"ZAux_Down3FileRom")) return;}

2. Explanation of Interface Parameter Configuration & Demonstration of Marking Effect

III. Vector Graphic Marking

1. Vector Graphic Marking Parameter Setting Interface

This routine allows us to mark various patterns, such as product LONG printing, pattern printing, and printing patterns on metal plates to make necklaces.

The operation process is similar to the previous two examples, the only difference being that here we are marking vector graphics. We need to select the saved vector graphics, set the size, position, and rotation angle, and then mark them. The added graphics can be seen in the lower right area (the QR code example also displays the graphics), as shown in the red box in the image below.

2. Vector graphics marking interface

The procedure is as follows:

·

//Display graphics void CZmc_laserDlg::OnShowGraph(){ CDC*dc = GetDlgItem(IDC_PIC_SHOW)->GetDC(); CRect rectClient; GetDlgItem(IDC_PIC_SHOW)->GetClientRect(rectClient); CBrush brush(RGB(255, 255, 255)); dc->FillRect(&rectClient, &brush); //Draw an outer frame int iwidth = rectClient.Width(); int iheight = rectClient.Height(); dc->MoveTo(0,0); dc->LineTo(iwidth-1,0); dc->LineTo(iwidth-1,iheight-1); dc->LineTo(0,iheight-1); dc->LineTo(0,0); int rtn=0; rtn = ZMotionCad3_DeleteChain((Struct_ZCad_Item *) m_pGraph->m_pVectorData); rtn = ZMotionCad3_DeleteChain((Struct_ZCad_Item *) m_pGraph->m_pImageData); m_pGraph->m_pImageData = NULL; m_pGraph->m_pVectorData = ZMotionCad3_ImportVectGraph(m_FileName, 1016,1,0.001); // Import the graph and generate the trajectory if (m_pGraph) { uint32 uiresult; // Element size float left, bottom, width, height; uiresult = ZMotionCad3_GetRange((Struct_ZCad_Item *)m_pGraph, &left, &bottom, &width, &height); float top; // Convert to display coordinates top = -(bottom + height); // Display area double WinWidth = rectClient.Width() - 8; double WinHeight = rectClient.Height() - 8; // Actual area double ObjectWidth = width; double ObjectHeight = height; double ObjectPixWidth, ObjectPixHeight; if (ObjectWidth*WinHeight <= WinWidth*ObjectHeight) { ObjectPixHeight = WinHeight; ObjectPixWidth = ObjectPixHeight *ObjectWidth/ObjectHeight; } else { ObjectPixWidth = WinWidth; ObjectPixHeight = ObjectPixWidth *ObjectHeight/ObjectWidth; } double dUnitsPerMm = ObjectPixHeight/ObjectHeight; //The number of display points per MM CPoint ZeroPoint; ZeroPoint.x = (rectClient.Width()-ObjectPixWidth)/2; ZeroPoint.y = (rectClient.Height()-ObjectPixHeight)/2; dc->SetViewportOrg(ZeroPoint.x-left*dUnitsPerMm, ZeroPoint.y-top*dUnitsPerMm); ZMotionCad3_Draw(dc->m_hDC, (Struct_ZCad_Item *) m_pGraph, 0, 1.0f/dUnitsPerMm); //Drawing}}

3. Explanation of Interface Parameter Configuration & Demonstration of Marking Effect

That concludes our presentation on the open-source laser galvanometer motion controller for positive motion technology: a C++ application that quickly calls graphics libraries.

For more exciting content, please follow the "Zheng Motion Assistant" WeChat official account. For related development environment and example code, please contact Zheng Motion Technology 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 improve China's intelligent manufacturing level together. Copyright of this article belongs to Zheng Motion Technology. Please indicate the source if you reprint it.

Read next

CATDOLL 92CM Shota Doll Q (Male Doll)

Height: 92cm Male Weight: 13kg Shoulder Width: 25cm Bust/Waist/Hip: 47/47/56cm Oral Depth: 3-5cm Vaginal Depth: N/A Ana...

Articles 2026-02-22