├── .gitignore ├── README.md ├── gcode_reference.md ├── snapmaker-artcam-configuration ├── .DS_Store ├── README.md ├── Snapmaker-2.0-CNC-Tools.tdb ├── Snapmaker_arc_cnc.con ├── image │ ├── area-clearance.png │ ├── create-new-model.png │ ├── material.png │ ├── post-processer.png │ ├── save-as.png │ ├── save.png │ ├── set-size.png │ ├── tool-list.png │ └── vector-text.png └── readme.txt ├── snapmaker-aspire-configuration ├── README.md ├── Snapmaker_2.0_tools.tool ├── Snapmaker_cnc_4axis_mm.pp └── Snapmaker_cnc_mm.pp ├── snapmaker-freecad-configuration ├── README.md ├── Snapmaker-2.0-CNC-Tools.json ├── image │ ├── body.png │ ├── c-body.png │ ├── close.png │ ├── cnc.png │ ├── contour.cnc │ ├── countor.png │ ├── i-countor.png │ ├── i-path.png │ ├── i-post.png │ ├── new-sketch.png │ ├── output.png │ ├── pad.png │ ├── part.png │ ├── path.png │ ├── polygon.png │ ├── post.png │ ├── regular.png │ ├── stepdown.png │ ├── tool.png │ └── tools.png ├── readme.txt └── snapmaker_freecad_post.py ├── snapmaker-fusion360-configuration-20180730 ├── Snapmaker 2.0 CNC Tool Library.tools ├── Snapmaker Artisan CNC tool library.tools ├── Snapmaker CNC tool library.tools ├── readme.txt ├── snapmaker-baxis.cps └── snapmaker.cps └── snapmaker-vcarve-configuration ├── README.md ├── Snapmaker 2.0 CNC Tools.vtdb └── Snapmaker_cnc_mm.pp /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SNAPMAKER CNC 2 | 3 | ## Background 4 | 5 | 1. Basic workflow explaination. 6 | * https://support.snapmaker.com/hc/en-us/articles/360041252474-CNC-Carving 7 | 2. Basic workflow explaination in video. 8 | * https://www.youtube.com/watch?v=OgUdDoCx5iw&feature=youtu.be 9 | 10 | 11 | 12 | **Snapmaker Luban / Snapmakerjs(Old version)** 13 | 14 | If you want to do some simple job. You can use any svg editor (Like Inkscape or Adobe Illustrator) to do the design, then export .svg file. Using Snapmaker Luban to generate the gcode. 15 | 16 | Snapmaker Luban also supports relief for small landscape. 17 | 18 | 19 | Generate gcode using Luban 20 | 21 | * https://support.snapmaker.com/hc/en-us/articles/360041252474-CNC-Carving 22 | * Using svg editor like Inkscape or other software to export .svg file, then import into Luban. 23 | * Notice that, Luban has supported .dxf file. 24 | 25 | 26 | **Fusion360** 27 | 28 | We can do more serious tasks by using Autodesk Fusion360. 29 | 30 | Generate gcode using Fusion 360 31 | 32 | * https://support.snapmaker.com/hc/en-us/articles/360060624834-CNC-Cutting-with-Files-Exported-from-Fusion-360 33 | * https://www.youtube.com/watch?v=h3vMEiMTlio&t=166s 34 | * We have developed post processor script for Fusion 360 to help more advanced use case. 35 | * The reason we favor Fusion 360 is that it has free license for education. 36 | 37 | 38 | 39 | 40 | ## Support software status overview 41 | 42 | | Software | Status | link | versions | 43 | | ------------- |:-------------:| -----:|-----:| 44 | | Snapmaker Luban| Stable | | | 45 | | Fusion 360 | Stable | [snapmaker-fusion360-configuration-20180730](https://github.com/Snapmaker/snapmaker_cnc_post_process/tree/master/snapmaker-fusion360-configuration-20180730)|v2.0.9937 | 46 | | FreeCAD | Testing | [snapmaker-freecad-configuration](https://github.com/Snapmaker/snapmaker_cnc_post_process/tree/master/snapmaker-freecad-configuration) |v0.18| 47 | | ArtCAM|Testing|[snapmaker-artcam-configuration](https://github.com/Snapmaker/snapmaker_cnc_post_process/tree/master/snapmaker-artcam-configuration)|v2008| 48 | | Mastercam | TODO | || 49 | | Aspire |Testing |[snapmaker-aspire-configuration](https://github.com/Snapmaker/snapmaker_cnc_post_process/tree/master/snapmaker-aspire-configuration)|v9.514| 50 | | Vcarve |Testing |[snapmaker-vcarve-configuration](https://github.com/Snapmaker/snapmaker_cnc_post_process/tree/master/snapmaker-vcarve-configuration)|| 51 | 52 | 53 | 54 | ## Gcode 55 | 56 | Similar to Fusion 360, it needs some development effort to create post process script for different CAD platform. These scripts are responsible for converting 3D trajectory (representation) into concrete Gcode dialects. There are Gcode dialect differences between firmwares (Vendors). 57 | 58 | We can refer to [Gcode Reference](./gcode_reference.md) to build post for specific software. 59 | 60 | 61 | ## Summary 62 | 63 | The documentation is still under active development. 64 | 65 | Leave a message in this [thread](https://forum.snapmaker.com/t/post-processor-required-for-cnc/4980/12) about what CAM software you are using. If you want official or community support, this is important. 66 | 67 | -------------------------------------------------------------------------------- /gcode_reference.md: -------------------------------------------------------------------------------- 1 | # Gcode Reference(Draft) 2 | 3 | This is a short Gcode Reference regarding to CNC related feature for Snapmaker 2.0 4 | 5 | 6 | ## Overview 7 | 8 | The Gcode that have been used in Snapmaker 2.0 is quite limited. 9 | 10 | Share your ideas to improve Snapmaker 2.0 in [forrm](https://forum.snapmaker.com/c/snapmaker-20/37) 11 | 12 | 13 | ## Reference 14 | 15 | ### G0 / G1 16 | 17 | The `G0` and `G1` commands add a linear move to the queue to be performed after all previous moves are completed. These commands yield control back to the command parser as soon as the move is queued, but they may delay the command parser while awaiting a slot in the queue. 18 | 19 | A linear move traces a straight line from one point to another, ensuring that the specified axes will arrive simultaneously at the given coordinates (by linear interpolation). The speed may change over time following an acceleration curve, according to the acceleration and jerk settings of the given axes. 20 | 21 | A command like `G1 F1000` sets the feedrate for all subsequent moves. 22 | 23 | *The arc move(G2/G3) should be convert to linear move by tolerance. refer to [Fusion 360 Post Example](./assets/snapmaker-fusion360-configuration-20180730/snapmaker.cps)* 24 | 25 | 26 | ### M3 27 | 28 | Usage: 29 | 30 | ``` 31 | M3 [P] | 50< percentage <=100 32 | M3 P100 indicate that spindle work at 12000 RPM 33 | ``` 34 | 35 | Wait for moves to complete, then set the spindle speed 36 | 37 | 38 | ### M5 39 | 40 | Wait for moves to complete, then turn off the spindle. 41 | 42 | 43 | ### Sample Gcode 44 | 45 | 1. [Snapmaker Text Cut by Snapmaker Luban](./assets/luban_3.1.0_snapamker_text.cnc) 46 | 2. Fusion 360 Sample Gcode TBD -------------------------------------------------------------------------------- /snapmaker-artcam-configuration/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-artcam-configuration/.DS_Store -------------------------------------------------------------------------------- /snapmaker-artcam-configuration/README.md: -------------------------------------------------------------------------------- 1 | Generate G-code Using ArtCAM 2 | =============== 3 | This instruction teaches you how to carve an “S” on a 2mm carbon fiber sheet. Once you are familiar with all the settings, you can design your own invention. 4 | 5 | ## Getting Started 6 | 7 | This software is available for Windows and Mac. Since the configuration for both systems is similar, here in this instruction, we take steps in Windows as an example. 8 | 9 | ### Step 1. Get the post-processer configuration Ready 10 | 11 | 1. Download the post-processing configuration on our https://github.com/Snapmaker/snapmaker_cnc_post_process 12 | 2. Copy [Snapmaker_arc_cnc.con](./Snapmaker_arc_cnc.con) to the C:\Program Files (x86)\${ArtCAM}\postp. Restart the ArtCAM. 13 | ![alt path](./image/post-processer.png) 14 | 15 | ### Step 2. Design the Model You Want to Carve 16 | 17 | 1. Create a new model with a width and height of 100mm. 18 | ![alt path](./image/create-new-model.png) 19 | 2. Select the assistant in the left toolbar and create a vector text with "s". 20 | ![alt path](./image/vector-text.png) 21 | 3. Set the size. The (0, 0) coordinate is in the lower left corner.Click Done. 22 | ![alt path](./image/set-size.png) 23 | 24 | ### Step 3. Generate Tool-Path Strategies 25 | 26 | 1. Select the Toolpaths in the left toolbar and Click **the 2D Toolpaths > Area Clearance**. 27 | ![alt path](./image/area-clearance.png) 28 | 1. Add Tools List. Import [Snapmaker-2.0-CNC-Tools.tdb](./Snapmaker-2.0-CNC-Tools.tdb) to ArtCAM and select **Snapmaker Tools > End Mill 1.5mm**. 29 | ![alt path](./image/tool-list.png) 30 | 2. Set the material to 2.0 mm. 31 | ![alt path](./image/material.png) 32 | 3. Select the model and Calculate now. 33 | 4. Close. 34 | 2. Copy [Snapmaker_arc_cnc.con](./Snapmaker_arc_cnc.con) to the C:\Program Files (x86)\${ArtCAM}\postp 35 | 1. Select **Toolpaths > Save Toolpath As**. 36 | ![alt path](./image/save-as.png) 37 | 2. Select the **Snapmaker CNC (mm)** as the Machine format output file. 38 | ![alt path](./image/save.png) 39 | 3. Change the G-code name as you need, and save the G-code. 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /snapmaker-artcam-configuration/Snapmaker-2.0-CNC-Tools.tdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-artcam-configuration/Snapmaker-2.0-CNC-Tools.tdb -------------------------------------------------------------------------------- /snapmaker-artcam-configuration/Snapmaker_arc_cnc.con: -------------------------------------------------------------------------------- 1 | ; 2 | ; G - Code configuration file - with Arc Support 3 | ; 4 | ; History 5 | ; 6 | ; Who When What 7 | ; === ======== ======================================== 8 | ; TM 13/05/99 Written 9 | ; BEM 20/05/99 Removed line numbers 10 | ; BEM 21/03/00 Added DESCRIPTION and FILE_EXTENSION fields 11 | ; BEM 19/06/01 Added support for circular arc output 12 | ; move to home pos at end instead of 0,0,ZH 13 | ; bem 07/09/01 Added G17 to define plane for circular arcs 14 | ; 15 | DESCRIPTION = "Snapmaker CNC (mm) (*.cnc)" 16 | ; 17 | FILE_EXTENSION = "cnc" 18 | ; 19 | UNITS = MM 20 | ; 21 | ; Cariage return - line feed at end of each line 22 | ; 23 | END_OF_LINE = "[13][10]" 24 | ; 25 | ; Block numbering 26 | ; 27 | LINE_NUM_START = 0 28 | LINE_NUM_INCREMENT = 10 29 | LINE_NUM_MAXIMUM = 999999 30 | ; 31 | ; Set up default formating for variables 32 | ; 33 | ; Line numbering 34 | FORMAT = [N|@|N|1.0] 35 | ; Spindle Speed 36 | FORMAT = [S|@|S|1.0] 37 | ; Feed Rate 38 | FORMAT = [F|#|F|1.1] 39 | ; Tool moves in x,y and z 40 | FORMAT = [X|#|X|1.3] 41 | FORMAT = [Y|#|Y|1.3] 42 | FORMAT = [Z|#|Z|1.3] 43 | ; Arc Centre Cordinates 44 | FORMAT = [I|@|I|1.3] 45 | FORMAT = [J|@|J|1.3] 46 | ; Home tool positions 47 | FORMAT = [XH|@|X|1.3] 48 | FORMAT = [YH|@|Y|1.3] 49 | FORMAT = [ZH|@|Z|1.3] 50 | ; 51 | ; Set up program header 52 | ; 53 | START = "G0 Z10.00 F120" 54 | START = "G0 Z0.50 F120" 55 | START = "M3 P100" 56 | ; 57 | ; Program moves 58 | ; 59 | RAPID_RATE_MOVE = "G0 [X] [Y] [Z]" 60 | ; 61 | FIRST_FEED_RATE_MOVE = "G1 [X] [Y] [Z] [F]" 62 | FEED_RATE_MOVE = "G1 [X] [Y] [Z]" 63 | ; 64 | FIRST_CW_ARC_MOVE = "G2 [X] [Y] [I] [J] [F]" 65 | CW_ARC_MOVE = "G2 [X] [Y] [I] [J]" 66 | ; 67 | FIRST_CCW_ARC_MOVE = "G3 [X] [Y] [I] [J] [F]" 68 | CCW_ARC_MOVE = "G3 [X] [Y] [I] [J]" 69 | ; 70 | ; End of file 71 | ; 72 | END = "M5" 73 | -------------------------------------------------------------------------------- /snapmaker-artcam-configuration/image/area-clearance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-artcam-configuration/image/area-clearance.png -------------------------------------------------------------------------------- /snapmaker-artcam-configuration/image/create-new-model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-artcam-configuration/image/create-new-model.png -------------------------------------------------------------------------------- /snapmaker-artcam-configuration/image/material.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-artcam-configuration/image/material.png -------------------------------------------------------------------------------- /snapmaker-artcam-configuration/image/post-processer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-artcam-configuration/image/post-processer.png -------------------------------------------------------------------------------- /snapmaker-artcam-configuration/image/save-as.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-artcam-configuration/image/save-as.png -------------------------------------------------------------------------------- /snapmaker-artcam-configuration/image/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-artcam-configuration/image/save.png -------------------------------------------------------------------------------- /snapmaker-artcam-configuration/image/set-size.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-artcam-configuration/image/set-size.png -------------------------------------------------------------------------------- /snapmaker-artcam-configuration/image/tool-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-artcam-configuration/image/tool-list.png -------------------------------------------------------------------------------- /snapmaker-artcam-configuration/image/vector-text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-artcam-configuration/image/vector-text.png -------------------------------------------------------------------------------- /snapmaker-artcam-configuration/readme.txt: -------------------------------------------------------------------------------- 1 | Copy Snapmaker_arc_cnc.con to C:\Program Files (x86)\ArtCAM\postp. 2 | 3 | -------------------------------------------------------------------------------- /snapmaker-aspire-configuration/README.md: -------------------------------------------------------------------------------- 1 | This is snapmaker's post-processing configuration file for aspire software. 2 | Including tool configuration files and post-processing files. 3 | 4 | **The official website is** 5 | - https://www.vectric.com/products/aspire 6 | 7 | **Aspire software post-processing documents** 8 | - https://docs.vectric.com/docs/V10.0/Aspire/ENU/Help/form/post-processor-editing 9 | 10 | **How to add the snapmaker post-processing to the aspire software?** 11 | 1. Copy the Snapmaker_cnc_mm.pp to the PostP path; 12 | The PostP folder can be reached from within the application, by clicking “File > Open Application Data Folder” from the main menu of the application. 13 | 14 | 2. By clicking “Toolpaths > install PostProcessor...” from the main menu of the application. 15 | 16 | **How to add the Snapmaker 2.0 CNC Tools to the aspire software?** 17 | - By clicking "Toolpaths > Tool Database" from the main menu of the application to open Tool Database,then clicking the import a tool database. 18 | 19 | #### Warn !!! 20 | 1. If you are using the tool provided by Snapmaker 2.0 but not the Snapmaker 2.0 CNC Tools.vtdb, then the "Feed rate" is preferably less than 600 mm/min or 22 inches/min, and the "Pass Depth" is preferably less than 0.4mm. 21 | 22 | 23 | -------------------------------------------------------------------------------- /snapmaker-aspire-configuration/Snapmaker_2.0_tools.tool: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-aspire-configuration/Snapmaker_2.0_tools.tool -------------------------------------------------------------------------------- /snapmaker-aspire-configuration/Snapmaker_cnc_4axis_mm.pp: -------------------------------------------------------------------------------- 1 | +================================================ 2 | + 3 | + Vectric machine output configuration file 4 | + 5 | +================================================ 6 | + 7 | + History 8 | + 9 | + Who When What 10 | + ======== ========== =========================== 11 | + Tony M 13/09/2010 Written 12 | + Mark 16/07/2015 Added New Segment section. 13 | + ================================================ 14 | 15 | POST_NAME = "Snapmaker CNC 4 Axis (mm) (*.cnc)" 16 | 17 | FILE_EXTENSION = "cnc" 18 | 19 | UNITS = "MM" 20 | 21 | ROTARY_WRAP_X = "B" 22 | 23 | +------------------------------------------------ 24 | + Line terminating characters 25 | +------------------------------------------------ 26 | 27 | LINE_ENDING = "[13][10]" 28 | 29 | +------------------------------------------------ 30 | + Block numbering 31 | +------------------------------------------------ 32 | 33 | LINE_NUMBER_START = 0 34 | LINE_NUMBER_INCREMENT = 10 35 | LINE_NUMBER_MAXIMUM = 9999999 36 | 37 | +================================================ 38 | + 39 | + Formating for variables 40 | + 41 | +================================================ 42 | 43 | VAR LINE_NUMBER = [N|A| N|1.0] 44 | VAR SPINDLE_SPEED = [S|A| S|1.0] 45 | VAR FEED_RATE = [F|C| F|1.1] 46 | VAR X_POSITION = [X|C| X|1.3] 47 | VAR Y_POSITION = [Y|C| Y|1.3] 48 | VAR Z_POSITION = [Z|C| Z|1.3] 49 | VAR ARC_CENTRE_I_ABS_POSITION = [IA|A| I|1.3] 50 | VAR ARC_CENTRE_J_ABS_POSITION = [JA|A| J|1.3] 51 | VAR X_HOME_POSITION = [XH|A| X|1.3] 52 | VAR Y_HOME_POSITION = [YH|A| Y|1.3] 53 | VAR Z_HOME_POSITION = [ZH|A| Z|1.3] 54 | 55 | +================================================ 56 | + 57 | + Block definitions for toolpath output 58 | + 59 | +================================================ 60 | 61 | +--------------------------------------------------- 62 | + Commands output at the start of the file 63 | +--------------------------------------------------- 64 | 65 | begin HEADER 66 | 67 | "G90" 68 | "G0 Z10.00 F600" 69 | "G21" 70 | "M3 [S]" 71 | 72 | +--------------------------------------------------- 73 | + Commands output for rapid moves 74 | +--------------------------------------------------- 75 | 76 | begin RAPID_MOVE 77 | 78 | "G0 [X] [Y] [Z]" 79 | 80 | 81 | +--------------------------------------------------- 82 | + Commands output for the first feed rate move 83 | +--------------------------------------------------- 84 | 85 | begin FIRST_FEED_MOVE 86 | 87 | "G1 [X] [Y] [Z] [F]" 88 | 89 | 90 | +--------------------------------------------------- 91 | + Commands output for feed rate moves 92 | +--------------------------------------------------- 93 | 94 | begin FEED_MOVE 95 | 96 | "G1 [X] [Y] [Z]" 97 | 98 | 99 | +--------------------------------------------------- 100 | + Commands output for the first clockwise arc move 101 | +--------------------------------------------------- 102 | 103 | begin FIRST_CW_ARC_MOVE 104 | 105 | "G2 [X] [Y] [IA] [JA] [F]" 106 | 107 | 108 | +--------------------------------------------------- 109 | + Commands output for clockwise arc move 110 | +--------------------------------------------------- 111 | 112 | begin CW_ARC_MOVE 113 | 114 | "G2 [X] [Y] [IA] [JA]" 115 | 116 | 117 | +--------------------------------------------------- 118 | + Commands output for the first counterclockwise arc move 119 | +--------------------------------------------------- 120 | 121 | begin FIRST_CCW_ARC_MOVE 122 | 123 | "G3 [X] [Y] [IA] [JA] [F]" 124 | 125 | 126 | +--------------------------------------------------- 127 | + Commands output for counterclockwise arc move 128 | +--------------------------------------------------- 129 | 130 | begin CCW_ARC_MOVE 131 | 132 | "G3 [X] [Y] [IA] [JA]" 133 | 134 | 135 | +--------------------------------------------------- 136 | + Commands output at the end of the file 137 | +--------------------------------------------------- 138 | 139 | begin FOOTER 140 | 141 | "M5" 142 | 143 | -------------------------------------------------------------------------------- /snapmaker-aspire-configuration/Snapmaker_cnc_mm.pp: -------------------------------------------------------------------------------- 1 | +================================================ 2 | + 3 | + Vectric machine output configuration file 4 | + 5 | +================================================ 6 | + 7 | + History 8 | + 9 | + Who When What 10 | + ======== ========== =========================== 11 | + Tony M 13/09/2010 Written 12 | + Mark 16/07/2015 Added New Segment section. 13 | + ================================================ 14 | 15 | POST_NAME = "Snapmaker CNC (mm) (*.cnc)" 16 | 17 | FILE_EXTENSION = "cnc" 18 | 19 | UNITS = "MM" 20 | 21 | +------------------------------------------------ 22 | + Line terminating characters 23 | +------------------------------------------------ 24 | 25 | LINE_ENDING = "[13][10]" 26 | 27 | +------------------------------------------------ 28 | + Block numbering 29 | +------------------------------------------------ 30 | 31 | LINE_NUMBER_START = 0 32 | LINE_NUMBER_INCREMENT = 10 33 | LINE_NUMBER_MAXIMUM = 9999999 34 | 35 | +================================================ 36 | + 37 | + Formating for variables 38 | + 39 | +================================================ 40 | 41 | VAR LINE_NUMBER = [N|A| N|1.0] 42 | VAR SPINDLE_SPEED = [S|A| S|1.0] 43 | VAR FEED_RATE = [F|C| F|1.1] 44 | VAR X_POSITION = [X|C| X|1.3] 45 | VAR Y_POSITION = [Y|C| Y|1.3] 46 | VAR Z_POSITION = [Z|C| Z|1.3] 47 | VAR ARC_CENTRE_I_INC_POSITION = [I|A| I|1.3] 48 | VAR ARC_CENTRE_J_INC_POSITION = [J|A| J|1.3] 49 | VAR X_HOME_POSITION = [XH|A| X|1.3] 50 | VAR Y_HOME_POSITION = [YH|A| Y|1.3] 51 | VAR Z_HOME_POSITION = [ZH|A| Z|1.3] 52 | 53 | +================================================ 54 | + 55 | + Block definitions for toolpath output 56 | + 57 | +================================================ 58 | 59 | +--------------------------------------------------- 60 | + Commands output at the start of the file 61 | +--------------------------------------------------- 62 | 63 | begin HEADER 64 | 65 | "G90" 66 | "G0 Z10.00 F600" 67 | "G21" 68 | "M3 [S]" 69 | 70 | +--------------------------------------------------- 71 | + Commands output for rapid moves 72 | +--------------------------------------------------- 73 | 74 | begin RAPID_MOVE 75 | 76 | "G0 [X] [Y] [Z]" 77 | 78 | 79 | +--------------------------------------------------- 80 | + Commands output for the first feed rate move 81 | +--------------------------------------------------- 82 | 83 | begin FIRST_FEED_MOVE 84 | 85 | "G1 [X] [Y] [Z] [F]" 86 | 87 | 88 | +--------------------------------------------------- 89 | + Commands output for feed rate moves 90 | +--------------------------------------------------- 91 | 92 | begin FEED_MOVE 93 | 94 | "G1 [X] [Y] [Z]" 95 | 96 | 97 | +--------------------------------------------------- 98 | + Commands output for the first clockwise arc move 99 | +--------------------------------------------------- 100 | 101 | begin FIRST_CW_ARC_MOVE 102 | 103 | "G2 [X] [Y] [I] [J] [F]" 104 | 105 | 106 | +--------------------------------------------------- 107 | + Commands output for clockwise arc move 108 | +--------------------------------------------------- 109 | 110 | begin CW_ARC_MOVE 111 | 112 | "G2 [X] [Y] [I] [J]" 113 | 114 | 115 | +--------------------------------------------------- 116 | + Commands output for the first counterclockwise arc move 117 | +--------------------------------------------------- 118 | 119 | begin FIRST_CCW_ARC_MOVE 120 | 121 | "G3 [X] [Y] [I] [J] [F]" 122 | 123 | 124 | +--------------------------------------------------- 125 | + Commands output for counterclockwise arc move 126 | +--------------------------------------------------- 127 | 128 | begin CCW_ARC_MOVE 129 | 130 | "G3 [X] [Y] [I] [J]" 131 | 132 | 133 | +--------------------------------------------------- 134 | + Commands output at the end of the file 135 | +--------------------------------------------------- 136 | 137 | begin FOOTER 138 | 139 | "M5" 140 | 141 | -------------------------------------------------------------------------------- /snapmaker-freecad-configuration/README.md: -------------------------------------------------------------------------------- 1 | Generate G-code Using FreeCAD 2 | =============== 3 | This instruction teaches you how to carve hexagons on a 2mm carbon fiber sheet. Once you are familiar with all the settings, you can design your own invention. For more details, please visit https://wiki.freecadweb.org/User_hub 4 | 5 | ## Getting Started 6 | 7 | This software is available for Windows and Mac. Since the configuration for both systems is similar, here in this instruction, we take steps in Windows as an example. 8 | 9 | ### Step 1. Get the Software Ready 10 | 11 | Install the software and save the configuration files according to the following steps: 12 | 13 | 1. Download and Install FreeCAD at https://www.freecadweb.org/. 14 | 2. Select the ![alt path](./image/path.png)**Path workbenches** and click ![alt tool](./image/tool.png)**tool manager** to import the [Snapmaker-2.0-CNC-Tools.json](./Snapmaker-2.0-CNC-Tools.json). 15 | 3. Copy [snapmaker_freecad_post.py](./snapmaker_freecad_post.py) to the C:\Program Files\\${FreeCAD Path}\Mod\Path\PathScripts\post to add the post processor of the Snapmaker to FreeCAD. 16 | - More FreeCAD path post details on the https://wiki.freecadweb.org/Path_Post 17 | 18 | ### Step 2. Design the Model You Want to Carve 19 | 20 | 1. In FreeCAD, select ![alt Part Design](./image/part.png)**Part Design** as the Workbenches. 21 | 2. Create a new sketch and select the XY_Plane(Base plane). 22 | ![alt new sketch](./image/new-sketch.png) 23 | 3. First set the navigation style to CAD, and click ![alt new sketch](./image/polygon.png) to create a regular polygon.When you finish editing, click ![alt new sketch](./image/close.png) to close the editing of the sketch. 24 | ![alt new sketch](./image/regular.png) 25 | 4. Click ![alt new sketch](./image/pad.png) and enter 2.00 mm in the Length field. Click OK. 26 | ![alt new sketch](./image/body.png) 27 | 28 | ### Step 3. Generate Tool-Path Strategies 29 | 1. Change the Workbenches to ![alt path](./image/path.png)**Path**. 30 | 2. Click ![alt path](./image/i-path.png),Selected body and Click OK. 31 | ![alt path](./image/c-body.png) 32 | - Select **Output** and set Processor is snapmaker_freecad. 33 | ![alt path](./image/output.png) 34 | - Select **Tools** and click Add.Selected the **flat end mill (3.175 mm)** and click **Create Tool Controllers(s)** to add the tools. 35 | ![alt path](./image/tools.png) 36 | - Click OK. 37 | 3. Click ![alt path](./image/i-countor.png) to create a contour and set the flat end mill tool. 38 | - Set the Step Down to 0.2mm 39 | ![alt path](./image/countor.png) 40 | - Click OK. 41 | ### Step 4. Generate G-code 42 | 1. Selected the **Job -> Operations -> Contour** and click ![alt path](./image/i-post.png) to post process. 43 | ![alt path](./image/post.png) 44 | 2. Change the G-code name as you need, and save the G-code. 45 | ![alt path](./image/cnc.png) 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /snapmaker-freecad-configuration/Snapmaker-2.0-CNC-Tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "Tools": { 3 | "1": { 4 | "cornerRadius": 0.0, 5 | "cuttingEdgeAngle": 180.0, 6 | "cuttingEdgeHeight": 0.0, 7 | "diameter": 3.17, 8 | "flatRadius": 0.0, 9 | "lengthOffset": 0.0, 10 | "material": "HighSpeedSteel", 11 | "name": "flat end mill (3.175 mm)", 12 | "tooltype": "EndMill", 13 | "version": 1 14 | }, 15 | "2": { 16 | "cornerRadius": 0.0, 17 | "cuttingEdgeAngle": 180.0, 18 | "cuttingEdgeHeight": 0.0, 19 | "diameter": 1.5, 20 | "flatRadius": 0.0, 21 | "lengthOffset": 0.0, 22 | "material": "HighSpeedSteel", 23 | "name": "flat end mill (1.5 mm)", 24 | "tooltype": "EndMill", 25 | "version": 1 26 | }, 27 | "3": { 28 | "cornerRadius": 0.0, 29 | "cuttingEdgeAngle": 30.0, 30 | "cuttingEdgeHeight": 0.0, 31 | "diameter": 3.17, 32 | "flatRadius": 0.0, 33 | "lengthOffset": 0.0, 34 | "material": "HighSpeedSteel", 35 | "name": "spot drill (3.175 V-Bit)", 36 | "tooltype": "Drill", 37 | "version": 1 38 | } 39 | }, 40 | "Version": 1 41 | } -------------------------------------------------------------------------------- /snapmaker-freecad-configuration/image/body.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-freecad-configuration/image/body.png -------------------------------------------------------------------------------- /snapmaker-freecad-configuration/image/c-body.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-freecad-configuration/image/c-body.png -------------------------------------------------------------------------------- /snapmaker-freecad-configuration/image/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-freecad-configuration/image/close.png -------------------------------------------------------------------------------- /snapmaker-freecad-configuration/image/cnc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-freecad-configuration/image/cnc.png -------------------------------------------------------------------------------- /snapmaker-freecad-configuration/image/contour.cnc: -------------------------------------------------------------------------------- 1 | ;Exported by Snapmaker 2 | ;Post Processor: snapmaker_freecad_post 3 | ;Output Time:2020-06-19 18:24:41.836379 4 | 5 | G0 Z10.00 F120 6 | G0 Z0.50 F120 7 | G21 8 | M3 S0 9 | ;finish operation: T1: flat end mill (3.175 mm) 10 | G0 Z8.000 11 | G0 X7.611 Y8.127 12 | G0 Z6.000 13 | G1 X7.611 Y8.127 Z2.800 14 | G1 X11.834 Y0.746 Z2.800 15 | G2 X11.828 Y-0.839 Z2.800 I-1.376 J-0.787 16 | G1 X6.563 Y-9.876 Z2.800 17 | G2 X5.187 Y-10.663 Z2.800 I-1.370 J0.798 18 | G1 X-5.271 Y-10.622 Z2.800 19 | G2 X-6.641 Y-9.824 Z2.800 I0.006 J1.585 20 | G1 X-11.834 Y-0.746 Z2.800 21 | G2 X-11.828 Y0.839 Z2.800 I1.376 J0.787 22 | G1 X-6.563 Y9.876 Z2.800 23 | G2 X-5.187 Y10.663 Z2.800 I1.370 J-0.798 24 | G1 X5.271 Y10.622 Z2.800 25 | G2 X6.641 Y9.824 Z2.800 I-0.006 J-1.585 26 | G1 X7.611 Y8.127 Z2.800 27 | G1 X7.611 Y8.127 Z2.600 28 | G1 X11.834 Y0.746 Z2.600 29 | G2 X11.828 Y-0.839 Z2.600 I-1.376 J-0.787 30 | G1 X6.563 Y-9.876 Z2.600 31 | G2 X5.187 Y-10.663 Z2.600 I-1.370 J0.798 32 | G1 X-5.271 Y-10.622 Z2.600 33 | G2 X-6.641 Y-9.824 Z2.600 I0.006 J1.585 34 | G1 X-11.834 Y-0.746 Z2.600 35 | G2 X-11.828 Y0.839 Z2.600 I1.376 J0.787 36 | G1 X-6.563 Y9.876 Z2.600 37 | G2 X-5.187 Y10.663 Z2.600 I1.370 J-0.798 38 | G1 X5.271 Y10.622 Z2.600 39 | G2 X6.641 Y9.824 Z2.600 I-0.006 J-1.585 40 | G1 X7.611 Y8.127 Z2.600 41 | G1 X7.611 Y8.127 Z2.400 42 | G1 X11.834 Y0.746 Z2.400 43 | G2 X11.828 Y-0.839 Z2.400 I-1.376 J-0.787 44 | G1 X6.563 Y-9.876 Z2.400 45 | G2 X5.187 Y-10.663 Z2.400 I-1.370 J0.798 46 | G1 X-5.271 Y-10.622 Z2.400 47 | G2 X-6.641 Y-9.824 Z2.400 I0.006 J1.585 48 | G1 X-11.834 Y-0.746 Z2.400 49 | G2 X-11.828 Y0.839 Z2.400 I1.376 J0.787 50 | G1 X-6.563 Y9.876 Z2.400 51 | G2 X-5.187 Y10.663 Z2.400 I1.370 J-0.798 52 | G1 X5.271 Y10.622 Z2.400 53 | G2 X6.641 Y9.824 Z2.400 I-0.006 J-1.585 54 | G1 X7.611 Y8.127 Z2.400 55 | G1 X7.611 Y8.127 Z2.200 56 | G1 X11.834 Y0.746 Z2.200 57 | G2 X11.828 Y-0.839 Z2.200 I-1.376 J-0.787 58 | G1 X6.563 Y-9.876 Z2.200 59 | G2 X5.187 Y-10.663 Z2.200 I-1.370 J0.798 60 | G1 X-5.271 Y-10.622 Z2.200 61 | G2 X-6.641 Y-9.824 Z2.200 I0.006 J1.585 62 | G1 X-11.834 Y-0.746 Z2.200 63 | G2 X-11.828 Y0.839 Z2.200 I1.376 J0.787 64 | G1 X-6.563 Y9.876 Z2.200 65 | G2 X-5.187 Y10.663 Z2.200 I1.370 J-0.798 66 | G1 X5.271 Y10.622 Z2.200 67 | G2 X6.641 Y9.824 Z2.200 I-0.006 J-1.585 68 | G1 X7.611 Y8.127 Z2.200 69 | G1 X7.611 Y8.127 Z2.000 70 | G1 X11.834 Y0.746 Z2.000 71 | G2 X11.828 Y-0.839 Z2.000 I-1.376 J-0.787 72 | G1 X6.563 Y-9.876 Z2.000 73 | G2 X5.187 Y-10.663 Z2.000 I-1.370 J0.798 74 | G1 X-5.271 Y-10.622 Z2.000 75 | G2 X-6.641 Y-9.824 Z2.000 I0.006 J1.585 76 | G1 X-11.834 Y-0.746 Z2.000 77 | G2 X-11.828 Y0.839 Z2.000 I1.376 J0.787 78 | G1 X-6.563 Y9.876 Z2.000 79 | G2 X-5.187 Y10.663 Z2.000 I1.370 J-0.798 80 | G1 X5.271 Y10.622 Z2.000 81 | G2 X6.641 Y9.824 Z2.000 I-0.006 J-1.585 82 | G1 X7.611 Y8.127 Z2.000 83 | G1 X7.611 Y8.127 Z1.800 84 | G1 X11.834 Y0.746 Z1.800 85 | G2 X11.828 Y-0.839 Z1.800 I-1.376 J-0.787 86 | G1 X6.563 Y-9.876 Z1.800 87 | G2 X5.187 Y-10.663 Z1.800 I-1.370 J0.798 88 | G1 X-5.271 Y-10.622 Z1.800 89 | G2 X-6.641 Y-9.824 Z1.800 I0.006 J1.585 90 | G1 X-11.834 Y-0.746 Z1.800 91 | G2 X-11.828 Y0.839 Z1.800 I1.376 J0.787 92 | G1 X-6.563 Y9.876 Z1.800 93 | G2 X-5.187 Y10.663 Z1.800 I1.370 J-0.798 94 | G1 X5.271 Y10.622 Z1.800 95 | G2 X6.641 Y9.824 Z1.800 I-0.006 J-1.585 96 | G1 X7.611 Y8.127 Z1.800 97 | G1 X7.611 Y8.127 Z1.600 98 | G1 X11.834 Y0.746 Z1.600 99 | G2 X11.828 Y-0.839 Z1.600 I-1.376 J-0.787 100 | G1 X6.563 Y-9.876 Z1.600 101 | G2 X5.187 Y-10.663 Z1.600 I-1.370 J0.798 102 | G1 X-5.271 Y-10.622 Z1.600 103 | G2 X-6.641 Y-9.824 Z1.600 I0.006 J1.585 104 | G1 X-11.834 Y-0.746 Z1.600 105 | G2 X-11.828 Y0.839 Z1.600 I1.376 J0.787 106 | G1 X-6.563 Y9.876 Z1.600 107 | G2 X-5.187 Y10.663 Z1.600 I1.370 J-0.798 108 | G1 X5.271 Y10.622 Z1.600 109 | G2 X6.641 Y9.824 Z1.600 I-0.006 J-1.585 110 | G1 X7.611 Y8.127 Z1.600 111 | G1 X7.611 Y8.127 Z1.400 112 | G1 X11.834 Y0.746 Z1.400 113 | G2 X11.828 Y-0.839 Z1.400 I-1.376 J-0.787 114 | G1 X6.563 Y-9.876 Z1.400 115 | G2 X5.187 Y-10.663 Z1.400 I-1.370 J0.798 116 | G1 X-5.271 Y-10.622 Z1.400 117 | G2 X-6.641 Y-9.824 Z1.400 I0.006 J1.585 118 | G1 X-11.834 Y-0.746 Z1.400 119 | G2 X-11.828 Y0.839 Z1.400 I1.376 J0.787 120 | G1 X-6.563 Y9.876 Z1.400 121 | G2 X-5.187 Y10.663 Z1.400 I1.370 J-0.798 122 | G1 X5.271 Y10.622 Z1.400 123 | G2 X6.641 Y9.824 Z1.400 I-0.006 J-1.585 124 | G1 X7.611 Y8.127 Z1.400 125 | G1 X7.611 Y8.127 Z1.200 126 | G1 X11.834 Y0.746 Z1.200 127 | G2 X11.828 Y-0.839 Z1.200 I-1.376 J-0.787 128 | G1 X6.563 Y-9.876 Z1.200 129 | G2 X5.187 Y-10.663 Z1.200 I-1.370 J0.798 130 | G1 X-5.271 Y-10.622 Z1.200 131 | G2 X-6.641 Y-9.824 Z1.200 I0.006 J1.585 132 | G1 X-11.834 Y-0.746 Z1.200 133 | G2 X-11.828 Y0.839 Z1.200 I1.376 J0.787 134 | G1 X-6.563 Y9.876 Z1.200 135 | G2 X-5.187 Y10.663 Z1.200 I1.370 J-0.798 136 | G1 X5.271 Y10.622 Z1.200 137 | G2 X6.641 Y9.824 Z1.200 I-0.006 J-1.585 138 | G1 X7.611 Y8.127 Z1.200 139 | G1 X7.611 Y8.127 Z1.000 140 | G1 X11.834 Y0.746 Z1.000 141 | G2 X11.828 Y-0.839 Z1.000 I-1.376 J-0.787 142 | G1 X6.563 Y-9.876 Z1.000 143 | G2 X5.187 Y-10.663 Z1.000 I-1.370 J0.798 144 | G1 X-5.271 Y-10.622 Z1.000 145 | G2 X-6.641 Y-9.824 Z1.000 I0.006 J1.585 146 | G1 X-11.834 Y-0.746 Z1.000 147 | G2 X-11.828 Y0.839 Z1.000 I1.376 J0.787 148 | G1 X-6.563 Y9.876 Z1.000 149 | G2 X-5.187 Y10.663 Z1.000 I1.370 J-0.798 150 | G1 X5.271 Y10.622 Z1.000 151 | G2 X6.641 Y9.824 Z1.000 I-0.006 J-1.585 152 | G1 X7.611 Y8.127 Z1.000 153 | G1 X7.611 Y8.127 Z0.800 154 | G1 X11.834 Y0.746 Z0.800 155 | G2 X11.828 Y-0.839 Z0.800 I-1.376 J-0.787 156 | G1 X6.563 Y-9.876 Z0.800 157 | G2 X5.187 Y-10.663 Z0.800 I-1.370 J0.798 158 | G1 X-5.271 Y-10.622 Z0.800 159 | G2 X-6.641 Y-9.824 Z0.800 I0.006 J1.585 160 | G1 X-11.834 Y-0.746 Z0.800 161 | G2 X-11.828 Y0.839 Z0.800 I1.376 J0.787 162 | G1 X-6.563 Y9.876 Z0.800 163 | G2 X-5.187 Y10.663 Z0.800 I1.370 J-0.798 164 | G1 X5.271 Y10.622 Z0.800 165 | G2 X6.641 Y9.824 Z0.800 I-0.006 J-1.585 166 | G1 X7.611 Y8.127 Z0.800 167 | G1 X7.611 Y8.127 Z0.600 168 | G1 X11.834 Y0.746 Z0.600 169 | G2 X11.828 Y-0.839 Z0.600 I-1.376 J-0.787 170 | G1 X6.563 Y-9.876 Z0.600 171 | G2 X5.187 Y-10.663 Z0.600 I-1.370 J0.798 172 | G1 X-5.271 Y-10.622 Z0.600 173 | G2 X-6.641 Y-9.824 Z0.600 I0.006 J1.585 174 | G1 X-11.834 Y-0.746 Z0.600 175 | G2 X-11.828 Y0.839 Z0.600 I1.376 J0.787 176 | G1 X-6.563 Y9.876 Z0.600 177 | G2 X-5.187 Y10.663 Z0.600 I1.370 J-0.798 178 | G1 X5.271 Y10.622 Z0.600 179 | G2 X6.641 Y9.824 Z0.600 I-0.006 J-1.585 180 | G1 X7.611 Y8.127 Z0.600 181 | G1 X7.611 Y8.127 Z0.400 182 | G1 X11.834 Y0.746 Z0.400 183 | G2 X11.828 Y-0.839 Z0.400 I-1.376 J-0.787 184 | G1 X6.563 Y-9.876 Z0.400 185 | G2 X5.187 Y-10.663 Z0.400 I-1.370 J0.798 186 | G1 X-5.271 Y-10.622 Z0.400 187 | G2 X-6.641 Y-9.824 Z0.400 I0.006 J1.585 188 | G1 X-11.834 Y-0.746 Z0.400 189 | G2 X-11.828 Y0.839 Z0.400 I1.376 J0.787 190 | G1 X-6.563 Y9.876 Z0.400 191 | G2 X-5.187 Y10.663 Z0.400 I1.370 J-0.798 192 | G1 X5.271 Y10.622 Z0.400 193 | G2 X6.641 Y9.824 Z0.400 I-0.006 J-1.585 194 | G1 X7.611 Y8.127 Z0.400 195 | G1 X7.611 Y8.127 Z0.200 196 | G1 X11.834 Y0.746 Z0.200 197 | G2 X11.828 Y-0.839 Z0.200 I-1.376 J-0.787 198 | G1 X6.563 Y-9.876 Z0.200 199 | G2 X5.187 Y-10.663 Z0.200 I-1.370 J0.798 200 | G1 X-5.271 Y-10.622 Z0.200 201 | G2 X-6.641 Y-9.824 Z0.200 I0.006 J1.585 202 | G1 X-11.834 Y-0.746 Z0.200 203 | G2 X-11.828 Y0.839 Z0.200 I1.376 J0.787 204 | G1 X-6.563 Y9.876 Z0.200 205 | G2 X-5.187 Y10.663 Z0.200 I1.370 J-0.798 206 | G1 X5.271 Y10.622 Z0.200 207 | G2 X6.641 Y9.824 Z0.200 I-0.006 J-1.585 208 | G1 X7.611 Y8.127 Z0.200 209 | G1 X7.611 Y8.127 Z0.000 210 | G1 X11.834 Y0.746 Z0.000 211 | G2 X11.828 Y-0.839 Z0.000 I-1.376 J-0.787 212 | G1 X6.563 Y-9.876 Z0.000 213 | G2 X5.187 Y-10.663 Z0.000 I-1.370 J0.798 214 | G1 X-5.271 Y-10.622 Z0.000 215 | G2 X-6.641 Y-9.824 Z0.000 I0.006 J1.585 216 | G1 X-11.834 Y-0.746 Z0.000 217 | G2 X-11.828 Y0.839 Z0.000 I1.376 J0.787 218 | G1 X-6.563 Y9.876 Z0.000 219 | G2 X-5.187 Y10.663 Z0.000 I1.370 J-0.798 220 | G1 X5.271 Y10.622 Z0.000 221 | G2 X6.641 Y9.824 Z0.000 I-0.006 J-1.585 222 | G1 X7.611 Y8.127 Z0.000 223 | G1 X7.611 Y8.127 Z-0.200 224 | G1 X11.834 Y0.746 Z-0.200 225 | G2 X11.828 Y-0.839 Z-0.200 I-1.376 J-0.787 226 | G1 X6.563 Y-9.876 Z-0.200 227 | G2 X5.187 Y-10.663 Z-0.200 I-1.370 J0.798 228 | G1 X-5.271 Y-10.622 Z-0.200 229 | G2 X-6.641 Y-9.824 Z-0.200 I0.006 J1.585 230 | G1 X-11.834 Y-0.746 Z-0.200 231 | G2 X-11.828 Y0.839 Z-0.200 I1.376 J0.787 232 | G1 X-6.563 Y9.876 Z-0.200 233 | G2 X-5.187 Y10.663 Z-0.200 I1.370 J-0.798 234 | G1 X5.271 Y10.622 Z-0.200 235 | G2 X6.641 Y9.824 Z-0.200 I-0.006 J-1.585 236 | G1 X7.611 Y8.127 Z-0.200 237 | G1 X7.611 Y8.127 Z-0.400 238 | G1 X11.834 Y0.746 Z-0.400 239 | G2 X11.828 Y-0.839 Z-0.400 I-1.376 J-0.787 240 | G1 X6.563 Y-9.876 Z-0.400 241 | G2 X5.187 Y-10.663 Z-0.400 I-1.370 J0.798 242 | G1 X-5.271 Y-10.622 Z-0.400 243 | G2 X-6.641 Y-9.824 Z-0.400 I0.006 J1.585 244 | G1 X-11.834 Y-0.746 Z-0.400 245 | G2 X-11.828 Y0.839 Z-0.400 I1.376 J0.787 246 | G1 X-6.563 Y9.876 Z-0.400 247 | G2 X-5.187 Y10.663 Z-0.400 I1.370 J-0.798 248 | G1 X5.271 Y10.622 Z-0.400 249 | G2 X6.641 Y9.824 Z-0.400 I-0.006 J-1.585 250 | G1 X7.611 Y8.127 Z-0.400 251 | G1 X7.611 Y8.127 Z-0.600 252 | G1 X11.834 Y0.746 Z-0.600 253 | G2 X11.828 Y-0.839 Z-0.600 I-1.376 J-0.787 254 | G1 X6.563 Y-9.876 Z-0.600 255 | G2 X5.187 Y-10.663 Z-0.600 I-1.370 J0.798 256 | G1 X-5.271 Y-10.622 Z-0.600 257 | G2 X-6.641 Y-9.824 Z-0.600 I0.006 J1.585 258 | G1 X-11.834 Y-0.746 Z-0.600 259 | G2 X-11.828 Y0.839 Z-0.600 I1.376 J0.787 260 | G1 X-6.563 Y9.876 Z-0.600 261 | G2 X-5.187 Y10.663 Z-0.600 I1.370 J-0.798 262 | G1 X5.271 Y10.622 Z-0.600 263 | G2 X6.641 Y9.824 Z-0.600 I-0.006 J-1.585 264 | G1 X7.611 Y8.127 Z-0.600 265 | G1 X7.611 Y8.127 Z-0.800 266 | G1 X11.834 Y0.746 Z-0.800 267 | G2 X11.828 Y-0.839 Z-0.800 I-1.376 J-0.787 268 | G1 X6.563 Y-9.876 Z-0.800 269 | G2 X5.187 Y-10.663 Z-0.800 I-1.370 J0.798 270 | G1 X-5.271 Y-10.622 Z-0.800 271 | G2 X-6.641 Y-9.824 Z-0.800 I0.006 J1.585 272 | G1 X-11.834 Y-0.746 Z-0.800 273 | G2 X-11.828 Y0.839 Z-0.800 I1.376 J0.787 274 | G1 X-6.563 Y9.876 Z-0.800 275 | G2 X-5.187 Y10.663 Z-0.800 I1.370 J-0.798 276 | G1 X5.271 Y10.622 Z-0.800 277 | G2 X6.641 Y9.824 Z-0.800 I-0.006 J-1.585 278 | G1 X7.611 Y8.127 Z-0.800 279 | G1 X7.611 Y8.127 Z-1.000 280 | G1 X11.834 Y0.746 Z-1.000 281 | G2 X11.828 Y-0.839 Z-1.000 I-1.376 J-0.787 282 | G1 X6.563 Y-9.876 Z-1.000 283 | G2 X5.187 Y-10.663 Z-1.000 I-1.370 J0.798 284 | G1 X-5.271 Y-10.622 Z-1.000 285 | G2 X-6.641 Y-9.824 Z-1.000 I0.006 J1.585 286 | G1 X-11.834 Y-0.746 Z-1.000 287 | G2 X-11.828 Y0.839 Z-1.000 I1.376 J0.787 288 | G1 X-6.563 Y9.876 Z-1.000 289 | G2 X-5.187 Y10.663 Z-1.000 I1.370 J-0.798 290 | G1 X5.271 Y10.622 Z-1.000 291 | G2 X6.641 Y9.824 Z-1.000 I-0.006 J-1.585 292 | G1 X7.611 Y8.127 Z-1.000 293 | G0 Z8.000 294 | ;finish operation: Contour 295 | ;begin postamble 296 | M5 297 | -------------------------------------------------------------------------------- /snapmaker-freecad-configuration/image/countor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-freecad-configuration/image/countor.png -------------------------------------------------------------------------------- /snapmaker-freecad-configuration/image/i-countor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-freecad-configuration/image/i-countor.png -------------------------------------------------------------------------------- /snapmaker-freecad-configuration/image/i-path.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-freecad-configuration/image/i-path.png -------------------------------------------------------------------------------- /snapmaker-freecad-configuration/image/i-post.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-freecad-configuration/image/i-post.png -------------------------------------------------------------------------------- /snapmaker-freecad-configuration/image/new-sketch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-freecad-configuration/image/new-sketch.png -------------------------------------------------------------------------------- /snapmaker-freecad-configuration/image/output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-freecad-configuration/image/output.png -------------------------------------------------------------------------------- /snapmaker-freecad-configuration/image/pad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-freecad-configuration/image/pad.png -------------------------------------------------------------------------------- /snapmaker-freecad-configuration/image/part.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-freecad-configuration/image/part.png -------------------------------------------------------------------------------- /snapmaker-freecad-configuration/image/path.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-freecad-configuration/image/path.png -------------------------------------------------------------------------------- /snapmaker-freecad-configuration/image/polygon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-freecad-configuration/image/polygon.png -------------------------------------------------------------------------------- /snapmaker-freecad-configuration/image/post.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-freecad-configuration/image/post.png -------------------------------------------------------------------------------- /snapmaker-freecad-configuration/image/regular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-freecad-configuration/image/regular.png -------------------------------------------------------------------------------- /snapmaker-freecad-configuration/image/stepdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-freecad-configuration/image/stepdown.png -------------------------------------------------------------------------------- /snapmaker-freecad-configuration/image/tool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-freecad-configuration/image/tool.png -------------------------------------------------------------------------------- /snapmaker-freecad-configuration/image/tools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-freecad-configuration/image/tools.png -------------------------------------------------------------------------------- /snapmaker-freecad-configuration/readme.txt: -------------------------------------------------------------------------------- 1 | Copy snapmaker_freecad_post.py to C:\Program Files (x86)\FreeCAD\Mod\Path\Pathscripts\Post. 2 | 3 | Save type: *.cnc 4 | 5 | Please read: 6 | https://wiki.freecadweb.org/Path_Post 7 | -------------------------------------------------------------------------------- /snapmaker-freecad-configuration/snapmaker_freecad_post.py: -------------------------------------------------------------------------------- 1 | # *************************************************************************** 2 | # * (c) sliptonic (shopinthewoods@gmail.com) 2014 * 3 | # * * 4 | # * This file is part of the FreeCAD CAx development system. * 5 | # * * 6 | # * This program is free software; you can redistribute it and/or modify * 7 | # * it under the terms of the GNU Lesser General Public License (LGPL) * 8 | # * as published by the Free Software Foundation; either version 2 of * 9 | # * the License, or (at your option) any later version. * 10 | # * for detail see the LICENCE text file. * 11 | # * * 12 | # * FreeCAD is distributed in the hope that it will be useful, * 13 | # * but WITHOUT ANY WARRANTY; without even the implied warranty of * 14 | # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 15 | # * GNU Lesser General Public License for more details. * 16 | # * * 17 | # * You should have received a copy of the GNU Library General Public * 18 | # * License along with FreeCAD; if not, write to the Free Software * 19 | # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * 20 | # * USA * 21 | # * * 22 | # ***************************************************************************/ 23 | from __future__ import print_function 24 | import FreeCAD 25 | from FreeCAD import Units 26 | import Path 27 | import argparse 28 | import datetime 29 | import shlex 30 | from PathScripts import PostUtils 31 | from PathScripts import PathUtils 32 | 33 | TOOLTIP = ''' 34 | This is a postprocessor file for the Path workbench. It is used to 35 | take a pseudo-gcode fragment outputted by a Path object, and output 36 | real GCode suitable for a linuxcnc 3 axis mill. This postprocessor, once placed 37 | in the appropriate PathScripts folder, can be used directly from inside 38 | FreeCAD, via the GUI importer or via python scripts with: 39 | 40 | import linuxcnc_post 41 | linuxcnc_post.export(object,"/path/to/file.ncc","") 42 | ''' 43 | 44 | now = datetime.datetime.now() 45 | 46 | parser = argparse.ArgumentParser(prog='linuxcnc', add_help=False) 47 | parser.add_argument('--no-header', action='store_true', help='suppress header output') 48 | parser.add_argument('--no-comments', action='store_true', help='suppress comment output') 49 | parser.add_argument('--line-numbers', action='store_true', help='prefix with line numbers') 50 | parser.add_argument('--no-show-editor', action='store_true', help='don\'t pop up editor before writing output') 51 | parser.add_argument('--precision', default='3', help='number of digits of precision, default=3') 52 | parser.add_argument('--preamble', help='set commands to be issued before the first command, default="G17\nG90"') 53 | parser.add_argument('--postamble', help='set commands to be issued after the last command, default="M05\nG17 G90\nM2"') 54 | parser.add_argument('--inches', action='store_true', help='Convert output for US imperial mode (G20)') 55 | parser.add_argument('--modal', action='store_true', help='Output the Same G-command Name USE NonModal Mode') 56 | parser.add_argument('--axis-modal', action='store_true', help='Output the Same Axis Value Mode') 57 | parser.add_argument('--no-tlo', action='store_true', help='suppress tool length offset (G43) following tool changes') 58 | 59 | TOOLTIP_ARGS = parser.format_help() 60 | 61 | # These globals set common customization preferences 62 | OUTPUT_COMMENTS = True 63 | OUTPUT_HEADER = True 64 | OUTPUT_LINE_NUMBERS = False 65 | SHOW_EDITOR = True 66 | MODAL = False # if true commands are suppressed if the same as previous line. 67 | USE_TLO = True # if true G43 will be output following tool changes 68 | OUTPUT_DOUBLES = True # if false duplicate axis values are suppressed if the same as previous line. 69 | COMMAND_SPACE = " " 70 | COMMANDS = ['G0','G00','G1','G01','G2','G02','G3','G03','M3'] 71 | LINENR = 100 # line number starting value 72 | 73 | # These globals will be reflected in the Machine configuration of the project 74 | UNITS = "G21" # G21 for metric, G20 for us standard 75 | UNIT_SPEED_FORMAT = 'mm/min' 76 | UNIT_FORMAT = 'mm' 77 | 78 | MACHINE_NAME = "LinuxCNC" 79 | CORNER_MIN = {'x': 0, 'y': 0, 'z': 0} 80 | CORNER_MAX = {'x': 500, 'y': 300, 'z': 300} 81 | PRECISION = 3 82 | 83 | # Preamble text will appear at the beginning of the GCODE output file. 84 | PREAMBLE = '''G17 G54 G40 G49 G80 G90 85 | ''' 86 | 87 | # Postamble text will appear following the last operation. 88 | POSTAMBLE = '''M5 89 | ''' 90 | 91 | # Pre operation text will be inserted before every operation 92 | PRE_OPERATION = '''''' 93 | 94 | # Post operation text will be inserted after every operation 95 | POST_OPERATION = '''''' 96 | 97 | # Tool Change commands will be inserted before a tool change 98 | TOOL_CHANGE = '''''' 99 | 100 | # to distinguish python built-in open function from the one declared below 101 | if open.__module__ in ['__builtin__','io']: 102 | pythonopen = open 103 | 104 | 105 | def processArguments(argstring): 106 | # pylint: disable=global-statement 107 | global OUTPUT_HEADER 108 | global OUTPUT_COMMENTS 109 | global OUTPUT_LINE_NUMBERS 110 | global SHOW_EDITOR 111 | global PRECISION 112 | global PREAMBLE 113 | global POSTAMBLE 114 | global UNITS 115 | global UNIT_SPEED_FORMAT 116 | global UNIT_FORMAT 117 | global MODAL 118 | global USE_TLO 119 | global OUTPUT_DOUBLES 120 | 121 | try: 122 | args = parser.parse_args(shlex.split(argstring)) 123 | if args.no_header: 124 | OUTPUT_HEADER = False 125 | if args.no_comments: 126 | OUTPUT_COMMENTS = False 127 | if args.line_numbers: 128 | OUTPUT_LINE_NUMBERS = True 129 | if args.no_show_editor: 130 | SHOW_EDITOR = False 131 | print("Show editor = %d" % SHOW_EDITOR) 132 | PRECISION = args.precision 133 | if args.preamble is not None: 134 | PREAMBLE = args.preamble 135 | if args.postamble is not None: 136 | POSTAMBLE = args.postamble 137 | if args.inches: 138 | UNITS = 'G20' 139 | UNIT_SPEED_FORMAT = 'in/min' 140 | UNIT_FORMAT = 'in' 141 | PRECISION = 4 142 | if args.modal: 143 | MODAL = True 144 | if args.no_tlo: 145 | USE_TLO = False 146 | if args.axis_modal: 147 | print ('here') 148 | OUTPUT_DOUBLES = False 149 | 150 | except Exception: # pylint: disable=broad-except 151 | return False 152 | 153 | return True 154 | 155 | 156 | def export(objectslist, filename, argstring): 157 | # pylint: disable=global-statement 158 | if not processArguments(argstring): 159 | return None 160 | global UNITS 161 | global UNIT_FORMAT 162 | global UNIT_SPEED_FORMAT 163 | 164 | for obj in objectslist: 165 | if not hasattr(obj, "Path"): 166 | print("the object " + obj.Name + " is not a path. Please select only path and Compounds.") 167 | return None 168 | 169 | print("postprocessing...") 170 | gcode = "" 171 | 172 | # write header 173 | if OUTPUT_HEADER: 174 | gcode += linenumber() + ";Exported by Snapmaker\n" 175 | gcode += linenumber() + ";Post Processor: " + __name__ + "\n" 176 | gcode += linenumber() + ";Output Time:" + str(now) + "\n" 177 | gcode += linenumber() + "\n" 178 | gcode += linenumber() + "G0 Z10.00 F120" + "\n" 179 | gcode += linenumber() + "G0 Z0.50 F120" + "\n" 180 | 181 | gcode += linenumber() + UNITS + "\n" 182 | 183 | for obj in objectslist: 184 | 185 | # Skip inactive operations 186 | if hasattr(obj, 'Active'): 187 | if not obj.Active: 188 | continue 189 | if hasattr(obj, 'Base') and hasattr(obj.Base, 'Active'): 190 | if not obj.Base.Active: 191 | continue 192 | 193 | # fetch machine details 194 | job = PathUtils.findParentJob(obj) 195 | 196 | myMachine = 'not set' 197 | 198 | if hasattr(job, "MachineName"): 199 | myMachine = job.MachineName 200 | 201 | if hasattr(job, "MachineUnits"): 202 | if job.MachineUnits == "Metric": 203 | UNITS = "G21" 204 | UNIT_FORMAT = 'mm' 205 | UNIT_SPEED_FORMAT = 'mm/min' 206 | else: 207 | UNITS = "G20" 208 | UNIT_FORMAT = 'in' 209 | UNIT_SPEED_FORMAT = 'in/min' 210 | 211 | 212 | # get coolant mode 213 | coolantMode = 'None' 214 | if hasattr(obj, "CoolantMode") or hasattr(obj, 'Base') and hasattr(obj.Base, "CoolantMode"): 215 | if hasattr(obj, "CoolantMode"): 216 | coolantMode = obj.CoolantMode 217 | else: 218 | coolantMode = obj.Base.CoolantMode 219 | 220 | # process the operation gcode 221 | gcode += parse(obj) 222 | 223 | # do the post_op 224 | if OUTPUT_COMMENTS: 225 | gcode += linenumber() + ";finish operation: %s\n" % obj.Label 226 | for line in POST_OPERATION.splitlines(True): 227 | gcode += linenumber() + line 228 | 229 | # do the post_amble 230 | if OUTPUT_COMMENTS: 231 | gcode += ";begin postamble\n" 232 | for line in POSTAMBLE.splitlines(True): 233 | gcode += linenumber() + line 234 | 235 | if FreeCAD.GuiUp and SHOW_EDITOR: 236 | dia = PostUtils.GCodeEditorDialog() 237 | dia.editor.setText(gcode) 238 | result = dia.exec_() 239 | if result: 240 | final = dia.editor.toPlainText() 241 | else: 242 | final = gcode 243 | else: 244 | final = gcode 245 | 246 | print("done postprocessing.") 247 | 248 | if not filename == '-': 249 | gfile = pythonopen(filename, "w") 250 | gfile.write(final) 251 | gfile.close() 252 | 253 | return final 254 | 255 | 256 | def linenumber(): 257 | # pylint: disable=global-statement 258 | global LINENR 259 | if OUTPUT_LINE_NUMBERS is True: 260 | LINENR += 10 261 | return "N" + str(LINENR) + " " 262 | return "" 263 | 264 | 265 | def parse(pathobj): 266 | # pylint: disable=global-statement 267 | global PRECISION 268 | global MODAL 269 | global OUTPUT_DOUBLES 270 | global UNIT_FORMAT 271 | global UNIT_SPEED_FORMAT 272 | 273 | out = "" 274 | lastcommand = None 275 | precision_string = '.' + str(PRECISION) + 'f' 276 | currLocation = {} # keep track for no doubles 277 | 278 | # the order of parameters 279 | # linuxcnc doesn't want K properties on XY plane Arcs need work. 280 | params = ['X', 'Y', 'Z', 'A', 'B', 'C', 'I', 'J', 'F', 'S', 'T', 'Q', 'R', 'L', 'H', 'D', 'P'] 281 | firstmove = Path.Command("G0", {"X": -1, "Y": -1, "Z": -1, "F": 0.0}) 282 | currLocation.update(firstmove.Parameters) # set First location Parameters 283 | 284 | if hasattr(pathobj, "Group"): # We have a compound or project. 285 | # if OUTPUT_COMMENTS: 286 | # out += linenumber() + "(compound: " + pathobj.Label + ")\n" 287 | for p in pathobj.Group: 288 | out += parse(p) 289 | return out 290 | else: # parsing simple path 291 | 292 | # groups might contain non-path things like stock. 293 | if not hasattr(pathobj, "Path"): 294 | return out 295 | 296 | for c in pathobj.Path.Commands: 297 | 298 | outstring = [] 299 | command = c.Name 300 | outstring.append(command) 301 | 302 | if command not in COMMANDS: 303 | continue 304 | 305 | # if modal: suppress the command if it is the same as the last one 306 | if MODAL is True: 307 | if command == lastcommand: 308 | outstring.pop(0) 309 | 310 | if c.Name[0] == '(': # command is a comment 311 | continue 312 | 313 | # Now add the remaining parameters in order 314 | for param in params: 315 | if param in c.Parameters: 316 | if param == 'F' and (currLocation[param] != c.Parameters[param] or OUTPUT_DOUBLES): 317 | if c.Name not in ["G0", "G00"]: # linuxcnc doesn't use rapid speeds 318 | speed = Units.Quantity(c.Parameters['F'], FreeCAD.Units.Velocity) 319 | if speed.getValueAs(UNIT_SPEED_FORMAT) > 0.0: 320 | outstring.append(param + format(float(speed.getValueAs(UNIT_SPEED_FORMAT)), precision_string)) 321 | else: 322 | continue 323 | elif param == 'T': 324 | outstring.append(param + str(int(c.Parameters['T']))) 325 | elif param == 'H': 326 | outstring.append(param + str(int(c.Parameters['H']))) 327 | elif param == 'D': 328 | outstring.append(param + str(int(c.Parameters['D']))) 329 | elif param == 'S': 330 | outstring.append(param + str(int(c.Parameters['S']))) 331 | else: 332 | if (not OUTPUT_DOUBLES) and (param in currLocation) and (currLocation[param] == c.Parameters[param]): 333 | continue 334 | else: 335 | pos = Units.Quantity(c.Parameters[param], FreeCAD.Units.Length) 336 | outstring.append( 337 | param + format(float(pos.getValueAs(UNIT_FORMAT)), precision_string)) 338 | 339 | # store the latest command 340 | lastcommand = command 341 | currLocation.update(c.Parameters) 342 | 343 | if command == "message": 344 | if OUTPUT_COMMENTS is False: 345 | out = [] 346 | else: 347 | outstring.pop(0) # remove the command 348 | 349 | # prepend a line number and append a newline 350 | if len(outstring) >= 1: 351 | if OUTPUT_LINE_NUMBERS: 352 | outstring.insert(0, (linenumber())) 353 | 354 | # append the line to the final output 355 | for w in outstring: 356 | out += w + COMMAND_SPACE 357 | out = out.strip() + "\n" 358 | 359 | return out 360 | 361 | print(__name__ + " gcode postprocessor loaded.") 362 | -------------------------------------------------------------------------------- /snapmaker-fusion360-configuration-20180730/Snapmaker 2.0 CNC Tool Library.tools: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-fusion360-configuration-20180730/Snapmaker 2.0 CNC Tool Library.tools -------------------------------------------------------------------------------- /snapmaker-fusion360-configuration-20180730/Snapmaker Artisan CNC tool library.tools: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-fusion360-configuration-20180730/Snapmaker Artisan CNC tool library.tools -------------------------------------------------------------------------------- /snapmaker-fusion360-configuration-20180730/Snapmaker CNC tool library.tools: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-fusion360-configuration-20180730/Snapmaker CNC tool library.tools -------------------------------------------------------------------------------- /snapmaker-fusion360-configuration-20180730/readme.txt: -------------------------------------------------------------------------------- 1 | Please read 2 | https://support.snapmaker.com/hc/en-us/articles/360060624834-CNC-Cutting-with-Files-Exported-from-Fusion-360 3 | -------------------------------------------------------------------------------- /snapmaker-fusion360-configuration-20180730/snapmaker-baxis.cps: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (C) 2012-2018 by Autodesk, Inc. 3 | All rights reserved. 4 | 5 | FANUC post processor configuration. 6 | 7 | $Revision: 42172 bd19858a62e243c722de6e4753876abf77ff3fb6 $ 8 | $Date: 2018-11-06 13:08:35 $ 9 | 10 | FORKID {CB457AE9-77B4-4F88-B95A-4DC6980DBE3D} 11 | */ 12 | 13 | description = 'FANUC - Inverse Time and A-axis'; 14 | vendor = 'Fanuc'; 15 | vendorUrl = 'http://www.fanuc.com'; 16 | legal = 'Copyright (C) 2012-2018 by Autodesk, Inc.'; 17 | certificationLevel = 2; 18 | minimumRevision = 40783; 19 | 20 | longDescription = 'Generic Fanuc post illustrating inverse time feed with an A-axis.'; 21 | 22 | extension = 'cnc'; 23 | programNameIsInteger = true; 24 | setCodePage('ascii'); 25 | 26 | capabilities = CAPABILITY_MILLING; 27 | tolerance = spatial(0.2, MM); 28 | 29 | minimumChordLength = spatial(10, MM); 30 | minimumCircularRadius = spatial(10, MM); 31 | maximumCircularRadius = spatial(1000, MM); 32 | minimumCircularSweep = toRad(10); 33 | maximumCircularSweep = toRad(180); 34 | allowHelicalMoves = true; 35 | allowedCircularPlanes = undefined; // allow any circular motion 36 | 37 | 38 | // user-defined properties 39 | properties = { 40 | writeMachine: true, // write machine 41 | writeTools: true, // writes the tools 42 | preloadTool: true, // preloads next tool on tool change if any 43 | showSequenceNumbers: false, // show sequence numbers 44 | sequenceNumberStart: 10, // first sequence number 45 | zInitialHeight: 50, 46 | sequenceNumberIncrement: 5, // increment for sequence numbers 47 | optionalStop: true, // optional stop 48 | o8: false, // specifies 8-digit program number 49 | separateWordsWithSpace: true, // specifies that the words should be separated with a white space 50 | allow3DArcs: false, // specifies that 3D circular arcs are allowed 51 | useInverseTimeFeed: false, // use 1/T feeds 52 | useClockwise: false, // use clockwise or anticlockwise,true: closewise,false:anticlockwise 53 | useRadius: false, // specifies that arcs should be output using the radius (R word) instead of the I, J, and K words 54 | forceIJK: false, // force output of IJK for G2/G3 when not using R word 55 | showNotes: false, // specifies that operation notes should be output 56 | useSmoothing: false, // specifies if smoothing should be used or not 57 | usePitchForTapping: false, // enable to use pitch instead of feed for the F-word for canned tapping cycles - note that your CNC control must be setup for pitch mode! 58 | useG95: false, // use IPR/MPR instead of IPM/MPM 59 | useG54x4: false, // Fanuc 30i supports G54.4 for Workpiece Error Compensation 60 | makeAAxisOtherWay: false, // make the A-axis rotate the opposite way 61 | useSubroutines: false, // specifies that subroutines per each operation should be generated 62 | useSubroutinePatterns: false, // generates subroutines for patterned operation 63 | useSubroutineCycles: false, // generates subroutines for cycle operations on same holes 64 | useRigidTapping: 'yes' // output rigid tapping block 65 | }; 66 | 67 | // user-defined property definitions 68 | propertyDefinitions = { 69 | writeMachine: { 70 | title: 'Write machine', 71 | description: 'Output the machine settings in the header of the code.', 72 | group: 0, 73 | type: 'boolean' 74 | }, 75 | writeTools: { 76 | title: 'Write tool list', 77 | description: 'Output a tool list in the header of the code.', 78 | group: 0, 79 | type: 'boolean' 80 | }, 81 | preloadTool: { 82 | title: 'Preload tool', 83 | description: 'Preloads the next tool at a tool change (if any).', 84 | group: 1, 85 | type: 'boolean' 86 | }, 87 | showSequenceNumbers: { 88 | title: 'Use sequence numbers', 89 | description: 'Use sequence numbers for each block of outputted code.', 90 | group: 1, 91 | type: 'boolean' 92 | }, 93 | sequenceNumberStart: { 94 | title: 'Start sequence number', 95 | description: 'The number at which to start the sequence numbers.', 96 | group: 1, 97 | type: 'integer' 98 | }, 99 | sequenceNumberIncrement: { 100 | title: 'Sequence number increment', 101 | description: 'The amount by which the sequence number is incremented by in each block.', 102 | group: 1, 103 | type: 'integer' 104 | }, 105 | zInitialHeight: { 106 | title: 'Z initial height', 107 | description: 'Initial height of Z before printing', 108 | group: 1, 109 | type: 'integer' 110 | }, 111 | optionalStop: { 112 | title: 'Optional stop', 113 | description: 'Outputs optional stop code during when necessary in the code.', 114 | type: 'boolean' 115 | }, 116 | o8: { 117 | title: '8 Digit program number', 118 | description: 'Specifies that an 8 digit program number is needed.', 119 | type: 'boolean' 120 | }, 121 | separateWordsWithSpace: { 122 | title: 'Separate words with space', 123 | description: 'Adds spaces between words if \'yes\' is selected.', 124 | type: 'boolean' 125 | }, 126 | allow3DArcs: { 127 | title: 'Allow 3D arcs', 128 | description: 'Specifies whether 3D circular arcs are allowed.', 129 | type: 'boolean' 130 | }, 131 | useInverseTimeFeed: { 132 | title: 'Use inverse time feed', 133 | description: '', 134 | type: 'boolean' 135 | }, 136 | useClockwise: { 137 | title: 'Use clockwise or anticlockwise', 138 | description: '', 139 | type: 'boolean' 140 | }, 141 | useRadius: { 142 | title: 'Radius arcs', 143 | description: 'If yes is selected, arcs are outputted using radius values rather than IJK.', 144 | type: 'boolean' 145 | }, 146 | forceIJK: { 147 | title: 'Force IJK', 148 | description: 'Force the output of IJK for G2/G3 when not using R mode.', 149 | type: 'boolean' 150 | }, 151 | showNotes: { 152 | title: 'Show notes', 153 | description: 'Writes operation notes as comments in the outputted code.', 154 | type: 'boolean' 155 | }, 156 | useSmoothing: { 157 | title: 'Use smoothing', 158 | description: 'Specifies if smoothing should be used or not.', 159 | type: 'boolean' 160 | }, 161 | usePitchForTapping: { 162 | title: 'Use pitch for tapping', 163 | description: 'Enables the use of pitch instead of feed for the F-word in canned tapping cycles. Your CNC control must be setup for pitch mode!', 164 | type: 'boolean' 165 | }, 166 | useG95: { 167 | title: 'Use G95', 168 | description: 'Use IPR/MPR instead of IPM/MPM.', 169 | type: 'boolean' 170 | }, 171 | useG54x4: { 172 | title: 'Use G54.4', 173 | description: 'Fanuc 30i supports G54.4 for workpiece error compensation.', 174 | type: 'boolean' 175 | }, 176 | makeAAxisOtherWay: { 177 | title: 'Reverse A-axis', 178 | description: 'Makes the A-axis rotate the opposite way.', 179 | type: 'boolean' 180 | }, 181 | useSubroutines: { 182 | title: 'Use subroutines', 183 | description: 'Specifies that subroutines per each operation should be generated.', 184 | type: 'boolean' 185 | }, 186 | useSubroutinePatterns: { 187 | title: 'Use subroutine patterns', 188 | description: 'Generates subroutines for patterned operation.', 189 | type: 'boolean' 190 | }, 191 | useSubroutineCycles: { 192 | title: 'Use subroutine cycles', 193 | description: 'Generates subroutines for cycle operations on same holes.', 194 | type: 'boolean' 195 | }, 196 | useRigidTapping: { 197 | title: 'Use rigid tapping', 198 | description: 'Select \'Yes\' to enable, \'No\' to disable, or \'Without spindle direction\' to enable rigid tapping without outputting the spindle direction block.', 199 | type: 'enum', 200 | values: [ 201 | { 202 | title: 'Yes', 203 | id: 'yes' 204 | }, 205 | { 206 | title: 'No', 207 | id: 'no' 208 | }, 209 | { 210 | title: 'Without spindle direction', 211 | id: 'without' 212 | } 213 | ] 214 | } 215 | }; 216 | 217 | // samples: 218 | // throughTool: {on: 88, off: 89} 219 | // throughTool: {on: [8, 88], off: [9, 89]} 220 | var coolants = { 221 | flood: {on: 8}, 222 | mist: {}, 223 | throughTool: { 224 | on: 88, 225 | off: 89 226 | }, 227 | air: {}, 228 | airThroughTool: {}, 229 | suction: {}, 230 | floodMist: {}, 231 | floodThroughTool: {}, 232 | off: 9 233 | }; 234 | 235 | var permittedCommentChars = ' ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,=_-'; 236 | 237 | var gFormat = createFormat({ 238 | prefix: 'G', 239 | width: 2, 240 | zeropad: true, 241 | decimals: 1 242 | }); 243 | var mFormat = createFormat({ 244 | prefix: 'M', 245 | width: 2, 246 | zeropad: true, 247 | decimals: 1 248 | }); 249 | var hFormat = createFormat({ 250 | prefix: 'H', 251 | width: 2, 252 | zeropad: true, 253 | decimals: 1 254 | }); 255 | var dFormat = createFormat({ 256 | prefix: 'D', 257 | width: 2, 258 | zeropad: true, 259 | decimals: 1 260 | }); 261 | var probe100Format = createFormat({ 262 | decimals: 3, 263 | zeropad: true, 264 | width: 3, 265 | forceDecimal: true 266 | }); 267 | 268 | var xyzFormat = createFormat({ 269 | decimals: (unit == MM ? 3 : 4), 270 | forceDecimal: true 271 | }); 272 | var rFormat = xyzFormat; // radius 273 | var abcFormat = createFormat({ 274 | decimals: 3, 275 | forceDecimal: true, 276 | scale: DEG 277 | }); 278 | var feedFormat = createFormat({ 279 | decimals: (unit == MM ? 1 : 2), 280 | forceDecimal: true 281 | }); 282 | var pitchFormat = createFormat({ 283 | decimals: (unit == MM ? 3 : 4), 284 | forceDecimal: true 285 | }); 286 | var toolFormat = createFormat({decimals: 0}); 287 | var rpmFormat = createFormat({decimals: 0}); 288 | var secFormat = createFormat({ 289 | decimals: 3, 290 | forceDecimal: true 291 | }); // seconds - range 0.001-99999.999 292 | var milliFormat = createFormat({decimals: 0}); // milliseconds // range 1-9999 293 | var taperFormat = createFormat({ 294 | decimals: 1, 295 | scale: DEG 296 | }); 297 | var oFormat = createFormat({ 298 | width: 4, 299 | zeropad: true, 300 | decimals: 0 301 | }); 302 | 303 | var xOutput = createVariable({prefix: 'X'}, xyzFormat); 304 | var yOutput = createVariable({prefix: 'Y'}, xyzFormat); 305 | var zOutput = createVariable({ 306 | onchange: function () { 307 | retracted = false; 308 | }, 309 | prefix: 'Z' 310 | }, xyzFormat); 311 | var aOutput = createVariable({prefix: 'A'}, abcFormat); 312 | var bOutput = createVariable({prefix: 'B'}, abcFormat); 313 | var cOutput = createVariable({prefix: 'C'}, abcFormat); 314 | var feedOutput = createVariable({prefix: 'F',force: true}, feedFormat); 315 | var pitchOutput = createVariable({ 316 | prefix: 'F', 317 | force: true 318 | }, pitchFormat); 319 | var inverseTimeOutput = createVariable({ 320 | prefix: 'F', 321 | force: true 322 | }, feedFormat); 323 | var sOutput = createVariable({ 324 | prefix: 'S', 325 | force: true 326 | }, rpmFormat); 327 | var dOutput = createVariable({}, dFormat); 328 | 329 | // circular output 330 | var iOutput = createReferenceVariable({prefix: 'I'}, xyzFormat); 331 | var jOutput = createReferenceVariable({prefix: 'J'}, xyzFormat); 332 | var kOutput = createReferenceVariable({prefix: 'K'}, xyzFormat); 333 | 334 | var gMotionModal = createModal({force: true}, gFormat); // modal group 1 // G0-G3, ... 335 | var gPlaneModal = createModal({ 336 | onchange: function () { 337 | gMotionModal.reset(); 338 | } 339 | }, gFormat); // modal group 2 // G17-19 340 | var gAbsIncModal = createModal({}, gFormat); // modal group 3 // G90-91 341 | var gFeedModeModal = createModal({}, gFormat); // modal group 5 // G94-95 342 | var gUnitModal = createModal({}, gFormat); // modal group 6 // G20-21 343 | var gCycleModal = createModal({}, gFormat); // modal group 9 // G81, ... 344 | var gRetractModal = createModal({}, gFormat); // modal group 10 // G98-99 345 | var gRotationModal = createModal({}, gFormat); // modal group 16 // G68-G69 346 | 347 | // fixed settings 348 | var useMultiAxisFeatures = false; 349 | var forceMultiAxisIndexing = false; // force multi-axis indexing for 3D programs 350 | var maximumLineLength = 80; // the maximum number of charaters allowed in a line 351 | var minimumCyclePoints = 5; // minimum number of points in cycle operation to consider for subprogram 352 | var cancelTiltFirst = false; // cancel G68.2 with G69 prior to G54-G59 WCS block 353 | var useABCPrepositioning = false; // position ABC axes prior to G68.2 block 354 | 355 | var WARNING_WORK_OFFSET = 0; 356 | 357 | var ANGLE_PROBE_NOT_SUPPORTED = 0; 358 | var ANGLE_PROBE_USE_ROTATION = 1; 359 | var ANGLE_PROBE_USE_CAXIS = 2; 360 | 361 | var SUB_UNKNOWN = 0; 362 | var SUB_PATTERN = 1; 363 | var SUB_CYCLE = 2; 364 | 365 | // collected state 366 | var sequenceNumber; 367 | var currentWorkOffset; 368 | var optionalSection = false; 369 | var forceSpindleSpeed = false; 370 | var g68RotationMode = 0; 371 | var angularProbingMode; 372 | var subprograms = []; 373 | var currentPattern = -1; 374 | var firstPattern = false; 375 | var currentSubprogram; 376 | var lastSubprogram; 377 | var definedPatterns = new Array(); 378 | var incrementalMode = false; 379 | var saveShowSequenceNumbers; 380 | var cycleSubprogramIsActive = false; 381 | var patternIsActive = false; 382 | var lastOperationComment = ''; 383 | var retracted = false; // specifies that the tool has been retracted to the safe plane 384 | 385 | /** 386 | Writes the specified block. 387 | */ 388 | function writeBlock() { 389 | var text = formatWords(arguments); 390 | if (!text) { 391 | return; 392 | } 393 | if (false) { 394 | if (optionalSection) { 395 | if (text) { 396 | writeWords('/', 'N' + sequenceNumber, text); 397 | } 398 | } else { 399 | writeWords2('N' + sequenceNumber, arguments); 400 | } 401 | sequenceNumber += properties.sequenceNumberIncrement; 402 | } else { 403 | if (optionalSection) { 404 | writeWords2('/', arguments); 405 | } else { 406 | writeWords(arguments); 407 | } 408 | } 409 | } 410 | 411 | /** 412 | Writes the specified optional block. 413 | */ 414 | function writeOptionalBlock() { 415 | if (properties.showSequenceNumbers) { 416 | var words = formatWords(arguments); 417 | if (words) { 418 | writeWords('/', 'N' + sequenceNumber, words); 419 | sequenceNumber += properties.sequenceNumberIncrement; 420 | } 421 | } else { 422 | writeWords2('/', arguments); 423 | } 424 | } 425 | 426 | function formatComment(text) { 427 | return ';' + filterText(String(text) 428 | .toUpperCase(), permittedCommentChars) 429 | .replace(/[()]/g, '') + ''; 430 | } 431 | 432 | /** 433 | Output a comment. 434 | */ 435 | function writeComment(text) { 436 | writeln(formatComment(text)); 437 | } 438 | 439 | function onOpen() { 440 | if (properties.useRadius) { 441 | maximumCircularSweep = toRad(90); // avoid potential center calculation errors for CNC 442 | } 443 | gRotationModal.format(69); // Default to G69 Rotation Off 444 | 445 | if (true) { 446 | // var aAxis = createAxis({coordinate:0, table:true, axis:[(properties.makeAAxisOtherWay ? -1 : 1) * -1, 0, 0], cyclic:true, preference:1}); 447 | var bAxis = createAxis({ 448 | coordinate: 1, 449 | table: true, 450 | axis: [0, (properties.makeAAxisOtherWay ? -1 : 1) * -1, 0], 451 | cyclic: true, 452 | preference: 1 453 | }); 454 | machineConfiguration = new MachineConfiguration(bAxis); 455 | 456 | setMachineConfiguration(machineConfiguration); 457 | optimizeMachineAngles2(1); // map tip mode 458 | } 459 | 460 | if (!machineConfiguration.isMachineCoordinate(0)) { 461 | aOutput.disable(); 462 | } 463 | if (!machineConfiguration.isMachineCoordinate(1)) { 464 | bOutput.disable(); 465 | } 466 | if (!machineConfiguration.isMachineCoordinate(2)) { 467 | cOutput.disable(); 468 | } 469 | 470 | if (!properties.separateWordsWithSpace) { 471 | setWordSeparator(''); 472 | } 473 | 474 | if (properties.forceIJK) { 475 | iOutput = createReferenceVariable({ 476 | prefix: 'I', 477 | force: true 478 | }, xyzFormat); 479 | jOutput = createReferenceVariable({ 480 | prefix: 'J', 481 | force: true 482 | }, xyzFormat); 483 | kOutput = createReferenceVariable({ 484 | prefix: 'K', 485 | force: true 486 | }, xyzFormat); 487 | } 488 | 489 | sequenceNumber = properties.sequenceNumberStart; 490 | 491 | if (programName) { 492 | var programId; 493 | try { 494 | programId = getAsInt(programName); 495 | } catch (e) { 496 | error(localize('Program name must be a number.')); 497 | return; 498 | } 499 | if (properties.o8) { 500 | if (!((programId >= 1) && (programId <= 99999999))) { 501 | error(localize('Program number is out of range.')); 502 | return; 503 | } 504 | } else { 505 | if (!((programId >= 1) && (programId <= 9999))) { 506 | error(localize('Program number is out of range.')); 507 | return; 508 | } 509 | } 510 | if ((programId >= 8000) && (programId <= 9999)) { 511 | warning(localize('Program number is reserved by tool builder.')); 512 | } 513 | oFormat = createFormat({ 514 | width: (properties.o8 ? 8 : 4), 515 | zeropad: true, 516 | decimals: 0 517 | }); 518 | if (programComment) { 519 | writeln(';' + oFormat.format(programId) + ' (' + filterText(String(programComment) 520 | .toUpperCase(), permittedCommentChars) + ')'); 521 | } else { 522 | writeln(';' + oFormat.format(programId)); 523 | } 524 | lastSubprogram = programId; 525 | } else { 526 | error(localize('Program name has not been specified.')); 527 | return; 528 | } 529 | 530 | // dump machine configuration 531 | var vendor = machineConfiguration.getVendor(); 532 | var model = machineConfiguration.getModel(); 533 | var description = machineConfiguration.getDescription(); 534 | 535 | if (properties.writeMachine && (vendor || model || description)) { 536 | writeComment(localize('Machine')); 537 | if (vendor) { 538 | writeComment(' ' + localize('vendor') + ': ' + vendor); 539 | } 540 | if (model) { 541 | writeComment(' ' + localize('model') + ': ' + model); 542 | } 543 | if (description) { 544 | writeComment(' ' + localize('description') + ': ' + description); 545 | } 546 | } 547 | 548 | // dump tool information 549 | if (properties.writeTools) { 550 | var zRanges = {}; 551 | if (is3D()) { 552 | var numberOfSections = getNumberOfSections(); 553 | for (var i = 0; i < numberOfSections; ++i) { 554 | var section = getSection(i); 555 | var zRange = section.getGlobalZRange(); 556 | var tool = section.getTool(); 557 | if (zRanges[tool.number]) { 558 | zRanges[tool.number].expandToRange(zRange); 559 | } else { 560 | zRanges[tool.number] = zRange; 561 | } 562 | } 563 | } 564 | 565 | var tools = getToolTable(); 566 | if (tools.getNumberOfTools() > 0) { 567 | for (var i = 0; i < tools.getNumberOfTools(); ++i) { 568 | var tool = tools.getTool(i); 569 | var comment = 'T' + toolFormat.format(tool.number) + ' ' + 570 | 'D=' + xyzFormat.format(tool.diameter) + ' ' + 571 | localize('CR') + '=' + xyzFormat.format(tool.cornerRadius); 572 | if ((tool.taperAngle > 0) && (tool.taperAngle < Math.PI)) { 573 | comment += ' ' + localize('TAPER') + '=' + taperFormat.format(tool.taperAngle) + localize('deg'); 574 | } 575 | if (zRanges[tool.number]) { 576 | comment += ' - ' + localize('ZMIN') + '=' + xyzFormat.format(zRanges[tool.number].getMinimum()); 577 | } 578 | comment += ' - ' + getToolTypeName(tool.type); 579 | writeComment(comment); 580 | } 581 | } 582 | } 583 | 584 | if (false) { 585 | // check for duplicate tool number 586 | for (var i = 0; i < getNumberOfSections(); ++i) { 587 | var sectioni = getSection(i); 588 | var tooli = sectioni.getTool(); 589 | for (var j = i + 1; j < getNumberOfSections(); ++j) { 590 | var sectionj = getSection(j); 591 | var toolj = sectionj.getTool(); 592 | if (tooli.number == toolj.number) { 593 | if (xyzFormat.areDifferent(tooli.diameter, toolj.diameter) || 594 | xyzFormat.areDifferent(tooli.cornerRadius, toolj.cornerRadius) || 595 | abcFormat.areDifferent(tooli.taperAngle, toolj.taperAngle) || 596 | (tooli.numberOfFlutes != toolj.numberOfFlutes)) { 597 | error( 598 | subst( 599 | localize('Using the same tool number for different cutter geometry for operation \'%1\' and \'%2\'.'), 600 | sectioni.hasParameter('operation-comment') ? sectioni.getParameter('operation-comment') : ('#' + (i + 1)), 601 | sectionj.hasParameter('operation-comment') ? sectionj.getParameter('operation-comment') : ('#' + (j + 1)) 602 | ) 603 | ); 604 | return; 605 | } 606 | } 607 | } 608 | } 609 | } 610 | 611 | if ((getNumberOfSections() > 0) && (getSection(0).workOffset == 0)) { 612 | for (var i = 0; i < getNumberOfSections(); ++i) { 613 | if (getSection(i).workOffset > 0) { 614 | error(localize('Using multiple work offsets is not possible if the initial work offset is 0.')); 615 | return; 616 | } 617 | } 618 | } 619 | 620 | // absolute coordinates and feed per min 621 | writeBlock(gAbsIncModal.format(90)); 622 | writeBlock(gFeedModeModal.format(properties.useG95 ? 95 : 94)); 623 | 624 | writeBlock("G00 Z" + properties.zInitialHeight); 625 | writeBlock("G00 X0 Y0"); 626 | 627 | switch (unit) { 628 | case IN: 629 | writeBlock(gUnitModal.format(20)); 630 | break; 631 | case MM: 632 | writeBlock(gUnitModal.format(21)); 633 | break; 634 | } 635 | 636 | if (properties.useG95) { 637 | feedFormat = createFormat({ 638 | decimals: (unit == MM ? 4 : 5), 639 | forceDecimal: true 640 | }); 641 | feedOutput = createVariable({prefix: 'F'}, feedFormat); 642 | } 643 | } 644 | 645 | function onComment(message) { 646 | var comments = String(message) 647 | .split(';'); 648 | for (comment in comments) { 649 | writeComment(comments[comment]); 650 | } 651 | } 652 | 653 | /** Force output of X, Y, and Z. */ 654 | function forceXYZ() { 655 | xOutput.reset(); 656 | yOutput.reset(); 657 | zOutput.reset(); 658 | } 659 | 660 | /** Force output of A, B, and C. */ 661 | function forceABC() { 662 | aOutput.reset(); 663 | bOutput.reset(); 664 | cOutput.reset(); 665 | } 666 | 667 | function forceFeed() { 668 | previousDPMFeed = 0; 669 | feedOutput.reset(); 670 | } 671 | 672 | /** Force output of X, Y, Z, A, B, C, and F on next output. */ 673 | function forceAny() { 674 | forceXYZ(); 675 | forceABC(); 676 | forceFeed(); 677 | } 678 | 679 | var lengthCompensationActive = false; 680 | var retracted = false; // specifies that the tool has been retracted to the safe plane 681 | 682 | /** Disables length compensation if currently active or if forced. */ 683 | function disableLengthCompensation(force) { 684 | if (lengthCompensationActive || force) { 685 | validate(retracted, 'Cannot cancel length compensation if the machine is not fully retracted.'); 686 | writeBlock(gFormat.format(49)); 687 | lengthCompensationActive = false; 688 | } 689 | } 690 | 691 | var currentSmoothing = false; 692 | 693 | function setSmoothing(mode) { 694 | if (mode == currentSmoothing) { 695 | return false; 696 | } 697 | 698 | // 1) Make sure G49 is called before the execution of G05.1 Q1 Rx 699 | // 2) G05.1 Q1 Rx must be engaged BEFORE G43-Tool Length Comp 700 | // 3) AICC and AIAPC need to be turned on and off for each tool 701 | // 4) AICC and AIAPC does not apply to canned drilling cycles 702 | validate(!lengthCompensationActive, 'Length compensation is active while trying to update smoothing.'); 703 | 704 | currentSmoothing = mode; 705 | writeBlock(gFormat.format(5.1), mode ? 'Q1' : 'Q0'); 706 | return true; 707 | } 708 | 709 | var currentWorkPlaneABC = undefined; 710 | 711 | function forceWorkPlane() { 712 | currentWorkPlaneABC = undefined; 713 | } 714 | 715 | function defineWorkPlane(_section, _setWorkPlane) { 716 | var abc = new Vector(0, 0, 0); 717 | if (forceMultiAxisIndexing || !is3D() || machineConfiguration.isMultiAxisConfiguration()) { // use 5-axis indexing for multi-axis mode 718 | // set working plane after datum shift 719 | 720 | if (_section.isMultiAxis()) { 721 | cancelTransformation(); 722 | abc = _section.getInitialToolAxisABC(); 723 | if (_setWorkPlane) { 724 | if (!retracted) { 725 | writeRetract(Z); 726 | } 727 | forceWorkPlane(); 728 | onCommand(COMMAND_UNLOCK_MULTI_AXIS); 729 | gMotionModal.reset(); 730 | writeBlock( 731 | gMotionModal.format(0), 732 | conditional(machineConfiguration.isMachineCoordinate(0), 'A' + abcFormat.format(abc.x)), 733 | conditional(machineConfiguration.isMachineCoordinate(1), 'B' + abcFormat.format(properties.useClockwise ? abc.y : -abc.y)), 734 | conditional(machineConfiguration.isMachineCoordinate(2), 'C' + abcFormat.format(abc.z)) 735 | ); 736 | } 737 | } else { 738 | if (useMultiAxisFeatures) { 739 | var euler = currentSection.workPlane.getEuler2(EULER_ZXZ_R); 740 | abc = new Vector(euler.x, euler.y, euler.z); 741 | cancelTransformation(); 742 | } else { 743 | abc = getWorkPlaneMachineABC(_section.workPlane, _setWorkPlane, true); 744 | } 745 | if (_setWorkPlane) { 746 | setWorkPlane(abc); 747 | } 748 | } 749 | } else { // pure 3D 750 | var remaining = _section.workPlane; 751 | if (!isSameDirection(remaining.forward, new Vector(0, 0, 1))) { 752 | error(localize('Tool orientation is not supported.')); 753 | return abc; 754 | } 755 | setRotation(remaining); 756 | } 757 | return abc; 758 | } 759 | 760 | function cancelWorkPlane() { 761 | writeBlock(gRotationModal.format(69)); // cancel frame 762 | forceWorkPlane(); 763 | } 764 | 765 | function setWorkPlane(abc) { 766 | if (!forceMultiAxisIndexing && is3D() && !machineConfiguration.isMultiAxisConfiguration()) { 767 | return; // ignore 768 | } 769 | 770 | if (!((currentWorkPlaneABC == undefined) || 771 | abcFormat.areDifferent(abc.x, currentWorkPlaneABC.x) || 772 | abcFormat.areDifferent(abc.y, currentWorkPlaneABC.y) || 773 | abcFormat.areDifferent(abc.z, currentWorkPlaneABC.z))) { 774 | return; // no change 775 | } 776 | 777 | onCommand(COMMAND_UNLOCK_MULTI_AXIS); 778 | if (!retracted) { 779 | writeRetract(Z); 780 | } 781 | 782 | if (useMultiAxisFeatures) { 783 | if (cancelTiltFirst) { 784 | cancelWorkPlane(); 785 | } 786 | if (machineConfiguration.isMultiAxisConfiguration() && useABCPrepositioning) { 787 | var angles = abc.isNonZero() ? getWorkPlaneMachineABC(currentSection.workPlane, false, false) : abc; 788 | 789 | gMotionModal.reset(); 790 | writeBlock( 791 | gMotionModal.format(0), 792 | conditional(machineConfiguration.isMachineCoordinate(0), 'A' + abcFormat.format(angles.x)), 793 | conditional(machineConfiguration.isMachineCoordinate(1), 'B' + abcFormat.format(properties.useClockwise ? angles.y: -angles.y)), 794 | conditional(machineConfiguration.isMachineCoordinate(2), 'C' + abcFormat.format(angles.z)) 795 | ); 796 | } 797 | if (abc.isNonZero()) { 798 | 799 | gRotationModal.reset(); 800 | writeBlock(gRotationModal.format(68.2), 'X' + xyzFormat.format(0), 'Y' + xyzFormat.format(0), 'Z' + xyzFormat.format(0), 801 | 'A' + abcFormat.format(abc.x), 'B' + abcFormat.format(properties.useClockwise ? abc.y : -abc.y), 'C' + abcFormat.format(abc.z)); // set frame 802 | writeBlock(gFormat.format(53.1)); // turn machine 803 | } else { 804 | if (!cancelTiltFirst) { 805 | cancelWorkPlane(); 806 | } 807 | } 808 | } else { 809 | 810 | gMotionModal.reset(); 811 | writeBlock( 812 | gMotionModal.format(0), 813 | conditional(machineConfiguration.isMachineCoordinate(0), 'A' + abcFormat.format(abc.x)), 814 | conditional(machineConfiguration.isMachineCoordinate(1), 'B' + abcFormat.format(properties.useClockwise ? abc.y : -abc.y)), 815 | conditional(machineConfiguration.isMachineCoordinate(2), 'C' + abcFormat.format(abc.z)) 816 | ); 817 | } 818 | 819 | onCommand(COMMAND_LOCK_MULTI_AXIS); 820 | 821 | currentWorkPlaneABC = abc; 822 | } 823 | 824 | var closestABC = false; // choose closest machine angles 825 | var currentMachineABC; 826 | 827 | function getWorkPlaneMachineABC(workPlane, _setWorkPlane, rotate) { 828 | var W = workPlane; // map to global frame 829 | 830 | var abc = machineConfiguration.getABC(W); 831 | if (closestABC) { 832 | if (currentMachineABC) { 833 | abc = machineConfiguration.remapToABC(abc, currentMachineABC); 834 | } else { 835 | abc = machineConfiguration.getPreferredABC(abc); 836 | } 837 | } else { 838 | abc = machineConfiguration.getPreferredABC(abc); 839 | } 840 | 841 | try { 842 | abc = machineConfiguration.remapABC(abc); 843 | if (_setWorkPlane) { 844 | currentMachineABC = abc; 845 | } 846 | } catch (e) { 847 | error( 848 | localize('Machine angles not supported') + ':' 849 | + conditional(machineConfiguration.isMachineCoordinate(0), ' A' + abcFormat.format(abc.x)) 850 | + conditional(machineConfiguration.isMachineCoordinate(1), ' B' + abcFormat.format(properties.useClockwise ? abc.y : -abc.y)) 851 | + conditional(machineConfiguration.isMachineCoordinate(2), ' C' + abcFormat.format(abc.z)) 852 | ); 853 | } 854 | 855 | var direction = machineConfiguration.getDirection(abc); 856 | if (!isSameDirection(direction, W.forward)) { 857 | error(localize('Orientation not supported.')); 858 | } 859 | 860 | if (!machineConfiguration.isABCSupported(abc)) { 861 | error( 862 | localize('Work plane is not supported') + ':' 863 | + conditional(machineConfiguration.isMachineCoordinate(0), ' A' + abcFormat.format(abc.x)) 864 | + conditional(machineConfiguration.isMachineCoordinate(1), ' B' + abcFormat.format(properties.useClockwise ? abc.y : -abc.y)) 865 | + conditional(machineConfiguration.isMachineCoordinate(2), ' C' + abcFormat.format(abc.z)) 866 | ); 867 | } 868 | 869 | if (rotate) { 870 | var tcp = false; 871 | if (tcp) { 872 | setRotation(W); // TCP mode 873 | } else { 874 | var O = machineConfiguration.getOrientation(abc); 875 | var R = machineConfiguration.getRemainingOrientation(abc, W); 876 | setRotation(R); 877 | } 878 | } 879 | 880 | return abc; 881 | } 882 | 883 | function isProbeOperation() { 884 | return hasParameter('operation-strategy') && (getParameter('operation-strategy') == 'probe'); 885 | } 886 | 887 | var probeOutputWorkOffset = 1; 888 | 889 | function onParameter(name, value) { 890 | if (name == 'probe-output-work-offset') { 891 | probeOutputWorkOffset = (value > 0) ? value : 1; 892 | } 893 | } 894 | 895 | /** Returns true if the spatial vectors are significantly different. */ 896 | function areSpatialVectorsDifferent(_vector1, _vector2) { 897 | return (xyzFormat.getResultingValue(_vector1.x) != xyzFormat.getResultingValue(_vector2.x)) || 898 | (xyzFormat.getResultingValue(_vector1.y) != xyzFormat.getResultingValue(_vector2.y)) || 899 | (xyzFormat.getResultingValue(_vector1.z) != xyzFormat.getResultingValue(_vector2.z)); 900 | } 901 | 902 | /** Returns true if the spatial boxes are a pure translation. */ 903 | function areSpatialBoxesTranslated(_box1, _box2) { 904 | return !areSpatialVectorsDifferent(Vector.diff(_box1[1], _box1[0]), Vector.diff(_box2[1], _box2[0])) && 905 | !areSpatialVectorsDifferent(Vector.diff(_box2[0], _box1[0]), Vector.diff(_box2[1], _box1[1])); 906 | } 907 | 908 | function subprogramDefine(_initialPosition, _abc, _retracted, _zIsOutput) { 909 | // convert patterns into subprograms 910 | var usePattern = false; 911 | patternIsActive = false; 912 | if (currentSection.isPatterned && currentSection.isPatterned() && properties.useSubroutinePatterns) { 913 | currentPattern = currentSection.getPatternId(); 914 | firstPattern = true; 915 | for (var i = 0; i < definedPatterns.length; ++i) { 916 | if ((definedPatterns[i].patternType == SUB_PATTERN) && (currentPattern == definedPatterns[i].patternId)) { 917 | currentSubprogram = definedPatterns[i].subProgram; 918 | usePattern = definedPatterns[i].validPattern; 919 | firstPattern = false; 920 | break; 921 | } 922 | } 923 | 924 | if (firstPattern) { 925 | // determine if this is a valid pattern for creating a subprogram 926 | usePattern = subprogramIsValid(currentSection, currentPattern, SUB_PATTERN); 927 | if (usePattern) { 928 | currentSubprogram = ++lastSubprogram; 929 | } 930 | definedPatterns.push({ 931 | patternType: SUB_PATTERN, 932 | patternId: currentPattern, 933 | subProgram: currentSubprogram, 934 | validPattern: usePattern, 935 | initialPosition: _initialPosition, 936 | finalPosition: _initialPosition 937 | }); 938 | } 939 | 940 | if (usePattern) { 941 | // make sure Z-position is output prior to subprogram call 942 | if (!_retracted && !_zIsOutput) { 943 | writeBlock(gMotionModal.format(0), zOutput.format(_initialPosition.z)); 944 | } 945 | 946 | // call subprogram 947 | writeBlock(mFormat.format(98), 'P' + oFormat.format(currentSubprogram)); 948 | patternIsActive = true; 949 | 950 | if (firstPattern) { 951 | subprogramStart(_initialPosition, _abc, true); 952 | } else { 953 | skipRemainingSection(); 954 | setCurrentPosition(getFramePosition(currentSection.getFinalPosition())); 955 | } 956 | } 957 | } 958 | 959 | // Output cycle operation as subprogram 960 | if (!usePattern && properties.useSubroutineCycles && currentSection.doesStrictCycle && 961 | (currentSection.getNumberOfCycles() == 1) && currentSection.getNumberOfCyclePoints() >= minimumCyclePoints) { 962 | var finalPosition = getFramePosition(currentSection.getFinalPosition()); 963 | currentPattern = currentSection.getNumberOfCyclePoints(); 964 | firstPattern = true; 965 | for (var i = 0; i < definedPatterns.length; ++i) { 966 | if ((definedPatterns[i].patternType == SUB_CYCLE) && (currentPattern == definedPatterns[i].patternId) && 967 | !areSpatialVectorsDifferent(_initialPosition, definedPatterns[i].initialPosition) && 968 | !areSpatialVectorsDifferent(finalPosition, definedPatterns[i].finalPosition)) { 969 | currentSubprogram = definedPatterns[i].subProgram; 970 | usePattern = definedPatterns[i].validPattern; 971 | firstPattern = false; 972 | break; 973 | } 974 | } 975 | 976 | if (firstPattern) { 977 | // determine if this is a valid pattern for creating a subprogram 978 | usePattern = subprogramIsValid(currentSection, currentPattern, SUB_CYCLE); 979 | if (usePattern) { 980 | currentSubprogram = ++lastSubprogram; 981 | } 982 | definedPatterns.push({ 983 | patternType: SUB_CYCLE, 984 | patternId: currentPattern, 985 | subProgram: currentSubprogram, 986 | validPattern: usePattern, 987 | initialPosition: _initialPosition, 988 | finalPosition: finalPosition 989 | }); 990 | } 991 | cycleSubprogramIsActive = usePattern; 992 | } 993 | 994 | // Output each operation as a subprogram 995 | if (!usePattern && properties.useSubroutines) { 996 | currentSubprogram = ++lastSubprogram; 997 | writeBlock(mFormat.format(98), 'P' + oFormat.format(currentSubprogram)); 998 | firstPattern = true; 999 | subprogramStart(_initialPosition, _abc, false); 1000 | } 1001 | } 1002 | 1003 | function subprogramStart(_initialPosition, _abc, _incremental) { 1004 | redirectToBuffer(); 1005 | var comment = ''; 1006 | if (hasParameter('operation-comment')) { 1007 | comment = getParameter('operation-comment'); 1008 | } 1009 | writeln( 1010 | 'O' + oFormat.format(currentSubprogram) + 1011 | conditional(comment, formatComment(comment.substr(0, maximumLineLength - 2 - 6 - 1))) 1012 | ); 1013 | saveShowSequenceNumbers = properties.showSequenceNumbers; 1014 | properties.showSequenceNumbers = false; 1015 | if (_incremental) { 1016 | setIncrementalMode(_initialPosition, _abc); 1017 | } 1018 | gPlaneModal.reset(); 1019 | gMotionModal.reset(); 1020 | } 1021 | 1022 | function subprogramEnd() { 1023 | if (firstPattern) { 1024 | writeBlock(mFormat.format(99)); 1025 | writeln(''); 1026 | subprograms += getRedirectionBuffer(); 1027 | } 1028 | forceAny(); 1029 | firstPattern = false; 1030 | properties.showSequenceNumbers = saveShowSequenceNumbers; 1031 | closeRedirection(); 1032 | } 1033 | 1034 | function subprogramIsValid(_section, _patternId, _patternType) { 1035 | var sectionId = _section.getId(); 1036 | var numberOfSections = getNumberOfSections(); 1037 | var validSubprogram = _patternType != SUB_CYCLE; 1038 | 1039 | var masterPosition = new Array(); 1040 | masterPosition[0] = getFramePosition(_section.getInitialPosition()); 1041 | masterPosition[1] = getFramePosition(_section.getFinalPosition()); 1042 | var tempBox = _section.getBoundingBox(); 1043 | var masterBox = new Array(); 1044 | masterBox[0] = getFramePosition(tempBox[0]); 1045 | masterBox[1] = getFramePosition(tempBox[1]); 1046 | 1047 | var rotation = getRotation(); 1048 | var translation = getTranslation(); 1049 | 1050 | for (var i = 0; i < numberOfSections; ++i) { 1051 | var section = getSection(i); 1052 | if (section.getId() != sectionId) { 1053 | defineWorkPlane(section, false); 1054 | // check for valid pattern 1055 | if (_patternType == SUB_PATTERN) { 1056 | if (section.getPatternId() == _patternId) { 1057 | var patternPosition = new Array(); 1058 | patternPosition[0] = getFramePosition(section.getInitialPosition()); 1059 | patternPosition[1] = getFramePosition(section.getFinalPosition()); 1060 | tempBox = section.getBoundingBox(); 1061 | var patternBox = new Array(); 1062 | patternBox[0] = getFramePosition(tempBox[0]); 1063 | patternBox[1] = getFramePosition(tempBox[1]); 1064 | 1065 | if (!areSpatialBoxesTranslated(masterPosition, patternPosition) || !areSpatialBoxesTranslated(masterBox, patternBox)) { 1066 | validSubprogram = false; 1067 | break; 1068 | } 1069 | } 1070 | 1071 | // check for valid cycle operation 1072 | } else if (_patternType == SUB_CYCLE) { 1073 | if ((section.getNumberOfCyclePoints() == _patternId) && (section.getNumberOfCycles() == 1)) { 1074 | var patternInitial = getFramePosition(section.getInitialPosition()); 1075 | var patternFinal = getFramePosition(section.getFinalPosition()); 1076 | if (!areSpatialVectorsDifferent(patternInitial, masterPosition[0]) && !areSpatialVectorsDifferent(patternFinal, masterPosition[1])) { 1077 | validSubprogram = true; 1078 | break; 1079 | } 1080 | } 1081 | } 1082 | } 1083 | } 1084 | setRotation(rotation); 1085 | setTranslation(translation); 1086 | return (validSubprogram); 1087 | } 1088 | 1089 | function setAxisMode(_format, _output, _prefix, _value, _incr) { 1090 | var i = _output.isEnabled(); 1091 | _output = _incr ? createIncrementalVariable({prefix: _prefix}, _format) : createVariable({prefix: _prefix}, _format); 1092 | _output.format(_value); 1093 | _output.format(_value); 1094 | i = i ? _output.enable() : _output.disable(); 1095 | return _output; 1096 | } 1097 | 1098 | function setIncrementalMode(xyz, abc) { 1099 | xOutput = setAxisMode(xyzFormat, xOutput, 'X', xyz.x, true); 1100 | yOutput = setAxisMode(xyzFormat, yOutput, 'Y', xyz.y, true); 1101 | zOutput = setAxisMode(xyzFormat, zOutput, 'Z', xyz.z, true); 1102 | aOutput = setAxisMode(abcFormat, aOutput, 'A', abc.x, true); 1103 | bOutput = setAxisMode(abcFormat, bOutput, 'B', abc.y, true); 1104 | cOutput = setAxisMode(abcFormat, cOutput, 'C', abc.z, true); 1105 | gAbsIncModal.reset(); 1106 | writeBlock(gAbsIncModal.format(91)); 1107 | incrementalMode = true; 1108 | } 1109 | 1110 | function setAbsoluteMode(xyz, abc) { 1111 | if (incrementalMode) { 1112 | xOutput = setAxisMode(xyzFormat, xOutput, 'X', xyz.x, false); 1113 | yOutput = setAxisMode(xyzFormat, yOutput, 'Y', xyz.y, false); 1114 | zOutput = setAxisMode(xyzFormat, zOutput, 'Z', xyz.z, false); 1115 | aOutput = setAxisMode(abcFormat, aOutput, 'A', abc.x, false); 1116 | bOutput = setAxisMode(abcFormat, bOutput, 'B', abc.y, false); 1117 | cOutput = setAxisMode(abcFormat, cOutput, 'C', abc.z, false); 1118 | gAbsIncModal.reset(); 1119 | writeBlock(gAbsIncModal.format(90)); 1120 | incrementalMode = false; 1121 | } 1122 | } 1123 | 1124 | function onSection() { 1125 | var forceToolAndRetract = optionalSection && !currentSection.isOptional(); 1126 | optionalSection = currentSection.isOptional(); 1127 | 1128 | var insertToolCall = forceToolAndRetract || isFirstSection() || 1129 | currentSection.getForceToolChange && currentSection.getForceToolChange() || 1130 | (tool.number != getPreviousSection() 1131 | .getTool().number); 1132 | 1133 | var newWorkOffset = isFirstSection() || 1134 | (getPreviousSection().workOffset != currentSection.workOffset); // work offset changes 1135 | var newWorkPlane = isFirstSection() || 1136 | !isSameDirection(getPreviousSection() 1137 | .getGlobalFinalToolAxis(), currentSection.getGlobalInitialToolAxis()) || 1138 | (currentSection.isOptimizedForMachine() && getPreviousSection() 1139 | .isOptimizedForMachine() && 1140 | Vector.diff(getPreviousSection() 1141 | .getFinalToolAxisABC(), currentSection.getInitialToolAxisABC()).length > 1e-4) || 1142 | (!machineConfiguration.isMultiAxisConfiguration() && currentSection.isMultiAxis()) || 1143 | (!getPreviousSection() 1144 | .isMultiAxis() && currentSection.isMultiAxis() || 1145 | getPreviousSection() 1146 | .isMultiAxis() && !currentSection.isMultiAxis()); // force newWorkPlane between indexing and simultaneous operations 1147 | var forceSmoothing = properties.useSmoothing && 1148 | (hasParameter('operation-strategy') && (getParameter('operation-strategy') == 'drill') || 1149 | !isFirstSection() && getPreviousSection() 1150 | .hasParameter('operation-strategy') && (getPreviousSection() 1151 | .getParameter('operation-strategy') == 'drill')); // force smoothing in case !insertToolCall (2d chamfer) 1152 | var zIsOutput = false; // true if the Z-position has been output, used for patterns 1153 | 1154 | if (insertToolCall || newWorkOffset || newWorkPlane || forceSmoothing) { 1155 | 1156 | // stop spindle before retract during tool change 1157 | if (insertToolCall && !isFirstSection()) { 1158 | onCommand(COMMAND_STOP_SPINDLE); 1159 | } 1160 | 1161 | // retract to safe plane 1162 | writeRetract(Z); 1163 | forceXYZ(); 1164 | if ((insertToolCall && !isFirstSection()) || forceSmoothing) { 1165 | disableLengthCompensation(); 1166 | setSmoothing(false); 1167 | } 1168 | } 1169 | 1170 | if (hasParameter('operation-comment')) { 1171 | var comment = getParameter('operation-comment'); 1172 | if (comment && ((comment !== lastOperationComment) || !patternIsActive || insertToolCall)) { 1173 | writeln(''); 1174 | writeComment(comment); 1175 | lastOperationComment = comment; 1176 | } else if (!patternIsActive || insertToolCall) { 1177 | writeln(''); 1178 | } 1179 | } else { 1180 | writeln(''); 1181 | } 1182 | 1183 | if (properties.showNotes && hasParameter('notes')) { 1184 | var notes = getParameter('notes'); 1185 | if (notes) { 1186 | var lines = String(notes) 1187 | .split('\n'); 1188 | var r1 = new RegExp('^[\\s]+', 'g'); 1189 | var r2 = new RegExp('[\\s]+$', 'g'); 1190 | for (line in lines) { 1191 | var comment = lines[line].replace(r1, '') 1192 | .replace(r2, ''); 1193 | if (comment) { 1194 | writeComment(comment); 1195 | } 1196 | } 1197 | } 1198 | } 1199 | 1200 | if (insertToolCall) { 1201 | forceWorkPlane(); 1202 | 1203 | setCoolant(COOLANT_OFF); 1204 | 1205 | if (!isFirstSection() && properties.optionalStop) { 1206 | onCommand(COMMAND_OPTIONAL_STOP); 1207 | } 1208 | 1209 | if (tool.number > 99) { 1210 | warning(localize('Tool number exceeds maximum value.')); 1211 | } 1212 | 1213 | disableLengthCompensation(); 1214 | // writeBlock("T" + toolFormat.format(tool.number), mFormat.format(6)); 1215 | if (tool.comment) { 1216 | writeComment(tool.comment); 1217 | } 1218 | var showToolZMin = false; 1219 | if (showToolZMin) { 1220 | if (is3D()) { 1221 | var numberOfSections = getNumberOfSections(); 1222 | var zRange = currentSection.getGlobalZRange(); 1223 | var number = tool.number; 1224 | for (var i = currentSection.getId() + 1; i < numberOfSections; ++i) { 1225 | var section = getSection(i); 1226 | if (section.getTool().number != number) { 1227 | break; 1228 | } 1229 | zRange.expandToRange(section.getGlobalZRange()); 1230 | } 1231 | writeComment(localize('ZMIN') + '=' + zRange.getMinimum()); 1232 | } 1233 | } 1234 | 1235 | if (properties.preloadTool) { 1236 | var nextTool = getNextTool(tool.number); 1237 | if (nextTool) { 1238 | writeBlock('T' + toolFormat.format(nextTool.number)); 1239 | } else { 1240 | // preload first tool 1241 | var section = getSection(0); 1242 | var firstToolNumber = section.getTool().number; 1243 | if (tool.number != firstToolNumber) { 1244 | writeBlock('T' + toolFormat.format(firstToolNumber)); 1245 | } 1246 | } 1247 | } 1248 | } 1249 | 1250 | if (!isProbeOperation() && 1251 | (insertToolCall || 1252 | forceSpindleSpeed || 1253 | isFirstSection() || 1254 | (rpmFormat.areDifferent(spindleSpeed, sOutput.getCurrent())) || 1255 | (tool.clockwise != getPreviousSection() 1256 | .getTool().clockwise))) { 1257 | forceSpindleSpeed = false; 1258 | 1259 | if (spindleSpeed < 1) { 1260 | error(localize('Spindle speed out of range.')); 1261 | return; 1262 | } 1263 | if (spindleSpeed > 99999) { 1264 | warning(localize('Spindle speed exceeds maximum value.')); 1265 | } 1266 | var tapping = hasParameter('operation:cycleType') && 1267 | ((getParameter('operation:cycleType') == 'tapping') || 1268 | (getParameter('operation:cycleType') == 'right-tapping') || 1269 | (getParameter('operation:cycleType') == 'left-tapping') || 1270 | (getParameter('operation:cycleType') == 'tapping-with-chip-breaking')); 1271 | if (!tapping || (tapping && !(properties.useRigidTapping == 'without'))) { 1272 | var initialPosition = getFramePosition(currentSection.getInitialPosition()); 1273 | writeBlock(gMotionModal.format(0), zOutput.format(initialPosition.z)); 1274 | writeBlock( 1275 | mFormat.format(tool.clockwise ? 3 : 4), sOutput.format(spindleSpeed) 1276 | ); 1277 | } 1278 | 1279 | onCommand(COMMAND_START_CHIP_TRANSPORT); 1280 | if (forceMultiAxisIndexing || !is3D() || machineConfiguration.isMultiAxisConfiguration()) { 1281 | // writeBlock(mFormat.format(xxx)); // shortest path traverse 1282 | } 1283 | } 1284 | 1285 | // wcs 1286 | if (insertToolCall) { // force work offset when changing tool 1287 | currentWorkOffset = undefined; 1288 | } 1289 | var workOffset = currentSection.workOffset; 1290 | if (workOffset == 0) { 1291 | warningOnce(localize('Work offset has not been specified. Using G54 as WCS.'), WARNING_WORK_OFFSET); 1292 | workOffset = 1; 1293 | } 1294 | if (workOffset != currentWorkOffset) { 1295 | if (cancelTiltFirst) { 1296 | cancelWorkPlane(); 1297 | } 1298 | forceWorkPlane(); 1299 | } 1300 | if (workOffset > 0) { 1301 | if (workOffset > 6) { 1302 | var p = workOffset - 6; // 1->... 1303 | if (p > 300) { 1304 | error(localize('Work offset out of range.')); 1305 | return; 1306 | } else { 1307 | if (workOffset != currentWorkOffset) { 1308 | writeBlock(gFormat.format(54.1), 'P' + p); // G54.1P 1309 | currentWorkOffset = workOffset; 1310 | } 1311 | } 1312 | } else { 1313 | if (workOffset != currentWorkOffset) { 1314 | // writeBlock(gFormat.format(53 + workOffset)); // G54->G59 1315 | currentWorkOffset = workOffset; 1316 | } 1317 | } 1318 | } 1319 | 1320 | forceXYZ(); 1321 | 1322 | var abc = defineWorkPlane(currentSection, true); 1323 | 1324 | // set coolant after we have positioned at Z 1325 | // setCoolant(tool.coolant); 1326 | 1327 | if (properties.useSmoothing) { 1328 | if (hasParameter('operation-strategy') && (getParameter('operation-strategy') != 'drill')) { 1329 | if (setSmoothing(true)) { 1330 | // we force G43 using lengthCompensationActive 1331 | } 1332 | } else { 1333 | if (setSmoothing(false)) { 1334 | // we force G43 using lengthCompensationActive 1335 | } 1336 | } 1337 | } 1338 | 1339 | forceAny(); 1340 | gMotionModal.reset(); 1341 | 1342 | var initialPosition = getFramePosition(currentSection.getInitialPosition()); 1343 | if (!retracted && !insertToolCall) { 1344 | if (getCurrentPosition().z < initialPosition.z) { 1345 | writeBlock(gMotionModal.format(0), zOutput.format(initialPosition.z)); 1346 | zIsOutput = true; 1347 | } 1348 | } 1349 | 1350 | if (insertToolCall || !lengthCompensationActive || retracted || (!isFirstSection() && getPreviousSection() 1351 | .isMultiAxis())) { 1352 | var lengthOffset = tool.lengthOffset; 1353 | if (lengthOffset > 99) { 1354 | error(localize('Length offset out of range.')); 1355 | return; 1356 | } 1357 | gMotionModal.reset(); 1358 | // writeBlock(gPlaneModal.format(17)); 1359 | 1360 | if (!machineConfiguration.isHeadConfiguration()) { 1361 | writeBlock( 1362 | gAbsIncModal.format(90), 1363 | gMotionModal.format(0), xOutput.format(initialPosition.x), yOutput.format(initialPosition.y) 1364 | ); 1365 | // writeBlock(gMotionModal.format(0), gFormat.format(43), zOutput.format(initialPosition.z), hFormat.format(lengthOffset)); 1366 | lengthCompensationActive = true; 1367 | } else { 1368 | writeBlock( 1369 | gAbsIncModal.format(90), 1370 | gMotionModal.format(0), 1371 | gFormat.format(43), xOutput.format(initialPosition.x), 1372 | yOutput.format(initialPosition.y), 1373 | zOutput.format(initialPosition.z), hFormat.format(lengthOffset) 1374 | ); 1375 | lengthCompensationActive = true; 1376 | } 1377 | zIsOutput = true; 1378 | gMotionModal.reset(); 1379 | } else { 1380 | writeBlock( 1381 | gAbsIncModal.format(90), 1382 | gMotionModal.format(0), 1383 | xOutput.format(initialPosition.x), 1384 | yOutput.format(initialPosition.y) 1385 | ); 1386 | } 1387 | 1388 | validate(lengthCompensationActive, 'Length compensation is not active.'); 1389 | 1390 | if (isProbeOperation()) { 1391 | if (g68RotationMode != 0) { 1392 | error(localize('You cannot probe while G68 Rotation is in effect.')); 1393 | return; 1394 | } 1395 | angularProbingMode = getAngularProbingMode(); 1396 | writeBlock(gFormat.format(65), 'P' + 9832); // spin the probe on 1397 | } 1398 | 1399 | // define subprogram 1400 | subprogramDefine(initialPosition, abc, retracted, zIsOutput); 1401 | 1402 | retracted = false; 1403 | } 1404 | 1405 | function onDwell(seconds) { 1406 | if (seconds > 99999.999) { 1407 | warning(localize('Dwelling time is out of range.')); 1408 | } 1409 | milliseconds = clamp(1, seconds * 1000, 99999999); 1410 | writeBlock(gFeedModeModal.format(94), gFormat.format(4), 'P' + milliFormat.format(milliseconds)); 1411 | writeBlock(gFeedModeModal.format(properties.useG95 ? 95 : 94)); // back to G95 1412 | } 1413 | 1414 | function onSpindleSpeed(spindleSpeed) { 1415 | writeBlock(sOutput.format(spindleSpeed)); 1416 | } 1417 | 1418 | function onCycle() { 1419 | writeBlock(gPlaneModal.format(17)); 1420 | } 1421 | 1422 | function getCommonCycle(x, y, z, r, c) { 1423 | forceXYZ(); // force xyz on first drill hole of any cycle 1424 | if (incrementalMode) { 1425 | zOutput.format(c); 1426 | return [xOutput.format(x), yOutput.format(y), 1427 | 'Z' + xyzFormat.format(z - r), 1428 | 'R' + xyzFormat.format(r - c)]; 1429 | } else { 1430 | return [xOutput.format(x), yOutput.format(y), 1431 | zOutput.format(z), 1432 | 'R' + xyzFormat.format(r)]; 1433 | } 1434 | } 1435 | 1436 | function setCyclePosition(_position) { 1437 | switch (gPlaneModal.getCurrent()) { 1438 | case 17: // XY 1439 | zOutput.format(_position); 1440 | break; 1441 | case 18: // ZX 1442 | yOutput.format(_position); 1443 | break; 1444 | case 19: // YZ 1445 | xOutput.format(_position); 1446 | break; 1447 | } 1448 | } 1449 | 1450 | /** Convert approach to sign. */ 1451 | function approach(value) { 1452 | validate((value == 'positive') || (value == 'negative'), 'Invalid approach.'); 1453 | return (value == 'positive') ? 1 : -1; 1454 | } 1455 | 1456 | /** 1457 | Determine if angular probing is supported 1458 | */ 1459 | function getAngularProbingMode() { 1460 | if (machineConfiguration.isMultiAxisConfiguration()) { 1461 | if (machineConfiguration.isMachineCoordinate(2)) { 1462 | return ANGLE_PROBE_USE_CAXIS; 1463 | } else { 1464 | return ANGLE_PROBE_NOT_SUPPORTED; 1465 | } 1466 | } else { 1467 | return ANGLE_PROBE_USE_ROTATION; 1468 | } 1469 | } 1470 | 1471 | /** 1472 | Output rotation offset based on angular probing cycle. 1473 | */ 1474 | function setProbingAngle() { 1475 | if ((g68RotationMode == 1) || (g68RotationMode == 2)) { // Rotate coordinate system for Angle Probing 1476 | if (!properties.useG54x4) { 1477 | gRotationModal.reset(); 1478 | gAbsIncModal.reset(); 1479 | writeBlock( 1480 | gRotationModal.format(68), gAbsIncModal.format(90), 1481 | (g68RotationMode == 1) ? 'X0' : 'X[#135]', 1482 | (g68RotationMode == 1) ? 'Y0' : 'Y[#136]', 1483 | 'Z0', 'I0.0', 'J0.0', 'K1.0', 'R[#139]' 1484 | ); 1485 | g68RotationMode = 3; 1486 | } else if (angularProbingMode != ANGLE_PROBE_NOT_SUPPORTED) { 1487 | writeBlock('#26010=#135'); 1488 | writeBlock('#26011=#136'); 1489 | writeBlock('#26012=#137'); 1490 | writeBlock('#26015=#139'); 1491 | writeBlock(gFormat.format(54.4), 'P1'); 1492 | g68RotationMode = 0; 1493 | } else { 1494 | error(localize('Angular probing is not supported for this machine configuration.')); 1495 | return; 1496 | } 1497 | } 1498 | } 1499 | 1500 | function onCyclePoint(x, y, z) { 1501 | if (!isSameDirection(getRotation().forward, new Vector(0, 0, 1))) { 1502 | expandCyclePoint(x, y, z); 1503 | return; 1504 | } 1505 | var probeWorkOffsetCode; 1506 | if (isProbeOperation()) { 1507 | if (!useMultiAxisFeatures && !isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, 1)) && (!cycle.probeMode || (cycle.probeMode == 0))) { 1508 | error(localize('Updating WCS / work offset using probing is only supported by the CNC in the WCS frame.')); 1509 | return; 1510 | } 1511 | 1512 | var workOffset = probeOutputWorkOffset ? probeOutputWorkOffset : currentWorkOffset; 1513 | if (workOffset > 99) { 1514 | error(localize('Work offset is out of range.')); 1515 | return; 1516 | } else if (workOffset > 6) { 1517 | probeWorkOffsetCode = probe100Format.format(workOffset - 6 + 100); 1518 | } else { 1519 | probeWorkOffsetCode = workOffset + '.'; // G54->G59 1520 | } 1521 | } 1522 | 1523 | if (isFirstCyclePoint()) { 1524 | repositionToCycleClearance(cycle, x, y, z); 1525 | 1526 | // return to initial Z which is clearance plane and set absolute mode 1527 | 1528 | var F = cycle.feedrate; 1529 | if (properties.useG95) { 1530 | F /= spindleSpeed; 1531 | } 1532 | var P = !cycle.dwell ? 0 : clamp(1, cycle.dwell * 1000, 99999999); // in milliseconds 1533 | 1534 | switch (cycleType) { 1535 | case 'drilling': 1536 | writeBlock( 1537 | gRetractModal.format(98), gCycleModal.format(81), 1538 | getCommonCycle(x, y, z, cycle.retract, cycle.clearance), 1539 | feedOutput.format(F) 1540 | ); 1541 | break; 1542 | case 'counter-boring': 1543 | if (P > 0) { 1544 | writeBlock( 1545 | gRetractModal.format(98), gCycleModal.format(82), 1546 | getCommonCycle(x, y, z, cycle.retract, cycle.clearance), 1547 | 'P' + milliFormat.format(P), 1548 | feedOutput.format(F) 1549 | ); 1550 | } else { 1551 | writeBlock( 1552 | gRetractModal.format(98), gCycleModal.format(81), 1553 | getCommonCycle(x, y, z, cycle.retract, cycle.clearance), 1554 | feedOutput.format(F) 1555 | ); 1556 | } 1557 | break; 1558 | case 'chip-breaking': 1559 | // cycle.accumulatedDepth is ignored 1560 | if (P > 0) { 1561 | expandCyclePoint(x, y, z); 1562 | } else { 1563 | writeBlock( 1564 | gRetractModal.format(98), gCycleModal.format(73), 1565 | getCommonCycle(x, y, z, cycle.retract, cycle.clearance), 1566 | 'Q' + xyzFormat.format(cycle.incrementalDepth), 1567 | feedOutput.format(F) 1568 | ); 1569 | } 1570 | break; 1571 | case 'deep-drilling': 1572 | if (P > 0) { 1573 | expandCyclePoint(x, y, z); 1574 | } else { 1575 | writeBlock( 1576 | gRetractModal.format(98), gCycleModal.format(83), 1577 | getCommonCycle(x, y, z, cycle.retract, cycle.clearance), 1578 | 'Q' + xyzFormat.format(cycle.incrementalDepth), 1579 | // conditional(P > 0, "P" + milliFormat.format(P)), 1580 | feedOutput.format(F) 1581 | ); 1582 | } 1583 | break; 1584 | case 'tapping': 1585 | if (properties.useRigidTapping != 'no') { 1586 | writeBlock(mFormat.format(29), sOutput.format(spindleSpeed)); 1587 | } 1588 | if (properties.usePitchForTapping) { 1589 | writeBlock( 1590 | gRetractModal.format(98), gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND) ? 74 : 84), 1591 | getCommonCycle(x, y, z, cycle.retract, cycle.clearance), 1592 | 'P' + milliFormat.format(P), 1593 | pitchOutput.format(tool.threadPitch) 1594 | ); 1595 | forceFeed(); 1596 | } else { 1597 | var tappingFPM = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); 1598 | F = (properties.useG95 ? tool.getThreadPitch() : tappingFPM); 1599 | writeBlock( 1600 | gRetractModal.format(98), gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND) ? 74 : 84), 1601 | getCommonCycle(x, y, z, cycle.retract, cycle.clearance), 1602 | 'P' + milliFormat.format(P), 1603 | feedOutput.format(F) 1604 | ); 1605 | } 1606 | break; 1607 | case 'left-tapping': 1608 | if (properties.useRigidTapping != 'no') { 1609 | writeBlock(mFormat.format(29), sOutput.format(spindleSpeed)); 1610 | } 1611 | if (properties.usePitchForTapping) { 1612 | writeBlock( 1613 | gRetractModal.format(98), gCycleModal.format(74), 1614 | getCommonCycle(x, y, z, cycle.retract, cycle.clearance), 1615 | 'P' + milliFormat.format(P), 1616 | pitchOutput.format(tool.threadPitch) 1617 | ); 1618 | forceFeed(); 1619 | } else { 1620 | var tappingFPM = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); 1621 | F = (properties.useG95 ? tool.getThreadPitch() : tappingFPM); 1622 | writeBlock( 1623 | gRetractModal.format(98), gCycleModal.format(74), 1624 | getCommonCycle(x, y, z, cycle.retract, cycle.clearance), 1625 | 'P' + milliFormat.format(P), 1626 | feedOutput.format(F) 1627 | ); 1628 | } 1629 | break; 1630 | case 'right-tapping': 1631 | if (properties.useRigidTapping != 'no') { 1632 | writeBlock(mFormat.format(29), sOutput.format(spindleSpeed)); 1633 | } 1634 | if (properties.usePitchForTapping) { 1635 | writeBlock( 1636 | gRetractModal.format(98), gCycleModal.format(84), 1637 | getCommonCycle(x, y, z, cycle.retract, cycle.clearance), 1638 | 'P' + milliFormat.format(P), 1639 | pitchOutput.format(tool.threadPitch) 1640 | ); 1641 | forceFeed(); 1642 | } else { 1643 | var tappingFPM = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); 1644 | F = (properties.useG95 ? tool.getThreadPitch() : tappingFPM); 1645 | writeBlock( 1646 | gRetractModal.format(98), gCycleModal.format(84), 1647 | getCommonCycle(x, y, z, cycle.retract, cycle.clearance), 1648 | 'P' + milliFormat.format(P), 1649 | feedOutput.format(F) 1650 | ); 1651 | } 1652 | break; 1653 | case 'tapping-with-chip-breaking': 1654 | case 'left-tapping-with-chip-breaking': 1655 | case 'right-tapping-with-chip-breaking': 1656 | if (properties.useRigidTapping != 'no') { 1657 | writeBlock(mFormat.format(29), sOutput.format(spindleSpeed)); 1658 | } 1659 | if (properties.usePitchForTapping) { 1660 | writeBlock( 1661 | gRetractModal.format(98), gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND ? 74 : 84)), 1662 | getCommonCycle(x, y, z, cycle.retract, cycle.clearance), 1663 | 'P' + milliFormat.format(P), 1664 | 'Q' + xyzFormat.format(cycle.incrementalDepth), 1665 | pitchOutput.format(tool.threadPitch) 1666 | ); 1667 | forceFeed(); 1668 | } else { 1669 | var tappingFPM = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); 1670 | F = (properties.useG95 ? tool.getThreadPitch() : tappingFPM); 1671 | writeBlock( 1672 | gRetractModal.format(98), gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND ? 74 : 84)), 1673 | getCommonCycle(x, y, z, cycle.retract, cycle.clearance), 1674 | 'P' + milliFormat.format(P), 1675 | 'Q' + xyzFormat.format(cycle.incrementalDepth), 1676 | feedOutput.format(F) 1677 | ); 1678 | } 1679 | break; 1680 | case 'fine-boring': 1681 | writeBlock( 1682 | gRetractModal.format(98), gCycleModal.format(76), 1683 | getCommonCycle(x, y, z, cycle.retract, cycle.clearance), 1684 | 'P' + milliFormat.format(P), // not optional 1685 | 'Q' + xyzFormat.format(cycle.shift), 1686 | feedOutput.format(F) 1687 | ); 1688 | break; 1689 | case 'back-boring': 1690 | var dx = (gPlaneModal.getCurrent() == 19) ? cycle.backBoreDistance : 0; 1691 | var dy = (gPlaneModal.getCurrent() == 18) ? cycle.backBoreDistance : 0; 1692 | var dz = (gPlaneModal.getCurrent() == 17) ? cycle.backBoreDistance : 0; 1693 | writeBlock( 1694 | gRetractModal.format(98), gCycleModal.format(87), 1695 | getCommonCycle(x - dx, y - dy, z - dz, cycle.bottom, cycle.clearance), 1696 | 'Q' + xyzFormat.format(cycle.shift), 1697 | 'P' + milliFormat.format(P), // not optional 1698 | feedOutput.format(F) 1699 | ); 1700 | break; 1701 | case 'reaming': 1702 | if (P > 0) { 1703 | writeBlock( 1704 | gRetractModal.format(98), gCycleModal.format(89), 1705 | getCommonCycle(x, y, z, cycle.retract, cycle.clearance), 1706 | 'P' + milliFormat.format(P), 1707 | feedOutput.format(F) 1708 | ); 1709 | } else { 1710 | writeBlock( 1711 | gRetractModal.format(98), gCycleModal.format(85), 1712 | getCommonCycle(x, y, z, cycle.retract, cycle.clearance), 1713 | feedOutput.format(F) 1714 | ); 1715 | } 1716 | break; 1717 | case 'stop-boring': 1718 | if (P > 0) { 1719 | expandCyclePoint(x, y, z); 1720 | } else { 1721 | writeBlock( 1722 | gRetractModal.format(98), gCycleModal.format(86), 1723 | getCommonCycle(x, y, z, cycle.retract, cycle.clearance), 1724 | feedOutput.format(F) 1725 | ); 1726 | } 1727 | break; 1728 | case 'manual-boring': 1729 | writeBlock( 1730 | gRetractModal.format(98), gCycleModal.format(88), 1731 | getCommonCycle(x, y, z, cycle.retract, cycle.clearance), 1732 | 'P' + milliFormat.format(P), // not optional 1733 | feedOutput.format(F) 1734 | ); 1735 | break; 1736 | case 'boring': 1737 | if (P > 0) { 1738 | writeBlock( 1739 | gRetractModal.format(98), gCycleModal.format(89), 1740 | getCommonCycle(x, y, z, cycle.retract, cycle.clearance), 1741 | 'P' + milliFormat.format(P), // not optional 1742 | feedOutput.format(F) 1743 | ); 1744 | } else { 1745 | writeBlock( 1746 | gRetractModal.format(98), gCycleModal.format(85), 1747 | getCommonCycle(x, y, z, cycle.retract, cycle.clearance), 1748 | feedOutput.format(F) 1749 | ); 1750 | } 1751 | break; 1752 | 1753 | case 'probing-x': 1754 | forceXYZ(); 1755 | // move slowly always from clearance not retract 1756 | writeBlock(gFormat.format(65), 'P' + 9810, zOutput.format(z - cycle.depth), feedOutput.format(F)); // protected positioning move 1757 | writeBlock( 1758 | gFormat.format(65), 'P' + 9811, 1759 | 'X' + xyzFormat.format(x + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)), 1760 | 'Q' + xyzFormat.format(cycle.probeOvertravel), 1761 | 'S' + probeWorkOffsetCode // "T" + toolFormat.format(probeToolDiameterOffset) 1762 | ); 1763 | break; 1764 | case 'probing-y': 1765 | forceXYZ(); 1766 | writeBlock(gFormat.format(65), 'P' + 9810, zOutput.format(z - cycle.depth), feedOutput.format(F)); // protected positioning move 1767 | writeBlock( 1768 | gFormat.format(65), 'P' + 9811, 1769 | 'Y' + xyzFormat.format(y + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)), 1770 | 'Q' + xyzFormat.format(cycle.probeOvertravel), 1771 | 'S' + probeWorkOffsetCode // "T" + toolFormat.format(probeToolDiameterOffset) 1772 | ); 1773 | break; 1774 | case 'probing-z': 1775 | forceXYZ(); 1776 | writeBlock(gFormat.format(65), 'P' + 9810, zOutput.format(Math.min(z - cycle.depth + cycle.probeClearance, cycle.retract)), feedOutput.format(F)); // protected positioning move 1777 | writeBlock( 1778 | gFormat.format(65), 'P' + 9811, 1779 | 'Z' + xyzFormat.format(z - cycle.depth), 1780 | 'Q' + xyzFormat.format(cycle.probeOvertravel), 1781 | 'S' + probeWorkOffsetCode // "T" + toolFormat.format(probeToolLengthOffset) 1782 | ); 1783 | break; 1784 | case 'probing-x-wall': 1785 | writeBlock(gFormat.format(65), 'P' + 9810, zOutput.format(z), feedOutput.format(F)); // protected positioning move 1786 | writeBlock( 1787 | gFormat.format(65), 'P' + 9812, 1788 | 'X' + xyzFormat.format(cycle.width1), 1789 | zOutput.format(z - cycle.depth), 1790 | 'Q' + xyzFormat.format(cycle.probeOvertravel), 1791 | 'R' + xyzFormat.format(cycle.probeClearance), 1792 | 'S' + probeWorkOffsetCode // "T" + toolFormat.format(probeToolDiameterOffset) 1793 | ); 1794 | break; 1795 | case 'probing-y-wall': 1796 | writeBlock(gFormat.format(65), 'P' + 9810, zOutput.format(z), feedOutput.format(F)); // protected positioning move 1797 | writeBlock( 1798 | gFormat.format(65), 'P' + 9812, 1799 | 'Y' + xyzFormat.format(cycle.width1), 1800 | zOutput.format(z - cycle.depth), 1801 | 'Q' + xyzFormat.format(cycle.probeOvertravel), 1802 | 'R' + xyzFormat.format(cycle.probeClearance), 1803 | 'S' + probeWorkOffsetCode // "T" + toolFormat.format(probeToolDiameterOffset) 1804 | ); 1805 | break; 1806 | case 'probing-x-channel': 1807 | writeBlock(gFormat.format(65), 'P' + 9810, zOutput.format(z - cycle.depth), feedOutput.format(F)); // protected positioning move 1808 | writeBlock( 1809 | gFormat.format(65), 'P' + 9812, 1810 | 'X' + xyzFormat.format(cycle.width1), 1811 | 'Q' + xyzFormat.format(cycle.probeOvertravel), 1812 | // not required "R" + xyzFormat.format(cycle.probeClearance), 1813 | 'S' + probeWorkOffsetCode // "T" + toolFormat.format(probeToolDiameterOffset) 1814 | ); 1815 | break; 1816 | case 'probing-x-channel-with-island': 1817 | writeBlock(gFormat.format(65), 'P' + 9810, zOutput.format(z), feedOutput.format(F)); // protected positioning move 1818 | writeBlock( 1819 | gFormat.format(65), 'P' + 9812, 1820 | 'X' + xyzFormat.format(cycle.width1), 1821 | zOutput.format(z - cycle.depth), 1822 | 'Q' + xyzFormat.format(cycle.probeOvertravel), 1823 | 'R' + xyzFormat.format(-cycle.probeClearance), 1824 | 'S' + probeWorkOffsetCode 1825 | ); 1826 | break; 1827 | case 'probing-y-channel': 1828 | yOutput.reset(); 1829 | writeBlock(gFormat.format(65), 'P' + 9810, zOutput.format(z - cycle.depth), feedOutput.format(F)); // protected positioning move 1830 | writeBlock( 1831 | gFormat.format(65), 'P' + 9812, 1832 | 'Y' + xyzFormat.format(cycle.width1), 1833 | 'Q' + xyzFormat.format(cycle.probeOvertravel), 1834 | // not required "R" + xyzFormat.format(cycle.probeClearance), 1835 | 'S' + probeWorkOffsetCode 1836 | ); 1837 | break; 1838 | case 'probing-y-channel-with-island': 1839 | yOutput.reset(); 1840 | writeBlock(gFormat.format(65), 'P' + 9810, zOutput.format(z), feedOutput.format(F)); // protected positioning move 1841 | writeBlock( 1842 | gFormat.format(65), 'P' + 9812, 1843 | 'Y' + xyzFormat.format(cycle.width1), 1844 | zOutput.format(z - cycle.depth), 1845 | 'Q' + xyzFormat.format(cycle.probeOvertravel), 1846 | 'R' + xyzFormat.format(-cycle.probeClearance), 1847 | 'S' + probeWorkOffsetCode 1848 | ); 1849 | break; 1850 | case 'probing-xy-circular-boss': 1851 | writeBlock(gFormat.format(65), 'P' + 9810, zOutput.format(z), feedOutput.format(F)); // protected positioning move 1852 | writeBlock( 1853 | gFormat.format(65), 'P' + 9814, 1854 | 'D' + xyzFormat.format(cycle.width1), 1855 | 'Z' + xyzFormat.format(z - cycle.depth), 1856 | 'Q' + xyzFormat.format(cycle.probeOvertravel), 1857 | 'R' + xyzFormat.format(cycle.probeClearance), 1858 | 'S' + probeWorkOffsetCode 1859 | ); 1860 | break; 1861 | case 'probing-xy-circular-hole': 1862 | writeBlock(gFormat.format(65), 'P' + 9810, zOutput.format(z - cycle.depth), feedOutput.format(F)); // protected positioning move 1863 | writeBlock( 1864 | gFormat.format(65), 'P' + 9814, 1865 | 'D' + xyzFormat.format(cycle.width1), 1866 | 'Q' + xyzFormat.format(cycle.probeOvertravel), 1867 | // not required "R" + xyzFormat.format(cycle.probeClearance), 1868 | 'S' + probeWorkOffsetCode 1869 | ); 1870 | break; 1871 | case 'probing-xy-circular-hole-with-island': 1872 | writeBlock(gFormat.format(65), 'P' + 9810, zOutput.format(z), feedOutput.format(F)); // protected positioning move 1873 | writeBlock( 1874 | gFormat.format(65), 'P' + 9814, 1875 | 'Z' + xyzFormat.format(z - cycle.depth), 1876 | 'D' + xyzFormat.format(cycle.width1), 1877 | 'Q' + xyzFormat.format(cycle.probeOvertravel), 1878 | 'R' + xyzFormat.format(-cycle.probeClearance), 1879 | 'S' + probeWorkOffsetCode 1880 | ); 1881 | break; 1882 | case 'probing-xy-rectangular-hole': 1883 | writeBlock(gFormat.format(65), 'P' + 9810, zOutput.format(z - cycle.depth), feedOutput.format(F)); // protected positioning move 1884 | writeBlock( 1885 | gFormat.format(65), 'P' + 9812, 1886 | 'X' + xyzFormat.format(cycle.width1), 1887 | 'Q' + xyzFormat.format(cycle.probeOvertravel), 1888 | // not required "R" + xyzFormat.format(-cycle.probeClearance), 1889 | 'S' + probeWorkOffsetCode 1890 | ); 1891 | writeBlock( 1892 | gFormat.format(65), 'P' + 9812, 1893 | 'Y' + xyzFormat.format(cycle.width2), 1894 | 'Q' + xyzFormat.format(cycle.probeOvertravel), 1895 | // not required "R" + xyzFormat.format(-cycle.probeClearance), 1896 | 'S' + probeWorkOffsetCode 1897 | ); 1898 | break; 1899 | case 'probing-xy-rectangular-boss': 1900 | writeBlock(gFormat.format(65), 'P' + 9810, zOutput.format(z), feedOutput.format(F)); // protected positioning move 1901 | writeBlock( 1902 | gFormat.format(65), 'P' + 9812, 1903 | 'Z' + xyzFormat.format(z - cycle.depth), 1904 | 'X' + xyzFormat.format(cycle.width1), 1905 | 'R' + xyzFormat.format(cycle.probeClearance), 1906 | 'Q' + xyzFormat.format(cycle.probeOvertravel), 1907 | 'S' + probeWorkOffsetCode 1908 | ); 1909 | writeBlock( 1910 | gFormat.format(65), 'P' + 9812, 1911 | 'Z' + xyzFormat.format(z - cycle.depth), 1912 | 'Y' + xyzFormat.format(cycle.width2), 1913 | 'R' + xyzFormat.format(cycle.probeClearance), 1914 | 'Q' + xyzFormat.format(cycle.probeOvertravel), 1915 | 'S' + probeWorkOffsetCode 1916 | ); 1917 | break; 1918 | case 'probing-xy-rectangular-hole-with-island': 1919 | writeBlock(gFormat.format(65), 'P' + 9810, zOutput.format(z), feedOutput.format(F)); // protected positioning move 1920 | writeBlock( 1921 | gFormat.format(65), 'P' + 9812, 1922 | 'Z' + xyzFormat.format(z - cycle.depth), 1923 | 'X' + xyzFormat.format(cycle.width1), 1924 | 'Q' + xyzFormat.format(cycle.probeOvertravel), 1925 | 'R' + xyzFormat.format(-cycle.probeClearance), 1926 | 'S' + probeWorkOffsetCode 1927 | ); 1928 | writeBlock( 1929 | gFormat.format(65), 'P' + 9812, 1930 | 'Z' + xyzFormat.format(z - cycle.depth), 1931 | 'Y' + xyzFormat.format(cycle.width2), 1932 | 'Q' + xyzFormat.format(cycle.probeOvertravel), 1933 | 'R' + xyzFormat.format(-cycle.probeClearance), 1934 | 'S' + probeWorkOffsetCode 1935 | ); 1936 | break; 1937 | 1938 | case 'probing-xy-inner-corner': 1939 | var cornerX = x + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2); 1940 | var cornerY = y + approach(cycle.approach2) * (cycle.probeClearance + tool.diameter / 2); 1941 | var cornerI = 0; 1942 | var cornerJ = 0; 1943 | if (cycle.probeSpacing !== undefined) { 1944 | cornerI = cycle.probeSpacing; 1945 | cornerJ = cycle.probeSpacing; 1946 | } 1947 | if ((cornerI != 0) && (cornerJ != 0)) { 1948 | g68RotationMode = 2; 1949 | } 1950 | writeBlock(gFormat.format(65), 'P' + 9810, zOutput.format(z - cycle.depth), feedOutput.format(F)); // protected positioning move 1951 | writeBlock( 1952 | gFormat.format(65), 'P' + 9815, xOutput.format(cornerX), yOutput.format(cornerY), 1953 | conditional(cornerI != 0, 'I' + xyzFormat.format(cornerI)), 1954 | conditional(cornerJ != 0, 'J' + xyzFormat.format(cornerJ)), 1955 | 'Q' + xyzFormat.format(cycle.probeOvertravel), 1956 | conditional((g68RotationMode == 0) || (angularProbingMode == ANGLE_PROBE_USE_CAXIS), 'S' + probeWorkOffsetCode) 1957 | ); 1958 | break; 1959 | case 'probing-xy-outer-corner': 1960 | var cornerX = x + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2); 1961 | var cornerY = y + approach(cycle.approach2) * (cycle.probeClearance + tool.diameter / 2); 1962 | var cornerI = 0; 1963 | var cornerJ = 0; 1964 | if (cycle.probeSpacing !== undefined) { 1965 | cornerI = cycle.probeSpacing; 1966 | cornerJ = cycle.probeSpacing; 1967 | } 1968 | if ((cornerI != 0) && (cornerJ != 0)) { 1969 | g68RotationMode = 2; 1970 | } 1971 | writeBlock(gFormat.format(65), 'P' + 9810, zOutput.format(z - cycle.depth), feedOutput.format(F)); // protected positioning move 1972 | writeBlock( 1973 | gFormat.format(65), 'P' + 9816, xOutput.format(cornerX), yOutput.format(cornerY), 1974 | conditional(cornerI != 0, 'I' + xyzFormat.format(cornerI)), 1975 | conditional(cornerJ != 0, 'J' + xyzFormat.format(cornerJ)), 1976 | 'Q' + xyzFormat.format(cycle.probeOvertravel), 1977 | conditional((g68RotationMode == 0) || (angularProbingMode == ANGLE_PROBE_USE_CAXIS), 'S' + probeWorkOffsetCode) 1978 | ); 1979 | break; 1980 | case 'probing-x-plane-angle': 1981 | forceXYZ(); 1982 | writeBlock(gFormat.format(65), 'P' + 9810, zOutput.format(z - cycle.depth), feedOutput.format(F)); // protected positioning move 1983 | writeBlock( 1984 | gFormat.format(65), 'P' + 9843, 1985 | 'X' + xyzFormat.format(x + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)), 1986 | 'D' + xyzFormat.format(cycle.probeSpacing), 1987 | 'Q' + xyzFormat.format(cycle.probeOvertravel) 1988 | ); 1989 | g68RotationMode = 1; 1990 | break; 1991 | case 'probing-y-plane-angle': 1992 | forceXYZ(); 1993 | writeBlock(gFormat.format(65), 'P' + 9810, zOutput.format(z - cycle.depth), feedOutput.format(F)); // protected positioning move 1994 | writeBlock( 1995 | gFormat.format(65), 'P' + 9843, 1996 | 'Y' + xyzFormat.format(y + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)), 1997 | 'D' + xyzFormat.format(cycle.probeSpacing), 1998 | 'Q' + xyzFormat.format(cycle.probeOvertravel) 1999 | ); 2000 | g68RotationMode = 1; 2001 | break; 2002 | default: 2003 | expandCyclePoint(x, y, z); 2004 | } 2005 | 2006 | // place cycle operation in subprogram 2007 | if (cycleSubprogramIsActive) { 2008 | if (cycleExpanded || isProbeOperation()) { 2009 | cycleSubprogramIsActive = false; 2010 | } else { 2011 | // call subprogram 2012 | writeBlock(mFormat.format(98), 'P' + oFormat.format(currentSubprogram)); 2013 | subprogramStart(new Vector(x, y, z), new Vector(0, 0, 0), false); 2014 | } 2015 | } 2016 | if (incrementalMode) { // set current position to clearance height 2017 | setCyclePosition(cycle.clearance); 2018 | } 2019 | 2020 | // 2nd through nth cycle point 2021 | } else { 2022 | if (isProbeOperation()) { 2023 | // do nothing 2024 | } else if (cycleExpanded) { 2025 | expandCyclePoint(x, y, z); 2026 | } else { 2027 | if (!xyzFormat.areDifferent(x, xOutput.getCurrent()) && 2028 | !xyzFormat.areDifferent(y, yOutput.getCurrent()) && 2029 | !xyzFormat.areDifferent(z, zOutput.getCurrent())) { 2030 | switch (gPlaneModal.getCurrent()) { 2031 | case 17: // XY 2032 | xOutput.reset(); // at least one axis is required 2033 | break; 2034 | case 18: // ZX 2035 | zOutput.reset(); // at least one axis is required 2036 | break; 2037 | case 19: // YZ 2038 | yOutput.reset(); // at least one axis is required 2039 | break; 2040 | } 2041 | } 2042 | if (incrementalMode) { // set current position to retract height 2043 | setCyclePosition(cycle.retract); 2044 | } 2045 | writeBlock(xOutput.format(x), yOutput.format(y)); 2046 | if (incrementalMode) { // set current position to clearance height 2047 | setCyclePosition(cycle.clearance); 2048 | } 2049 | } 2050 | } 2051 | } 2052 | 2053 | function onCycleEnd() { 2054 | if (isProbeOperation()) { 2055 | writeBlock(gFormat.format(65), 'P' + 9810, zOutput.format(cycle.clearance)); // protected retract move 2056 | writeBlock(gFormat.format(65), 'P' + 9833); // spin the probe off 2057 | setProbingAngle(); // define rotation of part 2058 | // we can move in rapid from retract optionally 2059 | 2060 | } else { 2061 | if (cycleSubprogramIsActive) { 2062 | subprogramEnd(); 2063 | cycleSubprogramIsActive = false; 2064 | } 2065 | if (!cycleExpanded) { 2066 | writeBlock(gCycleModal.format(80)); 2067 | zOutput.reset(); 2068 | } 2069 | } 2070 | } 2071 | 2072 | var pendingRadiusCompensation = -1; 2073 | 2074 | function onRadiusCompensation() { 2075 | pendingRadiusCompensation = radiusCompensation; 2076 | } 2077 | 2078 | function onRapid(_x, _y, _z) { 2079 | var x = xOutput.format(_x); 2080 | var y = yOutput.format(_y); 2081 | var z = zOutput.format(_z); 2082 | if (x || y || z) { 2083 | if (pendingRadiusCompensation >= 0) { 2084 | error(localize('Radius compensation mode cannot be changed at rapid traversal.')); 2085 | return; 2086 | } 2087 | writeBlock(gMotionModal.format(0), x, y, z); 2088 | forceFeed(); 2089 | } 2090 | } 2091 | 2092 | function onLinear(_x, _y, _z, feed) { 2093 | var x = xOutput.format(_x); 2094 | var y = yOutput.format(_y); 2095 | var z = zOutput.format(_z); 2096 | var f = feedOutput.format(feed); 2097 | if (x || y || z) { 2098 | if (pendingRadiusCompensation >= 0) { 2099 | pendingRadiusCompensation = -1; 2100 | var d = tool.diameterOffset; 2101 | if (d > 99) { 2102 | warning(localize('The diameter offset exceeds the maximum value.')); 2103 | } 2104 | writeBlock(gPlaneModal.format(17)); 2105 | switch (radiusCompensation) { 2106 | case RADIUS_COMPENSATION_LEFT: 2107 | dOutput.reset(); 2108 | writeBlock(gFeedModeModal.format(94), gMotionModal.format(1), gFormat.format(41), x, y, z, dOutput.format(d), f); 2109 | break; 2110 | case RADIUS_COMPENSATION_RIGHT: 2111 | dOutput.reset(); 2112 | writeBlock(gFeedModeModal.format(94), gMotionModal.format(1), gFormat.format(42), x, y, z, dOutput.format(d), f); 2113 | break; 2114 | default: 2115 | writeBlock(gFeedModeModal.format(94), gMotionModal.format(1), gFormat.format(40), x, y, z, f); 2116 | } 2117 | } else { 2118 | writeBlock(gFeedModeModal.format(94), gMotionModal.format(1), x, y, z, f); 2119 | } 2120 | } else if (f) { 2121 | if (getNextRecord() 2122 | .isMotion()) { // try not to output feed without motion 2123 | forceFeed(); // force feed on next line 2124 | } else { 2125 | writeBlock(gFeedModeModal.format(94), gMotionModal.format(1), f); 2126 | } 2127 | } 2128 | } 2129 | 2130 | function onRapid5D(_x, _y, _z, _a, _b, _c) { 2131 | if (pendingRadiusCompensation >= 0) { 2132 | error(localize('Radius compensation mode cannot be changed at rapid traversal.')); 2133 | return; 2134 | } 2135 | var x = xOutput.format(_x); 2136 | var y = yOutput.format(_y); 2137 | var z = zOutput.format(_z); 2138 | var a = aOutput.format(_a); 2139 | var b = bOutput.format(properties.useClockwise ? _b: -_b); 2140 | var c = cOutput.format(_c); 2141 | writeBlock(gMotionModal.format(0), x, y, z, a, b, c); 2142 | feedOutput.reset(); 2143 | } 2144 | 2145 | function onLinear5D(_x, _y, _z, _a, _b, _c, feed) { 2146 | 2147 | if (!currentSection.isOptimizedForMachine()) { 2148 | error(localize('This post configuration has not been customized for 5-axis simultaneous toolpath.')); 2149 | return; 2150 | } 2151 | if (pendingRadiusCompensation >= 0) { 2152 | error(localize('Radius compensation cannot be activated/deactivated for 5-axis move.')); 2153 | return; 2154 | } 2155 | 2156 | var x = xOutput.format(_x); 2157 | var y = yOutput.format(_y); 2158 | var z = zOutput.format(_z); 2159 | var a = aOutput.format(_a); 2160 | var b = bOutput.format(properties.useClockwise ? _b : -_b); 2161 | var c = cOutput.format(_c); 2162 | 2163 | // get feedrate number 2164 | var f = { 2165 | frn: 0, 2166 | fmode: 0 2167 | }; 2168 | if ((a || b || c ) && properties.useInverseTimeFeed) { 2169 | f = getMultiaxisFeed(_x, _y, _z, _a, _b, _c, feed); 2170 | f.frn = inverseTimeOutput.format(f.frn); 2171 | } else { 2172 | f.frn = feedOutput.format(feed); 2173 | f.fmode = 94; 2174 | } 2175 | 2176 | if (x || y || z || a || b || c) { 2177 | writeBlock(gFeedModeModal.format(f.fmode)); 2178 | writeBlock(gMotionModal.format(1), x, y, z, a, b, c, f.frn); 2179 | } else if (f.frn) { 2180 | if (getNextRecord() 2181 | .isMotion()) { // try not to output feed without motion 2182 | feedOutput.reset(); // force feed on next line 2183 | } else { 2184 | writeBlock(gFeedModeModal.format(f.fmode), gMotionModal.format(1), f.frn); 2185 | } 2186 | } 2187 | } 2188 | 2189 | // Start of multi-axis feedrate logic 2190 | /***** Be sure to add 'useInverseTime' to post properties if necessary. *****/ 2191 | /***** 'inverseTimeOutput' must be defined. *****/ 2192 | /***** 'headOffset' should be defined when a head rotary axis is defined. *****/ 2193 | /***** The feedrate mode must be included in motion block output (linear, circular, etc. *****/ 2194 | var dpmBPW = 0.1; // ratio of rotary accuracy to linear accuracy for DPM calculations 2195 | var inverseTimeUnits = 1.0; // 1.0 = minutes, 60.0 = seconds 2196 | var maxInverseTime = 9999; // maximum value to output for Inverse Time feeds 2197 | 2198 | // Start of multi-axis feedrate logic 2199 | /***** Be sure to add 'useInverseTime' to post properties if necessary. *****/ 2200 | /***** 'inverseTimeOutput' should be defined if Inverse Time feedrates are supported. *****/ 2201 | /***** 'previousABC' can be added throughout to maintain previous rotary positions. Required for Mill/Turn machines. *****/ 2202 | /***** 'headOffset' should be defined when a head rotary axis is defined. *****/ 2203 | /***** The feedrate mode must be included in motion block output (linear, circular, etc.) for Inverse Time feedrate support. *****/ 2204 | var dpmBPW = 0.1; // ratio of rotary accuracy to linear accuracy for DPM calculations 2205 | var inverseTimeUnits = 1.0; // 1.0 = minutes, 60.0 = seconds 2206 | var maxInverseTime = 9999; // maximum value to output for Inverse Time feeds 2207 | var maxDPM = 9999.99; // maximum value to output for DPM feeds 2208 | var previousDPMFeed = 0; // previously output DPM feed 2209 | var dpmFeedToler = 0.5; // tolerance to determine when the DPM feed has changed 2210 | // var previousABC = new Vector(0, 0, 0); // previous ABC position if maintained in post, don't define if not used 2211 | var forceOptimized = undefined; // used to override optimized-for-angles points (XZC-mode) 2212 | 2213 | /** Calculate the multi-axis feedrate number. */ 2214 | function getMultiaxisFeed(_x, _y, _z, _a, _b, _c, feed) { 2215 | var f = { 2216 | frn: 0, 2217 | fmode: 0 2218 | }; 2219 | if (feed <= 0) { 2220 | error(localize('Feedrate is less than or equal to 0.')); 2221 | return f; 2222 | } 2223 | 2224 | var length = getMoveLength(_x, _y, _z, _a, _b, _c); 2225 | 2226 | if (properties.useInverseTimeFeed) { // inverse time 2227 | f.frn = getInverseTime(length.tool, feed); 2228 | f.fmode = 93; 2229 | feedOutput.reset(); 2230 | } else { // degrees per minute 2231 | f.frn = getFeedDPM(length, feed); 2232 | f.fmode = 94; 2233 | } 2234 | return f; 2235 | } 2236 | 2237 | /** Returns point optimization mode. */ 2238 | function getOptimizedMode() { 2239 | if (forceOptimized != undefined) { 2240 | return forceOptimized; 2241 | } 2242 | // return (currentSection.getOptimizedTCPMode() != 0); // TAG:doesn't return correct value 2243 | return true; // always return false for non-TCP based heads 2244 | } 2245 | 2246 | /** Calculate the DPM feedrate number. */ 2247 | function getFeedDPM(_moveLength, _feed) { 2248 | if ((_feed == 0) || (_moveLength.tool < 0.0001) || (toDeg(_moveLength.abcLength) < 0.0005)) { 2249 | previousDPMFeed = 0; 2250 | return _feed; 2251 | } 2252 | var moveTime = _moveLength.tool / _feed; 2253 | if (moveTime == 0) { 2254 | previousDPMFeed = 0; 2255 | return _feed; 2256 | } 2257 | 2258 | var dpmFeed; 2259 | var tcp = false; // !getOptimizedMode() && (forceOptimized == undefined); // set to false for rotary heads 2260 | if (tcp) { // TCP mode is supported, output feed as FPM 2261 | dpmFeed = _feed; 2262 | } else if (false) { // standard DPM 2263 | dpmFeed = Math.min(toDeg(_moveLength.abcLength) / moveTime, maxDPM); 2264 | if (Math.abs(dpmFeed - previousDPMFeed) < dpmFeedToler) { 2265 | dpmFeed = previousDPMFeed; 2266 | } 2267 | } else if (true) { // combination FPM/DPM 2268 | 2269 | // var length = Math.sqrt(Math.pow(_moveLength.xyzLength, 2.0) + Math.pow((toDeg(_moveLength.abcLength) * dpmBPW), 2.0)); 2270 | dpmFeed = Math.min(Math.max(_moveLength.xyzLength / moveTime, _moveLength.radialLength / moveTime), maxDPM); 2271 | if (Math.abs(dpmFeed - previousDPMFeed) < dpmFeedToler) { 2272 | dpmFeed = previousDPMFeed; 2273 | } 2274 | } else { // machine specific calculation 2275 | dpmFeed = _feed; 2276 | } 2277 | previousDPMFeed = dpmFeed; 2278 | return dpmFeed; 2279 | } 2280 | 2281 | /** Calculate the Inverse time feedrate number. */ 2282 | function getInverseTime(_length, _feed) { 2283 | var inverseTime; 2284 | if (_length < 1.e-6) { // tool doesn't move 2285 | if (typeof maxInverseTime === 'number') { 2286 | inverseTime = maxInverseTime; 2287 | } else { 2288 | inverseTime = 999999; 2289 | } 2290 | } else { 2291 | inverseTime = _feed / _length / inverseTimeUnits; 2292 | if (typeof maxInverseTime === 'number') { 2293 | if (inverseTime > maxInverseTime) { 2294 | inverseTime = maxInverseTime; 2295 | } 2296 | } 2297 | } 2298 | return inverseTime; 2299 | } 2300 | 2301 | /** Calculate radius for each rotary axis. */ 2302 | function getRotaryRadii(startTool, endTool, startABC, endABC) { 2303 | var radii = new Vector(0, 0, 0); 2304 | var startRadius; 2305 | var endRadius; 2306 | var axis = new Array(machineConfiguration.getAxisU(), machineConfiguration.getAxisV(), machineConfiguration.getAxisW()); 2307 | for (var i = 0; i < 3; ++i) { 2308 | if (axis[i].isEnabled()) { 2309 | 2310 | var startRadius = getRotaryRadius(axis[i], startTool, startABC); 2311 | var endRadius = getRotaryRadius(axis[i], endTool, endABC); 2312 | radii.setCoordinate(axis[i].getCoordinate(), Math.max(startRadius, endRadius)); 2313 | } 2314 | } 2315 | return radii; 2316 | } 2317 | 2318 | /** Calculate the distance of the tool position to the center of a rotary axis. */ 2319 | function getRotaryRadius(axis, toolPosition, abc) { 2320 | if (!axis.isEnabled()) { 2321 | return 0; 2322 | } 2323 | 2324 | var direction = axis.getEffectiveAxis(); 2325 | var normal = direction.getNormalized(); 2326 | // calculate the rotary center based on head/table 2327 | var center; 2328 | var radius; 2329 | if (axis.isHead()) { 2330 | var pivot; 2331 | if (typeof headOffset === 'number') { 2332 | pivot = headOffset; 2333 | } else { 2334 | pivot = tool.getBodyLength(); 2335 | } 2336 | if (axis.getCoordinate() == machineConfiguration.getAxisU() 2337 | .getCoordinate()) { // rider 2338 | center = Vector.sum(toolPosition, Vector.product(machineConfiguration.getDirection(abc), pivot)); 2339 | center = Vector.sum(center, axis.getOffset()); 2340 | radius = Vector.diff(toolPosition, center).length; 2341 | } else { // carrier 2342 | var angle = abc.getCoordinate(machineConfiguration.getAxisU() 2343 | .getCoordinate()); 2344 | radius = Math.abs(pivot * Math.sin(angle)); 2345 | radius += axis.getOffset().length; 2346 | } 2347 | } else { 2348 | center = axis.getOffset(); 2349 | var d1 = toolPosition.x - center.x; 2350 | var d2 = toolPosition.y - center.y; 2351 | var d3 = toolPosition.z - center.z; 2352 | var radius = Math.sqrt( 2353 | Math.pow((d1 * normal.y) - (d2 * normal.x), 2.0) + 2354 | Math.pow((d2 * normal.z) - (d3 * normal.y), 2.0) + 2355 | Math.pow((d3 * normal.x) - (d1 * normal.z), 2.0) 2356 | ); 2357 | } 2358 | return radius; 2359 | } 2360 | 2361 | /** Calculate the linear distance based on the rotation of a rotary axis. */ 2362 | function getRadialDistance(radius, startABC, endABC) { 2363 | // calculate length of radial move 2364 | var delta = Math.abs(endABC - startABC); 2365 | if (delta > Math.PI) { 2366 | delta = 2 * Math.PI - delta; 2367 | } 2368 | var radialLength = (2 * Math.PI * radius) * (delta / (2 * Math.PI)); 2369 | return radialLength; 2370 | } 2371 | 2372 | /** Calculate tooltip, XYZ, and rotary move lengths. */ 2373 | function getMoveLength(_x, _y, _z, _a, _b, _c) { 2374 | // get starting and ending positions 2375 | var moveLength = {}; 2376 | var startTool; 2377 | var endTool; 2378 | var startXYZ; 2379 | var endXYZ; 2380 | var startABC; 2381 | if (typeof previousABC !== 'undefined') { 2382 | startABC = new Vector(previousABC.x, previousABC.y, previousABC.z); 2383 | } else { 2384 | startABC = getCurrentDirection(); 2385 | } 2386 | var endABC = new Vector(_a, _b, _c); 2387 | 2388 | if (!getOptimizedMode()) { // calculate XYZ from tool tip 2389 | startTool = getCurrentPosition(); 2390 | endTool = new Vector(_x, _y, _z); 2391 | startXYZ = startTool; 2392 | endXYZ = endTool; 2393 | 2394 | // adjust points for tables 2395 | if (!machineConfiguration.getTableABC(startABC) 2396 | .isZero() || !machineConfiguration.getTableABC(endABC) 2397 | .isZero()) { 2398 | startXYZ = machineConfiguration.getOrientation(machineConfiguration.getTableABC(startABC)) 2399 | .getTransposed() 2400 | .multiply(startXYZ); 2401 | endXYZ = machineConfiguration.getOrientation(machineConfiguration.getTableABC(endABC)) 2402 | .getTransposed() 2403 | .multiply(endXYZ); 2404 | } 2405 | 2406 | // adjust points for heads 2407 | if (machineConfiguration.getAxisU() 2408 | .isEnabled() && machineConfiguration.getAxisU() 2409 | .isHead()) { 2410 | if (typeof getOptimizedHeads === 'function') { // use post processor function to adjust heads 2411 | startXYZ = getOptimizedHeads(startXYZ.x, startXYZ.y, startXYZ.z, startABC.x, startABC.y, startABC.z); 2412 | endXYZ = getOptimizedHeads(endXYZ.x, endXYZ.y, endXYZ.z, endABC.x, endABC.y, endABC.z); 2413 | } else { // guess at head adjustments 2414 | var startDisplacement = machineConfiguration.getDirection(startABC); 2415 | startDisplacement.multiply(headOffset); 2416 | var endDisplacement = machineConfiguration.getDirection(endABC); 2417 | endDisplacement.multiply(headOffset); 2418 | startXYZ = Vector.sum(startTool, startDisplacement); 2419 | endXYZ = Vector.sum(endTool, endDisplacement); 2420 | } 2421 | } 2422 | } else { // calculate tool tip from XYZ, heads are always programmed in TCP mode, so not handled here 2423 | startXYZ = getCurrentPosition(); 2424 | endXYZ = new Vector(_x, _y, _z); 2425 | startTool = machineConfiguration.getOrientation(machineConfiguration.getTableABC(startABC)) 2426 | .multiply(startXYZ); 2427 | endTool = machineConfiguration.getOrientation(machineConfiguration.getTableABC(endABC)) 2428 | .multiply(endXYZ); 2429 | } 2430 | 2431 | // calculate axes movements 2432 | moveLength.xyz = Vector.diff(endXYZ, startXYZ).abs; 2433 | moveLength.xyzLength = moveLength.xyz.length; 2434 | moveLength.abc = Vector.diff(endABC, startABC).abs; 2435 | for (var i = 0; i < 3; ++i) { 2436 | if (moveLength.abc.getCoordinate(i) > Math.PI) { 2437 | moveLength.abc.setCoordinate(i, 2 * Math.PI - moveLength.abc.getCoordinate(i)); 2438 | } 2439 | } 2440 | moveLength.abcLength = moveLength.abc.length; 2441 | 2442 | // calculate radii 2443 | moveLength.radius = getRotaryRadii(startTool, endTool, startABC, endABC); 2444 | 2445 | // calculate the radial portion of the tool tip movement 2446 | moveLength.radialLength = Math.sqrt( 2447 | Math.pow(getRadialDistance(moveLength.radius.x, startABC.x, endABC.x), 2.0) + 2448 | Math.pow(getRadialDistance(moveLength.radius.y, startABC.y, endABC.y), 2.0) + 2449 | Math.pow(getRadialDistance(moveLength.radius.z, startABC.z, endABC.z), 2.0) 2450 | ); 2451 | 2452 | // calculate the tool tip move length 2453 | // tool tip distance is the move distance based on a combination of linear and rotary axes movement 2454 | moveLength.tool = moveLength.xyzLength + moveLength.radialLength; 2455 | 2456 | if (true) { 2457 | var temp = Vector.product(moveLength.abc, 180 / Math.PI); 2458 | } 2459 | return moveLength; 2460 | } 2461 | 2462 | // End of multi-axis feedrate logic 2463 | 2464 | function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { 2465 | if (pendingRadiusCompensation >= 0) { 2466 | error(localize('Radius compensation cannot be activated/deactivated for a circular move.')); 2467 | return; 2468 | } 2469 | 2470 | var start = getCurrentPosition(); 2471 | 2472 | if (isFullCircle()) { 2473 | if (properties.useRadius || isHelical()) { // radius mode does not support full arcs 2474 | linearize(tolerance); 2475 | return; 2476 | } 2477 | switch (getCircularPlane()) { 2478 | case PLANE_XY: 2479 | writeBlock(gPlaneModal.format(17), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), iOutput.format(cx - start.x, 0), jOutput.format(cy - start.y, 0), feedOutput.format(feed)); 2480 | break; 2481 | case PLANE_ZX: 2482 | writeBlock(gPlaneModal.format(18), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), iOutput.format(cx - start.x, 0), kOutput.format(cz - start.z, 0), feedOutput.format(feed)); 2483 | break; 2484 | case PLANE_YZ: 2485 | writeBlock(gPlaneModal.format(19), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), jOutput.format(cy - start.y, 0), kOutput.format(cz - start.z, 0), feedOutput.format(feed)); 2486 | break; 2487 | default: 2488 | linearize(tolerance); 2489 | } 2490 | } else if (!properties.useRadius) { 2491 | switch (getCircularPlane()) { 2492 | case PLANE_XY: 2493 | writeBlock(gPlaneModal.format(17), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x, 0), jOutput.format(cy - start.y, 0), feedOutput.format(feed)); 2494 | break; 2495 | case PLANE_ZX: 2496 | writeBlock(gPlaneModal.format(18), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x, 0), kOutput.format(cz - start.z, 0), feedOutput.format(feed)); 2497 | break; 2498 | case PLANE_YZ: 2499 | writeBlock(gPlaneModal.format(19), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), jOutput.format(cy - start.y, 0), kOutput.format(cz - start.z, 0), feedOutput.format(feed)); 2500 | break; 2501 | default: 2502 | if (properties.allow3DArcs) { 2503 | // make sure maximumCircularSweep is well below 360deg 2504 | // we could use G02.4 or G03.4 - direction is calculated 2505 | var ip = getPositionU(0.5); 2506 | writeBlock(gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2.4 : 3.4), xOutput.format(ip.x), yOutput.format(ip.y), zOutput.format(ip.z), feedOutput.format(feed)); 2507 | writeBlock(xOutput.format(x), yOutput.format(y), zOutput.format(z)); 2508 | } else { 2509 | linearize(tolerance); 2510 | } 2511 | } 2512 | } else { // use radius mode 2513 | var r = getCircularRadius(); 2514 | if (toDeg(getCircularSweep()) > (180 + 1e-9)) { 2515 | r = -r; // allow up to <360 deg arcs 2516 | } 2517 | switch (getCircularPlane()) { 2518 | case PLANE_XY: 2519 | writeBlock(gPlaneModal.format(17), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), 'R' + rFormat.format(r), feedOutput.format(feed)); 2520 | break; 2521 | case PLANE_ZX: 2522 | writeBlock(gPlaneModal.format(18), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), 'R' + rFormat.format(r), feedOutput.format(feed)); 2523 | break; 2524 | case PLANE_YZ: 2525 | writeBlock(gPlaneModal.format(19), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), 'R' + rFormat.format(r), feedOutput.format(feed)); 2526 | break; 2527 | default: 2528 | if (properties.allow3DArcs) { 2529 | // make sure maximumCircularSweep is well below 360deg 2530 | // we could use G02.4 or G03.4 - direction is calculated 2531 | var ip = getPositionU(0.5); 2532 | writeBlock(gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2.4 : 3.4), xOutput.format(ip.x), yOutput.format(ip.y), zOutput.format(ip.z), feedOutput.format(feed)); 2533 | writeBlock(xOutput.format(x), yOutput.format(y), zOutput.format(z)); 2534 | } else { 2535 | linearize(tolerance); 2536 | } 2537 | } 2538 | } 2539 | } 2540 | 2541 | var currentCoolantMode = COOLANT_OFF; 2542 | var coolantOff = undefined; 2543 | 2544 | function setCoolant(coolant) { 2545 | var coolantCodes = getCoolantCodes(coolant); 2546 | if (Array.isArray(coolantCodes)) { 2547 | for (var c in coolantCodes) { 2548 | writeBlock(coolantCodes[c]); 2549 | } 2550 | return undefined; 2551 | } 2552 | return coolantCodes; 2553 | } 2554 | 2555 | function getCoolantCodes(coolant) { 2556 | if (!coolants) { 2557 | error(localize('Coolants have not been defined.')); 2558 | } 2559 | if (!coolantOff) { // use the default coolant off command when an 'off' value is not specified for the previous coolant mode 2560 | coolantOff = coolants.off; 2561 | } 2562 | 2563 | if (isProbeOperation()) { // avoid coolant output for probing 2564 | coolant = COOLANT_OFF; 2565 | } 2566 | 2567 | if (coolant == currentCoolantMode) { 2568 | return undefined; // coolant is already active 2569 | } 2570 | 2571 | var multipleCoolantBlocks = new Array(); // create a formatted array to be passed into the outputted line 2572 | if ((coolant != COOLANT_OFF) && (currentCoolantMode != COOLANT_OFF)) { 2573 | multipleCoolantBlocks.push(mFormat.format(coolantOff)); 2574 | } 2575 | 2576 | var m; 2577 | if (coolant == COOLANT_OFF) { 2578 | m = coolantOff; 2579 | coolantOff = coolants.off; 2580 | } 2581 | 2582 | switch (coolant) { 2583 | case COOLANT_FLOOD: 2584 | if (!coolants.flood) { 2585 | break; 2586 | } 2587 | m = coolants.flood.on; 2588 | coolantOff = coolants.flood.off; 2589 | break; 2590 | case COOLANT_THROUGH_TOOL: 2591 | if (!coolants.throughTool) { 2592 | break; 2593 | } 2594 | m = coolants.throughTool.on; 2595 | coolantOff = coolants.throughTool.off; 2596 | break; 2597 | case COOLANT_AIR: 2598 | if (!coolants.air) { 2599 | break; 2600 | } 2601 | m = coolants.air.on; 2602 | coolantOff = coolants.air.off; 2603 | break; 2604 | case COOLANT_AIR_THROUGH_TOOL: 2605 | if (!coolants.airThroughTool) { 2606 | break; 2607 | } 2608 | m = coolants.airThroughTool.on; 2609 | coolantOff = coolants.airThroughTool.off; 2610 | break; 2611 | case COOLANT_FLOOD_MIST: 2612 | if (!coolants.floodMist) { 2613 | break; 2614 | } 2615 | m = coolants.floodMist.on; 2616 | coolantOff = coolants.floodMist.off; 2617 | break; 2618 | case COOLANT_MIST: 2619 | if (!coolants.mist) { 2620 | break; 2621 | } 2622 | m = coolants.mist.on; 2623 | coolantOff = coolants.mist.off; 2624 | break; 2625 | case COOLANT_SUCTION: 2626 | if (!coolants.suction) { 2627 | break; 2628 | } 2629 | m = coolants.suction.on; 2630 | coolantOff = coolants.suction.off; 2631 | break; 2632 | case COOLANT_FLOOD_THROUGH_TOOL: 2633 | if (!coolants.floodThroughTool) { 2634 | break; 2635 | } 2636 | m = coolants.floodThroughTool.on; 2637 | coolantOff = coolants.floodThroughTool.off; 2638 | break; 2639 | } 2640 | 2641 | if (!m) { 2642 | onUnsupportedCoolant(coolant); 2643 | m = 9; 2644 | } 2645 | 2646 | if (m) { 2647 | if (Array.isArray(m)) { 2648 | for (var i in m) { 2649 | multipleCoolantBlocks.push(mFormat.format(m[i])); 2650 | } 2651 | } else { 2652 | multipleCoolantBlocks.push(mFormat.format(m)); 2653 | } 2654 | currentCoolantMode = coolant; 2655 | return multipleCoolantBlocks; // return the single formatted coolant value 2656 | } 2657 | return undefined; 2658 | } 2659 | 2660 | var mapCommand = { 2661 | COMMAND_STOP: 0, 2662 | COMMAND_OPTIONAL_STOP: 1, 2663 | COMMAND_END: 2, 2664 | COMMAND_SPINDLE_CLOCKWISE: 3, 2665 | COMMAND_SPINDLE_COUNTERCLOCKWISE: 4, 2666 | COMMAND_STOP_SPINDLE: 5, 2667 | COMMAND_ORIENTATE_SPINDLE: 19 2668 | }; 2669 | 2670 | function onCommand(command) { 2671 | switch (command) { 2672 | case COMMAND_STOP: 2673 | writeBlock(mFormat.format(0)); 2674 | forceSpindleSpeed = true; 2675 | return; 2676 | case COMMAND_START_SPINDLE: 2677 | onCommand(tool.clockwise ? COMMAND_SPINDLE_CLOCKWISE : COMMAND_SPINDLE_COUNTERCLOCKWISE); 2678 | return; 2679 | case COMMAND_LOCK_MULTI_AXIS: 2680 | return; 2681 | case COMMAND_UNLOCK_MULTI_AXIS: 2682 | return; 2683 | case COMMAND_START_CHIP_TRANSPORT: 2684 | return; 2685 | case COMMAND_STOP_CHIP_TRANSPORT: 2686 | return; 2687 | case COMMAND_BREAK_CONTROL: 2688 | return; 2689 | case COMMAND_TOOL_MEASURE: 2690 | return; 2691 | } 2692 | 2693 | var stringId = getCommandStringId(command); 2694 | var mcode = mapCommand[stringId]; 2695 | if (mcode != undefined) { 2696 | writeBlock(mFormat.format(mcode)); 2697 | } else { 2698 | onUnsupportedCommand(command); 2699 | } 2700 | } 2701 | 2702 | function onSectionEnd() { 2703 | // writeBlock(gPlaneModal.format(17)); 2704 | 2705 | if (currentSection.isMultiAxis()) { 2706 | writeBlock(gFeedModeModal.format(94)); // inverse time feed off 2707 | } 2708 | 2709 | if (((getCurrentSectionId() + 1) >= getNumberOfSections()) || 2710 | (tool.number != getNextSection() 2711 | .getTool().number)) { 2712 | onCommand(COMMAND_BREAK_CONTROL); 2713 | } 2714 | 2715 | if (true) { 2716 | if (isRedirecting()) { 2717 | if (firstPattern) { 2718 | var finalPosition = getFramePosition(currentSection.getFinalPosition()); 2719 | var abc; 2720 | if (currentSection.isMultiAxis() && machineConfiguration.isMultiAxisConfiguration()) { 2721 | abc = currentSection.getFinalToolAxisABC(); 2722 | } else { 2723 | abc = currentWorkPlaneABC; 2724 | } 2725 | if (abc == undefined) { 2726 | abc = new Vector(0, 0, 0); 2727 | } 2728 | setAbsoluteMode(finalPosition, abc); 2729 | subprogramEnd(); 2730 | } 2731 | } 2732 | } 2733 | forceAny(); 2734 | } 2735 | 2736 | /** Output block to do safe retract and/or move to home position. */ 2737 | function writeRetract() { 2738 | if (arguments.length == 0) { 2739 | error(localize('No axis specified for writeRetract().')); 2740 | return; 2741 | } 2742 | var words = []; // store all retracted axes in an array 2743 | for (var i = 0; i < arguments.length; ++i) { 2744 | let instances = 0; // checks for duplicate retract calls 2745 | for (var j = 0; j < arguments.length; ++j) { 2746 | if (arguments[i] == arguments[j]) { 2747 | ++instances; 2748 | } 2749 | } 2750 | if (instances > 1) { // error if there are multiple retract calls for the same axis 2751 | error(localize('Cannot retract the same axis twice in one line')); 2752 | return; 2753 | } 2754 | switch (arguments[i]) { 2755 | case X: 2756 | words.push('X' + xyzFormat.format(machineConfiguration.hasHomePositionX() ? machineConfiguration.getHomePositionX() : 0)); 2757 | break; 2758 | case Y: 2759 | words.push('Y' + xyzFormat.format(machineConfiguration.hasHomePositionY() ? machineConfiguration.getHomePositionY() : 0)); 2760 | break; 2761 | case Z: 2762 | words.push('Z' + xyzFormat.format(machineConfiguration.getRetractPlane())); 2763 | retracted = true; // specifies that the tool has been retracted to the safe plane 2764 | break; 2765 | default: 2766 | error(localize('Bad axis specified for writeRetract().')); 2767 | return; 2768 | } 2769 | } 2770 | if (words.length > 0) { 2771 | gMotionModal.reset(); 2772 | gAbsIncModal.reset(); 2773 | // writeBlock(gFormat.format(28), gAbsIncModal.format(91), words); // retract 2774 | writeBlock(gAbsIncModal.format(90)); 2775 | } 2776 | zOutput.reset(); 2777 | } 2778 | 2779 | function onClose() { 2780 | writeln(''); 2781 | optionalSection = false; 2782 | 2783 | writeBlock(mFormat.format(5)); // stop program, spindle stop, coolant off 2784 | 2785 | setCoolant(COOLANT_OFF); 2786 | 2787 | writeRetract(Z); 2788 | 2789 | disableLengthCompensation(true); 2790 | setSmoothing(false); 2791 | zOutput.reset(); 2792 | 2793 | setWorkPlane(new Vector(0, 0, 0)); // reset working plane 2794 | 2795 | if (properties.useG54x4) { 2796 | writeBlock(gFormat.format(54.4), 'P0'); 2797 | } 2798 | 2799 | writeRetract(X, Y); 2800 | 2801 | onImpliedCommand(COMMAND_END); 2802 | onImpliedCommand(COMMAND_STOP_SPINDLE); 2803 | if (subprograms.length > 0) { 2804 | writeln(''); 2805 | write(subprograms); 2806 | } 2807 | // writeln("%"); 2808 | } 2809 | -------------------------------------------------------------------------------- /snapmaker-fusion360-configuration-20180730/snapmaker.cps: -------------------------------------------------------------------------------- 1 | /** 2 | Copyright (C) 2016-2017 by Snapmaker, Inc. 3 | All rights reserved. 4 | 5 | Snapmaker (Marlin) post processor configuration. 6 | 7 | */ 8 | 9 | description = "Generic Snapmaker (Marlin)"; 10 | vendor = "SNAPMAKER"; 11 | vendorUrl = "http://www.snapmaker.com"; 12 | legal = "Copyright (C) 2016-2018 by Snapmaker, Inc."; 13 | certificationLevel = 2; 14 | minimumRevision = 24000; 15 | 16 | longDescription = "Generic milling post for Snapmaker.v20180725"; 17 | 18 | extension = ".cnc"; 19 | setCodePage("ascii"); 20 | 21 | capabilities = CAPABILITY_MILLING; 22 | tolerance = spatial(0.002, MM); 23 | 24 | minimumChordLength = spatial(0.01, MM); 25 | minimumCircularRadius = spatial(0.01, MM); 26 | maximumCircularRadius = spatial(1000, MM); 27 | minimumCircularSweep = toRad(0.01); 28 | maximumCircularSweep = toRad(180); 29 | allowHelicalMoves = true; 30 | allowedCircularPlanes = 0; // circular interpolation is not supported 31 | 32 | 33 | 34 | // user-defined properties 35 | properties = { 36 | writeMachine: true, // write machine 37 | showSequenceNumbers: false, // show sequence numbers 38 | sequenceNumberStart: 10, // first sequence number 39 | sequenceNumberIncrement: 1, // increment for sequence numbers 40 | separateWordsWithSpace: true // specifies that the words should be separated with a white space 41 | }; 42 | 43 | 44 | 45 | var gFormat = createFormat({prefix:"G", decimals:0}); 46 | var mFormat = createFormat({prefix:"M", decimals:0}); 47 | 48 | var xyzFormat = createFormat({decimals:(unit == MM ? 3 : 4), trim:false}); 49 | var feedFormat = createFormat({decimals:(unit == MM ? 1 : 2)}); 50 | // var toolFormat = createFormat({decimals:0}); 51 | // var rpmFormat = createFormat({decimals:0}); 52 | var secFormat = createFormat({decimals:3, forceDecimal:true}); // seconds - range 0.001-1000 53 | // var taperFormat = createFormat({decimals:1, scale:DEG}); 54 | 55 | var xOutput = createVariable({prefix:"X", force:true}, xyzFormat); 56 | var yOutput = createVariable({prefix:"Y", force:true}, xyzFormat); 57 | var zOutput = createVariable({prefix:"Z", force:true}, xyzFormat); 58 | var feedOutput = createVariable({prefix:"F", force:true}, feedFormat); 59 | // var sOutput = createVariable({prefix:"S", force:true}, rpmFormat); 60 | 61 | // circular output 62 | var iOutput = createReferenceVariable({prefix:"I", force:true}, xyzFormat); 63 | var jOutput = createReferenceVariable({prefix:"J", force:true}, xyzFormat); 64 | // var kOutput = createReferenceVariable({prefix:"K", force:true}, xyzFormat); 65 | 66 | var gMotionModal = createModal({force:true}, gFormat); // modal group 1 // G0-G3, ... 67 | // var gPlaneModal = createModal({onchange:function () {gMotionModal.reset();}}, gFormat); // modal group 2 // G17-19 68 | var gAbsIncModal = createModal({}, gFormat); // modal group 3 // G90-91 69 | // var gFeedModeModal = createModal({}, gFormat); // modal group 5 // G93-94 70 | var gUnitModal = createModal({}, gFormat); // modal group 6 // G20-21 71 | 72 | // collected state 73 | var sequenceNumber; 74 | var currentWorkOffset; 75 | 76 | /** 77 | Writes the specified block. 78 | */ 79 | function writeBlock() { 80 | if (properties.showSequenceNumbers) { 81 | writeWords2("N" + sequenceNumber, arguments); 82 | sequenceNumber += properties.sequenceNumberIncrement; 83 | } else { 84 | writeWords(arguments); 85 | } 86 | } 87 | 88 | function formatComment(text) { 89 | return ";" + String(text).replace(/[\(\)]/g, ""); 90 | } 91 | 92 | /** 93 | Output a comment. 94 | */ 95 | function writeComment(text) { 96 | writeln(formatComment(text)); 97 | } 98 | 99 | function onOpen() { 100 | if (!properties.separateWordsWithSpace) { 101 | setWordSeparator(""); 102 | } 103 | 104 | sequenceNumber = properties.sequenceNumberStart; 105 | 106 | if (programName) { 107 | writeComment(programName); 108 | } 109 | if (programComment) { 110 | writeComment(programComment); 111 | } 112 | 113 | // dump machine configuration 114 | // var vendor = machineConfiguration.getVendor(); 115 | var description = "Generic Snapmaker (Marlin) v20180725"; // FIXME 116 | var vendor = "Snapmaker"; 117 | var model = machineConfiguration.getModel(); 118 | // var description = machineConfiguration.getDescription(); 119 | 120 | if (properties.writeMachine && (vendor || model || description)) { 121 | writeComment(localize("Machine")); 122 | if (vendor) { 123 | writeComment(localize("vendor") + ": " + vendor); 124 | } 125 | if (model) { 126 | writeComment(localize("model") + ": " + model); 127 | } 128 | if (description) { 129 | writeComment(localize("description") + ": " + description); 130 | } 131 | } 132 | 133 | writeBlock(mFormat.format(3) + " P100"); 134 | writeBlock("G4 S2"); // dwell 2 seconds. 135 | 136 | switch (unit) { 137 | case IN: 138 | error(localize("Please select millimeters as unit when post processing. Inch mode is not recommended by the BoXZY team.")); 139 | return; 140 | // writeBlock(gUnitModal.format(20)); 141 | // break; 142 | case MM: 143 | writeBlock(gUnitModal.format(21)); 144 | break; 145 | } 146 | 147 | // absolute coordinates 148 | writeBlock(gAbsIncModal.format(90)); 149 | 150 | // writeBlock(gFormat.format(92), xOutput.format(0), yOutput.format(0), zOutput.format(0)); 151 | forceXYZ(); 152 | 153 | } 154 | 155 | function onComment(message) { 156 | writeComment(message); 157 | } 158 | 159 | /** Force output of X, Y, and Z. */ 160 | function forceXYZ() { 161 | xOutput.reset(); 162 | yOutput.reset(); 163 | zOutput.reset(); 164 | } 165 | 166 | /** Force output of X, Y, Z, and F on next output. */ 167 | function forceAny() { 168 | forceXYZ(); 169 | feedOutput.reset(); 170 | } 171 | 172 | function onSection() { 173 | 174 | var retracted = false; // specifies that the tool has been retracted to the safe plane 175 | 176 | writeln(""); 177 | 178 | if (hasParameter("operation-comment")) { 179 | var comment = getParameter("operation-comment"); 180 | if (comment) { 181 | writeComment(comment); 182 | } 183 | } 184 | 185 | // tool change not supported 186 | 187 | forceXYZ(); 188 | 189 | { // pure 3D 190 | var remaining = currentSection.workPlane; 191 | if (!isSameDirection(remaining.forward, new Vector(0, 0, 1))) { 192 | error(localize("Tool orientation is not supported.")); 193 | return; 194 | } 195 | setRotation(remaining); 196 | } 197 | 198 | // coolant not supported 199 | 200 | forceAny(); 201 | 202 | var initialPosition = getFramePosition(currentSection.getInitialPosition()); 203 | if (!retracted) { 204 | if (getCurrentPosition().z < initialPosition.z) { 205 | writeBlock(gMotionModal.format(0), zOutput.format(initialPosition.z)); 206 | } 207 | } 208 | 209 | if (retracted || isFirstSection() || true) { // we pull up Z above if we start lower 210 | gMotionModal.reset(); 211 | 212 | writeBlock( 213 | gAbsIncModal.format(90), 214 | gMotionModal.format(0), 215 | xOutput.format(initialPosition.x), 216 | yOutput.format(initialPosition.y), 217 | zOutput.format(initialPosition.z) 218 | ); 219 | } else { 220 | writeBlock( 221 | gAbsIncModal.format(90), 222 | gMotionModal.format(0), 223 | xOutput.format(initialPosition.x), 224 | yOutput.format(initialPosition.y) 225 | ); 226 | } 227 | } 228 | 229 | function onDwell(seconds) { 230 | if (seconds > 99999.999) { 231 | warning(localize("Dwelling time is out of range.")); 232 | } 233 | seconds = clamp(0.001, seconds, 99999.999); 234 | writeBlock(gFormat.format(4), "P" + secFormat.format(seconds)); 235 | } 236 | 237 | function onSpindleSpeed(spindleSpeed) { 238 | // writeBlock(sOutput.format(spindleSpeed)); 239 | } 240 | 241 | var pendingRadiusCompensation = -1; 242 | 243 | function onRadiusCompensation() { 244 | pendingRadiusCompensation = radiusCompensation; 245 | } 246 | 247 | function onRapid(_x, _y, _z) { 248 | var x = xOutput.format(_x); 249 | var y = yOutput.format(_y); 250 | var z = zOutput.format(_z); 251 | if (x || y || z) { 252 | if (pendingRadiusCompensation >= 0) { 253 | error(localize("Radius compensation mode cannot be changed at rapid traversal.")); 254 | return; 255 | } 256 | writeBlock(gMotionModal.format(0), x, y, z); 257 | feedOutput.reset(); 258 | } 259 | } 260 | 261 | function onLinear(_x, _y, _z, feed) { 262 | // at least one axis is required 263 | if (pendingRadiusCompensation >= 0) { 264 | // ensure that we end at desired position when compensation is turned off 265 | xOutput.reset(); 266 | yOutput.reset(); 267 | } 268 | var x = xOutput.format(_x); 269 | var y = yOutput.format(_y); 270 | var z = zOutput.format(_z); 271 | var f = feedOutput.format(feed); 272 | if (x || y || z) { 273 | if (pendingRadiusCompensation >= 0) { 274 | error(localize("Radius compensation mode is not supported.")); 275 | return; 276 | } else { 277 | writeBlock(gMotionModal.format(1), x, y, z, f); 278 | } 279 | } else if (f) { 280 | if (getNextRecord().isMotion()) { // try not to output feed without motion 281 | feedOutput.reset(); // force feed on next line 282 | } else { 283 | writeBlock(gMotionModal.format(1), f); 284 | } 285 | } 286 | } 287 | 288 | function onRapid5D(_x, _y, _z, _a, _b, _c) { 289 | error(localize("Multi-axis motion is not supported.")); 290 | } 291 | 292 | function onLinear5D(_x, _y, _z, _a, _b, _c, feed) { 293 | error(localize("Multi-axis motion is not supported.")); 294 | } 295 | 296 | function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { 297 | // one of X/Y and I/J are required and likewise 298 | 299 | if (pendingRadiusCompensation >= 0) { 300 | error(localize("Radius compensation cannot be activated/deactivated for a circular move.")); 301 | return; 302 | } 303 | 304 | var start = getCurrentPosition(); 305 | 306 | if (isFullCircle()) { 307 | if (isHelical()) { 308 | linearize(tolerance); 309 | return; 310 | } 311 | switch (getCircularPlane()) { 312 | case PLANE_XY: 313 | writeBlock(gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), iOutput.format(cx - start.x, 0), jOutput.format(cy - start.y, 0), feedOutput.format(feed)); 314 | break; 315 | /* 316 | case PLANE_ZX: 317 | writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), zOutput.format(z), iOutput.format(cx - start.x, 0), kOutput.format(cz - start.z, 0), feedOutput.format(feed)); 318 | break; 319 | case PLANE_YZ: 320 | writeBlock(gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), yOutput.format(y), jOutput.format(cy - start.y, 0), kOutput.format(cz - start.z, 0), feedOutput.format(feed)); 321 | break; 322 | */ 323 | default: 324 | linearize(tolerance); 325 | } 326 | } else { 327 | switch (getCircularPlane()) { 328 | case PLANE_XY: 329 | writeBlock(gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x, 0), jOutput.format(cy - start.y, 0), feedOutput.format(feed)); 330 | break; 331 | /* 332 | case PLANE_ZX: 333 | writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x, 0), kOutput.format(cz - start.z, 0), feedOutput.format(feed)); 334 | break; 335 | case PLANE_YZ: 336 | writeBlock(gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), jOutput.format(cy - start.y, 0), kOutput.format(cz - start.z, 0), feedOutput.format(feed)); 337 | break; 338 | */ 339 | default: 340 | linearize(tolerance); 341 | } 342 | } 343 | } 344 | 345 | var mapCommand = { 346 | COMMAND_STOP:0, 347 | COMMAND_END:2, 348 | COMMAND_SPINDLE_CLOCKWISE:3, 349 | COMMAND_SPINDLE_COUNTERCLOCKWISE:4, 350 | COMMAND_STOP_SPINDLE:5 351 | }; 352 | 353 | function onCommand(command) { 354 | switch (command) { 355 | case COMMAND_START_SPINDLE: 356 | onCommand(tool.clockwise ? COMMAND_SPINDLE_CLOCKWISE : COMMAND_SPINDLE_COUNTERCLOCKWISE); 357 | return; 358 | case COMMAND_LOCK_MULTI_AXIS: 359 | return; 360 | case COMMAND_UNLOCK_MULTI_AXIS: 361 | return; 362 | case COMMAND_BREAK_CONTROL: 363 | return; 364 | case COMMAND_TOOL_MEASURE: 365 | return; 366 | } 367 | 368 | var stringId = getCommandStringId(command); 369 | var mcode = mapCommand[stringId]; 370 | if (mcode != undefined) { 371 | writeBlock(mFormat.format(mcode)); 372 | } else { 373 | onUnsupportedCommand(command); 374 | } 375 | } 376 | 377 | function onSectionEnd() { 378 | forceAny(); 379 | } 380 | 381 | function onClose() { 382 | writeBlock(gFormat.format(0), xOutput.format(0), yOutput.format(0)); // @TODO return to the origin 383 | writeBlock(mFormat.format(5)); 384 | } 385 | -------------------------------------------------------------------------------- /snapmaker-vcarve-configuration/README.md: -------------------------------------------------------------------------------- 1 | This is snapmaker's post-processing configuration file for aspire software. 2 | Including tool configuration files and post-processing files. 3 | 4 | **The official website is** 5 | - https://www.vectric.com/products/aspire 6 | 7 | **Aspire software post-processing documents** 8 | - https://docs.vectric.com/docs/V10.0/Aspire/ENU/Help/form/post-processor-editing 9 | 10 | **How to add the snapmaker post-processing to the aspire software?** 11 | 1. Copy the Snapmaker_cnc_mm.pp to the PostP path; 12 | The PostP folder can be reached from within the application, by clicking “File > Open Application Data Folder” from the main menu of the application. 13 | 14 | 2. By clicking “Toolpaths > install PostProcessor...” from the main menu of the application. 15 | 16 | **How to add the Snapmaker 2.0 CNC Tools to the aspire software?** 17 | - By clicking "Toolpaths > Tool Database" from the main menu of the application to open Tool Database,then clicking the import a tool database. 18 | 19 | #### Warn !!! 20 | 1. If you are using the tool provided by Snapmaker 2.0 but not the Snapmaker 2.0 CNC Tools.vtdb, then the "Feed rate" is preferably less than 600 mm/min or 22 inches/min, and the "Pass Depth" is preferably less than 0.4mm. 21 | 22 | 23 | -------------------------------------------------------------------------------- /snapmaker-vcarve-configuration/Snapmaker 2.0 CNC Tools.vtdb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Snapmaker/snapmaker_cnc_post_process/263bf4e84764273583fe7ceda27a303da5f23eab/snapmaker-vcarve-configuration/Snapmaker 2.0 CNC Tools.vtdb -------------------------------------------------------------------------------- /snapmaker-vcarve-configuration/Snapmaker_cnc_mm.pp: -------------------------------------------------------------------------------- 1 | +================================================ 2 | + 3 | + Vectric machine output configuration file 4 | + 5 | +================================================ 6 | + 7 | + History 8 | + 9 | + Who When What 10 | + ======== ========== =========================== 11 | + Tony M 13/09/2010 Written 12 | + Mark 16/07/2015 Added New Segment section. 13 | + ================================================ 14 | 15 | POST_NAME = "Snapmaker CNC (mm) (*.cnc)" 16 | 17 | FILE_EXTENSION = "cnc" 18 | 19 | UNITS = "MM" 20 | 21 | +------------------------------------------------ 22 | + Line terminating characters 23 | +------------------------------------------------ 24 | 25 | LINE_ENDING = "[13][10]" 26 | 27 | +------------------------------------------------ 28 | + Block numbering 29 | +------------------------------------------------ 30 | 31 | LINE_NUMBER_START = 0 32 | LINE_NUMBER_INCREMENT = 10 33 | LINE_NUMBER_MAXIMUM = 9999999 34 | 35 | +================================================ 36 | + 37 | + Formating for variables 38 | + 39 | +================================================ 40 | 41 | VAR LINE_NUMBER = [N|A| N|1.0] 42 | VAR SPINDLE_SPEED = [S|A| S|1.0] 43 | VAR FEED_RATE = [F|C| F|1.1] 44 | VAR X_POSITION = [X|C| X|1.3] 45 | VAR Y_POSITION = [Y|C| Y|1.3] 46 | VAR Z_POSITION = [Z|C| Z|1.3] 47 | VAR ARC_CENTRE_I_ABS_POSITION = [IA|A| I|1.3] 48 | VAR ARC_CENTRE_J_ABS_POSITION = [JA|A| J|1.3] 49 | VAR X_HOME_POSITION = [XH|A| X|1.3] 50 | VAR Y_HOME_POSITION = [YH|A| Y|1.3] 51 | VAR Z_HOME_POSITION = [ZH|A| Z|1.3] 52 | 53 | +================================================ 54 | + 55 | + Block definitions for toolpath output 56 | + 57 | +================================================ 58 | 59 | +--------------------------------------------------- 60 | + Commands output at the start of the file 61 | +--------------------------------------------------- 62 | 63 | begin HEADER 64 | 65 | "G90" 66 | "G0 Z10.00 F600" 67 | "G21" 68 | "M3 [S]" 69 | 70 | +--------------------------------------------------- 71 | + Commands output for rapid moves 72 | +--------------------------------------------------- 73 | 74 | begin RAPID_MOVE 75 | 76 | "G0 [X] [Y] [Z]" 77 | 78 | 79 | +--------------------------------------------------- 80 | + Commands output for the first feed rate move 81 | +--------------------------------------------------- 82 | 83 | begin FIRST_FEED_MOVE 84 | 85 | "G1 [X] [Y] [Z] [F]" 86 | 87 | 88 | +--------------------------------------------------- 89 | + Commands output for feed rate moves 90 | +--------------------------------------------------- 91 | 92 | begin FEED_MOVE 93 | 94 | "G1 [X] [Y] [Z]" 95 | 96 | 97 | +--------------------------------------------------- 98 | + Commands output for the first clockwise arc move 99 | +--------------------------------------------------- 100 | 101 | begin FIRST_CW_ARC_MOVE 102 | 103 | "G2 [X] [Y] [IA] [JA] [F]" 104 | 105 | 106 | +--------------------------------------------------- 107 | + Commands output for clockwise arc move 108 | +--------------------------------------------------- 109 | 110 | begin CW_ARC_MOVE 111 | 112 | "G2 [X] [Y] [IA] [JA]" 113 | 114 | 115 | +--------------------------------------------------- 116 | + Commands output for the first counterclockwise arc move 117 | +--------------------------------------------------- 118 | 119 | begin FIRST_CCW_ARC_MOVE 120 | 121 | "G3 [X] [Y] [IA] [JA] [F]" 122 | 123 | 124 | +--------------------------------------------------- 125 | + Commands output for counterclockwise arc move 126 | +--------------------------------------------------- 127 | 128 | begin CCW_ARC_MOVE 129 | 130 | "G3 [X] [Y] [IA] [JA]" 131 | 132 | 133 | +--------------------------------------------------- 134 | + Commands output at the end of the file 135 | +--------------------------------------------------- 136 | 137 | begin FOOTER 138 | 139 | "M5" 140 | 141 | --------------------------------------------------------------------------------