From bbb9e23e8f220f6eff83a62b8b96ac65180642f9 Mon Sep 17 00:00:00 2001 From: Jestah Carnie Date: Wed, 5 Mar 2025 00:36:23 +1300 Subject: [PATCH 01/21] minor UI changes to syil_lnc_toolpath.cps - Post properties table renamed and reordered - G30 option added to safePositionMethod() - Tool change position added to writeToolBlock() and machine simulation details updated to allow simulation of tool change connection moves --- syil_lnc_toolpath.cps | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/syil_lnc_toolpath.cps b/syil_lnc_toolpath.cps index 4b73796..2e69514 100644 --- a/syil_lnc_toolpath.cps +++ b/syil_lnc_toolpath.cps @@ -174,6 +174,7 @@ properties = { type : "enum", values : [ {title:"G28", id:"G28"}, + {title:"G30", id:"G30"}, {title:"G53", id:"G53"} ], value: "G28", @@ -182,6 +183,7 @@ properties = { breakControlError: { title : "Max. Break Control Error", description: "Maximum Allowable Error for Break Control.", + group : "toolChange", type : "number", value : 0.05, scope : "post" @@ -189,7 +191,7 @@ properties = { ForceTCPosition: { title : "Change Position Before Toolchange", description: "Change the machine position before executing a toolchange.", - group : 4, + group : "toolChange", type : "boolean", value : false, scope : "post" @@ -197,7 +199,7 @@ properties = { TCposX: { title : "Toolchange Position X Axis - Machine Coordinate", description: "Machine Coordinate for toolchange on X Axis.", - group : 4, + group : "toolChange", type : "number", value : 0, scope : "post" @@ -205,7 +207,7 @@ properties = { TCposY: { title : "Toolchange Position Y Axis - Machine Coordinate", description: "Machine Coordinate for toolchange on Y Axis.", - group : 4, + group : "toolChange", type : "number", value : 0, scope : "post" @@ -213,29 +215,34 @@ properties = { EnableZeroPointCompensation: { title : "Enable Zero Point Compensation", description: "Allows probing cycles to compensate for deltas bewteen a probed part and it's expected postition. The WCS after probing becomes the override origin translated by the computed deltas.", - group : 5, + group : "preferences", type : "boolean", value : false, scope : "post" }, - CustomOnOpenGcode: { - title : "Custom on open G-code", + _0CustomOnOpenGcode: { + title : "on open G-code", description: "Inserts custom G-code at the beginning of the program", - group : 6, + group : "CustomGcode", type : "string", value : "", scope : "post" }, - CustomOnCloseGcode: { - title : "Custom on close G-code", + _1CustomOnCloseGcode: { + title : "on close G-code", description: "Inserts custom G-code at the end of the program", - group : 7, + group : "CustomGcode", type : "string", value : "", scope : "post" } }; +groupDefinitions = { + toolChange : {title:"Tool change", description: "Setting related to toolchanges", collapsed: true, order: 31}, + CustomGcode : {title:"Custom G-code", description: "G-code to add to the start of the program", collapsed: true, order: 33}, +}; + // wcs definiton wcsDefinitions = { useZeroOffset: false, @@ -438,7 +445,7 @@ function onOpen() { writeBlock("@983 = TIME[5]"); //hour writeBlock("@984 = TIME[6]"); //minute writeBlock("@985 = TIME[7]"); //second - writeBlock(getProperty("CustomOnOpenGcode")); + writeBlock(getProperty("_0CustomOnOpenGcode")); } function setSmoothing(mode) { @@ -754,7 +761,7 @@ function onClose() { writeSubprograms(); } writeln("%"); - writeBlock(getProperty("CustomOnCloseGcode")); + writeBlock(getProperty("_1CustomOnCloseGcode")); } // >>>>> INCLUDED FROM include_files/commonFunctions.cpi @@ -1088,10 +1095,12 @@ function onComment(text) { */ function writeToolBlock() { var show = getProperty("showSequenceNumbers"); + var TCposX = getProperty("TCposX"); + var TCposY = getProperty("TCposY"); setProperty("showSequenceNumbers", (show == "true" || show == "toolChange") ? "true" : "false"); writeBlock(arguments); setProperty("showSequenceNumbers", show); - machineSimulation({/*x:toPreciseUnit(200, MM), y:toPreciseUnit(200, MM), coordinates:MACHINE,*/ mode:TOOLCHANGE}); // move machineSimulation to a tool change position + machineSimulation({x:toPreciseUnit(TCposX, MM), y:toPreciseUnit(TCposY, MM), coordinates:MACHINE, mode:TOOLCHANGE}); // move machineSimulation to a tool change position } var skipBlocks = false; From bdb5a8e7595045bf6ce9c2d1cd28db2978514677 Mon Sep 17 00:00:00 2001 From: Jestah Carnie Date: Wed, 5 Mar 2025 00:37:42 +1300 Subject: [PATCH 02/21] Update changelog.md minor UI changes to syil_lnc_toolpath.cps --- changelog.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/changelog.md b/changelog.md index 30e37c6..3d83150 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,8 @@ +# V1.2.2 +- Post properties table renamed and reordered +- G30 option added to safePositionMethod() +- Tool change position added to writeToolBlock() and machine simulation details updated to allow simulation of tool change connection moves + # V1.2.1 - Updated LOADTOOL to with the ability to skip resetting tool offsets and a few minor UI changes From 9a69c829e100866c52e2c21448cc8d3aca4ddf8e Mon Sep 17 00:00:00 2001 From: Jestah Carnie Date: Fri, 7 Mar 2025 18:44:10 +1300 Subject: [PATCH 03/21] Updated the manual tool change logic Added manual tool change logic to onSection() to support unloading the tool from the ATC umbrella and installing a second manual tool. - Extra logic to shut down coolant early to maximise drip-out time - Extra info passed from fusion into comments to help the operator confirm the right tool, holder and stick out is being loaded into the spindle. Added a first pass at tool brake control - needs testing and uses the stock syil provided macor M106 Removed unrequired variables from writeToolBlock() --- syil_lnc_toolpath.cps | 55 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/syil_lnc_toolpath.cps b/syil_lnc_toolpath.cps index 2e69514..9859a53 100644 --- a/syil_lnc_toolpath.cps +++ b/syil_lnc_toolpath.cps @@ -337,10 +337,10 @@ var settings = { }, retract: { cancelRotationOnRetracting: false, // specifies that rotations (G68) need to be canceled prior to retracting - methodXY : undefined, // special condition, overwrite retract behavior per axis + methodXY : "G30", // special condition, overwrite retract behavior per axis methodZ : undefined, // special condition, overwrite retract behavior per axis - useZeroValues : ["G28", "G30"], // enter property value id(s) for using "0" value instead of machineConfiguration axes home position values (ie G30 Z0) - homeXY : {onIndexing:false, onToolChange:false, onProgramEnd:{axes:[X, Y]}} // Specifies when the machine should be homed in X/Y. Sample: onIndexing:{axes:[X, Y], singleLine:false} + useZeroValues : ["G28"], // enter property value id(s) for using "0" value instead of machineConfiguration axes home position values (ie G30 Z0) + homeXY : {onIndexing:false, onToolChange:{axes:[X, Y]}, onProgramEnd:{axes:[X, Y]}} // Specifies when the machine should be homed in X/Y. Sample: onIndexing:{axes:[X, Y], singleLine:false} }, parametricFeeds: { firstFeedParameter : 500, // specifies the initial parameter number to be used for parametric feedrate output @@ -475,7 +475,33 @@ function onSection() { operationNeedsSafeStart = getProperty("safeStartAllOperations") && !isFirstSection(); initializeSmoothing(); // initialize smoothing mode + // Manual Tool Change Tool Removal + // place in own function or COMMAND_MANUAL_LOAD + COMMAND_MANUAL_UNLOAD + if (insertToolCall && !isFirstSection()) { + if(getPreviousSection().getTool().manualToolChange == true) { + setCoolant(COOLANT_OFF); + onCommand(COMMAND_STOP_SPINDLE); + writeRetract(Z); + writeRetract(settings.retract.homeXY.onToolChange); + onCommand(COMMAND_STOP); + machineSimulation({x:getProperty("TCposX"), y: getProperty("TCposY"), coordinates:MACHINE, mode:TOOLCHANGE}); // move machineSimulation to a tool change position + //writeComment("Flip to Manual, Swap tools then cycle start to resume"); KC need to test + writeComment(""); + previousSection = getPreviousSection(); + if (previousSection) { + previousToolNumber = previousSection.getTool().number; + writeComment("Flip to manual, remove T" + previousToolNumber + " and replace with T" + tool.number + " then cycle start to resume" ); + } else { + writeComment("No previous tool (first tool in program)."); + } + } + } + if (insertToolCall || newWorkOffset || newWorkPlane || smoothing.cancel || state.tcpIsActive) { + // stop coolant before retract during manual tool change + if (!isLastSection() && tool.manualToolChange == true && getNextSection().getTool().manualToolChange == true) { + onCommand(COMMAND_COOLANT_OFF) + } // stop spindle before retract during tool change if (insertToolCall && !isFirstSection()) { @@ -622,7 +648,10 @@ function onCommand(command) { case COMMAND_LOAD_TOOL: writeToolBlock("T" + toolFormat.format(tool.number), mFormat.format(6)); writeComment(tool.comment); - + if (tool.manualToolChange != true){ + writeComment(tool.description); + writeComment(tool.bodyLength + "mm Stick out below " + tool.holderDescription + " holder"); + } // preload tools not supported on umbrella changer machines //var preloadTool = getNextTool(tool.number != getFirstTool().number); //if (getProperty("preloadTool") && preloadTool) { @@ -646,6 +675,13 @@ function onCommand(command) { case COMMAND_STOP_CHIP_TRANSPORT: return; case COMMAND_BREAK_CONTROL: + onCommand(COMMAND_STOP_SPINDLE); + setCoolant(COOLANT_OFF) + writeRetract(Z); + // add tool change position move? + writeBlock(mFormat.format(106) + " T" + toolFormat.format(tool.number)+ " D" + xyzFormat.format(tool.diameter) + " E"+ getProperty("breakControlError")); + machineSimulation({x:getProperty("TCposX"), y: getProperty("TCposY"), coordinates:MACHINE, mode:TOOLCHANGE}); // move machineSimulation to a tool change position + // add second retract post tool measure? return; case COMMAND_TOOL_MEASURE: return; @@ -1095,12 +1131,10 @@ function onComment(text) { */ function writeToolBlock() { var show = getProperty("showSequenceNumbers"); - var TCposX = getProperty("TCposX"); - var TCposY = getProperty("TCposY"); setProperty("showSequenceNumbers", (show == "true" || show == "toolChange") ? "true" : "false"); writeBlock(arguments); setProperty("showSequenceNumbers", show); - machineSimulation({x:toPreciseUnit(TCposX, MM), y:toPreciseUnit(TCposY, MM), coordinates:MACHINE, mode:TOOLCHANGE}); // move machineSimulation to a tool change position + machineSimulation({x:getProperty("TCposX"), y: getProperty("TCposY"), coordinates:MACHINE, mode:TOOLCHANGE}); // move machineSimulation to a tool change position } var skipBlocks = false; @@ -1616,8 +1650,13 @@ function writeToolCall(tool, insertToolCall) { } if (tool.manualToolChange) { + onCommand(COMMAND_LOAD_TOOL); //KC calls tool change to swap out old tool for manual tool pocket onCommand(COMMAND_STOP); - writeComment("MANUAL TOOL CHANGE TO T" + toolFormat.format(tool.number)); + //writeComment("MANUAL TOOL CHANGE TO T" + toolFormat.format(tool.number)); + writeComment("Flip to Manual, Swap tool to T" + toolFormat.format(tool.number)); + writeComment("H" + tool.lengthOffset + " - " + tool.description); + writeComment(tool.bodyLength + "mm Stick out below " + tool.holderDescription + " holder"); + machineSimulation({x:toPreciseUnit(getProperty("TCposX"), MM), y:toPreciseUnit( getProperty("TCposY") , MM), coordinates:MACHINE, mode:TOOLCHANGE}); // move machineSimulation to a tool change position } else { if (!isFirstSection() && getProperty("optionalStop") && insertToolCall) { onCommand(COMMAND_OPTIONAL_STOP); From e21cb755dab8c5fb0e7a13ba02d27fa81efcb36d Mon Sep 17 00:00:00 2001 From: Robot Oblivion Date: Mon, 31 Mar 2025 17:14:23 +1300 Subject: [PATCH 04/21] Updates to the macro set by Robot Oblivion to work with post-processor Revision 44168 General updates - swapped many messages and alarms to lowercase for added readability at the control - a few minor variable number changes to allow new updates in other macros - all G28 Z0 calls for G53 G90 G00 Z0 CALIBRATEPROBEBLOCK - switch for spindle orientation called from ProbeConfig - removed inch mode call as not required (block calibrate) CALIBRATEPROBERING - argument A removed and the expected DIAMETER of the artifact is now provided by the PROBECONFIG macro - offset conversion moved to ProbingConfig PROBECONFIG - Added metric and freedom unit option pulls data from @10 used by many of the stock Syil tool change macros to assess machine settings - added ring gauge size in this macro so only one file needs to be updated - work offset conversion from G54.xx format and checks moved into this macro. Offsets P01-09 require a leading zero to be used to address issues around using values P10 - P99 - WCS above #137 are protected from update CALIBRATETOOLSET, TOOLSET - switch to swap between metric or freedom units - minor changes to load all variables before starting prep blocks CALIBRATEZ -few minor layout changes CHECKPOSITIONALTOLERANCE - switch for spindle orientation called from ProbeConfig - work offsets sent to probe config for conversion and checks - user message used to inform out of tolerance error at control for faster troubleshooting. Rounding is applied to these values before an alarm is called to stop the program and force a reset COMPZEROPOINT - switch for spindle orientation called from ProbeConfig - work offsets sent to probe config for conversion and checks COMPZEROPOINT, FINDCOR - work offsets sent to probe config for conversion and checks PROBEBORE, PROBECIRCULARBOSS, PROBEBORE - added a rounding option to the inspection report - inspection report is displayed in units the machine is set to PROBERECTANGULARBOSS - added a rounding option to the inspection report - the report is displayed in units the machine is set to - The spindle reorientated back to 0 degrees after probing PROBEINSIDECORNER, PROBEOUTSIDECORNER - switch for spindle orientation called from ProbeConfig - G00 call on exit to return to rapid as can not be called from post PROBEX, PROBEY - switch for spindle orientation called from ProbeConfig - work offsets sent to probe config for conversion and checks - spindle orientation added to ensure the probe is always touching the same surface and matches other cycles - G00 call on exit to return to rapid as can not be called from post PROBEZ - switch for spindle orientation called from ProbeConfig - work offsets sent to probe config for conversion and checks - G00 call on exit to return to rapid as can not be called from post PROBEXSLOT ,PROBEXWEB, PROBEYSLOT, PROBEYWEB - switch for spindle orientation called from ProbeConfig - work offsets sent to probe config for conversion and checks - user message used to inform overside error at control for faster troubleshooting. Rounding is applied to these values before an alarm is called to stop the program and force a reset - round applied to the inspection report PROBEXYANGLE - switch for spindle orientation called from ProbeConfig - work offsets sent to probe config for conversion and checks PROTECTEDMOVE, SAFESPIN - switch for spindle orientation called from ProbeConfig --- CALIBRATEPROBEBLOCK | 20 +++---- CALIBRATEPROBERING | 36 ++++++----- CALIBRATEPROBEZ | 55 ++++++++--------- CALIBRATETOOLSET | 57 +++++++++++------- CHECKPOSITIONALTOLERANCE | 126 +++++++++++++++++++++++---------------- COMPZEROPOINT | 40 +++++++------ COPYWCS | 24 ++++---- FINDCOR | 35 +++++------ LOADTOOL | 17 +++--- PROBEBORE | 50 +++++++++------- PROBECIRCULARBOSS | 68 ++++++++++++--------- PROBECONFIG | 104 +++++++++++++++++++++++++------- PROBEINSIDECORNER | 22 +++++-- PROBEOUTSIDECORNER | 24 +++++--- PROBEPOCKET | 46 ++++++++------ PROBERECTANGULARBOSS | 52 +++++++++------- PROBEX | 68 +++++++++++---------- PROBEXSLOT | 68 +++++++++++++-------- PROBEXWEB | 83 ++++++++++++++------------ PROBEXYANGLE | 42 +++++++------ PROBEY | 81 +++++++++++++------------ PROBEYSLOT | 69 ++++++++++++--------- PROBEYWEB | 75 +++++++++++++---------- PROBEZ | 103 ++++++++++++++++---------------- PROTECTEDMOVE | 26 +++++--- SAFESPIN | 21 +++++-- TOOLSET | 50 ++++++++++------ 27 files changed, 867 insertions(+), 595 deletions(-) diff --git a/CALIBRATEPROBEBLOCK b/CALIBRATEPROBEBLOCK index 6b00bd8..35815a7 100644 --- a/CALIBRATEPROBEBLOCK +++ b/CALIBRATEPROBEBLOCK @@ -1,14 +1,15 @@ -// Copyright 2024 Toolpath Labs Inc., Justin Gray, and Josh Smith +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion -// CALIBRATE PROBE TIP DIAMETER +//CALIBRATEPROBEBLOCK +//CALIBRATE PROBE TIP DIAMETER using a rectanglar object -// #1 is the expected X length of the artifact -// #2 is the expected Y length of the artifact -// #3 is the Z drop height +// Argument A -> #1 is the expected X length of the artifact +// Argument B -> #2 is the expected Y length of the artifact +// Argument C -> #3 is the Z drop height +// Initial Coding: Justin Gray G90 G94 G17 G49 G40 G80 -G20 // inch // load probe config G65 "PROBECONFIG" @@ -21,7 +22,6 @@ M19 // ORIENT SPINDLE // Make sure diameter is zero when calibrating W_TOOL_DATA[0,#100,3,0] // store tool diameter - // calling web probe macros macros to measure the rectangle G65 "PROBEXWEB" A0 B#1 C#3 Q0 G65 "PROBEYWEB" A0 B#2 C#3 Q0 @@ -35,8 +35,8 @@ G65 "PROBEYWEB" A0 B#2 C#3 Q0 W_TOOL_DATA[0,#100,3,#135] // store tool diameter MENU_ADD["Ruby Diameter Set To: #135",""]; -MENU["CALIBRATION REPORT","RESULTS","",1]; +MENU["Calibration report", "Results", "", 1]; -M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY G90 -M99 +M99 \ No newline at end of file diff --git a/CALIBRATEPROBERING b/CALIBRATEPROBERING index b5f93cb..8586d74 100644 --- a/CALIBRATEPROBERING +++ b/CALIBRATEPROBERING @@ -1,10 +1,12 @@ -// Copyright 2024 Toolpath Labs Inc., Justin Gray, and Josh Smith +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion -// CALIBRATEDIAMETER -// Description: Calibrate the Diameter of the probe using a ring guage -// Initial coding 1/14/2024: Joshua Smith +// CALIBRATEPROBERING +// Calibrate the Diameter of the probe using a ring guage // Your probe must be concentric and you must use a ring guage!!!!!!!!!! -// #1 is the expected DIAMETER of the artifact +// **Ring gauge ID set in ProbeConfig file + +// Initial coding 1/14/2024: Joshua Smith +// Modified 31/03/2025: Robot Oblivion // load probe config G65 "PROBECONFIG" @@ -13,32 +15,34 @@ M19 // ORIENT SPINDLE // important local variables #100 = @100 // TOOL NUMBER PROVIDED BY PROBECONFIG MACRO +#129 = @129 // Calibrated ring gauge diameter provided by PROBECONFIG MACRO +#111 = @111 // EXTENDED WORKOFFSET that stores Z calibration (is not updated or rest) // Make sure diameter is zero when calibrating W_TOOL_DATA[0,#100,3,0] // store tool diameter // calling our slot macros the first time centers probe -G65 "PROBEXSLOT" A0 B#1 Q0 -G65 "PROBEYSLOT" A0 B#1 Q0 +G65 "PROBEXSLOT" A54 P#111 B#129 Q0 I1 +G65 "PROBEYSLOT" A54 P#111 B#129 Q0 I1 // calling our slot macros a second time gives an accurate inspection -G65 "PROBEXSLOT" A0 B#1 Q0 -G65 "PROBEYSLOT" A0 B#1 Q0 +G65 "PROBEXSLOT" A54 P#111 B#129 Q0 I1 +G65 "PROBEYSLOT" A54 P#111 B#129 Q0 I1 // average Diameter calculation // @999 and @998 are set in the slot macros // this could be improved by keeping track of both X and Y diameters and controling probe orientation -#131 = @998 // measured ring guage diameter in x -#132 = @999 // measured ring guage diameter in y -#133 = #1-#131 // error in x -#134 = #1-#132 // error in y +#131 = @998 // measured ring guage diameter x +#132 = @999 // measured ring guage diameter y +#133 = #129 - #131 // error in x +#134 = #129 - #132 // error in y #135 = ABS[#133 + #134]/2 // average error W_TOOL_DATA[0,#100,3,#135] // store tool diameter MENU_ADD["Ruby Diameter Set To: #135",""]; -MENU["CALIBRATION REPORT","RESULTS","",1]; +MENU["Calibration report","Results","",1]; -M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY -G90 +M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +G90 // return to absolute mode M99 \ No newline at end of file diff --git a/CALIBRATEPROBEZ b/CALIBRATEPROBEZ index 5d06d7f..447669c 100644 --- a/CALIBRATEPROBEZ +++ b/CALIBRATEPROBEZ @@ -1,84 +1,79 @@ -// Copyright 2024 Toolpath Labs Inc., Justin Gray and Josh Smith +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion // CALIBRATEZ // THIS MACRO ASSUMES THAT YOU HAVE PUT YOUR GAUGE TOOL IN THE SPINDLE -// AND MANUALLY JOGGED UP TILL YOUR REFERENCE ARTIFACT CAN JUST BARELY SLIDE UNDER THE TOOL. -// THE MACRO WILL SAVE THE XY LOCATION FOR FUTURE USE AND STORE THE REFERENCE HEIGHT OFFSET +// AND MANUALLY JOGGED UP TILL YOUR REFERENCE ARTIFACT CAN JUST BARELY SLIDE UNDER THE TOOL. +// THE MACRO WILL SAVE THE XY LOCATION FOR FUTURE USE AND STORE THE REFERENCE HEIGHT OFFSET -// Argument A -> turns on/off full calibration: default is quick calibration +// Argument A -> #1 turns on/off full calibration: default is quick calibration + +// Initial Coding: Justin Gray +// Modified 31/03/2025: Robot Oblivion // load probe config G65 "PROBECONFIG" -M19 // ORIENT SPINDLE - // important local variables #100 = @100 // TOOL NUMBER PROVIDED BY PROBECONFIG MACRO - -#108 = @108 // PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO - #104 = @104 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO #105 = @105 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO #106 = @106 // PROBE CLEARANCE DISTANCE #108 = @108 // PROBE BACKOFF DISTANCE #109 = @109 // MASTER TOOL GAUGE LENGTH - // NOTE: @5109 will be used to save reference block height #111 = @111 // PROBE CALIBRATION EXTENDED WORKOFFSET NUMBER + // NOTE: @5109 will be used to save reference block height + +M19 // ORIENT SPINDLE IF [#1!=#0] - MSG_OK["CALIBRATE PROBE", "ZERO MASTER GAUGE TOOL ON CALIBRATION ARTIFACT AND LEAVE IT THERE",""] + MSG_OK["Calibrate probe", "Zero master gauge tool on calibration artifact and leave it there", ""] @5109 = R_MACH_COOR[0,3] // GET MACHINE Z COORDINATE WHICH SHOULD BE THE TOP OF A 123 BLOCK - #120 = @5109 + #140 = @5109 - // STORE THE CURRENT POSITION TO G54P99 FOR FUTURE FAST CALIBRATION + // STORE THE CURRENT POSITION TO PROBE CALIBRATION EXTENDED WORKOFFSET NUMBER FOR FUTURE FAST CALIBRATION W_G54EXP_COOR[0,#111,1,R_MACH_COOR[0,1]] W_G54EXP_COOR[0,#111,2,R_MACH_COOR[0,2]] ELSE // FAST CALIBRATION - MSG_OK["CALIBRATE PROBE", "INSTALL CALIBRATION ARTIFACT IN REFERENCE LOCATION",""] + MSG_OK["Calibrate probe", "Install calibration artifact in reference location", ""] END_IF -#120 = @5109 // PREVIOUSLY STORED REFERENCE HEIGHT +#140 = @5109 // PREVIOUSLY STORED REFERENCE HEIGHT + +T#100 M6 // COMMAND A TOOL CHANGE +G53 G90 G00 Z0 // BRING THE MACHINE UP TO TOOL CHANGE HEIGHT -// COMMAND A TOOL CHANGE -T#100 M6 // BRING THE MACHINE UP TO TOOL CHANGE HEIGHT -G28 G91 Z0. #121 = R_MACH_COOR[0,3] // GET MACHINE Z COORDINATE AFTER TOOL CHANGE IF [#1!=#0] // TELL THE PERSON TO PUT THE PROBE INTO THE SPINDLE - MSG_OK["INSTALL PROBE", "SWITCH TO MPG MODE AND INSTALL THE PROBE THEN SWITCH BACK AND HIT CYCLE START; T#100",""] + MSG_OK["Install probe", "Switch to MPG mode and install the probe then switch back and hit cycle start; T#100", ""] END_IF -G54P#111 // LOCATION OF PROBE CALIBARTION IS X0 Y0 ON G54P#111 +G54 P#111 // LOCATION OF PROBE CALIBARTION IS X0 Y0 ON G54P#111 G90 G0 X0. Y0. // MOVE TO TOOLSETTER -#123 = #120 - #109 // DELTA DISTANCE WE HAVE MOVED PLUS SOME INCASE PROBE IS SHORTER THAN GAUGE TOOL +#123 = #140 - #109 // DELTA DISTANCE WE HAVE MOVED PLUS SOME INCASE PROBE IS SHORTER THAN GAUGE TOOL // Probe Z ALL THE WAY BACK TO 123 BLOCK G31 G91 P2 Z[#123] F#104 // Check that the probe has triggered IF[R_SKIP[0,1] == 1] - - - G91 G01 Z[#108] // BACK OFF FIX_CUT_OR_ON G31 G91 P2 Z-[1.5*108] F#105 // PROBE Z AT SLOW SPEED FIX_CUT_OR_OFF #125 = R_SKIP[0,203] // GET MACHINE Z COORDINATE G91 G01 Z[#108] // BACK OFF - #126 = [#125-#120+#109] // PROBE LENGTH CALCULATION, ACCOUNTING FOR GAUGE TOOL LENGTH + #126 = [#125-#140+#109] // PROBE LENGTH CALCULATION, ACCOUNTING FOR GAUGE TOOL LENGTH W_TOOL_DATA[0,#100,203,#126] // STORE PROBE LENGTH - ELSE - ALARM["FAILED TO PROBE PART WITHIN SPECIFIED DISTANCE"] + ALARM["Failed to probe part within specified distance"] END_IF -G28 G91 Z0. +G53 G90 G00 Z0 // retract to top of Z -M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY -G90 +M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY M99 \ No newline at end of file diff --git a/CALIBRATETOOLSET b/CALIBRATETOOLSET index c400277..7eb88be 100644 --- a/CALIBRATETOOLSET +++ b/CALIBRATETOOLSET @@ -1,35 +1,50 @@ // Copyright 2024 Toolpath Labs Inc., Justin Gray, and Josh Smith +// CALIBRATETOOLSET +// use a master gauge tool to find the trigger height of a tool setter. -G94 G17 G49 G40 G80 +// Initial Coding: Justin Gray +// Modified 31/03/2025: Robot Oblivion -#100=R_SYS_INFO[0,2] // SAVE CURRENT TOOL NUMBER TO #100 +#100=R_SYS_INFO[0,2] // SAVE CURRENT TOOL NUMBER TO #100 +@10 = R_G_GROUP[0,6] // pull in metric or freedom units // load probe config G65 "PROBECONFIG" T#100 -M19 // ORIENT SPINDLE - -#102 = @115 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO -#103 = @116 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO -#109 = @109 // TOOLSETTER - T199 - LENGTH OFFSET +#115 = @117 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#116 = @116 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#109 = @109 // MASTER GAUGE LENGTH PROVIDED BY PROBECONFIG MACRO +#112 = @112 // EXTENDED WCS TO STORE TOOLSETTER LOCATION PROVIDED BY PROBECONFIG MACRO -G20 // INCH -G53 G90 G00 Z0 // Move the spindle all the way up before xy movement for safety -G54P100 // LOCATION OF TOOL SETTER IS X0 Y0 ON G54P100 -G90 X0 Y0 // MOVE TO TOOLSETTER - -G91 -G31 Z-20 F#102 // FEED UNTIL INPUT SIGNAL AKA SKIP -G91 G0 Z0.2 // MOVE UP -FIX_CUT_OR_ON -G31 Z-.21 F#103 // FEED UNTIL SKIP SLOWER +G94 G17 G49 G40 G80 +G53 G90 G00 Z0 // Move the spindle all the way up before xy movement for safety +G54 P#112 // Extended LOCATION OF TOOL SETTER +G90 X0 Y0 // MOVE TO TOOLSETTER + +M19 // ORIENT SPINDLE + +G91 // RELATIVE MODE + +IF[@10 == 21] + G21 // Metric + G31 Z-400.0 F#115 // FEED UNTIL INPUT SIGNAL AKA SKIP + G91 G0 Z5.0 // MOVE UP + FIX_CUT_OR_ON + G31 Z-5.5 F#116 // FEED UNTIL SKIP SLOWER +ELSEIF[@10 == 20] + G20 // fREEDOM UNITS (INCH) + G31 Z-20 F#115 // FEED UNTIL INPUT SIGNAL AKA SKIP + G91 G0 Z0.2 // MOVE UP + FIX_CUT_OR_ON + G31 Z-.21 F#116 // FEED UNTIL SKIP SLOWER +END_IF FIX_CUT_OR_OFF -#120=[R_SKIP[0,103]-#109] // MACHINE Z COORDINATE WITH - T199 ACCOUNTING FOR MASTER TOOL LENGTH +#141=[R_SKIP[0,103]-#109] // MACHINE Z COORDINATE WITH - MASTER TOOL LENGTH -W_TOOL_DATA[0,199,203,#120] +W_TOOL_DATA[0,199,203,#141] // STORE THE TOOL LENGTH OFFSET -G28 G91 Z0. -M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +G53 G90 G00 Z0 // Move the spindle all the way up before xy movement for safety +M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY M99 \ No newline at end of file diff --git a/CHECKPOSITIONALTOLERANCE b/CHECKPOSITIONALTOLERANCE index 93244c4..ca61ccc 100644 --- a/CHECKPOSITIONALTOLERANCE +++ b/CHECKPOSITIONALTOLERANCE @@ -1,7 +1,8 @@ -// Copyright 2024 Toolpath Labs Inc., Justin Gray, and Josh Smith +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + // CHECKPOSITIONALTOLERANCE -// Description: Check the XYZ positional tolerance based on the probed points and expected points -// Modified 2/10/2024: Joshua Smith +// Check the XYZ positional tolerance based on the probed points and expected points + // Argument A -> #1 is the work coordinate system to store offsets in. The format for extended G54 offsets would be a period followed by the offset// G54.5 // Argument B -> #2 is the override coordinate system. The format for extended G54 offsets would be a period followed by the offset// G54.5 // Argument T -> #20 positional tolerance @@ -11,53 +12,54 @@ // Argument Y -> #25 expected Y // Argument Z -> #26 expected Z -// load probe config -G65 "PROBECONFIG" - -M19 // ORIENT SPINDLE - -// CALCULATE EXTENDED WCS NUMBER -// FIX is a round down function and MOD is modulo -#114 = ROUND[[#1 - FIX[#1]] * 10] -#115 = ROUND[[#2 - FIX[#2]] * 10] - +// Modified 02/10/2024: Joshua Smith +// Modified 31/03/2025: Robot Oblivion - // get WCS ZERO - IF [#1 < 53 || #1 == #0 ] - ALARM["ERROR: PROBE WCS NOT PROVIDED"] - ELSEIF [#114 < 1] - #116 = R_G53G59_COOR[0,#1,1] // x work zero - #117 = R_G53G59_COOR[0,#1,2] // y work zero - #118 = R_G53G59_COOR[0,#1,3] // z work zero - ELSE - #116 = R_G54EXP_COOR[0,#114,1] // x work zero - #117 = R_G54EXP_COOR[0,#114,2] // y work zero - #118 = R_G54EXP_COOR[0,#114,3] // z work zero - END_IF +// load probe config +G65 "PROBECONFIG" A#1 B#2 +#114 = @114 // processed extended WCS number provided by ProbeConfig macro +#115 = @115 // processed extended WCS number provided by ProbeConfig macro +#128 = @128 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO - // Get override ZERO - IF [ #2 < 53 || #2 == #0] - ALARM["ERROR: OVERRIDE WCS NOT PROVIDED"] - ELSEIF [#115 < 1] - #119 = R_G53G59_COOR[0,#2,1] // x override zero - #120 = R_G53G59_COOR[0,#2,2] // y override zero - #121 = R_G53G59_COOR[0,#2,3] // z override zero - ELSE - #119 = R_G54EXP_COOR[0,#115,1] // x work zero - #120 = R_G54EXP_COOR[0,#115,2] // y work zero - #121 = R_G54EXP_COOR[0,#115,3] // z work zero - END_IF +IF[#128 == 1] + M19 // ORIENT SPINDLE +END_IF - // error = probed point - expected point - #122 = #116 - [#24 + #119] // x error calculation between selected wcs and expected probe point - #123 = #117 - [#25 + #120] // y error calculation between selected wcs and expected probe point - #124 = #118 - [#26 + #121] // z error calculation between selected wcs and expected probe point +// get WCS ZERO +IF [#1 == #0] + ALARM["ERROR: Probe WCS not provided"] +ELSEIF [#114 < 1] + #116 = R_G53G59_COOR[0,#1,1] // x work zero + #117 = R_G53G59_COOR[0,#1,2] // y work zero + #118 = R_G53G59_COOR[0,#1,3] // z work zero +ELSE + #116 = R_G54EXP_COOR[0,#114,1] // x work zero + #117 = R_G54EXP_COOR[0,#114,2] // y work zero + #118 = R_G54EXP_COOR[0,#114,3] // z work zero +END_IF +// Get override ZERO +IF [#2 == #0] + ALARM["ERROR: Override WCS not provided"] +ELSEIF [#115 < 1] + #119 = R_G53G59_COOR[0,#2,1] // x override zero + #120 = R_G53G59_COOR[0,#2,2] // y override zero + #121 = R_G53G59_COOR[0,#2,3] // z override zero +ELSE + #119 = R_G54EXP_COOR[0,#115,1] // x work zero + #120 = R_G54EXP_COOR[0,#115,2] // y work zero + #121 = R_G54EXP_COOR[0,#115,3] // z work zero +END_IF +// error = probed point - expected point +#122 = #116 - [#24 + #119] // x error calculation between selected wcs and expected probe point +#123 = #117 - [#25 + #120] // y error calculation between selected wcs and expected probe point +#124 = #118 - [#26 + #121] // z error calculation between selected wcs and expected probe point + // if the tolorance is null, default it to global variable from the probe config IF[#20==#0] - #20 = @114 + #20 = @110 END_IF #130 = ABS[#122] // absolute x error @@ -66,15 +68,39 @@ END_IF // out of postion alarm if error is greater than tolorance IF[#21!=#0 && #1==#2 ] - ALARM["ERROR: WCS OVERRIDE MUST BE ENABLED IN THE FUSION PROBING ROUTINE AND THE OVERRIDE WCS MUST BE DIFFERENT THAN THE WORK WCS"] + ALARM["WCS override must be enabled in the Fusion probing routine and the override WCS must be different than the work WCS."] ELSEIF[#21!=#0 && #130 > #20 && [#22 == 1 || #22 == 4 || #22 == 5]] - ALARM["ERROR: STOCK OUTSIDE OF POSITIONAL TOLORANCE IN X"] -ELSEIF [#21!=#0 && #131 > #20 && [#22 == 2 || #22 == 4 || #22 == 5]] - ALARM["ERROR: STOCK OUTSIDE OF POSITIONAL TOLORANCE IN Y"] -ELSEIF [#21!=#0 && #132 > #20 && [#22 == 3 || #22 == 5]] - ALARM["ERROR: STOCK OUTSIDE OF POSITIONAL TOLORANCE IN Z"] + #130 = ROUND[#130 * @11] / @11 // Round to 3/4 decimal places + #116 = ROUND[#116 * @11] / @11 // Round to 3/4 decimal places + MENU_ADD["Override point: #119",""]; + MENU_ADD["Probed point: #116",""]; + MENU_ADD["Limit / expected: #20 / #24",""]; + MENU_ADD["Out of position X: #130",""]; + MENU["Error","Stock out of position X","",4]; + ALARM["ERROR: Stock outside of positional tolerance in X"] +ELSEIF [#21!=#0 && #131 > #20 && [#22 == 2 || #22 == 4 || #22 == 5]] + #131 = ROUND[#131 * @11] / @11 // Round to 3/4 decimal places + #117 = ROUND[#117 * @11] / @11 // Round to 3/4 decimal places + MENU_ADD["Override point: #120",""]; + MENU_ADD["Probed point: #117",""]; + MENU_ADD["Limit / expected: #20 / #25",""]; + MENU_ADD["Out of position Y: #131",""]; + MENU["Error","Stock out of position Y","",1]; + ALARM["ERROR: Stock outside of positional tolerance in Y"] +ELSEIF [#21!=#0 && #132 > #20 && [#22 == 3 || #22 == 5]] + #132 = ROUND[#132 * @11] / @11 // Round to 3/4 decimal places + #118 = ROUND[#118 * @11] / @11 // Round to 3/4 decimal places + MENU_ADD["Override point: #121",""]; + MENU_ADD["Probed point: #118",""]; + MENU_ADD["Limit / expected: #20 / #26",""]; + MENU_ADD["Out of position Z: #132",""]; + MENU["Error","Stock out of position Z","",1]; + ALARM["ERROR: Stock outside of positional tolerance in Z"] +END_IF + +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY END_IF -M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY G90 -M99 +M99 \ No newline at end of file diff --git a/COMPZEROPOINT b/COMPZEROPOINT index dcbf40b..59427ae 100644 --- a/COMPZEROPOINT +++ b/COMPZEROPOINT @@ -1,27 +1,30 @@ -// Copyright 2024 Toolpath Labs Inc., Justin Gray, and Josh Smith +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + // COMPZEROPOINT -// Description: set probing wcs to probed part deltas plus zero point origin -// Modified 2/10/2024: Joshua Smith -// Simplified WCS extended number math, added probe error checking, added probe distance argument +// set probing wcs to probed part deltas plus zero point origin + // Argument A -> #1 is the work coordinate system to store offsets in. The format for extended G54 offsets would be a period followed by the offset// G54.5 // Argument B -> #2 is the override coordinate system. The format for extended G54 offsets would be a period followed by the offset// G54.5 // Argument X -> #24 expected X // Argument Y -> #25 expected Y // Argument Z -> #26 expected Z -// load probe config -G65 "PROBECONFIG" - -M19 // ORIENT SPINDLE +// Modified 2/10/2024: Joshua Smith +// Simplified WCS extended number math, added probe error checking, added probe distance argument +// Modified 31/03/2025: Robot Oblivion -// CALCULATE EXTENDED WCS NUMBER -// FIX is a round down function and MOD is modulo -#114 = ROUND[[#1 - FIX[#1]] * 10] -#115 = ROUND[[#2 - FIX[#2]] * 10] +// load probe config +G65 "PROBECONFIG" A#1 B#2 +#114 = @114 // processed extended WCS number provided by ProbeConfig macro +#115 = @115 // processed extended WCS number provided by ProbeConfig macro +#128 = @128 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO +IF[#128 == 1] + M19 // ORIENT SPINDLE +END_IF // get WCS ZERO - IF [#1 < 53 || #1 == #0 ] + IF [#1 == #0 ] ALARM["ERROR: PROBE WCS NOT PROVIDED"] ELSEIF [#114 < 1] #116 = R_G53G59_COOR[0,#1,1] // x work zero @@ -35,7 +38,7 @@ M19 // ORIENT SPINDLE // Get override ZERO - IF [ #2 < 53 || #2 == #0] + IF [#2 == #0] ALARM["ERROR: OVERRIDE WCS NOT PROVIDED"] ELSEIF [#115 < 1] #119 = R_G53G59_COOR[0,#2,1] // x override zero @@ -57,7 +60,7 @@ M19 // ORIENT SPINDLE #127 = #121 + #124 // translate z wcs by the error // Compensate WCS For ZeroPoint -IF [#1 < 53 || #1 == #0 || #1 == #2] +IF [#1 == #0 || #1 == #2] // DO NOT SET ANYTHING INTO WCS ELSEIF [#114 < 1] W_G53G59_COOR[0,#1,1,#125] @@ -73,6 +76,9 @@ ELSE W_G54EXP_COOR[0,#114,3,#121] END_IF -M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +END_IF + G90 -M99 +M99 \ No newline at end of file diff --git a/COPYWCS b/COPYWCS index 62273f3..a8dbd65 100644 --- a/COPYWCS +++ b/COPYWCS @@ -1,17 +1,20 @@ -// Copyright 2024 Toolpath Labs Inc., Justin Gray, and Josh Smith +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + // COMPZEROPOINT -// Description: copy wcs B into A -// Modified 2/10/2024: Joshua Smith +// copy wcs B into A + // Argument A -> #1 is the work coordinate system to store offsets in. The format for extended G54 offsets would be a period followed by the offset// G54.5 // Argument B -> #2 is the override coordinate system. The format for extended G54 offsets would be a period followed by the offset// G54.5 -// CALCULATE EXTENDED WCS NUMBER -// FIX is a round down function and MOD is modulo -#114 = ROUND[[#1 - FIX[#1]] * 10] -#115 = ROUND[[#2 - FIX[#2]] * 10] +// Modified 2/10/2024: Joshua Smith +// Modified 31/03/2025: Robot Oblivion + +G65 "PROBECONFIG" A#1 B#2 +#114 = @114 // processed extended WCS number provided by ProbeConfig macro +#115 = @115 // processed extended WCS number provided by ProbeConfig macro // Get Argument B WCS - IF [ #2 < 53 || #2 == #0] + IF [#2 == #0] ALARM["ERROR: OVERRIDE WCS NOT PROVIDED"] ELSEIF [#115 < 1] #119 = R_G53G59_COOR[0,#2,1] // x override zero @@ -24,7 +27,7 @@ END_IF // Copy one wcs into another -IF [#1 < 53 || #1 == #0 || #1 == #2] +IF [#1 == #0 || #1 == #2] // DO NOT SET ANYTHING INTO WCS ELSEIF [#114 < 1] W_G53G59_COOR[0,#1,1,#119] @@ -37,5 +40,4 @@ ELSE END_IF G90 - -M99 +M99 \ No newline at end of file diff --git a/FINDCOR b/FINDCOR index 7dfee17..3baa139 100644 --- a/FINDCOR +++ b/FINDCOR @@ -1,3 +1,6 @@ +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +//FINDCOR // Process is based on a rectangular artifact // mounted to the 4th axis // STEPS @@ -10,22 +13,19 @@ // 7) Reposition to Y=COR, then probe Z. // 8) With diameter + Z probe point compute the Z-COR +// Argument A -> #1 is the WCS to store the COR into +// Argument S -> #19 tuns on saving of the starting probe location +// Argument W -> #23 is the approximate width of the reference artifact -// #1 is the WCS to store the COR into -// #19 tuns on saving of the starting probe location -// #23 is the approximate width of the reference artifact - - -//CALCULATE EXTENDED WCS NUMBER -//FIX removes any decimal value -#114 = ROUND[[#1 - FIX[#1]] * 10] +// Initial Coding: Justin Gray, Josh Smith IF[#23==#0] // null check #23 = 1.0 // assume the narrow side of a 123 block END_IF -//load probe config -G65 "PROBECONFIG" +// load probe config +G65 "PROBECONFIG" A#1 +#114 = @114 // processed extended WCS number provided by ProbeConfig macro M19 // ORIENT SPINDLE @@ -39,7 +39,7 @@ M19 // ORIENT SPINDLE // CONVINIENT TO WORK IN PROBE 0 WCS -G54P#109 +G54 P#109 // store current X,Y,Z // ASSUME THE PROBE IS AT -Y @@ -76,8 +76,7 @@ IF[#19 != #0] // null check ELSE // RETRACT TO SAFE Z - G28 G91 Z0 - G90 +G53 G90 G00 Z0 // POSITION THE ROTATRY AXIS AT A0 M10 G0 A0. @@ -145,7 +144,7 @@ G65 "PROBEZ" B-[10*#131] //STORE COR OFFSET FOR WCS ZERO -IF [#1 < 53 || #1 == #0] +IF [#1 == #0] //DO NOT SET ANYTHING INTO WCS ELSEIF [#114 < 1] W_G53G59_COOR[0,#1,2,#132] @@ -157,9 +156,5 @@ END_IF M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY - -G28 G91 Z0 -G90 - -M99 - +G53 G90 G00 Z0 +M99 \ No newline at end of file diff --git a/LOADTOOL b/LOADTOOL index 06b50d1..2180c15 100644 --- a/LOADTOOL +++ b/LOADTOOL @@ -1,15 +1,16 @@ -// Copyright 2024 Toolpath Labs Inc., Justin Gray +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion +// LOADTOOL // LOAD A NEW TOOL INTO THE CAROUSEL -// #20 IS THE TOOL NUMBER TO LOAD - -// #13 Flag to reset tool offsets then call TOOLSET (not required and defaults on) - -// #15 tool number in carousel to swap out (not required) - +// Argument T -> #20 IS THE TOOL NUMBER TO LOAD +// Argument M -> #13 Flag to reset tool offsets then call TOOLSET (not required and defaults on) +// Argument O -> #15 tool number in carousel to swap out (not required) // THE TOOL TABLE IS VARIABLES 7000-7011 +// Initial Coding: Justin Gray +// Modified 31/03/2025: Robot Oblivion + #120 = 0 // STORES THE OLD TOOL NUMBER IF[#20 == R_REG[7813]] @@ -95,4 +96,4 @@ IF[#13 == 1] G65 "TOOLSET" A0.0 END_IF -M99 +M99 \ No newline at end of file diff --git a/PROBEBORE b/PROBEBORE index 16905f4..ae72040 100644 --- a/PROBEBORE +++ b/PROBEBORE @@ -1,16 +1,19 @@ -//Copyright 2024 Toolpath Labs Inc., Justin Gray, and Josh Smith - -//PROBEBORE -//Description: Probe a bore in X and Y -//Initial Coding: Justin Gray -//Modified 1/14/2024: Joshua Smith -//Simplified WCS extended number math, added probe error checking, added probe inspection report -//#1 is the work coordinate system to store offsets in -//#2 is the expected DIAMETER -//#9 print results enabled by fusion360 -//#17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on -//#19 oversize tolorance -//#20 enable oversize check +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// PROBEBORE +// Probe a bore in X and Y + +// Argument A -> #1 is the work coordinate system to store offsets in +// Argument B -> #2 is the expected DIAMETER +// Argument I -> #9 print results enabled by fusion360 +// Argument Q -> #17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on +// Argument S -> #19 oversize tolorance +// Argument T -> #20 enable oversize check + +// Initial Coding: Justin Gray +// Modified 1/14/2024: Joshua Smith +// Simplified WCS extended number math, added probe error checking, added probe inspection report +// Modified 31/03/2025: Robot Oblivion //calling our slot macros the first time centers probe G65 "PROBEXSLOT" A#1 B#2 I#9 Q0 R#18 S#19 @@ -25,14 +28,21 @@ @997 = [@998 + @999]/2 //simple inspection reporting -IF[#17>0] - MENU_ADD["Part Diameter In X: @998",""]; - MENU_ADD["Part Diameter In Y: @999",""]; - MENU_ADD["AVG Diameter: @997",""]; //THE WORD AVERAGE IS TO LONG FOR THE MENU - MENU["INSPECTION REPORT","RESULTS","",1]; +IF [#17 > 0] + #97 = ROUND[@997 * @11] / @11 // Round to 3/4 decimal places + #98 = ROUND[@998 * @11] / @11 // Round to 3/4 decimal places + #99 = ROUND[@999 * @11] / @11 // Round to 3/4 decimal places + IF[@10 == 21] + MENU_ADD["Part Diameter mm X: #98",""]; + MENU_ADD["Part Diameter mm Y: #99",""]; + MENU_ADD["AVG Diameter mm: #97",""]; //THE WORD AVERAGE IS TO LONG FOR THE MENU + ELSE + MENU_ADD["Part Diameter In X: #98",""]; + MENU_ADD["Part Diameter In Y: #99",""]; + MENU_ADD["AVG Diameter In: #97",""]; //THE WORD AVERAGE IS TO LONG FOR THE MENU + END_IF + MENU["INSPECTION REPORT","RESULTS","",1]; END_IF - G90 - M99 \ No newline at end of file diff --git a/PROBECIRCULARBOSS b/PROBECIRCULARBOSS index 111bb33..5c5ac06 100644 --- a/PROBECIRCULARBOSS +++ b/PROBECIRCULARBOSS @@ -1,39 +1,49 @@ -//Copyright 2024 Toolpath Labs Inc., Justin Gray, and Josh Smith - -//PROBECIRCULARBOSS -//Description: Probe a circular boss in X and Y -//Initial Coding: Justin Gray -//Modified 1/14/2024: Joshua Smith -//Simplified WCS extended number math, added probe error checking, added probe inspection report -//#1 is the work coordinate system to store offsets in -//#2 is the expected DIAMETER -//#3 is the Z drop height -//#9 print results enabled by fusion360 -//#17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on -//#18 oversize tolorance -//#19 enable oversize check - - //calling our web macros the first time centers us - G65 "PROBEXWEB" A#1 B#2 C#3 I#9 Q0 R#18 S#19 - G65 "PROBEYWEB" A#1 B#2 C#3 I#9 Q0 R#18 S#19 - - //calling our web macros the second time gives an accurate center - G65 "PROBEXWEB" A#1 B#2 C#3 I#9 Q0 R#18 S#19 - G65 "PROBEYWEB" A#1 B#2 C#3 I#9 Q0 R#18 S#19 +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// PROBECIRCULARBOSS +// Probe a circular boss in X and Y + +// Argument A -> #1 is the work coordinate system to store offsets in +// Argument B -> #2 is the expected DIAMETER +// Argument C -> #3 is the Z drop height +// Argument I -> #9 print results enabled by fusion360 +// Argument Q -> #17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on +// Argument R -> #18 oversize tolorance +// Argument S -> #19 enable oversize check + +// Initial Coding: Justin Gray +// Modified 1/14/2024: Joshua Smith +// Simplified WCS extended number math, added probe error checking, added probe inspection report +// Modified 31/03/2025: Robot Oblivion + +//calling our web macros the first time centers us +G65 "PROBEXWEB" A#1 B#2 C#3 I#9 Q0 R#18 S#19 +G65 "PROBEYWEB" A#1 B#2 C#3 I#9 Q0 R#18 S#19 + +//calling our web macros the second time gives an accurate center +G65 "PROBEXWEB" A#1 B#2 C#3 I#9 Q0 R#18 S#19 +G65 "PROBEYWEB" A#1 B#2 C#3 I#9 Q0 R#18 S#19 //average Diameter calculation //@999 and @998 are set in the web macros @997 = [@998 + @999]/2 //simple inspection reporting -IF[#17>0] - MENU_ADD["Part Diameter In X: @998",""]; - MENU_ADD["Part Diameter In Y: @999",""]; - MENU_ADD["AVG Diameter: @997",""]; //THE WORD AVERAGE IS TO LONG FOR THE MENU - MENU["INSPECTION REPORT","RESULTS","",1]; +IF [#17 > 0] + #97 = ROUND[@997 * @11] / @11 // Round to 3/4 decimal places + #98 = ROUND[@998 * @11] / @11 // Round to 3/4 decimal places + #99 = ROUND[@999 * @11] / @11 // Round to 3/4 decimal places + IF[@10 == 21] + MENU_ADD["Part Diameter mm X: #98",""]; + MENU_ADD["Part Diameter mm Y: #99",""]; + MENU_ADD["AVG Diameter mm: #97",""]; //THE WORD AVERAGE IS TO LONG FOR THE MENU + ELSE + MENU_ADD["Part Diameter In X: #98",""]; + MENU_ADD["Part Diameter In Y: #99",""]; + MENU_ADD["AVG Diameter In: #97",""]; //THE WORD AVERAGE IS TO LONG FOR THE MENU + END_IF + MENU["INSPECTION REPORT","RESULTS","",1]; END_IF - G90 - M99 \ No newline at end of file diff --git a/PROBECONFIG b/PROBECONFIG index 62aef45..153b5c1 100644 --- a/PROBECONFIG +++ b/PROBECONFIG @@ -1,46 +1,106 @@ -// Copyright 2024 Toolpath Labs Inc., Justin Gray, and Josh Smith +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion // PROBECONFIG -// Description: Probe Configuration File -// Initial Coding 1/25/2024: Joshua Smith -// macro to setup probe specs and units, called by every macro +// Probe Configuration file to setup probe specs and units, called by every macro + +// Argument T -> #20 turns off probe tool number checking : VACANT leaves it on ; non VACANT turns it off +// NOTE: @5109 STORES THE REFERENCE HEIGHT FOR FAST PROBE Z CALIBRATION -// #20 turns off probe tool number checking : VACANT leaves it on ; non VACANT turns it off +// Initial Coding 1/25/2024: Joshua Smith +// Modified 31/03/2025: Robot Oblivion // important global variables @100 = -1 // PROBE TOOL NUMBER, EX: 99 IF [@100==-1] - ALARM["HARD CODE PROBE NUMBER IN PROBECONFIG MACRO"] + ALARM["Hard code probe number in PROBECONFIG macro"] END_IF +@10 = R_G_GROUP[0,6] // Metric or freedom units check, DO NOT TOUCH!!! @101 = R_TOOL_DATA[0,@100,3] // TOOL DIAMETER, DO NOT TOUCH!!! @102 = @101/2 // TOOL RADIUS, DO NOT TOUCH!!! -@103 = 50 // FEED SPEED in/m, change to match your unit of choice, for metric users start at 2540mm -@104 = 50 // FAST PROBE SPEED in/m, change to match your unit of choice, for metric users start at 1270mm -@105 = 2.5 // SLOW PROBE SPEED in/m, change to match your unit of choice, for metric users start at 63mm -@106 = .5 // PROBE CLEARANCE DISTANCE in, change to match your unit of choice, for metric users start at 6mm @107 = [R_TOOL_DATA[0,@100,203]] // TOOL LENGHT OFFSET, DO NOT TOUCH!!! -@108 = .125 // PROBE BACKOFF DISTANCE,change to match your unit of choice, for metric users start at 3mm -@109 = 2.9997 // CALIBRATED LENGTH OF YOUR MASTER GAUGE TOOL -@110 = .05 // DEFAULT PART TOLERANCE -// NOTE: @5109 STORES THE REFERENCE HEIGHT FOR FAST PROBE Z CALIBRATION +@111 = 21 // EXTENDED WORKOFFSET TO STORE PROBE Z CALIBRATION LOCATION +@112 = 22 // EXTENDED WORKOFFSET TO STORE TOOLSETTER LOCATION +@113 = 23 // EXTENDED WORKOFFSET TO STORE THE 4TH COR PROBING START POINT +@110 = 1.0 // DEFAULT POSITION TOLERANCE +@128 = 0 // ORIENT SPINDLE SWITCH 0=OFF 1=ON +#137 = 95 // The highest WCS that can be used. Any above are protected from changes via these macros + +// metric settings +IF[@10 == 21] + @103 = 2500 // FEED SPEED mm/m, + @104 = 1250 // FAST PROBE SPEED mm/m, + @105 = 60 // SLOW PROBE SPEED mm/m, + @106 = 10 // PROBE CLEARANCE DISTANCE mm, + @108 = 2 // PROBE BACKOFF DISTANCE mm, + + @109 = 93.896 // CALIBRATED LENGTH OF YOUR MASTER GAUGE TOOL + @129 = 24.998 // Calibrated diameter of the master ring gauge tool + @110 = 1.0 // DEFAULT PART TOLERANCE + + @117 = 750 // FAST Tool Probe SPEED mm/m, + @116 = 40 // SLOW Tool Probe SPEED mm/m, + @11 = 1000 // rounding multiplier for 3 decimal places +END_IF; -@111 = 99 // EXTENDED WORKOFFSET TO STORE PROBE Z CALIBRATION LOCATION -@112 = 100 // EXTENDED WORKOFFSET TO STORE TOOLSETTER LOCATION -@113 = 98 // EXTENDED WORKOFFSET TO STORE THE 4TH COR PROBING START POINT -@114 = .05 // DEFAULT POSITION TOLERANCE +// Freedom unit settings +IF[@10 == 20] + @103 = 50 // FEED SPEED in/m, + @104 = 50 // FAST PROBE SPEED in/m, + @105 = 2.5 // SLOW PROBE SPEED in/m, + @106 = 0.5 // PROBE CLEARANCE DISTANCE in, + @108 = 0.125 // PROBE BACKOFF DISTANCE, -@115 = 30 // FAST Tool Probe SPEED in/m, change to match your unit of choice, for metric users start at 762mm -@116 = 1.5 // SLOW Tool Probe SPEED in/m, change to match your unit of choice, for metric users start at 38mm + @109 = 2.9997 // CALIBRATED LENGTH OF YOUR MASTER GAUGE TOOL + @129 = 0.9999 // Calibrated diameter of the master ring gauge tool + @110 = 0.05 // DEFAULT PART TOLERANCE + + @117 = 30 // FAST Tool Probe SPEED in/m, + @116 = 1.5 // SLOW Tool Probe SPEED in/m, + @11 = 10000 // rounding multiplier for 4 decimal places +END_IF; #120=R_SYS_INFO[0,2] // CURRENT TOOL NUMBER IF [@100 != #120 && #20==#0] // THE PROBE IS NOT LOADED - ALARM["ERROR: PROTECTED MOVE WITHOUT PROBE - CHANGE TO T#100 "] + ALARM["Error: Protected move without probe - change to T#100 "] END_IF - G90 +IF [#1 != #0] + IF [ROUND[MOD[#1,1] * 100] > 0] + @114 = ROUND[MOD[#1,1] * 100] // Extract the decimal part and multiply by 100 + IF [@114 < 1 || @114 >= #137] + ALARM["ERROR: Probe WCS G54 P@114 protected via ProbeConfig Macro"] + END_IF + IF [FIX[#1] != 54] + ALARM["ERROR: G54 must be used when calling extended work offsets"] + END_IF + ELSE + @114 = #1 + IF [@114 < 54 || @114 > 59] + ALARM["ERROR: Probe WCS G@114 out of range"] + END_IF + END_IF +END_IF + +IF [#2 != #0] + IF [ROUND[MOD[#2,1] * 100] > 0] + @115 = ROUND[MOD[#2,1] * 100] // Extract the decimal part and multiply by 100 + IF [@115 < 1 || @115 >= #137] + ALARM["ERROR: Override WCS G54 P@115 protected via ProbeConfig Macro"] + END_IF + IF [FIX[#2] != 54] + ALARM["ERROR: G54 must be used when calling extended work offsets"] + END_IF + ELSE + @115 = #2 + IF [@115 < 54 || @115 > 59] + ALARM["ERROR: Override WCS G@115 out of range"] + END_IF + END_IF +END_IF + M99 \ No newline at end of file diff --git a/PROBEINSIDECORNER b/PROBEINSIDECORNER index 26007e1..2f31a96 100644 --- a/PROBEINSIDECORNER +++ b/PROBEINSIDECORNER @@ -1,18 +1,25 @@ -// Copyright 2024 Toolpath Labs Inc., Justin Gray, and Josh Smith +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion // PROBEINSIDECORNER -// Description: Probe ONE OF 4 INSIDE CORNERS -// Simplified WCS extended number math, added probe error checking, added probe distance argument +// Probe ONE OF 4 INSIDE CORNERS + +// Probe ONE OF 4 INSIDE CORNERS // Argument A -> #1 is the work coordinate system to store offsets in. The format for extended G54 offsets would be a period followed by the offset// G54.5 // Argument B -> #2 defines which corner // 1 2 // 3 4 // Argument C -> #3 is the desired distance to probe part +// Simplified WCS extended number math, added probe error checking, added probe distance argument +// Modified 31/03/2025: Robot Oblivion + // load probe config G65 "PROBECONFIG" -M19 // ORIENT SPINDLE +#128 = @128 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO +IF[#128 == 1] + M19 // ORIENT SPINDLE +END_IF // important local variables #100 = @100 // TOOL NUMBER PROVIDED BY PROBECONFIG MACRO @@ -61,6 +68,9 @@ G65 "PROBEY" A#1 B#121*#3 G31 G91 P2 Y[#127] F#111 // PROTECTED MOVE G31 G91 P2 X[#126] F#111 // PROTECTED MOVE -M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +END_IF + G90 -M99 +M99 \ No newline at end of file diff --git a/PROBEOUTSIDECORNER b/PROBEOUTSIDECORNER index c3cd904..4fea02a 100644 --- a/PROBEOUTSIDECORNER +++ b/PROBEOUTSIDECORNER @@ -1,9 +1,8 @@ -// Copyright 2024 Toolpath Labs Inc., Justin Gray, and Josh Smith - +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion // PROBEOUTSIDECORNER -// Description: Probe ONE OF 4 OUTSIDE CORNERS -// Simplified WCS extended number math, added probe error checking, added probe distance argument +// Probe ONE OF 4 OUTSIDE CORNERS + // Argument A -> #1 is the work coordinate system to store offsets in. The format for extended G54 offsets would be a period followed by the offset -- G54.5 // Argument B -> #2 defines which corner // 1 2 @@ -11,10 +10,16 @@ // Argument C -> #3 is the desired probing distance from the corner // Argument D -> #4 is the desired distance to probe part +// Simplified WCS extended number math, added probe error checking, added probe distance argument +// Modified 31/03/2025: Robot Oblivion + // load probe config G65 "PROBECONFIG" -M19 // ORIENT SPINDLE +#128 = @128 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO +IF[#128 == 1] + M19 // ORIENT SPINDLE +END_IF // important local variables #100 = @100 // TOOL NUMBER PROVIDED BY PROBECONFIG MACRO @@ -84,6 +89,11 @@ G31 G91 P2 Y[#127] F#111 // PROTECTED MOVE G31 G91 P2 X[#126] F#111 // PROTECTED MOVE N1 -M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY + +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +END_IF + G90 -M99 +G00 // return to rapid speed +M99 \ No newline at end of file diff --git a/PROBEPOCKET b/PROBEPOCKET index 334f9cb..8646d9c 100644 --- a/PROBEPOCKET +++ b/PROBEPOCKET @@ -1,29 +1,39 @@ -//Copyright 2024 Toolpath Labs Inc., Justin Gray, and Josh Smith +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion -//PROBEBORE -//Description: Probe a bore in X and Y -//Initial Coding: Justin Gray -//Modified 1/14/2024: Joshua Smith -//Simplified WCS extended number math, added probe error checking, added probe inspection report -//#1 is the work coordinate system to store offsets in -//#2 is the expected length -//#3 is the expected width -//#9 print results enabled by fusion360 -//#17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on -//#18 oversize tolorance -//#19 enable oversize check +// PROBEBORE +// Probe a bore in X and Y + +// Argument A -> #1 is the work coordinate system to store offsets in +// Argument B -> #2 is the expected length +// Argument C -> #3 is the expected width +// Argument I -> #9 print results enabled by fusion360 +// Argument Q -> #17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on +// Argument R -> #18 oversize tolorance +// Argument S -> #19 enable oversize check + +// Initial Coding: Justin Gray +// Modified 1/14/2024: Joshua Smith +// Simplified WCS extended number math, added probe error checking, added probe inspection report +// Modified 31/03/2025: Robot Oblivion + +@10 = R_G_GROUP[0,6] // pull in metric or freedom units G65 "PROBEXSLOT" A#1 B#2 Q0 I#9 R#18 S#19 G65 "PROBEYSLOT" A#1 B#3 Q0 I#9 R#18 S#19 //simple inspection reporting -IF[#17>0] - MENU_ADD["Part Length In X: @998",""]; - MENU_ADD["Part Width In Y: @999",""]; +IF [#17 > 0] + #98 = ROUND[@998 * @11] / @11 // Round to 3/4 decimal places + #99 = ROUND[@999 * @11] / @11 // Round to 3/4 decimal places + IF[@10 == 21] + MENU_ADD["Part Width mm X: #98",""]; + MENU_ADD["Part Length mm Y: #99",""]; + ELSE + MENU_ADD["Part Width In X: #98",""]; + MENU_ADD["Part Length In Y: #99",""]; + END_IF MENU["INSPECTION REPORT","RESULTS","",1]; END_IF - G90 - M99 \ No newline at end of file diff --git a/PROBERECTANGULARBOSS b/PROBERECTANGULARBOSS index c8aea41..3e87fae 100644 --- a/PROBERECTANGULARBOSS +++ b/PROBERECTANGULARBOSS @@ -1,33 +1,45 @@ -//Copyright 2024 Toolpath Labs Inc., Justin Gray, and Josh Smith +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion -//PROBERECTANGULARBOSS -//Description: Probe a rectangular boss in X and Y -//Initial Coding: Justin Gray -//Modified 1/14/2024: Joshua Smith -//Simplified WCS extended number math, added probe error checking, added probe inspection report -//#1 is the work coordinate system to store offsets in -//#2 is the expected length of the web in the X direction -//#3 is the expected width of the web in the Y direction -//#4 is the Z drop height -//#9 print results enabled by fusion360 -//#17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on -//#18 oversize tolorance -//#19 enable oversize check +// PROBERECTANGULARBOSS +// Probe a rectangular boss in X and Y +// Argument A -> #1 is the work coordinate system to store offsets in +// Argument B -> #2 is the expected length of the web in the X direction //KC +// Argument C -> #3 is the expected width of the web in the Y direction //KC +// Argument D -> #4 is the Z drop height //KC +// Argument I -> #9 print results enabled by fusion360 +// Argument Q -> #17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on +// Argument R -> #18 oversize tolorance +// Argument S -> #19 enable oversize check - G65 "PROBEXWEB" A#1 B#2 C#4 I#9 Q0 R#18 S#19 - G65 "PROBEYWEB" A#1 B#3 C#4 I#9 Q0 R#18 S#19 +// Initial Coding: Justin Gray +// Modified 1/14/2024: Joshua Smith +// Simplified WCS extended number math, added probe error checking, added probe inspection report +// Modified 31/03/2025: Robot Oblivion +@10 = R_G_GROUP[0,6] // pull in metric or freedom units + +G65 "PROBEXWEB" A#1 B#2 C#4 I#9 Q0 R#18 S#19 +G65 "PROBEYWEB" A#1 B#3 C#4 I#9 Q0 R#18 S#19 //simple inspection reporting //@999 and @998 are set in the web macros -IF[#17>0] - MENU_ADD["Part Length In X: @998",""]; - MENU_ADD["Part Width In Y: @999",""]; +IF [#17 > 0] + #98 = ROUND[@998 * @11] / @11 // Round to 3/4 decimal places + #99 = ROUND[@999 * @11] / @11 // Round to 3/4 decimal places + IF[@10 == 21] + MENU_ADD["Part Width mm X: #98",""]; + MENU_ADD["Part Length mm Y: #99",""]; + ELSE + MENU_ADD["Part Width In X: #98",""]; + MENU_ADD["Part Length In Y: #99",""]; + END_IF MENU["INSPECTION REPORT","RESULTS","",1]; END_IF - G90 +G4 P100 +M20 // UNLOCK SPINDLE ORIENT +M19 P0 // ORIENT SPINDLE 0 DEGREES TO LEAVE AS IT ENTERED M99 \ No newline at end of file diff --git a/PROBEX b/PROBEX index ca30a83..d4dc98d 100644 --- a/PROBEX +++ b/PROBEX @@ -1,42 +1,46 @@ -//Copyright 2024 Toolpath Labs Inc., Justin Gray, and Josh Smith +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion -//PROBEX -//Description: Probe in X from the left or right side -//Initial Coding: Justin Gray -//Modified 1/14/2024: Joshua Smith -//Simplified WCS extended number math, added probe error checking, added probe distance argument -//Argument A -> #1 is the work coordinate system to store offsets in. The format for extended G54 offsets would be a period followed by the offset G54.5 -//Argument B -> #2 is the desired probing distance. Enter a positive value to probe on the left side and a negative value to probe on the right side -//Argument I -> #9 print results enabled by fusion360 +// PROBEX +// Probe in X from the left or right side -//load probe config -G65 "PROBECONFIG" +// Argument A -> #1 is the work coordinate system to store offsets in. The format for extended G54 offsets would be a period followed by the offset G54.5 +// Argument B -> #2 is the desired probing distance. Enter a positive value to probe on the left side and a negative value to probe on the right side +// Argument I -> #9 print results enabled by fusion360 -M19 // ORIENT SPINDLE +// Initial Coding: Justin Gray +// Modified 1/14/2024: Joshua Smith +// Simplified WCS extended number math, added probe error checking, added probe distance argument +// Modified 31/03/2025: Robot Oblivion -//important local variables -#111 = @104 //FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO -#112 = @105 //SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO -#105 = @102 //TOOL RADIUS PROVIDED BY PROBECONFIG MACRO -#108 = @108*[#2/ABS[#2]] //PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO * the sign +1 or -1 of probe distance +// load probe config +G65 "PROBECONFIG" A#1 +// important local variables +#111 = @104 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#112 = @105 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#105 = @102 // TOOL RADIUS PROVIDED BY PROBECONFIG MACRO +#108 = @108*[#2/ABS[#2]] // PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO * the sign +1 or -1 of probe distance +#114 = @114 // processed extended WCS number provided by ProbeConfig macro +#128 = @128 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO -//CALCULATE EXTENDED WCS NUMBER -//FIX is a round down function and MOD is modulo -#114 = ROUND[[#1 - FIX[#1]] * 10] +M20 // UNLOCK SPINDLE ORIENT +IF[#2 < 0] + M19 P180 // ORIENT SPINDLE 180 DEGREES +ELSE + M19 P0 // ORIENT SPINDLE 0 DEGREES +END_IF //Probe X the desired distance and at fast feed -G31 G91 P2 X[#2] F#111 +G31 G91 P2 X[#2] F#111 //FEED UNTIL SKIP FAST //Check that the probe has triggered -IF[R_SKIP[0,1] == 1] - - G91 G01 X-[#108] //back off 1/4 the probing distance +IF[R_SKIP[0,1] == 1] + G91 G01 X-[#108] //back off distance provided by ProbeConfig macro FIX_CUT_OR_ON G31 G91 P2 X[#2] F#112 //Probe X the desired distance at slow feed FIX_CUT_OR_OFF #104=R_SKIP[0,201] //GET MACHINE X COORDINATE - G91 G01 X-[#108] //back off 1/4 the probing distance + G91 G01 X-[#108] //back off distance provided by ProbeConfig macro #106 = [#104+[[#2/abs[#2]]*#105]] //current position +/- probe radius @996 = #106 @@ -46,8 +50,8 @@ IF[R_SKIP[0,1] == 1] END_IF //STORE X OFFSET FOR WCS ZERO - IF [#1 < 53 || #1 == #0 || #9 > 0] - //DO NOT SET ANYTHING INTO WCS + IF [#1 == #0 || #9 > 0] + //DO NOT WRITE ANYTHING TO WCS ELSEIF [#114 < 1] W_G53G59_COOR[0,#1,1,#106] ELSE @@ -55,9 +59,13 @@ IF[R_SKIP[0,1] == 1] END_IF ELSE - ALARM["ERROR: FAILED TO PROBE PART WITHIN SPECIFIED DISTANCE"] + ALARM["ERROR: FAILED TO PROBE PART WITHIN SPECIFIED DISTANCE"] +END_IF + +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY END_IF -M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY G90 -M99 +G00 // return to rapid speed +M99 \ No newline at end of file diff --git a/PROBEXSLOT b/PROBEXSLOT index 43b2abd..e9366d7 100644 --- a/PROBEXSLOT +++ b/PROBEXSLOT @@ -1,24 +1,27 @@ -//Copyright 2024 Toolpath Labs Inc., Justin Gray, and Josh Smith - -//PROBEXSLOT -//Description: Probe a SLOT in X from left to right -//Initial Coding: Justin Gray -//Modified 1/14/2024: Joshua Smith -//Simplified WCS extended number math, added probe error checking, added probe inspection report -//#1 is the work coordinate system to store offsets in -//#2 is the expected length of the web in the x direction -//#9 print results enabled by fusion360 -//#17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on -//#18 oversize tolorance -//#19 enable oversize check - -//load probe config -G65 "PROBECONFIG" +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// PROBEXSLOT +// Probe a SLOT in X from left to right + +// Argument A -> #1 is the work coordinate system to store offsets in +// Argument B -> #2 is the expected width of the web in the X direction +// Argument I -> #9 print results enabled by fusion360 +// Argument Q -> #17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on +// Argument R -> #18 oversize tolorance +// Argument S -> #19 enable oversize check + +// Initial Coding: Justin Gray +// Modified 1/14/2024: Joshua Smith +// Simplified WCS extended number math, added probe error checking, added probe inspection report +// Modified 31/03/2025: Robot Oblivion + +// load probe config +G65 "PROBECONFIG" A#1 M20 // UNLOCK SPINDLE ORIENT M19 P180 // ORIENT SPINDLE 180 DEGREES TO KEEP THE POBING POINT THE SAME -//important local variables +// important local variables #100 = @100 //TOOL NUMBER PROVIDED BY PROBECONFIG MACRO #111 = @104 //FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO #112 = @105 //SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO @@ -26,12 +29,9 @@ M19 P180 // ORIENT SPINDLE 180 DEGREES TO KEEP THE POBIN #122 = @106 //WEB PROBE DISTANCE PROVIDED BY PROBECONFIG MACRO #108 = @108 //PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO #2 = ABS[#2] +#114 = @114 // processed extended WCS number provided by ProbeConfig macro -//CALCULATE EXTENDED WCS NUMBER -//FIX removes any decimal value -#114 = ROUND[[#1 - FIX[#1]] * 10] - //probe X starting from a negative offset and probing in the positive direction //MOVE TO -X SIDE OF THE PART, BEFORE STARTING TO PROBE G31 G91 P2 X-[#2/2+#122] F#111 @@ -83,7 +83,14 @@ END_IF //oversized stock alarm if stock error is greater than tolorance IF[#19!=#0 && #126>#18 ] - ALARM["ERROR: STOCK OUTSIDE OF TOLORANCE IN X"] + #136 = ROUND[[#107-#2] * @11] / @11 // Round to 3/4 decimal places + #107 = ROUND[#107 * @11] / @11 // Round to 3/4 decimal places + MENU_ADD["Expected size: #2",""]; + MENU_ADD["Probed size: #107",""]; + MENU_ADD["Tolerance: #18",""]; + MENU_ADD["Off-target: #136",""]; + MENU["Error","Stock outside of tolerance in X","",1]; + ALARM["Error: Stock outside of tolerance in X"] END_IF //safety check for inspection variable @@ -93,7 +100,7 @@ END_IF //STORE X OFFSET -IF [#1 < 53 || #1 == #0 || #9 > 0] +IF [#1 == #0 || #9 > 0] //DO NOT WRITE ANYTHING TO WCS ELSEIF [#114 < 1] W_G53G59_COOR[0,#1,1,#104] @@ -102,13 +109,22 @@ ELSE END_IF //simple inspection reporting -IF[#17>0] - MENU_ADD["Part Length: #107",""]; +IF [#17 > 0] + #98 = ROUND[@998 * @11] / @11 // Round to 3/4 decimal places + IF[@10 == 21] + MENU_ADD["Part Width mm X: #98",""]; + ELSE + MENU_ADD["Part Width In X: #98",""]; + END_IF MENU["INSPECTION REPORT","RESULTS","",1]; END_IF + N1 -M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +END_IF + G90 M99 \ No newline at end of file diff --git a/PROBEXWEB b/PROBEXWEB index da677bc..7e0483d 100644 --- a/PROBEXWEB +++ b/PROBEXWEB @@ -1,22 +1,25 @@ -//Copyright 2024 Toolpath Labs Inc., Justin Gray, and Josh Smith - -//PROBEXWEB -//Description: Probe a web in X from left to right -//Initial Coding: Justin Gray -//Modified 1/14/2024: Joshua Smith -//Simplified WCS extended number math, added probe error checking, added probe inspection report -//#1 is the work coordinate system to store offsets in -//#2 is the expected length of the web in the x direction -//#3 is the Z drop height -//#9 print results enabled by fusion360 -//#17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on -//#18 oversize tolorance -//#19 enable oversize check - -//load probe config -G65 "PROBECONFIG" - -//important local variables +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// PROBEXWEB +// Probe a web in X from left to right + +// Argument A -> #1 is the work coordinate system to store offsets in +// Argument B -> #2 is the expected width of the web in the X direction +// Argument C -> #3 is the Z drop height +// Argument I -> #9 print results enabled by fusion360 +// Argument Q -> #17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on +// Argument R -> #18 oversize tolorance +// Argument S -> #19 enable oversize check + +// Initial Coding: Justin Gray +// Modified 1/14/2024: Joshua Smith +// Simplified WCS extended number math, added probe error checking, added probe inspection report +// Modified 31/03/2025: Robot Oblivion + +// load probe config +G65 "PROBECONFIG" A#1 + +// important local variables #100 = @100 //TOOL NUMBER PROVIDED BY PROBECONFIG MACRO #110 = @103 //FEED SPEED PROVIDED BY PROBECONFIG MACRO #111 = @104 //FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO @@ -26,11 +29,7 @@ G65 "PROBECONFIG" #108 = @108 //PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO #2 = ABS[#2] #3 = ABS[#3] - - -//CALCULATE EXTENDED WCS NUMBER -//FIX removes any decimal value -#114 = ROUND[[#1 - FIX[#1]] * 10] +#114 = @114 // processed extended WCS number provided by ProbeConfig macro //probe X starting from a negative offset and probing in the positive direction //MOVE TO -X SIDE OF THE PART, BEFORE STARTING TO PROBE @@ -46,7 +45,7 @@ M20 // UNLOCK SPINDLE ORIENT M19 P0 // ORIENT SPINDLE 0 DEGREES TO KEEP THE POBING POINT THE SAME //DROP TO PROBING HEIGHT -G31 G91 P2 Z-#3 F#110 +G31 G91 P2 Z-#3 F#110 //Error Checking IF[R_SKIP[0,1] == 1] @@ -54,9 +53,8 @@ IF[R_SKIP[0,1] == 1] GOTO1 //go to line with N1 and quit END_IF - //Probe X on left side -G31 G91 P2 X[#122+#108] F#111 //FEED PROBING DINSTANCE + BACK OFF UNTIL SKIP FAST +G31 G91 P2 X[#122+#108] F#111 //FEED PROBING DINSTANCE + BACK OFF UNTIL SKIP FAST //Error Checking IF[R_SKIP[0,1] == 0] @@ -64,8 +62,6 @@ IF[R_SKIP[0,1] == 0] GOTO1 //go to line with N1 and quit END_IF - - G91 G01 X[-#108] //Back OFF FIX_CUT_OR_ON G31 G91 P2 X[#108] F#112 //FEED UNTIL SKIP SLOW @@ -73,8 +69,6 @@ FIX_CUT_OR_OFF #104=R_SKIP[0,201] //GET FIRST MACHINE X COORDINATE G91 G01 X-[#108] //Back off - - //lift Z after probe G31 G91 P2 Z#3 F#110 //move above the part @@ -131,7 +125,14 @@ END_IF //oversized stock alarm if stock error is greater than tolorance IF[#19!=#0 && #126>#18 ] - ALARM["ERROR: STOCK OUTSIDE OF TOLORANCE IN X"] +#136 = ROUND[[#107-#2] * @11] / @11 // Round to 3/4 decimal places +#107 = ROUND[#107 * @11] / @11 // Round to 3/4 decimal places + MENU_ADD["Expected size: #2",""]; + MENU_ADD["Probed size: #107",""]; + MENU_ADD["Tolerance: #18",""]; + MENU_ADD["Off-target: #136",""]; + MENU["Error","Stock outside of tolerance in X","",1]; + ALARM["Error: Stock outside of tolerance in X"] END_IF //safety check for inspection variable @@ -140,7 +141,7 @@ IF[#9 == #0] END_IF //STORE X OFFSET -IF [#1 < 53 || #1 == #0 || #9>0] +IF [#1 == #0 || #9>0] //DO NOT SET ANYTHING INTO WCS ELSEIF [#114 < 1] W_G53G59_COOR[0,#1,1,#104] @@ -149,14 +150,22 @@ ELSE END_IF //simple inspection reporting -IF[#17>0] -MENU_ADD["Part Length: #107",""]; -MENU["INSPECTION REPORT","RESULTS","",1]; +IF [#17 > 0] + #98 = ROUND[@998 * @11] / @11 // Round to 3/4 decimal places + IF[@10 == 21] + MENU_ADD["Part Width mm X: #98",""]; + ELSE + MENU_ADD["Part Width In X: #98",""]; + END_IF + MENU["INSPECTION REPORT","RESULTS","",1]; END_IF N1 -M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +END_IF + G90 M99 \ No newline at end of file diff --git a/PROBEXYANGLE b/PROBEXYANGLE index 3b491c8..381a86c 100644 --- a/PROBEXYANGLE +++ b/PROBEXYANGLE @@ -1,18 +1,19 @@ // Copyright 2024 Toolpath Labs Inc., Justin Gray, and Josh Smith -// PROBEXWEB -// Description: Probe and report an angle measured in the XY plane +// PROBEXYANGLE +// Probe and report an angle measured in the XY plane + +// Argument A -> #1 is the work coordinate system to store offsets in +// Argument B -> #2 is the distance between probing points +// Argument C -> #3 is the probing distance +// Argument D -> #4 is the probing axis 1=X, 2=Y +// Argument Q -> #17 turns on inspection report on/off: 0 leaves it off ; 1 turns it on ; it is off by default + // Initial Coding: Joshua Smith -// #1 is the work coordinate system to store offsets in -// #2 is the distance between probing points -// #3 is the probing distance -// #4 is the probing axis 1=X, 2=Y -// #17 turns on inspection report on/off: 0 leaves it off ; 1 turns it on ; it is off by default +// Modified 31/03/2025: Robot Oblivion // load probe config -G65 "PROBECONFIG" - -M19 // ORIENT SPINDLE +G65 "PROBECONFIG" A#1 // important local variables #100 = @100 // TOOL NUMBER PROVIDED BY PROBECONFIG MACRO @@ -23,10 +24,12 @@ M19 // ORIENT SPINDLE #109 = R_MACH_COOR[0,1] // GET MACHINE X COORDINATE #110 = R_MACH_COOR[0,2] // GET MACHINE y COORDINATE #111 = R_MACH_COOR[0,3] // GET MACHINE z COORDINATE +#128 = @128 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO +#114 = @114 // processed extended WCS number provided by ProbeConfig macro -// CALCULATE EXTENDED WCS NUMBER -// FIX removes any decimal value -#114 = ROUND[[#1 - FIX[#1]] * 10] +IF[#128 == 1] + M19 // ORIENT SPINDLE +END_IF IF[#4== 1] @@ -171,17 +174,18 @@ ELSE END_IF - - // simple inspection reporting -IF[#17>0] -MENU_ADD["MEASURED ANGLE: #126",""]; -MENU["INSPECTION REPORT","RESULTS","",1]; +IF [#17 > 0] + MENU_ADD["MEASURED ANGLE: #126",""]; + MENU["INSPECTION REPORT","RESULTS","",1]; END_IF N1 -M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +END_IF + G90 M99 \ No newline at end of file diff --git a/PROBEY b/PROBEY index 98f40d5..03d2a6e 100644 --- a/PROBEY +++ b/PROBEY @@ -1,44 +1,46 @@ -//Copyright 2024 Toolpath Labs Inc., Justin Gray, and Josh Smith +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion -//PROBEY -//Description: Probe in Y from the front or back -//Initial Coding: Justin Gray -//Modified 1/14/2024: Joshua Smith -//Simplified WCS extended number math, added probe error checking, added probe distance argument -//Argument A -> #1 is the work coordinate system to store offsets in. The format for extended G54 offsets would be a period followed by the offset G54.5 -//Argument B -> #2 is the desired probing distance. Enter a positive value to probe the front and a negative value to probe the back -//Argument I -> #9 print results enabled by fusion360 +// PROBEY +// Probe in Y from the front or back -//load probe config -G65 "PROBECONFIG" +// Argument A -> #1 is the work coordinate system to store offsets in. The format for extended G54 offsets would be a period followed by the offset G54.5 +// Argument B -> #2 is the desired probing distance. Enter a positive value to probe the front and a negative value to probe the back +// Argument I -> #9 print results enabled by fusion360 -M19 // ORIENT SPINDLE +// Initial Coding: Justin Gray +// Modified 1/14/2024: Joshua Smith +// Simplified WCS extended number math, added probe error checking, added probe distance argument +// Modified 31/03/2025: Robot Oblivion -//important local variables -#111 = @104 //FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO -#112 = @105 //SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO -#105 = @102 //TOOL RADIUS PROVIDED BY PROBECONFIG MACRO -#108 = @108*[#2/ABS[#2]] //PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO * the sign//+1 or -1 of probe distance +// load probe config +G65 "PROBECONFIG" A#1 -//CALCULATE EXTENDED WCS NUMBER -//FIX removes any decimal value -#114 = ROUND[[#1 - FIX[#1]] * 10] +// important local variables +#111 = @104 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#112 = @105 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#105 = @102 // TOOL RADIUS PROVIDED BY PROBECONFIG MACRO +#108 = @108*[#2/ABS[#2]] // PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO * the sign +1 or -1 of probe distance +#114 = @114 // processed extended WCS number provided by ProbeConfig macro +#128 = @128 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO +M20 // UNLOCK SPINDLE ORIENT +IF[#2 < 0] + M19 P270 // ORIENT SPINDLE 270 DEGREES +ELSE + M19 P90 // ORIENT SPINDLE 0 DEGREES +END_IF //Probe X the desired distance and at fast feed -G31 G91 P2 Y[#2] F#111 //FEED UNTIL SKIP FAST +G31 G91 P2 Y[#2] F#111 //FEED UNTIL SKIP FAST //Check that the probe has triggered IF[R_SKIP[0,1] == 1] - - - - G91 G01 Y-[#108] //back off 1/4 the probing distance + G91 G01 Y-[#108] //back off distance provided by ProbeConfig macro FIX_CUT_OR_ON - G31 G91 P2 Y[#2] F#112 //FEED UNTIL SKIP SLOW + G31 G91 P2 Y[#2] F#112 //Probe Y the desired distance at slow feed FIX_CUT_OR_OFF #104=R_SKIP[0,202] //GET MACHINE Y COORDINATE - G91 G01 Y-[#108] //back off 1/4 the probing distance + G91 G01 Y-[#108] //back off distance provided by ProbeConfig macro #106 = [#104+[[#2/abs[#2]]*#105]] //current position +/- probe radius @996 = #106 @@ -47,20 +49,23 @@ IF[R_SKIP[0,1] == 1] #9 = 0 END_IF -//STORE Y OFFSET For WCS Zero -IF [#1 < 53 || #1 == #0 || #9 > 0] - //DO NOT WRITE ANYTHING TO WCS -ELSEIF [#114 < 1] - W_G53G59_COOR[0,#1,2,#106] + //STORE Y OFFSET For WCS Zero + IF [#1 == #0 || #9 > 0] + //DO NOT WRITE ANYTHING TO WCS + ELSEIF [#114 < 1] + W_G53G59_COOR[0,#1,2,#106] + ELSE + W_G54EXP_COOR[0,#114,2,#106] + END_IF + ELSE - W_G54EXP_COOR[0,#114,2,#106] + ALARM["ERROR: FAILED TO PROBE PART WITHIN SPECIFIED DISTANCE"] END_IF - -ELSE - ALARM["ERROR: FAILED TO PROBE PART WITHIN SPECIFIED DISTANCE"] +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY END_IF -M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY G90 -M99 +G00 // return to rapid speed +M99 \ No newline at end of file diff --git a/PROBEYSLOT b/PROBEYSLOT index 5f40ec6..05e429a 100644 --- a/PROBEYSLOT +++ b/PROBEYSLOT @@ -1,24 +1,27 @@ -//Copyright 2024 Toolpath Labs Inc., Justin Gray, and Josh Smith - -//PROBEYSLOT -//Description: Probe a web in X from left to right -//Initial Coding: Justin Gray -//Modified 1/14/2024: Joshua Smith -//Simplified WCS extended number math, added probe error checking, added probe inspection report -//#1 is the work coordinate system to store offsets in -//#2 is the expected width of the web in the Y direction -//#9 print results enabled by fusion360 -//#17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on -//#18 oversize tolorance -//#19 enable oversize check - -//load probe config -G65 "PROBECONFIG" +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// PROBEYSLOT +// Probe a web in X from left to right + +// Argument A -> #1 is the work coordinate system to store offsets in +// Argument B -> #2 is the expected length of the web in the Y direction +// Argument I -> #9 print results enabled by fusion360 +// Argument Q -> #17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on +// Argument R -> #18 oversize tolorance +// Argument S -> #19 enable oversize check + +// Initial Coding: Justin Gray +// Modified 1/14/2024: Joshua Smith +// Simplified WCS extended number math, added probe error checking, added probe inspection report +// Modified 31/03/2025: Robot Oblivion + +// load probe config +G65 "PROBECONFIG" A#1 M20 // UNLOCK SPINDLE ORIENT M19 P270 // ORIENT SPINDLE 270 DEGREES TO KEEP THE POBING POINT THE SAME -//important local variables +// important local variables #100 = @100 //TOOL NUMBER PROVIDED BY PROBECONFIG MACRO #110 = @103 //FEED SPEED PROVIDED BY PROBECONFIG MACRO #111 = @104 //FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO @@ -27,10 +30,7 @@ M19 P270 // ORIENT SPINDLE 270 DEGREES TO KEEP THE POBIN #122 = @106 //WEB PROBE DISTANCE PROVIDED BY PROBECONFIG MACRO #108 = @108 //PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO #2 = ABS[#2] - -//CALCULATE EXTENDED WCS NUMBER -//FIX is a round down function and MOD is modulo -#114 = ROUND[[#1 - FIX[#1]] * 10] +#114 = @114 // processed extended WCS number provided by ProbeConfig macro //probe Y starting from a negative offset and probing in the positive direction //MOVE TO -Y SIDE OF THE PART, BEFORE STARTING TO PROBE @@ -42,8 +42,6 @@ IF[R_SKIP[0,1] == 0] GOTO1 //go to line with N1 and quit END_IF - - G91 G01 Y[#108] //back off FIX_CUT_OR_ON G31 G91 P2 Y[-#108] F#112 //FEED UNTIL SKIP SLOW @@ -85,7 +83,14 @@ END_IF //oversized stock alarm if stock error is greater than tolorance IF[#19!=#0 && #126>#18 ] - ALARM["ERROR: STOCK OUTSIDE OF TOLORANCE IN Y"] + #136 = ROUND[[#107-#2] * @11] / @11 // Round to 3/4 decimal places + #107 = ROUND[#107 * @11] / @11 // Round to 3/4 decimal places + MENU_ADD["Expected size: #2",""]; + MENU_ADD["Probed size: #107",""]; + MENU_ADD["Tolerance: #18",""]; + MENU_ADD["Off-target: #136",""]; + MENU["Error","Stock outside of tolerance in Y","",1]; + ALARM["Error: Stock outside of tolerance in Y"] END_IF //safety check for inspection variable @@ -94,7 +99,7 @@ IF[#9 == #0] END_IF //STORE Y OFFSET -IF [#1 < 53 || #1 == #0 || #9 > 0] +IF [#1 == #0 || #9 > 0] //DO NOT WRITE ANYTHING TO WCS ELSEIF [#114 < 1] W_G53G59_COOR[0,#1,2,#104] @@ -103,13 +108,21 @@ ELSE END_IF //simple inspection reporting -IF[#17>0] - MENU_ADD["Part Width: #107",""]; +IF [#17 > 0] + #99 = ROUND[@999 * @11] / @11 // Round to 3/4 decimal places + IF[@10 == 21] + MENU_ADD["Part Length mm Y: #99",""]; + ELSE + MENU_ADD["Part Length In Y: #99",""]; + END_IF MENU["INSPECTION REPORT","RESULTS","",1]; END_IF N1 -M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +END_IF + G90 M99 \ No newline at end of file diff --git a/PROBEYWEB b/PROBEYWEB index 091ff73..19e7886 100644 --- a/PROBEYWEB +++ b/PROBEYWEB @@ -1,22 +1,25 @@ -//Copyright 2024 Toolpath Labs Inc., Justin Gray, and Josh Smith - -//PROBEYWEB -//Description: Probe a web in X from left to right -//Initial Coding: Justin Gray -//Modified 1/14/2024: Joshua Smith -//Simplified WCS extended number math, added probe error checking, added probe inspection report -//#1 is the work coordinate system to store offsets in -//#2 is the expected width of the web in the Y direction -//#3 is the Z drop height -//#9 print results enabled by fusion360 -//#17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on -//#18 oversize tolorance -//#19 enable oversize check - -//load probe config -G65 "PROBECONFIG" - -//important local variables +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// PROBEYWEB +// Probe a web in Y from Front to back + +// Argument A -> #1 is the work coordinate system to store offsets in +// Argument B -> #2 is the expected length of the web in the Y direction +// Argument C -> #3 is the Z drop height +// Argument I -> #9 print results enabled by fusion360 +// Argument Q -> #17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on +// Argument R -> #18 oversize tolorance +// Argument S -> #19 enable oversize check + +// Initial Coding: Justin Gray +// Modified 1/14/2024: Joshua Smith +// Simplified WCS extended number math, added probe error checking, added probe inspection report +// Modified 31/03/2025: Robot Oblivion + +// load probe config +G65 "PROBECONFIG" A#1 + +// important local variables #100 = @100 //TOOL NUMBER PROVIDED BY PROBECONFIG MACRO #110 = @103 //FEED SPEED PROVIDED BY PROBECONFIG MACRO #111 = @104 //FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO @@ -26,10 +29,7 @@ G65 "PROBECONFIG" #108 = @108 //PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO #2 = ABS[#2] #3 = ABS[#3] - -//CALCULATE EXTENDED WCS NUMBER -//FIX removes any decimal value -#114 = ROUND[[#1 - FIX[#1]] * 10] +#114 = @114 // processed extended WCS number provided by ProbeConfig macro //probe Y starting from a negative offset and probing in the positive direction //MOVE TO -Y SIDE OF THE PART, BEFORE STARTING TO PROBE @@ -42,7 +42,7 @@ IF[R_SKIP[0,1] == 1] END_IF M20 // UNLOCK SPINDLE ORIENT -M19 P90 // ORIENT SPINDLE 90 DEGREES TO KEEP THE POBING POINT THE SAME +M19 P90 // ORIENT SPINDLE 0 DEGREES TO KEEP THE POBING POINT THE SAME //DROP TO PROBING HEIGHT G31 G91 P2 Z-#3 F#110 @@ -125,7 +125,14 @@ END_IF //oversized stock alarm if stock error is greater than tolorance IF[#19!=#0 && #126>#18 ] - ALARM["ERROR: STOCK OUTSIDE OF TOLORANCE IN Y"] +#136 = ROUND[[#107-#2] * @11] / @11 // Round to 3/4 decimal places +#107 = ROUND[#107 * @11] / @11 // Round to 3/4 decimal places + MENU_ADD["Expected size: #2",""]; + MENU_ADD["Probed size: #107",""]; + MENU_ADD["Tolerance: #18",""]; + MENU_ADD["Off-target: #136",""]; + MENU["Error","Stock outside of tolerance in Y","",1]; + ALARM["Error: Stock outside of tolerance in Y"] END_IF //safety check for inspection variable @@ -134,7 +141,7 @@ IF[#9 == #0] END_IF //STORE Y OFFSET -IF [#1 < 53 || #1 == #0 || #9 > 0] +IF [#1 == #0 || #9 > 0] //DO NOT SET ANYTHING INTO WCS ELSEIF [#114 < 1] W_G53G59_COOR[0,#1,2,#104] @@ -143,14 +150,22 @@ ELSE END_IF //simple inspection reporting -IF[#17>0] -MENU_ADD["Part Width: #107",""]; -MENU["INSPECTION REPORT","RESULTS","",1]; +IF [#17 > 0] + #99 = ROUND[@999 * @11] / @11 // Round to 3/4 decimal places + IF[@10 == 21] + MENU_ADD["Part Length mm Y: #99",""]; + ELSE + MENU_ADD["Part Length In Y: #99",""]; + END_IF + MENU["INSPECTION REPORT","RESULTS","",1]; END_IF N1 -M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +END_IF + G90 M99 \ No newline at end of file diff --git a/PROBEZ b/PROBEZ index 80a1595..10124ac 100644 --- a/PROBEZ +++ b/PROBEZ @@ -1,71 +1,74 @@ -//Copyright 2024 Toolpath Labs Inc., Justin Gray, and Josh Smith +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion -//PROBEZ -//Description: Probe in Z from the above stock -//Initial Coding: Justin Gray -//Modified 1/14/2024: Joshua Smith -//Simplified WCS extended number math, added probe error checking, added probe distance argument,removed air blast -//Argument A -> #1 is the work coordinate system to store offsets in. The format for extended G54 offsets would be a period followed by the offset G54.5 -//Argument B -> #2 is the desired probing distance and should be negative -//Argument I -> #9 print results enabled by fusion360 +// PROBEZ +// Probe in Z from the above stock -//load probe config -G65 "PROBECONFIG" +// Argument A -> #1 is the work coordinate system to store offsets in. The format for extended G54 offsets would be a period followed by the offset G54.5 +// Argument B -> #2 is the desired probing distance and should be negative +// Argument I -> #9 print results enabled by fusion360 -M19 // ORIENT SPINDLE +// Initial Coding: Justin Gray +// Modified 1/14/2024: Joshua Smith +// Simplified WCS extended number math, added probe error checking, added probe distance argument,removed air blast +// Modified 31/03/2025: Robot Oblivion -//important local variables -#111 = @104 //FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO -#112 = @105 //SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO -#105 = @107 //TOOL LENGTH PROVIDED BY PROBECONFIG MACRO -#108 = @108 //PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO +// load probe config +G65 "PROBECONFIG" A#1 -//CALCULATE EXTENDED WCS NUMBER -//FIX removes any decimal value -#114 = ROUND[[#1 - FIX[#1]] * 10] +// important local variables +#104 = @104 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#105 = @105 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#107 = @107 // TOOL LENGTH PROVIDED BY PROBECONFIG MACRO +#108 = @108 // PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO +#114 = @114 // processed extended WCS number provided by ProbeConfig macro +#128 = @128 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO + +IF[#128 == 1] + M19 // ORIENT SPINDLE +END_IF //Check that the probe distance is negative IF[#2<0] -//Probe z the desired distance and at fast feed -G31 G91 P2 Z[#2] F#111 - - //Check that the probe has triggered - IF[R_SKIP[0,1] == 1] +//Probe Z the desired distance and at fast feed +G31 G91 P2 Z[#2] F#104 - +//Check that the probe has triggered +IF[R_SKIP[0,1] == 1] + G91 G01 Z+[#108] //back off distance provided by ProbeConfig macro + FIX_CUT_OR_ON + G31 G91 P2 Z[#2] F#105 //Probe X the desired distance at slow feed + FIX_CUT_OR_OFF + #142=R_SKIP[0,203] //GET MACHINE Z COORDINATE + G91 G01 Z+[#108] //back off distance provided by ProbeConfig macro + #143 = [#142-#107] //current position - probe length + @996 = #143 - G91 G01 Z+[#108] //back off 1/4 the probing distance - FIX_CUT_OR_ON - G31 G91 P2 Z[#2] F#112 //Probe X the desired distance at slow feed - FIX_CUT_OR_OFF - #104=R_SKIP[0,203] //GET MACHINE Z COORDINATE - G91 G01 Z+[#108] //back off 1/4 the probing distance - #106 = [#104-#105] //current position - probe length - @996 = #106 - - //safety check for inspection variable - IF[#9 == #0] - #9 = 0 - END_IF + //safety check for inspection variable + IF[#9 == #0] + #9 = 0 + END_IF - //STORE Z OFFSET FOR WCS ZERO - IF [#1 < 53 || #1 == #0 || #9 > 0] - //DO NOT SET ANYTHING INTO WCS - ELSEIF [#114 < 1] - W_G53G59_COOR[0,#1,3,#106] - ELSE - W_G54EXP_COOR[0,#114,3,#106] + //STORE Z OFFSET for WCS Zero + IF [#1 == #0 || #9 > 0] + //DO NOT WRITE ANYTHING TO WCS + ELSEIF [#114 < 1] + W_G53G59_COOR[0,#1,3,#143] + ELSE + W_G54EXP_COOR[0,#114,3,#143] END_IF - ELSE - ALARM["ERROR: FAILED TO PROBE PART WITHIN SPECIFIED DISTANCE"] + ALARM["Error: Failed to probe part within specified distance"] END_IF ELSE - ALARM["ERROR: PROBE DISTANCE MUST BE NEGATIVE"] + ALARM["Error: Probe distance must be negative"] +END_IF + +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY END_IF -M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY G90 +G00 // return to rapid speed M99 \ No newline at end of file diff --git a/PROTECTEDMOVE b/PROTECTEDMOVE index c3878ad..eb0df8e 100644 --- a/PROTECTEDMOVE +++ b/PROTECTEDMOVE @@ -1,21 +1,25 @@ // Copyright 2024 Toolpath Labs Inc., Justin Gray -// PROTECTED ABSOLUTE MOVE +// PROTECTEDMOVE +// Move to target position using G31 to stop should an unexpected collision occurs +// Argument X -> #24 ABSOLUTE X POSITION TO MOVE TO +// Argument Y -> #25 ABSOLUTE X POSITION TO MOVE TO +// Argument Z -> #26 ABSOLUTE X POSITION TO MOVE TO -// X #24-> ABSOLUTE X POSITION TO MOVE TO -// Y #25-> ABSOLUTE X POSITION TO MOVE TO -// Z #26-> ABSOLUTE X POSITION TO MOVE TO +// Initial Coding: Justin Gray +// Modified 31/03/2025: Robot Oblivion // load probe config G65 "PROBECONFIG" -M19 // ORIENT SPINDLE - - #100 = @100 // TOOL NUMBER PROVIDED BY PROBECONFIG MACRO #103 = @103 // FEED SPEED PROVIDED BY PROBECONFIG MACRO +#128 = @128 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO +IF[#128 == 1] + M19 // ORIENT SPINDLE +END_IF #120=R_SYS_INFO[0,2] // CURRENT TOOL NUMBER @@ -40,7 +44,11 @@ END_IF // Error Checking IF[R_SKIP[0,1] == 1] - ALARM["ERROR: PROTECTED MOVE TRIGGERED PROBE - UNEXPECTED OBSTACLE "] + ALARM["ERROR: Protected move triggered probe - unexpected obstacle"] END_IF -M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY + +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +END_IF + M99 \ No newline at end of file diff --git a/SAFESPIN b/SAFESPIN index 586eade..c854443 100644 --- a/SAFESPIN +++ b/SAFESPIN @@ -1,12 +1,20 @@ // Copyright 2024 Toolpath Labs Inc., Justin Gray +// SAFESPIN // TURN ON SPINDLE AFTER SAFTEY CHECK -// #1 is the commanded RPM +// Argument A -> #1 is the commanded RPM + +// Initial Coding: Justin Gray +// Modified 31/03/2025: Robot Oblivion // load probe config G65 "PROBECONFIG" -M19 // ORIENT SPINDLE + +#128 = @128 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO +IF[#128 == 1] + M19 // ORIENT SPINDLE +END_IF #110 = @100 // PROBE TOOL NUMBER @@ -18,6 +26,11 @@ IF [#100 == #110] // THE PROBE IS LOADED ELSE S#1 M3 END_IF -M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY -N1 + +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +END_IF + +N1 + M99 \ No newline at end of file diff --git a/TOOLSET b/TOOLSET index c9c6c7e..701d78c 100644 --- a/TOOLSET +++ b/TOOLSET @@ -1,45 +1,57 @@ // Copyright 2024 Toolpath Labs Inc., Justin Gray -// AUTO TOOL SET +// TOOLSET +// measure the tool length offset using the tool setter -// #1 is the tool diameter -// #2 is the tool angle +// Argument A -> #1 is the tool diameter +// Argument B -> #2 is the tool angle -#100=R_SYS_INFO[0,2] // SAVE CURRENT TOOL NUMBER TO #100 +// Initial Coding: Justin Gray +#100=R_SYS_INFO[0,2] // SAVE CURRENT TOOL NUMBER TO #100 +@10 = R_G_GROUP[0,6] // pull in metric or freedom units // load probe config G65 "PROBECONFIG" T#100 -#104 = @115 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#104 = @117 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO #105 = @116 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO -#110=R_TOOL_DATA[0,199,203] // TOOLSETTER - T199 - REFERENCE HEIGHT -#112=@112 // TOOLSETTER EXTENDED WORKOFFSET NUMBER +#110 = R_TOOL_DATA[0,199,203] // TOOLSETTER - T199 - REFERENCE HEIGHT +#112 = @112 // TOOLSETTER EXTENDED WORKOFFSET NUMBER G90 G94 G17 G49 G40 G80 -G20 // INCH -G28 G91 Z0. +G53 G90 G00 Z0 // Move the spindle all the way up before xy movement for safety G54P#112 // LOCATION OF TOOL SETTER IS X0 Y0 ON G54P100 - G90 G0 X[0+#1/2] Y0 // MOVE TO TOOLSETTER + TOOL RADIUS OFFSET + M20 // UNLOCK SPINDLE ORIENT M19 P#2 // ORIENT SPINDLE TO THE GIVEN ANGLE -G31 Z-20 F#104 // FEED UNTIL INPUT SIGNAL AKA SKIP -G91 G0 Z0.2 // MOVE UP -FIX_CUT_OR_ON -G31 Z-.21 F#105 // FEED UNTIL SKIP SLOWER +G91 // RELATIVE MODE + +IF[@10 == 21] + G21 // Metric + G31 Z-400.0 F#104 // FEED UNTIL INPUT SIGNAL AKA SKIP + G91 G0 Z5.0 // MOVE UP + FIX_CUT_OR_ON + G31 Z-5.5 F#105 // FEED UNTIL SKIP SLOWER +ELSEIF[@10 == 20] + G20 // fREEDOM UNITS (INCH) + G31 Z-20 F#104 // FEED UNTIL INPUT SIGNAL AKA SKIP + G91 G0 Z0.2 // MOVE UP + FIX_CUT_OR_ON + G31 Z-.21 F#105 // FEED UNTIL SKIP SLOWER +END_IF FIX_CUT_OR_OFF -#120= R_SKIP[0,103] // GET MACHINE Z COORDINATE + +#120= R_SKIP[0,103] // GET MACHINE Z COORDINATE // NOTE: LENGTH OF MASTER GAUGE TOOL IS ACOUNTED FOR IN CALIBRATION // MAKE SURE THE CORRECT VALUE IS SET IN PROBECONFIG #121 = [#120 - #110] // COMPUTE TOOL LENGTH - - W_TOOL_DATA[0,#100,203,#121] // WRITE TOOL Z LENGTH W_TOOL_DATA[0,#100,101,0] // SET TOOL RADIUS AND ALL WEAR OFFSETS TO 0 W_TOOL_DATA[0,#100,102,0] @@ -49,6 +61,6 @@ W_TOOL_DATA[0,#100,3,0] W_TOOL_DATA[0,#100,202,0] W_TOOL_DATA[0,#100,201,0] -G28 G91 Z0. -M20 // UNLOCK SPINDLE ORIENT +G53 G90 G00 Z0 // Move the spindle all the way up before xy movement for safety +M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY M99 \ No newline at end of file From 71a1f6a1e56c053c036668103e6e75a3d25212b7 Mon Sep 17 00:00:00 2001 From: Robot Oblivion Date: Mon, 31 Mar 2025 18:17:11 +1300 Subject: [PATCH 05/21] Major rebuild of the Toolpath.com Syil post by Scott Moyse to the latest revsion of the standard LNC post (Revision: 44168) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updated 28-3-25 : Enable inspection reporting check box added to probing operation post properties tab - when checked it will add a Q1 value to that probing arguments HSHP smoothing settings added to milling operation post properties tab - logic yet to be added to make this work Removed precisionLevel option that is not available to LNC6800 Probe inside corner function updated to match rev 42831 post Updated 21-3-25: probing output reworked to match the previous post version - initial position moves masked with protected calls for safety in writeInitialPositioning() - var macroCall moved to above onSection() to be available for initalPosition() - probeOutputWorkOffset variable and code pulled from old post and placed below subprogramEnd() - probing cycles updated to output required arguments for macros and match (rev. 42831) - probing-xy-inner-corner information pulled from FANUC Rev. 42831 - forceXYZ() removed from most cycles to avoid a double call - var probeOutputWorkOffset in setProbeAngle() commented out but may still be required Updated 17-3-25: added missing variables : - probeOutputWorkOffset - ln. 346 ***unsure of the best location - probeWorkOffsetCode - function writeProbeCycle(cycle, x, y, z, P, F) added logic to: - spin on the probe at the start of any block of probing operations - spin off the probe at the end of any block of probing operations - force the closing section of an optional operation(s) to ensure any probe off, manual tool changes or tool break detection cycles are run. - force any tool changes or work offsets that may have been skipped at the start of the first not optional section *** may need to add workplanes to the above list Added a Added a post properties option for spinning the probe on/off and selecting the corresponding M codes. Removed "Attention- Property 'Safe Retracts' is set to 'Clearance Height" warning. Updated 17-3-25: updated from LNC "Syntec" rev 44145 to 44168 (latest) standard post and headder updated Updated 16-3-25: Added clearance height flag for less Z retraction when working on the 4th full Z retract issued before: any automatic tool changes any changes of WCS tool break control cycle swapping a manual tool into the spindle swapping a manual tool out of the spindle after any optional sections to avoid the risk of a skipped full Z retract Z retract ignored: 4th axis indexing between operations that are the same WCS and the same tool -writeRetract(Z) commented out in two places effects need confirming are not dangerous: 1) function setWorkPlane(abc) { //writeRetract(Z); // ln 1649 2) function positionABC(abc, force) //writeRetract(Z); // ln 2880 - moved pre "operation-comment" code from start of onSection() into the end of onSectionEnd() for more predicable manual NC injection - Force tool change position logic added - Manual tool change position option and logic added - methodXY and methodZ set to G53 and on tool change updated as currently the most reliable option for me - Machine connection moves logic added - Tool table layout adjusted and below holder stick out information added - small minor changes made to formatting to aid in reliability - overall clean up to previous updates made to stock post - DebugByCarnie global variable switch created Updated 8-3-25: Added retract to clearance height option retract.methodXY set to G53 for more predictable simulation connection moves full retract called when changing WCS, tool change (manual and automatic) and before break detection cycles machine simulation moves for clearance height changed for work coordinates** ** Current issue when simulating moves to different WCS issuing the wrong WCS initial position however Gcode output looks safe with a full z retract called.   - small change to manual tool removal message Updated 7-3-25: Added manual tool change logic to onSection() to support unloading the tool in the ATC umbrella and installing a manual tool. extra logic to shut down coolant early to maximise drip-out time extra info passed from fusion into comments to help the operator confirm the right tool, holder and stick out is being loaded into the spindle. - Added a first pass at tool break control  - needs testing and uses the stock Syil provided macro M106 - Removed unrequired variables from writeToolBlock() Updated 4-3-25: Minor UI changes to syil_lnc_toolpath.cps - Post properties table renamed and reordered - G30 option added to safePositionMethod() - Tool change position added to writeToolBlock() and machine simulation details updated to allow simulation of tool change connection moves --- Syil_LNC_RobotOblivion.cps | 4488 ++++++++++++++++++++++++++++++++++++ 1 file changed, 4488 insertions(+) create mode 100644 Syil_LNC_RobotOblivion.cps diff --git a/Syil_LNC_RobotOblivion.cps b/Syil_LNC_RobotOblivion.cps new file mode 100644 index 0000000..08d875e --- /dev/null +++ b/Syil_LNC_RobotOblivion.cps @@ -0,0 +1,4488 @@ +/** + Copyright (C) 2012-2025 by Autodesk, Inc. + All rights reserved. + + Syntec post processor configuration. + + $Revision: 44168 693f63a68cfb67ec4ae6e75af05d444bd32a75b0 $ + $Date: 2025-02-19 11:52:14 $ + + FORKID {78441FCF-1C1F-4D81-BFA8-AAF6F30E1F3B} +*/ + +/*---------------------------------------------------------------------------------------------------------- +Post setup + - Set auto and manual tool change options and position values @ line: 263-310 + - If unchecked the post will fall back to the home position in the machine model and then to the post machine configuration + For the most realistic machine simulation to use: + retract: { + cancelRotationOnRetracting: false, // specifies that rotations (G68) need to be canceled prior to retracting + methodXY : "G53", // will use the post properties tool change location + methodZ : undefined, // leave undefined so that the post properties drop-down can override + useZeroValues : ["G28"], // do not add G53 as this will cause issues with the toolchange position and machine simulation + homeXY : {onIndexing:false, onToolChange:{axes:[X, Y]}, onProgramEnd:{axes:[X, Y]}}, // homing xy on indexing only possible if retract to clearance plane diabled + Setting the home values for each axis in the machine builder is recommended to park the mill at the end of the program + --This position becomes the default toolchange location if the force toolchange position flags are turned off + - Link this post to a machine and then in the machine setup Multi-axis tab choose the feedrate method to Inverse time (minutes) drop down + - Debug markers can be turned on and changed @ line 55 +----------------------------------------------------------------------------------------------------------*/ + +description = "SYIL LNC 6800"; +vendor = "Robot Oblivion"; +vendorUrl = "www.instagram.com/RobotOblivion"; +legal = "Copyright (C) 2012-2024 by Autodesk, Inc."; +certificationLevel = 2; +minimumRevision = 45917; + +longDescription = "Syil LNC 6800 Post Processor with A-axis and machine simulation by Robot Oblivion based on Scott Moyse's oringal Toolpath.com Syil post."; + +extension = "nc"; +programNameIsInteger = true; +setCodePage("ascii"); + +capabilities = CAPABILITY_MILLING | CAPABILITY_MACHINE_SIMULATION; +tolerance = spatial(0.002, MM); + +minimumChordLength = spatial(0.25, MM); +minimumCircularRadius = spatial(0.01, MM); +maximumCircularRadius = spatial(1000, MM); +minimumCircularSweep = toRad(0.01); +maximumCircularSweep = toRad(180); +allowHelicalMoves = true; +allowedCircularPlanes = undefined; // allow any circular motion +highFeedrate = (unit == MM) ? 5000 : 200; + +var debugByCarnie = 0; // 0 = off, 1 = section markers, 2 = section and sim, 3 = sim debug only // go to line 55 to set debug level + +// user-defined properties +properties = { +/* preloadTool: { + title : "Preload tool", + description: "Preloads the next tool at a tool change (if any).", + group : "preferences", + type : "boolean", + value : true, + scope : "post" + }, */ + showSequenceNumbers: { + title : "Use sequence numbers", + description: "'Yes' outputs sequence numbers on each block, 'Only on tool change' outputs sequence numbers on tool change blocks only, and 'No' disables the output of sequence numbers.", + group : "formats", + type : "enum", + values : [ + {title:"Yes", id:"true"}, + {title:"No", id:"false"}, + {title:"Only on tool change", id:"toolChange"} + ], + value: "True", + scope: "post" + }, + sequenceNumberStart: { + title : "Start sequence number", + description: "The number at which to start the sequence numbers.", + group : "formats", + type : "integer", + value : 10, + scope : "post" + }, + sequenceNumberIncrement: { + title : "Sequence number increment", + description: "The amount by which the sequence number is incremented by in each block.", + group : "formats", + type : "integer", + value : 5, + scope : "post" + }, + optionalStop: { + title : "Optional stop", + description: "Outputs optional stop code during when necessary in the code.", + group : "preferences", + type : "boolean", + value : true, + scope : "post" + }, + separateWordsWithSpace: { + title : "Separate words with space", + description: "Adds spaces between words if 'yes' is selected.", + group : "formats", + type : "boolean", + value : true, + scope : "post" + }, + allow3DArcs: { + title : "Allow 3D arcs", + description: "Specifies whether 3D circular arcs are allowed.", + group : "preferences", + type : "boolean", + value : false, + scope : "post" + }, + useRadius: { + title : "Radius arcs", + description: "If yes is selected, arcs are outputted using radius values rather than IJK.", + group : "preferences", + type : "boolean", + value : false, + scope : "post" + }, + showNotes: { + title : "Show notes", + description: "Writes operation notes as comments in the outputted code.", + group : "formats", + type : "boolean", + value : false, + scope : "post" + }, + useSmoothing: { + title : "HSHP Mode", + description: "Users can choose the High-Speed High-Precision Parameter based on the controller HSHP configuration.", + group : "preferences", + type : "enum", + values : [ + {title:"Off", id:"-1"}, + {title:"Automatic", id:"9999"}, + {title:"Fine Precision", id:"10"}, + {title:"Precision", id:"8"}, + {title:"Balanced", id:"6"}, + {title:"Semi-rough", id:"4"}, + {title:"Roughing", id:"2"} + ], + value : "-1", + scope : "operation", //,"post" + enable : "milling", + disabled : ["probing" , "drilling"] + }, + /* precisionLevel: { + title : "Machining Condition", + description: "Users can choose the High-Speed High-Precision Parameter based on the controller HSHP configuration", + group : "preferences", + type : "enum", + values : [ + {title:"P1 More Corner", id:"P1"}, + {title:"P2 More Arcs", id:"P2"}, + {title:"P3 3C Product", id:"P3"}, + ], + value: "P2", + scope : ["operation","post"], + enable : "milling", + disabled : ["probing" , "drilling"] + }, */ + usePitchForTapping: { + title : "Use pitch for tapping", + 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!", + group : "preferences", + type : "boolean", + value : false, + scope : "post" + }, + useG95: { + title : "Use G95", + description: "Use IPR/MPR instead of IPM/MPM.", + group : "preferences", + type : "boolean", + value : false, + scope : "post" + }, + safeStartAllOperations: { + title : "Safe start all operations", + description: "Write optional blocks at the beginning of all operations that include all commands to start program.", + group : "preferences", + type : "boolean", + value : false, + scope : "post" + }, + useClampCodes: { + title : "Use 4th clamp", + description: "Specifies whether clamp codes for rotary axes should be output. For simultaneous toolpaths rotary axes will always get unclamped.", + group : "multiAxis", + type : "boolean", + value : true, + scope : "post" + }, + _1spinOnProbe: { + title : "Spin probe on/off", + description: "Specifies whether spin-on and off cycles are required for the probe", + group : "multiAxis", + type : "boolean", + value : true, + scope : "post" + }, + probeOnMCode: { + title : "M-code Probe On", + description: "M-code to use to spin on the probe.", + group : "multiAxis", + type : "integer", + value : 10719, + scope : "post" + }, + probeOffMCode: { + title : "M-code Probe off", + description: "M-code to use to spin off the probe.", + group : "multiAxis", + type : "integer", + value : 10720, + scope : "post" + }, + probeScreenPrint: { + title : "Display probed report", + description: "Enable inspection reporting in compatible cycles to pause after probing and display the results at the control", + group : "multiAxis", + type : "boolean", + value : false, + scope : "operation", + enable : "probing", + disabled : "milling" + }, + safePositionMethod: { + title : "Safe Retracts", + description: "Select your desired Z axis retract method.", + group : "homePositions", + type : "enum", + values : [ + {title:"G28", id:"G28"}, + {title:"G53", id:"G53"} + ], + value: "G53", + scope: "post" + }, + retractToClearancePlane: { + title : "Clearance height retracts", + description: "Retracts to the operation clearance height; however, any tool or WCS changes will trigger a full Z-axis retract.", + group : "homePositions", + type : "boolean", + value : false, + scope : "post" + }, + _0breakControlError: { + title : "Max. Break Control Error", + description: "Maximum Allowable Error for Break Control.", + group : "toolChange", + type : "number", + value : 0.05, + scope : "post" + }, + _1forceTCPosition: { + title : "Change Position Before Toolchange", + description: "Change the machine position before executing a toolchange.", + group : "toolChange", + type : "boolean", + value : true, + scope : "post" + }, + _2TCposX: { + title : "Toolchange Position X Axis - Machine Coordinate", + description: "Machine Coordinate for toolchange on X Axis.", + group : "toolChange", + type : "number", + value : -390, // Back left corner for syil x7 + scope : "post" + }, + _2TCposY: { + title : "Toolchange Position Y Axis - Machine Coordinate", + description: "Machine Coordinate for toolchange on Y Axis.", + group : "toolChange", + type : "number", + value : 0, // Back left corner for syil x7 + scope : "post" + }, + _3forceManualTCPosition: { + title : "Change Position Before Manual Toolchange", + description: "Change the machine position before executing a manual toolchange.", + group : "toolChange", + type : "boolean", + value : false, + scope : "post" + }, + _4manual_TCposX: { + title : "Manual toolchange Position X Axis - Machine Coordinate", + description: "Machine Coordinate for manual toolchange - X Axis.", + group : "toolChange", + type : "number", + value : 0, + scope : "post" + }, + _4manual_TCposY: { + title : "Manual toolchange Position Y Axis - Machine Coordinate", + description: "Machine Coordinate for manual toolchange - Y Axis.", + group : "toolChange", + type : "number", + value : 0, + scope : "post" + }, + EnableZeroPointCompensation: { + title : "Zero Point Compensation", + description: "Allows probing cycles to compensate for deltas bewteen a probed part and it's expected postition. The WCS after probing becomes the override origin translated by the computed deltas.", + group : "preferences", + type : "boolean", + value : false, + scope : "post" + }, + _1CustomOnOpenGcode: { + title : "Custom on open G-code", + description: "Inserts custom G-code at the beginning of the program.", + group : "CustomGcode", + type : "string", + value : "", + scope : "post" + }, + _2CustomOnCloseGcode: { + title : "Custom on close G-code", + description: "Inserts custom G-code at the end of the program.", + group : "CustomGcode", + type : "string", + value : "", + scope : "post" + } +}; + +groupDefinitions = { + CustomGcode : {title:"Custom G-code", description: "G-code to add to the start of the program", collapsed: true, order: 10}, + toolChange : {title:"Tool change", description: "Setting related to toolchanges", collapsed: true, order: 31}, + multiAxis : {title:"Probe and 4th axis M-codes ", description: "Settings related to the probe outputs and 4th axis clamp", collapsed: true, order: 34}, +}; + +// wcs definiton +wcsDefinitions = { + useZeroOffset: false, + wcs : [ + {name:"Standard", format:"G", range:[54, 59]}, + {name:"Extended", format:"G54 P", range:[1, 106]} //format:"G54 P#" in old post + ] +}; + +var gFormat = createFormat({prefix:"G", minDigitsLeft:2, decimals:1}); +var mFormat = createFormat({prefix:"M", minDigitsLeft:2, decimals:1}); +var hFormat = createFormat({prefix:"H", minDigitsLeft:2, decimals:1}); +var diameterOffsetFormat = createFormat({prefix:"D", minDigitsLeft:2, decimals:1}); + +var xyzFormat = createFormat({decimals:(unit == MM ? 3 : 4), type:FORMAT_REAL}); +var ijkFormat = createFormat({decimals:6, type:FORMAT_REAL}); // unitless +var rFormat = xyzFormat; // radius +var abcFormat = createFormat({decimals:3, type:FORMAT_REAL, scale:DEG}); +var feedFormat = createFormat({decimals:(unit == MM ? 0 : 1), type:FORMAT_REAL}); +var inverseTimeFormat = createFormat({decimals:3, type:FORMAT_REAL}); +var pitchFormat = createFormat({decimals:(unit == MM ? 3 : 4), type:FORMAT_REAL}); +var toolFormat = createFormat({decimals:0}); +var rpmFormat = createFormat({decimals:0}); +var secFormat = createFormat({decimals:3, type:FORMAT_REAL}); // seconds - range 0.001-99999.999 +var milliFormat = createFormat({decimals:0}); // milliseconds // range 1-9999 +var taperFormat = createFormat({decimals:1, scale:DEG}); +var oFormat = createFormat({minDigitsLeft:4, decimals:0}); +var peckFormat = createFormat({decimals:(unit == MM ? 3 : 4), type:FORMAT_REAL}); +// var peckFormat = createFormat({decimals:0, type:FORMAT_LZS, minDigitsLeft:4, scale:(unit == MM ? 1000 : 10000)}); +var toolTableFormat = createFormat({decimals:1,type:FORMAT_INTEGER}); // layout spacer for tool table + +var xOutput = createOutputVariable({onchange:function() {state.retractedX = false;}, prefix:"X"}, xyzFormat); +var yOutput = createOutputVariable({onchange:function() {state.retractedY = false;}, prefix:"Y"}, xyzFormat); +var zOutput = createOutputVariable({onchange:function() {state.retractedZ = false;}, prefix:"Z"}, xyzFormat); +var toolVectorOutputI = createOutputVariable({prefix:"I", control:CONTROL_FORCE}, ijkFormat); +var toolVectorOutputJ = createOutputVariable({prefix:"J", control:CONTROL_FORCE}, ijkFormat); +var toolVectorOutputK = createOutputVariable({prefix:"K", control:CONTROL_FORCE}, ijkFormat); +var aOutput = createOutputVariable({prefix:"A"}, abcFormat); +var bOutput = createOutputVariable({prefix:"B"}, abcFormat); +var cOutput = createOutputVariable({prefix:"C"}, abcFormat); +var feedOutput = createOutputVariable({prefix:"F"}, feedFormat); +var inverseTimeOutput = createOutputVariable({prefix:"F", control:CONTROL_FORCE}, inverseTimeFormat); +var pitchOutput = createOutputVariable({prefix:"F", control:CONTROL_FORCE}, pitchFormat); +var sOutput = createOutputVariable({prefix:"S", control:CONTROL_FORCE}, rpmFormat); +var peckOutput = createOutputVariable({prefix:"Q", control:CONTROL_FORCE}, peckFormat); + +// circular output +var iOutput = createOutputVariable({prefix:"I", control:CONTROL_NONZERO}, xyzFormat); +var jOutput = createOutputVariable({prefix:"J", control:CONTROL_NONZERO}, xyzFormat); +var kOutput = createOutputVariable({prefix:"K", control:CONTROL_NONZERO}, xyzFormat); + +var gMotionModal = createOutputVariable({}, gFormat); // modal group 1 // G0-G3, ... +var gPlaneModal = createOutputVariable({onchange:function () {gMotionModal.reset();}}, gFormat); // modal group 2 // G17-19 +var gAbsIncModal = createOutputVariable({}, gFormat); // modal group 3 // G90-91 +var gFeedModeModal = createOutputVariable({}, gFormat); // modal group 5 // G94-95 +var gUnitModal = createOutputVariable({}, gFormat); // modal group 6 // G70-71 +var gCycleModal = createOutputVariable({}, gFormat); // modal group 9 // G81, ... +var gRetractModal = createOutputVariable({}, gFormat); // modal group 10 // G98-99 +var fourthAxisClamp = createOutputVariable({}, mFormat); +var fifthAxisClamp = createOutputVariable({}, mFormat); + +var settings = { + coolant: { + // samples: + // {id: COOLANT_THROUGH_TOOL, on: 88, off: 89} + // {id: COOLANT_THROUGH_TOOL, on: [8, 88], off: [9, 89]} + // {id: COOLANT_THROUGH_TOOL, on: "M88 P3 (myComment)", off: "M89"} + coolants: [ + {id:COOLANT_FLOOD, on:8}, + {id:COOLANT_MIST}, + {id:COOLANT_THROUGH_TOOL, on:88, off:89}, + {id:COOLANT_AIR, on:7}, + {id:COOLANT_AIR_THROUGH_TOOL}, + {id:COOLANT_SUCTION}, + {id:COOLANT_FLOOD_MIST}, + {id:COOLANT_FLOOD_THROUGH_TOOL, on:[8, 88], off:[9, 89]}, + {id:COOLANT_OFF, off:9} + ], + singleLineCoolant: false, // specifies to output multiple coolant codes in one line rather than in separate lines + }, + smoothing: { + roughing : 2, // roughing level for smoothing in automatic mode + semi : 4, // semi-roughing level for smoothing in automatic mode + semifinishing : 6, // semi-finishing level for smoothing in automatic mode + finishing : 8, // finishing level for smoothing in automatic mode + thresholdRoughing : toPreciseUnit(0.5, MM), // operations with stock/tolerance above that threshold will use roughing level in automatic mode + thresholdsemiRough : toPreciseUnit(0.25, MM), // operations with stock/tolerance below that threshold will use simi level in automatic mode + thresholdSemiFinishing: toPreciseUnit(0.1, MM), // operations with stock/tolerance above finishing and below threshold roughing that threshold will use semi finishing level in automatic mode + thresholdFinishing : toPreciseUnit(0.05, MM), // operations with stock/tolerance below that threshold will use finishing level in automatic mode + + differenceCriteria: "level", // options: "level", "tolerance", "both". Specifies criteria when output smoothing codes + autoLevelCriteria : "stock", // use "stock" or "tolerance" to determine levels in automatic mode + cancelCompensation: false // tool length compensation must be canceled prior to changing the smoothing level + }, + retract: { + cancelRotationOnRetracting: false, // specifies that rotations (G68) need to be canceled prior to retracting + methodXY : "G53", // keeps sim true by working in mech coor. special condition, overwrite retract behavior per axis + methodZ : undefined, // special condition, overwrite retract behavior per axis + useZeroValues : ["G28"], // keeps sim true by using zero value for Z moves and different method than XY enter property value id(s) for using "0" value instead of machineConfiguration axes home position values (ie G30 Z0) + homeXY : {onIndexing:false, onToolChange:{axes:[X, Y]}, onProgramEnd:{axes:[X, Y]}}, // Specifies when the machine should be homed in X/Y. Sample: onIndexing:{axes:[X, Y], singleLine:false} + }, + parametricFeeds: { + firstFeedParameter : 500, // specifies the initial parameter number to be used for parametric feedrate output + feedAssignmentVariable: "#", // specifies the syntax to define a parameter + feedOutputVariable : "F#" // specifies the syntax to output the feedrate as parameter + }, + machineAngles: { // refer to https://cam.autodesk.com/posts/reference/classMachineConfiguration.html#a14bcc7550639c482492b4ad05b1580c8 + controllingAxis: ABC, + type : PREFER_PREFERENCE, + options : ENABLE_ALL + }, + workPlaneMethod: { + useTiltedWorkplane : false, // specifies that tilted workplanes should be used (ie. G68.2, G254, PLANE SPATIAL, CYCLE800), can be overwritten by property + eulerConvention : EULER_ZXZ_R, // specifies the euler convention (ie EULER_XYZ_R), set to undefined to use machine angles for TWP commands ('undefined' requires machine configuration) + eulerCalculationMethod: "standard", // ('standard' / 'machine') 'machine' adjusts euler angles to match the machines ABC orientation, machine configuration required + cancelTiltFirst : true, // cancel tilted workplane prior to WCS (G54-G59) blocks + //useABCPrepositioning : true, // position ABC axes prior to tilted workplane blocks KC to test why off + forceMultiAxisIndexing: false, // force multi-axis indexing for 3D programs + optimizeType : undefined // can be set to OPTIMIZE_NONE, OPTIMIZE_BOTH, OPTIMIZE_TABLES, OPTIMIZE_HEADS, OPTIMIZE_AXIS. 'undefined' uses legacy rotations + }, + subprograms: { + initialSubprogramNumber: 9001, // specifies the initial number to be used for subprograms. 'undefined' uses the main program number + minimumCyclePoints : 5, // minimum number of points in cycle operation to consider for subprogram + format : oFormat, // the format to use for the subprogam number format + // objects below also accept strings with "%currentSubprogram" as placeholder. Sample: {files:["%"], embedded:"N" + "%currentSubprogram"} + files : {extension:extension, prefix:undefined}, // specifies the subprogram file extension and the prefix to use for the generated file + startBlock : {files:["%" + EOL + "O"], embedded:["N"]}, // specifies the start syntax of a subprogram followed by the subprogram number + endBlock : {files:[mFormat.format(99) + EOL + "%"], embedded:[mFormat.format(99)]}, // specifies the command to for the end of a subprogram + callBlock : {files:[mFormat.format(98) + " H"], embedded:[mFormat.format(98) + " H"]} // specifies the command for calling a subprogram followed by the subprogram number + }, + comments: { + permittedCommentChars: " abcdefghijklmnopqrstuvwxyz0123456789.,=_-:", // letters are not case sensitive, use option 'outputFormat' below. Set to 'undefined' to allow any character + prefix : "(", // specifies the prefix for the comment + suffix : ")", // specifies the suffix for the comment + outputFormat : "ignoreCase", // can be set to "upperCase", "lowerCase" and "ignoreCase". Set to "ignoreCase" to write comments without upper/lower case formatting + maximumLineLength : 80 // the maximum number of characters allowed in a line, set to 0 to disable comment output + }, + probing: { + macroCall : gFormat.format(65), // specifies the command to call a macro + probeAngleMethod : undefined, // supported options are: OFF, AXIS_ROT, G68, G54.4. 'undefined' uses automatic selection + probeAngleVariables : {x:"#135", y:"#136", z:0, i:0, j:0, k:1, r:"#144", baseParamG54x4:26000, baseParamAxisRot:5200, method:0}, // specifies variables for the angle compensation macros, method 0 = Fanuc, 1 = Haas + allowIndexingWCSProbing: false // specifies that probe WCS with tool orientation is supported + }, + maximumSequenceNumber : undefined, // the maximum sequence number (Nxxx), use 'undefined' for unlimited + supportsToolVectorOutput : true, // specifies if the control does support tool axis vector output for multi axis toolpath + allowCancelTCPBeforeRetracting: true, // allows TCP/tool length compensation to be canceled prior retracting. Warning, ensure machine parameters 5006.6(Fanuc)/F114 bit 1(Mazak) are set to prevent axis motion when cancelling compensation. + maximumToolLengthOffset : 199, + maximumToolDiameterOffset : 199 +}; + +function onOpen() { + // define and enable machine configuration + receivedMachineConfiguration = machineConfiguration.isReceived(); + if (typeof defineMachine == "function") { + defineMachine(); // hardcoded machine configuration + } + activateMachine(); + + // postprocessor/machine specific requirements + if (getProperty("useRadius")) { + maximumCircularSweep = toRad(90); // avoid potential center calculation errors for CNC + } + if (getProperty("safePositionMethod") == "G53" && (!machineConfiguration.hasHomePositionX() || !machineConfiguration.hasHomePositionY())) { + settings.retract.methodXY = "G28"; + } + + // initialize formats + gRotationModal.format(69); // Default to G69 Rotation Off + + if (!getProperty("separateWordsWithSpace")) { + setWordSeparator(""); + } + + if (getProperty("useG95")) { + if (getProperty("useParametricFeed")) { + error(localize("Parametric feed is not supported when using G95.")); + return; + } + feedFormat = createFormat({decimals:(unit == MM ? 4 : 5), type:FORMAT_REAL}); + feedOutput.setFormat(feedFormat); + } + + writeln("%"); + if (Number.isInteger(programName)) { + writeln("O" + oFormat.format(getProgramNumber()) + conditional(programComment, " " + formatComment(programComment))); + } else { + writeComment(programName); + } + writeProgramHeader(); + + // absolute coordinates and feed per min + writeBlock(gAbsIncModal.format(90), gFeedModeModal.format(getProperty("useG95") ? 95 : 94), gPlaneModal.format(17), toolLengthCompOutput.format(49), gFormat.format(40), gFormat.format(80)); + writeBlock(gUnitModal.format(unit == MM ? 21 : 20)); + validateCommonParameters(); + + // Save the G59 Z axis into a variable #199 for use with G10 calls + writeComment("G59 stores the zero point. #199 can be used with G10 commands to pull G59 into a local WCS"); + writeBlock("#199 = R_G53G59_COOR[0,59,3]"); + writeBlock("@980 = TIME[3]"); //month + writeBlock("@981 = TIME[4]"); //day + writeBlock("@982 = TIME[2]"); //year + writeBlock("@983 = TIME[5]"); //hour + writeBlock("@984 = TIME[6]"); //minute + writeBlock("@985 = TIME[7]"); //second + writeBlock(getProperty("_1CustomOnOpenGcode")); +} + +function setSmoothing(mode) { + smoothingSettings = settings.smoothing; + if (mode == smoothing.isActive && (!mode || !smoothing.isDifferent) && !smoothing.force) { + return; // return if smoothing is already active or is not different + } + if (validateLengthCompensation && smoothingSettings.cancelCompensation) { + validate(!state.lengthCompensationActive, "Length compensation is active while trying to update smoothing."); + } + if (mode) { // enable smoothing + //writeBlock(gFormat.format(120.1), getProperty("precisionLevel"), "Q" + smoothing.level); + writeBlock(gFormat.format(5), "P" + smoothing.level); + } else { // disable smoothing + writeBlock(gFormat.format(5)+" P0"); + } + smoothing.isActive = mode; + smoothing.force = false; + smoothing.isDifferent = false; +} +var macroCall = settings.probing.macroCall; // Moved up so set before initial positioning + +function onSection() { + if(debugByCarnie >= 1 && debugByCarnie <= 2){writeComment("onSection---------v")}; // go to line 55 to set debug level + + var forceSectionRestart = !isFirstSection() && getPreviousSection().isOptional() && !currentSection.isOptional(); + optionalSection = currentSection.isOptional(); + var insertToolCall = isToolChangeNeeded("number") || forceSectionRestart; + var newWorkOffset = isNewWorkOffset() || forceSectionRestart; + var newWorkPlane = isNewWorkPlane() || forceSectionRestart; + operationNeedsSafeStart = getProperty("safeStartAllOperations") && !isFirstSection(); + initializeSmoothing(); // initialize smoothing mode + + /* Code below move to end of onSectionEnd + if (insertToolCall || newWorkOffset || newWorkPlane || smoothing.cancel || state.tcpIsActive) { + + // stop spindle before retract during tool change + if (insertToolCall && !isFirstSection()) { + onCommand(COMMAND_STOP_SPINDLE); + } + disableLengthCompensation(); + if (getSetting("workPlaneMethod.cancelTiltFirst", false)) { + cancelWorkPlane(); + } + writeRetract(Z); // retract + if (isFirstSection() && machineConfiguration.isMultiAxisConfiguration()) { + setWorkPlane(new Vector(0, 0, 0)); // reset working plane + forceABC(); + } + forceXYZ(); + if (!isFirstSection() && (insertToolCall || smoothing.cancel || state.tcpIsActive)) { + disableLengthCompensation(); + if (smoothing.cancel || insertToolCall) { + setSmoothing(false); + } + } + } + Code above move to end of onSectionEnd */ + + writeln(""); + writeComment(getParameter("operation-comment", "")); + + if (getProperty("showNotes")) { + writeSectionNotes(); + } + + // retract Z axis after any optional section and may not be required, as picked up by forceSectionRestart in onSectionEnd, but it adds an extra Z retract at the start of the section after any optional section in case of at machine change of location by operator in manual mode. + if ((!isFirstSection() && getPreviousSection().isOptional()) && optionalSection != true ) { + //state.retractedZ = false // likely not required + writeRetract(Z); + } + + // tool change + writeToolCall(tool, insertToolCall); + startSpindle(tool, insertToolCall); + + // Spin on probe + if (isProbeOperation() && (isFirstSection() || getPreviousSection().getTool().type != TOOL_PROBE) && getProperty("_1spinOnProbe")) { + onCommand(COMMAND_PROBE_ON) + } + + // write parametric feedrate table + if (typeof initializeParametricFeeds == "function") { + initializeParametricFeeds(insertToolCall); + } + + // Output modal commands here + writeBlock(gPlaneModal.format(17), gAbsIncModal.format(90), gFeedModeModal.format(getProperty("useG95") ? 95 : 94)); + + // set wcs + var wcsIsRequired = true; + if (insertToolCall || operationNeedsSafeStart) { + currentWorkOffset = undefined; // force work offset when changing tool + wcsIsRequired = newWorkOffset || insertToolCall || !operationNeedsSafeStart; + } + writeWCS(currentSection, wcsIsRequired); + + forceXYZ(); + + onCommand(COMMAND_START_CHIP_TRANSPORT); + + var abc = defineWorkPlane(currentSection, true); + + // Force simulation line to patch a bug in machine connection moves when swapping WCS without a tool change in between + if (!isFirstSection() && newWorkOffset && !insertToolCall) { + var finalPositionPrevious = getPreviousSection().getFinalPosition() + var xfinalPositionPrevious = finalPositionPrevious.getCoordinate(0); + var yfinalPositionPrevious = finalPositionPrevious.getCoordinate(1); + machineSimulation({x: xfinalPositionPrevious, y: yfinalPositionPrevious, mode:TOOLCHANGE}) // kc to sort this is now not needed sometimes + } + + setCoolant(tool.coolant); // writes the required coolant codes + + setSmoothing(smoothing.isAllowed); // writes the required smoothing codes + + // prepositioning + var initialPosition = getFramePosition(currentSection.getInitialPosition()); + var isRequired = insertToolCall || state.retractedZ || !state.lengthCompensationActive || (!isFirstSection() && getPreviousSection().isMultiAxis()); + writeInitialPositioning(initialPosition, isRequired); + + if (subprogramsAreSupported()) { + subprogramDefine(initialPosition, abc); // define subprogram + } + state.retractedZ = false; + if(debugByCarnie >= 1 && debugByCarnie <= 2){writeComment("onSection---------^")}; // go to line 55 to set debug level +} + +function onDwell(seconds) { + if (seconds > 99999.999) { + warning(localize("Dwelling time is out of range.")); + } + milliseconds = clamp(1, seconds * 1000, 99999999); + writeBlock(gFeedModeModal.format(94), gFormat.format(4), "P" + milliFormat.format(milliseconds)); + writeBlock(gFeedModeModal.format(getProperty("useG95") ? 95 : 94)); // back to G95 +} + +function onSpindleSpeed(spindleSpeed) { + writeBlock(sOutput.format(spindleSpeed)); +} + +function onCycle() { + writeBlock(gPlaneModal.format(17)); +} + +function onCyclePoint(x, y, z) { + if (isInspectionOperation()) { + if (typeof inspectionCycleInspect == "function") { + inspectionCycleInspect(cycle, x, y, z); + return; + } else { + cycleNotSupported(); + } + } else if (isProbeOperation()) { + writeProbeCycle(cycle, x, y, z); + } else { + properties.useRigidTapping = {current:"no"}; // TAG: required to include common Fanuc cycles + writeDrillCycle(cycle, x, y, z); + } +} + +function onCycleEnd() { + if (subprogramsAreSupported() && subprogramState.cycleSubprogramIsActive) { + subprogramEnd(); + } + if (!cycleExpanded) { + writeBlock(gFeedModeModal.format(getProperty("useG95") ? 95 : 94), gCycleModal.format(80)); + zOutput.reset(); + } +} + +var mapCommand = { + COMMAND_END : 2, + COMMAND_SPINDLE_CLOCKWISE : 3, + COMMAND_SPINDLE_COUNTERCLOCKWISE: 4, + COMMAND_STOP_SPINDLE : 5, + COMMAND_ORIENTATE_SPINDLE : 19 +}; + +function onCommand(command) { + switch (command) { + case COMMAND_COOLANT_OFF: + setCoolant(COOLANT_OFF); + return; + case COMMAND_COOLANT_ON: + setCoolant(tool.coolant); + return; + case COMMAND_STOP: + writeBlock(mFormat.format(0)); + forceSpindleSpeed = true; + forceCoolant = true; + return; + case COMMAND_OPTIONAL_STOP: + writeBlock(mFormat.format(1)); + forceSpindleSpeed = true; + forceCoolant = true; + return; + case COMMAND_START_SPINDLE: + forceSpindleSpeed = false; + writeBlock(sOutput.format(spindleSpeed), mFormat.format(tool.clockwise ? 3 : 4)); + return; + case COMMAND_LOAD_TOOL: + writeToolBlock("T" + toolFormat.format(tool.number), mFormat.format(6)); + writeComment(tool.comment); + + //var preloadTool = getNextTool(tool.number != getFirstTool().number); // preload tools not supported on umbrella changer machines + //if (getProperty("preloadTool") && preloadTool) { + // writeBlock("T" + toolFormat.format(preloadTool.number)); // preload next/first tool + //} + return; + case COMMAND_LOCK_MULTI_AXIS: + var outputClampCodes = getProperty("useClampCodes") || currentSection.isMultiAxis(); + if (outputClampCodes && machineConfiguration.isMultiAxisConfiguration()) { + writeBlock(fourthAxisClamp.format(10), conditional(machineConfiguration.getNumberOfAxes() > 4, fifthAxisClamp.format(110))); // lock 4th + 5th axis + } + return; + case COMMAND_UNLOCK_MULTI_AXIS: + var outputClampCodes = getProperty("useClampCodes") || currentSection.isMultiAxis(); + if (outputClampCodes && machineConfiguration.isMultiAxisConfiguration()) { + writeBlock(fourthAxisClamp.format(11), conditional(machineConfiguration.getNumberOfAxes() > 4, fifthAxisClamp.format(111))); // unlock 4th + 5th axis + } + return; + case COMMAND_START_CHIP_TRANSPORT: + return; + case COMMAND_STOP_CHIP_TRANSPORT: + return; + case COMMAND_BREAK_CONTROL: + writeBlock(mFormat.format(106) + " T" + toolFormat.format(tool.number)+ " D" + xyzFormat.format(tool.diameter) + " E"+ getProperty("_0breakControlError")); + machineSimulation({x:toPreciseUnit(getProperty("_2TCposX"), MM), y:toPreciseUnit(getProperty("_2TCposY"), MM), coordinates:MACHINE, mode:TOOLCHANGE }); // Machine Simulation to the tool change position + return; + case COMMAND_TOOL_MEASURE: + return; + case COMMAND_PROBE_ON: + writeBlock(mFormat.format(getProperty("probeOnMCode"))); // Spin the probe on + return; + case COMMAND_PROBE_OFF: + writeBlock(mFormat.format(getProperty("probeOffMCode"))); // Spin the probe off + writeBlock(mFormat.format(19)) // Turn probe to the front for faster removal + writeBlock(mFormat.format(20)) // unlock spindle orintation + return; + } + + var stringId = getCommandStringId(command); + var mcode = mapCommand[stringId]; + if (mcode != undefined) { + writeBlock(mFormat.format(mcode)); + } else { + onUnsupportedCommand(command); + } +} + +function onSectionEnd() { + if(debugByCarnie >= 1 && debugByCarnie <= 2){writeComment("onSectionEnd---v")}; // go to line 55 to set debug level + + var nextSection = getNextSection(); + //---- reworked onSectionEnd below --v + var forceSectionRestartNext = currentSection.isOptional() && !nextSection.isOptional(); + optionalSection = forceSectionRestartNext && !getNextSection().isOptional || forceSectionRestartNext ? false : optionalSection ; + var insertToolCallNext = isLastSection() || isToolChangeNeeded(nextSection,"number","description") || forceSectionRestartNext; + var newWorkOffsetNext = isLastSection() || isNewWorkOffset(nextSection) || forceSectionRestartNext; + var newWorkPlaneNext = isLastSection() || isNewWorkPlane(nextSection) || forceSectionRestartNext; + operationNeedsSafeStart = getProperty("safeStartAllOperations") && !isFirstSection(); + + if (currentSection.isMultiAxis()) { + writeBlock(gFeedModeModal.format(getProperty("useG95") ? 95 : 94)); // inverse time feed off + } + writeBlock(gPlaneModal.format(17)); + + // Spin off probe + if (isProbeOperation()) { + if (isLastSection() || getNextSection().getTool().type != TOOL_PROBE && getProperty("_1spinOnProbe")) { + onCommand(COMMAND_PROBE_OFF) + } + /*if (probeVariables.probeAngleMethod != "G68") { + setProbeAngle(); // Output probe angle rotations if required (may not be required as pulled from old post) + }*/ + } + + if (!isLastSection()) { + if (nextSection.getTool().coolant != tool.coolant) { + setCoolant(COOLANT_OFF); + } + if (tool.breakControl && isToolChangeNeeded(nextSection, getProperty("toolAsName") ? "description" : "number")) { + setCoolant(COOLANT_OFF); + onCommand(COMMAND_STOP_SPINDLE); + writeRetract(Z); + if (getSetting("retract.homeXY.onToolChange", false)) { + writeRetract(settings.retract.homeXY.onToolChange); // KC needs switch to turn off + } + machineSimulation({x:toPreciseUnit(getProperty("_2TCposX"), MM), y:toPreciseUnit(getProperty("_2TCposY"), MM), coordinates:MACHINE}); // simulate manual tool change position + onCommand(COMMAND_BREAK_CONTROL); + } + //Unload manual tool and replace with pocket placeholder or chip fan + if (tool.manualToolChange && isToolChangeNeeded(nextSection, getProperty("toolAsName") ? "description" : "number")) { + setCoolant(COOLANT_OFF); + onCommand(COMMAND_STOP_SPINDLE); + writeRetract(Z); + if (getProperty("_3forceManualTCPosition")) { + forceModals(gMotionModal); + writeBlock(gAbsIncModal.format(90), gFormat.format(53), gMotionModal.format(0), xOutput.format(getProperty("_4manual_TCposX")), yOutput.format(getProperty("_4manual_TCposY"))); + machineSimulation({x:toPreciseUnit(getProperty("_4manual_TCposX"), MM), y:toPreciseUnit(getProperty("_4manual_TCposY"), MM), coordinates:MACHINE}); // , mode:TOOLCHANGE move machineSimulation to a tool change position + } else { + if (getSetting("retract.homeXY.onToolChange", false)) { + writeRetract(settings.retract.homeXY.onToolChange); + } + } + onCommand(COMMAND_STOP); + writeComment("Flip to manual, remove T" + tool.number + " and replace with pocket placeholder"); // wording for use with LOADTOOL macro : T" + tool.number + " then cycle start to resume" ); + } + } + + if (subprogramsAreSupported()) { + subprogramEnd(); + } + + forceAny(); + + operationNeedsSafeStart = false; // reset for next section + + //------------ onSection() setup below: + initializeSmoothing(); // initialize smoothing mode + + if (insertToolCallNext || newWorkOffsetNext || newWorkPlaneNext || smoothing.cancel || state.tcpIsActive) { + + // stop spindle before retract during tool change + if (insertToolCallNext && !isLastSection()) { + onCommand(COMMAND_STOP_SPINDLE); + } + disableLengthCompensation(); + if (getSetting("workPlaneMethod.cancelTiltFirst", false)) { + cancelWorkPlane(); + } + // Retracts between opperations added to this section + if (!getProperty("retractToClearancePlane") || insertToolCallNext || newWorkOffsetNext){ + writeRetract(Z); + if (newWorkOffsetNext && !insertToolCallNext) { + } + } + if (isFirstSection() && machineConfiguration.isMultiAxisConfiguration()) { + setWorkPlane(new Vector(0, 0, 0)); // reset working plane + forceABC(); + } + forceXYZ(); + + if (insertToolCallNext || smoothing.cancel || state.tcpIsActive) { + disableLengthCompensation(); + if (smoothing.cancel || insertToolCallNext) { + setSmoothing(false); + } + } + } + if(debugByCarnie >= 1 && debugByCarnie <= 2){writeComment("onSectionEnd---^")}; // go to line 55 to set debug level +} + +// Start of onRewindMachine logic +/** Allow user to override the onRewind logic. */ +function onRewindMachineEntry(_a, _b, _c) { + return false; +} + +/** Retract to safe position before indexing rotaries. */ +function onMoveToSafeRetractPosition() { + writeRetract(Z); + // cancel TCP so that tool doesn't follow rotaries + if (currentSection.isMultiAxis() && tcp.isSupportedByOperation) { + disableLengthCompensation(false, "TCPC OFF"); + } +} + +/** Rotate axes to new position above reentry position */ +function onRotateAxes(_x, _y, _z, _a, _b, _c) { + // position rotary axes + xOutput.disable(); + yOutput.disable(); + zOutput.disable(); + onRapid5D(_x, _y, _z, _a, _b, _c); + setCurrentABC(new Vector(_a, _b, _c)); + machineSimulation({a:_a, b:_b, c:_c, coordinates:MACHINE}); + xOutput.enable(); + yOutput.enable(); + zOutput.enable(); +} + +/** Return from safe position after indexing rotaries. */ +function onReturnFromSafeRetractPosition(_x, _y, _z) { + // reinstate TCP / tool length compensation + if (!state.lengthCompensationActive) { + writeBlock(getOffsetCode(), hFormat.format(tool.lengthOffset)); + } + + // position in XY + forceXYZ(); + xOutput.reset(); + yOutput.reset(); + zOutput.disable(); + if (highFeedMapping != HIGH_FEED_NO_MAPPING) { + onLinear(_x, _y, _z, highFeedrate); + } else { + onRapid(_x, _y, _z); + } + machineSimulation({x:_x, y:_y}); + // position in Z + zOutput.enable(); + invokeOnRapid(_x, _y, _z); +} +// End of onRewindMachine logic + +function onClose() { + if(debugByCarnie >= 1 && debugByCarnie <= 2){writeComment("onClose---------v")}; // go to line 55 to set debug level + optionalSection = false; + writeln(""); + onCommand(COMMAND_STOP_SPINDLE); + onCommand(COMMAND_COOLANT_OFF); + disableLengthCompensation(true); + cancelWorkPlane(); + writeRetract(Z); // retract + setSmoothing(false); + forceWorkPlane(); + setWorkPlane(new Vector(0, 0, 0)); // reset working plane + if (getSetting("retract.homeXY.onProgramEnd", false)) { + writeRetract(settings.retract.homeXY.onProgramEnd); + } + writeBlock(mFormat.format(30)); // program end + + if (subprogramsAreSupported()) { + writeSubprograms(); + } + writeln("%"); + writeBlock(getProperty("_2CustomOnCloseGcode")); + if(debugByCarnie >= 1 && debugByCarnie <= 2){writeComment("onClose---------^")}; // go to line 55 to set debug level +} + +// >>>>> INCLUDED FROM include_files/commonFunctions.cpi +// internal variables, do not change +var receivedMachineConfiguration; +var tcp = {isSupportedByControl:getSetting("supportsTCP", true), isSupportedByMachine:false, isSupportedByOperation:false}; +var state = { + retractedX : false, // specifies that the machine has been retracted in X + retractedY : false, // specifies that the machine has been retracted in Y + retractedZ : false, // specifies that the machine has been retracted in Z + tcpIsActive : false, // specifies that TCP is currently active + twpIsActive : false, // specifies that TWP is currently active + lengthCompensationActive: !getSetting("outputToolLengthCompensation", true), // specifies that tool length compensation is active + mainState : true // specifies the current context of the state (true = main, false = optional) +}; +var validateLengthCompensation = getSetting("outputToolLengthCompensation", true); // disable validation when outputToolLengthCompensation is disabled +var multiAxisFeedrate; +var sequenceNumber; +var optionalSection = false; +var currentWorkOffset; +var forceSpindleSpeed = false; +var operationNeedsSafeStart = false; // used to convert blocks to optional for safeStartAllOperations + +function activateMachine() { + // disable unsupported rotary axes output + if (!machineConfiguration.isMachineCoordinate(0) && (typeof aOutput != "undefined")) { + aOutput.disable(); + } + if (!machineConfiguration.isMachineCoordinate(1) && (typeof bOutput != "undefined")) { + bOutput.disable(); + } + if (!machineConfiguration.isMachineCoordinate(2) && (typeof cOutput != "undefined")) { + cOutput.disable(); + } + + // setup usage of useTiltedWorkplane + settings.workPlaneMethod.useTiltedWorkplane = getProperty("useTiltedWorkplane") != undefined ? getProperty("useTiltedWorkplane") : + getSetting("workPlaneMethod.useTiltedWorkplane", false); + settings.workPlaneMethod.useABCPrepositioning = getSetting("workPlaneMethod.useABCPrepositioning", true); + + if (!machineConfiguration.isMultiAxisConfiguration()) { + return; // don't need to modify any settings for 3-axis machines + } + + // identify if any of the rotary axes has TCP enabled + var axes = [machineConfiguration.getAxisU(), machineConfiguration.getAxisV(), machineConfiguration.getAxisW()]; + tcp.isSupportedByMachine = axes.some(function(axis) {return axis.isEnabled() && axis.isTCPEnabled();}); // true if TCP is enabled on any rotary axis + + // save multi-axis feedrate settings from machine configuration + var mode = machineConfiguration.getMultiAxisFeedrateMode(); + var type = mode == FEED_INVERSE_TIME ? machineConfiguration.getMultiAxisFeedrateInverseTimeUnits() : + (mode == FEED_DPM ? machineConfiguration.getMultiAxisFeedrateDPMType() : DPM_STANDARD); + multiAxisFeedrate = { + mode : mode, + maximum : machineConfiguration.getMultiAxisFeedrateMaximum(), + type : type, + tolerance: mode == FEED_DPM ? machineConfiguration.getMultiAxisFeedrateOutputTolerance() : 0, + bpwRatio : mode == FEED_DPM ? machineConfiguration.getMultiAxisFeedrateBpwRatio() : 1 + }; + + // setup of retract/reconfigure TAG: Only needed until post kernel supports these machine config settings + if (receivedMachineConfiguration && machineConfiguration.performRewinds()) { + safeRetractDistance = machineConfiguration.getSafeRetractDistance(); + safePlungeFeed = machineConfiguration.getSafePlungeFeedrate(); + safeRetractFeed = machineConfiguration.getSafeRetractFeedrate(); + } + if (typeof safeRetractDistance == "number" && getProperty("safeRetractDistance") != undefined && getProperty("safeRetractDistance") != 0) { + safeRetractDistance = getProperty("safeRetractDistance"); + } + + if (machineConfiguration.isHeadConfiguration() && getSetting("workPlaneMethod.compensateToolLength", false)) { + for (var i = 0; i < getNumberOfSections(); ++i) { + var section = getSection(i); + if (section.isMultiAxis()) { + machineConfiguration.setToolLength(getBodyLength(section.getTool())); // define the tool length for head adjustments + section.optimizeMachineAnglesByMachine(machineConfiguration, OPTIMIZE_AXIS); + } + } + } else { + optimizeMachineAngles2(OPTIMIZE_AXIS); + } +} + +function getBodyLength(tool) { + for (var i = 0; i < getNumberOfSections(); ++i) { + var section = getSection(i); + if (tool.number == section.getTool().number) { + if (section.hasParameter("operation:tool_assemblyGaugeLength")) { // For Fusion + return tool.bodyLength + tool.holderLength; + } else { // Legacy products + return section.getParameter("operation:tool_overallLength", tool.bodyLength + tool.holderLength); + } + } + } + return tool.bodyLength + tool.holderLength; +} + +function getFeed(f) { + if (getProperty("useG95")) { + return feedOutput.format(f / spindleSpeed); // use feed value + } + if (typeof activeMovements != "undefined" && activeMovements) { + var feedContext = activeMovements[movement]; + if (feedContext != undefined) { + if (!feedFormat.areDifferent(feedContext.feed, f)) { + if (feedContext.id == currentFeedId) { + return ""; // nothing has changed + } + forceFeed(); + currentFeedId = feedContext.id; + return settings.parametricFeeds.feedOutputVariable + (settings.parametricFeeds.firstFeedParameter + feedContext.id); + } + } + currentFeedId = undefined; // force parametric feed next time + } + return feedOutput.format(f); // use feed value +} + +function validateCommonParameters() { + validateToolData(); + for (var i = 0; i < getNumberOfSections(); ++i) { + var section = getSection(i); + if (getSection(0).workOffset == 0 && section.workOffset > 0) { + if (!(typeof wcsDefinitions != "undefined" && wcsDefinitions.useZeroOffset)) { + error(localize("Using multiple work offsets is not possible if the initial work offset is 0.")); + } + } + if (section.isMultiAxis()) { + if (!section.isOptimizedForMachine() && + (!getSetting("workPlaneMethod.useTiltedWorkplane", false) || !getSetting("supportsToolVectorOutput", false))) { + error(localize("This postprocessor requires a machine configuration for 5-axis simultaneous toolpath.")); + } + if (machineConfiguration.getMultiAxisFeedrateMode() == FEED_INVERSE_TIME && !getSetting("supportsInverseTimeFeed", true)) { + error(localize("This postprocessor does not support inverse time feedrates.")); + } + if (getSetting("supportsToolVectorOutput", false) && !tcp.isSupportedByControl) { + error(localize("Incompatible postprocessor settings detected." + EOL + + "Setting 'supportsToolVectorOutput' requires setting 'supportsTCP' to be enabled as well.")); + } + } + } + if (!tcp.isSupportedByControl && tcp.isSupportedByMachine) { + error(localize("The machine configuration has TCP enabled which is not supported by this postprocessor.")); + } +/* if (getProperty("retractToClearancePlane")) { + var msg = "-Attention- Property 'Safe Retracts' is set to 'Clearance Height'." + EOL + + "Ensure the clearance height will clear the part and or fixtures." + EOL + + "Raise the Z-axis to a safe height before starting the program."; + warning(msg); + writeComment(msg); + } */ +} + +function validateToolData() { + var _default = 99999; + var _maximumSpindleRPM = machineConfiguration.getMaximumSpindleSpeed() > 0 ? machineConfiguration.getMaximumSpindleSpeed() : + settings.maximumSpindleRPM == undefined ? _default : settings.maximumSpindleRPM; + var _maximumToolNumber = machineConfiguration.isReceived() && machineConfiguration.getNumberOfTools() > 0 ? machineConfiguration.getNumberOfTools() : + settings.maximumToolNumber == undefined ? _default : settings.maximumToolNumber; + var _maximumToolLengthOffset = settings.maximumToolLengthOffset == undefined ? _default : settings.maximumToolLengthOffset; + var _maximumToolDiameterOffset = settings.maximumToolDiameterOffset == undefined ? _default : settings.maximumToolDiameterOffset; + + var header = ["Detected maximum values are out of range.", "Maximum values:"]; + var warnings = { + toolNumber : {msg:"Tool number value exceeds the maximum value for tool: " + EOL, max:" Tool number: " + _maximumToolNumber, values:[]}, + lengthOffset : {msg:"Tool length offset value exceeds the maximum value for tool: " + EOL, max:" Tool length offset: " + _maximumToolLengthOffset, values:[]}, + diameterOffset: {msg:"Tool diameter offset value exceeds the maximum value for tool: " + EOL, max:" Tool diameter offset: " + _maximumToolDiameterOffset, values:[]}, + spindleSpeed : {msg:"Spindle speed exceeds the maximum value for operation: " + EOL, max:" Spindle speed: " + _maximumSpindleRPM, values:[]} + }; + + var toolIds = []; + for (var i = 0; i < getNumberOfSections(); ++i) { + var section = getSection(i); + if (toolIds.indexOf(section.getTool().getToolId()) === -1) { // loops only through sections which have a different tool ID + var toolNumber = section.getTool().number; + var lengthOffset = section.getTool().lengthOffset; + var diameterOffset = section.getTool().diameterOffset; + var comment = section.getParameter("operation-comment", ""); + + if (toolNumber > _maximumToolNumber && !getProperty("toolAsName")) { + warnings.toolNumber.values.push(SP + toolNumber + EOL); + } + if (lengthOffset > _maximumToolLengthOffset) { + warnings.lengthOffset.values.push(SP + "Tool " + toolNumber + " (" + comment + "," + " Length offset: " + lengthOffset + ")" + EOL); + } + if (diameterOffset > _maximumToolDiameterOffset) { + warnings.diameterOffset.values.push(SP + "Tool " + toolNumber + " (" + comment + "," + " Diameter offset: " + diameterOffset + ")" + EOL); + } + toolIds.push(section.getTool().getToolId()); + } + // loop through all sections regardless of tool id for idenitfying spindle speeds + + // identify if movement ramp is used in current toolpath, use ramp spindle speed for comparisons + var ramp = section.getMovements() & ((1 << MOVEMENT_RAMP) | (1 << MOVEMENT_RAMP_ZIG_ZAG) | (1 << MOVEMENT_RAMP_PROFILE) | (1 << MOVEMENT_RAMP_HELIX)); + var _sectionSpindleSpeed = Math.max(section.getTool().spindleRPM, ramp ? section.getTool().rampingSpindleRPM : 0, 0); + if (_sectionSpindleSpeed > _maximumSpindleRPM) { + warnings.spindleSpeed.values.push(SP + section.getParameter("operation-comment", "") + " (" + _sectionSpindleSpeed + " RPM" + ")" + EOL); + } + } + + // sort lists by tool number + warnings.toolNumber.values.sort(function(a, b) {return a - b;}); + warnings.lengthOffset.values.sort(function(a, b) {return a.localeCompare(b);}); + warnings.diameterOffset.values.sort(function(a, b) {return a.localeCompare(b);}); + + var warningMessages = []; + for (var key in warnings) { + if (warnings[key].values != "") { + header.push(warnings[key].max); // add affected max values to the header + warningMessages.push(warnings[key].msg + warnings[key].values.join("")); + } + } + if (warningMessages.length != 0) { + warningMessages.unshift(header.join(EOL) + EOL); + warning(warningMessages.join(EOL)); + } +} + +function forceFeed() { + currentFeedId = undefined; + feedOutput.reset(); +} + +/** Force output of X, Y, and Z. */ +function forceXYZ() { + xOutput.reset(); + yOutput.reset(); + zOutput.reset(); +} + +/** Force output of A, B, and C. */ +function forceABC() { + aOutput.reset(); + bOutput.reset(); + cOutput.reset(); +} + +/** Force output of X, Y, Z, A, B, C, and F on next output. */ +function forceAny() { + forceXYZ(); + forceABC(); + forceFeed(); +} + +/** + Writes the specified block. +*/ +function writeBlock() { + var text = formatWords(arguments); + if (!text) { + return; + } + var prefix = getSetting("sequenceNumberPrefix", "N"); + var suffix = getSetting("writeBlockSuffix", ""); + if ((optionalSection || skipBlocks) && !getSetting("supportsOptionalBlocks", true)) { + error(localize("Optional blocks are not supported by this post.")); + } + if (getProperty("showSequenceNumbers") == "true") { + if (sequenceNumber == undefined || sequenceNumber >= settings.maximumSequenceNumber) { + sequenceNumber = getProperty("sequenceNumberStart"); + } + if (optionalSection || skipBlocks) { + writeWords2("/", prefix + sequenceNumber, text + suffix); + } else { + writeWords2(prefix + sequenceNumber, text + suffix); + } + sequenceNumber += getProperty("sequenceNumberIncrement"); + } else { + if (optionalSection || skipBlocks) { + writeWords2("/", text + suffix); + } else { + writeWords(text + suffix); + } + } +} + +validate(settings.comments, "Setting 'comments' is required but not defined."); +function formatComment(text) { + var prefix = settings.comments.prefix; + var suffix = settings.comments.suffix; + var _permittedCommentChars = settings.comments.permittedCommentChars == undefined ? "" : settings.comments.permittedCommentChars; + switch (settings.comments.outputFormat) { + case "upperCase": + text = text.toUpperCase(); + _permittedCommentChars = _permittedCommentChars.toUpperCase(); + break; + case "lowerCase": + text = text.toLowerCase(); + _permittedCommentChars = _permittedCommentChars.toLowerCase(); + break; + case "ignoreCase": + _permittedCommentChars = _permittedCommentChars.toUpperCase() + _permittedCommentChars.toLowerCase(); + break; + default: + error(localize("Unsupported option specified for setting 'comments.outputFormat'.")); + } + if (_permittedCommentChars != "") { + text = filterText(String(text), _permittedCommentChars); + } + text = String(text).substring(0, settings.comments.maximumLineLength - prefix.length - suffix.length); + return text != "" ? prefix + text + suffix : ""; +} + +/** + Output a comment. +*/ +function writeComment(text) { + if (!text) { + return; + } + var comments = String(text).split(EOL); + for (comment in comments) { + var _comment = formatComment(comments[comment]); + if (_comment) { + if (getSetting("comments.showSequenceNumbers", false)) { + writeBlock(_comment); + } else { + writeln(_comment); + } + } + } +} + +function onComment(text) { + writeComment(text); +} + +/** + Writes the specified block - used for tool changes only. +*/ +function writeToolBlock() { + var show = getProperty("showSequenceNumbers"); + setProperty("showSequenceNumbers", (show == "true" || show == "toolChange") ? "true" : "false"); + writeBlock(arguments); + setProperty("showSequenceNumbers", show); + machineSimulation({x:toPreciseUnit(getProperty("_2TCposX"), MM), y:toPreciseUnit(getProperty("_2TCposY"), MM), coordinates:MACHINE, mode:TOOLCHANGE}); +} + +var skipBlocks = false; +var initialState = JSON.parse(JSON.stringify(state)); // save initial state +var optionalState = JSON.parse(JSON.stringify(state)); +var saveCurrentSectionId = undefined; +function writeStartBlocks(isRequired, code) { + var saveSkipBlocks = skipBlocks; + var saveMainState = state; // save main state + + if (!isRequired) { + if (!getProperty("safeStartAllOperations", false)) { + return; // when safeStartAllOperations is disabled, dont output code and return + } + if (saveCurrentSectionId != getCurrentSectionId()) { + saveCurrentSectionId = getCurrentSectionId(); + forceModals(); // force all modal variables when entering a new section + optionalState = Object.create(initialState); // reset optionalState to initialState when entering a new section + } + skipBlocks = true; // if values are not required, but safeStartAllOperations is enabled - write following blocks as optional + state = optionalState; // set state to optionalState if skipBlocks is true + state.mainState = false; + } + code(); // writes out the code which is passed to this function as an argument + + state = saveMainState; // restore main state + skipBlocks = saveSkipBlocks; // restore skipBlocks value +} + +var pendingRadiusCompensation = -1; +function onRadiusCompensation() { + pendingRadiusCompensation = radiusCompensation; + if (pendingRadiusCompensation >= 0 && !getSetting("supportsRadiusCompensation", true)) { + error(localize("Radius compensation mode is not supported.")); + return; + } +} + +function onPassThrough(text) { + var commands = String(text).split(","); + for (text in commands) { + writeBlock(commands[text]); + } +} + +function forceModals() { + if (arguments.length == 0) { // reset all modal variables listed below + if (typeof gMotionModal != "undefined") { + gMotionModal.reset(); + } + if (typeof gPlaneModal != "undefined") { + gPlaneModal.reset(); + } + if (typeof gAbsIncModal != "undefined") { + gAbsIncModal.reset(); + } + if (typeof gFeedModeModal != "undefined") { + gFeedModeModal.reset(); + } + } else { + for (var i in arguments) { + arguments[i].reset(); // only reset the modal variable passed to this function + } + } +} + +/** Helper function to be able to use a default value for settings which do not exist. */ +function getSetting(setting, defaultValue) { + var result = defaultValue; + var keys = setting.split("."); + var obj = settings; + for (var i in keys) { + if (obj[keys[i]] != undefined) { // setting does exist + result = obj[keys[i]]; + if (typeof [keys[i]] === "object") { + obj = obj[keys[i]]; + continue; + } + } else { // setting does not exist, use default value + if (defaultValue != undefined) { + result = defaultValue; + } else { + error("Setting '" + keys[i] + "' has no default value and/or does not exist."); + return undefined; + } + } + } + return result; +} + +function getForwardDirection(_section) { + var forward = undefined; + var _optimizeType = settings.workPlaneMethod && settings.workPlaneMethod.optimizeType; + if (_section.isMultiAxis()) { + forward = _section.workPlane.forward; + } else if (!getSetting("workPlaneMethod.useTiltedWorkplane", false) && machineConfiguration.isMultiAxisConfiguration()) { + if (_optimizeType == undefined) { + var saveRotation = getRotation(); + getWorkPlaneMachineABC(_section, true); + forward = getRotation().forward; + setRotation(saveRotation); // reset rotation + } else { + var abc = getWorkPlaneMachineABC(_section, false); + var forceAdjustment = settings.workPlaneMethod.optimizeType == OPTIMIZE_TABLES || settings.workPlaneMethod.optimizeType == OPTIMIZE_BOTH; + forward = machineConfiguration.getOptimizedDirection(_section.workPlane.forward, abc, false, forceAdjustment); + } + } else { + forward = getRotation().forward; + } + return forward; +} + +function getRetractParameters() { + var _arguments = typeof arguments[0] === "object" ? arguments[0].axes : arguments; + var singleLine = arguments[0].singleLine == undefined ? true : arguments[0].singleLine; + var words = []; // store all retracted axes in an array + var retractAxes = new Array(false, false, false); + var method = getProperty("safePositionMethod", "undefined"); + /*if (method == "clearanceHeight") { + if (!is3D()) { + error(localize("Safe retract option 'Clearance Height' is only supported when all operations are along the setup Z-axis.")); + } + return undefined; + }*/ + validate(settings.retract, "Setting 'retract' is required but not defined."); + validate(_arguments.length != 0, "No axis specified for getRetractParameters()."); + for (i in _arguments) { + retractAxes[_arguments[i]] = true; + } + if ((retractAxes[0] || retractAxes[1]) && !state.retractedZ) { // retract Z first before moving to X/Y home + error(localize("Retracting in X/Y is not possible without being retracted in Z.")); + return undefined; + } + // special conditions + if (retractAxes[0] || retractAxes[1]) { + method = getSetting("retract.methodXY", method); + } + if (retractAxes[2]) { + method = getSetting("retract.methodZ", method); + } + // define home positions + var useZeroValues = (settings.retract.useZeroValues && settings.retract.useZeroValues.indexOf(method) != -1); + var _xHome = machineConfiguration.hasHomePositionX() && !useZeroValues ? machineConfiguration.getHomePositionX() : toPreciseUnit(0, MM); + var _yHome = machineConfiguration.hasHomePositionY() && !useZeroValues ? machineConfiguration.getHomePositionY() : toPreciseUnit(0, MM); + var _zHome = machineConfiguration.getRetractPlane() != 0 && !useZeroValues ? machineConfiguration.getRetractPlane() : toPreciseUnit(0, MM); + for (var i = 0; i < _arguments.length; ++i) { + switch (_arguments[i]) { + case X: + if (!state.retractedX) { + words.push("X" + xyzFormat.format(_xHome)); + xOutput.reset(); + state.retractedX = true; + } + break; + case Y: + if (!state.retractedY) { + words.push("Y" + xyzFormat.format(_yHome)); + yOutput.reset(); + state.retractedY = true; + } + break; + case Z: + if (!state.retractedZ) { + words.push("Z" + xyzFormat.format(_zHome)); + zOutput.reset(); + state.retractedZ = true; + } + break; + default: + error(localize("Unsupported axis specified for getRetractParameters().")); + return undefined; + } + } + return { + method : method, + retractAxes: retractAxes, + words : words, + positions : { + x: retractAxes[0] ? _xHome : undefined, + y: retractAxes[1] ? _yHome : undefined, + z: retractAxes[2] ? _zHome : undefined}, + singleLine: singleLine}; +} + +/** Returns true when subprogram logic does exist into the post. */ +function subprogramsAreSupported() { + return typeof subprogramState != "undefined"; +} + +// Start of machine simulation connection move support +var debugSimulation = debugByCarnie >= 2 && debugByCarnie <= 3 ? true : false; // enable to output debug information for connection move support in the NC program +var TCPON = "TCP ON"; +var TCPOFF = "TCP OFF"; +var TWPON = "TWP ON"; +var TWPOFF = "TWP OFF"; +var TOOLCHANGE = "TOOL CHANGE"; +var RETRACTTOOLAXIS = "RETRACT TOOLAXIS"; +var WORK = "WORK CS"; +var MACHINE = "MACHINE CS"; +var MIN = "MIN"; +var MAX = "MAX"; +var WARNING_NON_RANGE = [0, 1, 2]; +var isTwpOn; // only used for debugging +var isTcpOn; // only used for debugging +/** + * Helper function for connection moves in machine simulation. + * @param {Object} parameters An object containing the desired options for machine simulation. + * @note Available properties are: + * @param {Number} x X axis position, alternatively use MIN or MAX to move to the axis limit + * @param {Number} y Y axis position, alternatively use MIN or MAX to move to the axis limit + * @param {Number} z Z axis position, alternatively use MIN or MAX to move to the axis limit + * @param {Number} a A axis position (in radians) + * @param {Number} b B axis position (in radians) + * @param {Number} c C axis position (in radians) + * @param {Number} feed desired feedrate, automatically set to high/current feedrate if not specified + * @param {String} mode mode TCPON | TCPOFF | TWPON | TWPOFF | TOOLCHANGE | RETRACTTOOLAXIS + * @param {String} coordinates WORK | MACHINE - if undefined, work coordinates will be used by default + * @param {Number} eulerAngles the calculated Euler angles for the workplane + * @example + machineSimulation({a:abc.x, b:abc.y, c:abc.z, coordinates:MACHINE}); + machineSimulation({x:toPreciseUnit(200, MM), y:toPreciseUnit(200, MM), coordinates:MACHINE, mode:TOOLCHANGE}); +*/ +function machineSimulation(parameters) { + if (revision < 50075 || skipBlocks) { + return; // return when post kernel revision is lower than 50075 or when skipBlocks is enabled + } + getAxisLimit = function(axis, limit) { + validate(limit == MIN || limit == MAX, subst(localize("Invalid argument \"%1\" passed to the machineSimulation function."), limit)); + var range = axis.getRange(); + if (range.isNonRange()) { + var axisLetters = ["X", "Y", "Z"]; + var warningMessage = subst(localize("An attempt was made to move the \"%1\" axis to its MIN/MAX limits during machine simulation, but its range is set to \"unlimited\"." + EOL + + "A limited range must be set for the \"%1\" axis in the machine definition, or these motions will not be shown in machine simulation."), axisLetters[axis.getCoordinate()]); + warningOnce(warningMessage, WARNING_NON_RANGE[axis.getCoordinate()]); + return undefined; + } + return limit == MIN ? range.minimum : range.maximum; + }; + var x = (isNaN(parameters.x) && parameters.x) ? getAxisLimit(machineConfiguration.getAxisX(), parameters.x) : parameters.x; + var y = (isNaN(parameters.y) && parameters.y) ? getAxisLimit(machineConfiguration.getAxisY(), parameters.y) : parameters.y; + var z = (isNaN(parameters.z) && parameters.z) ? getAxisLimit(machineConfiguration.getAxisZ(), parameters.z) : parameters.z; + var rotaryAxesErrorMessage = localize("Invalid argument for rotary axes passed to the machineSimulation function. Only numerical values are supported."); + var a = (isNaN(parameters.a) && parameters.a) ? error(rotaryAxesErrorMessage) : parameters.a; + var b = (isNaN(parameters.b) && parameters.b) ? error(rotaryAxesErrorMessage) : parameters.b; + var c = (isNaN(parameters.c) && parameters.c) ? error(rotaryAxesErrorMessage) : parameters.c; + var coordinates = parameters.coordinates; + var eulerAngles = parameters.eulerAngles; + var feed = parameters.feed; + if (feed === undefined && typeof gMotionModal !== "undefined") { + feed = gMotionModal.getCurrent() !== 0; + } + var mode = parameters.mode; + var performToolChange = mode == TOOLCHANGE; + if (mode !== undefined && ![TCPON, TCPOFF, TWPON, TWPOFF, TOOLCHANGE, RETRACTTOOLAXIS].includes(mode)) { + error(subst("Mode '%1' is not supported.", mode)); + } + + // mode takes precedence over TCP/TWP states + var enableTCP = false; + var enableTWP = false; + if (mode === TCPON) { + enableTCP = true; + } else if (mode === TCPOFF) { + enableTWP = typeof state !== "undefined" && state.twpIsActive; + } else if (mode === TWPON) { + enableTWP = true; + } else if (mode === TWPOFF) { + enableTCP = typeof state !== "undefined" && state.tcpIsActive; + } else { + enableTCP = typeof state !== "undefined" && state.tcpIsActive; + enableTWP = typeof state !== "undefined" && state.twpIsActive; + } + var disableTCP = !enableTCP; + var disableTWP = !enableTWP; + // update TCP mode + if (enableTCP) { + simulation.setTCPModeOn(); + isTcpOn = true; + } + if (disableTCP) { + simulation.setTCPModeOff(); + isTcpOn = false; + } + // update TWP mode + if (enableTWP) { + if (settings.workPlaneMethod.eulerConvention == undefined) { + simulation.setTWPModeAlignToCurrentPose(); + } else if (eulerAngles) { + simulation.setTWPModeByEulerAngles(settings.workPlaneMethod.eulerConvention, eulerAngles.x, eulerAngles.y, eulerAngles.z); + } + isTwpOn = true; + } + if (disableTWP) { + simulation.setTWPModeOff(); + isTwpOn = false; + } + if (mode == RETRACTTOOLAXIS) { + simulation.retractAlongToolAxisToLimit(); + } + + if (debugSimulation) { + writeln(" DEBUG" + JSON.stringify(parameters)); + //writeln(" DEBUG" + JSON.stringify({isTwpOn:isTwpOn, isTcpOn:isTcpOn, feed:feed})); + } + + if (x !== undefined || y !== undefined || z !== undefined || a !== undefined || b !== undefined || c !== undefined) { + if (x !== undefined) {simulation.setTargetX(x);} + if (y !== undefined) {simulation.setTargetY(y);} + if (z !== undefined) {simulation.setTargetZ(z);} + if (a !== undefined) {simulation.setTargetA(a);} + if (b !== undefined) {simulation.setTargetB(b);} + if (c !== undefined) {simulation.setTargetC(c);} + + if (feed != undefined && feed) { + simulation.setMotionToLinear(); + simulation.setFeedrate(typeof feed == "number" ? feed : feedOutput.getCurrent() == 0 ? highFeedrate : feedOutput.getCurrent()); + } else { + simulation.setMotionToRapid(); + } + + if (coordinates != undefined && coordinates == MACHINE) { + simulation.moveToTargetInMachineCoords(); + } else { + simulation.moveToTargetInWorkCoords(); + } + } + if (performToolChange) { + simulation.performToolChangeCycle(); + simulation.moveToTargetInMachineCoords(); + } +} +// <<<<< INCLUDED FROM include_files/commonFunctions.cpi +// >>>>> INCLUDED FROM include_files/defineMachine.cpi +function defineMachine() { + var useTCP = true; + if (false) { // note: setup your machine here + var aAxis = createAxis({coordinate:0, table:true, axis:[1, 0, 0], range:[-120, 120], preference:1, tcp:useTCP}); + var cAxis = createAxis({coordinate:2, table:true, axis:[0, 0, 1], range:[-360, 360], preference:0, tcp:useTCP}); + machineConfiguration = new MachineConfiguration(aAxis, cAxis); + + setMachineConfiguration(machineConfiguration); + if (receivedMachineConfiguration) { + warning(localize("The provided CAM machine configuration is overwritten by the postprocessor.")); + receivedMachineConfiguration = false; // CAM provided machine configuration is overwritten + } + } + + if (!receivedMachineConfiguration) { + // multiaxis settings + if (machineConfiguration.isHeadConfiguration()) { + machineConfiguration.setVirtualTooltip(false); // translate the pivot point to the virtual tool tip for nonTCP rotary heads + } + + // retract / reconfigure + var performRewinds = false; // set to true to enable the rewind/reconfigure logic + if (performRewinds) { + machineConfiguration.enableMachineRewinds(); // enables the retract/reconfigure logic + safeRetractDistance = (unit == IN) ? 1 : 25; // additional distance to retract out of stock, can be overridden with a property + safeRetractFeed = (unit == IN) ? 20 : 500; // retract feed rate + safePlungeFeed = (unit == IN) ? 10 : 250; // plunge feed rate + machineConfiguration.setSafeRetractDistance(safeRetractDistance); + machineConfiguration.setSafeRetractFeedrate(safeRetractFeed); + machineConfiguration.setSafePlungeFeedrate(safePlungeFeed); + var stockExpansion = new Vector(toPreciseUnit(0.1, IN), toPreciseUnit(0.1, IN), toPreciseUnit(0.1, IN)); // expand stock XYZ values + machineConfiguration.setRewindStockExpansion(stockExpansion); + } + + // multi-axis feedrates + if (machineConfiguration.isMultiAxisConfiguration()) { + machineConfiguration.setMultiAxisFeedrate( + useTCP ? FEED_FPM : getProperty("useDPMFeeds") ? FEED_DPM : FEED_INVERSE_TIME, + 9999.99, // maximum output value for inverse time feed rates + getProperty("useDPMFeeds") ? DPM_COMBINATION : INVERSE_MINUTES, // INVERSE_MINUTES/INVERSE_SECONDS or DPM_COMBINATION/DPM_STANDARD + 0.5, // tolerance to determine when the DPM feed has changed + 1.0 // ratio of rotary accuracy to linear accuracy for DPM calculations + ); + setMachineConfiguration(machineConfiguration); + } + + /* home positions */ + // machineConfiguration.setHomePositionX(toPreciseUnit(0, IN)); + // machineConfiguration.setHomePositionY(toPreciseUnit(0, IN)); + // machineConfiguration.setRetractPlane(toPreciseUnit(0, IN)); + } +} +// <<<<< INCLUDED FROM include_files/defineMachine.cpi +// >>>>> INCLUDED FROM include_files/defineWorkPlane.cpi +validate(settings.workPlaneMethod, "Setting 'workPlaneMethod' is required but not defined."); +function defineWorkPlane(_section, _setWorkPlane) { + var abc = new Vector(0, 0, 0); + if (settings.workPlaneMethod.forceMultiAxisIndexing || !is3D() || machineConfiguration.isMultiAxisConfiguration()) { + if (isPolarModeActive()) { + abc = getCurrentDirection(); + } else if (_section.isMultiAxis()) { + forceWorkPlane(); + cancelTransformation(); + abc = _section.isOptimizedForMachine() ? _section.getInitialToolAxisABC() : _section.getGlobalInitialToolAxis(); + } else if (settings.workPlaneMethod.useTiltedWorkplane && settings.workPlaneMethod.eulerConvention != undefined) { + if (settings.workPlaneMethod.eulerCalculationMethod == "machine" && machineConfiguration.isMultiAxisConfiguration()) { + abc = machineConfiguration.getOrientation(getWorkPlaneMachineABC(_section, true)).getEuler2(settings.workPlaneMethod.eulerConvention); + } else { + abc = _section.workPlane.getEuler2(settings.workPlaneMethod.eulerConvention); + } + } else { + abc = getWorkPlaneMachineABC(_section, true); + } + + if (_setWorkPlane) { + if (_section.isMultiAxis() || isPolarModeActive()) { // 4-5x simultaneous operations + cancelWorkPlane(); + if (_section.isOptimizedForMachine()) { + positionABC(abc, true); + } else { + setCurrentDirection(abc); + } + } else { // 3x and/or 3+2x operations + setWorkPlane(abc); + } + } + } else { + var remaining = _section.workPlane; + if (!isSameDirection(remaining.forward, new Vector(0, 0, 1))) { + error(localize("Tool orientation is not supported.")); + return abc; + } + setRotation(remaining); + } + tcp.isSupportedByOperation = isTCPSupportedByOperation(_section); + return abc; +} + +function isTCPSupportedByOperation(_section) { + var _tcp = _section.getOptimizedTCPMode() == OPTIMIZE_NONE; + if (!_section.isMultiAxis() && (settings.workPlaneMethod.useTiltedWorkplane || + isSameDirection(machineConfiguration.getSpindleAxis(), getForwardDirection(_section)) || + settings.workPlaneMethod.optimizeType == OPTIMIZE_HEADS || + settings.workPlaneMethod.optimizeType == OPTIMIZE_TABLES || + settings.workPlaneMethod.optimizeType == OPTIMIZE_BOTH)) { + _tcp = false; + } + return _tcp; +} +// <<<<< INCLUDED FROM include_files/defineWorkPlane.cpi +// >>>>> INCLUDED FROM include_files/getWorkPlaneMachineABC.cpi +validate(settings.machineAngles, "Setting 'machineAngles' is required but not defined."); +function getWorkPlaneMachineABC(_section, rotate) { + var currentABC = isFirstSection() ? new Vector(0, 0, 0) : getCurrentABC(); + var abc = _section.getABCByPreference(machineConfiguration, _section.workPlane, currentABC, settings.machineAngles.controllingAxis, settings.machineAngles.type, settings.machineAngles.options); + if (!isSameDirection(machineConfiguration.getDirection(abc), _section.workPlane.forward)) { + error(localize("Orientation not supported.")); + } + if (rotate) { + if (settings.workPlaneMethod.optimizeType == undefined || settings.workPlaneMethod.useTiltedWorkplane) { // legacy + var useTCP = false; + var R = machineConfiguration.getRemainingOrientation(abc, _section.workPlane); + setRotation(useTCP ? _section.workPlane : R); + } else { + if (!_section.isOptimizedForMachine()) { + machineConfiguration.setToolLength(getSetting("workPlaneMethod.compensateToolLength", false) ? getBodyLength(_section.getTool()) : 0); // define the tool length for head adjustments + _section.optimize3DPositionsByMachine(machineConfiguration, abc, settings.workPlaneMethod.optimizeType); + } + } + } + return abc; +} +// <<<<< INCLUDED FROM include_files/getWorkPlaneMachineABC.cpi +// >>>>> INCLUDED FROM include_files/positionABC.cpi +function positionABC(abc, force) { + if (!machineConfiguration.isMultiAxisConfiguration()) { + error("Function 'positionABC' can only be used with multi-axis machine configurations."); + } + if (typeof unwindABC == "function") { + unwindABC(abc); + } + if (force) { + forceABC(); + } + var a = aOutput.format(abc.x); + var b = bOutput.format(abc.y); + var c = cOutput.format(abc.z); + if (a || b || c) { + //writeRetract(Z); // *** retract removed + if (getSetting("retract.homeXY.onIndexing", false)) { + writeRetract(settings.retract.homeXY.onIndexing); + } + onCommand(COMMAND_UNLOCK_MULTI_AXIS); + gMotionModal.reset(); + writeBlock(gMotionModal.format(0), a, b, c); + setCurrentABC(abc); // required for machine simulation + machineSimulation({a:abc.x, b:abc.y, c:abc.z, coordinates:MACHINE}); + } +} +// <<<<< INCLUDED FROM include_files/positionABC.cpi +// >>>>> INCLUDED FROM include_files/writeWCS.cpi +function writeWCS(section, wcsIsRequired) { + if (section.workOffset != currentWorkOffset) { + if (getSetting("workPlaneMethod.cancelTiltFirst", false) && wcsIsRequired) { + cancelWorkPlane(); + } + if (typeof forceWorkPlane == "function" && wcsIsRequired) { + forceWorkPlane(); + } + writeStartBlocks(wcsIsRequired, function () { + writeBlock(section.wcs); + }); + currentWorkOffset = section.workOffset; + } +} +// <<<<< INCLUDED FROM include_files/writeWCS.cpi +// >>>>> INCLUDED FROM include_files/writeToolCall.cpi +function writeToolCall(tool, insertToolCall) { + if (!isFirstSection()) { + writeStartBlocks(!getProperty("safeStartAllOperations") && insertToolCall, function () { + writeRetract(Z); // write optional Z retract before tool change if safeStartAllOperations is enabled + }); + } + writeStartBlocks(insertToolCall, function () { + writeRetract(Z); + if (getProperty("_1forceTCPosition", false)) { + forceModals(gMotionModal); + writeBlock(gAbsIncModal.format(90), gFormat.format(53), gMotionModal.format(0), xOutput.format(getProperty("_2TCposX")), yOutput.format(getProperty("_2TCposY"))); + machineSimulation({x:toPreciseUnit(getProperty("_2TCposX"), MM), y:toPreciseUnit(getProperty("_2TCposY"), MM), coordinates:MACHINE, mode:TOOLCHANGE}); // move machineSimulation to a tool change position + } else if (getSetting("retract.homeXY.onToolChange", false)) { + writeRetract(settings.retract.homeXY.onToolChange); + } + if (!isFirstSection() && insertToolCall) { + if (typeof forceWorkPlane == "function") { + forceWorkPlane(); + } + onCommand(COMMAND_COOLANT_OFF); // turn off coolant on tool change + if (typeof disableLengthCompensation == "function") { + disableLengthCompensation(false); + } + } + + if (tool.manualToolChange) { + onCommand(COMMAND_LOAD_TOOL); //tool change to bring "pocket placeholder" into spindle + if (getProperty("_3forceManualTCPosition", false)) { + forceModals(gMotionModal); + writeBlock(gAbsIncModal.format(90), gFormat.format(53), gMotionModal.format(0), xOutput.format(getProperty("_4manual_TCposX")), yOutput.format(getProperty("_4manual_TCposY"))); + machineSimulation({x:toPreciseUnit(getProperty("_4manual_TCposX"), MM), y:toPreciseUnit(getProperty("_4manual_TCposY"), MM), coordinates:MACHINE}); // , mode:TOOLCHANGE move machineSimulation to a tool change position + } else if (getSetting("retract.homeXY.onToolChange", false)) { + writeRetract(settings.retract.homeXY.onToolChange); + } + onCommand(COMMAND_STOP); + //writeComment("MANUAL TOOL CHANGE TO T" + toolFormat.format(tool.number)); + writeComment("Flip to Manual, Swap tool to T" + toolFormat.format(tool.number)); + writeComment("H" + tool.lengthOffset + " - " + tool.description); + writeComment(tool.bodyLength + "mm Stick out below " + tool.holderDescription + " holder"); + } else { + if (!isFirstSection() && getProperty("optionalStop") && insertToolCall) { + onCommand(COMMAND_OPTIONAL_STOP); + } + onCommand(COMMAND_LOAD_TOOL); + machineSimulation({x:toPreciseUnit(getProperty("_2TCposX"), MM), y:toPreciseUnit( getProperty("_2TCposY") , MM), coordinates:MACHINE}); //, mode:TOOLCHANGE move machineSimulation to a tool change position + } + }); + if (typeof forceModals == "function" && (insertToolCall || getProperty("safeStartAllOperations"))) { + forceModals(); + } +} +// <<<<< INCLUDED FROM include_files/writeToolCall.cpi +// >>>>> INCLUDED FROM include_files/startSpindle.cpi + +function startSpindle(tool, insertToolCall) { + if (tool.type != TOOL_PROBE) { + var spindleSpeedIsRequired = insertToolCall || forceSpindleSpeed || isFirstSection() || + rpmFormat.areDifferent(spindleSpeed, sOutput.getCurrent()) || + (tool.clockwise != getPreviousSection().getTool().clockwise); + + writeStartBlocks(spindleSpeedIsRequired, function () { + if (spindleSpeedIsRequired || operationNeedsSafeStart) { + onCommand(COMMAND_START_SPINDLE); + } + }); + } +} +// <<<<< INCLUDED FROM include_files/startSpindle.cpi +// >>>>> INCLUDED FROM include_files/parametricFeeds.cpi +properties.useParametricFeed = { + title : "Parametric feed", + description: "Specifies that the feedrates should be output using parameters.", + group : "preferences", + type : "boolean", + value : false, + scope : "post" +}; +var activeMovements; +var currentFeedId; +validate(settings.parametricFeeds, "Setting 'parametricFeeds' is required but not defined."); +function initializeParametricFeeds(insertToolCall) { + if (getProperty("useParametricFeed") && getParameter("operation-strategy") != "drill" && !currentSection.hasAnyCycle()) { + if (!insertToolCall && activeMovements && (getCurrentSectionId() > 0) && + ((getPreviousSection().getPatternId() == currentSection.getPatternId()) && (currentSection.getPatternId() != 0))) { + return; // use the current feeds + } + } else { + activeMovements = undefined; + return; + } + + activeMovements = new Array(); + var movements = currentSection.getMovements(); + + var id = 0; + var activeFeeds = new Array(); + if (hasParameter("operation:tool_feedCutting")) { + if (movements & ((1 << MOVEMENT_CUTTING) | (1 << MOVEMENT_LINK_TRANSITION) | (1 << MOVEMENT_EXTENDED))) { + var feedContext = new FeedContext(id, localize("Cutting"), getParameter("operation:tool_feedCutting")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_CUTTING] = feedContext; + if (!hasParameter("operation:tool_feedTransition")) { + activeMovements[MOVEMENT_LINK_TRANSITION] = feedContext; + } + activeMovements[MOVEMENT_EXTENDED] = feedContext; + } + ++id; + if (movements & (1 << MOVEMENT_PREDRILL)) { + feedContext = new FeedContext(id, localize("Predrilling"), getParameter("operation:tool_feedCutting")); + activeMovements[MOVEMENT_PREDRILL] = feedContext; + activeFeeds.push(feedContext); + } + ++id; + } + if (hasParameter("operation:finishFeedrate")) { + if (movements & (1 << MOVEMENT_FINISH_CUTTING)) { + var feedContext = new FeedContext(id, localize("Finish"), getParameter("operation:finishFeedrate")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_FINISH_CUTTING] = feedContext; + } + ++id; + } else if (hasParameter("operation:tool_feedCutting")) { + if (movements & (1 << MOVEMENT_FINISH_CUTTING)) { + var feedContext = new FeedContext(id, localize("Finish"), getParameter("operation:tool_feedCutting")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_FINISH_CUTTING] = feedContext; + } + ++id; + } + if (hasParameter("operation:tool_feedEntry")) { + if (movements & (1 << MOVEMENT_LEAD_IN)) { + var feedContext = new FeedContext(id, localize("Entry"), getParameter("operation:tool_feedEntry")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_LEAD_IN] = feedContext; + } + ++id; + } + if (hasParameter("operation:tool_feedExit")) { + if (movements & (1 << MOVEMENT_LEAD_OUT)) { + var feedContext = new FeedContext(id, localize("Exit"), getParameter("operation:tool_feedExit")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_LEAD_OUT] = feedContext; + } + ++id; + } + if (hasParameter("operation:noEngagementFeedrate")) { + if (movements & (1 << MOVEMENT_LINK_DIRECT)) { + var feedContext = new FeedContext(id, localize("Direct"), getParameter("operation:noEngagementFeedrate")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_LINK_DIRECT] = feedContext; + } + ++id; + } else if (hasParameter("operation:tool_feedCutting") && + hasParameter("operation:tool_feedEntry") && + hasParameter("operation:tool_feedExit")) { + if (movements & (1 << MOVEMENT_LINK_DIRECT)) { + var feedContext = new FeedContext(id, localize("Direct"), Math.max(getParameter("operation:tool_feedCutting"), getParameter("operation:tool_feedEntry"), getParameter("operation:tool_feedExit"))); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_LINK_DIRECT] = feedContext; + } + ++id; + } + if (hasParameter("operation:reducedFeedrate")) { + if (movements & (1 << MOVEMENT_REDUCED)) { + var feedContext = new FeedContext(id, localize("Reduced"), getParameter("operation:reducedFeedrate")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_REDUCED] = feedContext; + } + ++id; + } + if (hasParameter("operation:tool_feedRamp")) { + if (movements & ((1 << MOVEMENT_RAMP) | (1 << MOVEMENT_RAMP_HELIX) | (1 << MOVEMENT_RAMP_PROFILE) | (1 << MOVEMENT_RAMP_ZIG_ZAG))) { + var feedContext = new FeedContext(id, localize("Ramping"), getParameter("operation:tool_feedRamp")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_RAMP] = feedContext; + activeMovements[MOVEMENT_RAMP_HELIX] = feedContext; + activeMovements[MOVEMENT_RAMP_PROFILE] = feedContext; + activeMovements[MOVEMENT_RAMP_ZIG_ZAG] = feedContext; + } + ++id; + } + if (hasParameter("operation:tool_feedPlunge")) { + if (movements & (1 << MOVEMENT_PLUNGE)) { + var feedContext = new FeedContext(id, localize("Plunge"), getParameter("operation:tool_feedPlunge")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_PLUNGE] = feedContext; + } + ++id; + } + if (true) { // high feed + if ((movements & (1 << MOVEMENT_HIGH_FEED)) || (highFeedMapping != HIGH_FEED_NO_MAPPING)) { + var feed; + if (hasParameter("operation:highFeedrateMode") && getParameter("operation:highFeedrateMode") != "disabled") { + feed = getParameter("operation:highFeedrate"); + } else { + feed = this.highFeedrate; + } + var feedContext = new FeedContext(id, localize("High Feed"), feed); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_HIGH_FEED] = feedContext; + activeMovements[MOVEMENT_RAPID] = feedContext; + } + ++id; + } + if (hasParameter("operation:tool_feedTransition")) { + if (movements & (1 << MOVEMENT_LINK_TRANSITION)) { + var feedContext = new FeedContext(id, localize("Transition"), getParameter("operation:tool_feedTransition")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_LINK_TRANSITION] = feedContext; + } + ++id; + } + + for (var i = 0; i < activeFeeds.length; ++i) { + var feedContext = activeFeeds[i]; + var feedDescription = typeof formatComment == "function" ? formatComment(feedContext.description) : feedContext.description; + writeBlock(settings.parametricFeeds.feedAssignmentVariable + (settings.parametricFeeds.firstFeedParameter + feedContext.id) + "=" + feedFormat.format(feedContext.feed) + SP + feedDescription); + } +} + +function FeedContext(id, description, feed) { + this.id = id; + this.description = description; + this.feed = feed; +} +// <<<<< INCLUDED FROM include_files/parametricFeeds.cpi +// >>>>> INCLUDED FROM include_files/coolant.cpi +var currentCoolantMode = COOLANT_OFF; +var coolantOff = undefined; +var isOptionalCoolant = false; +var forceCoolant = false; + +function setCoolant(coolant) { + var coolantCodes = getCoolantCodes(coolant); + if (Array.isArray(coolantCodes)) { + writeStartBlocks(!isOptionalCoolant, function () { + if (settings.coolant.singleLineCoolant) { + writeBlock(coolantCodes.join(getWordSeparator())); + } else { + for (var c in coolantCodes) { + writeBlock(coolantCodes[c]); + } + } + }); + return undefined; + } + return coolantCodes; +} + +function getCoolantCodes(coolant, format) { + if (!getProperty("useCoolant", true)) { + return undefined; // coolant output is disabled by property if it exists + } + isOptionalCoolant = false; + if (typeof operationNeedsSafeStart == "undefined") { + operationNeedsSafeStart = false; + } + var multipleCoolantBlocks = new Array(); // create a formatted array to be passed into the outputted line + var coolants = settings.coolant.coolants; + if (!coolants) { + error(localize("Coolants have not been defined.")); + } + if (tool.type && tool.type == TOOL_PROBE) { // avoid coolant output for probing + coolant = COOLANT_OFF; + } + if (coolant == currentCoolantMode) { + if (operationNeedsSafeStart && coolant != COOLANT_OFF) { + isOptionalCoolant = true; + } else if (!forceCoolant || coolant == COOLANT_OFF) { + return undefined; // coolant is already active + } + } + if ((coolant != COOLANT_OFF) && (currentCoolantMode != COOLANT_OFF) && (coolantOff != undefined) && !forceCoolant && !isOptionalCoolant) { + if (Array.isArray(coolantOff)) { + for (var i in coolantOff) { + multipleCoolantBlocks.push(coolantOff[i]); + } + } else { + multipleCoolantBlocks.push(coolantOff); + } + } + forceCoolant = false; + + var m; + var coolantCodes = {}; + for (var c in coolants) { // find required coolant codes into the coolants array + if (coolants[c].id == coolant) { + coolantCodes.on = coolants[c].on; + if (coolants[c].off != undefined) { + coolantCodes.off = coolants[c].off; + break; + } else { + for (var i in coolants) { + if (coolants[i].id == COOLANT_OFF) { + coolantCodes.off = coolants[i].off; + break; + } + } + } + } + } + if (coolant == COOLANT_OFF) { + m = !coolantOff ? coolantCodes.off : coolantOff; // use the default coolant off command when an 'off' value is not specified + } else { + coolantOff = coolantCodes.off; + m = coolantCodes.on; + } + + if (!m) { + onUnsupportedCoolant(coolant); + m = 9; + } else { + if (Array.isArray(m)) { + for (var i in m) { + multipleCoolantBlocks.push(m[i]); + } + } else { + multipleCoolantBlocks.push(m); + } + currentCoolantMode = coolant; + for (var i in multipleCoolantBlocks) { + if (typeof multipleCoolantBlocks[i] == "number") { + multipleCoolantBlocks[i] = mFormat.format(multipleCoolantBlocks[i]); + } + } + if (format == undefined || format) { + return multipleCoolantBlocks; // return the single formatted coolant value + } else { + return m; // return unformatted coolant value + } + } + return undefined; +} +// <<<<< INCLUDED FROM include_files/coolant.cpi +// >>>>> INCLUDED FROM include_files/smoothing.cpi +// collected state below, do not edit +validate(settings.smoothing, "Setting 'smoothing' is required but not defined."); +var smoothing = { + cancel : false, // cancel tool length prior to update smoothing for this operation + isActive : false, // the current state of smoothing + isAllowed : false, // smoothing is allowed for this operation + isDifferent: false, // tells if smoothing levels/tolerances/both are different between operations + level : -1, // the active level of smoothing + tolerance : -1, // the current operation tolerance + force : false // smoothing needs to be forced out in this operation +}; + +function initializeSmoothing() { + var smoothingSettings = settings.smoothing; + var previousLevel = smoothing.level; + var previousTolerance = xyzFormat.getResultingValue(smoothing.tolerance); + + // format threshold parameters + var thresholdRoughing = xyzFormat.getResultingValue(smoothingSettings.thresholdRoughing); + var thresholdSemiFinishing = xyzFormat.getResultingValue(smoothingSettings.thresholdSemiFinishing); + var thresholdFinishing = xyzFormat.getResultingValue(smoothingSettings.thresholdFinishing); + + // determine new smoothing levels and tolerances + smoothing.level = parseInt(getProperty("useSmoothing"), 10); + smoothing.level = isNaN(smoothing.level) ? -1 : smoothing.level; + smoothing.tolerance = xyzFormat.getResultingValue(Math.max(getParameter("operation:tolerance", thresholdFinishing), 0)); + + if (smoothing.level == 9999) { + if (smoothingSettings.autoLevelCriteria == "stock") { // determine auto smoothing level based on stockToLeave + var stockToLeave = xyzFormat.getResultingValue(getParameter("operation:stockToLeave", 0)); + var verticalStockToLeave = xyzFormat.getResultingValue(getParameter("operation:verticalStockToLeave", 0)); + if (((stockToLeave >= thresholdRoughing) && (verticalStockToLeave >= thresholdRoughing)) || getParameter("operation:strategy", "") == "face") { + smoothing.level = smoothingSettings.roughing; // set roughing level + } else { + if (((stockToLeave >= thresholdSemiFinishing) && (stockToLeave < thresholdRoughing)) && + ((verticalStockToLeave >= thresholdSemiFinishing) && (verticalStockToLeave < thresholdRoughing))) { + smoothing.level = smoothingSettings.semi; // set semi level + } else if (((stockToLeave >= thresholdFinishing) && (stockToLeave < thresholdSemiFinishing)) && + ((verticalStockToLeave >= thresholdFinishing) && (verticalStockToLeave < thresholdSemiFinishing))) { + smoothing.level = smoothingSettings.semifinishing; // set semi-finishing level + } else { + smoothing.level = smoothingSettings.finishing; // set finishing level + } + } + } else { // detemine auto smoothing level based on operation tolerance instead of stockToLeave + if (smoothing.tolerance >= thresholdRoughing || getParameter("operation:strategy", "") == "face") { + smoothing.level = smoothingSettings.roughing; // set roughing level + } else { + if (((smoothing.tolerance >= thresholdSemiFinishing) && (smoothing.tolerance < thresholdRoughing))) { + smoothing.level = smoothingSettings.semi; // set semi level + } else if (((smoothing.tolerance >= thresholdFinishing) && (smoothing.tolerance < thresholdSemiFinishing))) { + smoothing.level = smoothingSettings.semifinishing; // set semi-finishing level + } else { + smoothing.level = smoothingSettings.finishing; // set finishing level + } + } + } + } + + if (smoothing.level == -1) { // useSmoothing is disabled + smoothing.isAllowed = false; + } else { // do not output smoothing for the following operations + smoothing.isAllowed = !(currentSection.getTool().type == TOOL_PROBE || isDrillingCycle()); + } + if (!smoothing.isAllowed) { + smoothing.level = -1; + smoothing.tolerance = -1; + } + + switch (smoothingSettings.differenceCriteria) { + case "level": + smoothing.isDifferent = smoothing.level != previousLevel; + break; + case "tolerance": + smoothing.isDifferent = smoothing.tolerance != previousTolerance; + break; + case "both": + smoothing.isDifferent = smoothing.level != previousLevel || smoothing.tolerance != previousTolerance; + break; + default: + error(localize("Unsupported smoothing criteria.")); + return; + } + + // tool length compensation needs to be canceled when smoothing state/level changes + if (smoothingSettings.cancelCompensation) { + smoothing.cancel = !isFirstSection() && smoothing.isDifferent; + } +} +// <<<<< INCLUDED FROM include_files/smoothing.cpi +// >>>>> INCLUDED FROM include_files/writeProgramHeader.cpi +properties.writeMachine = { + title : "Write machine", + description: "Output the machine settings in the header of the program.", + group : "formats", + type : "boolean", + value : true, + scope : "post" +}; +properties.writeTools = { + title : "Write tool list", + description: "Output a tool list in the header of the program.", + group : "formats", + type : "boolean", + value : true, + scope : "post" +}; +function writeProgramHeader() { + writeComment((now.getMonth() + 1) + "-" + now.getDate() + "-" + now.getFullYear() + " " + now.getHours() + ":" + ("0" + now.getMinutes()).slice(-2)); //BJE + // dump machine configuration + var vendor = machineConfiguration.getVendor(); + var model = machineConfiguration.getModel(); + var mDescription = machineConfiguration.getDescription(); + if (getProperty("writeMachine") && (vendor || model || mDescription)) { + writeComment(localize("Machine")); + if (vendor) { + writeComment(" " + localize("vendor") + ": " + vendor); + } + if (model) { + writeComment(" " + localize("model") + ": " + model); + } + if (mDescription) { + writeComment(" " + localize("description") + ": " + mDescription); + } + } + + // dump tool information + if (getProperty("writeTools")) { + if (false) { // set to true to use the post kernel version of the tool list + writeToolTable(TOOL_NUMBER_COL); + } else { + var zRanges = {}; + if (is3D()) { + var numberOfSections = getNumberOfSections(); + for (var i = 0; i < numberOfSections; ++i) { + var section = getSection(i); + var zRange = section.getGlobalZRange(); + var tool = section.getTool(); + if (zRanges[tool.number]) { + zRanges[tool.number].expandToRange(zRange); + } else { + zRanges[tool.number] = zRange; + } + } + } + var tools = getToolTable(); + if (tools.getNumberOfTools() > 0) { + for (var i = 0; i < tools.getNumberOfTools(); ++i) { + var tool = tools.getTool(i); + var comment = (getProperty("toolAsName") ? "\"" + tool.description.toUpperCase() + "\"" : " T" + toolFormat.format(tool.number)) + " " + + toolTableFormat.format(tool.diameter) +"D " +// " " + + toolTableFormat.format(tool.bodyLength) + localize("-BH ") + + toolTableFormat.format(tool.cornerRadius) + localize("-CR ") ; + + if (zRanges[tool.number]) { + comment += localize("Zmin") + "=" + toolTableFormat.format(zRanges[tool.number].getMinimum())+ " "; + } + if ((tool.taperAngle > 0) && (tool.taperAngle < Math.PI)) { + comment += taperFormat.format(tool.taperAngle) + localize("deg")+ " "; + } + comment += getToolTypeName(tool.type); + + writeComment(comment); + } + } + } + } +} +// <<<<< INCLUDED FROM include_files/writeProgramHeader.cpi +// >>>>> INCLUDED FROM include_files/subprograms.cpi +properties.useSubroutines = { + title : "Use subroutines", + description: "Select your desired subroutine option. 'All Operations' creates subroutines per each operation, 'Cycles' creates subroutines for cycle operations on same holes, and 'Patterns' creates subroutines for patterned operations.", + group : "preferences", + type : "enum", + values : [ + {title:"No", id:"none"}, + {title:"All Operations", id:"allOperations"}, + {title:"All Operations & Patterns", id:"allPatterns"}, + {title:"Cycles", id:"cycles"}, + {title:"Operations, Patterns, Cycles", id:"all"}, + {title:"Patterns", id:"patterns"} + ], + value: "none", + scope: "post" +}; +properties.useFilesForSubprograms = { + title : "Use files for subroutines", + description: "If enabled, subroutines will be saved as individual files.", + group : "preferences", + type : "boolean", + value : false, + scope : "post" +}; + +var NONE = 0x0000; +var PATTERNS = 0x0001; +var CYCLES = 0x0010; +var ALLOPERATIONS = 0x0100; +var subroutineBitmasks = { + none : NONE, + patterns : PATTERNS, + cycles : CYCLES, + allOperations: ALLOPERATIONS, + allPatterns : PATTERNS + ALLOPERATIONS, + all : PATTERNS + CYCLES + ALLOPERATIONS +}; + +var SUB_UNKNOWN = 0; +var SUB_PATTERN = 1; +var SUB_CYCLE = 2; + +// collected state below, do not edit +validate(settings.subprograms, "Setting 'subprograms' is required but not defined."); +var subprogramState = { + subprograms : [], // Redirection buffer + newSubprogram : false, // Indicate if the current subprogram is new to definedSubprograms + currentSubprogram : 0, // The current subprogram number + lastSubprogram : undefined, // The last subprogram number + definedSubprograms : new Array(), // A collection of pattern and cycle subprograms + saveShowSequenceNumbers: "", // Used to store pre-condition of "showSequenceNumbers" + cycleSubprogramIsActive: false, // Indicate if it's handling a cycle subprogram + patternIsActive : false, // Indicate if it's handling a pattern subprogram + incrementalSubprogram : false, // Indicate if the current subprogram needs to go incremental mode + incrementalMode : false, // Indicate if incremental mode is on + mainProgramNumber : undefined // The main program number +}; + +function subprogramResolveSetting(_setting, _val, _comment) { + if (typeof _setting == "string") { + return formatWords(_setting.toString().replace("%currentSubprogram", subprogramState.currentSubprogram), (_comment ? formatComment(_comment) : "")); + } else { + return formatWords(_setting + (_val ? settings.subprograms.format.format(_val) : ""), (_comment ? formatComment(_comment) : "")); + } +} + +/** + * Start to redirect buffer to subprogram. + * @param {Vector} initialPosition Initial position + * @param {Vector} abc Machine axis angles + * @param {boolean} incremental If the subprogram needs to go incremental mode + */ +function subprogramStart(initialPosition, abc, incremental) { + var comment = getParameter("operation-comment", ""); + var startBlock; + if (getProperty("useFilesForSubprograms")) { + var _fileName = subprogramState.currentSubprogram; + var subprogramExtension = extension; + if (settings.subprograms.files) { + if (settings.subprograms.files.prefix != undefined) { + _fileName = subprogramResolveSetting(settings.subprograms.files.prefix, subprogramState.currentSubprogram); + } + if (settings.subprograms.files.extension) { + subprogramExtension = settings.subprograms.files.extension; + } + } + var path = FileSystem.getCombinedPath(FileSystem.getFolderPath(getOutputPath()), _fileName + "." + subprogramExtension); + redirectToFile(path); + startBlock = subprogramResolveSetting(settings.subprograms.startBlock.files, subprogramState.currentSubprogram, comment); + } else { + redirectToBuffer(); + startBlock = subprogramResolveSetting(settings.subprograms.startBlock.embedded, subprogramState.currentSubprogram, comment); + } + writeln(startBlock); + + subprogramState.saveShowSequenceNumbers = getProperty("showSequenceNumbers", undefined); + if (subprogramState.saveShowSequenceNumbers != undefined) { + setProperty("showSequenceNumbers", "false"); + } + if (incremental) { + setAbsIncMode(true, initialPosition, abc); + } + if (typeof gPlaneModal != "undefined" && typeof gMotionModal != "undefined") { + forceModals(gPlaneModal, gMotionModal); + } +} + +/** Output the command for calling a subprogram by its subprogram number. */ +function subprogramCall() { + var callBlock; + if (getProperty("useFilesForSubprograms")) { + callBlock = subprogramResolveSetting(settings.subprograms.callBlock.files, subprogramState.currentSubprogram); + } else { + callBlock = subprogramResolveSetting(settings.subprograms.callBlock.embedded, subprogramState.currentSubprogram); + } + writeBlock(callBlock); // call subprogram +} + +/** End of subprogram and close redirection. */ +function subprogramEnd() { + if (isRedirecting()) { + if (subprogramState.newSubprogram) { + var finalPosition = getFramePosition(currentSection.getFinalPosition()); + var abc; + if (currentSection.isMultiAxis() && machineConfiguration.isMultiAxisConfiguration()) { + abc = currentSection.getFinalToolAxisABC(); + } else { + abc = getCurrentDirection(); + } + setAbsIncMode(false, finalPosition, abc); + + if (getProperty("useFilesForSubprograms")) { + var endBlockFiles = subprogramResolveSetting(settings.subprograms.endBlock.files); + writeln(endBlockFiles); + } else { + var endBlockEmbedded = subprogramResolveSetting(settings.subprograms.endBlock.embedded); + writeln(endBlockEmbedded); + writeln(""); + subprogramState.subprograms += getRedirectionBuffer(); + } + } + forceAny(); + subprogramState.newSubprogram = false; + subprogramState.cycleSubprogramIsActive = false; + if (subprogramState.saveShowSequenceNumbers != undefined) { + setProperty("showSequenceNumbers", subprogramState.saveShowSequenceNumbers); + } + closeRedirection(); + } +} + +// below pulled from old post but not sure of best location +var probeOutputWorkOffset = 1; +function onParameter(name, value) { + if (name == "probe-output-work-offset") { + probeOutputWorkOffset = (value > 0) ? value : 1; + } +} +// above pulled from old post but not sure of best location + +/** Returns true if the spatial vectors are significantly different. */ +function areSpatialVectorsDifferent(_vector1, _vector2) { + return (xyzFormat.getResultingValue(_vector1.x) != xyzFormat.getResultingValue(_vector2.x)) || + (xyzFormat.getResultingValue(_vector1.y) != xyzFormat.getResultingValue(_vector2.y)) || + (xyzFormat.getResultingValue(_vector1.z) != xyzFormat.getResultingValue(_vector2.z)); +} + +/** Returns true if the spatial boxes are a pure translation. */ +function areSpatialBoxesTranslated(_box1, _box2) { + return !areSpatialVectorsDifferent(Vector.diff(_box1[1], _box1[0]), Vector.diff(_box2[1], _box2[0])) && + !areSpatialVectorsDifferent(Vector.diff(_box2[0], _box1[0]), Vector.diff(_box2[1], _box1[1])); +} + +/** Returns true if the spatial boxes are same. */ +function areSpatialBoxesSame(_box1, _box2) { + return !areSpatialVectorsDifferent(_box1[0], _box2[0]) && !areSpatialVectorsDifferent(_box1[1], _box2[1]); +} + +/** + * Search defined pattern subprogram by the given id. + * @param {number} subprogramId Subprogram Id + * @returns {Object} Returns defined subprogram if found, otherwise returns undefined + */ +function getDefinedPatternSubprogram(subprogramId) { + for (var i = 0; i < subprogramState.definedSubprograms.length; ++i) { + if ((SUB_PATTERN == subprogramState.definedSubprograms[i].type) && (subprogramId == subprogramState.definedSubprograms[i].id)) { + return subprogramState.definedSubprograms[i]; + } + } + return undefined; +} + +/** + * Search defined cycle subprogram pattern by the given id, initialPosition, finalPosition. + * @param {number} subprogramId Subprogram Id + * @param {Vector} initialPosition Initial position of the cycle + * @param {Vector} finalPosition Final position of the cycle + * @returns {Object} Returns defined subprogram if found, otherwise returns undefined + */ +function getDefinedCycleSubprogram(subprogramId, initialPosition, finalPosition) { + for (var i = 0; i < subprogramState.definedSubprograms.length; ++i) { + if ((SUB_CYCLE == subprogramState.definedSubprograms[i].type) && (subprogramId == subprogramState.definedSubprograms[i].id) && + !areSpatialVectorsDifferent(initialPosition, subprogramState.definedSubprograms[i].initialPosition) && + !areSpatialVectorsDifferent(finalPosition, subprogramState.definedSubprograms[i].finalPosition)) { + return subprogramState.definedSubprograms[i]; + } + } + return undefined; +} + +/** + * Creates and returns new defined subprogram + * @param {Section} section The section to create subprogram + * @param {number} subprogramId Subprogram Id + * @param {number} subprogramType Subprogram type, can be SUB_UNKNOWN, SUB_PATTERN or SUB_CYCLE + * @param {Vector} initialPosition Initial position + * @param {Vector} finalPosition Final position + * @returns {Object} Returns new defined subprogram + */ +function defineNewSubprogram(section, subprogramId, subprogramType, initialPosition, finalPosition) { + // determine if this is valid for creating a subprogram + isValid = subprogramIsValid(section, subprogramId, subprogramType); + var subprogram = isValid ? subprogram = ++subprogramState.lastSubprogram : undefined; + subprogramState.definedSubprograms.push({ + type : subprogramType, + id : subprogramId, + subProgram : subprogram, + isValid : isValid, + initialPosition: initialPosition, + finalPosition : finalPosition + }); + return subprogramState.definedSubprograms[subprogramState.definedSubprograms.length - 1]; +} + +/** Returns true if the given section is a pattern **/ +function isPatternOperation(section) { + return section.isPatterned && section.isPatterned(); +} + +/** Returns true if the given section is a cycle operation **/ +function isCycleOperation(section, minimumCyclePoints) { + return section.doesStrictCycle && + (section.getNumberOfCycles() == 1) && (section.getNumberOfCyclePoints() >= minimumCyclePoints); +} + +/** Returns true if the subroutine bit flag is enabled **/ +function isSubProgramEnabledFor(subroutine) { + return subroutineBitmasks[getProperty("useSubroutines")] & subroutine; +} + +/** + * Define subprogram based on the property "useSubroutines" + * @param {Vector} _initialPosition Initial position + * @param {Vector} _abc Machine axis angles + */ +function subprogramDefine(_initialPosition, _abc) { + if (isSubProgramEnabledFor(NONE)) { + // Return early + return; + } + + if (subprogramState.lastSubprogram == undefined) { // initialize first subprogram number + if (settings.subprograms.initialSubprogramNumber == undefined) { + try { + subprogramState.lastSubprogram = getAsInt(programName); + subprogramState.mainProgramNumber = subprogramState.lastSubprogram; // mainProgramNumber must be a number + } catch (e) { + error(localize("Program name must be a number when using subprograms.")); + return; + } + } else { + subprogramState.lastSubprogram = settings.subprograms.initialSubprogramNumber - 1; + // if programName is a string set mainProgramNumber to undefined, if programName is a number set mainProgramNumber to programName + subprogramState.mainProgramNumber = (!isNaN(programName) && !isNaN(parseInt(programName, 10))) ? getAsInt(programName) : undefined; + } + } + + // convert patterns into subprograms + subprogramState.patternIsActive = false; + if (isSubProgramEnabledFor(PATTERNS) && isPatternOperation(currentSection)) { + var subprogramId = currentSection.getPatternId(); + var subprogramType = SUB_PATTERN; + var subprogramDefinition = getDefinedPatternSubprogram(subprogramId); + + subprogramState.newSubprogram = !subprogramDefinition; + if (subprogramState.newSubprogram) { + subprogramDefinition = defineNewSubprogram(currentSection, subprogramId, subprogramType, _initialPosition, _initialPosition); + } + + subprogramState.currentSubprogram = subprogramDefinition.subProgram; + if (subprogramDefinition.isValid) { + // make sure Z-position is output prior to subprogram call + var z = zOutput.format(_initialPosition.z); + if (!state.retractedZ && z) { + validate(!validateLengthCompensation || state.lengthCompensationActive, "Tool length compensation is not active."); // make sure that length compensation is enabled + var block = ""; + if (typeof gAbsIncModal != "undefined") { + block += gAbsIncModal.format(90); + } + if (typeof gPlaneModal != "undefined") { + block += gPlaneModal.format(17); + } + writeBlock(block); + zOutput.reset(); + invokeOnRapid(xOutput.getCurrent(), yOutput.getCurrent(), _initialPosition.z); + } + + // call subprogram + subprogramCall(); + subprogramState.patternIsActive = true; + + if (subprogramState.newSubprogram) { + subprogramStart(_initialPosition, _abc, subprogramState.incrementalSubprogram); + } else { + skipRemainingSection(); + setCurrentPosition(getFramePosition(currentSection.getFinalPosition())); + } + } + } + + // Patterns are not used, check other cases + if (!subprogramState.patternIsActive) { + // Output cycle operation as subprogram + if (isSubProgramEnabledFor(CYCLES) && isCycleOperation(currentSection, settings.subprograms.minimumCyclePoints)) { + var finalPosition = getFramePosition(currentSection.getFinalPosition()); + var subprogramId = currentSection.getNumberOfCyclePoints(); + var subprogramType = SUB_CYCLE; + var subprogramDefinition = getDefinedCycleSubprogram(subprogramId, _initialPosition, finalPosition); + subprogramState.newSubprogram = !subprogramDefinition; + if (subprogramState.newSubprogram) { + subprogramDefinition = defineNewSubprogram(currentSection, subprogramId, subprogramType, _initialPosition, finalPosition); + } + subprogramState.currentSubprogram = subprogramDefinition.subProgram; + subprogramState.cycleSubprogramIsActive = subprogramDefinition.isValid; + } + + // Neither patterns and cycles are used, check other operations + if (!subprogramState.cycleSubprogramIsActive && isSubProgramEnabledFor(ALLOPERATIONS)) { + // Output all operations as subprograms + subprogramState.currentSubprogram = ++subprogramState.lastSubprogram; + if (subprogramState.mainProgramNumber != undefined && (subprogramState.currentSubprogram == subprogramState.mainProgramNumber)) { + subprogramState.currentSubprogram = ++subprogramState.lastSubprogram; // avoid using main program number for current subprogram + } + subprogramCall(); + subprogramState.newSubprogram = true; + subprogramStart(_initialPosition, _abc, false); + } + } +} + +/** + * Determine if this is valid for creating a subprogram + * @param {Section} section The section to create subprogram + * @param {number} subprogramId Subprogram Id + * @param {number} subprogramType Subprogram type, can be SUB_UNKNOWN, SUB_PATTERN or SUB_CYCLE + * @returns {boolean} If this is valid for creating a subprogram + */ +function subprogramIsValid(_section, subprogramId, subprogramType) { + var sectionId = _section.getId(); + var numberOfSections = getNumberOfSections(); + var validSubprogram = subprogramType != SUB_CYCLE; + + var masterPosition = new Array(); + masterPosition[0] = getFramePosition(_section.getInitialPosition()); + masterPosition[1] = getFramePosition(_section.getFinalPosition()); + var tempBox = _section.getBoundingBox(); + var masterBox = new Array(); + masterBox[0] = getFramePosition(tempBox[0]); + masterBox[1] = getFramePosition(tempBox[1]); + + var rotation = getRotation(); + var translation = getTranslation(); + subprogramState.incrementalSubprogram = undefined; + + for (var i = 0; i < numberOfSections; ++i) { + var section = getSection(i); + if (section.getId() != sectionId) { + defineWorkPlane(section, false); + + // check for valid pattern + if (subprogramType == SUB_PATTERN) { + if (section.getPatternId() == subprogramId) { + var patternPosition = new Array(); + patternPosition[0] = getFramePosition(section.getInitialPosition()); + patternPosition[1] = getFramePosition(section.getFinalPosition()); + tempBox = section.getBoundingBox(); + var patternBox = new Array(); + patternBox[0] = getFramePosition(tempBox[0]); + patternBox[1] = getFramePosition(tempBox[1]); + + if (areSpatialBoxesSame(masterPosition, patternPosition) && areSpatialBoxesSame(masterBox, patternBox) && !section.isMultiAxis()) { + subprogramState.incrementalSubprogram = subprogramState.incrementalSubprogram ? subprogramState.incrementalSubprogram : false; + } else if (!areSpatialBoxesTranslated(masterPosition, patternPosition) || !areSpatialBoxesTranslated(masterBox, patternBox)) { + validSubprogram = false; + break; + } else { + subprogramState.incrementalSubprogram = true; + } + } + + // check for valid cycle operation + } else if (subprogramType == SUB_CYCLE) { + if ((section.getNumberOfCyclePoints() == subprogramId) && (section.getNumberOfCycles() == 1)) { + var patternInitial = getFramePosition(section.getInitialPosition()); + var patternFinal = getFramePosition(section.getFinalPosition()); + if (!areSpatialVectorsDifferent(patternInitial, masterPosition[0]) && !areSpatialVectorsDifferent(patternFinal, masterPosition[1])) { + validSubprogram = true; + break; + } + } + } + } + } + setRotation(rotation); + setTranslation(translation); + return (validSubprogram); +} + +/** + * Sets xyz and abc output formats to incremental or absolute type + * @param {boolean} incremental true: Sets incremental mode, false: Sets absolute mode + * @param {Vector} xyz Linear axis values for formating + * @param {Vector} abc Rotary axis values for formating +*/ +function setAbsIncMode(incremental, xyz, abc) { + var outputFormats = [xOutput, yOutput, zOutput, aOutput, bOutput, cOutput]; + for (var i = 0; i < outputFormats.length; ++i) { + outputFormats[i].setType(incremental ? TYPE_INCREMENTAL : TYPE_ABSOLUTE); + if (typeof incPrefix != "undefined" && typeof absPrefix != "undefined") { + outputFormats[i].setPrefix(incremental ? incPrefix[i] : absPrefix[i]); + } + if (i <= 2) { // xyz + outputFormats[i].setCurrent(xyz.getCoordinate(i)); + } else { // abc + outputFormats[i].setCurrent(abc.getCoordinate(i - 3)); + } + } + subprogramState.incrementalMode = incremental; + if (typeof gAbsIncModal != "undefined") { + if (incremental) { + forceModals(gAbsIncModal); + } + writeBlock(gAbsIncModal.format(incremental ? 91 : 90)); + } +} + +function setCyclePosition(_position) { + var _spindleAxis; + if (typeof gPlaneModal != "undefined") { + _spindleAxis = gPlaneModal.getCurrent() == 17 ? Z : (gPlaneModal.getCurrent() == 18 ? Y : X); + } else { + var _spindleDirection = machineConfiguration.getSpindleAxis().getAbsolute(); + _spindleAxis = isSameDirection(_spindleDirection, new Vector(0, 0, 1)) ? Z : isSameDirection(_spindleDirection, new Vector(0, 1, 0)) ? Y : X; + } + switch (_spindleAxis) { + case Z: + zOutput.format(_position); + break; + case Y: + yOutput.format(_position); + break; + case X: + xOutput.format(_position); + break; + } +} + +/** + * Place cycle operation in subprogram + * @param {Vector} initialPosition Initial position + * @param {Vector} abc Machine axis angles + * @param {boolean} incremental If the subprogram needs to go incremental mode + */ +function handleCycleSubprogram(initialPosition, abc, incremental) { + subprogramState.cycleSubprogramIsActive &= !(cycleExpanded || isProbeOperation()); + if (subprogramState.cycleSubprogramIsActive) { + // call subprogram + subprogramCall(); + subprogramStart(initialPosition, abc, incremental); + } +} + +function writeSubprograms() { + if (subprogramState.subprograms.length > 0) { + writeln(""); + write(subprogramState.subprograms); + } +} +// <<<<< INCLUDED FROM include_files/subprograms.cpi + +// >>>>> INCLUDED FROM include_files/onRapid_fanuc.cpi +function onRapid(_x, _y, _z) { + var x = xOutput.format(_x); + var y = yOutput.format(_y); + var z = zOutput.format(_z); + if (x || y || z) { + if (pendingRadiusCompensation >= 0) { + error(localize("Radius compensation mode cannot be changed at rapid traversal.")); + return; + } + writeBlock(gMotionModal.format(0), x, y, z); + forceFeed(); + } +} +// <<<<< INCLUDED FROM include_files/onRapid_fanuc.cpi +// >>>>> INCLUDED FROM include_files/onLinear_fanuc.cpi +function onLinear(_x, _y, _z, feed) { + if (pendingRadiusCompensation >= 0) { + xOutput.reset(); + yOutput.reset(); + } + var x = xOutput.format(_x); + var y = yOutput.format(_y); + var z = zOutput.format(_z); + var f = getFeed(feed); + if (x || y || z) { + if (pendingRadiusCompensation >= 0) { + pendingRadiusCompensation = -1; + var d = getSetting("outputToolDiameterOffset", true) ? diameterOffsetFormat.format(tool.diameterOffset) : ""; + writeBlock(gPlaneModal.format(17)); + switch (radiusCompensation) { + case RADIUS_COMPENSATION_LEFT: + writeBlock(gMotionModal.format(1), gFormat.format(41), x, y, z, d, f); + break; + case RADIUS_COMPENSATION_RIGHT: + writeBlock(gMotionModal.format(1), gFormat.format(42), x, y, z, d, f); + break; + default: + writeBlock(gMotionModal.format(1), gFormat.format(40), x, y, z, f); + } + } else { + writeBlock(gMotionModal.format(1), x, y, z, f); + } + } else if (f) { + if (getNextRecord().isMotion()) { // try not to output feed without motion + forceFeed(); // force feed on next line + } else { + writeBlock(gMotionModal.format(1), f); + } + } +} +// <<<<< INCLUDED FROM include_files/onLinear_fanuc.cpi +// >>>>> INCLUDED FROM include_files/onRapid5D_fanuc.cpi +function onRapid5D(_x, _y, _z, _a, _b, _c) { + if (pendingRadiusCompensation >= 0) { + error(localize("Radius compensation mode cannot be changed at rapid traversal.")); + return; + } + if (!currentSection.isOptimizedForMachine()) { + forceXYZ(); + } + var x = xOutput.format(_x); + var y = yOutput.format(_y); + var z = zOutput.format(_z); + var a = currentSection.isOptimizedForMachine() ? aOutput.format(_a) : toolVectorOutputI.format(_a); + var b = currentSection.isOptimizedForMachine() ? bOutput.format(_b) : toolVectorOutputJ.format(_b); + var c = currentSection.isOptimizedForMachine() ? cOutput.format(_c) : toolVectorOutputK.format(_c); + + if (x || y || z || a || b || c) { + writeBlock(gMotionModal.format(0), x, y, z, a, b, c); + forceFeed(); + } +} +// <<<<< INCLUDED FROM include_files/onRapid5D_fanuc.cpi +// >>>>> INCLUDED FROM include_files/onLinear5D_fanuc.cpi +function onLinear5D(_x, _y, _z, _a, _b, _c, feed, feedMode) { + if (pendingRadiusCompensation >= 0) { + error(localize("Radius compensation cannot be activated/deactivated for 5-axis move.")); + return; + } + if (!currentSection.isOptimizedForMachine()) { + forceXYZ(); + } + var x = xOutput.format(_x); + var y = yOutput.format(_y); + var z = zOutput.format(_z); + var a = currentSection.isOptimizedForMachine() ? aOutput.format(_a) : toolVectorOutputI.format(_a); + var b = currentSection.isOptimizedForMachine() ? bOutput.format(_b) : toolVectorOutputJ.format(_b); + var c = currentSection.isOptimizedForMachine() ? cOutput.format(_c) : toolVectorOutputK.format(_c); + if (feedMode == FEED_INVERSE_TIME) { + forceFeed(); + } + var f = feedMode == FEED_INVERSE_TIME ? inverseTimeOutput.format(feed) : getFeed(feed); + var fMode = feedMode == FEED_INVERSE_TIME ? 93 : getProperty("useG95") ? 95 : 94; + + if (x || y || z || a || b || c) { + writeBlock(gFeedModeModal.format(fMode), gMotionModal.format(1), x, y, z, a, b, c, f); + } else if (f) { + if (getNextRecord().isMotion()) { // try not to output feed without motion + forceFeed(); // force feed on next line + } else { + writeBlock(gFeedModeModal.format(fMode), gMotionModal.format(1), f); + } + } +} +// <<<<< INCLUDED FROM include_files/onLinear5D_fanuc.cpi +// >>>>> INCLUDED FROM include_files/onCircular_fanuc.cpi +function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { + if (pendingRadiusCompensation >= 0) { + error(localize("Radius compensation cannot be activated/deactivated for a circular move.")); + return; + } + + var start = getCurrentPosition(); + + if (isFullCircle()) { + if (getProperty("useRadius") || isHelical()) { // radius mode does not support full arcs + linearize(tolerance); + return; + } + switch (getCircularPlane()) { + case PLANE_XY: + writeBlock(gPlaneModal.format(17), gMotionModal.format(clockwise ? 2 : 3), iOutput.format(cx - start.x), jOutput.format(cy - start.y), getFeed(feed)); + break; + case PLANE_ZX: + writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), iOutput.format(cx - start.x), kOutput.format(cz - start.z), getFeed(feed)); + break; + case PLANE_YZ: + writeBlock(gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), jOutput.format(cy - start.y), kOutput.format(cz - start.z), getFeed(feed)); + break; + default: + linearize(tolerance); + } + } else if (!getProperty("useRadius")) { + switch (getCircularPlane()) { + case PLANE_XY: + writeBlock(gPlaneModal.format(17), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x), jOutput.format(cy - start.y), getFeed(feed)); + break; + case PLANE_ZX: + writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x), kOutput.format(cz - start.z), getFeed(feed)); + break; + case PLANE_YZ: + writeBlock(gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), jOutput.format(cy - start.y), kOutput.format(cz - start.z), getFeed(feed)); + break; + default: + if (getProperty("allow3DArcs")) { + // make sure maximumCircularSweep is well below 360deg + // we could use G02.4 or G03.4 - direction is calculated + var ip = getPositionU(0.5); + writeBlock(gMotionModal.format(clockwise ? 2.4 : 3.4), xOutput.format(ip.x), yOutput.format(ip.y), zOutput.format(ip.z), getFeed(feed)); + writeBlock(xOutput.format(x), yOutput.format(y), zOutput.format(z)); + } else { + linearize(tolerance); + } + } + } else { // use radius mode + var r = getCircularRadius(); + if (toDeg(getCircularSweep()) > (180 + 1e-9)) { + r = -r; // allow up to <360 deg arcs + } + switch (getCircularPlane()) { + case PLANE_XY: + writeBlock(gPlaneModal.format(17), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed)); + break; + case PLANE_ZX: + writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed)); + break; + case PLANE_YZ: + writeBlock(gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed)); + break; + default: + if (getProperty("allow3DArcs")) { + // make sure maximumCircularSweep is well below 360deg + // we could use G02.4 or G03.4 - direction is calculated + var ip = getPositionU(0.5); + writeBlock(gMotionModal.format(clockwise ? 2.4 : 3.4), xOutput.format(ip.x), yOutput.format(ip.y), zOutput.format(ip.z), getFeed(feed)); + writeBlock(xOutput.format(x), yOutput.format(y), zOutput.format(z)); + } else { + linearize(tolerance); + } + } + } +} +// <<<<< INCLUDED FROM include_files/onCircular_fanuc.cpi +// >>>>> INCLUDED FROM include_files/workPlaneFunctions_fanuc.cpi +var gRotationModal = createOutputVariable({current : 69, + onchange: function () { + state.twpIsActive = gRotationModal.getCurrent() != 69; + if (typeof probeVariables != "undefined") { + probeVariables.outputRotationCodes = probeVariables.probeAngleMethod == "G68"; + } + machineSimulation({}); // update machine simulation TWP state + }}, gFormat); + +var currentWorkPlaneABC = undefined; +function forceWorkPlane() { + currentWorkPlaneABC = undefined; +} + +function cancelWCSRotation() { + if (typeof gRotationModal != "undefined" && gRotationModal.getCurrent() == 68) { + cancelWorkPlane(true); + } +} + +function cancelWorkPlane(force) { + if (typeof gRotationModal != "undefined") { + if (force) { + gRotationModal.reset(); + } + var command = gRotationModal.format(69); + if (command) { + writeBlock(command); // cancel frame + forceWorkPlane(); + } + } +} + +function setWorkPlane(abc) { + if (!settings.workPlaneMethod.forceMultiAxisIndexing && is3D() && !machineConfiguration.isMultiAxisConfiguration()) { + return; // ignore + } + var workplaneIsRequired = (currentWorkPlaneABC == undefined) || + abcFormat.areDifferent(abc.x, currentWorkPlaneABC.x) || + abcFormat.areDifferent(abc.y, currentWorkPlaneABC.y) || + abcFormat.areDifferent(abc.z, currentWorkPlaneABC.z); + + writeStartBlocks(workplaneIsRequired, function () { + //writeRetract(Z); // *** retract removed + if (getSetting("retract.homeXY.onIndexing", false)) { + writeRetract(settings.retract.homeXY.onIndexing); + } + if (currentSection.getId() > 0 && (isTCPSupportedByOperation(getSection(currentSection.getId() - 1) || tcp.isSupportedByOperation)) && typeof disableLengthCompensation == "function") { + disableLengthCompensation(); // cancel TCP + } + + if (settings.workPlaneMethod.useTiltedWorkplane) { + onCommand(COMMAND_UNLOCK_MULTI_AXIS); + cancelWorkPlane(); + if (machineConfiguration.isMultiAxisConfiguration()) { + var machineABC = abc.isNonZero() ? (currentSection.isMultiAxis() ? getCurrentDirection() : getWorkPlaneMachineABC(currentSection, false)) : abc; + if (settings.workPlaneMethod.useABCPrepositioning || machineABC.isZero()) { + positionABC(machineABC, false); + } else { + setCurrentABC(machineABC); + } + } + if (abc.isNonZero() || !machineConfiguration.isMultiAxisConfiguration()) { + gRotationModal.reset(); + writeBlock( + gRotationModal.format(68.2), "X" + xyzFormat.format(currentSection.workOrigin.x), "Y" + xyzFormat.format(currentSection.workOrigin.y), "Z" + xyzFormat.format(currentSection.workOrigin.z), + "I" + abcFormat.format(abc.x), "J" + abcFormat.format(abc.y), "K" + abcFormat.format(abc.z) + ); // set frame + writeBlock(gFormat.format(53.1)); // turn machine + machineSimulation({a:getCurrentABC().x, b:getCurrentABC().y, c:getCurrentABC().z, coordinates:MACHINE, eulerAngles:abc}); + } + } else { + positionABC(abc, true); + } + if (!currentSection.isMultiAxis()) { + onCommand(COMMAND_LOCK_MULTI_AXIS); + } + currentWorkPlaneABC = abc; + }); +} +// <<<<< INCLUDED FROM include_files/workPlaneFunctions_fanuc.cpi +// >>>>> INCLUDED FROM include_files/writeRetract_fanuc.cpi +function writeRetract() { + var retract = getRetractParameters.apply(this, arguments); + if (retract && retract.words.length > 0) { + if (typeof cancelWCSRotation == "function" && getSetting("retract.cancelRotationOnRetracting", false)) { // cancel rotation before retracting + cancelWCSRotation(); + } + if (typeof disableLengthCompensation == "function" && getSetting("allowCancelTCPBeforeRetracting", false) && state.tcpIsActive) { + disableLengthCompensation(); // cancel TCP before retracting + } + for (var i in retract.words) { + var words = retract.singleLine ? retract.words : retract.words[i]; + switch (retract.method) { + case "G28": + forceModals(gMotionModal, gAbsIncModal); + writeBlock(gFormat.format(28), gAbsIncModal.format(91), words); + writeBlock(gAbsIncModal.format(90)); + break; + case "G30": + forceModals(gMotionModal, gAbsIncModal); + writeBlock(gFormat.format(30), gAbsIncModal.format(91), words); + writeBlock(gAbsIncModal.format(90)); + break; + case "G53": + forceModals(gMotionModal); + writeBlock(gAbsIncModal.format(90), gFormat.format(53), gMotionModal.format(0), words); + break; + default: + if (typeof writeRetractCustom == "function") { + writeRetractCustom(retract); + return; + } else { + error(subst(localize("Unsupported safe position method '%1'"), retract.method)); + } + } + machineSimulation({ + x : retract.singleLine || words.indexOf("X") != -1 ? retract.positions.x : undefined, + y : retract.singleLine || words.indexOf("Y") != -1 ? retract.positions.y : undefined, + z : retract.singleLine || words.indexOf("Z") != -1 ? retract.positions.z : undefined, + coordinates: MACHINE + }); + /* simulation method to only display from previous method + var retractPositionZSim = state.retractedZ == false ? currentSection.getFinalPosition().getZ() : retract.positions.z ; // + var coordinatesZSim = state.retractedZ == false ? WORK : MACHINE; + xSim = retract.singleLine || words.indexOf("X") !== -1 ? retract.positions.x : undefined; + ySim = retract.singleLine || words.indexOf("Y") !== -1 ? retract.positions.y : undefined; + zSim = retract.singleLine || words.indexOf("Z") !== -1 ? retractPositionZSim : undefined; + // Only call machineSimulation for X and Y if either has a value + if (xSim !== undefined || ySim !== undefined) { + machineSimulation({ + x: xSim, + y: ySim, + coordinates: MACHINE + }); + } + // Only call machineSimulation for Z if it has a value and switch between coordinates methods + if (zSim !== undefined) { + machineSimulation({ + z: zSim, + coordinates: coordinatesZSim, + }); + } + */ + if (retract.singleLine) { + break; + } + } + } +} +// <<<<< INCLUDED FROM include_files/writeRetract_fanuc.cpi +// >>>>> INCLUDED FROM include_files/initialPositioning_fanuc.cpi +/** + * Writes the initial positioning procedure for a section to get to the start position of the toolpath. + * @param {Vector} position The initial position to move to + * @param {boolean} isRequired true: Output full positioning, false: Output full positioning in optional state or output simple positioning only + * @param {String} codes1 Allows to add additional code to the first positioning line + * @param {String} codes2 Allows to add additional code to the second positioning line (if applicable) + * @example + var myVar1 = formatWords("T" + tool.number, currentSection.wcs); + var myVar2 = getCoolantCodes(tool.coolant); + writeInitialPositioning(initialPosition, isRequired, myVar1, myVar2); +*/ +function writeInitialPositioning(position, isRequired, codes1, codes2) { + var motionCode = {single:0, multi:0}; + switch (highFeedMapping) { + case HIGH_FEED_MAP_ANY: + motionCode = {single:1, multi:1}; // map all rapid traversals to high feed + break; + case HIGH_FEED_MAP_MULTI: + motionCode = {single:0, multi:1}; // map rapid traversal along more than one axis to high feed + break; + } + var feed = (highFeedMapping != HIGH_FEED_NO_MAPPING) ? getFeed(highFeedrate) : ""; + var hOffset = getSetting("outputToolLengthOffset", true) ? hFormat.format(tool.lengthOffset) : ""; + var additionalCodes = [formatWords(codes1), formatWords(codes2)]; + + forceModals(gMotionModal); + writeStartBlocks(isRequired, function() { + var modalCodes = formatWords(gAbsIncModal.format(90), gPlaneModal.format(17)); + if (typeof disableLengthCompensation == "function") { + disableLengthCompensation(!isRequired); // cancel tool length compensation prior to enabling it, required when switching G43/G43.4 modes + } + + // multi axis prepositioning with TWP + if (currentSection.isMultiAxis() && getSetting("workPlaneMethod.prepositionWithTWP", true) && getSetting("workPlaneMethod.useTiltedWorkplane", false) && + tcp.isSupportedByOperation && getCurrentDirection().isNonZero()) { + var W = machineConfiguration.isMultiAxisConfiguration() ? machineConfiguration.getOrientation(getCurrentDirection()) : + Matrix.getOrientationFromDirection(getCurrentDirection()); + var prePosition = W.getTransposed().multiply(position); + var angles = W.getEuler2(settings.workPlaneMethod.eulerConvention); + setWorkPlane(angles); + writeBlock(modalCodes, gMotionModal.format(motionCode.multi), xOutput.format(prePosition.x), yOutput.format(prePosition.y), feed, additionalCodes[0]); + machineSimulation({x:prePosition.x, y:prePosition.y}); + cancelWorkPlane(); + writeBlock(getOffsetCode(), hOffset, additionalCodes[1]); // omit Z-axis output is desired + forceAny(); // required to output XYZ coordinates in the following line + } else { + if (machineConfiguration.isHeadConfiguration()) { + writeBlock(modalCodes, gMotionModal.format(motionCode.multi), getOffsetCode(), + xOutput.format(position.x), yOutput.format(position.y), zOutput.format(position.z), + hOffset, feed, additionalCodes + ); + machineSimulation({x:position.x, y:position.y, z:position.z}); + } else { + // non-protected move for the probe is required to ensure the correct H value is issued. A tall clearance height set in Fusion is recommended + writeBlock(modalCodes, gMotionModal.format(motionCode.multi), xOutput.format(position.x), yOutput.format(position.y), feed, additionalCodes[0]); + machineSimulation({x:position.x, y:position.y, mode:TOOLCHANGE}); // TOOLCHANGE added to patch simulation bug when swapping WCS without a tool change between + writeBlock(gMotionModal.format(motionCode.single), getOffsetCode(), zOutput.format(position.z), hOffset, additionalCodes[1]); + machineSimulation(tcp.isSupportedByOperation ? {x:position.x, y:position.y, z:position.z} : {z:position.z}); + } + } + forceModals(gMotionModal); + if (isRequired) { + additionalCodes = []; // clear additionalCodes buffer + } + }); + + validate(!validateLengthCompensation || state.lengthCompensationActive, "Tool length compensation is not active."); // make sure that lenght compensation is enabled + if (!isRequired) { // simple positioning + var modalCodes = formatWords(gAbsIncModal.format(90), gPlaneModal.format(17)); + forceXYZ(); + if (!state.retractedZ && xyzFormat.getResultingValue(getCurrentPosition().z) < xyzFormat.getResultingValue(position.z)) { + // Probe to be sent to initial position using protected moves + !isProbeOperation() ? + writeBlock(modalCodes, gMotionModal.format(motionCode.single), zOutput.format(position.z), feed) + : writeBlock(macroCall, "\"PROTECTEDMOVE\"", zOutput.format(position.z), feed) ; //, additionalCodes + writeln(feed) + machineSimulation({z:position.z}); + } + !isProbeOperation() ? + writeBlock(modalCodes, gMotionModal.format(motionCode.multi), xOutput.format(position.x), yOutput.format(position.y), feed, additionalCodes) + : writeBlock(macroCall, "\"PROTECTEDMOVE\"", xOutput.format(position.x), yOutput.format(position.y), feed, additionalCodes) ; + machineSimulation({x:position.x, y:position.y}); + } +} + +Matrix.getOrientationFromDirection = function (ijk) { + var forward = ijk; + var unitZ = new Vector(0, 0, 1); + var W; + if (Math.abs(Vector.dot(forward, unitZ)) < 0.5) { + var imX = Vector.cross(forward, unitZ).getNormalized(); + W = new Matrix(imX, Vector.cross(forward, imX), forward); + } else { + var imX = Vector.cross(new Vector(0, 1, 0), forward).getNormalized(); + W = new Matrix(imX, Vector.cross(forward, imX), forward); + } + return W; +}; +// <<<<< INCLUDED FROM include_files/initialPositioning_fanuc.cpi +// >>>>> INCLUDED FROM include_files/getOffsetCode_fanuc.cpi +var toolLengthCompOutput = createOutputVariable({control : CONTROL_FORCE, + onchange: function() { + state.tcpIsActive = toolLengthCompOutput.getCurrent() == 43.4 || toolLengthCompOutput.getCurrent() == 43.5; + state.lengthCompensationActive = toolLengthCompOutput.getCurrent() != 49; + machineSimulation({}); // update machine simulation TCP state + } +}, gFormat); + +function getOffsetCode() { + if (!getSetting("outputToolLengthCompensation", true) && toolLengthCompOutput.isEnabled()) { + state.lengthCompensationActive = true; // always assume that length compensation is active + toolLengthCompOutput.disable(); + } + var offsetCode = 43; + if (tcp.isSupportedByOperation) { + offsetCode = machineConfiguration.isMultiAxisConfiguration() ? 43.4 : 43.5; + } + return toolLengthCompOutput.format(offsetCode); +} +// <<<<< INCLUDED FROM include_files/getOffsetCode_fanuc.cpi +// >>>>> INCLUDED FROM include_files/disableLengthCompensation_fanuc.cpi +function disableLengthCompensation(force) { + if (state.lengthCompensationActive || force) { + if (force) { + toolLengthCompOutput.reset(); + } + if (!getSetting("allowCancelTCPBeforeRetracting", false)) { + validate(state.retractedZ, "Cannot cancel tool length compensation if the machine is not fully retracted."); + } + writeBlock(toolLengthCompOutput.format(49)); + } +} +// <<<<< INCLUDED FROM include_files/disableLengthCompensation_fanuc.cpi +// >>>>> INCLUDED FROM include_files/getProgramNumber_fanuc.cpi +function getProgramNumber() { + if (typeof oFormat != "undefined" && getProperty("o8")) { + oFormat.setMinDigitsLeft(8); + } + var minimumProgramNumber = getSetting("programNumber.min", 1); + var maximumProgramNumber = getSetting("programNumber.max", getProperty("o8") ? 99999999 : 9999); + var reservedProgramNumbers = getSetting("programNumber.reserved", [8000, 9999]); + if (programName) { + var _programNumber; + try { + _programNumber = getAsInt(programName); + } catch (e) { + error(localize("Program name must be a number.")); + } + if (!((_programNumber >= minimumProgramNumber) && (_programNumber <= maximumProgramNumber))) { + error(subst(localize("Program number '%1' is out of range. Please enter a program number between '%2' and '%3'."), _programNumber, minimumProgramNumber, maximumProgramNumber)); + } + if ((_programNumber >= reservedProgramNumbers[0]) && (_programNumber <= reservedProgramNumbers[1])) { + warning(subst(localize("Program number '%1' is potentially reserved by the machine tool builder. Reserved range is '%2' to '%3'."), _programNumber, reservedProgramNumbers[0], reservedProgramNumbers[1])); + } + } else { + error(localize("Program name has not been specified.")); + } + return _programNumber; +} +// <<<<< INCLUDED FROM include_files/getProgramNumber_fanuc.cpi +// >>>>> INCLUDED FROM include_files/drillCycles_fanuc.cpi +function writeDrillCycle(cycle, x, y, z) { + if (!isSameDirection(machineConfiguration.getSpindleAxis(), getForwardDirection(currentSection))) { + expandCyclePoint(x, y, z); + return; + } + if (isFirstCyclePoint()) { + // return to initial Z which is clearance plane and set absolute mode + repositionToCycleClearance(cycle, x, y, z); + + var F = getProperty("useG95") ? (cycle.feedrate / spindleSpeed) : cycle.feedrate; + var P = !cycle.dwell ? 0 : clamp(1, cycle.dwell * 1000, 99999999); // in milliseconds + switch (cycleType) { + case "drilling": + writeBlock( + gRetractModal.format(98), gCycleModal.format(81), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + feedOutput.format(F) + ); + break; + case "counter-boring": + if (P > 0) { + writeBlock( + gRetractModal.format(98), gCycleModal.format(82), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), + feedOutput.format(F) + ); + } else { + writeBlock( + gRetractModal.format(98), gCycleModal.format(81), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + feedOutput.format(F) + ); + } + break; + case "chip-breaking": + if ((cycle.accumulatedDepth < cycle.depth) || (P > 0)) { + expandCyclePoint(x, y, z); + } else { + writeBlock( + gRetractModal.format(98), gCycleModal.format(73), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + peckOutput.format(cycle.incrementalDepth), + feedOutput.format(F) + ); + } + break; + case "deep-drilling": + if (P > 0) { + expandCyclePoint(x, y, z); + } else { + writeBlock( + gRetractModal.format(98), gCycleModal.format(83), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + peckOutput.format(cycle.incrementalDepth), + // conditional(P > 0, "P" + milliFormat.format(P)), + feedOutput.format(F) + ); + } + break; + case "tapping": + if (getProperty("useRigidTapping") != "no") { + writeBlock(mFormat.format(29), sOutput.format(spindleSpeed)); + } + if (getProperty("usePitchForTapping")) { + writeBlock( + gRetractModal.format(98), gFeedModeModal.format(95), gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND) ? 74 : 84), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), + pitchOutput.format(tool.threadPitch) + ); + forceFeed(); + } else { + var tappingFPM = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); + F = (getProperty("useG95") ? tool.getThreadPitch() : tappingFPM); + writeBlock( + gRetractModal.format(98), gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND) ? 74 : 84), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), + feedOutput.format(F) + ); + } + break; + case "left-tapping": + if (getProperty("useRigidTapping") != "no") { + writeBlock(mFormat.format(29), sOutput.format(spindleSpeed)); + } + if (getProperty("usePitchForTapping")) { + writeBlock( + gRetractModal.format(98), gFeedModeModal.format(95), gCycleModal.format(74), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), + pitchOutput.format(tool.threadPitch) + ); + forceFeed(); + } else { + var tappingFPM = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); + F = (getProperty("useG95") ? tool.getThreadPitch() : tappingFPM); + writeBlock( + gRetractModal.format(98), gCycleModal.format(74), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), + feedOutput.format(F) + ); + } + break; + case "right-tapping": + if (getProperty("useRigidTapping") != "no") { + writeBlock(mFormat.format(29), sOutput.format(spindleSpeed)); + } + if (getProperty("usePitchForTapping")) { + writeBlock( + gRetractModal.format(98), gFeedModeModal.format(95), gCycleModal.format(84), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), + pitchOutput.format(tool.threadPitch) + ); + forceFeed(); + } else { + var tappingFPM = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); + F = (getProperty("useG95") ? tool.getThreadPitch() : tappingFPM); + writeBlock( + gRetractModal.format(98), gCycleModal.format(84), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), + feedOutput.format(F) + ); + } + break; + case "tapping-with-chip-breaking": + case "left-tapping-with-chip-breaking": + case "right-tapping-with-chip-breaking": + if (cycle.accumulatedDepth < cycle.depth) { + error(localize("Accumulated pecking depth is not supported for tapping cycles with chip breaking.")); + return; + } else { + if (getProperty("useRigidTapping") != "no") { + writeBlock(mFormat.format(29), sOutput.format(spindleSpeed)); + } + if (getProperty("usePitchForTapping")) { + writeBlock( + gRetractModal.format(98), gFeedModeModal.format(95), gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND ? 74 : 84)), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), + peckOutput.format(cycle.incrementalDepth), + pitchOutput.format(tool.threadPitch) + ); + forceFeed(); + } else { + var tappingFPM = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); + F = (getProperty("useG95") ? tool.getThreadPitch() : tappingFPM); + writeBlock( + gRetractModal.format(98), gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND ? 74 : 84)), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), + peckOutput.format(cycle.incrementalDepth), + feedOutput.format(F) + ); + } + } + break; + case "fine-boring": + writeBlock( + gRetractModal.format(98), gCycleModal.format(76), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), // not optional + "Q" + xyzFormat.format(cycle.shift), + feedOutput.format(F) + ); + break; + case "back-boring": + var dx = (gPlaneModal.getCurrent() == 19) ? cycle.backBoreDistance : 0; + var dy = (gPlaneModal.getCurrent() == 18) ? cycle.backBoreDistance : 0; + var dz = (gPlaneModal.getCurrent() == 17) ? cycle.backBoreDistance : 0; + writeBlock( + gRetractModal.format(98), gCycleModal.format(87), + getCommonCycle(x - dx, y - dy, z - dz, cycle.bottom, cycle.clearance), + "Q" + xyzFormat.format(cycle.shift), + "P" + milliFormat.format(P), // not optional + feedOutput.format(F) + ); + break; + case "reaming": + if (feedFormat.getResultingValue(cycle.feedrate) != feedFormat.getResultingValue(cycle.retractFeedrate)) { + expandCyclePoint(x, y, z); + break; + } + if (P > 0) { + writeBlock( + gRetractModal.format(98), gCycleModal.format(89), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), + feedOutput.format(F) + ); + } else { + writeBlock( + gRetractModal.format(98), gCycleModal.format(85), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + feedOutput.format(F) + ); + } + break; + case "stop-boring": + if (P > 0) { + expandCyclePoint(x, y, z); + } else { + writeBlock( + gRetractModal.format(98), gCycleModal.format(86), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + feedOutput.format(F) + ); + } + break; + case "manual-boring": + writeBlock( + gRetractModal.format(98), gCycleModal.format(88), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), // not optional + feedOutput.format(F) + ); + break; + case "boring": + if (feedFormat.getResultingValue(cycle.feedrate) != feedFormat.getResultingValue(cycle.retractFeedrate)) { + expandCyclePoint(x, y, z); + break; + } + if (P > 0) { + writeBlock( + gRetractModal.format(98), gCycleModal.format(89), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), // not optional + feedOutput.format(F) + ); + } else { + writeBlock( + gRetractModal.format(98), gCycleModal.format(85), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + feedOutput.format(F) + ); + } + break; + default: + expandCyclePoint(x, y, z); + } + if (subprogramsAreSupported()) { + // place cycle operation in subprogram + handleCycleSubprogram(new Vector(x, y, z), new Vector(0, 0, 0), false); + if (subprogramState.incrementalMode) { // set current position to clearance height + setCyclePosition(cycle.clearance); + } + } + } else { + if (cycleExpanded) { + expandCyclePoint(x, y, z); + } else { + if (!xyzFormat.areDifferent(x, xOutput.getCurrent()) && + !xyzFormat.areDifferent(y, yOutput.getCurrent()) && + !xyzFormat.areDifferent(z, zOutput.getCurrent())) { + switch (gPlaneModal.getCurrent()) { + case 17: // XY + xOutput.reset(); // at least one axis is required + break; + case 18: // ZX + zOutput.reset(); // at least one axis is required + break; + case 19: // YZ + yOutput.reset(); // at least one axis is required + break; + } + } + if (subprogramsAreSupported() && subprogramState.incrementalMode) { // set current position to retract height + setCyclePosition(cycle.retract); + } + writeBlock(xOutput.format(x), yOutput.format(y), zOutput.format(z)); + if (subprogramsAreSupported() && subprogramState.incrementalMode) { // set current position to clearance height + setCyclePosition(cycle.clearance); + } + } + } +} + +function getCommonCycle(x, y, z, r, c) { + forceXYZ(); // force xyz on first drill hole of any cycle + if (subprogramsAreSupported() && subprogramState.incrementalMode) { + zOutput.format(c); + return [xOutput.format(x), yOutput.format(y), + "Z" + xyzFormat.format(z - r), + "R" + xyzFormat.format(r - c)]; + } else { + return [xOutput.format(x), yOutput.format(y), + zOutput.format(z), + "R" + xyzFormat.format(r)]; + } +} +// <<<<< INCLUDED FROM include_files/drillCycles_fanuc.cpi +// >>>>> INCLUDED FROM include_files/commonInspectionFunctions_fanuc.cpi +var macroFormat = createFormat({prefix:(typeof inspectionVariables == "undefined" ? "#" : inspectionVariables.localVariablePrefix), decimals:0}); +var macroRoundingFormat = (unit == MM) ? "[53]" : "[44]"; +var isDPRNTopen = false; + +var WARNING_OUTDATED = 0; +var toolpathIdFormat = createFormat({decimals:5, forceDecimal:true}); +var patternInstances = new Array(); +var initializePatternInstances = true; // initialize patternInstances array the first time inspectionGetToolpathId is called +function inspectionGetToolpathId(section) { + if (initializePatternInstances) { + for (var i = 0; i < getNumberOfSections(); ++i) { + var _section = getSection(i); + if (_section.getInternalPatternId) { + var sectionId = _section.getId(); + var patternId = _section.getInternalPatternId(); + var isPatterned = _section.isPatterned && _section.isPatterned(); + var isMirrored = patternId != _section.getPatternId(); + if (isPatterned || isMirrored) { + var isKnownPatternId = false; + for (var j = 0; j < patternInstances.length; j++) { + if (patternId == patternInstances[j].patternId) { + patternInstances[j].patternIndex++; + patternInstances[j].sections.push(sectionId); + isKnownPatternId = true; + break; + } + } + if (!isKnownPatternId) { + patternInstances.push({patternId:patternId, patternIndex:1, sections:[sectionId]}); + } + } + } + } + initializePatternInstances = false; + } + + var _operationId = section.getParameter("autodeskcam:operation-id", ""); + var key = -1; + for (k in patternInstances) { + if (patternInstances[k].patternId == _operationId) { + key = k; + break; + } + } + var _patternId = (key > -1) ? patternInstances[key].sections.indexOf(section.getId()) + 1 : 0; + var _cycleId = cycle && ("cycleID" in cycle) ? cycle.cycleID : section.getParameter("cycleID", 0); + if (isProbeOperation(section) && _cycleId == 0 && getGlobalParameter("product-id").toLowerCase().indexOf("fusion") > -1) { + // we expect the cycleID to be non zero always for macro probing toolpaths, Fusion only + warningOnce(localize("Outdated macro probing operations detected. Please regenerate all macro probing operations."), WARNING_OUTDATED); + } + if (_patternId > 99) { + error(subst(localize("The maximum number of pattern instances is limited to 99" + EOL + + "You need to split operation '%1' into separate pattern groups." + ), section.getParameter("operation-comment", ""))); + } + if (_cycleId > 99) { + error(subst(localize("The maximum number of probing cycles is limited to 99" + EOL + + "You need to split operation '%1' to multiple operations with less than 100 cycles in each operation." + ), section.getParameter("operation-comment", ""))); + } + return toolpathIdFormat.format(_operationId + (_cycleId * 0.01) + (_patternId * 0.0001) + 0.00001); +} + +var localVariableStart = 19; +var localVariable = [ + macroFormat.format(localVariableStart + 1), + macroFormat.format(localVariableStart + 2), + macroFormat.format(localVariableStart + 3), + macroFormat.format(localVariableStart + 4), + macroFormat.format(localVariableStart + 5), + macroFormat.format(localVariableStart + 6) +]; + +function defineLocalVariable(indx, value) { + writeln(localVariable[indx - 1] + " = " + value); +} + +function formatLocalVariable(prefix, indx, rnd) { + return prefix + localVariable[indx - 1] + rnd; +} + +function inspectionCreateResultsFileHeader() { + if (isDPRNTopen) { + if (!getProperty("singleResultsFile")) { + writeln("DPRNT[END]"); + writeBlock("PCLOS"); + isDPRNTopen = false; + } + } + + if (isProbeOperation() && !printProbeResults()) { + return; // if print results is not desired by probe/ probeWCS + } + + if (!isDPRNTopen) { + writeBlock("PCLOS"); + writeBlock("POPEN"); + // check for existence of none alphanumeric characters but not spaces + var resFile; + if (getProperty("singleResultsFile")) { + resFile = getParameter("job-description") + "-RESULTS"; + } else { + resFile = getParameter("operation-comment") + "-RESULTS"; + } + resFile = resFile.replace(/:/g, "-"); + resFile = resFile.replace(/[^a-zA-Z0-9 -]/g, ""); + resFile = resFile.replace(/\s/g, "-"); + resFile = resFile.toUpperCase(); + writeln("DPRNT[START]"); + writeln("DPRNT[RESULTSFILE*" + resFile + "]"); + if (hasGlobalParameter("document-id")) { + writeln("DPRNT[DOCUMENTID*" + getGlobalParameter("document-id").toUpperCase() + "]"); + } + if (hasGlobalParameter("model-version")) { + writeln("DPRNT[MODELVERSION*" + getGlobalParameter("model-version").toUpperCase() + "]"); + } + } + if (isProbeOperation() && printProbeResults()) { + isDPRNTopen = true; + } +} + +function getPointNumber() { + if (typeof inspectionWriteVariables == "function") { + return (inspectionVariables.pointNumber); + } else { + return ("#122[60]"); + } +} + +function inspectionWriteCADTransform() { + var cadOrigin = currentSection.getModelOrigin(); + var cadWorkPlane = currentSection.getModelPlane().getTransposed(); + var cadEuler = cadWorkPlane.getEuler2(EULER_XYZ_S); + defineLocalVariable(1, abcFormat.format(cadEuler.x)); + defineLocalVariable(2, abcFormat.format(cadEuler.y)); + defineLocalVariable(3, abcFormat.format(cadEuler.z)); + defineLocalVariable(4, xyzFormat.format(-cadOrigin.x)); + defineLocalVariable(5, xyzFormat.format(-cadOrigin.y)); + defineLocalVariable(6, xyzFormat.format(-cadOrigin.z)); + /* writeln( + "DPRNT[G331" + + "*N" + getPointNumber() + + formatLocalVariable("*A", 1, macroRoundingFormat) + + formatLocalVariable("*B", 2, macroRoundingFormat) + + formatLocalVariable("*C", 3, macroRoundingFormat) + + formatLocalVariable("*X", 4, macroRoundingFormat) + + formatLocalVariable("*Y", 5, macroRoundingFormat) + + formatLocalVariable("*Z", 6, macroRoundingFormat) + + "]" + ); */ //KC removed +} + +function inspectionWriteWorkplaneTransform() { + var orientation = machineConfiguration.isMultiAxisConfiguration() ? machineConfiguration.getOrientation(getCurrentDirection()) : currentSection.workPlane; + var abc = orientation.getEuler2(EULER_XYZ_S); + if (getProperty("useLiveConnection")) { + liveConnectorInterface("WORKPLANE"); + writeBlock(inspectionVariables.liveConnectionWPA, "=", abcFormat.format(abc.x)); + writeBlock(inspectionVariables.liveConnectionWPB, "=", abcFormat.format(abc.y)); + writeBlock(inspectionVariables.liveConnectionWPC, "=", abcFormat.format(abc.z)); + forceSequenceNumbers(true); + writeBlock("IF [" + inspectionVariables.workplaneStartAddress, "NE -1] GOTO" + skipNLines(2)); + writeBlock(inspectionVariables.workplaneStartAddress, "=", inspectionGetToolpathId(currentSection)); + writeBlock(" "); + forceSequenceNumbers(false); + } + + defineLocalVariable(1, abcFormat.format(abc.x)); + defineLocalVariable(2, abcFormat.format(abc.y)); + defineLocalVariable(3, abcFormat.format(abc.z)); + writeln("DPRNT[G330" + + "*N" + getPointNumber() + + formatLocalVariable("*A", 1, macroRoundingFormat) + + formatLocalVariable("*B", 2, macroRoundingFormat) + + formatLocalVariable("*C", 3, macroRoundingFormat) + + "*X0*Y0*Z0*I0*R0]" + ); +} + +function writeProbingToolpathInformation(cycleDepth) { + defineLocalVariable(1, inspectionGetToolpathId(currentSection)); + //writeln(formatLocalVariable("DPRNT[TOOLPATHID*", 1, "[35]]")); KC removed + if (isInspectionOperation()) { + writeln("DPRNT[TOOLPATH*" + getParameter("operation-comment").toUpperCase().replace(/[()]/g, "") + "]"); + } else { + defineLocalVariable(2, xyzFormat.format(cycleDepth)); + //writeln(formatLocalVariable("DPRNT[CYCLEDEPTH*", 2, macroRoundingFormat + "]")); KC removed + } +} +// <<<<< INCLUDED FROM include_files/commonInspectionFunctions_fanuc.cpi +// >>>>> INCLUDED FROM include_files/probeCycles_renishaw.cpi +validate(settings.probing, "Setting 'probing' is required but not defined."); +var probeVariables = { + outputRotationCodes: false, // determines if it is required to output rotation codes + compensationXY : undefined, + probeAngleMethod : undefined, + rotaryTableAxis : -1 +}; +function writeProbeCycle(cycle, x, y, z, P, F) { + var openString = "OPEN[0,1,\"" + programName + "_inspection_report" + "_@980" + "_@981" + "_@982" + "_@983" + "_@984" + "_@985" + "\"]"; + var probeWorkOffsetCode; + + if (isProbeOperation()) { + if (!settings.workPlaneMethod.useTiltedWorkplane && !isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, 1))) { + if (!settings.probing.allowIndexingWCSProbing && currentSection.strategy == "probe") { + error(localize("Updating WCS / work offset using probing is only supported by the CNC in the WCS frame.")); + return; + } + } + + var workOffset = probeOutputWorkOffset ? probeOutputWorkOffset : currentWorkOffset; + if (workOffset > 106) { + error(localize("Work offset is out of range." + workOffset)); + return; + } else { + probeWorkOffsetCode = workOffset; + } + + if (printProbeResults()) { + //writeProbingToolpathInformation(z - cycle.depth + tool.diameter / 2); //#20 #21 + //inspectionWriteCADTransform(); // #20 21 22 23 24 25 + //inspectionWriteWorkplaneTransform(); 20 21 22 and dprnt line + if (typeof inspectionWriteVariables == "function") { + inspectionVariables.pointNumber += 1; + } + } + //protectedProbeMove(cycle, x, y, z); // removed as added extra unrequied moves + } + + //var macroCall = settings.probing.macroCall; // moved up above onSection() + switch (cycleType) { + case "probing-x": + //forceXYZ(); + protectedProbeMove(cycle, x, y, z - cycle.depth); + + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + EXPECTED_Y = yOutput.format(y + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)); + EXPECTED_X = xOutput.format(x + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)); + //EXPECTED_Y = "Y" + xyzFormat.format(y + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)); // KC to sort + //EXPECTED_X = "X" + xyzFormat.format(x + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)); + EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); + DISTANCE = approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2 + cycle.probeOvertravel); + B_ARG = "B" + xyzFormat.format(DISTANCE); + + writeBlock(macroCall, "\"PROBEX\"", WCS_CODE[7], WCS_CODE[8], B_ARG); + writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V1", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + + if (WCS_CODE[7] === "I1.") { + writeBlock(openString); + writeBlock("PRINT[\"Probed x point: @996\"]"); + writeBlock("CLOSE[]"); + } + break; + case "probing-y": + //forceXYZ(); + protectedProbeMove(cycle, x, y, z - cycle.depth); + + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + EXPECTED_Y = "Y" + xyzFormat.format(y + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)); // yOutput.format + EXPECTED_X = "X" + xyzFormat.format(x + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)); // xOutput.format + EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); + DISTANCE = approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2 + cycle.probeOvertravel); + B_ARG = "B" + xyzFormat.format(DISTANCE); + + writeBlock(macroCall, "\"PROBEY\"", WCS_CODE[7], WCS_CODE[8], B_ARG); + writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V2", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + + if (WCS_CODE[7] === "I1.") { + writeBlock(openString); + writeBlock("PRINT[\"Probed y point: @996\"]"); + writeBlock("CLOSE[]"); + } + break; + case "probing-z": + //forceXYZ(); // KC adds go to zero probe pos moves before but would need to drop out entry moves above + protectedProbeMove(cycle, x, y, z); + + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + EXPECTED_X = "X" + xyzFormat.format(x); // xOutput.format(x); + EXPECTED_Y = "Y" + xyzFormat.format(y); // yOutput.format(y); + EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); + B_ARG = "B" + xyzFormat.format(-cycle.depth - cycle.probeOvertravel); + + writeBlock(macroCall, "\"PROBEZ\"", WCS_CODE[7], WCS_CODE[8], B_ARG); + writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V3", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + + if (WCS_CODE[7] === "I1.") { + open_string = "OPEN[0,1,\"" + programName + "_inspection_report" + "_@980" + "_@981" + "_@982" + "_@983" + "_@984" + "_@985" +"\"]"; + writeBlock(open_string); + writeBlock('PRINT["Probed Z point: @996"]'); + writeBlock('CLOSE[]'); + /*writeBlock("PRINT[\"PROBED Z POINT: @996\"]"); + writeBlock("CLOSE[]"); */ + } + break; + case "probing-x-wall": + //forceXYZ(); + protectedProbeMove(cycle, x, y, z); + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + WEB_WIDTH = "B" + xyzFormat.format(cycle.width1); + Z_DROP = "C" + xyzFormat.format(cycle.depth); + + writeBlock(macroCall, "\"PROBEXWEB\"", WCS_CODE[7], WCS_CODE[8], WEB_WIDTH, Z_DROP, WCS_CODE[10], WCS_CODE[2]); + + if (WCS_CODE[7] === "I1.") { + writeBlock(openString); + writeBlock("PRINT[\"Measured X web width: @998\"]"); + writeBlock("CLOSE[]"); + } + break; + case "probing-y-wall": + //forceXYZ(); + protectedProbeMove(cycle, x, y, z); + + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + WEB_WIDTH = "B" + xyzFormat.format(cycle.width1); + Z_DROP = "C" + xyzFormat.format(cycle.depth); + + writeBlock(macroCall, "\"PROBEYWEB\"", WCS_CODE[7], WCS_CODE[8], WEB_WIDTH, Z_DROP, WCS_CODE[10], WCS_CODE[2]); + + if (WCS_CODE[7] === "I1.") { + writeBlock(openString); + writeBlock("PRINT[\"Measured Y web width: @999\"]"); + writeBlock("CLOSE[]"); + } + break; + case "probing-x-channel": + //forceXYZ(); + protectedProbeMove(cycle, x, y, z - cycle.depth); + + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + SLOT_WIDTH = "B" + xyzFormat.format(cycle.width1); + + writeBlock(macroCall, "\"PROBEXSLOT\"", WCS_CODE[7], WCS_CODE[8], SLOT_WIDTH, WCS_CODE[10], WCS_CODE[2]); + + if (WCS_CODE[7] === "I1.") { + writeBlock(openString); + writeBlock("PRINT[\"MEASURED X SLOT WIDTH: @998\"]"); + writeBlock("CLOSE[]"); + } + break; + case "probing-x-channel-with-island": + error(localize("probing-x-channel-with-island is unsupported")); + /*protectedProbeMove(cycle, x, y, z); + writeBlock( + macroCall, "P" + 9812, + "X" + xyzFormat.format(cycle.width1), + zOutput.format(z - cycle.depth), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(-cycle.probeClearance), + getProbingArguments(cycle, true) + ); */ + break; + case "probing-y-channel": + //forceXYZ(); + protectedProbeMove(cycle, x, y, z - cycle.depth); + + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + SLOT_WIDTH = "B" + xyzFormat.format(cycle.width1); + + writeBlock(macroCall, "\"PROBEYSLOT\"", WCS_CODE[7], WCS_CODE[8], SLOT_WIDTH, WCS_CODE[10], WCS_CODE[2]); + + if (WCS_CODE[7] === "I1.") { + writeBlock(openString); + writeBlock("PRINT[\"Measured Y slot width: @999\"]"); + writeBlock("CLOSE[]"); + } + break; + case "probing-y-channel-with-island": + error(localize("probing-y-channel-with-island is unsupported")); + /*protectedProbeMove(cycle, x, y, z); + writeBlock( + macroCall, "P" + 9812, + "Y" + xyzFormat.format(cycle.width1), + zOutput.format(z - cycle.depth), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(-cycle.probeClearance), + getProbingArguments(cycle, true) + ); */ + break; + case "probing-xy-circular-boss": + forceXYZ(); + protectedProbeMove(cycle, x, y, z); + + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + BOSS_DIAMETER = "B" + xyzFormat.format(cycle.width1); + Z_DROP = "C" + xyzFormat.format(cycle.depth); + EXPECTED_X = "X" + xyzFormat.format(x); //xOutput.format + EXPECTED_Y = "Y" + xyzFormat.format(y); //yOutput.format + EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); + + writeBlock(macroCall, "\"PROBECIRCULARBOSS\"", WCS_CODE[7], WCS_CODE[8], BOSS_DIAMETER, Z_DROP, WCS_CODE[10], WCS_CODE[2]); + writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V4", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + if (getProperty("EnableZeroPointCompensation") == true && WCS_CODE[7] === null) { + writeBlock(macroCall, "\"COMPZEROPOINT\"", WCS_CODE[8], WCS_CODE[9], EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + } + + if (WCS_CODE[7] === "I1.") { + writeBlock(openString); + writeBlock("PRINT[\"Measured circular boss diameter " + (unit==MM?"mm":"in") + " X: @998\"]"); + writeBlock("PRINT[\"Measured circular boss diameter " + (unit==MM?"mm":"in") + " Y: @999\"]"); + writeBlock("PRINT[\"Measured circular boss avg diameter : @997\"]"); + writeBlock("CLOSE[]"); + } + break; + case "probing-xy-circular-partial-boss": + error(localize("probing-xy-circular-partial-boss is unsupported")); + /*protectedProbeMove(cycle, x, y, z); + writeBlock( + macroCall, "P" + 9823, + "A" + xyzFormat.format(cycle.partialCircleAngleA), + "B" + xyzFormat.format(cycle.partialCircleAngleB), + "C" + xyzFormat.format(cycle.partialCircleAngleC), + "D" + xyzFormat.format(cycle.width1), + "Z" + xyzFormat.format(z - cycle.depth), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(cycle.probeClearance), + getProbingArguments(cycle, true) + ); */ + break; + case "probing-xy-circular-hole": + //forceXYZ(); + protectedProbeMove(cycle, x, y, z - cycle.depth); + + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + BORE_DIAMETER = "B" + xyzFormat.format(cycle.width1); + EXPECTED_X = "X" + xyzFormat.format(x); //xOutput.format + EXPECTED_Y = "Y" + xyzFormat.format(y); //yOutput.format + EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); + + writeBlock(macroCall, "\"PROBEBORE\"", WCS_CODE[7], WCS_CODE[8], BORE_DIAMETER, WCS_CODE[10], WCS_CODE[2]); + writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V4", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + if (getProperty("EnableZeroPointCompensation") == true && WCS_CODE[7] === null) { + writeBlock(macroCall, "\"COMPZEROPOINT\"", WCS_CODE[8], WCS_CODE[9], EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + } + + if (WCS_CODE[7] === "I1.") { + writeBlock(openString); + writeBlock("PRINT[\"Measured bore diameter " + (unit==MM?"mm":"IN") + " X: @998\"]"); + writeBlock("PRINT[\"Measured bore diameter " + (unit==MM?"mm":"IN") + " Y: @999\"]"); + writeBlock("PRINT[\"Measured bore avg diameter : @997\"]"); + writeBlock("CLOSE[]"); + } + break; + case "probing-xy-circular-partial-hole": + error(localize("probing-xy-circular-partial-hole is unsupported")); + /* protectedProbeMove(cycle, x, y, z - cycle.depth); + writeBlock( + macroCall, "P" + 9823, + "A" + xyzFormat.format(cycle.partialCircleAngleA), + "B" + xyzFormat.format(cycle.partialCircleAngleB), + "C" + xyzFormat.format(cycle.partialCircleAngleC), + "D" + xyzFormat.format(cycle.width1), + "Q" + xyzFormat.format(cycle.probeOvertravel), + getProbingArguments(cycle, true) + ); */ + break; + case "probing-xy-circular-hole-with-island": + error(localize("probing-xy-circular-hole-with-island is unsupported")); + /* protectedProbeMove(cycle, x, y, z); + writeBlock( + macroCall, "P" + 9814, + "Z" + xyzFormat.format(z - cycle.depth), + "D" + xyzFormat.format(cycle.width1), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(-cycle.probeClearance), + getProbingArguments(cycle, true) + ); */ + break; + case "probing-xy-circular-partial-hole-with-island": + error(localize("probing-xy-circular-partial-hole-with-island is unsupported")); + /* protectedProbeMove(cycle, x, y, z); + writeBlock( + macroCall, "P" + 9823, + "Z" + xyzFormat.format(z - cycle.depth), + "A" + xyzFormat.format(cycle.partialCircleAngleA), + "B" + xyzFormat.format(cycle.partialCircleAngleB), + "C" + xyzFormat.format(cycle.partialCircleAngleC), + "D" + xyzFormat.format(cycle.width1), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(-cycle.probeClearance), + getProbingArguments(cycle, true) + ); */ + break; + case "probing-xy-rectangular-hole": + //forceXYZ(); + protectedProbeMove(cycle, x, y, z - cycle.depth); + + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + XWEB_WIDTH = "B" + xyzFormat.format(cycle.width1); + YWEB_WIDTH = "C" + xyzFormat.format(cycle.width2); + EXPECTED_X = "X" + xyzFormat.format(x); //xOutput.format + EXPECTED_Y = "Y" + xyzFormat.format(y); //yOutput.format + EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); + + writeBlock(macroCall, "\"PROBEPOCKET\"", WCS_CODE[7], WCS_CODE[8], XWEB_WIDTH, YWEB_WIDTH, WCS_CODE[10], WCS_CODE[2]); + writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V4", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + if (getProperty("EnableZeroPointCompensation") == true && WCS_CODE[7] === null) { + writeBlock(macroCall, "\"COMPZEROPOINT\"", WCS_CODE[8], WCS_CODE[9], EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + } + + if (WCS_CODE[7] === "I1.") { + writeBlock(openString); + writeBlock("PRINT[\"Measured pocket length " + (unit==MM?"mm":"in") + " X: @998\"]"); + writeBlock("PRINT[\"Measured pocket width " + (unit==MM?"mm":"in") + " Y: @999\"]"); + writeBlock("CLOSE[]"); + } + break; + case "probing-xy-rectangular-boss": + //forceXYZ(); // may not be requied as alread at location in initial move above KC to sort + protectedProbeMove(cycle, x, y, z); + + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + XWEB_WIDTH = "B" + xyzFormat.format(cycle.width1); + YWEB_WIDTH = "C" + xyzFormat.format(cycle.width2); + EXPECTED_X = "X" + xyzFormat.format(x); //xOutput.format + EXPECTED_Y = "Y" + xyzFormat.format(y); //yOutput.format + EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); + Z_DROP = "D" + xyzFormat.format(cycle.depth); + + writeBlock(macroCall, "\"PROBERECTANGULARBOSS\"", WCS_CODE[7], WCS_CODE[8], XWEB_WIDTH, YWEB_WIDTH, Z_DROP, WCS_CODE[10], WCS_CODE[2]); + writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V4", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + if (getProperty("EnableZeroPointCompensation") == true && WCS_CODE[7] === null) { + writeBlock(macroCall, "\"COMPZEROPOINT\"", WCS_CODE[8], WCS_CODE[9], EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + } + + if (WCS_CODE[7] === "I1.") { + writeBlock(openString); + writeBlock("PRINT[\"Measured rectangular boss length " + (unit==MM?"mm":"in") + " X: @998\"]"); + writeBlock("PRINT[\"Measured rectangular boss width " + (unit==MM?"mm":"in") + " Y: @999\"]"); + writeBlock("CLOSE[]"); + } + break; + case "probing-xy-rectangular-hole-with-island": + error(localize("probing-xy-rectangular-hole-with-island is unsupported")); + /* protectedProbeMove(cycle, x, y, z); + writeBlock( + macroCall, "P" + 9812, + "Z" + xyzFormat.format(z - cycle.depth), + "X" + xyzFormat.format(cycle.width1), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(-cycle.probeClearance), + getProbingArguments(cycle, true) + ); + if (getProperty("useLiveConnection") && (typeof liveConnectionStoreResults == "function")) { + liveConnectionStoreResults(); + } + writeBlock( + macroCall, "P" + 9812, + "Z" + xyzFormat.format(z - cycle.depth), + "Y" + xyzFormat.format(cycle.width2), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(-cycle.probeClearance), + getProbingArguments(cycle, true) + ); */ + break; + + case "probing-xy-inner-corner": + /* var cornerX = x + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2); + var cornerY = y + approach(cycle.approach2) * (cycle.probeClearance + tool.diameter / 2); + var cornerI = 0; + var cornerJ = 0; + if (cycle.probeSpacing !== undefined) { + cornerI = cycle.probeSpacing; + cornerJ = cycle.probeSpacing; + } + if ((cornerI != 0) && (cornerJ != 0)) { + g68RotationMode = 2; + } */ + //forceXYZ(); + + protectedProbeMove(cycle, x, y, z - cycle.depth); + xdir = approach(cycle.approach1); + ydir = approach(cycle.approach2); + var CORNER_NUM = 0; + if (xdir == 1 && ydir == 1) {CORNER_NUM = 2;} else if (xdir == 1 && ydir == -1) {CORNER_NUM = 4;} else if (xdir == -1 && ydir == 1) {CORNER_NUM = 1;} else if (xdir == -1 && ydir == -1) {CORNER_NUM = 3;} + + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + CORNER_POSITION = "B" + CORNER_NUM; + PROBING_DISTANCE = "C" + xyzFormat.format(cycle.probeClearance + cycle.probeOvertravel); + + writeBlock(macroCall, "\"PROBEINSIDECORNER\"", WCS_CODE[8], CORNER_POSITION, PROBING_DISTANCE, WCS_CODE[10]); + break; + case "probing-xy-outer-corner": + //forceXYZ(); + protectedProbeMove(cycle, x, y, z - cycle.depth); + xdir = approach(cycle.approach1); + ydir = approach(cycle.approach2); + var CORNER_NUM = 0; + if (xdir == 1 && ydir == 1) {CORNER_NUM = 3;} else if (xdir == 1 && ydir == -1) {CORNER_NUM = 1;} else if (xdir == -1 && ydir == 1) {CORNER_NUM = 4;} else if (xdir == -1 && ydir == -1) {CORNER_NUM = 2;} + + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + CORNER_POSITION = "B" + CORNER_NUM; + TRAVEL_DISTANCE = "C" + xyzFormat.format(2 * cycle.probeClearance + tool.diameter / 2); + PROBING_DISTANCE = "D" + xyzFormat.format(cycle.probeClearance + cycle.probeOvertravel); + + writeBlock(macroCall, "\"PROBEOUTSIDECORNER\"", + WCS_CODE[8], + CORNER_POSITION, + TRAVEL_DISTANCE, + PROBING_DISTANCE, "Q0"); + break; + case "probing-x-plane-angle": + error(localize("probing-x-plane-angle - Unsupported Probing Cycle")); + /*protectedProbeMove(cycle, x, y, z - cycle.depth); + writeBlock( + macroCall, "P" + 9843, + "X" + xyzFormat.format(x + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)), + "D" + xyzFormat.format(cycle.probeSpacing), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "A" + xyzFormat.format(cycle.nominalAngle != undefined ? cycle.nominalAngle : 90), + getProbingArguments(cycle, false) + ); + if (currentSection.strategy == "probe") { + setProbeAngleMethod(); + probeVariables.compensationXY = "X" + xyzFormat.format(0) + " Y" + xyzFormat.format(0); + } */ + break; + case "probing-y-plane-angle": + error(localize("probing-y-plane-angle - Unsupported Probing Cycle")); + /* protectedProbeMove(cycle, x, y, z - cycle.depth); + writeBlock( + macroCall, "P" + 9843, + "Y" + xyzFormat.format(y + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)), + "D" + xyzFormat.format(cycle.probeSpacing), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "A" + xyzFormat.format(cycle.nominalAngle != undefined ? cycle.nominalAngle : 0), + getProbingArguments(cycle, false) + ); + if (currentSection.strategy == "probe") { + setProbeAngleMethod(); + probeVariables.compensationXY = "X" + xyzFormat.format(0) + " Y" + xyzFormat.format(0); + } */ + break; + case "probing-xy-pcd-hole": + error(localize("probing-xy-pcd-hole - Unsupported Probing Cycle")); + /* protectedProbeMove(cycle, x, y, z); + writeBlock( + macroCall, "P" + 9819, + "A" + xyzFormat.format(cycle.pcdStartingAngle), + "B" + xyzFormat.format(cycle.numberOfSubfeatures), + "C" + xyzFormat.format(cycle.widthPCD), + "D" + xyzFormat.format(cycle.widthFeature), + "K" + xyzFormat.format(z - cycle.depth), + "Q" + xyzFormat.format(cycle.probeOvertravel), + getProbingArguments(cycle, false) + ); + if (cycle.updateToolWear) { + error(localize("Action -Update Tool Wear- is not supported with this cycle.")); + return; + } */ + break; + case "probing-xy-pcd-boss": + error(localize("probing-xy-pcd-boss - Unsupported Probing Cycle")); + /* protectedProbeMove(cycle, x, y, z); + writeBlock( + macroCall, "P" + 9819, + "A" + xyzFormat.format(cycle.pcdStartingAngle), + "B" + xyzFormat.format(cycle.numberOfSubfeatures), + "C" + xyzFormat.format(cycle.widthPCD), + "D" + xyzFormat.format(cycle.widthFeature), + "Z" + xyzFormat.format(z - cycle.depth), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(cycle.probeClearance), + getProbingArguments(cycle, false) + ); + if (cycle.updateToolWear) { + error(localize("Action -Update Tool Wear- is not supported with this cycle.")); + return; + } */ + break; + } +} + +function printProbeResults() { + return currentSection.getParameter("printResults", 0) == 1; +} + +/** Convert approach to sign. */ +function approach(value) { + validate((value == "positive") || (value == "negative"), "Invalid approach."); + return (value == "positive") ? 1 : -1; +} +// <<<<< INCLUDED FROM include_files/probeCycles_renishaw.cpi +// >>>>> INCLUDED FROM include_files/getProbingArguments_renishaw.cpi +/* function getProbingArguments(cycle, updateWCS) { // new Autodesk function + var outputWCSCode = updateWCS && currentSection.strategy == "probe"; + if (outputWCSCode) { + var maximumWcsNumber = 0; + for (var i in wcsDefinitions.wcs) { + maximumWcsNumber = Math.max(maximumWcsNumber, wcsDefinitions.wcs[i].range[1]); + } + maximumWcsNumber = probeExtWCSFormat.getResultingValue(maximumWcsNumber); + var resultingWcsNumber = probeExtWCSFormat.getResultingValue(currentSection.probeWorkOffset - 6); + validate(resultingWcsNumber <= maximumWcsNumber, subst("Probe work offset %1 is out of range, maximum value is %2.", resultingWcsNumber, maximumWcsNumber)); + var probeOutputWorkOffset = currentSection.probeWorkOffset > 6 ? probeExtWCSFormat.format(currentSection.probeWorkOffset - 6) : probeWCSFormat.format(currentSection.probeWorkOffset); + + var nextWorkOffset = hasNextSection() ? getNextSection().workOffset == 0 ? 1 : getNextSection().workOffset : -1; + if (currentSection.probeWorkOffset == nextWorkOffset) { + currentWorkOffset = undefined; + } + } + return [ + (cycle.angleAskewAction == "stop-message" ? "B" + xyzFormat.format(cycle.toleranceAngle ? cycle.toleranceAngle : 0) : undefined), + ((cycle.updateToolWear && cycle.toolWearErrorCorrection < 100) ? "F" + xyzFormat.format(cycle.toolWearErrorCorrection ? cycle.toolWearErrorCorrection / 100 : 100) : undefined), + (cycle.wrongSizeAction == "stop-message" ? "H" + xyzFormat.format(cycle.toleranceSize ? cycle.toleranceSize : 0) : undefined), + (cycle.outOfPositionAction == "stop-message" ? "M" + xyzFormat.format(cycle.tolerancePosition ? cycle.tolerancePosition : 0) : undefined), + ((cycle.updateToolWear && cycleType == "probing-z") ? "T" + xyzFormat.format(cycle.toolLengthOffset) : undefined), + ((cycle.updateToolWear && cycleType !== "probing-z") ? "T" + xyzFormat.format(cycle.toolDiameterOffset) : undefined), + (cycle.updateToolWear ? "V" + xyzFormat.format(cycle.toolWearUpdateThreshold ? cycle.toolWearUpdateThreshold : 0) : undefined), + (cycle.printResults ? "W" + xyzFormat.format(1 + cycle.incrementComponent) : undefined), // 1 for advance feature, 2 for reset feature count and advance component number. first reported result in a program should use W2. + conditional(outputWCSCode, probeOutputWorkOffset) + ]; +} */ +function getProbingArguments(cycle, probeWorkOffsetCode) { // Old Toolpath Syil function + var probeWCS = hasParameter("operation-strategy") && (getParameter("operation-strategy") == "probe"); + + var PROBE_ARGS = ""; + if (probeOutputWorkOffset <= 6) { + var WCS_NUM = 53 + probeOutputWorkOffset; + PROBE_ARGS = "A" + WCS_NUM; + } else { + var WCS_NUM = probeOutputWorkOffset - 6; + if (WCS_NUM >= 10) { + PROBE_ARGS = "A54." + WCS_NUM; + } else { + PROBE_ARGS = "A54.0" + WCS_NUM; + } + } + + var PROBE_OVERRIDE_ARGS = ""; + if (currentWorkOffset <= 6) { + var WCS_NUM = 53 + currentWorkOffset; + PROBE_OVERRIDE_ARGS = "B" + WCS_NUM; + } else { + var WCS_NUM = currentWorkOffset - 6; + if (WCS_NUM >= 10) { + PROBE_OVERRIDE_ARGS = "B54." + WCS_NUM; + } else { + PROBE_OVERRIDE_ARGS = "B54.0" + WCS_NUM; + } + } + + return [ + (cycle.angleAskewAction == "stop-message" ? "B" + xyzFormat.format(cycle.toleranceAngle ? cycle.toleranceAngle : 0) : undefined), + ((cycle.updateToolWear && cycle.toolWearErrorCorrection < 100) ? "F" + xyzFormat.format(cycle.toolWearErrorCorrection ? cycle.toolWearErrorCorrection / 100 : 100) : undefined), + (cycle.wrongSizeAction == "stop-message" ? "R" + xyzFormat.format(cycle.toleranceSize ? cycle.toleranceSize : 0) + " S1" : undefined), + (cycle.outOfPositionAction == "stop-message" ? "T" + xyzFormat.format(cycle.tolerancePosition ? cycle.tolerancePosition : 0) + " U1" : undefined), + ((cycle.updateToolWear && cycleType == "probing-z") ? "T" + xyzFormat.format(cycle.toolLengthOffset) : undefined), + ((cycle.updateToolWear && cycleType !== "probing-z") ? "T" + xyzFormat.format(cycle.toolDiameterOffset) : undefined), + (cycle.updateToolWear ? "V" + xyzFormat.format(cycle.toolWearUpdateThreshold ? cycle.toolWearUpdateThreshold : 0) : undefined), + (cycle.printResults ? "I" + xyzFormat.format(1 + cycle.incrementComponent) : undefined), // 1 for advance feature, 2 for reset feature count and advance component number. first reported result in a program should use W2. + conditional(probeWorkOffsetCode && probeWCS, PROBE_ARGS), + conditional(probeWorkOffsetCode && probeWCS, PROBE_OVERRIDE_ARGS), + ("Q" + (getProperty("probeScreenPrint") ? 1 : 0)) + ]; +} +// <<<<< INCLUDED FROM include_files/getProbingArguments_renishaw.cpi +// >>>>> INCLUDED FROM include_files/protectedProbeMove_renishaw.cpi +function protectedProbeMove(_cycle, x, y, z) { + var _x = xOutput.format(x); + var _y = yOutput.format(y); + var _z = zOutput.format(z); + var macroCall = settings.probing.macroCall; + if (_z && z >= getCurrentPosition().z) { + writeBlock(macroCall, "\"PROTECTEDMOVE\"", _z, getFeed(cycle.feedrate)); // protected positioning move + } + if (_x || _y) { + writeBlock(macroCall, "\"PROTECTEDMOVE\"", _x, _y, getFeed(highFeedrate)); // protected positioning move + } + if (_z && z < getCurrentPosition().z) { + writeBlock(macroCall, "\"PROTECTEDMOVE\"", _z, getFeed(cycle.feedrate)); // protected positioning move + } +} +// <<<<< INCLUDED FROM include_files/protectedProbeMove_renishaw.cpi +// >>>>> INCLUDED FROM include_files/setProbeAngle_fanuc.cpi +function setProbeAngle() { + if (probeVariables.outputRotationCodes) { + validate(settings.probing.probeAngleVariables, localize("Setting 'probing.probeAngleVariables' is required for angular probing.")); + var probeAngleVariables = settings.probing.probeAngleVariables; + var px = probeAngleVariables.x; + var py = probeAngleVariables.y; + var pz = probeAngleVariables.z; + var pi = probeAngleVariables.i; + var pj = probeAngleVariables.j; + var pk = probeAngleVariables.k; + var pr = probeAngleVariables.r; + var baseParamG54x4 = probeAngleVariables.baseParamG54x4; + var baseParamAxisRot = probeAngleVariables.baseParamAxisRot; + //var probeOutputWorkOffset = currentSection.probeWorkOffset; // called above function onParameter() KC + + validate(probeOutputWorkOffset <= 6, "Angular Probing only supports work offsets 1-6."); + if (probeVariables.probeAngleMethod == "G68" && (Vector.diff(currentSection.getGlobalInitialToolAxis(), new Vector(0, 0, 1)).length > 1e-4)) { + error(localize("You cannot use multi axis toolpaths while G68 Rotation is in effect.")); + } + var validateWorkOffset = false; + switch (probeVariables.probeAngleMethod) { + case "G54.4": + var param = baseParamG54x4 + (probeOutputWorkOffset * 10); + writeBlock("#" + param + "=" + px); + writeBlock("#" + (param + 1) + "=" + py); + writeBlock("#" + (param + 5) + "=" + pr); + writeBlock(gFormat.format(54.4), "P" + probeOutputWorkOffset); + break; + case "G68": + gRotationModal.reset(); + gAbsIncModal.reset(); + var xy = probeVariables.compensationXY || formatWords(formatCompensationParameter("X", px), formatCompensationParameter("Y", py)); + writeBlock( + gRotationModal.format(68), gAbsIncModal.format(90), + xy, + formatCompensationParameter("Z", pz), + formatCompensationParameter("I", pi), + formatCompensationParameter("J", pj), + formatCompensationParameter("K", pk), + formatCompensationParameter("R", pr) + ); + validateWorkOffset = true; + break; + case "AXIS_ROT": + var param = baseParamAxisRot + probeOutputWorkOffset * 20 + probeVariables.rotaryTableAxis + 4; + writeBlock("#" + param + " = " + "[#" + param + " + " + pr + "]"); + forceWorkPlane(); // force workplane to rotate ABC in order to apply rotation offsets + currentWorkOffset = undefined; // force WCS output to make use of updated parameters + validateWorkOffset = true; + break; + default: + error(localize("Angular Probing is not supported for this machine configuration.")); + return; + } + if (validateWorkOffset) { + for (var i = currentSection.getId(); i < getNumberOfSections(); ++i) { + if (getSection(i).workOffset != currentSection.workOffset) { + error(localize("WCS offset cannot change while using angle rotation compensation.")); + return; + } + } + } + probeVariables.outputRotationCodes = false; + } +} + +function formatCompensationParameter(label, value) { + return typeof value == "string" ? label + "[" + value + "]" : typeof value == "number" ? label + xyzFormat.format(value) : ""; +} +// <<<<< INCLUDED FROM include_files/setProbeAngle_fanuc.cpi +// >>>>> INCLUDED FROM include_files/setProbeAngleMethod.cpi +function setProbeAngleMethod() { + var axisRotIsSupported = false; + var axes = [machineConfiguration.getAxisU(), machineConfiguration.getAxisV(), machineConfiguration.getAxisW()]; + for (var i = 0; i < axes.length; ++i) { + if (axes[i].isEnabled() && isSameDirection((axes[i].getAxis()).getAbsolute(), new Vector(0, 0, 1)) && axes[i].isTable()) { + axisRotIsSupported = true; + if (settings.probing.probeAngleVariables.method == 0) { // Fanuc + validate(i < 2, localize("Rotary table axis is invalid.")); + probeVariables.rotaryTableAxis = i; + } else { // Haas + probeVariables.rotaryTableAxis = axes[i].getCoordinate(); + } + break; + } + } + if (settings.probing.probeAngleMethod == undefined) { + probeVariables.probeAngleMethod = axisRotIsSupported ? "AXIS_ROT" : getProperty("useG54x4") ? "G54.4" : "G68"; // automatic selection + } else { + probeVariables.probeAngleMethod = settings.probing.probeAngleMethod; // use probeAngleMethod from settings + if (probeVariables.probeAngleMethod == "AXIS_ROT" && !axisRotIsSupported) { + error(localize("Setting probeAngleMethod 'AXIS_ROT' is not supported on this machine.")); + } + } + probeVariables.outputRotationCodes = true; +} +// <<<<< INCLUDED FROM include_files/setProbeAngleMethod.cpi + +var now = new Date(); // BJE \ No newline at end of file From f3e3c3703a8448eea7e2e64af0acd50198cd5244 Mon Sep 17 00:00:00 2001 From: Robot Oblivion Date: Wed, 2 Apr 2025 03:06:45 +1300 Subject: [PATCH 06/21] Patched a few bugs I came across when re-running the calibration macros. CALIBRATEPROBERING - fixed an error in the way A arguments to PROBEXSLOT were called PROBECONFIG - changed storage offset into the range protected by the PROBECONFIG macro settings (96+) TOOLSET, CALIBRATEZ, CALIBRATEPROBERING - Minor whitespace or wording adjustment --- CALIBRATEPROBERING | 13 ++++++------- CALIBRATEPROBEZ | 6 +++--- PROBECONFIG | 6 +++--- TOOLSET | 2 +- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/CALIBRATEPROBERING b/CALIBRATEPROBERING index 8586d74..999a865 100644 --- a/CALIBRATEPROBERING +++ b/CALIBRATEPROBERING @@ -1,7 +1,7 @@ // Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion // CALIBRATEPROBERING -// Calibrate the Diameter of the probe using a ring guage +// Calibrate the Diameter of the probe using a ring guage // Your probe must be concentric and you must use a ring guage!!!!!!!!!! // **Ring gauge ID set in ProbeConfig file @@ -16,19 +16,18 @@ M19 // ORIENT SPINDLE // important local variables #100 = @100 // TOOL NUMBER PROVIDED BY PROBECONFIG MACRO #129 = @129 // Calibrated ring gauge diameter provided by PROBECONFIG MACRO -#111 = @111 // EXTENDED WORKOFFSET that stores Z calibration (is not updated or rest) // Make sure diameter is zero when calibrating W_TOOL_DATA[0,#100,3,0] // store tool diameter +// G54 is used below to pass ProbeConfig WCS checks, but I1 calls ensure that G54 remains unchanged. // calling our slot macros the first time centers probe -G65 "PROBEXSLOT" A54 P#111 B#129 Q0 I1 -G65 "PROBEYSLOT" A54 P#111 B#129 Q0 I1 - +G65 "PROBEXSLOT" A54 B#129 Q0 I1 +G65 "PROBEYSLOT" A54 B#129 Q0 I1 // calling our slot macros a second time gives an accurate inspection -G65 "PROBEXSLOT" A54 P#111 B#129 Q0 I1 -G65 "PROBEYSLOT" A54 P#111 B#129 Q0 I1 +G65 "PROBEXSLOT" A#111 B#129 Q0 I1 +G65 "PROBEYSLOT" A#111 B#129 Q0 I1 // average Diameter calculation // @999 and @998 are set in the slot macros diff --git a/CALIBRATEPROBEZ b/CALIBRATEPROBEZ index 447669c..bd8d0aa 100644 --- a/CALIBRATEPROBEZ +++ b/CALIBRATEPROBEZ @@ -2,7 +2,7 @@ // CALIBRATEZ // THIS MACRO ASSUMES THAT YOU HAVE PUT YOUR GAUGE TOOL IN THE SPINDLE -// AND MANUALLY JOGGED UP TILL YOUR REFERENCE ARTIFACT CAN JUST BARELY SLIDE UNDER THE TOOL. +// AND positioned slightly above your REFERENCE ARTIFACT. // THE MACRO WILL SAVE THE XY LOCATION FOR FUTURE USE AND STORE THE REFERENCE HEIGHT OFFSET // Argument A -> #1 turns on/off full calibration: default is quick calibration @@ -26,7 +26,7 @@ G65 "PROBECONFIG" M19 // ORIENT SPINDLE IF [#1!=#0] - MSG_OK["Calibrate probe", "Zero master gauge tool on calibration artifact and leave it there", ""] + MSG_OK["Calibrate probe", "Switch to MPG mode and zero the master gauge tool on the calibration artifact. Only press Cycle Start when ready to proceed. The measured value will be stored in G@111", ""] @5109 = R_MACH_COOR[0,3] // GET MACHINE Z COORDINATE WHICH SHOULD BE THE TOP OF A 123 BLOCK #140 = @5109 @@ -48,7 +48,7 @@ G53 G90 G00 Z0 // BRING THE MACHINE UP TO TOOL CHANGE HEIGHT IF [#1!=#0] // TELL THE PERSON TO PUT THE PROBE INTO THE SPINDLE - MSG_OK["Install probe", "Switch to MPG mode and install the probe then switch back and hit cycle start; T#100", ""] + MSG_OK["Install probe", "Switch to MPG mode and install the probe (T@100). Then, switch back before pressing Cycle Start.", ""] END_IF G54 P#111 // LOCATION OF PROBE CALIBARTION IS X0 Y0 ON G54P#111 diff --git a/PROBECONFIG b/PROBECONFIG index 153b5c1..9b0465c 100644 --- a/PROBECONFIG +++ b/PROBECONFIG @@ -21,9 +21,9 @@ END_IF @102 = @101/2 // TOOL RADIUS, DO NOT TOUCH!!! @107 = [R_TOOL_DATA[0,@100,203]] // TOOL LENGHT OFFSET, DO NOT TOUCH!!! -@111 = 21 // EXTENDED WORKOFFSET TO STORE PROBE Z CALIBRATION LOCATION -@112 = 22 // EXTENDED WORKOFFSET TO STORE TOOLSETTER LOCATION -@113 = 23 // EXTENDED WORKOFFSET TO STORE THE 4TH COR PROBING START POINT +@111 = 97 // EXTENDED WORKOFFSET TO STORE PROBE Z CALIBRATION LOCATION +@112 = 98 // EXTENDED WORKOFFSET TO STORE TOOLSETTER LOCATION +@113 = 99 // EXTENDED WORKOFFSET TO STORE THE 4TH COR PROBING START POINT @110 = 1.0 // DEFAULT POSITION TOLERANCE @128 = 0 // ORIENT SPINDLE SWITCH 0=OFF 1=ON #137 = 95 // The highest WCS that can be used. Any above are protected from changes via these macros diff --git a/TOOLSET b/TOOLSET index 701d78c..fe50e66 100644 --- a/TOOLSET +++ b/TOOLSET @@ -23,7 +23,7 @@ G65 "PROBECONFIG" T#100 G90 G94 G17 G49 G40 G80 G53 G90 G00 Z0 // Move the spindle all the way up before xy movement for safety -G54P#112 // LOCATION OF TOOL SETTER IS X0 Y0 ON G54P100 +G54 P#112 // LOCATION OF TOOL SETTER IS X0 Y0 ON G54P100 G90 G0 X[0+#1/2] Y0 // MOVE TO TOOLSETTER + TOOL RADIUS OFFSET M20 // UNLOCK SPINDLE ORIENT From 46353d562c7febf2c35185dbe1db2e511cd4f203 Mon Sep 17 00:00:00 2001 From: Robot Oblivion Date: Wed, 2 Apr 2025 03:45:08 +1300 Subject: [PATCH 07/21] Helper NC file to help with probe and tool setter calibration . --- probingSetupHelp_v0.1.nc | 65 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 probingSetupHelp_v0.1.nc diff --git a/probingSetupHelp_v0.1.nc b/probingSetupHelp_v0.1.nc new file mode 100644 index 0000000..a9133ca --- /dev/null +++ b/probingSetupHelp_v0.1.nc @@ -0,0 +1,65 @@ +; Copyright 2025 Robot Oblivion + +; ProbingConfigHelper +; A NC program to suport the process of doing the first full probing calibration +; Initial Coding: Robot Oblivion + +; Before running, ensure the following: +; - backup your tool table, offset table and @1-200 variables in case of wanting to revert +; - Clear as many items as possible from the table to prevent collisions with stock, jigs, fixtures, or vices. +; - Ensure the table zero point is empty, lightly stoned, and free of coolant. +; - Have your master tool, probe, and ring gauge ready. +; - Set all user inputs in the ProbeConfig file. +; - copy all macro files CNC control +; - Copy the table zero point (XYZ) offsets to the extended work offsets that will store the calibration artifact location. +; - Find the tool setter's centre and zero out the extended work offsets that will store this location. + +G65 "PROBECONFIG" T1 + +G90 G94 G17 G49 G40 G80 +G53 G00 Z0 + +; toolchange to probe tool pocket +IF [@100 != R_SYS_INFO[0,2]] + G53 G00 X-390 Y0 + G65 "LOADTOOL" M0 T@100 +END_IF + +#96 = MSG_YES["Ready to start?", "Is the master tool loaded in the spindle",""] +IF [#96 == 0] + MSG_OK["Install the master tool", "Switch to MPG mode and install the master tool (T@100) then switch back to auto and retry calibration", ""] + M30 +END_IF + +#96 = MSG_YES["Calibrate Tool Setter?", "would you like to run the tool setter calibration?",""] +IF [#96 == 1] + #96 = MSG_YES["Tool setter WCS set?", "Is the tool setter centre location loaded into G54 P@112?",""] + IF [#96 == 0] + MSG_OK["Set missing WCS", "Make sure to find the tool setters center and update offsets G54 P@112", ""] + M30 + END_IF + G65 "CALIBRATETOOLSET" +END_IF + +#96 = MSG_YES["Probing WCS set?", "Is the location of the Z probing object loaded into G54 P@111?",""] +IF [#96 == 0] + M1430 +END_IF + +G54 P@111 +G1 F2000 X0 Y0 + +;G65 "CALIBRATEPROBEZ" A1 ; full Z calibration + +G43 H@100 +G65 "PROTECTEDMOVE" Z100 + +; swap out block for ring gauge +MSG_OK["Load ring gauge", "Switch to MPG mode and install the ring gauge onto the table. Lower the probe tip into the ring gauge, then press Cycle Start only when ready to proceed. ",""] +M00 + +G65 "CALIBRATEPROBERING" + +G53 G00 Z0. +G53 G00 X-390 Y0 +M30 \ No newline at end of file From 9e670175e2c4cc49a9ac2cd5e429a4ac702e9a58 Mon Sep 17 00:00:00 2001 From: Robot Oblivion Date: Wed, 2 Apr 2025 15:47:10 +1300 Subject: [PATCH 08/21] Added top-level folders to organise files for simpler deployment --- .../Syil_LNC_RobotOblivion.cps | 0 .../syil_lnc_toolpath.cps | 8400 ++++++++--------- .../syil_x7_three_axis_machine_model.f3d | Bin .../SPINDLE_WARMUP.NC | 0 .../SPINDLE_WARMUP_FAST.NC | 0 .../probingSetupHelp_v0.1.nc | 0 .../CALIBRATEPROBEBLOCK | 0 .../CALIBRATEPROBERING | 0 .../CALIBRATEPROBEZ | 0 .../CALIBRATETOOLSET | 0 .../CHECKPOSITIONALTOLERANCE | 0 .../COMPZEROPOINT | 0 COPYWCS => Macros for Controller/COPYWCS | 0 FINDCOR => Macros for Controller/FINDCOR | 0 LOADTOOL => Macros for Controller/LOADTOOL | 0 PROBEBORE => Macros for Controller/PROBEBORE | 0 .../PROBECIRCULARBOSS | 0 .../PROBECONFIG | 0 .../PROBEINSIDECORNER | 0 .../PROBEOUTSIDECORNER | 0 .../PROBEPOCKET | 0 .../PROBERECTANGULARBOSS | 0 PROBEX => Macros for Controller/PROBEX | 0 .../PROBEXSLOT | 0 PROBEXWEB => Macros for Controller/PROBEXWEB | 0 .../PROBEXYANGLE | 0 PROBEY => Macros for Controller/PROBEY | 0 .../PROBEYSLOT | 0 PROBEYWEB => Macros for Controller/PROBEYWEB | 0 PROBEZ => Macros for Controller/PROBEZ | 0 .../PROTECTEDMOVE | 0 SAFESPIN => Macros for Controller/SAFESPIN | 0 TOOLSET => Macros for Controller/TOOLSET | 0 .../UNLOADTOOL | 0 .../LNC-Operation Manual.compressed.pdf | Bin .../LNC-Programming Manual.compressed.pdf | Bin .../LinuxMACROManualV0100ENG.pdf | Bin 37 files changed, 4200 insertions(+), 4200 deletions(-) rename Syil_LNC_RobotOblivion.cps => Fusion Posts & Machine Model/Syil_LNC_RobotOblivion.cps (100%) rename syil_lnc_toolpath.cps => Fusion Posts & Machine Model/syil_lnc_toolpath.cps (97%) rename syil_x7_three_axis_machine_model.f3d => Fusion Posts & Machine Model/syil_x7_three_axis_machine_model.f3d (100%) rename SPINDLE_WARMUP.NC => Helpful NC Programs/SPINDLE_WARMUP.NC (100%) rename SPINDLE_WARMUP_FAST.NC => Helpful NC Programs/SPINDLE_WARMUP_FAST.NC (100%) rename probingSetupHelp_v0.1.nc => Helpful NC Programs/probingSetupHelp_v0.1.nc (100%) rename CALIBRATEPROBEBLOCK => Macros for Controller/CALIBRATEPROBEBLOCK (100%) rename CALIBRATEPROBERING => Macros for Controller/CALIBRATEPROBERING (100%) rename CALIBRATEPROBEZ => Macros for Controller/CALIBRATEPROBEZ (100%) rename CALIBRATETOOLSET => Macros for Controller/CALIBRATETOOLSET (100%) rename CHECKPOSITIONALTOLERANCE => Macros for Controller/CHECKPOSITIONALTOLERANCE (100%) rename COMPZEROPOINT => Macros for Controller/COMPZEROPOINT (100%) rename COPYWCS => Macros for Controller/COPYWCS (100%) rename FINDCOR => Macros for Controller/FINDCOR (100%) rename LOADTOOL => Macros for Controller/LOADTOOL (100%) rename PROBEBORE => Macros for Controller/PROBEBORE (100%) rename PROBECIRCULARBOSS => Macros for Controller/PROBECIRCULARBOSS (100%) rename PROBECONFIG => Macros for Controller/PROBECONFIG (100%) rename PROBEINSIDECORNER => Macros for Controller/PROBEINSIDECORNER (100%) rename PROBEOUTSIDECORNER => Macros for Controller/PROBEOUTSIDECORNER (100%) rename PROBEPOCKET => Macros for Controller/PROBEPOCKET (100%) rename PROBERECTANGULARBOSS => Macros for Controller/PROBERECTANGULARBOSS (100%) rename PROBEX => Macros for Controller/PROBEX (100%) rename PROBEXSLOT => Macros for Controller/PROBEXSLOT (100%) rename PROBEXWEB => Macros for Controller/PROBEXWEB (100%) rename PROBEXYANGLE => Macros for Controller/PROBEXYANGLE (100%) rename PROBEY => Macros for Controller/PROBEY (100%) rename PROBEYSLOT => Macros for Controller/PROBEYSLOT (100%) rename PROBEYWEB => Macros for Controller/PROBEYWEB (100%) rename PROBEZ => Macros for Controller/PROBEZ (100%) rename PROTECTEDMOVE => Macros for Controller/PROTECTEDMOVE (100%) rename SAFESPIN => Macros for Controller/SAFESPIN (100%) rename TOOLSET => Macros for Controller/TOOLSET (100%) rename UNLOADTOOL => Macros for Controller/UNLOADTOOL (100%) rename LNC-Operation Manual.compressed.pdf => Support Docs/LNC-Operation Manual.compressed.pdf (100%) rename LNC-Programming Manual.compressed.pdf => Support Docs/LNC-Programming Manual.compressed.pdf (100%) rename LinuxMACROManualV0100ENG.pdf => Support Docs/LinuxMACROManualV0100ENG.pdf (100%) diff --git a/Syil_LNC_RobotOblivion.cps b/Fusion Posts & Machine Model/Syil_LNC_RobotOblivion.cps similarity index 100% rename from Syil_LNC_RobotOblivion.cps rename to Fusion Posts & Machine Model/Syil_LNC_RobotOblivion.cps diff --git a/syil_lnc_toolpath.cps b/Fusion Posts & Machine Model/syil_lnc_toolpath.cps similarity index 97% rename from syil_lnc_toolpath.cps rename to Fusion Posts & Machine Model/syil_lnc_toolpath.cps index 9859a53..5035aa8 100644 --- a/syil_lnc_toolpath.cps +++ b/Fusion Posts & Machine Model/syil_lnc_toolpath.cps @@ -1,4200 +1,4200 @@ -/** - Copyright (C) 2012-2024 by Autodesk, Inc. - All rights reserved. - - Syntec post processor configuration. - - $Revision: 44145 4f7aaa6c97df2d49db23603652fb3cf23f709aa1 $ - $Date: 2024-09-19 10:09:13 $ - - FORKID {78441FCF-1C1F-4D81-BFA8-AAF6F30E1F3B} -*/ - -description = "SYIL LNC 6800"; -vendor = "Scott Moyse"; -vendorUrl = "Toolpath.com"; -legal = "Copyright (C) 2012-2024 by Autodesk, Inc."; -certificationLevel = 2; -minimumRevision = 45917; - -longDescription = "Syil LNC 6800 Post Processor with A-axis and machine simulation. Written by Scott Moyse"; - -extension = "nc"; -programNameIsInteger = true; -setCodePage("ascii"); - -capabilities = CAPABILITY_MILLING | CAPABILITY_MACHINE_SIMULATION; -tolerance = spatial(0.002, MM); - -minimumChordLength = spatial(0.25, MM); -minimumCircularRadius = spatial(0.01, MM); -maximumCircularRadius = spatial(1000, MM); -minimumCircularSweep = toRad(0.01); -maximumCircularSweep = toRad(180); -allowHelicalMoves = true; -allowedCircularPlanes = undefined; // allow any circular motion -highFeedrate = (unit == MM) ? 5000 : 200; - -// user-defined properties -properties = { - - showSequenceNumbers: { - title : "Use sequence numbers", - description: "'Yes' outputs sequence numbers on each block, 'Only on tool change' outputs sequence numbers on tool change blocks only, and 'No' disables the output of sequence numbers.", - group : "formats", - type : "enum", - values : [ - {title:"Yes", id:"true"}, - {title:"No", id:"false"}, - {title:"Only on tool change", id:"toolChange"} - ], - value: "true", - scope: "post" - }, - sequenceNumberStart: { - title : "Start sequence number", - description: "The number at which to start the sequence numbers.", - group : "formats", - type : "integer", - value : 10, - scope : "post" - }, - sequenceNumberIncrement: { - title : "Sequence number increment", - description: "The amount by which the sequence number is incremented by in each block.", - group : "formats", - type : "integer", - value : 5, - scope : "post" - }, - optionalStop: { - title : "Optional stop", - description: "Outputs optional stop code during when necessary in the code.", - group : "preferences", - type : "boolean", - value : true, - scope : "post" - }, - separateWordsWithSpace: { - title : "Separate words with space", - description: "Adds spaces between words if 'yes' is selected.", - group : "formats", - type : "boolean", - value : true, - scope : "post" - }, - allow3DArcs: { - title : "Allow 3D arcs", - description: "Specifies whether 3D circular arcs are allowed.", - group : "preferences", - type : "boolean", - value : false, - scope : "post" - }, - useRadius: { - title : "Radius arcs", - description: "If yes is selected, arcs are outputted using radius values rather than IJK.", - group : "preferences", - type : "boolean", - value : false, - scope : "post" - }, - showNotes: { - title : "Show notes", - description: "Writes operation notes as comments in the outputted code.", - group : "formats", - type : "boolean", - value : false, - scope : "post" - }, - useSmoothing: { - title : "SGI / High Precision Mode", - description: "High-Speed High-Precision Parameter.", - group : "preferences", - type : "enum", - values : [ - {title:"Off", id:"-1"}, - {title:"Automatic", id:"9999"}, - {title:"Fine Precision", id:"1"}, - {title:"Fine Velocity", id:"2"}, - {title:"Rough", id:"3"} - ], - value: "-1", - scope: "post" - }, - precisionLevel: { - title : "Machining Condition", - description: "Users can choose the High-Speed High-Precision Parameter based on the controller HSHP configuration", - group : "preferences", - type : "enum", - values : [ - {title:"P1 More Corner", id:"P1"}, - {title:"P2 More Arcs", id:"P2"}, - {title:"P3 3C Product", id:"P3"}, - ], - value: "P2", - scope: "post" - }, - usePitchForTapping: { - title : "Use pitch for tapping", - 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!", - group : "preferences", - type : "boolean", - value : false, - scope : "post" - }, - useG95: { - title : "Use G95", - description: "Use IPR/MPR instead of IPM/MPM.", - group : "preferences", - type : "boolean", - value : false, - scope : "post" - }, - safeStartAllOperations: { - title : "Safe start all operations", - description: "Write optional blocks at the beginning of all operations that include all commands to start program.", - group : "preferences", - type : "boolean", - value : false, - scope : "post" - }, - useClampCodes: { - title : "Use clamp codes", - description: "Specifies whether clamp codes for rotary axes should be output. For simultaneous toolpaths rotary axes will always get unclamped.", - group : "multiAxis", - type : "boolean", - value : true, - scope : "post" - }, - safePositionMethod: { - title : "Safe Retracts", - description: "Select your desired retract option. 'Clearance Height' retracts to the operation clearance height.", - group : "homePositions", - type : "enum", - values : [ - {title:"G28", id:"G28"}, - {title:"G30", id:"G30"}, - {title:"G53", id:"G53"} - ], - value: "G28", - scope: "post" - }, - breakControlError: { - title : "Max. Break Control Error", - description: "Maximum Allowable Error for Break Control.", - group : "toolChange", - type : "number", - value : 0.05, - scope : "post" - }, - ForceTCPosition: { - title : "Change Position Before Toolchange", - description: "Change the machine position before executing a toolchange.", - group : "toolChange", - type : "boolean", - value : false, - scope : "post" - }, - TCposX: { - title : "Toolchange Position X Axis - Machine Coordinate", - description: "Machine Coordinate for toolchange on X Axis.", - group : "toolChange", - type : "number", - value : 0, - scope : "post" - }, - TCposY: { - title : "Toolchange Position Y Axis - Machine Coordinate", - description: "Machine Coordinate for toolchange on Y Axis.", - group : "toolChange", - type : "number", - value : 0, - scope : "post" - }, - EnableZeroPointCompensation: { - title : "Enable Zero Point Compensation", - description: "Allows probing cycles to compensate for deltas bewteen a probed part and it's expected postition. The WCS after probing becomes the override origin translated by the computed deltas.", - group : "preferences", - type : "boolean", - value : false, - scope : "post" - }, - _0CustomOnOpenGcode: { - title : "on open G-code", - description: "Inserts custom G-code at the beginning of the program", - group : "CustomGcode", - type : "string", - value : "", - scope : "post" - }, - _1CustomOnCloseGcode: { - title : "on close G-code", - description: "Inserts custom G-code at the end of the program", - group : "CustomGcode", - type : "string", - value : "", - scope : "post" - } -}; - -groupDefinitions = { - toolChange : {title:"Tool change", description: "Setting related to toolchanges", collapsed: true, order: 31}, - CustomGcode : {title:"Custom G-code", description: "G-code to add to the start of the program", collapsed: true, order: 33}, -}; - -// wcs definiton -wcsDefinitions = { - useZeroOffset: false, - wcs : [ - {name:"Standard", format:"G", range:[54, 59]}, - {name:"Extended", format:"G59.", range:[1, 106]} - ] -}; - -var gFormat = createFormat({prefix:"G", minDigitsLeft:2, decimals:1}); -var mFormat = createFormat({prefix:"M", minDigitsLeft:2, decimals:1}); -var hFormat = createFormat({prefix:"H", minDigitsLeft:2, decimals:1}); -var diameterOffsetFormat = createFormat({prefix:"D", minDigitsLeft:2, decimals:1}); - -var xyzFormat = createFormat({decimals:(unit == MM ? 3 : 4), type:FORMAT_REAL}); -var ijkFormat = createFormat({decimals:6, type:FORMAT_REAL}); // unitless -var rFormat = xyzFormat; // radius -var abcFormat = createFormat({decimals:3, type:FORMAT_REAL, scale:DEG}); -var feedFormat = createFormat({decimals:(unit == MM ? 0 : 1), type:FORMAT_REAL}); -var inverseTimeFormat = createFormat({decimals:3, type:FORMAT_REAL}); -var pitchFormat = createFormat({decimals:(unit == MM ? 3 : 4), type:FORMAT_REAL}); -var toolFormat = createFormat({decimals:0}); -var rpmFormat = createFormat({decimals:0}); -var secFormat = createFormat({decimals:3, type:FORMAT_REAL}); // seconds - range 0.001-99999.999 -var milliFormat = createFormat({decimals:0}); // milliseconds // range 1-9999 -var taperFormat = createFormat({decimals:1, scale:DEG}); -var oFormat = createFormat({minDigitsLeft:4, decimals:0}); -var peckFormat = createFormat({decimals:(unit == MM ? 3 : 4), type:FORMAT_REAL}); -// var peckFormat = createFormat({decimals:0, type:FORMAT_LZS, minDigitsLeft:4, scale:(unit == MM ? 1000 : 10000)}); - -var xOutput = createOutputVariable({onchange:function() {state.retractedX = false;}, prefix:"X"}, xyzFormat); -var yOutput = createOutputVariable({onchange:function() {state.retractedY = false;}, prefix:"Y"}, xyzFormat); -var zOutput = createOutputVariable({onchange:function() {state.retractedZ = false;}, prefix:"Z"}, xyzFormat); -var toolVectorOutputI = createOutputVariable({prefix:"I", control:CONTROL_FORCE}, ijkFormat); -var toolVectorOutputJ = createOutputVariable({prefix:"J", control:CONTROL_FORCE}, ijkFormat); -var toolVectorOutputK = createOutputVariable({prefix:"K", control:CONTROL_FORCE}, ijkFormat); -var aOutput = createOutputVariable({prefix:"A"}, abcFormat); -var bOutput = createOutputVariable({prefix:"B"}, abcFormat); -var cOutput = createOutputVariable({prefix:"C"}, abcFormat); -var feedOutput = createOutputVariable({prefix:"F"}, feedFormat); -var inverseTimeOutput = createOutputVariable({prefix:"F", control:CONTROL_FORCE}, inverseTimeFormat); -var pitchOutput = createOutputVariable({prefix:"F", control:CONTROL_FORCE}, pitchFormat); -var sOutput = createOutputVariable({prefix:"S", control:CONTROL_FORCE}, rpmFormat); -var peckOutput = createOutputVariable({prefix:"Q", control:CONTROL_FORCE}, peckFormat); - -// circular output -var iOutput = createOutputVariable({prefix:"I", control:CONTROL_NONZERO}, xyzFormat); -var jOutput = createOutputVariable({prefix:"J", control:CONTROL_NONZERO}, xyzFormat); -var kOutput = createOutputVariable({prefix:"K", control:CONTROL_NONZERO}, xyzFormat); - -var gMotionModal = createOutputVariable({}, gFormat); // modal group 1 // G0-G3, ... -var gPlaneModal = createOutputVariable({onchange:function () {gMotionModal.reset();}}, gFormat); // modal group 2 // G17-19 -var gAbsIncModal = createOutputVariable({}, gFormat); // modal group 3 // G90-91 -var gFeedModeModal = createOutputVariable({}, gFormat); // modal group 5 // G94-95 -var gUnitModal = createOutputVariable({}, gFormat); // modal group 6 // G70-71 -var gCycleModal = createOutputVariable({}, gFormat); // modal group 9 // G81, ... -var gRetractModal = createOutputVariable({}, gFormat); // modal group 10 // G98-99 -var fourthAxisClamp = createOutputVariable({}, mFormat); -var fifthAxisClamp = createOutputVariable({}, mFormat); - -var settings = { - coolant: { - // samples: - // {id: COOLANT_THROUGH_TOOL, on: 88, off: 89} - // {id: COOLANT_THROUGH_TOOL, on: [8, 88], off: [9, 89]} - // {id: COOLANT_THROUGH_TOOL, on: "M88 P3 (myComment)", off: "M89"} - coolants: [ - {id:COOLANT_FLOOD, on:8}, - {id:COOLANT_MIST}, - {id:COOLANT_THROUGH_TOOL, on:88, off:89}, - {id:COOLANT_AIR, on:7}, - {id:COOLANT_AIR_THROUGH_TOOL}, - {id:COOLANT_SUCTION}, - {id:COOLANT_FLOOD_MIST}, - {id:COOLANT_FLOOD_THROUGH_TOOL, on:[8, 88], off:[9, 89]}, - {id:COOLANT_OFF, off:9} - ], - singleLineCoolant: false, // specifies to output multiple coolant codes in one line rather than in separate lines - }, - smoothing: { - roughing : 3, // roughing level for smoothing in automatic mode - semi : 2, // semi-roughing level for smoothing in automatic mode - semifinishing : 2, // semi-finishing level for smoothing in automatic mode - finishing : 1, // finishing level for smoothing in automatic mode - thresholdRoughing : toPreciseUnit(0.5, MM), // operations with stock/tolerance above that threshold will use roughing level in automatic mode - thresholdFinishing : toPreciseUnit(0.05, MM), // operations with stock/tolerance below that threshold will use finishing level in automatic mode - thresholdSemiFinishing: toPreciseUnit(0.1, MM), // operations with stock/tolerance above finishing and below threshold roughing that threshold will use semi finishing level in automatic mode - - differenceCriteria: "level", // options: "level", "tolerance", "both". Specifies criteria when output smoothing codes - autoLevelCriteria : "stock", // use "stock" or "tolerance" to determine levels in automatic mode - cancelCompensation: false // tool length compensation must be canceled prior to changing the smoothing level - }, - retract: { - cancelRotationOnRetracting: false, // specifies that rotations (G68) need to be canceled prior to retracting - methodXY : "G30", // special condition, overwrite retract behavior per axis - methodZ : undefined, // special condition, overwrite retract behavior per axis - useZeroValues : ["G28"], // enter property value id(s) for using "0" value instead of machineConfiguration axes home position values (ie G30 Z0) - homeXY : {onIndexing:false, onToolChange:{axes:[X, Y]}, onProgramEnd:{axes:[X, Y]}} // Specifies when the machine should be homed in X/Y. Sample: onIndexing:{axes:[X, Y], singleLine:false} - }, - parametricFeeds: { - firstFeedParameter : 500, // specifies the initial parameter number to be used for parametric feedrate output - feedAssignmentVariable: "#", // specifies the syntax to define a parameter - feedOutputVariable : "F#" // specifies the syntax to output the feedrate as parameter - }, - machineAngles: { // refer to https://cam.autodesk.com/posts/reference/classMachineConfiguration.html#a14bcc7550639c482492b4ad05b1580c8 - controllingAxis: ABC, - type : PREFER_PREFERENCE, - options : ENABLE_ALL - }, - workPlaneMethod: { - useTiltedWorkplane : false, // specifies that tilted workplanes should be used (ie. G68.2, G254, PLANE SPATIAL, CYCLE800), can be overwritten by property - eulerConvention : EULER_ZXZ_R, // specifies the euler convention (ie EULER_XYZ_R), set to undefined to use machine angles for TWP commands ('undefined' requires machine configuration) - eulerCalculationMethod: "standard", // ('standard' / 'machine') 'machine' adjusts euler angles to match the machines ABC orientation, machine configuration required - cancelTiltFirst : true, // cancel tilted workplane prior to WCS (G54-G59) blocks - useABCPrepositioning : true, // position ABC axes prior to tilted workplane blocks - forceMultiAxisIndexing: false, // force multi-axis indexing for 3D programs - optimizeType : undefined // can be set to OPTIMIZE_NONE, OPTIMIZE_BOTH, OPTIMIZE_TABLES, OPTIMIZE_HEADS, OPTIMIZE_AXIS. 'undefined' uses legacy rotations - }, - subprograms: { - initialSubprogramNumber: 9001, // specifies the initial number to be used for subprograms. 'undefined' uses the main program number - minimumCyclePoints : 5, // minimum number of points in cycle operation to consider for subprogram - format : oFormat, // the format to use for the subprogam number format - // objects below also accept strings with "%currentSubprogram" as placeholder. Sample: {files:["%"], embedded:"N" + "%currentSubprogram"} - files : {extension:extension, prefix:undefined}, // specifies the subprogram file extension and the prefix to use for the generated file - startBlock : {files:["%" + EOL + "O"], embedded:["N"]}, // specifies the start syntax of a subprogram followed by the subprogram number - endBlock : {files:[mFormat.format(99) + EOL + "%"], embedded:[mFormat.format(99)]}, // specifies the command to for the end of a subprogram - callBlock : {files:[mFormat.format(98) + " H"], embedded:[mFormat.format(98) + " H"]} // specifies the command for calling a subprogram followed by the subprogram number - }, - comments: { - permittedCommentChars: " abcdefghijklmnopqrstuvwxyz0123456789.,=_-:", // letters are not case sensitive, use option 'outputFormat' below. Set to 'undefined' to allow any character - prefix : "(", // specifies the prefix for the comment - suffix : ")", // specifies the suffix for the comment - outputFormat : "upperCase", // can be set to "upperCase", "lowerCase" and "ignoreCase". Set to "ignoreCase" to write comments without upper/lower case formatting - maximumLineLength : 80 // the maximum number of characters allowed in a line, set to 0 to disable comment output - }, - probing: { - macroCall : gFormat.format(65), // specifies the command to call a macro - probeAngleMethod : undefined, // supported options are: OFF, AXIS_ROT, G68, G54.4. 'undefined' uses automatic selection - probeAngleVariables : {x:"#135", y:"#136", z:0, i:0, j:0, k:1, r:"#144", baseParamG54x4:26000, baseParamAxisRot:5200, method:0}, // specifies variables for the angle compensation macros, method 0 = Fanuc, 1 = Haas - allowIndexingWCSProbing: false // specifies that probe WCS with tool orientation is supported - }, - maximumSequenceNumber : undefined, // the maximum sequence number (Nxxx), use 'undefined' for unlimited - supportsToolVectorOutput : true, // specifies if the control does support tool axis vector output for multi axis toolpath - allowCancelTCPBeforeRetracting: true, // allows TCP/tool length compensation to be canceled prior retracting. Warning, ensure machine parameters 5006.6(Fanuc)/F114 bit 1(Mazak) are set to prevent axis motion when cancelling compensation. - maximumToolLengthOffset : 199, - maximumToolDiameterOffset : 199 -}; - -function onOpen() { - // define and enable machine configuration - receivedMachineConfiguration = machineConfiguration.isReceived(); - if (typeof defineMachine == "function") { - defineMachine(); // hardcoded machine configuration - } - activateMachine(); - - // postprocessor/machine specific requirements - if (getProperty("useRadius")) { - maximumCircularSweep = toRad(90); // avoid potential center calculation errors for CNC - } - if (getProperty("safePositionMethod") == "G53" && (!machineConfiguration.hasHomePositionX() || !machineConfiguration.hasHomePositionY())) { - settings.retract.methodXY = "G28"; - } - - // initialize formats - gRotationModal.format(69); // Default to G69 Rotation Off - - if (!getProperty("separateWordsWithSpace")) { - setWordSeparator(""); - } - - if (getProperty("useG95")) { - if (getProperty("useParametricFeed")) { - error(localize("Parametric feed is not supported when using G95.")); - return; - } - feedFormat = createFormat({decimals:(unit == MM ? 4 : 5), type:FORMAT_REAL}); - feedOutput.setFormat(feedFormat); - } - - writeln("%"); - if (Number.isInteger(programName)) { - writeln("O" + oFormat.format(getProgramNumber()) + conditional(programComment, " " + formatComment(programComment))); - } else { - writeComment(programName); - } - writeProgramHeader(); - - // absolute coordinates and feed per min - writeBlock(gAbsIncModal.format(90), gFeedModeModal.format(getProperty("useG95") ? 95 : 94), gPlaneModal.format(17), toolLengthCompOutput.format(49), gFormat.format(40), gFormat.format(80)); - writeBlock(gUnitModal.format(unit == MM ? 21 : 20)); - validateCommonParameters(); - - // Save the G59 Z axis into a variable #199 for use with G10 calls - writeComment("G59 stores the zero point. #199 can be used with G10 commands to pull G59 into a local WCS"); - writeBlock("#199 = R_G53G59_COOR[0,59,3]"); - writeBlock("@980 = TIME[3]"); //month - writeBlock("@981 = TIME[4]"); //day - writeBlock("@982 = TIME[2]"); //year - writeBlock("@983 = TIME[5]"); //hour - writeBlock("@984 = TIME[6]"); //minute - writeBlock("@985 = TIME[7]"); //second - writeBlock(getProperty("_0CustomOnOpenGcode")); -} - -function setSmoothing(mode) { - smoothingSettings = settings.smoothing; - if (mode == smoothing.isActive && (!mode || !smoothing.isDifferent) && !smoothing.force) { - return; // return if smoothing is already active or is not different - } - if (validateLengthCompensation && smoothingSettings.cancelCompensation) { - validate(!state.lengthCompensationActive, "Length compensation is active while trying to update smoothing."); - } - if (mode) { // enable smoothing - writeBlock(gFormat.format(120.1), getProperty("precisionLevel"), "Q" + smoothing.level); - } else { // disable smoothing - writeBlock(gFormat.format(121)); - } - smoothing.isActive = mode; - smoothing.force = false; - smoothing.isDifferent = false; -} - -function onSection() { - var forceSectionRestart = optionalSection && !currentSection.isOptional(); - optionalSection = currentSection.isOptional(); - var insertToolCall = isToolChangeNeeded("number") || forceSectionRestart; - var newWorkOffset = isNewWorkOffset() || forceSectionRestart; - var newWorkPlane = isNewWorkPlane() || forceSectionRestart; - operationNeedsSafeStart = getProperty("safeStartAllOperations") && !isFirstSection(); - initializeSmoothing(); // initialize smoothing mode - - // Manual Tool Change Tool Removal - // place in own function or COMMAND_MANUAL_LOAD + COMMAND_MANUAL_UNLOAD - if (insertToolCall && !isFirstSection()) { - if(getPreviousSection().getTool().manualToolChange == true) { - setCoolant(COOLANT_OFF); - onCommand(COMMAND_STOP_SPINDLE); - writeRetract(Z); - writeRetract(settings.retract.homeXY.onToolChange); - onCommand(COMMAND_STOP); - machineSimulation({x:getProperty("TCposX"), y: getProperty("TCposY"), coordinates:MACHINE, mode:TOOLCHANGE}); // move machineSimulation to a tool change position - //writeComment("Flip to Manual, Swap tools then cycle start to resume"); KC need to test - writeComment(""); - previousSection = getPreviousSection(); - if (previousSection) { - previousToolNumber = previousSection.getTool().number; - writeComment("Flip to manual, remove T" + previousToolNumber + " and replace with T" + tool.number + " then cycle start to resume" ); - } else { - writeComment("No previous tool (first tool in program)."); - } - } - } - - if (insertToolCall || newWorkOffset || newWorkPlane || smoothing.cancel || state.tcpIsActive) { - // stop coolant before retract during manual tool change - if (!isLastSection() && tool.manualToolChange == true && getNextSection().getTool().manualToolChange == true) { - onCommand(COMMAND_COOLANT_OFF) - } - - // stop spindle before retract during tool change - if (insertToolCall && !isFirstSection()) { - onCommand(COMMAND_STOP_SPINDLE); - } - disableLengthCompensation(); - if (getSetting("workPlaneMethod.cancelTiltFirst", false)) { - cancelWorkPlane(); - } - writeRetract(Z); // retract - if (isFirstSection() && machineConfiguration.isMultiAxisConfiguration()) { - setWorkPlane(new Vector(0, 0, 0)); // reset working plane - forceABC(); - } - forceXYZ(); - if (!isFirstSection() && (insertToolCall || smoothing.cancel || state.tcpIsActive)) { - disableLengthCompensation(); - if (smoothing.cancel || insertToolCall) { - setSmoothing(false); - } - } - } - - writeln(""); - writeComment(getParameter("operation-comment", "")); - - if (getProperty("showNotes")) { - writeSectionNotes(); - } - - // tool change - writeToolCall(tool, insertToolCall); - startSpindle(tool, insertToolCall); - - // write parametric feedrate table - if (typeof initializeParametricFeeds == "function") { - initializeParametricFeeds(insertToolCall); - } - // Output modal commands here - writeBlock(gPlaneModal.format(17), gAbsIncModal.format(90), gFeedModeModal.format(getProperty("useG95") ? 95 : 94)); - - // set wcs - var wcsIsRequired = true; - if (insertToolCall || operationNeedsSafeStart) { - currentWorkOffset = undefined; // force work offset when changing tool - wcsIsRequired = newWorkOffset || insertToolCall || !operationNeedsSafeStart; - } - writeWCS(currentSection, wcsIsRequired); - - forceXYZ(); - - onCommand(COMMAND_START_CHIP_TRANSPORT); - - var abc = defineWorkPlane(currentSection, true); - - setCoolant(tool.coolant); // writes the required coolant codes - - setSmoothing(smoothing.isAllowed); // writes the required smoothing codes - - // prepositioning - var initialPosition = getFramePosition(currentSection.getInitialPosition()); - var isRequired = insertToolCall || state.retractedZ || !state.lengthCompensationActive || (!isFirstSection() && getPreviousSection().isMultiAxis()); - writeInitialPositioning(initialPosition, isRequired); - - if (subprogramsAreSupported()) { - subprogramDefine(initialPosition, abc); // define subprogram - } - state.retractedZ = false; -} - -function onDwell(seconds) { - if (seconds > 99999.999) { - warning(localize("Dwelling time is out of range.")); - } - milliseconds = clamp(1, seconds * 1000, 99999999); - writeBlock(gFeedModeModal.format(94), gFormat.format(4), "P" + milliFormat.format(milliseconds)); - writeBlock(gFeedModeModal.format(getProperty("useG95") ? 95 : 94)); // back to G95 -} - -function onSpindleSpeed(spindleSpeed) { - writeBlock(sOutput.format(spindleSpeed)); -} - -function onCycle() { - writeBlock(gPlaneModal.format(17)); -} - -function onCyclePoint(x, y, z) { - if (isInspectionOperation()) { - if (typeof inspectionCycleInspect == "function") { - inspectionCycleInspect(cycle, x, y, z); - return; - } else { - cycleNotSupported(); - } - } else if (isProbeOperation()) { - writeProbeCycle(cycle, x, y, z); - } else { - properties.useRigidTapping = {current:"no"}; // TAG: required to include common Fanuc cycles - writeDrillCycle(cycle, x, y, z); - } -} - -function onCycleEnd() { - if (subprogramsAreSupported() && subprogramState.cycleSubprogramIsActive) { - subprogramEnd(); - } - if (!cycleExpanded) { - writeBlock(gFeedModeModal.format(getProperty("useG95") ? 95 : 94), gCycleModal.format(80)); - zOutput.reset(); - } -} - -var mapCommand = { - COMMAND_END : 2, - COMMAND_SPINDLE_CLOCKWISE : 3, - COMMAND_SPINDLE_COUNTERCLOCKWISE: 4, - COMMAND_STOP_SPINDLE : 5, - COMMAND_ORIENTATE_SPINDLE : 19 -}; - -function onCommand(command) { - switch (command) { - case COMMAND_COOLANT_OFF: - setCoolant(COOLANT_OFF); - return; - case COMMAND_COOLANT_ON: - setCoolant(tool.coolant); - return; - case COMMAND_STOP: - writeBlock(mFormat.format(0)); - forceSpindleSpeed = true; - forceCoolant = true; - return; - case COMMAND_OPTIONAL_STOP: - writeBlock(mFormat.format(1)); - forceSpindleSpeed = true; - forceCoolant = true; - return; - case COMMAND_START_SPINDLE: - forceSpindleSpeed = false; - writeBlock(sOutput.format(spindleSpeed), mFormat.format(tool.clockwise ? 3 : 4)); - return; - case COMMAND_LOAD_TOOL: - writeToolBlock("T" + toolFormat.format(tool.number), mFormat.format(6)); - writeComment(tool.comment); - if (tool.manualToolChange != true){ - writeComment(tool.description); - writeComment(tool.bodyLength + "mm Stick out below " + tool.holderDescription + " holder"); - } - // preload tools not supported on umbrella changer machines - //var preloadTool = getNextTool(tool.number != getFirstTool().number); - //if (getProperty("preloadTool") && preloadTool) { - // writeBlock("T" + toolFormat.format(preloadTool.number)); // preload next/first tool - //} - return; - case COMMAND_LOCK_MULTI_AXIS: - var outputClampCodes = getProperty("useClampCodes") || currentSection.isMultiAxis(); - if (outputClampCodes && machineConfiguration.isMultiAxisConfiguration()) { - writeBlock(fourthAxisClamp.format(10), conditional(machineConfiguration.getNumberOfAxes() > 4, fifthAxisClamp.format(110))); // lock 4th + 5th axis - } - return; - case COMMAND_UNLOCK_MULTI_AXIS: - var outputClampCodes = getProperty("useClampCodes") || currentSection.isMultiAxis(); - if (outputClampCodes && machineConfiguration.isMultiAxisConfiguration()) { - writeBlock(fourthAxisClamp.format(11), conditional(machineConfiguration.getNumberOfAxes() > 4, fifthAxisClamp.format(111))); // unlock 4th + 5th axis - } - return; - case COMMAND_START_CHIP_TRANSPORT: - return; - case COMMAND_STOP_CHIP_TRANSPORT: - return; - case COMMAND_BREAK_CONTROL: - onCommand(COMMAND_STOP_SPINDLE); - setCoolant(COOLANT_OFF) - writeRetract(Z); - // add tool change position move? - writeBlock(mFormat.format(106) + " T" + toolFormat.format(tool.number)+ " D" + xyzFormat.format(tool.diameter) + " E"+ getProperty("breakControlError")); - machineSimulation({x:getProperty("TCposX"), y: getProperty("TCposY"), coordinates:MACHINE, mode:TOOLCHANGE}); // move machineSimulation to a tool change position - // add second retract post tool measure? - return; - case COMMAND_TOOL_MEASURE: - return; - case COMMAND_PROBE_ON: - return; - case COMMAND_PROBE_OFF: - return; - } - - var stringId = getCommandStringId(command); - var mcode = mapCommand[stringId]; - if (mcode != undefined) { - writeBlock(mFormat.format(mcode)); - } else { - onUnsupportedCommand(command); - } -} - -function onSectionEnd() { - if (currentSection.isMultiAxis()) { - writeBlock(gFeedModeModal.format(getProperty("useG95") ? 95 : 94)); // inverse time feed off - } - writeBlock(gPlaneModal.format(17)); - - if (!isLastSection()) { - if (getNextSection().getTool().coolant != tool.coolant) { - setCoolant(COOLANT_OFF); - } - if (tool.breakControl && isToolChangeNeeded(getNextSection(), getProperty("toolAsName") ? "description" : "number")) { - onCommand(COMMAND_BREAK_CONTROL); - } - } - - if (subprogramsAreSupported()) { - subprogramEnd(); - } - - forceAny(); - - operationNeedsSafeStart = false; // reset for next section -} - -// Start of onRewindMachine logic -/** Allow user to override the onRewind logic. */ -function onRewindMachineEntry(_a, _b, _c) { - return false; -} - -/** Retract to safe position before indexing rotaries. */ -function onMoveToSafeRetractPosition() { - writeRetract(Z); - // cancel TCP so that tool doesn't follow rotaries - if (currentSection.isMultiAxis() && tcp.isSupportedByOperation) { - disableLengthCompensation(false, "TCPC OFF"); - } -} - -/** Rotate axes to new position above reentry position */ -function onRotateAxes(_x, _y, _z, _a, _b, _c) { - // position rotary axes - xOutput.disable(); - yOutput.disable(); - zOutput.disable(); - onRapid5D(_x, _y, _z, _a, _b, _c); - setCurrentABC(new Vector(_a, _b, _c)); - machineSimulation({a:_a, b:_b, c:_c, coordinates:MACHINE}); - xOutput.enable(); - yOutput.enable(); - zOutput.enable(); -} - -/** Return from safe position after indexing rotaries. */ -function onReturnFromSafeRetractPosition(_x, _y, _z) { - // reinstate TCP / tool length compensation - if (!state.lengthCompensationActive) { - writeBlock(getOffsetCode(), hFormat.format(tool.lengthOffset)); - } - - // position in XY - forceXYZ(); - xOutput.reset(); - yOutput.reset(); - zOutput.disable(); - if (highFeedMapping != HIGH_FEED_NO_MAPPING) { - onLinear(_x, _y, _z, highFeedrate); - } else { - onRapid(_x, _y, _z); - } - machineSimulation({x:_x, y:_y}); - // position in Z - zOutput.enable(); - invokeOnRapid(_x, _y, _z); -} -// End of onRewindMachine logic - -function onClose() { - optionalSection = false; - writeln(""); - onCommand(COMMAND_STOP_SPINDLE); - onCommand(COMMAND_COOLANT_OFF); - disableLengthCompensation(true); - cancelWorkPlane(); - writeRetract(Z); // retract - setSmoothing(false); - forceWorkPlane(); - setWorkPlane(new Vector(0, 0, 0)); // reset working plane - if (getSetting("retract.homeXY.onProgramEnd", false)) { - writeRetract(settings.retract.homeXY.onProgramEnd); - } - writeBlock(mFormat.format(30)); // program end - - if (subprogramsAreSupported()) { - writeSubprograms(); - } - writeln("%"); - writeBlock(getProperty("_1CustomOnCloseGcode")); -} - -// >>>>> INCLUDED FROM include_files/commonFunctions.cpi -// internal variables, do not change -var receivedMachineConfiguration; -var tcp = {isSupportedByControl:getSetting("supportsTCP", true), isSupportedByMachine:false, isSupportedByOperation:false}; -var state = { - retractedX : false, // specifies that the machine has been retracted in X - retractedY : false, // specifies that the machine has been retracted in Y - retractedZ : false, // specifies that the machine has been retracted in Z - tcpIsActive : false, // specifies that TCP is currently active - twpIsActive : false, // specifies that TWP is currently active - lengthCompensationActive: !getSetting("outputToolLengthCompensation", true), // specifies that tool length compensation is active - mainState : true // specifies the current context of the state (true = main, false = optional) -}; -var validateLengthCompensation = getSetting("outputToolLengthCompensation", true); // disable validation when outputToolLengthCompensation is disabled -var multiAxisFeedrate; -var sequenceNumber; -var optionalSection = false; -var currentWorkOffset; -var forceSpindleSpeed = false; -var operationNeedsSafeStart = false; // used to convert blocks to optional for safeStartAllOperations - -function activateMachine() { - // disable unsupported rotary axes output - if (!machineConfiguration.isMachineCoordinate(0) && (typeof aOutput != "undefined")) { - aOutput.disable(); - } - if (!machineConfiguration.isMachineCoordinate(1) && (typeof bOutput != "undefined")) { - bOutput.disable(); - } - if (!machineConfiguration.isMachineCoordinate(2) && (typeof cOutput != "undefined")) { - cOutput.disable(); - } - - // setup usage of useTiltedWorkplane - settings.workPlaneMethod.useTiltedWorkplane = getProperty("useTiltedWorkplane") != undefined ? getProperty("useTiltedWorkplane") : - getSetting("workPlaneMethod.useTiltedWorkplane", false); - settings.workPlaneMethod.useABCPrepositioning = getProperty("useABCPrepositioning") != undefined ? getProperty("useABCPrepositioning") : - getSetting("workPlaneMethod.useABCPrepositioning", false); - - if (!machineConfiguration.isMultiAxisConfiguration()) { - return; // don't need to modify any settings for 3-axis machines - } - - // identify if any of the rotary axes has TCP enabled - var axes = [machineConfiguration.getAxisU(), machineConfiguration.getAxisV(), machineConfiguration.getAxisW()]; - tcp.isSupportedByMachine = axes.some(function(axis) {return axis.isEnabled() && axis.isTCPEnabled();}); // true if TCP is enabled on any rotary axis - - // save multi-axis feedrate settings from machine configuration - var mode = machineConfiguration.getMultiAxisFeedrateMode(); - var type = mode == FEED_INVERSE_TIME ? machineConfiguration.getMultiAxisFeedrateInverseTimeUnits() : - (mode == FEED_DPM ? machineConfiguration.getMultiAxisFeedrateDPMType() : DPM_STANDARD); - multiAxisFeedrate = { - mode : mode, - maximum : machineConfiguration.getMultiAxisFeedrateMaximum(), - type : type, - tolerance: mode == FEED_DPM ? machineConfiguration.getMultiAxisFeedrateOutputTolerance() : 0, - bpwRatio : mode == FEED_DPM ? machineConfiguration.getMultiAxisFeedrateBpwRatio() : 1 - }; - - // setup of retract/reconfigure TAG: Only needed until post kernel supports these machine config settings - if (receivedMachineConfiguration && machineConfiguration.performRewinds()) { - safeRetractDistance = machineConfiguration.getSafeRetractDistance(); - safePlungeFeed = machineConfiguration.getSafePlungeFeedrate(); - safeRetractFeed = machineConfiguration.getSafeRetractFeedrate(); - } - if (typeof safeRetractDistance == "number" && getProperty("safeRetractDistance") != undefined && getProperty("safeRetractDistance") != 0) { - safeRetractDistance = getProperty("safeRetractDistance"); - } - - if (machineConfiguration.isHeadConfiguration()) { - compensateToolLength = typeof compensateToolLength == "undefined" ? false : compensateToolLength; - } - - if (machineConfiguration.isHeadConfiguration() && compensateToolLength) { - for (var i = 0; i < getNumberOfSections(); ++i) { - var section = getSection(i); - if (section.isMultiAxis()) { - machineConfiguration.setToolLength(getBodyLength(section.getTool())); // define the tool length for head adjustments - section.optimizeMachineAnglesByMachine(machineConfiguration, OPTIMIZE_AXIS); - } - } - } else { - optimizeMachineAngles2(OPTIMIZE_AXIS); - } -} - -function getBodyLength(tool) { - for (var i = 0; i < getNumberOfSections(); ++i) { - var section = getSection(i); - if (tool.number == section.getTool().number) { - return section.getParameter("operation:tool_overallLength", tool.bodyLength + tool.holderLength); - } - } - return tool.bodyLength + tool.holderLength; -} - -function getFeed(f) { - if (getProperty("useG95")) { - return feedOutput.format(f / spindleSpeed); // use feed value - } - if (typeof activeMovements != "undefined" && activeMovements) { - var feedContext = activeMovements[movement]; - if (feedContext != undefined) { - if (!feedFormat.areDifferent(feedContext.feed, f)) { - if (feedContext.id == currentFeedId) { - return ""; // nothing has changed - } - forceFeed(); - currentFeedId = feedContext.id; - return settings.parametricFeeds.feedOutputVariable + (settings.parametricFeeds.firstFeedParameter + feedContext.id); - } - } - currentFeedId = undefined; // force parametric feed next time - } - return feedOutput.format(f); // use feed value -} - -function validateCommonParameters() { - validateToolData(); - for (var i = 0; i < getNumberOfSections(); ++i) { - var section = getSection(i); - if (getSection(0).workOffset == 0 && section.workOffset > 0) { - if (!(typeof wcsDefinitions != "undefined" && wcsDefinitions.useZeroOffset)) { - error(localize("Using multiple work offsets is not possible if the initial work offset is 0.")); - } - } - if (section.isMultiAxis()) { - if (!section.isOptimizedForMachine() && - (!getSetting("workPlaneMethod.useTiltedWorkplane", false) || !getSetting("supportsToolVectorOutput", false))) { - error(localize("This postprocessor requires a machine configuration for 5-axis simultaneous toolpath.")); - } - if (machineConfiguration.getMultiAxisFeedrateMode() == FEED_INVERSE_TIME && !getSetting("supportsInverseTimeFeed", true)) { - error(localize("This postprocessor does not support inverse time feedrates.")); - } - if (getSetting("supportsToolVectorOutput", false) && !tcp.isSupportedByControl) { - error(localize("Incompatible postprocessor settings detected." + EOL + - "Setting 'supportsToolVectorOutput' requires setting 'supportsTCP' to be enabled as well.")); - } - } - } - if (!tcp.isSupportedByControl && tcp.isSupportedByMachine) { - error(localize("The machine configuration has TCP enabled which is not supported by this postprocessor.")); - } - if (getProperty("safePositionMethod") == "clearanceHeight") { - var msg = "-Attention- Property 'Safe Retracts' is set to 'Clearance Height'." + EOL + - "Ensure the clearance height will clear the part and or fixtures." + EOL + - "Raise the Z-axis to a safe height before starting the program."; - warning(msg); - writeComment(msg); - } -} - -function validateToolData() { - var _default = 99999; - var _maximumSpindleRPM = machineConfiguration.getMaximumSpindleSpeed() > 0 ? machineConfiguration.getMaximumSpindleSpeed() : - settings.maximumSpindleRPM == undefined ? _default : settings.maximumSpindleRPM; - var _maximumToolNumber = machineConfiguration.isReceived() && machineConfiguration.getNumberOfTools() > 0 ? machineConfiguration.getNumberOfTools() : - settings.maximumToolNumber == undefined ? _default : settings.maximumToolNumber; - var _maximumToolLengthOffset = settings.maximumToolLengthOffset == undefined ? _default : settings.maximumToolLengthOffset; - var _maximumToolDiameterOffset = settings.maximumToolDiameterOffset == undefined ? _default : settings.maximumToolDiameterOffset; - - var header = ["Detected maximum values are out of range.", "Maximum values:"]; - var warnings = { - toolNumber : {msg:"Tool number value exceeds the maximum value for tool: " + EOL, max:" Tool number: " + _maximumToolNumber, values:[]}, - lengthOffset : {msg:"Tool length offset value exceeds the maximum value for tool: " + EOL, max:" Tool length offset: " + _maximumToolLengthOffset, values:[]}, - diameterOffset: {msg:"Tool diameter offset value exceeds the maximum value for tool: " + EOL, max:" Tool diameter offset: " + _maximumToolDiameterOffset, values:[]}, - spindleSpeed : {msg:"Spindle speed exceeds the maximum value for operation: " + EOL, max:" Spindle speed: " + _maximumSpindleRPM, values:[]} - }; - - var toolIds = []; - for (var i = 0; i < getNumberOfSections(); ++i) { - var section = getSection(i); - if (toolIds.indexOf(section.getTool().getToolId()) === -1) { // loops only through sections which have a different tool ID - var toolNumber = section.getTool().number; - var lengthOffset = section.getTool().lengthOffset; - var diameterOffset = section.getTool().diameterOffset; - var comment = section.getParameter("operation-comment", ""); - - if (toolNumber > _maximumToolNumber && !getProperty("toolAsName")) { - warnings.toolNumber.values.push(SP + toolNumber + EOL); - } - if (lengthOffset > _maximumToolLengthOffset) { - warnings.lengthOffset.values.push(SP + "Tool " + toolNumber + " (" + comment + "," + " Length offset: " + lengthOffset + ")" + EOL); - } - if (diameterOffset > _maximumToolDiameterOffset) { - warnings.diameterOffset.values.push(SP + "Tool " + toolNumber + " (" + comment + "," + " Diameter offset: " + diameterOffset + ")" + EOL); - } - toolIds.push(section.getTool().getToolId()); - } - // loop through all sections regardless of tool id for idenitfying spindle speeds - - // identify if movement ramp is used in current toolpath, use ramp spindle speed for comparisons - var ramp = section.getMovements() & ((1 << MOVEMENT_RAMP) | (1 << MOVEMENT_RAMP_ZIG_ZAG) | (1 << MOVEMENT_RAMP_PROFILE) | (1 << MOVEMENT_RAMP_HELIX)); - var _sectionSpindleSpeed = Math.max(section.getTool().spindleRPM, ramp ? section.getTool().rampingSpindleRPM : 0, 0); - if (_sectionSpindleSpeed > _maximumSpindleRPM) { - warnings.spindleSpeed.values.push(SP + section.getParameter("operation-comment", "") + " (" + _sectionSpindleSpeed + " RPM" + ")" + EOL); - } - } - - // sort lists by tool number - warnings.toolNumber.values.sort(function(a, b) {return a - b;}); - warnings.lengthOffset.values.sort(function(a, b) {return a.localeCompare(b);}); - warnings.diameterOffset.values.sort(function(a, b) {return a.localeCompare(b);}); - - var warningMessages = []; - for (var key in warnings) { - if (warnings[key].values != "") { - header.push(warnings[key].max); // add affected max values to the header - warningMessages.push(warnings[key].msg + warnings[key].values.join("")); - } - } - if (warningMessages.length != 0) { - warningMessages.unshift(header.join(EOL) + EOL); - warning(warningMessages.join(EOL)); - } -} - -function forceFeed() { - currentFeedId = undefined; - feedOutput.reset(); -} - -/** Force output of X, Y, and Z. */ -function forceXYZ() { - xOutput.reset(); - yOutput.reset(); - zOutput.reset(); -} - -/** Force output of A, B, and C. */ -function forceABC() { - aOutput.reset(); - bOutput.reset(); - cOutput.reset(); -} - -/** Force output of X, Y, Z, A, B, C, and F on next output. */ -function forceAny() { - forceXYZ(); - forceABC(); - forceFeed(); -} - -/** - Writes the specified block. -*/ -function writeBlock() { - var text = formatWords(arguments); - if (!text) { - return; - } - var prefix = getSetting("sequenceNumberPrefix", "N"); - var suffix = getSetting("writeBlockSuffix", ""); - if ((optionalSection || skipBlocks) && !getSetting("supportsOptionalBlocks", true)) { - error(localize("Optional blocks are not supported by this post.")); - } - if (getProperty("showSequenceNumbers") == "true") { - if (sequenceNumber == undefined || sequenceNumber >= settings.maximumSequenceNumber) { - sequenceNumber = getProperty("sequenceNumberStart"); - } - if (optionalSection || skipBlocks) { - writeWords2("/", prefix + sequenceNumber, text + suffix); - } else { - writeWords2(prefix + sequenceNumber, text + suffix); - } - sequenceNumber += getProperty("sequenceNumberIncrement"); - } else { - if (optionalSection || skipBlocks) { - writeWords2("/", text + suffix); - } else { - writeWords(text + suffix); - } - } -} - -validate(settings.comments, "Setting 'comments' is required but not defined."); -function formatComment(text) { - var prefix = settings.comments.prefix; - var suffix = settings.comments.suffix; - var _permittedCommentChars = settings.comments.permittedCommentChars == undefined ? "" : settings.comments.permittedCommentChars; - switch (settings.comments.outputFormat) { - case "upperCase": - text = text.toUpperCase(); - _permittedCommentChars = _permittedCommentChars.toUpperCase(); - break; - case "lowerCase": - text = text.toLowerCase(); - _permittedCommentChars = _permittedCommentChars.toLowerCase(); - break; - case "ignoreCase": - _permittedCommentChars = _permittedCommentChars.toUpperCase() + _permittedCommentChars.toLowerCase(); - break; - default: - error(localize("Unsupported option specified for setting 'comments.outputFormat'.")); - } - if (_permittedCommentChars != "") { - text = filterText(String(text), _permittedCommentChars); - } - text = String(text).substring(0, settings.comments.maximumLineLength - prefix.length - suffix.length); - return text != "" ? prefix + text + suffix : ""; -} - -/** - Output a comment. -*/ -function writeComment(text) { - if (!text) { - return; - } - var comments = String(text).split(EOL); - for (comment in comments) { - var _comment = formatComment(comments[comment]); - if (_comment) { - if (getSetting("comments.showSequenceNumbers", false)) { - writeBlock(_comment); - } else { - writeln(_comment); - } - } - } -} - -function onComment(text) { - writeComment(text); -} - -/** - Writes the specified block - used for tool changes only. -*/ -function writeToolBlock() { - var show = getProperty("showSequenceNumbers"); - setProperty("showSequenceNumbers", (show == "true" || show == "toolChange") ? "true" : "false"); - writeBlock(arguments); - setProperty("showSequenceNumbers", show); - machineSimulation({x:getProperty("TCposX"), y: getProperty("TCposY"), coordinates:MACHINE, mode:TOOLCHANGE}); // move machineSimulation to a tool change position -} - -var skipBlocks = false; -var initialState = JSON.parse(JSON.stringify(state)); // save initial state -var optionalState = JSON.parse(JSON.stringify(state)); -var saveCurrentSectionId = undefined; -function writeStartBlocks(isRequired, code) { - var saveSkipBlocks = skipBlocks; - var saveMainState = state; // save main state - - if (!isRequired) { - if (!getProperty("safeStartAllOperations", false)) { - return; // when safeStartAllOperations is disabled, dont output code and return - } - if (saveCurrentSectionId != getCurrentSectionId()) { - saveCurrentSectionId = getCurrentSectionId(); - forceModals(); // force all modal variables when entering a new section - optionalState = Object.create(initialState); // reset optionalState to initialState when entering a new section - } - skipBlocks = true; // if values are not required, but safeStartAllOperations is enabled - write following blocks as optional - state = optionalState; // set state to optionalState if skipBlocks is true - state.mainState = false; - } - code(); // writes out the code which is passed to this function as an argument - - state = saveMainState; // restore main state - skipBlocks = saveSkipBlocks; // restore skipBlocks value -} - -var pendingRadiusCompensation = -1; -function onRadiusCompensation() { - pendingRadiusCompensation = radiusCompensation; - if (pendingRadiusCompensation >= 0 && !getSetting("supportsRadiusCompensation", true)) { - error(localize("Radius compensation mode is not supported.")); - return; - } -} - -function onPassThrough(text) { - var commands = String(text).split(","); - for (text in commands) { - writeBlock(commands[text]); - } -} - -function forceModals() { - if (arguments.length == 0) { // reset all modal variables listed below - if (typeof gMotionModal != "undefined") { - gMotionModal.reset(); - } - if (typeof gPlaneModal != "undefined") { - gPlaneModal.reset(); - } - if (typeof gAbsIncModal != "undefined") { - gAbsIncModal.reset(); - } - if (typeof gFeedModeModal != "undefined") { - gFeedModeModal.reset(); - } - } else { - for (var i in arguments) { - arguments[i].reset(); // only reset the modal variable passed to this function - } - } -} - -/** Helper function to be able to use a default value for settings which do not exist. */ -function getSetting(setting, defaultValue) { - var result = defaultValue; - var keys = setting.split("."); - var obj = settings; - for (var i in keys) { - if (obj[keys[i]] != undefined) { // setting does exist - result = obj[keys[i]]; - if (typeof [keys[i]] === "object") { - obj = obj[keys[i]]; - continue; - } - } else { // setting does not exist, use default value - if (defaultValue != undefined) { - result = defaultValue; - } else { - error("Setting '" + keys[i] + "' has no default value and/or does not exist."); - return undefined; - } - } - } - return result; -} - -function getForwardDirection(_section) { - var forward = undefined; - var _optimizeType = settings.workPlaneMethod && settings.workPlaneMethod.optimizeType; - if (_section.isMultiAxis()) { - forward = _section.workPlane.forward; - } else if (!getSetting("workPlaneMethod.useTiltedWorkplane", false) && machineConfiguration.isMultiAxisConfiguration()) { - if (_optimizeType == undefined) { - var saveRotation = getRotation(); - getWorkPlaneMachineABC(_section, true); - forward = getRotation().forward; - setRotation(saveRotation); // reset rotation - } else { - var abc = getWorkPlaneMachineABC(_section, false); - var forceAdjustment = settings.workPlaneMethod.optimizeType == OPTIMIZE_TABLES || settings.workPlaneMethod.optimizeType == OPTIMIZE_BOTH; - forward = machineConfiguration.getOptimizedDirection(_section.workPlane.forward, abc, false, forceAdjustment); - } - } else { - forward = getRotation().forward; - } - return forward; -} - -function getRetractParameters() { - var _arguments = typeof arguments[0] === "object" ? arguments[0].axes : arguments; - var singleLine = arguments[0].singleLine == undefined ? true : arguments[0].singleLine; - var words = []; // store all retracted axes in an array - var retractAxes = new Array(false, false, false); - var method = getProperty("safePositionMethod", "undefined"); - if (method == "clearanceHeight") { - if (!is3D()) { - error(localize("Safe retract option 'Clearance Height' is only supported when all operations are along the setup Z-axis.")); - } - return undefined; - } - validate(settings.retract, "Setting 'retract' is required but not defined."); - validate(_arguments.length != 0, "No axis specified for getRetractParameters()."); - for (i in _arguments) { - retractAxes[_arguments[i]] = true; - } - if ((retractAxes[0] || retractAxes[1]) && !state.retractedZ) { // retract Z first before moving to X/Y home - error(localize("Retracting in X/Y is not possible without being retracted in Z.")); - return undefined; - } - // special conditions - if (retractAxes[0] || retractAxes[1]) { - method = getSetting("retract.methodXY", method); - } - if (retractAxes[2]) { - method = getSetting("retract.methodZ", method); - } - // define home positions - var useZeroValues = (settings.retract.useZeroValues && settings.retract.useZeroValues.indexOf(method) != -1); - var _xHome = machineConfiguration.hasHomePositionX() && !useZeroValues ? machineConfiguration.getHomePositionX() : toPreciseUnit(0, MM); - var _yHome = machineConfiguration.hasHomePositionY() && !useZeroValues ? machineConfiguration.getHomePositionY() : toPreciseUnit(0, MM); - var _zHome = machineConfiguration.getRetractPlane() != 0 && !useZeroValues ? machineConfiguration.getRetractPlane() : toPreciseUnit(0, MM); - for (var i = 0; i < _arguments.length; ++i) { - switch (_arguments[i]) { - case X: - if (!state.retractedX) { - words.push("X" + xyzFormat.format(_xHome)); - xOutput.reset(); - state.retractedX = true; - } - break; - case Y: - if (!state.retractedY) { - words.push("Y" + xyzFormat.format(_yHome)); - yOutput.reset(); - state.retractedY = true; - } - break; - case Z: - if (!state.retractedZ) { - words.push("Z" + xyzFormat.format(_zHome)); - zOutput.reset(); - state.retractedZ = true; - } - break; - default: - error(localize("Unsupported axis specified for getRetractParameters().")); - return undefined; - } - } - return { - method : method, - retractAxes: retractAxes, - words : words, - positions : { - x: retractAxes[0] ? _xHome : undefined, - y: retractAxes[1] ? _yHome : undefined, - z: retractAxes[2] ? _zHome : undefined}, - singleLine: singleLine}; -} - -/** Returns true when subprogram logic does exist into the post. */ -function subprogramsAreSupported() { - return typeof subprogramState != "undefined"; -} - -// Start of machine simulation connection move support -var TCPON = "TCP ON"; -var TCPOFF = "TCP OFF"; -var TWPON = "TWP ON"; -var TWPOFF = "TWP OFF"; -var TOOLCHANGE = "TOOL CHANGE"; -var WORK = "WORK CS"; -var MACHINE = "MACHINE CS"; -var isTwpOn; // only used for debugging -var isTcpOn; // only used for debugging -if (typeof groupDefinitions != "object") { - groupDefinitions = {}; -} -groupDefinitions.machineSimulation = {title:"Machine Simulation", collapsed:true, order:99}; -properties.simulateConnectionMoves = { - title : "Simulate Connection Moves (Preview feature)", - description: "Specifies that connection moves like prepositioning, tool changes, retracts and other non-cutting moves should be shown in the machine simulation." + EOL + - "Note, this property does not affect the NC output, it only affects the machine simulation.", - group: "machineSimulation", - type : "boolean", - value: false, - scope: "machine" -}; -/** - * Helper function for connection moves in machine simulation. - * @param {Object} parameters An object containing the desired options for machine simulation. - * @note Available properties are: - * @param {Number} x X axis position - * @param {Number} y Y axis position - * @param {Number} z Z axis position - * @param {Number} a A axis position (in radians) - * @param {Number} b B axis position (in radians) - * @param {Number} c C axis position (in radians) - * @param {Number} feed desired feedrate, automatically set to high/current feedrate if not specified - * @param {String} mode mode TCPON | TCPOFF | TWPON | TWPOFF | TOOLCHANGE - * @param {String} coordinates WORK | MACHINE - if undefined, work coordinates will be used by default - * @param {Number} eulerAngles the calculated Euler angles for the workplane - * @example - machineSimulation({a:abc.x, b:abc.y, c:abc.z, coordinates:MACHINE}); - machineSimulation({x:toPreciseUnit(200, MM), y:toPreciseUnit(200, MM), coordinates:MACHINE, toolChange:true}); -*/ -var debugSimulation = false; // enable to output debug information for connection move support in the NC program - -function machineSimulation(parameters) { - if (revision < 50075 || skipBlocks || !getProperty("simulateConnectionMoves")) { - return; // return when post kernel revision is lower than 50075 or when skipBlocks is enabled - } - var x = parameters.x; - var y = parameters.y; - var z = parameters.z; - var a = parameters.a; - var b = parameters.b; - var c = parameters.c; - var coordinates = parameters.coordinates; - var eulerAngles = parameters.eulerAngles; - var feed = parameters.feed; - if (feed === undefined && typeof gMotionModal !== "undefined") { - feed = gMotionModal.getCurrent() !== 0; - } - var mode = parameters.mode; - var performToolChange = mode == TOOLCHANGE; - if (mode !== undefined && ![TCPON, TCPOFF, TWPON, TWPOFF, TOOLCHANGE].includes(mode)) { - error(subst("Mode '%1' is not supported.", mode)); - } - - // mode takes precedence over active state - var enableTCP = mode != undefined ? mode == TCPON : typeof state !== "undefined" && state.tcpIsActive; - var enableTWP = mode != undefined ? mode == TWPON : typeof state !== "undefined" && state.twpIsActive; - var disableTCP = mode != undefined ? mode == TCPOFF : typeof state !== "undefined" && !state.tcpIsActive; - var disableTWP = mode != undefined ? mode == TWPOFF : typeof state !== "undefined" && !state.twpIsActive; - if (enableTCP) { // update TCP mode - simulation.setTWPModeOff(); - simulation.setTCPModeOn(); - isTcpOn = true; - } else if (disableTCP) { - simulation.setTCPModeOff(); - isTcpOn = false; - } - - if (enableTWP) { // update TWP mode - simulation.setTCPModeOff(); - if (settings.workPlaneMethod.eulerConvention == undefined) { - simulation.setTWPModeAlignToCurrentPose(); - } else if (eulerAngles) { - simulation.setTWPModeByEulerAngles(settings.workPlaneMethod.eulerConvention, eulerAngles.x, eulerAngles.y, eulerAngles.z); - } - isTwpOn = true; - } else if (disableTWP) { - simulation.setTWPModeOff(); - isTwpOn = false; - } - if (debugSimulation) { - writeln(" DEBUG" + JSON.stringify(parameters)); - writeln(" DEBUG" + JSON.stringify({isTwpOn:isTwpOn, isTcpOn:isTcpOn, feed:feed})); - } - - if (x !== undefined || y !== undefined || z !== undefined || a !== undefined || b !== undefined || c !== undefined) { - if (x !== undefined) {simulation.setTargetX(x);} - if (y !== undefined) {simulation.setTargetY(y);} - if (z !== undefined) {simulation.setTargetZ(z);} - if (a !== undefined) {simulation.setTargetA(a);} - if (b !== undefined) {simulation.setTargetB(b);} - if (c !== undefined) {simulation.setTargetC(c);} - - if (feed != undefined && feed) { - simulation.setMotionToLinear(); - simulation.setFeedrate(typeof feed == "number" ? feed : feedOutput.getCurrent() == 0 ? highFeedrate : feedOutput.getCurrent()); - } else { - simulation.setMotionToRapid(); - } - - if (coordinates != undefined && coordinates == MACHINE) { - simulation.moveToTargetInMachineCoords(); - } else { - simulation.moveToTargetInWorkCoords(); - } - } - if (performToolChange) { - simulation.performToolChangeCycle(); - } -} -// <<<<< INCLUDED FROM include_files/commonFunctions.cpi -// >>>>> INCLUDED FROM include_files/defineMachine.cpi -var compensateToolLength = false; // add the tool length to the pivot distance for nonTCP rotary heads -function defineMachine() { - var useTCP = true; - if (false) { // note: setup your machine here - var aAxis = createAxis({coordinate:0, table:true, axis:[1, 0, 0], range:[-120, 120], preference:1, tcp:useTCP}); - var cAxis = createAxis({coordinate:2, table:true, axis:[0, 0, 1], range:[-360, 360], preference:0, tcp:useTCP}); - machineConfiguration = new MachineConfiguration(aAxis, cAxis); - - setMachineConfiguration(machineConfiguration); - if (receivedMachineConfiguration) { - warning(localize("The provided CAM machine configuration is overwritten by the postprocessor.")); - receivedMachineConfiguration = false; // CAM provided machine configuration is overwritten - } - } - - if (!receivedMachineConfiguration) { - // multiaxis settings - if (machineConfiguration.isHeadConfiguration()) { - machineConfiguration.setVirtualTooltip(false); // translate the pivot point to the virtual tool tip for nonTCP rotary heads - } - - // retract / reconfigure - var performRewinds = false; // set to true to enable the rewind/reconfigure logic - if (performRewinds) { - machineConfiguration.enableMachineRewinds(); // enables the retract/reconfigure logic - safeRetractDistance = (unit == IN) ? 1 : 25; // additional distance to retract out of stock, can be overridden with a property - safeRetractFeed = (unit == IN) ? 20 : 500; // retract feed rate - safePlungeFeed = (unit == IN) ? 10 : 250; // plunge feed rate - machineConfiguration.setSafeRetractDistance(safeRetractDistance); - machineConfiguration.setSafeRetractFeedrate(safeRetractFeed); - machineConfiguration.setSafePlungeFeedrate(safePlungeFeed); - var stockExpansion = new Vector(toPreciseUnit(0.1, IN), toPreciseUnit(0.1, IN), toPreciseUnit(0.1, IN)); // expand stock XYZ values - machineConfiguration.setRewindStockExpansion(stockExpansion); - } - - // multi-axis feedrates - if (machineConfiguration.isMultiAxisConfiguration()) { - machineConfiguration.setMultiAxisFeedrate( - useTCP ? FEED_FPM : getProperty("useDPMFeeds") ? FEED_DPM : FEED_INVERSE_TIME, - 9999.99, // maximum output value for inverse time feed rates - getProperty("useDPMFeeds") ? DPM_COMBINATION : INVERSE_MINUTES, // INVERSE_MINUTES/INVERSE_SECONDS or DPM_COMBINATION/DPM_STANDARD - 0.5, // tolerance to determine when the DPM feed has changed - 1.0 // ratio of rotary accuracy to linear accuracy for DPM calculations - ); - setMachineConfiguration(machineConfiguration); - } - - /* home positions */ - // machineConfiguration.setHomePositionX(toPreciseUnit(0, IN)); - // machineConfiguration.setHomePositionY(toPreciseUnit(0, IN)); - // machineConfiguration.setRetractPlane(toPreciseUnit(0, IN)); - } -} -// <<<<< INCLUDED FROM include_files/defineMachine.cpi -// >>>>> INCLUDED FROM include_files/defineWorkPlane.cpi -validate(settings.workPlaneMethod, "Setting 'workPlaneMethod' is required but not defined."); -function defineWorkPlane(_section, _setWorkPlane) { - var abc = new Vector(0, 0, 0); - if (settings.workPlaneMethod.forceMultiAxisIndexing || !is3D() || machineConfiguration.isMultiAxisConfiguration()) { - if (isPolarModeActive()) { - abc = getCurrentDirection(); - } else if (_section.isMultiAxis()) { - forceWorkPlane(); - cancelTransformation(); - abc = _section.isOptimizedForMachine() ? _section.getInitialToolAxisABC() : _section.getGlobalInitialToolAxis(); - } else if (settings.workPlaneMethod.useTiltedWorkplane && settings.workPlaneMethod.eulerConvention != undefined) { - if (settings.workPlaneMethod.eulerCalculationMethod == "machine" && machineConfiguration.isMultiAxisConfiguration()) { - abc = machineConfiguration.getOrientation(getWorkPlaneMachineABC(_section, true)).getEuler2(settings.workPlaneMethod.eulerConvention); - } else { - abc = _section.workPlane.getEuler2(settings.workPlaneMethod.eulerConvention); - } - } else { - abc = getWorkPlaneMachineABC(_section, true); - } - - if (_setWorkPlane) { - if (_section.isMultiAxis() || isPolarModeActive()) { // 4-5x simultaneous operations - cancelWorkPlane(); - if (_section.isOptimizedForMachine()) { - positionABC(abc, true); - } else { - setCurrentDirection(abc); - } - } else { // 3x and/or 3+2x operations - setWorkPlane(abc); - } - } - } else { - var remaining = _section.workPlane; - if (!isSameDirection(remaining.forward, new Vector(0, 0, 1))) { - error(localize("Tool orientation is not supported.")); - return abc; - } - setRotation(remaining); - } - tcp.isSupportedByOperation = isTCPSupportedByOperation(_section); - return abc; -} - -function isTCPSupportedByOperation(_section) { - var _tcp = _section.getOptimizedTCPMode() == OPTIMIZE_NONE; - if (!_section.isMultiAxis() && (settings.workPlaneMethod.useTiltedWorkplane || - isSameDirection(machineConfiguration.getSpindleAxis(), getForwardDirection(_section)) || - settings.workPlaneMethod.optimizeType == OPTIMIZE_HEADS || - settings.workPlaneMethod.optimizeType == OPTIMIZE_TABLES || - settings.workPlaneMethod.optimizeType == OPTIMIZE_BOTH)) { - _tcp = false; - } - return _tcp; -} -// <<<<< INCLUDED FROM include_files/defineWorkPlane.cpi -// >>>>> INCLUDED FROM include_files/getWorkPlaneMachineABC.cpi -validate(settings.machineAngles, "Setting 'machineAngles' is required but not defined."); -function getWorkPlaneMachineABC(_section, rotate) { - var currentABC = isFirstSection() ? new Vector(0, 0, 0) : getCurrentABC(); - var abc = _section.getABCByPreference(machineConfiguration, _section.workPlane, currentABC, settings.machineAngles.controllingAxis, settings.machineAngles.type, settings.machineAngles.options); - if (!isSameDirection(machineConfiguration.getDirection(abc), _section.workPlane.forward)) { - error(localize("Orientation not supported.")); - } - if (rotate) { - if (settings.workPlaneMethod.optimizeType == undefined || settings.workPlaneMethod.useTiltedWorkplane) { // legacy - var useTCP = false; - var R = machineConfiguration.getRemainingOrientation(abc, _section.workPlane); - setRotation(useTCP ? _section.workPlane : R); - } else { - if (!_section.isOptimizedForMachine()) { - machineConfiguration.setToolLength(compensateToolLength ? _section.getTool().overallLength : 0); // define the tool length for head adjustments - _section.optimize3DPositionsByMachine(machineConfiguration, abc, settings.workPlaneMethod.optimizeType); - } - } - } - return abc; -} -// <<<<< INCLUDED FROM include_files/getWorkPlaneMachineABC.cpi -// >>>>> INCLUDED FROM include_files/positionABC.cpi -function positionABC(abc, force) { - if (!machineConfiguration.isMultiAxisConfiguration()) { - error("Function 'positionABC' can only be used with multi-axis machine configurations."); - } - if (typeof unwindABC == "function") { - unwindABC(abc); - } - if (force) { - forceABC(); - } - var a = aOutput.format(abc.x); - var b = bOutput.format(abc.y); - var c = cOutput.format(abc.z); - if (a || b || c) { - writeRetract(Z); - if (getSetting("retract.homeXY.onIndexing", false)) { - writeRetract(settings.retract.homeXY.onIndexing); - } - onCommand(COMMAND_UNLOCK_MULTI_AXIS); - gMotionModal.reset(); - writeBlock(gMotionModal.format(0), a, b, c); - - if (getCurrentSectionId() != -1) { - setCurrentABC(abc); // required for machine simulation - } - machineSimulation({a:abc.x, b:abc.y, c:abc.z, coordinates:MACHINE}); - } -} -// <<<<< INCLUDED FROM include_files/positionABC.cpi -// >>>>> INCLUDED FROM include_files/writeWCS.cpi -function writeWCS(section, wcsIsRequired) { - if (section.workOffset != currentWorkOffset) { - if (getSetting("workPlaneMethod.cancelTiltFirst", false) && wcsIsRequired) { - cancelWorkPlane(); - } - if (typeof forceWorkPlane == "function" && wcsIsRequired) { - forceWorkPlane(); - } - writeStartBlocks(wcsIsRequired, function () { - writeBlock(section.wcs); - }); - currentWorkOffset = section.workOffset; - } -} -// <<<<< INCLUDED FROM include_files/writeWCS.cpi -// >>>>> INCLUDED FROM include_files/writeToolCall.cpi -function writeToolCall(tool, insertToolCall) { - if (!isFirstSection()) { - writeStartBlocks(!getProperty("safeStartAllOperations") && insertToolCall, function () { - writeRetract(Z); // write optional Z retract before tool change if safeStartAllOperations is enabled - }); - } - writeStartBlocks(insertToolCall, function () { - writeRetract(Z); - if (getSetting("retract.homeXY.onToolChange", false)) { - writeRetract(settings.retract.homeXY.onToolChange); - } - if (!isFirstSection() && insertToolCall) { - if (typeof forceWorkPlane == "function") { - forceWorkPlane(); - } - onCommand(COMMAND_COOLANT_OFF); // turn off coolant on tool change - if (typeof disableLengthCompensation == "function") { - disableLengthCompensation(false); - } - } - - if (tool.manualToolChange) { - onCommand(COMMAND_LOAD_TOOL); //KC calls tool change to swap out old tool for manual tool pocket - onCommand(COMMAND_STOP); - //writeComment("MANUAL TOOL CHANGE TO T" + toolFormat.format(tool.number)); - writeComment("Flip to Manual, Swap tool to T" + toolFormat.format(tool.number)); - writeComment("H" + tool.lengthOffset + " - " + tool.description); - writeComment(tool.bodyLength + "mm Stick out below " + tool.holderDescription + " holder"); - machineSimulation({x:toPreciseUnit(getProperty("TCposX"), MM), y:toPreciseUnit( getProperty("TCposY") , MM), coordinates:MACHINE, mode:TOOLCHANGE}); // move machineSimulation to a tool change position - } else { - if (!isFirstSection() && getProperty("optionalStop") && insertToolCall) { - onCommand(COMMAND_OPTIONAL_STOP); - } - onCommand(COMMAND_LOAD_TOOL); - } - }); - if (typeof forceModals == "function" && (insertToolCall || getProperty("safeStartAllOperations"))) { - forceModals(); - } -} -// <<<<< INCLUDED FROM include_files/writeToolCall.cpi -// >>>>> INCLUDED FROM include_files/startSpindle.cpi - -function startSpindle(tool, insertToolCall) { - if (tool.type != TOOL_PROBE) { - var spindleSpeedIsRequired = insertToolCall || forceSpindleSpeed || isFirstSection() || - rpmFormat.areDifferent(spindleSpeed, sOutput.getCurrent()) || - (tool.clockwise != getPreviousSection().getTool().clockwise); - - writeStartBlocks(spindleSpeedIsRequired, function () { - if (spindleSpeedIsRequired || operationNeedsSafeStart) { - onCommand(COMMAND_START_SPINDLE); - } - }); - } -} -// <<<<< INCLUDED FROM include_files/startSpindle.cpi -// >>>>> INCLUDED FROM include_files/parametricFeeds.cpi -properties.useParametricFeed = { - title : "Parametric feed", - description: "Specifies that the feedrates should be output using parameters.", - group : "preferences", - type : "boolean", - value : false, - scope : "post" -}; -var activeMovements; -var currentFeedId; -validate(settings.parametricFeeds, "Setting 'parametricFeeds' is required but not defined."); -function initializeParametricFeeds(insertToolCall) { - if (getProperty("useParametricFeed") && getParameter("operation-strategy") != "drill" && !currentSection.hasAnyCycle()) { - if (!insertToolCall && activeMovements && (getCurrentSectionId() > 0) && - ((getPreviousSection().getPatternId() == currentSection.getPatternId()) && (currentSection.getPatternId() != 0))) { - return; // use the current feeds - } - } else { - activeMovements = undefined; - return; - } - - activeMovements = new Array(); - var movements = currentSection.getMovements(); - - var id = 0; - var activeFeeds = new Array(); - if (hasParameter("operation:tool_feedCutting")) { - if (movements & ((1 << MOVEMENT_CUTTING) | (1 << MOVEMENT_LINK_TRANSITION) | (1 << MOVEMENT_EXTENDED))) { - var feedContext = new FeedContext(id, localize("Cutting"), getParameter("operation:tool_feedCutting")); - activeFeeds.push(feedContext); - activeMovements[MOVEMENT_CUTTING] = feedContext; - if (!hasParameter("operation:tool_feedTransition")) { - activeMovements[MOVEMENT_LINK_TRANSITION] = feedContext; - } - activeMovements[MOVEMENT_EXTENDED] = feedContext; - } - ++id; - if (movements & (1 << MOVEMENT_PREDRILL)) { - feedContext = new FeedContext(id, localize("Predrilling"), getParameter("operation:tool_feedCutting")); - activeMovements[MOVEMENT_PREDRILL] = feedContext; - activeFeeds.push(feedContext); - } - ++id; - } - if (hasParameter("operation:finishFeedrate")) { - if (movements & (1 << MOVEMENT_FINISH_CUTTING)) { - var feedContext = new FeedContext(id, localize("Finish"), getParameter("operation:finishFeedrate")); - activeFeeds.push(feedContext); - activeMovements[MOVEMENT_FINISH_CUTTING] = feedContext; - } - ++id; - } else if (hasParameter("operation:tool_feedCutting")) { - if (movements & (1 << MOVEMENT_FINISH_CUTTING)) { - var feedContext = new FeedContext(id, localize("Finish"), getParameter("operation:tool_feedCutting")); - activeFeeds.push(feedContext); - activeMovements[MOVEMENT_FINISH_CUTTING] = feedContext; - } - ++id; - } - if (hasParameter("operation:tool_feedEntry")) { - if (movements & (1 << MOVEMENT_LEAD_IN)) { - var feedContext = new FeedContext(id, localize("Entry"), getParameter("operation:tool_feedEntry")); - activeFeeds.push(feedContext); - activeMovements[MOVEMENT_LEAD_IN] = feedContext; - } - ++id; - } - if (hasParameter("operation:tool_feedExit")) { - if (movements & (1 << MOVEMENT_LEAD_OUT)) { - var feedContext = new FeedContext(id, localize("Exit"), getParameter("operation:tool_feedExit")); - activeFeeds.push(feedContext); - activeMovements[MOVEMENT_LEAD_OUT] = feedContext; - } - ++id; - } - if (hasParameter("operation:noEngagementFeedrate")) { - if (movements & (1 << MOVEMENT_LINK_DIRECT)) { - var feedContext = new FeedContext(id, localize("Direct"), getParameter("operation:noEngagementFeedrate")); - activeFeeds.push(feedContext); - activeMovements[MOVEMENT_LINK_DIRECT] = feedContext; - } - ++id; - } else if (hasParameter("operation:tool_feedCutting") && - hasParameter("operation:tool_feedEntry") && - hasParameter("operation:tool_feedExit")) { - if (movements & (1 << MOVEMENT_LINK_DIRECT)) { - var feedContext = new FeedContext(id, localize("Direct"), Math.max(getParameter("operation:tool_feedCutting"), getParameter("operation:tool_feedEntry"), getParameter("operation:tool_feedExit"))); - activeFeeds.push(feedContext); - activeMovements[MOVEMENT_LINK_DIRECT] = feedContext; - } - ++id; - } - if (hasParameter("operation:reducedFeedrate")) { - if (movements & (1 << MOVEMENT_REDUCED)) { - var feedContext = new FeedContext(id, localize("Reduced"), getParameter("operation:reducedFeedrate")); - activeFeeds.push(feedContext); - activeMovements[MOVEMENT_REDUCED] = feedContext; - } - ++id; - } - if (hasParameter("operation:tool_feedRamp")) { - if (movements & ((1 << MOVEMENT_RAMP) | (1 << MOVEMENT_RAMP_HELIX) | (1 << MOVEMENT_RAMP_PROFILE) | (1 << MOVEMENT_RAMP_ZIG_ZAG))) { - var feedContext = new FeedContext(id, localize("Ramping"), getParameter("operation:tool_feedRamp")); - activeFeeds.push(feedContext); - activeMovements[MOVEMENT_RAMP] = feedContext; - activeMovements[MOVEMENT_RAMP_HELIX] = feedContext; - activeMovements[MOVEMENT_RAMP_PROFILE] = feedContext; - activeMovements[MOVEMENT_RAMP_ZIG_ZAG] = feedContext; - } - ++id; - } - if (hasParameter("operation:tool_feedPlunge")) { - if (movements & (1 << MOVEMENT_PLUNGE)) { - var feedContext = new FeedContext(id, localize("Plunge"), getParameter("operation:tool_feedPlunge")); - activeFeeds.push(feedContext); - activeMovements[MOVEMENT_PLUNGE] = feedContext; - } - ++id; - } - if (true) { // high feed - if ((movements & (1 << MOVEMENT_HIGH_FEED)) || (highFeedMapping != HIGH_FEED_NO_MAPPING)) { - var feed; - if (hasParameter("operation:highFeedrateMode") && getParameter("operation:highFeedrateMode") != "disabled") { - feed = getParameter("operation:highFeedrate"); - } else { - feed = this.highFeedrate; - } - var feedContext = new FeedContext(id, localize("High Feed"), feed); - activeFeeds.push(feedContext); - activeMovements[MOVEMENT_HIGH_FEED] = feedContext; - activeMovements[MOVEMENT_RAPID] = feedContext; - } - ++id; - } - if (hasParameter("operation:tool_feedTransition")) { - if (movements & (1 << MOVEMENT_LINK_TRANSITION)) { - var feedContext = new FeedContext(id, localize("Transition"), getParameter("operation:tool_feedTransition")); - activeFeeds.push(feedContext); - activeMovements[MOVEMENT_LINK_TRANSITION] = feedContext; - } - ++id; - } - - for (var i = 0; i < activeFeeds.length; ++i) { - var feedContext = activeFeeds[i]; - var feedDescription = typeof formatComment == "function" ? formatComment(feedContext.description) : feedContext.description; - writeBlock(settings.parametricFeeds.feedAssignmentVariable + (settings.parametricFeeds.firstFeedParameter + feedContext.id) + "=" + feedFormat.format(feedContext.feed) + SP + feedDescription); - } -} - -function FeedContext(id, description, feed) { - this.id = id; - this.description = description; - this.feed = feed; -} -// <<<<< INCLUDED FROM include_files/parametricFeeds.cpi -// >>>>> INCLUDED FROM include_files/coolant.cpi -var currentCoolantMode = COOLANT_OFF; -var coolantOff = undefined; -var isOptionalCoolant = false; -var forceCoolant = false; - -function setCoolant(coolant) { - var coolantCodes = getCoolantCodes(coolant); - if (Array.isArray(coolantCodes)) { - writeStartBlocks(!isOptionalCoolant, function () { - if (settings.coolant.singleLineCoolant) { - writeBlock(coolantCodes.join(getWordSeparator())); - } else { - for (var c in coolantCodes) { - writeBlock(coolantCodes[c]); - } - } - }); - return undefined; - } - return coolantCodes; -} - -function getCoolantCodes(coolant, format) { - if (!getProperty("useCoolant", true)) { - return undefined; // coolant output is disabled by property if it exists - } - isOptionalCoolant = false; - if (typeof operationNeedsSafeStart == "undefined") { - operationNeedsSafeStart = false; - } - var multipleCoolantBlocks = new Array(); // create a formatted array to be passed into the outputted line - var coolants = settings.coolant.coolants; - if (!coolants) { - error(localize("Coolants have not been defined.")); - } - if (tool.type && tool.type == TOOL_PROBE) { // avoid coolant output for probing - coolant = COOLANT_OFF; - } - if (coolant == currentCoolantMode) { - if (operationNeedsSafeStart && coolant != COOLANT_OFF) { - isOptionalCoolant = true; - } else if (!forceCoolant || coolant == COOLANT_OFF) { - return undefined; // coolant is already active - } - } - if ((coolant != COOLANT_OFF) && (currentCoolantMode != COOLANT_OFF) && (coolantOff != undefined) && !forceCoolant && !isOptionalCoolant) { - if (Array.isArray(coolantOff)) { - for (var i in coolantOff) { - multipleCoolantBlocks.push(coolantOff[i]); - } - } else { - multipleCoolantBlocks.push(coolantOff); - } - } - forceCoolant = false; - - var m; - var coolantCodes = {}; - for (var c in coolants) { // find required coolant codes into the coolants array - if (coolants[c].id == coolant) { - coolantCodes.on = coolants[c].on; - if (coolants[c].off != undefined) { - coolantCodes.off = coolants[c].off; - break; - } else { - for (var i in coolants) { - if (coolants[i].id == COOLANT_OFF) { - coolantCodes.off = coolants[i].off; - break; - } - } - } - } - } - if (coolant == COOLANT_OFF) { - m = !coolantOff ? coolantCodes.off : coolantOff; // use the default coolant off command when an 'off' value is not specified - } else { - coolantOff = coolantCodes.off; - m = coolantCodes.on; - } - - if (!m) { - onUnsupportedCoolant(coolant); - m = 9; - } else { - if (Array.isArray(m)) { - for (var i in m) { - multipleCoolantBlocks.push(m[i]); - } - } else { - multipleCoolantBlocks.push(m); - } - currentCoolantMode = coolant; - for (var i in multipleCoolantBlocks) { - if (typeof multipleCoolantBlocks[i] == "number") { - multipleCoolantBlocks[i] = mFormat.format(multipleCoolantBlocks[i]); - } - } - if (format == undefined || format) { - return multipleCoolantBlocks; // return the single formatted coolant value - } else { - return m; // return unformatted coolant value - } - } - return undefined; -} -// <<<<< INCLUDED FROM include_files/coolant.cpi -// >>>>> INCLUDED FROM include_files/smoothing.cpi -// collected state below, do not edit -validate(settings.smoothing, "Setting 'smoothing' is required but not defined."); -var smoothing = { - cancel : false, // cancel tool length prior to update smoothing for this operation - isActive : false, // the current state of smoothing - isAllowed : false, // smoothing is allowed for this operation - isDifferent: false, // tells if smoothing levels/tolerances/both are different between operations - level : -1, // the active level of smoothing - tolerance : -1, // the current operation tolerance - force : false // smoothing needs to be forced out in this operation -}; - -function initializeSmoothing() { - var smoothingSettings = settings.smoothing; - var previousLevel = smoothing.level; - var previousTolerance = xyzFormat.getResultingValue(smoothing.tolerance); - - // format threshold parameters - var thresholdRoughing = xyzFormat.getResultingValue(smoothingSettings.thresholdRoughing); - var thresholdSemiFinishing = xyzFormat.getResultingValue(smoothingSettings.thresholdSemiFinishing); - var thresholdFinishing = xyzFormat.getResultingValue(smoothingSettings.thresholdFinishing); - - // determine new smoothing levels and tolerances - smoothing.level = parseInt(getProperty("useSmoothing"), 10); - smoothing.level = isNaN(smoothing.level) ? -1 : smoothing.level; - smoothing.tolerance = xyzFormat.getResultingValue(Math.max(getParameter("operation:tolerance", thresholdFinishing), 0)); - - if (smoothing.level == 9999) { - if (smoothingSettings.autoLevelCriteria == "stock") { // determine auto smoothing level based on stockToLeave - var stockToLeave = xyzFormat.getResultingValue(getParameter("operation:stockToLeave", 0)); - var verticalStockToLeave = xyzFormat.getResultingValue(getParameter("operation:verticalStockToLeave", 0)); - if (((stockToLeave >= thresholdRoughing) && (verticalStockToLeave >= thresholdRoughing)) || getParameter("operation:strategy", "") == "face") { - smoothing.level = smoothingSettings.roughing; // set roughing level - } else { - if (((stockToLeave >= thresholdSemiFinishing) && (stockToLeave < thresholdRoughing)) && - ((verticalStockToLeave >= thresholdSemiFinishing) && (verticalStockToLeave < thresholdRoughing))) { - smoothing.level = smoothingSettings.semi; // set semi level - } else if (((stockToLeave >= thresholdFinishing) && (stockToLeave < thresholdSemiFinishing)) && - ((verticalStockToLeave >= thresholdFinishing) && (verticalStockToLeave < thresholdSemiFinishing))) { - smoothing.level = smoothingSettings.semifinishing; // set semi-finishing level - } else { - smoothing.level = smoothingSettings.finishing; // set finishing level - } - } - } else { // detemine auto smoothing level based on operation tolerance instead of stockToLeave - if (smoothing.tolerance >= thresholdRoughing || getParameter("operation:strategy", "") == "face") { - smoothing.level = smoothingSettings.roughing; // set roughing level - } else { - if (((smoothing.tolerance >= thresholdSemiFinishing) && (smoothing.tolerance < thresholdRoughing))) { - smoothing.level = smoothingSettings.semi; // set semi level - } else if (((smoothing.tolerance >= thresholdFinishing) && (smoothing.tolerance < thresholdSemiFinishing))) { - smoothing.level = smoothingSettings.semifinishing; // set semi-finishing level - } else { - smoothing.level = smoothingSettings.finishing; // set finishing level - } - } - } - } - - if (smoothing.level == -1) { // useSmoothing is disabled - smoothing.isAllowed = false; - } else { // do not output smoothing for the following operations - smoothing.isAllowed = !(currentSection.getTool().type == TOOL_PROBE || isDrillingCycle()); - } - if (!smoothing.isAllowed) { - smoothing.level = -1; - smoothing.tolerance = -1; - } - - switch (smoothingSettings.differenceCriteria) { - case "level": - smoothing.isDifferent = smoothing.level != previousLevel; - break; - case "tolerance": - smoothing.isDifferent = smoothing.tolerance != previousTolerance; - break; - case "both": - smoothing.isDifferent = smoothing.level != previousLevel || smoothing.tolerance != previousTolerance; - break; - default: - error(localize("Unsupported smoothing criteria.")); - return; - } - - // tool length compensation needs to be canceled when smoothing state/level changes - if (smoothingSettings.cancelCompensation) { - smoothing.cancel = !isFirstSection() && smoothing.isDifferent; - } -} -// <<<<< INCLUDED FROM include_files/smoothing.cpi -// >>>>> INCLUDED FROM include_files/writeProgramHeader.cpi -properties.writeMachine = { - title : "Write machine", - description: "Output the machine settings in the header of the program.", - group : "formats", - type : "boolean", - value : true, - scope : "post" -}; -properties.writeTools = { - title : "Write tool list", - description: "Output a tool list in the header of the program.", - group : "formats", - type : "boolean", - value : true, - scope : "post" -}; -function writeProgramHeader() { - writeComment((now.getMonth() + 1) + "-" + now.getDate() + "-" + now.getFullYear() + " " + now.getHours() + ":" + ("0" + now.getMinutes()).slice(-2)); //BJE - // dump machine configuration - var vendor = machineConfiguration.getVendor(); - var model = machineConfiguration.getModel(); - var mDescription = machineConfiguration.getDescription(); - if (getProperty("writeMachine") && (vendor || model || mDescription)) { - writeComment(localize("Machine")); - if (vendor) { - writeComment(" " + localize("vendor") + ": " + vendor); - } - if (model) { - writeComment(" " + localize("model") + ": " + model); - } - if (mDescription) { - writeComment(" " + localize("description") + ": " + mDescription); - } - } - - // dump tool information - if (getProperty("writeTools")) { - if (false) { // set to true to use the post kernel version of the tool list - writeToolTable(TOOL_NUMBER_COL); - } else { - var zRanges = {}; - if (is3D()) { - var numberOfSections = getNumberOfSections(); - for (var i = 0; i < numberOfSections; ++i) { - var section = getSection(i); - var zRange = section.getGlobalZRange(); - var tool = section.getTool(); - if (zRanges[tool.number]) { - zRanges[tool.number].expandToRange(zRange); - } else { - zRanges[tool.number] = zRange; - } - } - } - var tools = getToolTable(); - if (tools.getNumberOfTools() > 0) { - for (var i = 0; i < tools.getNumberOfTools(); ++i) { - var tool = tools.getTool(i); - var comment = (getProperty("toolAsName") ? "\"" + tool.description.toUpperCase() + "\"" : "T" + toolFormat.format(tool.number)) + " " + - "D=" + xyzFormat.format(tool.diameter) + " " + - localize("CR") + "=" + xyzFormat.format(tool.cornerRadius); - if ((tool.taperAngle > 0) && (tool.taperAngle < Math.PI)) { - comment += " " + localize("TAPER") + "=" + taperFormat.format(tool.taperAngle) + localize("deg"); - } - if (zRanges[tool.number]) { - comment += " - " + localize("ZMIN") + "=" + xyzFormat.format(zRanges[tool.number].getMinimum()); - } - comment += " - " + getToolTypeName(tool.type); - writeComment(comment); - } - } - } - } -} -// <<<<< INCLUDED FROM include_files/writeProgramHeader.cpi -// >>>>> INCLUDED FROM include_files/subprograms.cpi -properties.useSubroutines = { - title : "Use subroutines", - description: "Select your desired subroutine option. 'All Operations' creates subroutines per each operation, 'Cycles' creates subroutines for cycle operations on same holes, and 'Patterns' creates subroutines for patterned operations.", - group : "preferences", - type : "enum", - values : [ - {title:"No", id:"none"}, - {title:"All Operations", id:"allOperations"}, - {title:"All Operations & Patterns", id:"allPatterns"}, - {title:"Cycles", id:"cycles"}, - {title:"Operations, Patterns, Cycles", id:"all"}, - {title:"Patterns", id:"patterns"} - ], - value: "none", - scope: "post" -}; -properties.useFilesForSubprograms = { - title : "Use files for subroutines", - description: "If enabled, subroutines will be saved as individual files.", - group : "preferences", - type : "boolean", - value : false, - scope : "post" -}; - -var NONE = 0x0000; -var PATTERNS = 0x0001; -var CYCLES = 0x0010; -var ALLOPERATIONS = 0x0100; -var subroutineBitmasks = { - none : NONE, - patterns : PATTERNS, - cycles : CYCLES, - allOperations: ALLOPERATIONS, - allPatterns : PATTERNS + ALLOPERATIONS, - all : PATTERNS + CYCLES + ALLOPERATIONS -}; - -var SUB_UNKNOWN = 0; -var SUB_PATTERN = 1; -var SUB_CYCLE = 2; - -// collected state below, do not edit -validate(settings.subprograms, "Setting 'subprograms' is required but not defined."); -var subprogramState = { - subprograms : [], // Redirection buffer - newSubprogram : false, // Indicate if the current subprogram is new to definedSubprograms - currentSubprogram : 0, // The current subprogram number - lastSubprogram : undefined, // The last subprogram number - definedSubprograms : new Array(), // A collection of pattern and cycle subprograms - saveShowSequenceNumbers: "", // Used to store pre-condition of "showSequenceNumbers" - cycleSubprogramIsActive: false, // Indicate if it's handling a cycle subprogram - patternIsActive : false, // Indicate if it's handling a pattern subprogram - incrementalSubprogram : false, // Indicate if the current subprogram needs to go incremental mode - incrementalMode : false, // Indicate if incremental mode is on - mainProgramNumber : undefined // The main program number -}; - -function subprogramResolveSetting(_setting, _val, _comment) { - if (typeof _setting == "string") { - return formatWords(_setting.toString().replace("%currentSubprogram", subprogramState.currentSubprogram), (_comment ? formatComment(_comment) : "")); - } else { - return formatWords(_setting + (_val ? settings.subprograms.format.format(_val) : ""), (_comment ? formatComment(_comment) : "")); - } -} - -/** - * Start to redirect buffer to subprogram. - * @param {Vector} initialPosition Initial position - * @param {Vector} abc Machine axis angles - * @param {boolean} incremental If the subprogram needs to go incremental mode - */ -function subprogramStart(initialPosition, abc, incremental) { - var comment = getParameter("operation-comment", ""); - var startBlock; - if (getProperty("useFilesForSubprograms")) { - var _fileName = subprogramState.currentSubprogram; - var subprogramExtension = extension; - if (settings.subprograms.files) { - if (settings.subprograms.files.prefix != undefined) { - _fileName = subprogramResolveSetting(settings.subprograms.files.prefix, subprogramState.currentSubprogram); - } - if (settings.subprograms.files.extension) { - subprogramExtension = settings.subprograms.files.extension; - } - } - var path = FileSystem.getCombinedPath(FileSystem.getFolderPath(getOutputPath()), _fileName + "." + subprogramExtension); - redirectToFile(path); - startBlock = subprogramResolveSetting(settings.subprograms.startBlock.files, subprogramState.currentSubprogram, comment); - } else { - redirectToBuffer(); - startBlock = subprogramResolveSetting(settings.subprograms.startBlock.embedded, subprogramState.currentSubprogram, comment); - } - writeln(startBlock); - - subprogramState.saveShowSequenceNumbers = getProperty("showSequenceNumbers", undefined); - if (subprogramState.saveShowSequenceNumbers != undefined) { - setProperty("showSequenceNumbers", "false"); - } - if (incremental) { - setAbsIncMode(true, initialPosition, abc); - } - if (typeof gPlaneModal != "undefined" && typeof gMotionModal != "undefined") { - forceModals(gPlaneModal, gMotionModal); - } -} - -/** Output the command for calling a subprogram by its subprogram number. */ -function subprogramCall() { - var callBlock; - if (getProperty("useFilesForSubprograms")) { - callBlock = subprogramResolveSetting(settings.subprograms.callBlock.files, subprogramState.currentSubprogram); - } else { - callBlock = subprogramResolveSetting(settings.subprograms.callBlock.embedded, subprogramState.currentSubprogram); - } - writeBlock(callBlock); // call subprogram -} - -/** End of subprogram and close redirection. */ -function subprogramEnd() { - if (isRedirecting()) { - if (subprogramState.newSubprogram) { - var finalPosition = getFramePosition(currentSection.getFinalPosition()); - var abc; - if (currentSection.isMultiAxis() && machineConfiguration.isMultiAxisConfiguration()) { - abc = currentSection.getFinalToolAxisABC(); - } else { - abc = getCurrentDirection(); - } - setAbsIncMode(false, finalPosition, abc); - - if (getProperty("useFilesForSubprograms")) { - var endBlockFiles = subprogramResolveSetting(settings.subprograms.endBlock.files); - writeln(endBlockFiles); - } else { - var endBlockEmbedded = subprogramResolveSetting(settings.subprograms.endBlock.embedded); - writeln(endBlockEmbedded); - writeln(""); - subprogramState.subprograms += getRedirectionBuffer(); - } - } - forceAny(); - subprogramState.newSubprogram = false; - subprogramState.cycleSubprogramIsActive = false; - if (subprogramState.saveShowSequenceNumbers != undefined) { - setProperty("showSequenceNumbers", subprogramState.saveShowSequenceNumbers); - } - closeRedirection(); - } -} - -/** Returns true if the spatial vectors are significantly different. */ -function areSpatialVectorsDifferent(_vector1, _vector2) { - return (xyzFormat.getResultingValue(_vector1.x) != xyzFormat.getResultingValue(_vector2.x)) || - (xyzFormat.getResultingValue(_vector1.y) != xyzFormat.getResultingValue(_vector2.y)) || - (xyzFormat.getResultingValue(_vector1.z) != xyzFormat.getResultingValue(_vector2.z)); -} - -/** Returns true if the spatial boxes are a pure translation. */ -function areSpatialBoxesTranslated(_box1, _box2) { - return !areSpatialVectorsDifferent(Vector.diff(_box1[1], _box1[0]), Vector.diff(_box2[1], _box2[0])) && - !areSpatialVectorsDifferent(Vector.diff(_box2[0], _box1[0]), Vector.diff(_box2[1], _box1[1])); -} - -/** Returns true if the spatial boxes are same. */ -function areSpatialBoxesSame(_box1, _box2) { - return !areSpatialVectorsDifferent(_box1[0], _box2[0]) && !areSpatialVectorsDifferent(_box1[1], _box2[1]); -} - -/** - * Search defined pattern subprogram by the given id. - * @param {number} subprogramId Subprogram Id - * @returns {Object} Returns defined subprogram if found, otherwise returns undefined - */ -function getDefinedPatternSubprogram(subprogramId) { - for (var i = 0; i < subprogramState.definedSubprograms.length; ++i) { - if ((SUB_PATTERN == subprogramState.definedSubprograms[i].type) && (subprogramId == subprogramState.definedSubprograms[i].id)) { - return subprogramState.definedSubprograms[i]; - } - } - return undefined; -} - -/** - * Search defined cycle subprogram pattern by the given id, initialPosition, finalPosition. - * @param {number} subprogramId Subprogram Id - * @param {Vector} initialPosition Initial position of the cycle - * @param {Vector} finalPosition Final position of the cycle - * @returns {Object} Returns defined subprogram if found, otherwise returns undefined - */ -function getDefinedCycleSubprogram(subprogramId, initialPosition, finalPosition) { - for (var i = 0; i < subprogramState.definedSubprograms.length; ++i) { - if ((SUB_CYCLE == subprogramState.definedSubprograms[i].type) && (subprogramId == subprogramState.definedSubprograms[i].id) && - !areSpatialVectorsDifferent(initialPosition, subprogramState.definedSubprograms[i].initialPosition) && - !areSpatialVectorsDifferent(finalPosition, subprogramState.definedSubprograms[i].finalPosition)) { - return subprogramState.definedSubprograms[i]; - } - } - return undefined; -} - -/** - * Creates and returns new defined subprogram - * @param {Section} section The section to create subprogram - * @param {number} subprogramId Subprogram Id - * @param {number} subprogramType Subprogram type, can be SUB_UNKNOWN, SUB_PATTERN or SUB_CYCLE - * @param {Vector} initialPosition Initial position - * @param {Vector} finalPosition Final position - * @returns {Object} Returns new defined subprogram - */ -function defineNewSubprogram(section, subprogramId, subprogramType, initialPosition, finalPosition) { - // determine if this is valid for creating a subprogram - isValid = subprogramIsValid(section, subprogramId, subprogramType); - var subprogram = isValid ? subprogram = ++subprogramState.lastSubprogram : undefined; - subprogramState.definedSubprograms.push({ - type : subprogramType, - id : subprogramId, - subProgram : subprogram, - isValid : isValid, - initialPosition: initialPosition, - finalPosition : finalPosition - }); - return subprogramState.definedSubprograms[subprogramState.definedSubprograms.length - 1]; -} - -/** Returns true if the given section is a pattern **/ -function isPatternOperation(section) { - return section.isPatterned && section.isPatterned(); -} - -/** Returns true if the given section is a cycle operation **/ -function isCycleOperation(section, minimumCyclePoints) { - return section.doesStrictCycle && - (section.getNumberOfCycles() == 1) && (section.getNumberOfCyclePoints() >= minimumCyclePoints); -} - -/** Returns true if the subroutine bit flag is enabled **/ -function isSubProgramEnabledFor(subroutine) { - return subroutineBitmasks[getProperty("useSubroutines")] & subroutine; -} - -/** - * Define subprogram based on the property "useSubroutines" - * @param {Vector} _initialPosition Initial position - * @param {Vector} _abc Machine axis angles - */ -function subprogramDefine(_initialPosition, _abc) { - if (isSubProgramEnabledFor(NONE)) { - // Return early - return; - } - - if (subprogramState.lastSubprogram == undefined) { // initialize first subprogram number - if (settings.subprograms.initialSubprogramNumber == undefined) { - try { - subprogramState.lastSubprogram = getAsInt(programName); - subprogramState.mainProgramNumber = subprogramState.lastSubprogram; // mainProgramNumber must be a number - } catch (e) { - error(localize("Program name must be a number when using subprograms.")); - return; - } - } else { - subprogramState.lastSubprogram = settings.subprograms.initialSubprogramNumber - 1; - // if programName is a string set mainProgramNumber to undefined, if programName is a number set mainProgramNumber to programName - subprogramState.mainProgramNumber = (!isNaN(programName) && !isNaN(parseInt(programName, 10))) ? getAsInt(programName) : undefined; - } - } - - // convert patterns into subprograms - subprogramState.patternIsActive = false; - if (isSubProgramEnabledFor(PATTERNS) && isPatternOperation(currentSection)) { - var subprogramId = currentSection.getPatternId(); - var subprogramType = SUB_PATTERN; - var subprogramDefinition = getDefinedPatternSubprogram(subprogramId); - - subprogramState.newSubprogram = !subprogramDefinition; - if (subprogramState.newSubprogram) { - subprogramDefinition = defineNewSubprogram(currentSection, subprogramId, subprogramType, _initialPosition, _initialPosition); - } - - subprogramState.currentSubprogram = subprogramDefinition.subProgram; - if (subprogramDefinition.isValid) { - // make sure Z-position is output prior to subprogram call - var z = zOutput.format(_initialPosition.z); - if (!state.retractedZ && z) { - validate(!validateLengthCompensation || state.lengthCompensationActive, "Tool length compensation is not active."); // make sure that length compensation is enabled - var block = ""; - if (typeof gAbsIncModal != "undefined") { - block += gAbsIncModal.format(90); - } - if (typeof gPlaneModal != "undefined") { - block += gPlaneModal.format(17); - } - writeBlock(block); - zOutput.reset(); - invokeOnRapid(xOutput.getCurrent(), yOutput.getCurrent(), _initialPosition.z); - } - - // call subprogram - subprogramCall(); - subprogramState.patternIsActive = true; - - if (subprogramState.newSubprogram) { - subprogramStart(_initialPosition, _abc, subprogramState.incrementalSubprogram); - } else { - skipRemainingSection(); - setCurrentPosition(getFramePosition(currentSection.getFinalPosition())); - } - } - } - - // Patterns are not used, check other cases - if (!subprogramState.patternIsActive) { - // Output cycle operation as subprogram - if (isSubProgramEnabledFor(CYCLES) && isCycleOperation(currentSection, settings.subprograms.minimumCyclePoints)) { - var finalPosition = getFramePosition(currentSection.getFinalPosition()); - var subprogramId = currentSection.getNumberOfCyclePoints(); - var subprogramType = SUB_CYCLE; - var subprogramDefinition = getDefinedCycleSubprogram(subprogramId, _initialPosition, finalPosition); - subprogramState.newSubprogram = !subprogramDefinition; - if (subprogramState.newSubprogram) { - subprogramDefinition = defineNewSubprogram(currentSection, subprogramId, subprogramType, _initialPosition, finalPosition); - } - subprogramState.currentSubprogram = subprogramDefinition.subProgram; - subprogramState.cycleSubprogramIsActive = subprogramDefinition.isValid; - } - - // Neither patterns and cycles are used, check other operations - if (!subprogramState.cycleSubprogramIsActive && isSubProgramEnabledFor(ALLOPERATIONS)) { - // Output all operations as subprograms - subprogramState.currentSubprogram = ++subprogramState.lastSubprogram; - if (subprogramState.mainProgramNumber != undefined && (subprogramState.currentSubprogram == subprogramState.mainProgramNumber)) { - subprogramState.currentSubprogram = ++subprogramState.lastSubprogram; // avoid using main program number for current subprogram - } - subprogramCall(); - subprogramState.newSubprogram = true; - subprogramStart(_initialPosition, _abc, false); - } - } -} - -/** - * Determine if this is valid for creating a subprogram - * @param {Section} section The section to create subprogram - * @param {number} subprogramId Subprogram Id - * @param {number} subprogramType Subprogram type, can be SUB_UNKNOWN, SUB_PATTERN or SUB_CYCLE - * @returns {boolean} If this is valid for creating a subprogram - */ -function subprogramIsValid(_section, subprogramId, subprogramType) { - var sectionId = _section.getId(); - var numberOfSections = getNumberOfSections(); - var validSubprogram = subprogramType != SUB_CYCLE; - - var masterPosition = new Array(); - masterPosition[0] = getFramePosition(_section.getInitialPosition()); - masterPosition[1] = getFramePosition(_section.getFinalPosition()); - var tempBox = _section.getBoundingBox(); - var masterBox = new Array(); - masterBox[0] = getFramePosition(tempBox[0]); - masterBox[1] = getFramePosition(tempBox[1]); - - var rotation = getRotation(); - var translation = getTranslation(); - subprogramState.incrementalSubprogram = undefined; - - for (var i = 0; i < numberOfSections; ++i) { - var section = getSection(i); - if (section.getId() != sectionId) { - defineWorkPlane(section, false); - - // check for valid pattern - if (subprogramType == SUB_PATTERN) { - if (section.getPatternId() == subprogramId) { - var patternPosition = new Array(); - patternPosition[0] = getFramePosition(section.getInitialPosition()); - patternPosition[1] = getFramePosition(section.getFinalPosition()); - tempBox = section.getBoundingBox(); - var patternBox = new Array(); - patternBox[0] = getFramePosition(tempBox[0]); - patternBox[1] = getFramePosition(tempBox[1]); - - if (areSpatialBoxesSame(masterPosition, patternPosition) && areSpatialBoxesSame(masterBox, patternBox) && !section.isMultiAxis()) { - subprogramState.incrementalSubprogram = subprogramState.incrementalSubprogram ? subprogramState.incrementalSubprogram : false; - } else if (!areSpatialBoxesTranslated(masterPosition, patternPosition) || !areSpatialBoxesTranslated(masterBox, patternBox)) { - validSubprogram = false; - break; - } else { - subprogramState.incrementalSubprogram = true; - } - } - - // check for valid cycle operation - } else if (subprogramType == SUB_CYCLE) { - if ((section.getNumberOfCyclePoints() == subprogramId) && (section.getNumberOfCycles() == 1)) { - var patternInitial = getFramePosition(section.getInitialPosition()); - var patternFinal = getFramePosition(section.getFinalPosition()); - if (!areSpatialVectorsDifferent(patternInitial, masterPosition[0]) && !areSpatialVectorsDifferent(patternFinal, masterPosition[1])) { - validSubprogram = true; - break; - } - } - } - } - } - setRotation(rotation); - setTranslation(translation); - return (validSubprogram); -} - -/** - * Sets xyz and abc output formats to incremental or absolute type - * @param {boolean} incremental true: Sets incremental mode, false: Sets absolute mode - * @param {Vector} xyz Linear axis values for formating - * @param {Vector} abc Rotary axis values for formating -*/ -function setAbsIncMode(incremental, xyz, abc) { - var outputFormats = [xOutput, yOutput, zOutput, aOutput, bOutput, cOutput]; - for (var i = 0; i < outputFormats.length; ++i) { - outputFormats[i].setType(incremental ? TYPE_INCREMENTAL : TYPE_ABSOLUTE); - if (typeof incPrefix != "undefined" && typeof absPrefix != "undefined") { - outputFormats[i].setPrefix(incremental ? incPrefix[i] : absPrefix[i]); - } - if (i <= 2) { // xyz - outputFormats[i].setCurrent(xyz.getCoordinate(i)); - } else { // abc - outputFormats[i].setCurrent(abc.getCoordinate(i - 3)); - } - } - subprogramState.incrementalMode = incremental; - if (typeof gAbsIncModal != "undefined") { - if (incremental) { - forceModals(gAbsIncModal); - } - writeBlock(gAbsIncModal.format(incremental ? 91 : 90)); - } -} - -function setCyclePosition(_position) { - var _spindleAxis; - if (typeof gPlaneModal != "undefined") { - _spindleAxis = gPlaneModal.getCurrent() == 17 ? Z : (gPlaneModal.getCurrent() == 18 ? Y : X); - } else { - var _spindleDirection = machineConfiguration.getSpindleAxis().getAbsolute(); - _spindleAxis = isSameDirection(_spindleDirection, new Vector(0, 0, 1)) ? Z : isSameDirection(_spindleDirection, new Vector(0, 1, 0)) ? Y : X; - } - switch (_spindleAxis) { - case Z: - zOutput.format(_position); - break; - case Y: - yOutput.format(_position); - break; - case X: - xOutput.format(_position); - break; - } -} - -/** - * Place cycle operation in subprogram - * @param {Vector} initialPosition Initial position - * @param {Vector} abc Machine axis angles - * @param {boolean} incremental If the subprogram needs to go incremental mode - */ -function handleCycleSubprogram(initialPosition, abc, incremental) { - subprogramState.cycleSubprogramIsActive &= !(cycleExpanded || isProbeOperation()); - if (subprogramState.cycleSubprogramIsActive) { - // call subprogram - subprogramCall(); - subprogramStart(initialPosition, abc, incremental); - } -} - -function writeSubprograms() { - if (subprogramState.subprograms.length > 0) { - writeln(""); - write(subprogramState.subprograms); - } -} -// <<<<< INCLUDED FROM include_files/subprograms.cpi - -// >>>>> INCLUDED FROM include_files/onRapid_fanuc.cpi -function onRapid(_x, _y, _z) { - var x = xOutput.format(_x); - var y = yOutput.format(_y); - var z = zOutput.format(_z); - if (x || y || z) { - if (pendingRadiusCompensation >= 0) { - error(localize("Radius compensation mode cannot be changed at rapid traversal.")); - return; - } - writeBlock(gMotionModal.format(0), x, y, z); - forceFeed(); - } -} -// <<<<< INCLUDED FROM include_files/onRapid_fanuc.cpi -// >>>>> INCLUDED FROM include_files/onLinear_fanuc.cpi -function onLinear(_x, _y, _z, feed) { - if (pendingRadiusCompensation >= 0) { - xOutput.reset(); - yOutput.reset(); - } - var x = xOutput.format(_x); - var y = yOutput.format(_y); - var z = zOutput.format(_z); - var f = getFeed(feed); - if (x || y || z) { - if (pendingRadiusCompensation >= 0) { - pendingRadiusCompensation = -1; - var d = getSetting("outputToolDiameterOffset", true) ? diameterOffsetFormat.format(tool.diameterOffset) : ""; - writeBlock(gPlaneModal.format(17)); - switch (radiusCompensation) { - case RADIUS_COMPENSATION_LEFT: - writeBlock(gMotionModal.format(1), gFormat.format(41), x, y, z, d, f); - break; - case RADIUS_COMPENSATION_RIGHT: - writeBlock(gMotionModal.format(1), gFormat.format(42), x, y, z, d, f); - break; - default: - writeBlock(gMotionModal.format(1), gFormat.format(40), x, y, z, f); - } - } else { - writeBlock(gMotionModal.format(1), x, y, z, f); - } - } else if (f) { - if (getNextRecord().isMotion()) { // try not to output feed without motion - forceFeed(); // force feed on next line - } else { - writeBlock(gMotionModal.format(1), f); - } - } -} -// <<<<< INCLUDED FROM include_files/onLinear_fanuc.cpi -// >>>>> INCLUDED FROM include_files/onRapid5D_fanuc.cpi -function onRapid5D(_x, _y, _z, _a, _b, _c) { - if (pendingRadiusCompensation >= 0) { - error(localize("Radius compensation mode cannot be changed at rapid traversal.")); - return; - } - if (!currentSection.isOptimizedForMachine()) { - forceXYZ(); - } - var x = xOutput.format(_x); - var y = yOutput.format(_y); - var z = zOutput.format(_z); - var a = currentSection.isOptimizedForMachine() ? aOutput.format(_a) : toolVectorOutputI.format(_a); - var b = currentSection.isOptimizedForMachine() ? bOutput.format(_b) : toolVectorOutputJ.format(_b); - var c = currentSection.isOptimizedForMachine() ? cOutput.format(_c) : toolVectorOutputK.format(_c); - - if (x || y || z || a || b || c) { - writeBlock(gMotionModal.format(0), x, y, z, a, b, c); - forceFeed(); - } -} -// <<<<< INCLUDED FROM include_files/onRapid5D_fanuc.cpi -// >>>>> INCLUDED FROM include_files/onLinear5D_fanuc.cpi -function onLinear5D(_x, _y, _z, _a, _b, _c, feed, feedMode) { - if (pendingRadiusCompensation >= 0) { - error(localize("Radius compensation cannot be activated/deactivated for 5-axis move.")); - return; - } - if (!currentSection.isOptimizedForMachine()) { - forceXYZ(); - } - var x = xOutput.format(_x); - var y = yOutput.format(_y); - var z = zOutput.format(_z); - var a = currentSection.isOptimizedForMachine() ? aOutput.format(_a) : toolVectorOutputI.format(_a); - var b = currentSection.isOptimizedForMachine() ? bOutput.format(_b) : toolVectorOutputJ.format(_b); - var c = currentSection.isOptimizedForMachine() ? cOutput.format(_c) : toolVectorOutputK.format(_c); - if (feedMode == FEED_INVERSE_TIME) { - forceFeed(); - } - var f = feedMode == FEED_INVERSE_TIME ? inverseTimeOutput.format(feed) : getFeed(feed); - var fMode = feedMode == FEED_INVERSE_TIME ? 93 : getProperty("useG95") ? 95 : 94; - - if (x || y || z || a || b || c) { - writeBlock(gFeedModeModal.format(fMode), gMotionModal.format(1), x, y, z, a, b, c, f); - } else if (f) { - if (getNextRecord().isMotion()) { // try not to output feed without motion - forceFeed(); // force feed on next line - } else { - writeBlock(gFeedModeModal.format(fMode), gMotionModal.format(1), f); - } - } -} -// <<<<< INCLUDED FROM include_files/onLinear5D_fanuc.cpi -// >>>>> INCLUDED FROM include_files/onCircular_fanuc.cpi -function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { - if (pendingRadiusCompensation >= 0) { - error(localize("Radius compensation cannot be activated/deactivated for a circular move.")); - return; - } - - var start = getCurrentPosition(); - - if (isFullCircle()) { - if (getProperty("useRadius") || isHelical()) { // radius mode does not support full arcs - linearize(tolerance); - return; - } - switch (getCircularPlane()) { - case PLANE_XY: - writeBlock(gPlaneModal.format(17), gMotionModal.format(clockwise ? 2 : 3), iOutput.format(cx - start.x), jOutput.format(cy - start.y), getFeed(feed)); - break; - case PLANE_ZX: - writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), iOutput.format(cx - start.x), kOutput.format(cz - start.z), getFeed(feed)); - break; - case PLANE_YZ: - writeBlock(gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), jOutput.format(cy - start.y), kOutput.format(cz - start.z), getFeed(feed)); - break; - default: - linearize(tolerance); - } - } else if (!getProperty("useRadius")) { - switch (getCircularPlane()) { - case PLANE_XY: - writeBlock(gPlaneModal.format(17), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x), jOutput.format(cy - start.y), getFeed(feed)); - break; - case PLANE_ZX: - writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x), kOutput.format(cz - start.z), getFeed(feed)); - break; - case PLANE_YZ: - writeBlock(gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), jOutput.format(cy - start.y), kOutput.format(cz - start.z), getFeed(feed)); - break; - default: - if (getProperty("allow3DArcs")) { - // make sure maximumCircularSweep is well below 360deg - // we could use G02.4 or G03.4 - direction is calculated - var ip = getPositionU(0.5); - writeBlock(gMotionModal.format(clockwise ? 2.4 : 3.4), xOutput.format(ip.x), yOutput.format(ip.y), zOutput.format(ip.z), getFeed(feed)); - writeBlock(xOutput.format(x), yOutput.format(y), zOutput.format(z)); - } else { - linearize(tolerance); - } - } - } else { // use radius mode - var r = getCircularRadius(); - if (toDeg(getCircularSweep()) > (180 + 1e-9)) { - r = -r; // allow up to <360 deg arcs - } - switch (getCircularPlane()) { - case PLANE_XY: - writeBlock(gPlaneModal.format(17), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed)); - break; - case PLANE_ZX: - writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed)); - break; - case PLANE_YZ: - writeBlock(gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed)); - break; - default: - if (getProperty("allow3DArcs")) { - // make sure maximumCircularSweep is well below 360deg - // we could use G02.4 or G03.4 - direction is calculated - var ip = getPositionU(0.5); - writeBlock(gMotionModal.format(clockwise ? 2.4 : 3.4), xOutput.format(ip.x), yOutput.format(ip.y), zOutput.format(ip.z), getFeed(feed)); - writeBlock(xOutput.format(x), yOutput.format(y), zOutput.format(z)); - } else { - linearize(tolerance); - } - } - } -} -// <<<<< INCLUDED FROM include_files/onCircular_fanuc.cpi -// >>>>> INCLUDED FROM include_files/workPlaneFunctions_fanuc.cpi -var gRotationModal = createOutputVariable({current : 69, - onchange: function () { - state.twpIsActive = gRotationModal.getCurrent() != 69; - if (typeof probeVariables != "undefined") { - probeVariables.outputRotationCodes = probeVariables.probeAngleMethod == "G68"; - } - }}, gFormat); - -var currentWorkPlaneABC = undefined; -function forceWorkPlane() { - currentWorkPlaneABC = undefined; -} - -function cancelWCSRotation() { - if (typeof gRotationModal != "undefined" && gRotationModal.getCurrent() == 68) { - cancelWorkPlane(true); - } -} - -function cancelWorkPlane(force) { - if (typeof gRotationModal != "undefined") { - if (force) { - gRotationModal.reset(); - } - var command = gRotationModal.format(69); - if (command) { - writeBlock(command); // cancel frame - forceWorkPlane(); - } - } -} - -function setWorkPlane(abc) { - if (!settings.workPlaneMethod.forceMultiAxisIndexing && is3D() && !machineConfiguration.isMultiAxisConfiguration()) { - return; // ignore - } - var workplaneIsRequired = (currentWorkPlaneABC == undefined) || - abcFormat.areDifferent(abc.x, currentWorkPlaneABC.x) || - abcFormat.areDifferent(abc.y, currentWorkPlaneABC.y) || - abcFormat.areDifferent(abc.z, currentWorkPlaneABC.z); - - writeStartBlocks(workplaneIsRequired, function () { - writeRetract(Z); - if (getSetting("retract.homeXY.onIndexing", false)) { - writeRetract(settings.retract.homeXY.onIndexing); - } - if (currentSection.getId() > 0 && (isTCPSupportedByOperation(getSection(currentSection.getId() - 1) || tcp.isSupportedByOperation)) && typeof disableLengthCompensation == "function") { - disableLengthCompensation(); // cancel TCP - } - - if (settings.workPlaneMethod.useTiltedWorkplane) { - onCommand(COMMAND_UNLOCK_MULTI_AXIS); - cancelWorkPlane(); - if (machineConfiguration.isMultiAxisConfiguration()) { - var machineABC = abc.isNonZero() ? (currentSection.isMultiAxis() ? getCurrentDirection() : getWorkPlaneMachineABC(currentSection, false)) : abc; - if (settings.workPlaneMethod.useABCPrepositioning || machineABC.isZero()) { - positionABC(machineABC, false); - } else { - setCurrentABC(machineABC); - } - } - if (abc.isNonZero() || !machineConfiguration.isMultiAxisConfiguration()) { - gRotationModal.reset(); - writeBlock( - gRotationModal.format(68.2), "X" + xyzFormat.format(currentSection.workOrigin.x), "Y" + xyzFormat.format(currentSection.workOrigin.y), "Z" + xyzFormat.format(currentSection.workOrigin.z), - "I" + abcFormat.format(abc.x), "J" + abcFormat.format(abc.y), "K" + abcFormat.format(abc.z) - ); // set frame - writeBlock(gFormat.format(53.1)); // turn machine - machineSimulation({a:getCurrentABC().x, b:getCurrentABC().y, c:getCurrentABC().z, coordinates:MACHINE, eulerAngles:abc}); - } - } else { - positionABC(abc, true); - } - if (!currentSection.isMultiAxis()) { - onCommand(COMMAND_LOCK_MULTI_AXIS); - } - currentWorkPlaneABC = abc; - }); -} -// <<<<< INCLUDED FROM include_files/workPlaneFunctions_fanuc.cpi -// >>>>> INCLUDED FROM include_files/writeRetract_fanuc.cpi -function writeRetract() { - var retract = getRetractParameters.apply(this, arguments); - if (retract && retract.words.length > 0) { - if (typeof cancelWCSRotation == "function" && getSetting("retract.cancelRotationOnRetracting", false)) { // cancel rotation before retracting - cancelWCSRotation(); - } - if (typeof disableLengthCompensation == "function" && getSetting("allowCancelTCPBeforeRetracting", false) && state.tcpIsActive) { - disableLengthCompensation(); // cancel TCP before retracting - } - for (var i in retract.words) { - var words = retract.singleLine ? retract.words : retract.words[i]; - switch (retract.method) { - case "G28": - forceModals(gMotionModal, gAbsIncModal); - writeBlock(gFormat.format(28), gAbsIncModal.format(91), words); - writeBlock(gAbsIncModal.format(90)); - break; - case "G30": - forceModals(gMotionModal, gAbsIncModal); - writeBlock(gFormat.format(30), gAbsIncModal.format(91), words); - writeBlock(gAbsIncModal.format(90)); - break; - case "G53": - forceModals(gMotionModal); - writeBlock(gAbsIncModal.format(90), gFormat.format(53), gMotionModal.format(0), words); - break; - default: - if (typeof writeRetractCustom == "function") { - writeRetractCustom(retract); - } else { - error(subst(localize("Unsupported safe position method '%1'"), retract.method)); - return; - } - } - machineSimulation({ - x : retract.singleLine || words.indexOf("X") != -1 ? retract.positions.x : undefined, - y : retract.singleLine || words.indexOf("Y") != -1 ? retract.positions.y : undefined, - z : retract.singleLine || words.indexOf("Z") != -1 ? retract.positions.z : undefined, - coordinates: MACHINE - }); - if (retract.singleLine) { - break; - } - } - } -} -// <<<<< INCLUDED FROM include_files/writeRetract_fanuc.cpi -// >>>>> INCLUDED FROM include_files/initialPositioning_fanuc.cpi -/** - * Writes the initial positioning procedure for a section to get to the start position of the toolpath. - * @param {Vector} position The initial position to move to - * @param {boolean} isRequired true: Output full positioning, false: Output full positioning in optional state or output simple positioning only - * @param {String} codes1 Allows to add additional code to the first positioning line - * @param {String} codes2 Allows to add additional code to the second positioning line (if applicable) - * @example - var myVar1 = formatWords("T" + tool.number, currentSection.wcs); - var myVar2 = getCoolantCodes(tool.coolant); - writeInitialPositioning(initialPosition, isRequired, myVar1, myVar2); -*/ -function writeInitialPositioning(position, isRequired, codes1, codes2) { - var motionCode = {single:0, multi:0}; - switch (highFeedMapping) { - case HIGH_FEED_MAP_ANY: - motionCode = {single:1, multi:1}; // map all rapid traversals to high feed - break; - case HIGH_FEED_MAP_MULTI: - motionCode = {single:0, multi:1}; // map rapid traversal along more than one axis to high feed - break; - } - var feed = (highFeedMapping != HIGH_FEED_NO_MAPPING) ? getFeed(highFeedrate) : ""; - var hOffset = getSetting("outputToolLengthOffset", true) ? hFormat.format(tool.lengthOffset) : ""; - var additionalCodes = [formatWords(codes1), formatWords(codes2)]; - - forceModals(gMotionModal); - writeStartBlocks(isRequired, function() { - var modalCodes = formatWords(gAbsIncModal.format(90), gPlaneModal.format(17)); - if (typeof disableLengthCompensation == "function") { - disableLengthCompensation(!isRequired); // cancel tool length compensation prior to enabling it, required when switching G43/G43.4 modes - } - - // multi axis prepositioning with TWP - if (currentSection.isMultiAxis() && getSetting("workPlaneMethod.prepositionWithTWP", true) && getSetting("workPlaneMethod.useTiltedWorkplane", false) && - tcp.isSupportedByOperation && getCurrentDirection().isNonZero()) { - var W = machineConfiguration.isMultiAxisConfiguration() ? machineConfiguration.getOrientation(getCurrentDirection()) : - Matrix.getOrientationFromDirection(getCurrentDirection()); - var prePosition = W.getTransposed().multiply(position); - var angles = W.getEuler2(settings.workPlaneMethod.eulerConvention); - setWorkPlane(angles); - writeBlock(modalCodes, gMotionModal.format(motionCode.multi), xOutput.format(prePosition.x), yOutput.format(prePosition.y), feed, additionalCodes[0]); - machineSimulation({x:prePosition.x, y:prePosition.y}); - cancelWorkPlane(); - writeBlock(getOffsetCode(), hOffset, additionalCodes[1]); // omit Z-axis output is desired - forceAny(); // required to output XYZ coordinates in the following line - } else { - if (machineConfiguration.isHeadConfiguration()) { - writeBlock(modalCodes, gMotionModal.format(motionCode.multi), getOffsetCode(), - xOutput.format(position.x), yOutput.format(position.y), zOutput.format(position.z), - hOffset, feed, additionalCodes - ); - machineSimulation({x:position.x, y:position.y, z:position.z}); - } else { - writeBlock(modalCodes, gMotionModal.format(motionCode.multi), xOutput.format(position.x), yOutput.format(position.y), feed, additionalCodes[0]); - machineSimulation({x:position.x, y:position.y}); - writeBlock(gMotionModal.format(motionCode.single), getOffsetCode(), zOutput.format(position.z), hOffset, additionalCodes[1]); - machineSimulation(tcp.isSupportedByOperation ? {x:position.x, y:position.y, z:position.z} : {z:position.z}); - } - } - forceModals(gMotionModal); - if (isRequired) { - additionalCodes = []; // clear additionalCodes buffer - } - }); - - validate(!validateLengthCompensation || state.lengthCompensationActive, "Tool length compensation is not active."); // make sure that lenght compensation is enabled - if (!isRequired) { // simple positioning - var modalCodes = formatWords(gAbsIncModal.format(90), gPlaneModal.format(17)); - if (!state.retractedZ && xyzFormat.getResultingValue(getCurrentPosition().z) < xyzFormat.getResultingValue(position.z)) { - writeBlock(modalCodes, gMotionModal.format(motionCode.single), zOutput.format(position.z), feed); - machineSimulation({z:position.z}); - } - forceXYZ(); - writeBlock(modalCodes, gMotionModal.format(motionCode.multi), xOutput.format(position.x), yOutput.format(position.y), feed, additionalCodes); - machineSimulation({x:position.x, y:position.y}); - } -} - -Matrix.getOrientationFromDirection = function (ijk) { - var forward = ijk; - var unitZ = new Vector(0, 0, 1); - var W; - if (Math.abs(Vector.dot(forward, unitZ)) < 0.5) { - var imX = Vector.cross(forward, unitZ).getNormalized(); - W = new Matrix(imX, Vector.cross(forward, imX), forward); - } else { - var imX = Vector.cross(new Vector(0, 1, 0), forward).getNormalized(); - W = new Matrix(imX, Vector.cross(forward, imX), forward); - } - return W; -}; -// <<<<< INCLUDED FROM include_files/initialPositioning_fanuc.cpi -// >>>>> INCLUDED FROM include_files/getOffsetCode_fanuc.cpi -var toolLengthCompOutput = createOutputVariable({control : CONTROL_FORCE, - onchange: function() { - state.tcpIsActive = toolLengthCompOutput.getCurrent() == 43.4 || toolLengthCompOutput.getCurrent() == 43.5; - state.lengthCompensationActive = toolLengthCompOutput.getCurrent() != 49; - } -}, gFormat); - -function getOffsetCode() { - if (!getSetting("outputToolLengthCompensation", true) && toolLengthCompOutput.isEnabled()) { - state.lengthCompensationActive = true; // always assume that length compensation is active - toolLengthCompOutput.disable(); - } - var offsetCode = 43; - if (tcp.isSupportedByOperation) { - offsetCode = machineConfiguration.isMultiAxisConfiguration() ? 43.4 : 43.5; - } - return toolLengthCompOutput.format(offsetCode); -} -// <<<<< INCLUDED FROM include_files/getOffsetCode_fanuc.cpi -// >>>>> INCLUDED FROM include_files/disableLengthCompensation_fanuc.cpi -function disableLengthCompensation(force) { - if (state.lengthCompensationActive || force) { - if (force) { - toolLengthCompOutput.reset(); - } - if (!getSetting("allowCancelTCPBeforeRetracting", false)) { - validate(state.retractedZ, "Cannot cancel tool length compensation if the machine is not fully retracted."); - } - writeBlock(toolLengthCompOutput.format(49)); - } -} -// <<<<< INCLUDED FROM include_files/disableLengthCompensation_fanuc.cpi -// >>>>> INCLUDED FROM include_files/getProgramNumber_fanuc.cpi -function getProgramNumber() { - if (typeof oFormat != "undefined" && getProperty("o8")) { - oFormat.setMinDigitsLeft(8); - } - var minimumProgramNumber = getSetting("programNumber.min", 1); - var maximumProgramNumber = getSetting("programNumber.max", getProperty("o8") ? 99999999 : 9999); - var reservedProgramNumbers = getSetting("programNumber.reserved", [8000, 9999]); - if (programName) { - var _programNumber; - try { - _programNumber = getAsInt(programName); - } catch (e) { - error(localize("Program name must be a number.")); - } - if (!((_programNumber >= minimumProgramNumber) && (_programNumber <= maximumProgramNumber))) { - error(subst(localize("Program number '%1' is out of range. Please enter a program number between '%2' and '%3'."), _programNumber, minimumProgramNumber, maximumProgramNumber)); - } - if ((_programNumber >= reservedProgramNumbers[0]) && (_programNumber <= reservedProgramNumbers[1])) { - warning(subst(localize("Program number '%1' is potentially reserved by the machine tool builder. Reserved range is '%2' to '%3'."), _programNumber, reservedProgramNumbers[0], reservedProgramNumbers[1])); - } - } else { - error(localize("Program name has not been specified.")); - } - return _programNumber; -} -// <<<<< INCLUDED FROM include_files/getProgramNumber_fanuc.cpi -// >>>>> INCLUDED FROM include_files/drillCycles_fanuc.cpi -function writeDrillCycle(cycle, x, y, z) { - if (!isSameDirection(machineConfiguration.getSpindleAxis(), getForwardDirection(currentSection))) { - expandCyclePoint(x, y, z); - return; - } - if (isFirstCyclePoint()) { - // return to initial Z which is clearance plane and set absolute mode - repositionToCycleClearance(cycle, x, y, z); - - var F = getProperty("useG95") ? (cycle.feedrate / spindleSpeed) : cycle.feedrate; - var P = !cycle.dwell ? 0 : clamp(1, cycle.dwell * 1000, 99999999); // in milliseconds - switch (cycleType) { - case "drilling": - writeBlock( - gRetractModal.format(98), gCycleModal.format(81), - getCommonCycle(x, y, z, cycle.retract, cycle.clearance), - feedOutput.format(F) - ); - break; - case "counter-boring": - if (P > 0) { - writeBlock( - gRetractModal.format(98), gCycleModal.format(82), - getCommonCycle(x, y, z, cycle.retract, cycle.clearance), - "P" + milliFormat.format(P), - feedOutput.format(F) - ); - } else { - writeBlock( - gRetractModal.format(98), gCycleModal.format(81), - getCommonCycle(x, y, z, cycle.retract, cycle.clearance), - feedOutput.format(F) - ); - } - break; - case "chip-breaking": - if ((cycle.accumulatedDepth < cycle.depth) || (P > 0)) { - expandCyclePoint(x, y, z); - } else { - writeBlock( - gRetractModal.format(98), gCycleModal.format(73), - getCommonCycle(x, y, z, cycle.retract, cycle.clearance), - peckOutput.format(cycle.incrementalDepth), - feedOutput.format(F) - ); - } - break; - case "deep-drilling": - if (P > 0) { - expandCyclePoint(x, y, z); - } else { - writeBlock( - gRetractModal.format(98), gCycleModal.format(83), - getCommonCycle(x, y, z, cycle.retract, cycle.clearance), - peckOutput.format(cycle.incrementalDepth), - // conditional(P > 0, "P" + milliFormat.format(P)), - feedOutput.format(F) - ); - } - break; - case "tapping": - if (getProperty("useRigidTapping") != "no") { - writeBlock(mFormat.format(29), sOutput.format(spindleSpeed)); - } - if (getProperty("usePitchForTapping")) { - writeBlock( - gRetractModal.format(98), gFeedModeModal.format(95), gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND) ? 74 : 84), - getCommonCycle(x, y, z, cycle.retract, cycle.clearance), - "P" + milliFormat.format(P), - pitchOutput.format(tool.threadPitch) - ); - forceFeed(); - } else { - var tappingFPM = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); - F = (getProperty("useG95") ? tool.getThreadPitch() : tappingFPM); - writeBlock( - gRetractModal.format(98), gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND) ? 74 : 84), - getCommonCycle(x, y, z, cycle.retract, cycle.clearance), - "P" + milliFormat.format(P), - feedOutput.format(F) - ); - } - break; - case "left-tapping": - if (getProperty("useRigidTapping") != "no") { - writeBlock(mFormat.format(29), sOutput.format(spindleSpeed)); - } - if (getProperty("usePitchForTapping")) { - writeBlock( - gRetractModal.format(98), gFeedModeModal.format(95), gCycleModal.format(74), - getCommonCycle(x, y, z, cycle.retract, cycle.clearance), - "P" + milliFormat.format(P), - pitchOutput.format(tool.threadPitch) - ); - forceFeed(); - } else { - var tappingFPM = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); - F = (getProperty("useG95") ? tool.getThreadPitch() : tappingFPM); - writeBlock( - gRetractModal.format(98), gCycleModal.format(74), - getCommonCycle(x, y, z, cycle.retract, cycle.clearance), - "P" + milliFormat.format(P), - feedOutput.format(F) - ); - } - break; - case "right-tapping": - if (getProperty("useRigidTapping") != "no") { - writeBlock(mFormat.format(29), sOutput.format(spindleSpeed)); - } - if (getProperty("usePitchForTapping")) { - writeBlock( - gRetractModal.format(98), gFeedModeModal.format(95), gCycleModal.format(84), - getCommonCycle(x, y, z, cycle.retract, cycle.clearance), - "P" + milliFormat.format(P), - pitchOutput.format(tool.threadPitch) - ); - forceFeed(); - } else { - var tappingFPM = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); - F = (getProperty("useG95") ? tool.getThreadPitch() : tappingFPM); - writeBlock( - gRetractModal.format(98), gCycleModal.format(84), - getCommonCycle(x, y, z, cycle.retract, cycle.clearance), - "P" + milliFormat.format(P), - feedOutput.format(F) - ); - } - break; - case "tapping-with-chip-breaking": - case "left-tapping-with-chip-breaking": - case "right-tapping-with-chip-breaking": - if (cycle.accumulatedDepth < cycle.depth) { - error(localize("Accumulated pecking depth is not supported for tapping cycles with chip breaking.")); - return; - } else { - if (getProperty("useRigidTapping") != "no") { - writeBlock(mFormat.format(29), sOutput.format(spindleSpeed)); - } - if (getProperty("usePitchForTapping")) { - writeBlock( - gRetractModal.format(98), gFeedModeModal.format(95), gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND ? 74 : 84)), - getCommonCycle(x, y, z, cycle.retract, cycle.clearance), - "P" + milliFormat.format(P), - peckOutput.format(cycle.incrementalDepth), - pitchOutput.format(tool.threadPitch) - ); - forceFeed(); - } else { - var tappingFPM = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); - F = (getProperty("useG95") ? tool.getThreadPitch() : tappingFPM); - writeBlock( - gRetractModal.format(98), gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND ? 74 : 84)), - getCommonCycle(x, y, z, cycle.retract, cycle.clearance), - "P" + milliFormat.format(P), - peckOutput.format(cycle.incrementalDepth), - feedOutput.format(F) - ); - } - } - break; - case "fine-boring": - writeBlock( - gRetractModal.format(98), gCycleModal.format(76), - getCommonCycle(x, y, z, cycle.retract, cycle.clearance), - "P" + milliFormat.format(P), // not optional - "Q" + xyzFormat.format(cycle.shift), - feedOutput.format(F) - ); - break; - case "back-boring": - var dx = (gPlaneModal.getCurrent() == 19) ? cycle.backBoreDistance : 0; - var dy = (gPlaneModal.getCurrent() == 18) ? cycle.backBoreDistance : 0; - var dz = (gPlaneModal.getCurrent() == 17) ? cycle.backBoreDistance : 0; - writeBlock( - gRetractModal.format(98), gCycleModal.format(87), - getCommonCycle(x - dx, y - dy, z - dz, cycle.bottom, cycle.clearance), - "Q" + xyzFormat.format(cycle.shift), - "P" + milliFormat.format(P), // not optional - feedOutput.format(F) - ); - break; - case "reaming": - if (feedFormat.getResultingValue(cycle.feedrate) != feedFormat.getResultingValue(cycle.retractFeedrate)) { - expandCyclePoint(x, y, z); - break; - } - if (P > 0) { - writeBlock( - gRetractModal.format(98), gCycleModal.format(89), - getCommonCycle(x, y, z, cycle.retract, cycle.clearance), - "P" + milliFormat.format(P), - feedOutput.format(F) - ); - } else { - writeBlock( - gRetractModal.format(98), gCycleModal.format(85), - getCommonCycle(x, y, z, cycle.retract, cycle.clearance), - feedOutput.format(F) - ); - } - break; - case "stop-boring": - if (P > 0) { - expandCyclePoint(x, y, z); - } else { - writeBlock( - gRetractModal.format(98), gCycleModal.format(86), - getCommonCycle(x, y, z, cycle.retract, cycle.clearance), - feedOutput.format(F) - ); - } - break; - case "manual-boring": - writeBlock( - gRetractModal.format(98), gCycleModal.format(88), - getCommonCycle(x, y, z, cycle.retract, cycle.clearance), - "P" + milliFormat.format(P), // not optional - feedOutput.format(F) - ); - break; - case "boring": - if (feedFormat.getResultingValue(cycle.feedrate) != feedFormat.getResultingValue(cycle.retractFeedrate)) { - expandCyclePoint(x, y, z); - break; - } - if (P > 0) { - writeBlock( - gRetractModal.format(98), gCycleModal.format(89), - getCommonCycle(x, y, z, cycle.retract, cycle.clearance), - "P" + milliFormat.format(P), // not optional - feedOutput.format(F) - ); - } else { - writeBlock( - gRetractModal.format(98), gCycleModal.format(85), - getCommonCycle(x, y, z, cycle.retract, cycle.clearance), - feedOutput.format(F) - ); - } - break; - default: - expandCyclePoint(x, y, z); - } - if (subprogramsAreSupported()) { - // place cycle operation in subprogram - handleCycleSubprogram(new Vector(x, y, z), new Vector(0, 0, 0), false); - if (subprogramState.incrementalMode) { // set current position to clearance height - setCyclePosition(cycle.clearance); - } - } - } else { - if (cycleExpanded) { - expandCyclePoint(x, y, z); - } else { - if (!xyzFormat.areDifferent(x, xOutput.getCurrent()) && - !xyzFormat.areDifferent(y, yOutput.getCurrent()) && - !xyzFormat.areDifferent(z, zOutput.getCurrent())) { - switch (gPlaneModal.getCurrent()) { - case 17: // XY - xOutput.reset(); // at least one axis is required - break; - case 18: // ZX - zOutput.reset(); // at least one axis is required - break; - case 19: // YZ - yOutput.reset(); // at least one axis is required - break; - } - } - if (subprogramsAreSupported() && subprogramState.incrementalMode) { // set current position to retract height - setCyclePosition(cycle.retract); - } - writeBlock(xOutput.format(x), yOutput.format(y), zOutput.format(z)); - if (subprogramsAreSupported() && subprogramState.incrementalMode) { // set current position to clearance height - setCyclePosition(cycle.clearance); - } - } - } -} - -function getCommonCycle(x, y, z, r, c) { - forceXYZ(); // force xyz on first drill hole of any cycle - if (subprogramsAreSupported() && subprogramState.incrementalMode) { - zOutput.format(c); - return [xOutput.format(x), yOutput.format(y), - "Z" + xyzFormat.format(z - r), - "R" + xyzFormat.format(r - c)]; - } else { - return [xOutput.format(x), yOutput.format(y), - zOutput.format(z), - "R" + xyzFormat.format(r)]; - } -} -// <<<<< INCLUDED FROM include_files/drillCycles_fanuc.cpi -// >>>>> INCLUDED FROM include_files/commonInspectionFunctions_fanuc.cpi -var macroFormat = createFormat({prefix:(typeof inspectionVariables == "undefined" ? "#" : inspectionVariables.localVariablePrefix), decimals:0}); -var macroRoundingFormat = (unit == MM) ? "[53]" : "[44]"; -var isDPRNTopen = false; - -var WARNING_OUTDATED = 0; -var toolpathIdFormat = createFormat({decimals:5, forceDecimal:true}); -var patternInstances = new Array(); -var initializePatternInstances = true; // initialize patternInstances array the first time inspectionGetToolpathId is called -function inspectionGetToolpathId(section) { - if (initializePatternInstances) { - for (var i = 0; i < getNumberOfSections(); ++i) { - var _section = getSection(i); - if (_section.getInternalPatternId) { - var sectionId = _section.getId(); - var patternId = _section.getInternalPatternId(); - var isPatterned = _section.isPatterned && _section.isPatterned(); - var isMirrored = patternId != _section.getPatternId(); - if (isPatterned || isMirrored) { - var isKnownPatternId = false; - for (var j = 0; j < patternInstances.length; j++) { - if (patternId == patternInstances[j].patternId) { - patternInstances[j].patternIndex++; - patternInstances[j].sections.push(sectionId); - isKnownPatternId = true; - break; - } - } - if (!isKnownPatternId) { - patternInstances.push({patternId:patternId, patternIndex:1, sections:[sectionId]}); - } - } - } - } - initializePatternInstances = false; - } - - var _operationId = section.getParameter("autodeskcam:operation-id", ""); - var key = -1; - for (k in patternInstances) { - if (patternInstances[k].patternId == _operationId) { - key = k; - break; - } - } - var _patternId = (key > -1) ? patternInstances[key].sections.indexOf(section.getId()) + 1 : 0; - var _cycleId = cycle && ("cycleID" in cycle) ? cycle.cycleID : section.getParameter("cycleID", 0); - if (isProbeOperation(section) && _cycleId == 0 && getGlobalParameter("product-id").toLowerCase().indexOf("fusion") > -1) { - // we expect the cycleID to be non zero always for macro probing toolpaths, Fusion only - warningOnce(localize("Outdated macro probing operations detected. Please regenerate all macro probing operations."), WARNING_OUTDATED); - } - if (_patternId > 99) { - error(subst(localize("The maximum number of pattern instances is limited to 99" + EOL + - "You need to split operation '%1' into separate pattern groups." - ), section.getParameter("operation-comment", ""))); - } - if (_cycleId > 99) { - error(subst(localize("The maximum number of probing cycles is limited to 99" + EOL + - "You need to split operation '%1' to multiple operations with less than 100 cycles in each operation." - ), section.getParameter("operation-comment", ""))); - } - return toolpathIdFormat.format(_operationId + (_cycleId * 0.01) + (_patternId * 0.0001) + 0.00001); -} - -var localVariableStart = 19; -var localVariable = [ - macroFormat.format(localVariableStart + 1), - macroFormat.format(localVariableStart + 2), - macroFormat.format(localVariableStart + 3), - macroFormat.format(localVariableStart + 4), - macroFormat.format(localVariableStart + 5), - macroFormat.format(localVariableStart + 6) -]; - -function defineLocalVariable(indx, value) { - writeln(localVariable[indx - 1] + " = " + value); -} - -function formatLocalVariable(prefix, indx, rnd) { - return prefix + localVariable[indx - 1] + rnd; -} - -function inspectionCreateResultsFileHeader() { - if (isDPRNTopen) { - if (!getProperty("singleResultsFile")) { - writeln("DPRNT[END]"); - writeBlock("PCLOS"); - isDPRNTopen = false; - } - } - - if (isProbeOperation() && !printProbeResults()) { - return; // if print results is not desired by probe/ probeWCS - } - - if (!isDPRNTopen) { - writeBlock("PCLOS"); - writeBlock("POPEN"); - // check for existence of none alphanumeric characters but not spaces - var resFile; - if (getProperty("singleResultsFile")) { - resFile = getParameter("job-description") + "-RESULTS"; - } else { - resFile = getParameter("operation-comment") + "-RESULTS"; - } - resFile = resFile.replace(/:/g, "-"); - resFile = resFile.replace(/[^a-zA-Z0-9 -]/g, ""); - resFile = resFile.replace(/\s/g, "-"); - resFile = resFile.toUpperCase(); - writeln("DPRNT[START]"); - writeln("DPRNT[RESULTSFILE*" + resFile + "]"); - if (hasGlobalParameter("document-id")) { - writeln("DPRNT[DOCUMENTID*" + getGlobalParameter("document-id").toUpperCase() + "]"); - } - if (hasGlobalParameter("model-version")) { - writeln("DPRNT[MODELVERSION*" + getGlobalParameter("model-version").toUpperCase() + "]"); - } - } - if (isProbeOperation() && printProbeResults()) { - isDPRNTopen = true; - } -} - -function getPointNumber() { - if (typeof inspectionWriteVariables == "function") { - return (inspectionVariables.pointNumber); - } else { - return ("#122[60]"); - } -} - -function inspectionWriteCADTransform() { - var cadOrigin = currentSection.getModelOrigin(); - var cadWorkPlane = currentSection.getModelPlane().getTransposed(); - var cadEuler = cadWorkPlane.getEuler2(EULER_XYZ_S); - defineLocalVariable(1, abcFormat.format(cadEuler.x)); - defineLocalVariable(2, abcFormat.format(cadEuler.y)); - defineLocalVariable(3, abcFormat.format(cadEuler.z)); - defineLocalVariable(4, xyzFormat.format(-cadOrigin.x)); - defineLocalVariable(5, xyzFormat.format(-cadOrigin.y)); - defineLocalVariable(6, xyzFormat.format(-cadOrigin.z)); - writeln( - "DPRNT[G331" + - "*N" + getPointNumber() + - formatLocalVariable("*A", 1, macroRoundingFormat) + - formatLocalVariable("*B", 2, macroRoundingFormat) + - formatLocalVariable("*C", 3, macroRoundingFormat) + - formatLocalVariable("*X", 4, macroRoundingFormat) + - formatLocalVariable("*Y", 5, macroRoundingFormat) + - formatLocalVariable("*Z", 6, macroRoundingFormat) + - "]" - ); -} - -function inspectionWriteWorkplaneTransform() { - var orientation = machineConfiguration.isMultiAxisConfiguration() ? machineConfiguration.getOrientation(getCurrentDirection()) : currentSection.workPlane; - var abc = orientation.getEuler2(EULER_XYZ_S); - if (getProperty("useLiveConnection")) { - liveConnectorInterface("WORKPLANE"); - writeBlock(inspectionVariables.liveConnectionWPA, "=", abcFormat.format(abc.x)); - writeBlock(inspectionVariables.liveConnectionWPB, "=", abcFormat.format(abc.y)); - writeBlock(inspectionVariables.liveConnectionWPC, "=", abcFormat.format(abc.z)); - forceSequenceNumbers(true); - writeBlock("IF [" + inspectionVariables.workplaneStartAddress, "NE -1] GOTO" + skipNLines(2)); - writeBlock(inspectionVariables.workplaneStartAddress, "=", inspectionGetToolpathId(currentSection)); - writeBlock(" "); - forceSequenceNumbers(false); - } - - defineLocalVariable(1, abcFormat.format(abc.x)); - defineLocalVariable(2, abcFormat.format(abc.y)); - defineLocalVariable(3, abcFormat.format(abc.z)); - writeln("DPRNT[G330" + - "*N" + getPointNumber() + - formatLocalVariable("*A", 1, macroRoundingFormat) + - formatLocalVariable("*B", 2, macroRoundingFormat) + - formatLocalVariable("*C", 3, macroRoundingFormat) + - "*X0*Y0*Z0*I0*R0]" - ); -} - -function writeProbingToolpathInformation(cycleDepth) { - defineLocalVariable(1, inspectionGetToolpathId(currentSection)); - writeln(formatLocalVariable("DPRNT[TOOLPATHID*", 1, "[35]]")); - if (isInspectionOperation()) { - writeln("DPRNT[TOOLPATH*" + getParameter("operation-comment").toUpperCase().replace(/[()]/g, "") + "]"); - } else { - defineLocalVariable(2, xyzFormat.format(cycleDepth)); - writeln(formatLocalVariable("DPRNT[CYCLEDEPTH*", 2, macroRoundingFormat + "]")); - } -} -// <<<<< INCLUDED FROM include_files/commonInspectionFunctions_fanuc.cpi -// >>>>> INCLUDED FROM include_files/probeCycles_renishaw.cpi -validate(settings.probing, "Setting 'probing' is required but not defined."); -var probeVariables = { - outputRotationCodes: false, // determines if it is required to output rotation codes - compensationXY : undefined, - probeAngleMethod : undefined, - rotaryTableAxis : -1 -}; -function writeProbeCycle(cycle, x, y, z, P, F) { - var openString = "OPEN[0,1,\"" + programName + "_inspection_report" + "_@980" + "_@981" + "_@982" + "_@983" + "_@984" + "_@985" + "\"]"; - if (isProbeOperation()) { - if (!settings.workPlaneMethod.useTiltedWorkplane && !isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, 1))) { - if (!settings.probing.allowIndexingWCSProbing && currentSection.strategy == "probe") { - error(localize("Updating WCS / work offset using probing is only supported by the CNC in the WCS frame.")); - return; - } - } - if (printProbeResults()) { - writeProbingToolpathInformation(z - cycle.depth + tool.diameter / 2); - inspectionWriteCADTransform(); - inspectionWriteWorkplaneTransform(); - if (typeof inspectionWriteVariables == "function") { - inspectionVariables.pointNumber += 1; - } - } - protectedProbeMove(cycle, x, y, z); - } - - var macroCall = settings.probing.macroCall; - switch (cycleType) { - case "probing-x": - forceXYZ(); - protectedProbeMove(cycle, x, y, z - cycle.depth); - - WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); - EXPECTED_Y = yOutput.format(y + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)); - EXPECTED_X = xOutput.format(x + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)); - EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); - DISTANCE = approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2 + cycle.probeOvertravel); - B_ARG = "B" + xyzFormat.format(DISTANCE); - - writeBlock(macroCall, "\"PROBEX\"", WCS_CODE[7], WCS_CODE[8], B_ARG); - writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V1", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); - - if (WCS_CODE[7] === "I1.") { - writeBlock(openString); - writeBlock("PRINT[\"PROBED X POINT: @996\"]"); - writeBlock("CLOSE[]"); - } - break; - case "probing-y": - forceXYZ(); - protectedProbeMove(cycle, x, y, z - cycle.depth); - - WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); - EXPECTED_Y = yOutput.format(y + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)); - EXPECTED_X = xOutput.format(x + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)); - EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); - DISTANCE = approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2 + cycle.probeOvertravel); - B_ARG = "B" + xyzFormat.format(DISTANCE); - - writeBlock(macroCall, "\"PROBEY\"", WCS_CODE[7], WCS_CODE[8], B_ARG); - writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V2", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); - - if (WCS_CODE[7] === "I1.") { - writeBlock(openString); - writeBlock("PRINT[\"PROBED Y POINT: @996\"]"); - writeBlock("CLOSE[]"); - } - break; - case "probing-z": - forceXYZ(); - protectedProbeMove(cycle, x, y, Math.min(z - cycle.depth + cycle.probeClearance, cycle.retract)); - - WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); - EXPECTED_X = xOutput.format(x); - EXPECTED_Y = yOutput.format(y); - EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); - B_ARG = "B" + xyzFormat.format(-cycle.depth - cycle.probeOvertravel); - - writeBlock(macroCall, "\"PROBEZ\"", WCS_CODE[7], WCS_CODE[8], B_ARG); - writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V3", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); - - if (WCS_CODE[7] === "I1.") { - writeBlock(openString); - writeBlock("PRINT[\"PROBED Z POINT: @996\"]"); - writeBlock("CLOSE[]"); - } - break; - case "probing-x-wall": - forceXYZ(); - protectedProbeMove(cycle, x, y, z); - WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); - WEB_WIDTH = "B" + xyzFormat.format(cycle.width1); - Z_DROP = "C" + xyzFormat.format(cycle.depth); - - writeBlock(macroCall, "\"PROBEXWEB\"", WCS_CODE[7], WCS_CODE[8], WEB_WIDTH, Z_DROP, "Q0", WCS_CODE[2]); - - if (WCS_CODE[7] === "I1.") { - writeBlock(openString); - writeBlock("PRINT[\"MEASURED X WEB WIDTH: @998\"]"); - writeBlock("CLOSE[]"); - } - break; - case "probing-y-wall": - forceXYZ(); - protectedProbeMove(cycle, x, y, z); - - WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); - WEB_WIDTH = "B" + xyzFormat.format(cycle.width1); - Z_DROP = "C" + xyzFormat.format(cycle.depth); - - writeBlock(macroCall, "\"PROBEYWEB\"", WCS_CODE[7], WCS_CODE[8], WEB_WIDTH, Z_DROP, "Q0", WCS_CODE[2]); - - if (WCS_CODE[7] === "I1.") { - writeBlock(openString); - writeBlock("PRINT[\"MEASURED Y WEB WIDTH: @999\"]"); - writeBlock("CLOSE[]"); - } - break; - case "probing-x-channel": - forceXYZ(); - protectedProbeMove(cycle, x, y, z - cycle.depth); - - WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); - SLOT_WIDTH = "B" + xyzFormat.format(cycle.width1); - - writeBlock(macroCall, "\"PROBEXSLOT\"", WCS_CODE[7], WCS_CODE[8], SLOT_WIDTH, "Q0", WCS_CODE[2]); - - if (WCS_CODE[7] === "I1.") { - writeBlock(openString); - writeBlock("PRINT[\"MEASURED X SLOT WIDTH: @998\"]"); - writeBlock("CLOSE[]"); - } - break; - case "probing-x-channel-with-island": - error(localize("probing-x-channel-with-island is unsupported")); - /*protectedProbeMove(cycle, x, y, z); - writeBlock( - macroCall, "P" + 9812, - "X" + xyzFormat.format(cycle.width1), - zOutput.format(z - cycle.depth), - "Q" + xyzFormat.format(cycle.probeOvertravel), - "R" + xyzFormat.format(-cycle.probeClearance), - getProbingArguments(cycle, true) - ); */ - break; - case "probing-y-channel": - forceXYZ(); - protectedProbeMove(cycle, x, y, z - cycle.depth); - - WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); - SLOT_WIDTH = "B" + xyzFormat.format(cycle.width1); - - writeBlock(macroCall, "\"PROBEYSLOT\"", WCS_CODE[7], WCS_CODE[8], SLOT_WIDTH, "Q0", WCS_CODE[2]); - - if (WCS_CODE[7] === "I1.") { - writeBlock(openString); - writeBlock("PRINT[\"MEASURED Y SLOT WIDTH: @999\"]"); - writeBlock("CLOSE[]"); - } - break; - case "probing-y-channel-with-island": - error(localize("probing-y-channel-with-island is unsupported")); - /*protectedProbeMove(cycle, x, y, z); - writeBlock( - macroCall, "P" + 9812, - "Y" + xyzFormat.format(cycle.width1), - zOutput.format(z - cycle.depth), - "Q" + xyzFormat.format(cycle.probeOvertravel), - "R" + xyzFormat.format(-cycle.probeClearance), - getProbingArguments(cycle, true) - ); */ - break; - case "probing-xy-circular-boss": - forceXYZ(); - protectedProbeMove(cycle, x, y, z); - - WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); - BOSS_DIAMETER = "B" + xyzFormat.format(cycle.width1); - Z_DROP = "C" + xyzFormat.format(cycle.depth); - EXPECTED_X = xOutput.format(x); - EXPECTED_Y = yOutput.format(y); - EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); - - writeBlock(macroCall, "\"PROBECIRCULARBOSS\"", WCS_CODE[7], WCS_CODE[8], BOSS_DIAMETER, Z_DROP, "Q0", WCS_CODE[2]); - writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V4", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); - if (getProperty("EnableZeroPointCompensation") == true && WCS_CODE[7] === null) { - writeBlock(macroCall, "\"COMPZEROPOINT\"", WCS_CODE[8], WCS_CODE[9], EXPECTED_X, EXPECTED_Y, EXPECTED_Z); - } - - if (WCS_CODE[7] === "I1.") { - writeBlock(openString); - writeBlock("PRINT[\"MEASURED CIRCULAR BOSS DIAMETER IN X: @998\"]"); - writeBlock("PRINT[\"MEASURED CIRCULAR BOSS DIAMETER IN Y: @999\"]"); - writeBlock("PRINT[\"MEASURED CIRCULAR BOSS AVG DIAMETER : @997\"]"); - writeBlock("CLOSE[]"); - } - break; - case "probing-xy-circular-partial-boss": - error(localize("probing-xy-circular-partial-boss is unsupported")); - /*protectedProbeMove(cycle, x, y, z); - writeBlock( - macroCall, "P" + 9823, - "A" + xyzFormat.format(cycle.partialCircleAngleA), - "B" + xyzFormat.format(cycle.partialCircleAngleB), - "C" + xyzFormat.format(cycle.partialCircleAngleC), - "D" + xyzFormat.format(cycle.width1), - "Z" + xyzFormat.format(z - cycle.depth), - "Q" + xyzFormat.format(cycle.probeOvertravel), - "R" + xyzFormat.format(cycle.probeClearance), - getProbingArguments(cycle, true) - ); */ - break; - case "probing-xy-circular-hole": - forceXYZ(); - protectedProbeMove(cycle, x, y, z - cycle.depth); - - WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); - BORE_DIAMETER = "B" + xyzFormat.format(cycle.width1); - EXPECTED_X = xOutput.format(x); - EXPECTED_Y = yOutput.format(y); - EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); - - writeBlock(macroCall, "\"PROBEBORE\"", WCS_CODE[7], WCS_CODE[8], BORE_DIAMETER, "Q0", WCS_CODE[2]); - writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V4", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); - if (getProperty("EnableZeroPointCompensation") == true && WCS_CODE[7] === null) { - writeBlock(macroCall, "\"COMPZEROPOINT\"", WCS_CODE[8], WCS_CODE[9], EXPECTED_X, EXPECTED_Y, EXPECTED_Z); - } - - if (WCS_CODE[7] === "I1.") { - writeBlock(openString); - writeBlock("PRINT[\"MEASURED BORE DIAMETER IN X: @998\"]"); - writeBlock("PRINT[\"MEASURED BORE DIAMETER IN Y: @999\"]"); - writeBlock("PRINT[\"MEASURED BORE AVG DIAMETER : @997\"]"); - writeBlock("CLOSE[]"); - } - break; - case "probing-xy-circular-partial-hole": - error(localize("probing-xy-circular-partial-hole is unsupported")); - /* protectedProbeMove(cycle, x, y, z - cycle.depth); - writeBlock( - macroCall, "P" + 9823, - "A" + xyzFormat.format(cycle.partialCircleAngleA), - "B" + xyzFormat.format(cycle.partialCircleAngleB), - "C" + xyzFormat.format(cycle.partialCircleAngleC), - "D" + xyzFormat.format(cycle.width1), - "Q" + xyzFormat.format(cycle.probeOvertravel), - getProbingArguments(cycle, true) - ); */ - break; - case "probing-xy-circular-hole-with-island": - error(localize("probing-xy-circular-hole-with-island is unsupported")); - /* protectedProbeMove(cycle, x, y, z); - writeBlock( - macroCall, "P" + 9814, - "Z" + xyzFormat.format(z - cycle.depth), - "D" + xyzFormat.format(cycle.width1), - "Q" + xyzFormat.format(cycle.probeOvertravel), - "R" + xyzFormat.format(-cycle.probeClearance), - getProbingArguments(cycle, true) - ); */ - break; - case "probing-xy-circular-partial-hole-with-island": - error(localize("probing-xy-circular-partial-hole-with-island is unsupported")); - /* protectedProbeMove(cycle, x, y, z); - writeBlock( - macroCall, "P" + 9823, - "Z" + xyzFormat.format(z - cycle.depth), - "A" + xyzFormat.format(cycle.partialCircleAngleA), - "B" + xyzFormat.format(cycle.partialCircleAngleB), - "C" + xyzFormat.format(cycle.partialCircleAngleC), - "D" + xyzFormat.format(cycle.width1), - "Q" + xyzFormat.format(cycle.probeOvertravel), - "R" + xyzFormat.format(-cycle.probeClearance), - getProbingArguments(cycle, true) - ); */ - break; - case "probing-xy-rectangular-hole": - forceXYZ(); - protectedProbeMove(cycle, x, y, z - cycle.depth); - - WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); - XWEB_WIDTH = "B" + xyzFormat.format(cycle.width1); - YWEB_WIDTH = "C" + xyzFormat.format(cycle.width2); - EXPECTED_X = xOutput.format(x); - EXPECTED_Y = yOutput.format(y); - EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); - - writeBlock(macroCall, "\"PROBEPOCKET\"", WCS_CODE[7], WCS_CODE[8], XWEB_WIDTH, YWEB_WIDTH, "Q0", WCS_CODE[2]); - writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V4", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); - if (getProperty("EnableZeroPointCompensation") == true && WCS_CODE[7] === null) { - writeBlock(macroCall, "\"COMPZEROPOINT\"", WCS_CODE[8], WCS_CODE[9], EXPECTED_X, EXPECTED_Y, EXPECTED_Z); - } - - if (WCS_CODE[7] === "I1.") { - writeBlock(openString); - writeBlock("PRINT[\"MEASURED POCKET LENGTH IN X: @998\"]"); - writeBlock("PRINT[\"MEASURED POCKET WIDTH IN Y: @999\"]"); - writeBlock("CLOSE[]"); - } - break; - case "probing-xy-rectangular-boss": - forceXYZ(); - protectedProbeMove(cycle, x, y, z); - - WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); - XWEB_WIDTH = "B" + xyzFormat.format(cycle.width1); - YWEB_WIDTH = "C" + xyzFormat.format(cycle.width2); - EXPECTED_X = xOutput.format(x); - EXPECTED_Y = yOutput.format(y); - EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); - Z_DROP = "D" + xyzFormat.format(cycle.depth); - - writeBlock(macroCall, "\"PROBERECTANGULARBOSS\"", WCS_CODE[7], WCS_CODE[8], XWEB_WIDTH, YWEB_WIDTH, Z_DROP, "Q0", WCS_CODE[2]); - writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V4", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); - if (getProperty("EnableZeroPointCompensation") == true && WCS_CODE[7] === null) { - writeBlock(macroCall, "\"COMPZEROPOINT\"", WCS_CODE[8], WCS_CODE[9], EXPECTED_X, EXPECTED_Y, EXPECTED_Z); - } - - if (WCS_CODE[7] === "I1.") { - writeBlock(openString); - writeBlock("PRINT[\"MEASURED RECTANGULAR BOSS LENGTH IN X: @998\"]"); - writeBlock("PRINT[\"MEASURED RECTANGULAR BOSS WIDTH IN Y: @999\"]"); - writeBlock("CLOSE[]"); - } - break; - case "probing-xy-rectangular-hole-with-island": - error(localize("probing-xy-rectangular-hole-with-island is unsupported")); - /* protectedProbeMove(cycle, x, y, z); - writeBlock( - macroCall, "P" + 9812, - "Z" + xyzFormat.format(z - cycle.depth), - "X" + xyzFormat.format(cycle.width1), - "Q" + xyzFormat.format(cycle.probeOvertravel), - "R" + xyzFormat.format(-cycle.probeClearance), - getProbingArguments(cycle, true) - ); - if (getProperty("useLiveConnection") && (typeof liveConnectionStoreResults == "function")) { - liveConnectionStoreResults(); - } - writeBlock( - macroCall, "P" + 9812, - "Z" + xyzFormat.format(z - cycle.depth), - "Y" + xyzFormat.format(cycle.width2), - "Q" + xyzFormat.format(cycle.probeOvertravel), - "R" + xyzFormat.format(-cycle.probeClearance), - getProbingArguments(cycle, true) - ); */ - break; - - case "probing-xy-inner-corner": - forceXYZ(); - protectedProbeMove(cycle, x, y, z - cycle.depth); - - WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); - CORNER_POSITION = "B" + xyzFormat.format(cycle.width1); - PROBING_DISTANCE = "C" + xyzFormat.format(cycle.width2); - - writeBlock(macroCall, "\"PROBEINSIDECORNER\"", WCS_CODE[8], CORNER_POSITION, PROBING_DISTANCE, "Q0"); - break; - case "probing-xy-outer-corner": - forceXYZ(); - protectedProbeMove(cycle, x, y, z - cycle.depth); - xdir = approach(cycle.approach1); - ydir = approach(cycle.approach2); - var CORNER_NUM = 0; - if (xdir == 1 && ydir == 1) {CORNER_NUM = 3;} else if (xdir == 1 && ydir == -1) {CORNER_NUM = 1;} else if (xdir == -1 && ydir == 1) {CORNER_NUM = 4;} else if (xdir == -1 && ydir == -1) {CORNER_NUM = 2;} - - WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); - CORNER_POSITION = "B" + CORNER_NUM; - TRAVEL_DISTANCE = "C" + xyzFormat.format(2 * cycle.probeClearance + tool.diameter / 2); - PROBING_DISTANCE = "D" + xyzFormat.format(cycle.probeClearance + cycle.probeOvertravel); - - writeBlock(macroCall, "\"PROBEOUTSIDECORNER\"", - WCS_CODE[8], - CORNER_POSITION, - TRAVEL_DISTANCE, - PROBING_DISTANCE, "Q0"); - break; - case "probing-x-plane-angle": - error(localize("probing-x-plane-angle - Unsupported Probing Cycle")); - /*protectedProbeMove(cycle, x, y, z - cycle.depth); - writeBlock( - macroCall, "P" + 9843, - "X" + xyzFormat.format(x + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)), - "D" + xyzFormat.format(cycle.probeSpacing), - "Q" + xyzFormat.format(cycle.probeOvertravel), - "A" + xyzFormat.format(cycle.nominalAngle != undefined ? cycle.nominalAngle : 90), - getProbingArguments(cycle, false) - ); - if (currentSection.strategy == "probe") { - setProbeAngleMethod(); - probeVariables.compensationXY = "X" + xyzFormat.format(0) + " Y" + xyzFormat.format(0); - } */ - break; - case "probing-y-plane-angle": - error(localize("probing-y-plane-angle - Unsupported Probing Cycle")); - /* protectedProbeMove(cycle, x, y, z - cycle.depth); - writeBlock( - macroCall, "P" + 9843, - "Y" + xyzFormat.format(y + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)), - "D" + xyzFormat.format(cycle.probeSpacing), - "Q" + xyzFormat.format(cycle.probeOvertravel), - "A" + xyzFormat.format(cycle.nominalAngle != undefined ? cycle.nominalAngle : 0), - getProbingArguments(cycle, false) - ); - if (currentSection.strategy == "probe") { - setProbeAngleMethod(); - probeVariables.compensationXY = "X" + xyzFormat.format(0) + " Y" + xyzFormat.format(0); - } */ - break; - case "probing-xy-pcd-hole": - error(localize("probing-xy-pcd-hole - Unsupported Probing Cycle")); - /* protectedProbeMove(cycle, x, y, z); - writeBlock( - macroCall, "P" + 9819, - "A" + xyzFormat.format(cycle.pcdStartingAngle), - "B" + xyzFormat.format(cycle.numberOfSubfeatures), - "C" + xyzFormat.format(cycle.widthPCD), - "D" + xyzFormat.format(cycle.widthFeature), - "K" + xyzFormat.format(z - cycle.depth), - "Q" + xyzFormat.format(cycle.probeOvertravel), - getProbingArguments(cycle, false) - ); - if (cycle.updateToolWear) { - error(localize("Action -Update Tool Wear- is not supported with this cycle.")); - return; - } */ - break; - case "probing-xy-pcd-boss": - error(localize("probing-xy-pcd-boss - Unsupported Probing Cycle")); - /* protectedProbeMove(cycle, x, y, z); - writeBlock( - macroCall, "P" + 9819, - "A" + xyzFormat.format(cycle.pcdStartingAngle), - "B" + xyzFormat.format(cycle.numberOfSubfeatures), - "C" + xyzFormat.format(cycle.widthPCD), - "D" + xyzFormat.format(cycle.widthFeature), - "Z" + xyzFormat.format(z - cycle.depth), - "Q" + xyzFormat.format(cycle.probeOvertravel), - "R" + xyzFormat.format(cycle.probeClearance), - getProbingArguments(cycle, false) - ); - if (cycle.updateToolWear) { - error(localize("Action -Update Tool Wear- is not supported with this cycle.")); - return; - } */ - break; - } -} - -function printProbeResults() { - return currentSection.getParameter("printResults", 0) == 1; -} - -/** Convert approach to sign. */ -function approach(value) { - validate((value == "positive") || (value == "negative"), "Invalid approach."); - return (value == "positive") ? 1 : -1; -} -// <<<<< INCLUDED FROM include_files/probeCycles_renishaw.cpi -// >>>>> INCLUDED FROM include_files/getProbingArguments_renishaw.cpi -/* function getProbingArguments(cycle, updateWCS) { // new Autodesk function - var outputWCSCode = updateWCS && currentSection.strategy == "probe"; - if (outputWCSCode) { - var maximumWcsNumber = 0; - for (var i in wcsDefinitions.wcs) { - maximumWcsNumber = Math.max(maximumWcsNumber, wcsDefinitions.wcs[i].range[1]); - } - maximumWcsNumber = probeExtWCSFormat.getResultingValue(maximumWcsNumber); - var resultingWcsNumber = probeExtWCSFormat.getResultingValue(currentSection.probeWorkOffset - 6); - validate(resultingWcsNumber <= maximumWcsNumber, subst("Probe work offset %1 is out of range, maximum value is %2.", resultingWcsNumber, maximumWcsNumber)); - var probeOutputWorkOffset = currentSection.probeWorkOffset > 6 ? probeExtWCSFormat.format(currentSection.probeWorkOffset - 6) : probeWCSFormat.format(currentSection.probeWorkOffset); - - var nextWorkOffset = hasNextSection() ? getNextSection().workOffset == 0 ? 1 : getNextSection().workOffset : -1; - if (currentSection.probeWorkOffset == nextWorkOffset) { - currentWorkOffset = undefined; - } - } - return [ - (cycle.angleAskewAction == "stop-message" ? "B" + xyzFormat.format(cycle.toleranceAngle ? cycle.toleranceAngle : 0) : undefined), - ((cycle.updateToolWear && cycle.toolWearErrorCorrection < 100) ? "F" + xyzFormat.format(cycle.toolWearErrorCorrection ? cycle.toolWearErrorCorrection / 100 : 100) : undefined), - (cycle.wrongSizeAction == "stop-message" ? "H" + xyzFormat.format(cycle.toleranceSize ? cycle.toleranceSize : 0) : undefined), - (cycle.outOfPositionAction == "stop-message" ? "M" + xyzFormat.format(cycle.tolerancePosition ? cycle.tolerancePosition : 0) : undefined), - ((cycle.updateToolWear && cycleType == "probing-z") ? "T" + xyzFormat.format(cycle.toolLengthOffset) : undefined), - ((cycle.updateToolWear && cycleType !== "probing-z") ? "T" + xyzFormat.format(cycle.toolDiameterOffset) : undefined), - (cycle.updateToolWear ? "V" + xyzFormat.format(cycle.toolWearUpdateThreshold ? cycle.toolWearUpdateThreshold : 0) : undefined), - (cycle.printResults ? "W" + xyzFormat.format(1 + cycle.incrementComponent) : undefined), // 1 for advance feature, 2 for reset feature count and advance component number. first reported result in a program should use W2. - conditional(outputWCSCode, probeOutputWorkOffset) - ]; -} */ -function getProbingArguments(cycle, probeWorkOffsetCode) { // Old Toolpath Syil function - var probeWCS = hasParameter("operation-strategy") && (getParameter("operation-strategy") == "probe"); - - var PROBE_ARGS = ""; - if (probeOutputWorkOffset < 7) { - var WCS_NUM = 53 + probeOutputWorkOffset; - PROBE_ARGS = "A" + WCS_NUM; - } else { - var WCS_NUM = probeOutputWorkOffset - 6; - PROBE_ARGS = "A54." + WCS_NUM; - } - - var PROBE_OVERRIDE_ARGS = ""; - if (currentWorkOffset < 7) { - var WCS_NUM = 53 + currentWorkOffset; - PROBE_OVERRIDE_ARGS = "B" + WCS_NUM; - } else { - var WCS_NUM = currentWorkOffset - 6; - PROBE_OVERRIDE_ARGS = "B54." + WCS_NUM; - } - - return [ - (cycle.angleAskewAction == "stop-message" ? "B" + xyzFormat.format(cycle.toleranceAngle ? cycle.toleranceAngle : 0) : undefined), - ((cycle.updateToolWear && cycle.toolWearErrorCorrection < 100) ? "F" + xyzFormat.format(cycle.toolWearErrorCorrection ? cycle.toolWearErrorCorrection / 100 : 100) : undefined), - (cycle.wrongSizeAction == "stop-message" ? "R" + xyzFormat.format(cycle.toleranceSize ? cycle.toleranceSize : 0) + " S1" : undefined), - (cycle.outOfPositionAction == "stop-message" ? "T" + xyzFormat.format(cycle.tolerancePosition ? cycle.tolerancePosition : 0) + " U1" : undefined), - ((cycle.updateToolWear && cycleType == "probing-z") ? "T" + xyzFormat.format(cycle.toolLengthOffset) : undefined), - ((cycle.updateToolWear && cycleType !== "probing-z") ? "T" + xyzFormat.format(cycle.toolDiameterOffset) : undefined), - (cycle.updateToolWear ? "V" + xyzFormat.format(cycle.toolWearUpdateThreshold ? cycle.toolWearUpdateThreshold : 0) : undefined), - (cycle.printResults ? "I" + xyzFormat.format(1 + cycle.incrementComponent) : undefined), // 1 for advance feature, 2 for reset feature count and advance component number. first reported result in a program should use W2. - conditional(probeWorkOffsetCode && probeWCS, PROBE_ARGS), - conditional(probeWorkOffsetCode && probeWCS, PROBE_OVERRIDE_ARGS) - ]; -} -// <<<<< INCLUDED FROM include_files/getProbingArguments_renishaw.cpi -// >>>>> INCLUDED FROM include_files/protectedProbeMove_renishaw.cpi -function protectedProbeMove(_cycle, x, y, z) { - var _x = xOutput.format(x); - var _y = yOutput.format(y); - var _z = zOutput.format(z - cycle.depth); - var macroCall = settings.probing.macroCall; - if (_z && z >= getCurrentPosition().z) { - writeBlock(macroCall, "\"PROTECTEDMOVE\"", _z, getFeed(cycle.feedrate)); // protected positioning move - } - if (_x || _y) { - writeBlock(macroCall, "\"PROTECTEDMOVE\"", _x, _y, getFeed(highFeedrate)); // protected positioning move - } - if (_z && z < getCurrentPosition().z) { - writeBlock(macroCall, "\"PROTECTEDMOVE\"", _z, getFeed(cycle.feedrate)); // protected positioning move - } -} -// <<<<< INCLUDED FROM include_files/protectedProbeMove_renishaw.cpi -// >>>>> INCLUDED FROM include_files/setProbeAngle_fanuc.cpi -function setProbeAngle() { - if (probeVariables.outputRotationCodes) { - validate(settings.probing.probeAngleVariables, localize("Setting 'probing.probeAngleVariables' is required for angular probing.")); - var probeAngleVariables = settings.probing.probeAngleVariables; - var px = probeAngleVariables.x; - var py = probeAngleVariables.y; - var pz = probeAngleVariables.z; - var pi = probeAngleVariables.i; - var pj = probeAngleVariables.j; - var pk = probeAngleVariables.k; - var pr = probeAngleVariables.r; - var baseParamG54x4 = probeAngleVariables.baseParamG54x4; - var baseParamAxisRot = probeAngleVariables.baseParamAxisRot; - var probeOutputWorkOffset = currentSection.probeWorkOffset; - - validate(probeOutputWorkOffset <= 6, "Angular Probing only supports work offsets 1-6."); - if (probeVariables.probeAngleMethod == "G68" && (Vector.diff(currentSection.getGlobalInitialToolAxis(), new Vector(0, 0, 1)).length > 1e-4)) { - error(localize("You cannot use multi axis toolpaths while G68 Rotation is in effect.")); - } - var validateWorkOffset = false; - switch (probeVariables.probeAngleMethod) { - case "G54.4": - var param = baseParamG54x4 + (probeOutputWorkOffset * 10); - writeBlock("#" + param + "=" + px); - writeBlock("#" + (param + 1) + "=" + py); - writeBlock("#" + (param + 5) + "=" + pr); - writeBlock(gFormat.format(54.4), "P" + probeOutputWorkOffset); - break; - case "G68": - gRotationModal.reset(); - gAbsIncModal.reset(); - var xy = probeVariables.compensationXY || formatWords(formatCompensationParameter("X", px), formatCompensationParameter("Y", py)); - writeBlock( - gRotationModal.format(68), gAbsIncModal.format(90), - xy, - formatCompensationParameter("Z", pz), - formatCompensationParameter("I", pi), - formatCompensationParameter("J", pj), - formatCompensationParameter("K", pk), - formatCompensationParameter("R", pr) - ); - validateWorkOffset = true; - break; - case "AXIS_ROT": - var param = baseParamAxisRot + probeOutputWorkOffset * 20 + probeVariables.rotaryTableAxis + 4; - writeBlock("#" + param + " = " + "[#" + param + " + " + pr + "]"); - forceWorkPlane(); // force workplane to rotate ABC in order to apply rotation offsets - currentWorkOffset = undefined; // force WCS output to make use of updated parameters - validateWorkOffset = true; - break; - default: - error(localize("Angular Probing is not supported for this machine configuration.")); - return; - } - if (validateWorkOffset) { - for (var i = currentSection.getId(); i < getNumberOfSections(); ++i) { - if (getSection(i).workOffset != currentSection.workOffset) { - error(localize("WCS offset cannot change while using angle rotation compensation.")); - return; - } - } - } - probeVariables.outputRotationCodes = false; - } -} - -function formatCompensationParameter(label, value) { - return typeof value == "string" ? label + "[" + value + "]" : typeof value == "number" ? label + xyzFormat.format(value) : ""; -} -// <<<<< INCLUDED FROM include_files/setProbeAngle_fanuc.cpi -// >>>>> INCLUDED FROM include_files/setProbeAngleMethod.cpi -function setProbeAngleMethod() { - var axisRotIsSupported = false; - var axes = [machineConfiguration.getAxisU(), machineConfiguration.getAxisV(), machineConfiguration.getAxisW()]; - for (var i = 0; i < axes.length; ++i) { - if (axes[i].isEnabled() && isSameDirection((axes[i].getAxis()).getAbsolute(), new Vector(0, 0, 1)) && axes[i].isTable()) { - axisRotIsSupported = true; - if (settings.probing.probeAngleVariables.method == 0) { // Fanuc - validate(i < 2, localize("Rotary table axis is invalid.")); - probeVariables.rotaryTableAxis = i; - } else { // Haas - probeVariables.rotaryTableAxis = axes[i].getCoordinate(); - } - break; - } - } - if (settings.probing.probeAngleMethod == undefined) { - probeVariables.probeAngleMethod = axisRotIsSupported ? "AXIS_ROT" : getProperty("useG54x4") ? "G54.4" : "G68"; // automatic selection - } else { - probeVariables.probeAngleMethod = settings.probing.probeAngleMethod; // use probeAngleMethod from settings - if (probeVariables.probeAngleMethod == "AXIS_ROT" && !axisRotIsSupported) { - error(localize("Setting probeAngleMethod 'AXIS_ROT' is not supported on this machine.")); - } - } - probeVariables.outputRotationCodes = true; -} -// <<<<< INCLUDED FROM include_files/setProbeAngleMethod.cpi - -var now = new Date(); // BJE +/** + Copyright (C) 2012-2024 by Autodesk, Inc. + All rights reserved. + + Syntec post processor configuration. + + $Revision: 44145 4f7aaa6c97df2d49db23603652fb3cf23f709aa1 $ + $Date: 2024-09-19 10:09:13 $ + + FORKID {78441FCF-1C1F-4D81-BFA8-AAF6F30E1F3B} +*/ + +description = "SYIL LNC 6800"; +vendor = "Scott Moyse"; +vendorUrl = "Toolpath.com"; +legal = "Copyright (C) 2012-2024 by Autodesk, Inc."; +certificationLevel = 2; +minimumRevision = 45917; + +longDescription = "Syil LNC 6800 Post Processor with A-axis and machine simulation. Written by Scott Moyse"; + +extension = "nc"; +programNameIsInteger = true; +setCodePage("ascii"); + +capabilities = CAPABILITY_MILLING | CAPABILITY_MACHINE_SIMULATION; +tolerance = spatial(0.002, MM); + +minimumChordLength = spatial(0.25, MM); +minimumCircularRadius = spatial(0.01, MM); +maximumCircularRadius = spatial(1000, MM); +minimumCircularSweep = toRad(0.01); +maximumCircularSweep = toRad(180); +allowHelicalMoves = true; +allowedCircularPlanes = undefined; // allow any circular motion +highFeedrate = (unit == MM) ? 5000 : 200; + +// user-defined properties +properties = { + + showSequenceNumbers: { + title : "Use sequence numbers", + description: "'Yes' outputs sequence numbers on each block, 'Only on tool change' outputs sequence numbers on tool change blocks only, and 'No' disables the output of sequence numbers.", + group : "formats", + type : "enum", + values : [ + {title:"Yes", id:"true"}, + {title:"No", id:"false"}, + {title:"Only on tool change", id:"toolChange"} + ], + value: "true", + scope: "post" + }, + sequenceNumberStart: { + title : "Start sequence number", + description: "The number at which to start the sequence numbers.", + group : "formats", + type : "integer", + value : 10, + scope : "post" + }, + sequenceNumberIncrement: { + title : "Sequence number increment", + description: "The amount by which the sequence number is incremented by in each block.", + group : "formats", + type : "integer", + value : 5, + scope : "post" + }, + optionalStop: { + title : "Optional stop", + description: "Outputs optional stop code during when necessary in the code.", + group : "preferences", + type : "boolean", + value : true, + scope : "post" + }, + separateWordsWithSpace: { + title : "Separate words with space", + description: "Adds spaces between words if 'yes' is selected.", + group : "formats", + type : "boolean", + value : true, + scope : "post" + }, + allow3DArcs: { + title : "Allow 3D arcs", + description: "Specifies whether 3D circular arcs are allowed.", + group : "preferences", + type : "boolean", + value : false, + scope : "post" + }, + useRadius: { + title : "Radius arcs", + description: "If yes is selected, arcs are outputted using radius values rather than IJK.", + group : "preferences", + type : "boolean", + value : false, + scope : "post" + }, + showNotes: { + title : "Show notes", + description: "Writes operation notes as comments in the outputted code.", + group : "formats", + type : "boolean", + value : false, + scope : "post" + }, + useSmoothing: { + title : "SGI / High Precision Mode", + description: "High-Speed High-Precision Parameter.", + group : "preferences", + type : "enum", + values : [ + {title:"Off", id:"-1"}, + {title:"Automatic", id:"9999"}, + {title:"Fine Precision", id:"1"}, + {title:"Fine Velocity", id:"2"}, + {title:"Rough", id:"3"} + ], + value: "-1", + scope: "post" + }, + precisionLevel: { + title : "Machining Condition", + description: "Users can choose the High-Speed High-Precision Parameter based on the controller HSHP configuration", + group : "preferences", + type : "enum", + values : [ + {title:"P1 More Corner", id:"P1"}, + {title:"P2 More Arcs", id:"P2"}, + {title:"P3 3C Product", id:"P3"}, + ], + value: "P2", + scope: "post" + }, + usePitchForTapping: { + title : "Use pitch for tapping", + 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!", + group : "preferences", + type : "boolean", + value : false, + scope : "post" + }, + useG95: { + title : "Use G95", + description: "Use IPR/MPR instead of IPM/MPM.", + group : "preferences", + type : "boolean", + value : false, + scope : "post" + }, + safeStartAllOperations: { + title : "Safe start all operations", + description: "Write optional blocks at the beginning of all operations that include all commands to start program.", + group : "preferences", + type : "boolean", + value : false, + scope : "post" + }, + useClampCodes: { + title : "Use clamp codes", + description: "Specifies whether clamp codes for rotary axes should be output. For simultaneous toolpaths rotary axes will always get unclamped.", + group : "multiAxis", + type : "boolean", + value : true, + scope : "post" + }, + safePositionMethod: { + title : "Safe Retracts", + description: "Select your desired retract option. 'Clearance Height' retracts to the operation clearance height.", + group : "homePositions", + type : "enum", + values : [ + {title:"G28", id:"G28"}, + {title:"G30", id:"G30"}, + {title:"G53", id:"G53"} + ], + value: "G28", + scope: "post" + }, + breakControlError: { + title : "Max. Break Control Error", + description: "Maximum Allowable Error for Break Control.", + group : "toolChange", + type : "number", + value : 0.05, + scope : "post" + }, + ForceTCPosition: { + title : "Change Position Before Toolchange", + description: "Change the machine position before executing a toolchange.", + group : "toolChange", + type : "boolean", + value : false, + scope : "post" + }, + TCposX: { + title : "Toolchange Position X Axis - Machine Coordinate", + description: "Machine Coordinate for toolchange on X Axis.", + group : "toolChange", + type : "number", + value : 0, + scope : "post" + }, + TCposY: { + title : "Toolchange Position Y Axis - Machine Coordinate", + description: "Machine Coordinate for toolchange on Y Axis.", + group : "toolChange", + type : "number", + value : 0, + scope : "post" + }, + EnableZeroPointCompensation: { + title : "Enable Zero Point Compensation", + description: "Allows probing cycles to compensate for deltas bewteen a probed part and it's expected postition. The WCS after probing becomes the override origin translated by the computed deltas.", + group : "preferences", + type : "boolean", + value : false, + scope : "post" + }, + _0CustomOnOpenGcode: { + title : "on open G-code", + description: "Inserts custom G-code at the beginning of the program", + group : "CustomGcode", + type : "string", + value : "", + scope : "post" + }, + _1CustomOnCloseGcode: { + title : "on close G-code", + description: "Inserts custom G-code at the end of the program", + group : "CustomGcode", + type : "string", + value : "", + scope : "post" + } +}; + +groupDefinitions = { + toolChange : {title:"Tool change", description: "Setting related to toolchanges", collapsed: true, order: 31}, + CustomGcode : {title:"Custom G-code", description: "G-code to add to the start of the program", collapsed: true, order: 33}, +}; + +// wcs definiton +wcsDefinitions = { + useZeroOffset: false, + wcs : [ + {name:"Standard", format:"G", range:[54, 59]}, + {name:"Extended", format:"G59.", range:[1, 106]} + ] +}; + +var gFormat = createFormat({prefix:"G", minDigitsLeft:2, decimals:1}); +var mFormat = createFormat({prefix:"M", minDigitsLeft:2, decimals:1}); +var hFormat = createFormat({prefix:"H", minDigitsLeft:2, decimals:1}); +var diameterOffsetFormat = createFormat({prefix:"D", minDigitsLeft:2, decimals:1}); + +var xyzFormat = createFormat({decimals:(unit == MM ? 3 : 4), type:FORMAT_REAL}); +var ijkFormat = createFormat({decimals:6, type:FORMAT_REAL}); // unitless +var rFormat = xyzFormat; // radius +var abcFormat = createFormat({decimals:3, type:FORMAT_REAL, scale:DEG}); +var feedFormat = createFormat({decimals:(unit == MM ? 0 : 1), type:FORMAT_REAL}); +var inverseTimeFormat = createFormat({decimals:3, type:FORMAT_REAL}); +var pitchFormat = createFormat({decimals:(unit == MM ? 3 : 4), type:FORMAT_REAL}); +var toolFormat = createFormat({decimals:0}); +var rpmFormat = createFormat({decimals:0}); +var secFormat = createFormat({decimals:3, type:FORMAT_REAL}); // seconds - range 0.001-99999.999 +var milliFormat = createFormat({decimals:0}); // milliseconds // range 1-9999 +var taperFormat = createFormat({decimals:1, scale:DEG}); +var oFormat = createFormat({minDigitsLeft:4, decimals:0}); +var peckFormat = createFormat({decimals:(unit == MM ? 3 : 4), type:FORMAT_REAL}); +// var peckFormat = createFormat({decimals:0, type:FORMAT_LZS, minDigitsLeft:4, scale:(unit == MM ? 1000 : 10000)}); + +var xOutput = createOutputVariable({onchange:function() {state.retractedX = false;}, prefix:"X"}, xyzFormat); +var yOutput = createOutputVariable({onchange:function() {state.retractedY = false;}, prefix:"Y"}, xyzFormat); +var zOutput = createOutputVariable({onchange:function() {state.retractedZ = false;}, prefix:"Z"}, xyzFormat); +var toolVectorOutputI = createOutputVariable({prefix:"I", control:CONTROL_FORCE}, ijkFormat); +var toolVectorOutputJ = createOutputVariable({prefix:"J", control:CONTROL_FORCE}, ijkFormat); +var toolVectorOutputK = createOutputVariable({prefix:"K", control:CONTROL_FORCE}, ijkFormat); +var aOutput = createOutputVariable({prefix:"A"}, abcFormat); +var bOutput = createOutputVariable({prefix:"B"}, abcFormat); +var cOutput = createOutputVariable({prefix:"C"}, abcFormat); +var feedOutput = createOutputVariable({prefix:"F"}, feedFormat); +var inverseTimeOutput = createOutputVariable({prefix:"F", control:CONTROL_FORCE}, inverseTimeFormat); +var pitchOutput = createOutputVariable({prefix:"F", control:CONTROL_FORCE}, pitchFormat); +var sOutput = createOutputVariable({prefix:"S", control:CONTROL_FORCE}, rpmFormat); +var peckOutput = createOutputVariable({prefix:"Q", control:CONTROL_FORCE}, peckFormat); + +// circular output +var iOutput = createOutputVariable({prefix:"I", control:CONTROL_NONZERO}, xyzFormat); +var jOutput = createOutputVariable({prefix:"J", control:CONTROL_NONZERO}, xyzFormat); +var kOutput = createOutputVariable({prefix:"K", control:CONTROL_NONZERO}, xyzFormat); + +var gMotionModal = createOutputVariable({}, gFormat); // modal group 1 // G0-G3, ... +var gPlaneModal = createOutputVariable({onchange:function () {gMotionModal.reset();}}, gFormat); // modal group 2 // G17-19 +var gAbsIncModal = createOutputVariable({}, gFormat); // modal group 3 // G90-91 +var gFeedModeModal = createOutputVariable({}, gFormat); // modal group 5 // G94-95 +var gUnitModal = createOutputVariable({}, gFormat); // modal group 6 // G70-71 +var gCycleModal = createOutputVariable({}, gFormat); // modal group 9 // G81, ... +var gRetractModal = createOutputVariable({}, gFormat); // modal group 10 // G98-99 +var fourthAxisClamp = createOutputVariable({}, mFormat); +var fifthAxisClamp = createOutputVariable({}, mFormat); + +var settings = { + coolant: { + // samples: + // {id: COOLANT_THROUGH_TOOL, on: 88, off: 89} + // {id: COOLANT_THROUGH_TOOL, on: [8, 88], off: [9, 89]} + // {id: COOLANT_THROUGH_TOOL, on: "M88 P3 (myComment)", off: "M89"} + coolants: [ + {id:COOLANT_FLOOD, on:8}, + {id:COOLANT_MIST}, + {id:COOLANT_THROUGH_TOOL, on:88, off:89}, + {id:COOLANT_AIR, on:7}, + {id:COOLANT_AIR_THROUGH_TOOL}, + {id:COOLANT_SUCTION}, + {id:COOLANT_FLOOD_MIST}, + {id:COOLANT_FLOOD_THROUGH_TOOL, on:[8, 88], off:[9, 89]}, + {id:COOLANT_OFF, off:9} + ], + singleLineCoolant: false, // specifies to output multiple coolant codes in one line rather than in separate lines + }, + smoothing: { + roughing : 3, // roughing level for smoothing in automatic mode + semi : 2, // semi-roughing level for smoothing in automatic mode + semifinishing : 2, // semi-finishing level for smoothing in automatic mode + finishing : 1, // finishing level for smoothing in automatic mode + thresholdRoughing : toPreciseUnit(0.5, MM), // operations with stock/tolerance above that threshold will use roughing level in automatic mode + thresholdFinishing : toPreciseUnit(0.05, MM), // operations with stock/tolerance below that threshold will use finishing level in automatic mode + thresholdSemiFinishing: toPreciseUnit(0.1, MM), // operations with stock/tolerance above finishing and below threshold roughing that threshold will use semi finishing level in automatic mode + + differenceCriteria: "level", // options: "level", "tolerance", "both". Specifies criteria when output smoothing codes + autoLevelCriteria : "stock", // use "stock" or "tolerance" to determine levels in automatic mode + cancelCompensation: false // tool length compensation must be canceled prior to changing the smoothing level + }, + retract: { + cancelRotationOnRetracting: false, // specifies that rotations (G68) need to be canceled prior to retracting + methodXY : "G30", // special condition, overwrite retract behavior per axis + methodZ : undefined, // special condition, overwrite retract behavior per axis + useZeroValues : ["G28"], // enter property value id(s) for using "0" value instead of machineConfiguration axes home position values (ie G30 Z0) + homeXY : {onIndexing:false, onToolChange:{axes:[X, Y]}, onProgramEnd:{axes:[X, Y]}} // Specifies when the machine should be homed in X/Y. Sample: onIndexing:{axes:[X, Y], singleLine:false} + }, + parametricFeeds: { + firstFeedParameter : 500, // specifies the initial parameter number to be used for parametric feedrate output + feedAssignmentVariable: "#", // specifies the syntax to define a parameter + feedOutputVariable : "F#" // specifies the syntax to output the feedrate as parameter + }, + machineAngles: { // refer to https://cam.autodesk.com/posts/reference/classMachineConfiguration.html#a14bcc7550639c482492b4ad05b1580c8 + controllingAxis: ABC, + type : PREFER_PREFERENCE, + options : ENABLE_ALL + }, + workPlaneMethod: { + useTiltedWorkplane : false, // specifies that tilted workplanes should be used (ie. G68.2, G254, PLANE SPATIAL, CYCLE800), can be overwritten by property + eulerConvention : EULER_ZXZ_R, // specifies the euler convention (ie EULER_XYZ_R), set to undefined to use machine angles for TWP commands ('undefined' requires machine configuration) + eulerCalculationMethod: "standard", // ('standard' / 'machine') 'machine' adjusts euler angles to match the machines ABC orientation, machine configuration required + cancelTiltFirst : true, // cancel tilted workplane prior to WCS (G54-G59) blocks + useABCPrepositioning : true, // position ABC axes prior to tilted workplane blocks + forceMultiAxisIndexing: false, // force multi-axis indexing for 3D programs + optimizeType : undefined // can be set to OPTIMIZE_NONE, OPTIMIZE_BOTH, OPTIMIZE_TABLES, OPTIMIZE_HEADS, OPTIMIZE_AXIS. 'undefined' uses legacy rotations + }, + subprograms: { + initialSubprogramNumber: 9001, // specifies the initial number to be used for subprograms. 'undefined' uses the main program number + minimumCyclePoints : 5, // minimum number of points in cycle operation to consider for subprogram + format : oFormat, // the format to use for the subprogam number format + // objects below also accept strings with "%currentSubprogram" as placeholder. Sample: {files:["%"], embedded:"N" + "%currentSubprogram"} + files : {extension:extension, prefix:undefined}, // specifies the subprogram file extension and the prefix to use for the generated file + startBlock : {files:["%" + EOL + "O"], embedded:["N"]}, // specifies the start syntax of a subprogram followed by the subprogram number + endBlock : {files:[mFormat.format(99) + EOL + "%"], embedded:[mFormat.format(99)]}, // specifies the command to for the end of a subprogram + callBlock : {files:[mFormat.format(98) + " H"], embedded:[mFormat.format(98) + " H"]} // specifies the command for calling a subprogram followed by the subprogram number + }, + comments: { + permittedCommentChars: " abcdefghijklmnopqrstuvwxyz0123456789.,=_-:", // letters are not case sensitive, use option 'outputFormat' below. Set to 'undefined' to allow any character + prefix : "(", // specifies the prefix for the comment + suffix : ")", // specifies the suffix for the comment + outputFormat : "upperCase", // can be set to "upperCase", "lowerCase" and "ignoreCase". Set to "ignoreCase" to write comments without upper/lower case formatting + maximumLineLength : 80 // the maximum number of characters allowed in a line, set to 0 to disable comment output + }, + probing: { + macroCall : gFormat.format(65), // specifies the command to call a macro + probeAngleMethod : undefined, // supported options are: OFF, AXIS_ROT, G68, G54.4. 'undefined' uses automatic selection + probeAngleVariables : {x:"#135", y:"#136", z:0, i:0, j:0, k:1, r:"#144", baseParamG54x4:26000, baseParamAxisRot:5200, method:0}, // specifies variables for the angle compensation macros, method 0 = Fanuc, 1 = Haas + allowIndexingWCSProbing: false // specifies that probe WCS with tool orientation is supported + }, + maximumSequenceNumber : undefined, // the maximum sequence number (Nxxx), use 'undefined' for unlimited + supportsToolVectorOutput : true, // specifies if the control does support tool axis vector output for multi axis toolpath + allowCancelTCPBeforeRetracting: true, // allows TCP/tool length compensation to be canceled prior retracting. Warning, ensure machine parameters 5006.6(Fanuc)/F114 bit 1(Mazak) are set to prevent axis motion when cancelling compensation. + maximumToolLengthOffset : 199, + maximumToolDiameterOffset : 199 +}; + +function onOpen() { + // define and enable machine configuration + receivedMachineConfiguration = machineConfiguration.isReceived(); + if (typeof defineMachine == "function") { + defineMachine(); // hardcoded machine configuration + } + activateMachine(); + + // postprocessor/machine specific requirements + if (getProperty("useRadius")) { + maximumCircularSweep = toRad(90); // avoid potential center calculation errors for CNC + } + if (getProperty("safePositionMethod") == "G53" && (!machineConfiguration.hasHomePositionX() || !machineConfiguration.hasHomePositionY())) { + settings.retract.methodXY = "G28"; + } + + // initialize formats + gRotationModal.format(69); // Default to G69 Rotation Off + + if (!getProperty("separateWordsWithSpace")) { + setWordSeparator(""); + } + + if (getProperty("useG95")) { + if (getProperty("useParametricFeed")) { + error(localize("Parametric feed is not supported when using G95.")); + return; + } + feedFormat = createFormat({decimals:(unit == MM ? 4 : 5), type:FORMAT_REAL}); + feedOutput.setFormat(feedFormat); + } + + writeln("%"); + if (Number.isInteger(programName)) { + writeln("O" + oFormat.format(getProgramNumber()) + conditional(programComment, " " + formatComment(programComment))); + } else { + writeComment(programName); + } + writeProgramHeader(); + + // absolute coordinates and feed per min + writeBlock(gAbsIncModal.format(90), gFeedModeModal.format(getProperty("useG95") ? 95 : 94), gPlaneModal.format(17), toolLengthCompOutput.format(49), gFormat.format(40), gFormat.format(80)); + writeBlock(gUnitModal.format(unit == MM ? 21 : 20)); + validateCommonParameters(); + + // Save the G59 Z axis into a variable #199 for use with G10 calls + writeComment("G59 stores the zero point. #199 can be used with G10 commands to pull G59 into a local WCS"); + writeBlock("#199 = R_G53G59_COOR[0,59,3]"); + writeBlock("@980 = TIME[3]"); //month + writeBlock("@981 = TIME[4]"); //day + writeBlock("@982 = TIME[2]"); //year + writeBlock("@983 = TIME[5]"); //hour + writeBlock("@984 = TIME[6]"); //minute + writeBlock("@985 = TIME[7]"); //second + writeBlock(getProperty("_0CustomOnOpenGcode")); +} + +function setSmoothing(mode) { + smoothingSettings = settings.smoothing; + if (mode == smoothing.isActive && (!mode || !smoothing.isDifferent) && !smoothing.force) { + return; // return if smoothing is already active or is not different + } + if (validateLengthCompensation && smoothingSettings.cancelCompensation) { + validate(!state.lengthCompensationActive, "Length compensation is active while trying to update smoothing."); + } + if (mode) { // enable smoothing + writeBlock(gFormat.format(120.1), getProperty("precisionLevel"), "Q" + smoothing.level); + } else { // disable smoothing + writeBlock(gFormat.format(121)); + } + smoothing.isActive = mode; + smoothing.force = false; + smoothing.isDifferent = false; +} + +function onSection() { + var forceSectionRestart = optionalSection && !currentSection.isOptional(); + optionalSection = currentSection.isOptional(); + var insertToolCall = isToolChangeNeeded("number") || forceSectionRestart; + var newWorkOffset = isNewWorkOffset() || forceSectionRestart; + var newWorkPlane = isNewWorkPlane() || forceSectionRestart; + operationNeedsSafeStart = getProperty("safeStartAllOperations") && !isFirstSection(); + initializeSmoothing(); // initialize smoothing mode + + // Manual Tool Change Tool Removal + // place in own function or COMMAND_MANUAL_LOAD + COMMAND_MANUAL_UNLOAD + if (insertToolCall && !isFirstSection()) { + if(getPreviousSection().getTool().manualToolChange == true) { + setCoolant(COOLANT_OFF); + onCommand(COMMAND_STOP_SPINDLE); + writeRetract(Z); + writeRetract(settings.retract.homeXY.onToolChange); + onCommand(COMMAND_STOP); + machineSimulation({x:getProperty("TCposX"), y: getProperty("TCposY"), coordinates:MACHINE, mode:TOOLCHANGE}); // move machineSimulation to a tool change position + //writeComment("Flip to Manual, Swap tools then cycle start to resume"); KC need to test + writeComment(""); + previousSection = getPreviousSection(); + if (previousSection) { + previousToolNumber = previousSection.getTool().number; + writeComment("Flip to manual, remove T" + previousToolNumber + " and replace with T" + tool.number + " then cycle start to resume" ); + } else { + writeComment("No previous tool (first tool in program)."); + } + } + } + + if (insertToolCall || newWorkOffset || newWorkPlane || smoothing.cancel || state.tcpIsActive) { + // stop coolant before retract during manual tool change + if (!isLastSection() && tool.manualToolChange == true && getNextSection().getTool().manualToolChange == true) { + onCommand(COMMAND_COOLANT_OFF) + } + + // stop spindle before retract during tool change + if (insertToolCall && !isFirstSection()) { + onCommand(COMMAND_STOP_SPINDLE); + } + disableLengthCompensation(); + if (getSetting("workPlaneMethod.cancelTiltFirst", false)) { + cancelWorkPlane(); + } + writeRetract(Z); // retract + if (isFirstSection() && machineConfiguration.isMultiAxisConfiguration()) { + setWorkPlane(new Vector(0, 0, 0)); // reset working plane + forceABC(); + } + forceXYZ(); + if (!isFirstSection() && (insertToolCall || smoothing.cancel || state.tcpIsActive)) { + disableLengthCompensation(); + if (smoothing.cancel || insertToolCall) { + setSmoothing(false); + } + } + } + + writeln(""); + writeComment(getParameter("operation-comment", "")); + + if (getProperty("showNotes")) { + writeSectionNotes(); + } + + // tool change + writeToolCall(tool, insertToolCall); + startSpindle(tool, insertToolCall); + + // write parametric feedrate table + if (typeof initializeParametricFeeds == "function") { + initializeParametricFeeds(insertToolCall); + } + // Output modal commands here + writeBlock(gPlaneModal.format(17), gAbsIncModal.format(90), gFeedModeModal.format(getProperty("useG95") ? 95 : 94)); + + // set wcs + var wcsIsRequired = true; + if (insertToolCall || operationNeedsSafeStart) { + currentWorkOffset = undefined; // force work offset when changing tool + wcsIsRequired = newWorkOffset || insertToolCall || !operationNeedsSafeStart; + } + writeWCS(currentSection, wcsIsRequired); + + forceXYZ(); + + onCommand(COMMAND_START_CHIP_TRANSPORT); + + var abc = defineWorkPlane(currentSection, true); + + setCoolant(tool.coolant); // writes the required coolant codes + + setSmoothing(smoothing.isAllowed); // writes the required smoothing codes + + // prepositioning + var initialPosition = getFramePosition(currentSection.getInitialPosition()); + var isRequired = insertToolCall || state.retractedZ || !state.lengthCompensationActive || (!isFirstSection() && getPreviousSection().isMultiAxis()); + writeInitialPositioning(initialPosition, isRequired); + + if (subprogramsAreSupported()) { + subprogramDefine(initialPosition, abc); // define subprogram + } + state.retractedZ = false; +} + +function onDwell(seconds) { + if (seconds > 99999.999) { + warning(localize("Dwelling time is out of range.")); + } + milliseconds = clamp(1, seconds * 1000, 99999999); + writeBlock(gFeedModeModal.format(94), gFormat.format(4), "P" + milliFormat.format(milliseconds)); + writeBlock(gFeedModeModal.format(getProperty("useG95") ? 95 : 94)); // back to G95 +} + +function onSpindleSpeed(spindleSpeed) { + writeBlock(sOutput.format(spindleSpeed)); +} + +function onCycle() { + writeBlock(gPlaneModal.format(17)); +} + +function onCyclePoint(x, y, z) { + if (isInspectionOperation()) { + if (typeof inspectionCycleInspect == "function") { + inspectionCycleInspect(cycle, x, y, z); + return; + } else { + cycleNotSupported(); + } + } else if (isProbeOperation()) { + writeProbeCycle(cycle, x, y, z); + } else { + properties.useRigidTapping = {current:"no"}; // TAG: required to include common Fanuc cycles + writeDrillCycle(cycle, x, y, z); + } +} + +function onCycleEnd() { + if (subprogramsAreSupported() && subprogramState.cycleSubprogramIsActive) { + subprogramEnd(); + } + if (!cycleExpanded) { + writeBlock(gFeedModeModal.format(getProperty("useG95") ? 95 : 94), gCycleModal.format(80)); + zOutput.reset(); + } +} + +var mapCommand = { + COMMAND_END : 2, + COMMAND_SPINDLE_CLOCKWISE : 3, + COMMAND_SPINDLE_COUNTERCLOCKWISE: 4, + COMMAND_STOP_SPINDLE : 5, + COMMAND_ORIENTATE_SPINDLE : 19 +}; + +function onCommand(command) { + switch (command) { + case COMMAND_COOLANT_OFF: + setCoolant(COOLANT_OFF); + return; + case COMMAND_COOLANT_ON: + setCoolant(tool.coolant); + return; + case COMMAND_STOP: + writeBlock(mFormat.format(0)); + forceSpindleSpeed = true; + forceCoolant = true; + return; + case COMMAND_OPTIONAL_STOP: + writeBlock(mFormat.format(1)); + forceSpindleSpeed = true; + forceCoolant = true; + return; + case COMMAND_START_SPINDLE: + forceSpindleSpeed = false; + writeBlock(sOutput.format(spindleSpeed), mFormat.format(tool.clockwise ? 3 : 4)); + return; + case COMMAND_LOAD_TOOL: + writeToolBlock("T" + toolFormat.format(tool.number), mFormat.format(6)); + writeComment(tool.comment); + if (tool.manualToolChange != true){ + writeComment(tool.description); + writeComment(tool.bodyLength + "mm Stick out below " + tool.holderDescription + " holder"); + } + // preload tools not supported on umbrella changer machines + //var preloadTool = getNextTool(tool.number != getFirstTool().number); + //if (getProperty("preloadTool") && preloadTool) { + // writeBlock("T" + toolFormat.format(preloadTool.number)); // preload next/first tool + //} + return; + case COMMAND_LOCK_MULTI_AXIS: + var outputClampCodes = getProperty("useClampCodes") || currentSection.isMultiAxis(); + if (outputClampCodes && machineConfiguration.isMultiAxisConfiguration()) { + writeBlock(fourthAxisClamp.format(10), conditional(machineConfiguration.getNumberOfAxes() > 4, fifthAxisClamp.format(110))); // lock 4th + 5th axis + } + return; + case COMMAND_UNLOCK_MULTI_AXIS: + var outputClampCodes = getProperty("useClampCodes") || currentSection.isMultiAxis(); + if (outputClampCodes && machineConfiguration.isMultiAxisConfiguration()) { + writeBlock(fourthAxisClamp.format(11), conditional(machineConfiguration.getNumberOfAxes() > 4, fifthAxisClamp.format(111))); // unlock 4th + 5th axis + } + return; + case COMMAND_START_CHIP_TRANSPORT: + return; + case COMMAND_STOP_CHIP_TRANSPORT: + return; + case COMMAND_BREAK_CONTROL: + onCommand(COMMAND_STOP_SPINDLE); + setCoolant(COOLANT_OFF) + writeRetract(Z); + // add tool change position move? + writeBlock(mFormat.format(106) + " T" + toolFormat.format(tool.number)+ " D" + xyzFormat.format(tool.diameter) + " E"+ getProperty("breakControlError")); + machineSimulation({x:getProperty("TCposX"), y: getProperty("TCposY"), coordinates:MACHINE, mode:TOOLCHANGE}); // move machineSimulation to a tool change position + // add second retract post tool measure? + return; + case COMMAND_TOOL_MEASURE: + return; + case COMMAND_PROBE_ON: + return; + case COMMAND_PROBE_OFF: + return; + } + + var stringId = getCommandStringId(command); + var mcode = mapCommand[stringId]; + if (mcode != undefined) { + writeBlock(mFormat.format(mcode)); + } else { + onUnsupportedCommand(command); + } +} + +function onSectionEnd() { + if (currentSection.isMultiAxis()) { + writeBlock(gFeedModeModal.format(getProperty("useG95") ? 95 : 94)); // inverse time feed off + } + writeBlock(gPlaneModal.format(17)); + + if (!isLastSection()) { + if (getNextSection().getTool().coolant != tool.coolant) { + setCoolant(COOLANT_OFF); + } + if (tool.breakControl && isToolChangeNeeded(getNextSection(), getProperty("toolAsName") ? "description" : "number")) { + onCommand(COMMAND_BREAK_CONTROL); + } + } + + if (subprogramsAreSupported()) { + subprogramEnd(); + } + + forceAny(); + + operationNeedsSafeStart = false; // reset for next section +} + +// Start of onRewindMachine logic +/** Allow user to override the onRewind logic. */ +function onRewindMachineEntry(_a, _b, _c) { + return false; +} + +/** Retract to safe position before indexing rotaries. */ +function onMoveToSafeRetractPosition() { + writeRetract(Z); + // cancel TCP so that tool doesn't follow rotaries + if (currentSection.isMultiAxis() && tcp.isSupportedByOperation) { + disableLengthCompensation(false, "TCPC OFF"); + } +} + +/** Rotate axes to new position above reentry position */ +function onRotateAxes(_x, _y, _z, _a, _b, _c) { + // position rotary axes + xOutput.disable(); + yOutput.disable(); + zOutput.disable(); + onRapid5D(_x, _y, _z, _a, _b, _c); + setCurrentABC(new Vector(_a, _b, _c)); + machineSimulation({a:_a, b:_b, c:_c, coordinates:MACHINE}); + xOutput.enable(); + yOutput.enable(); + zOutput.enable(); +} + +/** Return from safe position after indexing rotaries. */ +function onReturnFromSafeRetractPosition(_x, _y, _z) { + // reinstate TCP / tool length compensation + if (!state.lengthCompensationActive) { + writeBlock(getOffsetCode(), hFormat.format(tool.lengthOffset)); + } + + // position in XY + forceXYZ(); + xOutput.reset(); + yOutput.reset(); + zOutput.disable(); + if (highFeedMapping != HIGH_FEED_NO_MAPPING) { + onLinear(_x, _y, _z, highFeedrate); + } else { + onRapid(_x, _y, _z); + } + machineSimulation({x:_x, y:_y}); + // position in Z + zOutput.enable(); + invokeOnRapid(_x, _y, _z); +} +// End of onRewindMachine logic + +function onClose() { + optionalSection = false; + writeln(""); + onCommand(COMMAND_STOP_SPINDLE); + onCommand(COMMAND_COOLANT_OFF); + disableLengthCompensation(true); + cancelWorkPlane(); + writeRetract(Z); // retract + setSmoothing(false); + forceWorkPlane(); + setWorkPlane(new Vector(0, 0, 0)); // reset working plane + if (getSetting("retract.homeXY.onProgramEnd", false)) { + writeRetract(settings.retract.homeXY.onProgramEnd); + } + writeBlock(mFormat.format(30)); // program end + + if (subprogramsAreSupported()) { + writeSubprograms(); + } + writeln("%"); + writeBlock(getProperty("_1CustomOnCloseGcode")); +} + +// >>>>> INCLUDED FROM include_files/commonFunctions.cpi +// internal variables, do not change +var receivedMachineConfiguration; +var tcp = {isSupportedByControl:getSetting("supportsTCP", true), isSupportedByMachine:false, isSupportedByOperation:false}; +var state = { + retractedX : false, // specifies that the machine has been retracted in X + retractedY : false, // specifies that the machine has been retracted in Y + retractedZ : false, // specifies that the machine has been retracted in Z + tcpIsActive : false, // specifies that TCP is currently active + twpIsActive : false, // specifies that TWP is currently active + lengthCompensationActive: !getSetting("outputToolLengthCompensation", true), // specifies that tool length compensation is active + mainState : true // specifies the current context of the state (true = main, false = optional) +}; +var validateLengthCompensation = getSetting("outputToolLengthCompensation", true); // disable validation when outputToolLengthCompensation is disabled +var multiAxisFeedrate; +var sequenceNumber; +var optionalSection = false; +var currentWorkOffset; +var forceSpindleSpeed = false; +var operationNeedsSafeStart = false; // used to convert blocks to optional for safeStartAllOperations + +function activateMachine() { + // disable unsupported rotary axes output + if (!machineConfiguration.isMachineCoordinate(0) && (typeof aOutput != "undefined")) { + aOutput.disable(); + } + if (!machineConfiguration.isMachineCoordinate(1) && (typeof bOutput != "undefined")) { + bOutput.disable(); + } + if (!machineConfiguration.isMachineCoordinate(2) && (typeof cOutput != "undefined")) { + cOutput.disable(); + } + + // setup usage of useTiltedWorkplane + settings.workPlaneMethod.useTiltedWorkplane = getProperty("useTiltedWorkplane") != undefined ? getProperty("useTiltedWorkplane") : + getSetting("workPlaneMethod.useTiltedWorkplane", false); + settings.workPlaneMethod.useABCPrepositioning = getProperty("useABCPrepositioning") != undefined ? getProperty("useABCPrepositioning") : + getSetting("workPlaneMethod.useABCPrepositioning", false); + + if (!machineConfiguration.isMultiAxisConfiguration()) { + return; // don't need to modify any settings for 3-axis machines + } + + // identify if any of the rotary axes has TCP enabled + var axes = [machineConfiguration.getAxisU(), machineConfiguration.getAxisV(), machineConfiguration.getAxisW()]; + tcp.isSupportedByMachine = axes.some(function(axis) {return axis.isEnabled() && axis.isTCPEnabled();}); // true if TCP is enabled on any rotary axis + + // save multi-axis feedrate settings from machine configuration + var mode = machineConfiguration.getMultiAxisFeedrateMode(); + var type = mode == FEED_INVERSE_TIME ? machineConfiguration.getMultiAxisFeedrateInverseTimeUnits() : + (mode == FEED_DPM ? machineConfiguration.getMultiAxisFeedrateDPMType() : DPM_STANDARD); + multiAxisFeedrate = { + mode : mode, + maximum : machineConfiguration.getMultiAxisFeedrateMaximum(), + type : type, + tolerance: mode == FEED_DPM ? machineConfiguration.getMultiAxisFeedrateOutputTolerance() : 0, + bpwRatio : mode == FEED_DPM ? machineConfiguration.getMultiAxisFeedrateBpwRatio() : 1 + }; + + // setup of retract/reconfigure TAG: Only needed until post kernel supports these machine config settings + if (receivedMachineConfiguration && machineConfiguration.performRewinds()) { + safeRetractDistance = machineConfiguration.getSafeRetractDistance(); + safePlungeFeed = machineConfiguration.getSafePlungeFeedrate(); + safeRetractFeed = machineConfiguration.getSafeRetractFeedrate(); + } + if (typeof safeRetractDistance == "number" && getProperty("safeRetractDistance") != undefined && getProperty("safeRetractDistance") != 0) { + safeRetractDistance = getProperty("safeRetractDistance"); + } + + if (machineConfiguration.isHeadConfiguration()) { + compensateToolLength = typeof compensateToolLength == "undefined" ? false : compensateToolLength; + } + + if (machineConfiguration.isHeadConfiguration() && compensateToolLength) { + for (var i = 0; i < getNumberOfSections(); ++i) { + var section = getSection(i); + if (section.isMultiAxis()) { + machineConfiguration.setToolLength(getBodyLength(section.getTool())); // define the tool length for head adjustments + section.optimizeMachineAnglesByMachine(machineConfiguration, OPTIMIZE_AXIS); + } + } + } else { + optimizeMachineAngles2(OPTIMIZE_AXIS); + } +} + +function getBodyLength(tool) { + for (var i = 0; i < getNumberOfSections(); ++i) { + var section = getSection(i); + if (tool.number == section.getTool().number) { + return section.getParameter("operation:tool_overallLength", tool.bodyLength + tool.holderLength); + } + } + return tool.bodyLength + tool.holderLength; +} + +function getFeed(f) { + if (getProperty("useG95")) { + return feedOutput.format(f / spindleSpeed); // use feed value + } + if (typeof activeMovements != "undefined" && activeMovements) { + var feedContext = activeMovements[movement]; + if (feedContext != undefined) { + if (!feedFormat.areDifferent(feedContext.feed, f)) { + if (feedContext.id == currentFeedId) { + return ""; // nothing has changed + } + forceFeed(); + currentFeedId = feedContext.id; + return settings.parametricFeeds.feedOutputVariable + (settings.parametricFeeds.firstFeedParameter + feedContext.id); + } + } + currentFeedId = undefined; // force parametric feed next time + } + return feedOutput.format(f); // use feed value +} + +function validateCommonParameters() { + validateToolData(); + for (var i = 0; i < getNumberOfSections(); ++i) { + var section = getSection(i); + if (getSection(0).workOffset == 0 && section.workOffset > 0) { + if (!(typeof wcsDefinitions != "undefined" && wcsDefinitions.useZeroOffset)) { + error(localize("Using multiple work offsets is not possible if the initial work offset is 0.")); + } + } + if (section.isMultiAxis()) { + if (!section.isOptimizedForMachine() && + (!getSetting("workPlaneMethod.useTiltedWorkplane", false) || !getSetting("supportsToolVectorOutput", false))) { + error(localize("This postprocessor requires a machine configuration for 5-axis simultaneous toolpath.")); + } + if (machineConfiguration.getMultiAxisFeedrateMode() == FEED_INVERSE_TIME && !getSetting("supportsInverseTimeFeed", true)) { + error(localize("This postprocessor does not support inverse time feedrates.")); + } + if (getSetting("supportsToolVectorOutput", false) && !tcp.isSupportedByControl) { + error(localize("Incompatible postprocessor settings detected." + EOL + + "Setting 'supportsToolVectorOutput' requires setting 'supportsTCP' to be enabled as well.")); + } + } + } + if (!tcp.isSupportedByControl && tcp.isSupportedByMachine) { + error(localize("The machine configuration has TCP enabled which is not supported by this postprocessor.")); + } + if (getProperty("safePositionMethod") == "clearanceHeight") { + var msg = "-Attention- Property 'Safe Retracts' is set to 'Clearance Height'." + EOL + + "Ensure the clearance height will clear the part and or fixtures." + EOL + + "Raise the Z-axis to a safe height before starting the program."; + warning(msg); + writeComment(msg); + } +} + +function validateToolData() { + var _default = 99999; + var _maximumSpindleRPM = machineConfiguration.getMaximumSpindleSpeed() > 0 ? machineConfiguration.getMaximumSpindleSpeed() : + settings.maximumSpindleRPM == undefined ? _default : settings.maximumSpindleRPM; + var _maximumToolNumber = machineConfiguration.isReceived() && machineConfiguration.getNumberOfTools() > 0 ? machineConfiguration.getNumberOfTools() : + settings.maximumToolNumber == undefined ? _default : settings.maximumToolNumber; + var _maximumToolLengthOffset = settings.maximumToolLengthOffset == undefined ? _default : settings.maximumToolLengthOffset; + var _maximumToolDiameterOffset = settings.maximumToolDiameterOffset == undefined ? _default : settings.maximumToolDiameterOffset; + + var header = ["Detected maximum values are out of range.", "Maximum values:"]; + var warnings = { + toolNumber : {msg:"Tool number value exceeds the maximum value for tool: " + EOL, max:" Tool number: " + _maximumToolNumber, values:[]}, + lengthOffset : {msg:"Tool length offset value exceeds the maximum value for tool: " + EOL, max:" Tool length offset: " + _maximumToolLengthOffset, values:[]}, + diameterOffset: {msg:"Tool diameter offset value exceeds the maximum value for tool: " + EOL, max:" Tool diameter offset: " + _maximumToolDiameterOffset, values:[]}, + spindleSpeed : {msg:"Spindle speed exceeds the maximum value for operation: " + EOL, max:" Spindle speed: " + _maximumSpindleRPM, values:[]} + }; + + var toolIds = []; + for (var i = 0; i < getNumberOfSections(); ++i) { + var section = getSection(i); + if (toolIds.indexOf(section.getTool().getToolId()) === -1) { // loops only through sections which have a different tool ID + var toolNumber = section.getTool().number; + var lengthOffset = section.getTool().lengthOffset; + var diameterOffset = section.getTool().diameterOffset; + var comment = section.getParameter("operation-comment", ""); + + if (toolNumber > _maximumToolNumber && !getProperty("toolAsName")) { + warnings.toolNumber.values.push(SP + toolNumber + EOL); + } + if (lengthOffset > _maximumToolLengthOffset) { + warnings.lengthOffset.values.push(SP + "Tool " + toolNumber + " (" + comment + "," + " Length offset: " + lengthOffset + ")" + EOL); + } + if (diameterOffset > _maximumToolDiameterOffset) { + warnings.diameterOffset.values.push(SP + "Tool " + toolNumber + " (" + comment + "," + " Diameter offset: " + diameterOffset + ")" + EOL); + } + toolIds.push(section.getTool().getToolId()); + } + // loop through all sections regardless of tool id for idenitfying spindle speeds + + // identify if movement ramp is used in current toolpath, use ramp spindle speed for comparisons + var ramp = section.getMovements() & ((1 << MOVEMENT_RAMP) | (1 << MOVEMENT_RAMP_ZIG_ZAG) | (1 << MOVEMENT_RAMP_PROFILE) | (1 << MOVEMENT_RAMP_HELIX)); + var _sectionSpindleSpeed = Math.max(section.getTool().spindleRPM, ramp ? section.getTool().rampingSpindleRPM : 0, 0); + if (_sectionSpindleSpeed > _maximumSpindleRPM) { + warnings.spindleSpeed.values.push(SP + section.getParameter("operation-comment", "") + " (" + _sectionSpindleSpeed + " RPM" + ")" + EOL); + } + } + + // sort lists by tool number + warnings.toolNumber.values.sort(function(a, b) {return a - b;}); + warnings.lengthOffset.values.sort(function(a, b) {return a.localeCompare(b);}); + warnings.diameterOffset.values.sort(function(a, b) {return a.localeCompare(b);}); + + var warningMessages = []; + for (var key in warnings) { + if (warnings[key].values != "") { + header.push(warnings[key].max); // add affected max values to the header + warningMessages.push(warnings[key].msg + warnings[key].values.join("")); + } + } + if (warningMessages.length != 0) { + warningMessages.unshift(header.join(EOL) + EOL); + warning(warningMessages.join(EOL)); + } +} + +function forceFeed() { + currentFeedId = undefined; + feedOutput.reset(); +} + +/** Force output of X, Y, and Z. */ +function forceXYZ() { + xOutput.reset(); + yOutput.reset(); + zOutput.reset(); +} + +/** Force output of A, B, and C. */ +function forceABC() { + aOutput.reset(); + bOutput.reset(); + cOutput.reset(); +} + +/** Force output of X, Y, Z, A, B, C, and F on next output. */ +function forceAny() { + forceXYZ(); + forceABC(); + forceFeed(); +} + +/** + Writes the specified block. +*/ +function writeBlock() { + var text = formatWords(arguments); + if (!text) { + return; + } + var prefix = getSetting("sequenceNumberPrefix", "N"); + var suffix = getSetting("writeBlockSuffix", ""); + if ((optionalSection || skipBlocks) && !getSetting("supportsOptionalBlocks", true)) { + error(localize("Optional blocks are not supported by this post.")); + } + if (getProperty("showSequenceNumbers") == "true") { + if (sequenceNumber == undefined || sequenceNumber >= settings.maximumSequenceNumber) { + sequenceNumber = getProperty("sequenceNumberStart"); + } + if (optionalSection || skipBlocks) { + writeWords2("/", prefix + sequenceNumber, text + suffix); + } else { + writeWords2(prefix + sequenceNumber, text + suffix); + } + sequenceNumber += getProperty("sequenceNumberIncrement"); + } else { + if (optionalSection || skipBlocks) { + writeWords2("/", text + suffix); + } else { + writeWords(text + suffix); + } + } +} + +validate(settings.comments, "Setting 'comments' is required but not defined."); +function formatComment(text) { + var prefix = settings.comments.prefix; + var suffix = settings.comments.suffix; + var _permittedCommentChars = settings.comments.permittedCommentChars == undefined ? "" : settings.comments.permittedCommentChars; + switch (settings.comments.outputFormat) { + case "upperCase": + text = text.toUpperCase(); + _permittedCommentChars = _permittedCommentChars.toUpperCase(); + break; + case "lowerCase": + text = text.toLowerCase(); + _permittedCommentChars = _permittedCommentChars.toLowerCase(); + break; + case "ignoreCase": + _permittedCommentChars = _permittedCommentChars.toUpperCase() + _permittedCommentChars.toLowerCase(); + break; + default: + error(localize("Unsupported option specified for setting 'comments.outputFormat'.")); + } + if (_permittedCommentChars != "") { + text = filterText(String(text), _permittedCommentChars); + } + text = String(text).substring(0, settings.comments.maximumLineLength - prefix.length - suffix.length); + return text != "" ? prefix + text + suffix : ""; +} + +/** + Output a comment. +*/ +function writeComment(text) { + if (!text) { + return; + } + var comments = String(text).split(EOL); + for (comment in comments) { + var _comment = formatComment(comments[comment]); + if (_comment) { + if (getSetting("comments.showSequenceNumbers", false)) { + writeBlock(_comment); + } else { + writeln(_comment); + } + } + } +} + +function onComment(text) { + writeComment(text); +} + +/** + Writes the specified block - used for tool changes only. +*/ +function writeToolBlock() { + var show = getProperty("showSequenceNumbers"); + setProperty("showSequenceNumbers", (show == "true" || show == "toolChange") ? "true" : "false"); + writeBlock(arguments); + setProperty("showSequenceNumbers", show); + machineSimulation({x:getProperty("TCposX"), y: getProperty("TCposY"), coordinates:MACHINE, mode:TOOLCHANGE}); // move machineSimulation to a tool change position +} + +var skipBlocks = false; +var initialState = JSON.parse(JSON.stringify(state)); // save initial state +var optionalState = JSON.parse(JSON.stringify(state)); +var saveCurrentSectionId = undefined; +function writeStartBlocks(isRequired, code) { + var saveSkipBlocks = skipBlocks; + var saveMainState = state; // save main state + + if (!isRequired) { + if (!getProperty("safeStartAllOperations", false)) { + return; // when safeStartAllOperations is disabled, dont output code and return + } + if (saveCurrentSectionId != getCurrentSectionId()) { + saveCurrentSectionId = getCurrentSectionId(); + forceModals(); // force all modal variables when entering a new section + optionalState = Object.create(initialState); // reset optionalState to initialState when entering a new section + } + skipBlocks = true; // if values are not required, but safeStartAllOperations is enabled - write following blocks as optional + state = optionalState; // set state to optionalState if skipBlocks is true + state.mainState = false; + } + code(); // writes out the code which is passed to this function as an argument + + state = saveMainState; // restore main state + skipBlocks = saveSkipBlocks; // restore skipBlocks value +} + +var pendingRadiusCompensation = -1; +function onRadiusCompensation() { + pendingRadiusCompensation = radiusCompensation; + if (pendingRadiusCompensation >= 0 && !getSetting("supportsRadiusCompensation", true)) { + error(localize("Radius compensation mode is not supported.")); + return; + } +} + +function onPassThrough(text) { + var commands = String(text).split(","); + for (text in commands) { + writeBlock(commands[text]); + } +} + +function forceModals() { + if (arguments.length == 0) { // reset all modal variables listed below + if (typeof gMotionModal != "undefined") { + gMotionModal.reset(); + } + if (typeof gPlaneModal != "undefined") { + gPlaneModal.reset(); + } + if (typeof gAbsIncModal != "undefined") { + gAbsIncModal.reset(); + } + if (typeof gFeedModeModal != "undefined") { + gFeedModeModal.reset(); + } + } else { + for (var i in arguments) { + arguments[i].reset(); // only reset the modal variable passed to this function + } + } +} + +/** Helper function to be able to use a default value for settings which do not exist. */ +function getSetting(setting, defaultValue) { + var result = defaultValue; + var keys = setting.split("."); + var obj = settings; + for (var i in keys) { + if (obj[keys[i]] != undefined) { // setting does exist + result = obj[keys[i]]; + if (typeof [keys[i]] === "object") { + obj = obj[keys[i]]; + continue; + } + } else { // setting does not exist, use default value + if (defaultValue != undefined) { + result = defaultValue; + } else { + error("Setting '" + keys[i] + "' has no default value and/or does not exist."); + return undefined; + } + } + } + return result; +} + +function getForwardDirection(_section) { + var forward = undefined; + var _optimizeType = settings.workPlaneMethod && settings.workPlaneMethod.optimizeType; + if (_section.isMultiAxis()) { + forward = _section.workPlane.forward; + } else if (!getSetting("workPlaneMethod.useTiltedWorkplane", false) && machineConfiguration.isMultiAxisConfiguration()) { + if (_optimizeType == undefined) { + var saveRotation = getRotation(); + getWorkPlaneMachineABC(_section, true); + forward = getRotation().forward; + setRotation(saveRotation); // reset rotation + } else { + var abc = getWorkPlaneMachineABC(_section, false); + var forceAdjustment = settings.workPlaneMethod.optimizeType == OPTIMIZE_TABLES || settings.workPlaneMethod.optimizeType == OPTIMIZE_BOTH; + forward = machineConfiguration.getOptimizedDirection(_section.workPlane.forward, abc, false, forceAdjustment); + } + } else { + forward = getRotation().forward; + } + return forward; +} + +function getRetractParameters() { + var _arguments = typeof arguments[0] === "object" ? arguments[0].axes : arguments; + var singleLine = arguments[0].singleLine == undefined ? true : arguments[0].singleLine; + var words = []; // store all retracted axes in an array + var retractAxes = new Array(false, false, false); + var method = getProperty("safePositionMethod", "undefined"); + if (method == "clearanceHeight") { + if (!is3D()) { + error(localize("Safe retract option 'Clearance Height' is only supported when all operations are along the setup Z-axis.")); + } + return undefined; + } + validate(settings.retract, "Setting 'retract' is required but not defined."); + validate(_arguments.length != 0, "No axis specified for getRetractParameters()."); + for (i in _arguments) { + retractAxes[_arguments[i]] = true; + } + if ((retractAxes[0] || retractAxes[1]) && !state.retractedZ) { // retract Z first before moving to X/Y home + error(localize("Retracting in X/Y is not possible without being retracted in Z.")); + return undefined; + } + // special conditions + if (retractAxes[0] || retractAxes[1]) { + method = getSetting("retract.methodXY", method); + } + if (retractAxes[2]) { + method = getSetting("retract.methodZ", method); + } + // define home positions + var useZeroValues = (settings.retract.useZeroValues && settings.retract.useZeroValues.indexOf(method) != -1); + var _xHome = machineConfiguration.hasHomePositionX() && !useZeroValues ? machineConfiguration.getHomePositionX() : toPreciseUnit(0, MM); + var _yHome = machineConfiguration.hasHomePositionY() && !useZeroValues ? machineConfiguration.getHomePositionY() : toPreciseUnit(0, MM); + var _zHome = machineConfiguration.getRetractPlane() != 0 && !useZeroValues ? machineConfiguration.getRetractPlane() : toPreciseUnit(0, MM); + for (var i = 0; i < _arguments.length; ++i) { + switch (_arguments[i]) { + case X: + if (!state.retractedX) { + words.push("X" + xyzFormat.format(_xHome)); + xOutput.reset(); + state.retractedX = true; + } + break; + case Y: + if (!state.retractedY) { + words.push("Y" + xyzFormat.format(_yHome)); + yOutput.reset(); + state.retractedY = true; + } + break; + case Z: + if (!state.retractedZ) { + words.push("Z" + xyzFormat.format(_zHome)); + zOutput.reset(); + state.retractedZ = true; + } + break; + default: + error(localize("Unsupported axis specified for getRetractParameters().")); + return undefined; + } + } + return { + method : method, + retractAxes: retractAxes, + words : words, + positions : { + x: retractAxes[0] ? _xHome : undefined, + y: retractAxes[1] ? _yHome : undefined, + z: retractAxes[2] ? _zHome : undefined}, + singleLine: singleLine}; +} + +/** Returns true when subprogram logic does exist into the post. */ +function subprogramsAreSupported() { + return typeof subprogramState != "undefined"; +} + +// Start of machine simulation connection move support +var TCPON = "TCP ON"; +var TCPOFF = "TCP OFF"; +var TWPON = "TWP ON"; +var TWPOFF = "TWP OFF"; +var TOOLCHANGE = "TOOL CHANGE"; +var WORK = "WORK CS"; +var MACHINE = "MACHINE CS"; +var isTwpOn; // only used for debugging +var isTcpOn; // only used for debugging +if (typeof groupDefinitions != "object") { + groupDefinitions = {}; +} +groupDefinitions.machineSimulation = {title:"Machine Simulation", collapsed:true, order:99}; +properties.simulateConnectionMoves = { + title : "Simulate Connection Moves (Preview feature)", + description: "Specifies that connection moves like prepositioning, tool changes, retracts and other non-cutting moves should be shown in the machine simulation." + EOL + + "Note, this property does not affect the NC output, it only affects the machine simulation.", + group: "machineSimulation", + type : "boolean", + value: false, + scope: "machine" +}; +/** + * Helper function for connection moves in machine simulation. + * @param {Object} parameters An object containing the desired options for machine simulation. + * @note Available properties are: + * @param {Number} x X axis position + * @param {Number} y Y axis position + * @param {Number} z Z axis position + * @param {Number} a A axis position (in radians) + * @param {Number} b B axis position (in radians) + * @param {Number} c C axis position (in radians) + * @param {Number} feed desired feedrate, automatically set to high/current feedrate if not specified + * @param {String} mode mode TCPON | TCPOFF | TWPON | TWPOFF | TOOLCHANGE + * @param {String} coordinates WORK | MACHINE - if undefined, work coordinates will be used by default + * @param {Number} eulerAngles the calculated Euler angles for the workplane + * @example + machineSimulation({a:abc.x, b:abc.y, c:abc.z, coordinates:MACHINE}); + machineSimulation({x:toPreciseUnit(200, MM), y:toPreciseUnit(200, MM), coordinates:MACHINE, toolChange:true}); +*/ +var debugSimulation = false; // enable to output debug information for connection move support in the NC program + +function machineSimulation(parameters) { + if (revision < 50075 || skipBlocks || !getProperty("simulateConnectionMoves")) { + return; // return when post kernel revision is lower than 50075 or when skipBlocks is enabled + } + var x = parameters.x; + var y = parameters.y; + var z = parameters.z; + var a = parameters.a; + var b = parameters.b; + var c = parameters.c; + var coordinates = parameters.coordinates; + var eulerAngles = parameters.eulerAngles; + var feed = parameters.feed; + if (feed === undefined && typeof gMotionModal !== "undefined") { + feed = gMotionModal.getCurrent() !== 0; + } + var mode = parameters.mode; + var performToolChange = mode == TOOLCHANGE; + if (mode !== undefined && ![TCPON, TCPOFF, TWPON, TWPOFF, TOOLCHANGE].includes(mode)) { + error(subst("Mode '%1' is not supported.", mode)); + } + + // mode takes precedence over active state + var enableTCP = mode != undefined ? mode == TCPON : typeof state !== "undefined" && state.tcpIsActive; + var enableTWP = mode != undefined ? mode == TWPON : typeof state !== "undefined" && state.twpIsActive; + var disableTCP = mode != undefined ? mode == TCPOFF : typeof state !== "undefined" && !state.tcpIsActive; + var disableTWP = mode != undefined ? mode == TWPOFF : typeof state !== "undefined" && !state.twpIsActive; + if (enableTCP) { // update TCP mode + simulation.setTWPModeOff(); + simulation.setTCPModeOn(); + isTcpOn = true; + } else if (disableTCP) { + simulation.setTCPModeOff(); + isTcpOn = false; + } + + if (enableTWP) { // update TWP mode + simulation.setTCPModeOff(); + if (settings.workPlaneMethod.eulerConvention == undefined) { + simulation.setTWPModeAlignToCurrentPose(); + } else if (eulerAngles) { + simulation.setTWPModeByEulerAngles(settings.workPlaneMethod.eulerConvention, eulerAngles.x, eulerAngles.y, eulerAngles.z); + } + isTwpOn = true; + } else if (disableTWP) { + simulation.setTWPModeOff(); + isTwpOn = false; + } + if (debugSimulation) { + writeln(" DEBUG" + JSON.stringify(parameters)); + writeln(" DEBUG" + JSON.stringify({isTwpOn:isTwpOn, isTcpOn:isTcpOn, feed:feed})); + } + + if (x !== undefined || y !== undefined || z !== undefined || a !== undefined || b !== undefined || c !== undefined) { + if (x !== undefined) {simulation.setTargetX(x);} + if (y !== undefined) {simulation.setTargetY(y);} + if (z !== undefined) {simulation.setTargetZ(z);} + if (a !== undefined) {simulation.setTargetA(a);} + if (b !== undefined) {simulation.setTargetB(b);} + if (c !== undefined) {simulation.setTargetC(c);} + + if (feed != undefined && feed) { + simulation.setMotionToLinear(); + simulation.setFeedrate(typeof feed == "number" ? feed : feedOutput.getCurrent() == 0 ? highFeedrate : feedOutput.getCurrent()); + } else { + simulation.setMotionToRapid(); + } + + if (coordinates != undefined && coordinates == MACHINE) { + simulation.moveToTargetInMachineCoords(); + } else { + simulation.moveToTargetInWorkCoords(); + } + } + if (performToolChange) { + simulation.performToolChangeCycle(); + } +} +// <<<<< INCLUDED FROM include_files/commonFunctions.cpi +// >>>>> INCLUDED FROM include_files/defineMachine.cpi +var compensateToolLength = false; // add the tool length to the pivot distance for nonTCP rotary heads +function defineMachine() { + var useTCP = true; + if (false) { // note: setup your machine here + var aAxis = createAxis({coordinate:0, table:true, axis:[1, 0, 0], range:[-120, 120], preference:1, tcp:useTCP}); + var cAxis = createAxis({coordinate:2, table:true, axis:[0, 0, 1], range:[-360, 360], preference:0, tcp:useTCP}); + machineConfiguration = new MachineConfiguration(aAxis, cAxis); + + setMachineConfiguration(machineConfiguration); + if (receivedMachineConfiguration) { + warning(localize("The provided CAM machine configuration is overwritten by the postprocessor.")); + receivedMachineConfiguration = false; // CAM provided machine configuration is overwritten + } + } + + if (!receivedMachineConfiguration) { + // multiaxis settings + if (machineConfiguration.isHeadConfiguration()) { + machineConfiguration.setVirtualTooltip(false); // translate the pivot point to the virtual tool tip for nonTCP rotary heads + } + + // retract / reconfigure + var performRewinds = false; // set to true to enable the rewind/reconfigure logic + if (performRewinds) { + machineConfiguration.enableMachineRewinds(); // enables the retract/reconfigure logic + safeRetractDistance = (unit == IN) ? 1 : 25; // additional distance to retract out of stock, can be overridden with a property + safeRetractFeed = (unit == IN) ? 20 : 500; // retract feed rate + safePlungeFeed = (unit == IN) ? 10 : 250; // plunge feed rate + machineConfiguration.setSafeRetractDistance(safeRetractDistance); + machineConfiguration.setSafeRetractFeedrate(safeRetractFeed); + machineConfiguration.setSafePlungeFeedrate(safePlungeFeed); + var stockExpansion = new Vector(toPreciseUnit(0.1, IN), toPreciseUnit(0.1, IN), toPreciseUnit(0.1, IN)); // expand stock XYZ values + machineConfiguration.setRewindStockExpansion(stockExpansion); + } + + // multi-axis feedrates + if (machineConfiguration.isMultiAxisConfiguration()) { + machineConfiguration.setMultiAxisFeedrate( + useTCP ? FEED_FPM : getProperty("useDPMFeeds") ? FEED_DPM : FEED_INVERSE_TIME, + 9999.99, // maximum output value for inverse time feed rates + getProperty("useDPMFeeds") ? DPM_COMBINATION : INVERSE_MINUTES, // INVERSE_MINUTES/INVERSE_SECONDS or DPM_COMBINATION/DPM_STANDARD + 0.5, // tolerance to determine when the DPM feed has changed + 1.0 // ratio of rotary accuracy to linear accuracy for DPM calculations + ); + setMachineConfiguration(machineConfiguration); + } + + /* home positions */ + // machineConfiguration.setHomePositionX(toPreciseUnit(0, IN)); + // machineConfiguration.setHomePositionY(toPreciseUnit(0, IN)); + // machineConfiguration.setRetractPlane(toPreciseUnit(0, IN)); + } +} +// <<<<< INCLUDED FROM include_files/defineMachine.cpi +// >>>>> INCLUDED FROM include_files/defineWorkPlane.cpi +validate(settings.workPlaneMethod, "Setting 'workPlaneMethod' is required but not defined."); +function defineWorkPlane(_section, _setWorkPlane) { + var abc = new Vector(0, 0, 0); + if (settings.workPlaneMethod.forceMultiAxisIndexing || !is3D() || machineConfiguration.isMultiAxisConfiguration()) { + if (isPolarModeActive()) { + abc = getCurrentDirection(); + } else if (_section.isMultiAxis()) { + forceWorkPlane(); + cancelTransformation(); + abc = _section.isOptimizedForMachine() ? _section.getInitialToolAxisABC() : _section.getGlobalInitialToolAxis(); + } else if (settings.workPlaneMethod.useTiltedWorkplane && settings.workPlaneMethod.eulerConvention != undefined) { + if (settings.workPlaneMethod.eulerCalculationMethod == "machine" && machineConfiguration.isMultiAxisConfiguration()) { + abc = machineConfiguration.getOrientation(getWorkPlaneMachineABC(_section, true)).getEuler2(settings.workPlaneMethod.eulerConvention); + } else { + abc = _section.workPlane.getEuler2(settings.workPlaneMethod.eulerConvention); + } + } else { + abc = getWorkPlaneMachineABC(_section, true); + } + + if (_setWorkPlane) { + if (_section.isMultiAxis() || isPolarModeActive()) { // 4-5x simultaneous operations + cancelWorkPlane(); + if (_section.isOptimizedForMachine()) { + positionABC(abc, true); + } else { + setCurrentDirection(abc); + } + } else { // 3x and/or 3+2x operations + setWorkPlane(abc); + } + } + } else { + var remaining = _section.workPlane; + if (!isSameDirection(remaining.forward, new Vector(0, 0, 1))) { + error(localize("Tool orientation is not supported.")); + return abc; + } + setRotation(remaining); + } + tcp.isSupportedByOperation = isTCPSupportedByOperation(_section); + return abc; +} + +function isTCPSupportedByOperation(_section) { + var _tcp = _section.getOptimizedTCPMode() == OPTIMIZE_NONE; + if (!_section.isMultiAxis() && (settings.workPlaneMethod.useTiltedWorkplane || + isSameDirection(machineConfiguration.getSpindleAxis(), getForwardDirection(_section)) || + settings.workPlaneMethod.optimizeType == OPTIMIZE_HEADS || + settings.workPlaneMethod.optimizeType == OPTIMIZE_TABLES || + settings.workPlaneMethod.optimizeType == OPTIMIZE_BOTH)) { + _tcp = false; + } + return _tcp; +} +// <<<<< INCLUDED FROM include_files/defineWorkPlane.cpi +// >>>>> INCLUDED FROM include_files/getWorkPlaneMachineABC.cpi +validate(settings.machineAngles, "Setting 'machineAngles' is required but not defined."); +function getWorkPlaneMachineABC(_section, rotate) { + var currentABC = isFirstSection() ? new Vector(0, 0, 0) : getCurrentABC(); + var abc = _section.getABCByPreference(machineConfiguration, _section.workPlane, currentABC, settings.machineAngles.controllingAxis, settings.machineAngles.type, settings.machineAngles.options); + if (!isSameDirection(machineConfiguration.getDirection(abc), _section.workPlane.forward)) { + error(localize("Orientation not supported.")); + } + if (rotate) { + if (settings.workPlaneMethod.optimizeType == undefined || settings.workPlaneMethod.useTiltedWorkplane) { // legacy + var useTCP = false; + var R = machineConfiguration.getRemainingOrientation(abc, _section.workPlane); + setRotation(useTCP ? _section.workPlane : R); + } else { + if (!_section.isOptimizedForMachine()) { + machineConfiguration.setToolLength(compensateToolLength ? _section.getTool().overallLength : 0); // define the tool length for head adjustments + _section.optimize3DPositionsByMachine(machineConfiguration, abc, settings.workPlaneMethod.optimizeType); + } + } + } + return abc; +} +// <<<<< INCLUDED FROM include_files/getWorkPlaneMachineABC.cpi +// >>>>> INCLUDED FROM include_files/positionABC.cpi +function positionABC(abc, force) { + if (!machineConfiguration.isMultiAxisConfiguration()) { + error("Function 'positionABC' can only be used with multi-axis machine configurations."); + } + if (typeof unwindABC == "function") { + unwindABC(abc); + } + if (force) { + forceABC(); + } + var a = aOutput.format(abc.x); + var b = bOutput.format(abc.y); + var c = cOutput.format(abc.z); + if (a || b || c) { + writeRetract(Z); + if (getSetting("retract.homeXY.onIndexing", false)) { + writeRetract(settings.retract.homeXY.onIndexing); + } + onCommand(COMMAND_UNLOCK_MULTI_AXIS); + gMotionModal.reset(); + writeBlock(gMotionModal.format(0), a, b, c); + + if (getCurrentSectionId() != -1) { + setCurrentABC(abc); // required for machine simulation + } + machineSimulation({a:abc.x, b:abc.y, c:abc.z, coordinates:MACHINE}); + } +} +// <<<<< INCLUDED FROM include_files/positionABC.cpi +// >>>>> INCLUDED FROM include_files/writeWCS.cpi +function writeWCS(section, wcsIsRequired) { + if (section.workOffset != currentWorkOffset) { + if (getSetting("workPlaneMethod.cancelTiltFirst", false) && wcsIsRequired) { + cancelWorkPlane(); + } + if (typeof forceWorkPlane == "function" && wcsIsRequired) { + forceWorkPlane(); + } + writeStartBlocks(wcsIsRequired, function () { + writeBlock(section.wcs); + }); + currentWorkOffset = section.workOffset; + } +} +// <<<<< INCLUDED FROM include_files/writeWCS.cpi +// >>>>> INCLUDED FROM include_files/writeToolCall.cpi +function writeToolCall(tool, insertToolCall) { + if (!isFirstSection()) { + writeStartBlocks(!getProperty("safeStartAllOperations") && insertToolCall, function () { + writeRetract(Z); // write optional Z retract before tool change if safeStartAllOperations is enabled + }); + } + writeStartBlocks(insertToolCall, function () { + writeRetract(Z); + if (getSetting("retract.homeXY.onToolChange", false)) { + writeRetract(settings.retract.homeXY.onToolChange); + } + if (!isFirstSection() && insertToolCall) { + if (typeof forceWorkPlane == "function") { + forceWorkPlane(); + } + onCommand(COMMAND_COOLANT_OFF); // turn off coolant on tool change + if (typeof disableLengthCompensation == "function") { + disableLengthCompensation(false); + } + } + + if (tool.manualToolChange) { + onCommand(COMMAND_LOAD_TOOL); //KC calls tool change to swap out old tool for manual tool pocket + onCommand(COMMAND_STOP); + //writeComment("MANUAL TOOL CHANGE TO T" + toolFormat.format(tool.number)); + writeComment("Flip to Manual, Swap tool to T" + toolFormat.format(tool.number)); + writeComment("H" + tool.lengthOffset + " - " + tool.description); + writeComment(tool.bodyLength + "mm Stick out below " + tool.holderDescription + " holder"); + machineSimulation({x:toPreciseUnit(getProperty("TCposX"), MM), y:toPreciseUnit( getProperty("TCposY") , MM), coordinates:MACHINE, mode:TOOLCHANGE}); // move machineSimulation to a tool change position + } else { + if (!isFirstSection() && getProperty("optionalStop") && insertToolCall) { + onCommand(COMMAND_OPTIONAL_STOP); + } + onCommand(COMMAND_LOAD_TOOL); + } + }); + if (typeof forceModals == "function" && (insertToolCall || getProperty("safeStartAllOperations"))) { + forceModals(); + } +} +// <<<<< INCLUDED FROM include_files/writeToolCall.cpi +// >>>>> INCLUDED FROM include_files/startSpindle.cpi + +function startSpindle(tool, insertToolCall) { + if (tool.type != TOOL_PROBE) { + var spindleSpeedIsRequired = insertToolCall || forceSpindleSpeed || isFirstSection() || + rpmFormat.areDifferent(spindleSpeed, sOutput.getCurrent()) || + (tool.clockwise != getPreviousSection().getTool().clockwise); + + writeStartBlocks(spindleSpeedIsRequired, function () { + if (spindleSpeedIsRequired || operationNeedsSafeStart) { + onCommand(COMMAND_START_SPINDLE); + } + }); + } +} +// <<<<< INCLUDED FROM include_files/startSpindle.cpi +// >>>>> INCLUDED FROM include_files/parametricFeeds.cpi +properties.useParametricFeed = { + title : "Parametric feed", + description: "Specifies that the feedrates should be output using parameters.", + group : "preferences", + type : "boolean", + value : false, + scope : "post" +}; +var activeMovements; +var currentFeedId; +validate(settings.parametricFeeds, "Setting 'parametricFeeds' is required but not defined."); +function initializeParametricFeeds(insertToolCall) { + if (getProperty("useParametricFeed") && getParameter("operation-strategy") != "drill" && !currentSection.hasAnyCycle()) { + if (!insertToolCall && activeMovements && (getCurrentSectionId() > 0) && + ((getPreviousSection().getPatternId() == currentSection.getPatternId()) && (currentSection.getPatternId() != 0))) { + return; // use the current feeds + } + } else { + activeMovements = undefined; + return; + } + + activeMovements = new Array(); + var movements = currentSection.getMovements(); + + var id = 0; + var activeFeeds = new Array(); + if (hasParameter("operation:tool_feedCutting")) { + if (movements & ((1 << MOVEMENT_CUTTING) | (1 << MOVEMENT_LINK_TRANSITION) | (1 << MOVEMENT_EXTENDED))) { + var feedContext = new FeedContext(id, localize("Cutting"), getParameter("operation:tool_feedCutting")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_CUTTING] = feedContext; + if (!hasParameter("operation:tool_feedTransition")) { + activeMovements[MOVEMENT_LINK_TRANSITION] = feedContext; + } + activeMovements[MOVEMENT_EXTENDED] = feedContext; + } + ++id; + if (movements & (1 << MOVEMENT_PREDRILL)) { + feedContext = new FeedContext(id, localize("Predrilling"), getParameter("operation:tool_feedCutting")); + activeMovements[MOVEMENT_PREDRILL] = feedContext; + activeFeeds.push(feedContext); + } + ++id; + } + if (hasParameter("operation:finishFeedrate")) { + if (movements & (1 << MOVEMENT_FINISH_CUTTING)) { + var feedContext = new FeedContext(id, localize("Finish"), getParameter("operation:finishFeedrate")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_FINISH_CUTTING] = feedContext; + } + ++id; + } else if (hasParameter("operation:tool_feedCutting")) { + if (movements & (1 << MOVEMENT_FINISH_CUTTING)) { + var feedContext = new FeedContext(id, localize("Finish"), getParameter("operation:tool_feedCutting")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_FINISH_CUTTING] = feedContext; + } + ++id; + } + if (hasParameter("operation:tool_feedEntry")) { + if (movements & (1 << MOVEMENT_LEAD_IN)) { + var feedContext = new FeedContext(id, localize("Entry"), getParameter("operation:tool_feedEntry")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_LEAD_IN] = feedContext; + } + ++id; + } + if (hasParameter("operation:tool_feedExit")) { + if (movements & (1 << MOVEMENT_LEAD_OUT)) { + var feedContext = new FeedContext(id, localize("Exit"), getParameter("operation:tool_feedExit")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_LEAD_OUT] = feedContext; + } + ++id; + } + if (hasParameter("operation:noEngagementFeedrate")) { + if (movements & (1 << MOVEMENT_LINK_DIRECT)) { + var feedContext = new FeedContext(id, localize("Direct"), getParameter("operation:noEngagementFeedrate")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_LINK_DIRECT] = feedContext; + } + ++id; + } else if (hasParameter("operation:tool_feedCutting") && + hasParameter("operation:tool_feedEntry") && + hasParameter("operation:tool_feedExit")) { + if (movements & (1 << MOVEMENT_LINK_DIRECT)) { + var feedContext = new FeedContext(id, localize("Direct"), Math.max(getParameter("operation:tool_feedCutting"), getParameter("operation:tool_feedEntry"), getParameter("operation:tool_feedExit"))); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_LINK_DIRECT] = feedContext; + } + ++id; + } + if (hasParameter("operation:reducedFeedrate")) { + if (movements & (1 << MOVEMENT_REDUCED)) { + var feedContext = new FeedContext(id, localize("Reduced"), getParameter("operation:reducedFeedrate")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_REDUCED] = feedContext; + } + ++id; + } + if (hasParameter("operation:tool_feedRamp")) { + if (movements & ((1 << MOVEMENT_RAMP) | (1 << MOVEMENT_RAMP_HELIX) | (1 << MOVEMENT_RAMP_PROFILE) | (1 << MOVEMENT_RAMP_ZIG_ZAG))) { + var feedContext = new FeedContext(id, localize("Ramping"), getParameter("operation:tool_feedRamp")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_RAMP] = feedContext; + activeMovements[MOVEMENT_RAMP_HELIX] = feedContext; + activeMovements[MOVEMENT_RAMP_PROFILE] = feedContext; + activeMovements[MOVEMENT_RAMP_ZIG_ZAG] = feedContext; + } + ++id; + } + if (hasParameter("operation:tool_feedPlunge")) { + if (movements & (1 << MOVEMENT_PLUNGE)) { + var feedContext = new FeedContext(id, localize("Plunge"), getParameter("operation:tool_feedPlunge")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_PLUNGE] = feedContext; + } + ++id; + } + if (true) { // high feed + if ((movements & (1 << MOVEMENT_HIGH_FEED)) || (highFeedMapping != HIGH_FEED_NO_MAPPING)) { + var feed; + if (hasParameter("operation:highFeedrateMode") && getParameter("operation:highFeedrateMode") != "disabled") { + feed = getParameter("operation:highFeedrate"); + } else { + feed = this.highFeedrate; + } + var feedContext = new FeedContext(id, localize("High Feed"), feed); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_HIGH_FEED] = feedContext; + activeMovements[MOVEMENT_RAPID] = feedContext; + } + ++id; + } + if (hasParameter("operation:tool_feedTransition")) { + if (movements & (1 << MOVEMENT_LINK_TRANSITION)) { + var feedContext = new FeedContext(id, localize("Transition"), getParameter("operation:tool_feedTransition")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_LINK_TRANSITION] = feedContext; + } + ++id; + } + + for (var i = 0; i < activeFeeds.length; ++i) { + var feedContext = activeFeeds[i]; + var feedDescription = typeof formatComment == "function" ? formatComment(feedContext.description) : feedContext.description; + writeBlock(settings.parametricFeeds.feedAssignmentVariable + (settings.parametricFeeds.firstFeedParameter + feedContext.id) + "=" + feedFormat.format(feedContext.feed) + SP + feedDescription); + } +} + +function FeedContext(id, description, feed) { + this.id = id; + this.description = description; + this.feed = feed; +} +// <<<<< INCLUDED FROM include_files/parametricFeeds.cpi +// >>>>> INCLUDED FROM include_files/coolant.cpi +var currentCoolantMode = COOLANT_OFF; +var coolantOff = undefined; +var isOptionalCoolant = false; +var forceCoolant = false; + +function setCoolant(coolant) { + var coolantCodes = getCoolantCodes(coolant); + if (Array.isArray(coolantCodes)) { + writeStartBlocks(!isOptionalCoolant, function () { + if (settings.coolant.singleLineCoolant) { + writeBlock(coolantCodes.join(getWordSeparator())); + } else { + for (var c in coolantCodes) { + writeBlock(coolantCodes[c]); + } + } + }); + return undefined; + } + return coolantCodes; +} + +function getCoolantCodes(coolant, format) { + if (!getProperty("useCoolant", true)) { + return undefined; // coolant output is disabled by property if it exists + } + isOptionalCoolant = false; + if (typeof operationNeedsSafeStart == "undefined") { + operationNeedsSafeStart = false; + } + var multipleCoolantBlocks = new Array(); // create a formatted array to be passed into the outputted line + var coolants = settings.coolant.coolants; + if (!coolants) { + error(localize("Coolants have not been defined.")); + } + if (tool.type && tool.type == TOOL_PROBE) { // avoid coolant output for probing + coolant = COOLANT_OFF; + } + if (coolant == currentCoolantMode) { + if (operationNeedsSafeStart && coolant != COOLANT_OFF) { + isOptionalCoolant = true; + } else if (!forceCoolant || coolant == COOLANT_OFF) { + return undefined; // coolant is already active + } + } + if ((coolant != COOLANT_OFF) && (currentCoolantMode != COOLANT_OFF) && (coolantOff != undefined) && !forceCoolant && !isOptionalCoolant) { + if (Array.isArray(coolantOff)) { + for (var i in coolantOff) { + multipleCoolantBlocks.push(coolantOff[i]); + } + } else { + multipleCoolantBlocks.push(coolantOff); + } + } + forceCoolant = false; + + var m; + var coolantCodes = {}; + for (var c in coolants) { // find required coolant codes into the coolants array + if (coolants[c].id == coolant) { + coolantCodes.on = coolants[c].on; + if (coolants[c].off != undefined) { + coolantCodes.off = coolants[c].off; + break; + } else { + for (var i in coolants) { + if (coolants[i].id == COOLANT_OFF) { + coolantCodes.off = coolants[i].off; + break; + } + } + } + } + } + if (coolant == COOLANT_OFF) { + m = !coolantOff ? coolantCodes.off : coolantOff; // use the default coolant off command when an 'off' value is not specified + } else { + coolantOff = coolantCodes.off; + m = coolantCodes.on; + } + + if (!m) { + onUnsupportedCoolant(coolant); + m = 9; + } else { + if (Array.isArray(m)) { + for (var i in m) { + multipleCoolantBlocks.push(m[i]); + } + } else { + multipleCoolantBlocks.push(m); + } + currentCoolantMode = coolant; + for (var i in multipleCoolantBlocks) { + if (typeof multipleCoolantBlocks[i] == "number") { + multipleCoolantBlocks[i] = mFormat.format(multipleCoolantBlocks[i]); + } + } + if (format == undefined || format) { + return multipleCoolantBlocks; // return the single formatted coolant value + } else { + return m; // return unformatted coolant value + } + } + return undefined; +} +// <<<<< INCLUDED FROM include_files/coolant.cpi +// >>>>> INCLUDED FROM include_files/smoothing.cpi +// collected state below, do not edit +validate(settings.smoothing, "Setting 'smoothing' is required but not defined."); +var smoothing = { + cancel : false, // cancel tool length prior to update smoothing for this operation + isActive : false, // the current state of smoothing + isAllowed : false, // smoothing is allowed for this operation + isDifferent: false, // tells if smoothing levels/tolerances/both are different between operations + level : -1, // the active level of smoothing + tolerance : -1, // the current operation tolerance + force : false // smoothing needs to be forced out in this operation +}; + +function initializeSmoothing() { + var smoothingSettings = settings.smoothing; + var previousLevel = smoothing.level; + var previousTolerance = xyzFormat.getResultingValue(smoothing.tolerance); + + // format threshold parameters + var thresholdRoughing = xyzFormat.getResultingValue(smoothingSettings.thresholdRoughing); + var thresholdSemiFinishing = xyzFormat.getResultingValue(smoothingSettings.thresholdSemiFinishing); + var thresholdFinishing = xyzFormat.getResultingValue(smoothingSettings.thresholdFinishing); + + // determine new smoothing levels and tolerances + smoothing.level = parseInt(getProperty("useSmoothing"), 10); + smoothing.level = isNaN(smoothing.level) ? -1 : smoothing.level; + smoothing.tolerance = xyzFormat.getResultingValue(Math.max(getParameter("operation:tolerance", thresholdFinishing), 0)); + + if (smoothing.level == 9999) { + if (smoothingSettings.autoLevelCriteria == "stock") { // determine auto smoothing level based on stockToLeave + var stockToLeave = xyzFormat.getResultingValue(getParameter("operation:stockToLeave", 0)); + var verticalStockToLeave = xyzFormat.getResultingValue(getParameter("operation:verticalStockToLeave", 0)); + if (((stockToLeave >= thresholdRoughing) && (verticalStockToLeave >= thresholdRoughing)) || getParameter("operation:strategy", "") == "face") { + smoothing.level = smoothingSettings.roughing; // set roughing level + } else { + if (((stockToLeave >= thresholdSemiFinishing) && (stockToLeave < thresholdRoughing)) && + ((verticalStockToLeave >= thresholdSemiFinishing) && (verticalStockToLeave < thresholdRoughing))) { + smoothing.level = smoothingSettings.semi; // set semi level + } else if (((stockToLeave >= thresholdFinishing) && (stockToLeave < thresholdSemiFinishing)) && + ((verticalStockToLeave >= thresholdFinishing) && (verticalStockToLeave < thresholdSemiFinishing))) { + smoothing.level = smoothingSettings.semifinishing; // set semi-finishing level + } else { + smoothing.level = smoothingSettings.finishing; // set finishing level + } + } + } else { // detemine auto smoothing level based on operation tolerance instead of stockToLeave + if (smoothing.tolerance >= thresholdRoughing || getParameter("operation:strategy", "") == "face") { + smoothing.level = smoothingSettings.roughing; // set roughing level + } else { + if (((smoothing.tolerance >= thresholdSemiFinishing) && (smoothing.tolerance < thresholdRoughing))) { + smoothing.level = smoothingSettings.semi; // set semi level + } else if (((smoothing.tolerance >= thresholdFinishing) && (smoothing.tolerance < thresholdSemiFinishing))) { + smoothing.level = smoothingSettings.semifinishing; // set semi-finishing level + } else { + smoothing.level = smoothingSettings.finishing; // set finishing level + } + } + } + } + + if (smoothing.level == -1) { // useSmoothing is disabled + smoothing.isAllowed = false; + } else { // do not output smoothing for the following operations + smoothing.isAllowed = !(currentSection.getTool().type == TOOL_PROBE || isDrillingCycle()); + } + if (!smoothing.isAllowed) { + smoothing.level = -1; + smoothing.tolerance = -1; + } + + switch (smoothingSettings.differenceCriteria) { + case "level": + smoothing.isDifferent = smoothing.level != previousLevel; + break; + case "tolerance": + smoothing.isDifferent = smoothing.tolerance != previousTolerance; + break; + case "both": + smoothing.isDifferent = smoothing.level != previousLevel || smoothing.tolerance != previousTolerance; + break; + default: + error(localize("Unsupported smoothing criteria.")); + return; + } + + // tool length compensation needs to be canceled when smoothing state/level changes + if (smoothingSettings.cancelCompensation) { + smoothing.cancel = !isFirstSection() && smoothing.isDifferent; + } +} +// <<<<< INCLUDED FROM include_files/smoothing.cpi +// >>>>> INCLUDED FROM include_files/writeProgramHeader.cpi +properties.writeMachine = { + title : "Write machine", + description: "Output the machine settings in the header of the program.", + group : "formats", + type : "boolean", + value : true, + scope : "post" +}; +properties.writeTools = { + title : "Write tool list", + description: "Output a tool list in the header of the program.", + group : "formats", + type : "boolean", + value : true, + scope : "post" +}; +function writeProgramHeader() { + writeComment((now.getMonth() + 1) + "-" + now.getDate() + "-" + now.getFullYear() + " " + now.getHours() + ":" + ("0" + now.getMinutes()).slice(-2)); //BJE + // dump machine configuration + var vendor = machineConfiguration.getVendor(); + var model = machineConfiguration.getModel(); + var mDescription = machineConfiguration.getDescription(); + if (getProperty("writeMachine") && (vendor || model || mDescription)) { + writeComment(localize("Machine")); + if (vendor) { + writeComment(" " + localize("vendor") + ": " + vendor); + } + if (model) { + writeComment(" " + localize("model") + ": " + model); + } + if (mDescription) { + writeComment(" " + localize("description") + ": " + mDescription); + } + } + + // dump tool information + if (getProperty("writeTools")) { + if (false) { // set to true to use the post kernel version of the tool list + writeToolTable(TOOL_NUMBER_COL); + } else { + var zRanges = {}; + if (is3D()) { + var numberOfSections = getNumberOfSections(); + for (var i = 0; i < numberOfSections; ++i) { + var section = getSection(i); + var zRange = section.getGlobalZRange(); + var tool = section.getTool(); + if (zRanges[tool.number]) { + zRanges[tool.number].expandToRange(zRange); + } else { + zRanges[tool.number] = zRange; + } + } + } + var tools = getToolTable(); + if (tools.getNumberOfTools() > 0) { + for (var i = 0; i < tools.getNumberOfTools(); ++i) { + var tool = tools.getTool(i); + var comment = (getProperty("toolAsName") ? "\"" + tool.description.toUpperCase() + "\"" : "T" + toolFormat.format(tool.number)) + " " + + "D=" + xyzFormat.format(tool.diameter) + " " + + localize("CR") + "=" + xyzFormat.format(tool.cornerRadius); + if ((tool.taperAngle > 0) && (tool.taperAngle < Math.PI)) { + comment += " " + localize("TAPER") + "=" + taperFormat.format(tool.taperAngle) + localize("deg"); + } + if (zRanges[tool.number]) { + comment += " - " + localize("ZMIN") + "=" + xyzFormat.format(zRanges[tool.number].getMinimum()); + } + comment += " - " + getToolTypeName(tool.type); + writeComment(comment); + } + } + } + } +} +// <<<<< INCLUDED FROM include_files/writeProgramHeader.cpi +// >>>>> INCLUDED FROM include_files/subprograms.cpi +properties.useSubroutines = { + title : "Use subroutines", + description: "Select your desired subroutine option. 'All Operations' creates subroutines per each operation, 'Cycles' creates subroutines for cycle operations on same holes, and 'Patterns' creates subroutines for patterned operations.", + group : "preferences", + type : "enum", + values : [ + {title:"No", id:"none"}, + {title:"All Operations", id:"allOperations"}, + {title:"All Operations & Patterns", id:"allPatterns"}, + {title:"Cycles", id:"cycles"}, + {title:"Operations, Patterns, Cycles", id:"all"}, + {title:"Patterns", id:"patterns"} + ], + value: "none", + scope: "post" +}; +properties.useFilesForSubprograms = { + title : "Use files for subroutines", + description: "If enabled, subroutines will be saved as individual files.", + group : "preferences", + type : "boolean", + value : false, + scope : "post" +}; + +var NONE = 0x0000; +var PATTERNS = 0x0001; +var CYCLES = 0x0010; +var ALLOPERATIONS = 0x0100; +var subroutineBitmasks = { + none : NONE, + patterns : PATTERNS, + cycles : CYCLES, + allOperations: ALLOPERATIONS, + allPatterns : PATTERNS + ALLOPERATIONS, + all : PATTERNS + CYCLES + ALLOPERATIONS +}; + +var SUB_UNKNOWN = 0; +var SUB_PATTERN = 1; +var SUB_CYCLE = 2; + +// collected state below, do not edit +validate(settings.subprograms, "Setting 'subprograms' is required but not defined."); +var subprogramState = { + subprograms : [], // Redirection buffer + newSubprogram : false, // Indicate if the current subprogram is new to definedSubprograms + currentSubprogram : 0, // The current subprogram number + lastSubprogram : undefined, // The last subprogram number + definedSubprograms : new Array(), // A collection of pattern and cycle subprograms + saveShowSequenceNumbers: "", // Used to store pre-condition of "showSequenceNumbers" + cycleSubprogramIsActive: false, // Indicate if it's handling a cycle subprogram + patternIsActive : false, // Indicate if it's handling a pattern subprogram + incrementalSubprogram : false, // Indicate if the current subprogram needs to go incremental mode + incrementalMode : false, // Indicate if incremental mode is on + mainProgramNumber : undefined // The main program number +}; + +function subprogramResolveSetting(_setting, _val, _comment) { + if (typeof _setting == "string") { + return formatWords(_setting.toString().replace("%currentSubprogram", subprogramState.currentSubprogram), (_comment ? formatComment(_comment) : "")); + } else { + return formatWords(_setting + (_val ? settings.subprograms.format.format(_val) : ""), (_comment ? formatComment(_comment) : "")); + } +} + +/** + * Start to redirect buffer to subprogram. + * @param {Vector} initialPosition Initial position + * @param {Vector} abc Machine axis angles + * @param {boolean} incremental If the subprogram needs to go incremental mode + */ +function subprogramStart(initialPosition, abc, incremental) { + var comment = getParameter("operation-comment", ""); + var startBlock; + if (getProperty("useFilesForSubprograms")) { + var _fileName = subprogramState.currentSubprogram; + var subprogramExtension = extension; + if (settings.subprograms.files) { + if (settings.subprograms.files.prefix != undefined) { + _fileName = subprogramResolveSetting(settings.subprograms.files.prefix, subprogramState.currentSubprogram); + } + if (settings.subprograms.files.extension) { + subprogramExtension = settings.subprograms.files.extension; + } + } + var path = FileSystem.getCombinedPath(FileSystem.getFolderPath(getOutputPath()), _fileName + "." + subprogramExtension); + redirectToFile(path); + startBlock = subprogramResolveSetting(settings.subprograms.startBlock.files, subprogramState.currentSubprogram, comment); + } else { + redirectToBuffer(); + startBlock = subprogramResolveSetting(settings.subprograms.startBlock.embedded, subprogramState.currentSubprogram, comment); + } + writeln(startBlock); + + subprogramState.saveShowSequenceNumbers = getProperty("showSequenceNumbers", undefined); + if (subprogramState.saveShowSequenceNumbers != undefined) { + setProperty("showSequenceNumbers", "false"); + } + if (incremental) { + setAbsIncMode(true, initialPosition, abc); + } + if (typeof gPlaneModal != "undefined" && typeof gMotionModal != "undefined") { + forceModals(gPlaneModal, gMotionModal); + } +} + +/** Output the command for calling a subprogram by its subprogram number. */ +function subprogramCall() { + var callBlock; + if (getProperty("useFilesForSubprograms")) { + callBlock = subprogramResolveSetting(settings.subprograms.callBlock.files, subprogramState.currentSubprogram); + } else { + callBlock = subprogramResolveSetting(settings.subprograms.callBlock.embedded, subprogramState.currentSubprogram); + } + writeBlock(callBlock); // call subprogram +} + +/** End of subprogram and close redirection. */ +function subprogramEnd() { + if (isRedirecting()) { + if (subprogramState.newSubprogram) { + var finalPosition = getFramePosition(currentSection.getFinalPosition()); + var abc; + if (currentSection.isMultiAxis() && machineConfiguration.isMultiAxisConfiguration()) { + abc = currentSection.getFinalToolAxisABC(); + } else { + abc = getCurrentDirection(); + } + setAbsIncMode(false, finalPosition, abc); + + if (getProperty("useFilesForSubprograms")) { + var endBlockFiles = subprogramResolveSetting(settings.subprograms.endBlock.files); + writeln(endBlockFiles); + } else { + var endBlockEmbedded = subprogramResolveSetting(settings.subprograms.endBlock.embedded); + writeln(endBlockEmbedded); + writeln(""); + subprogramState.subprograms += getRedirectionBuffer(); + } + } + forceAny(); + subprogramState.newSubprogram = false; + subprogramState.cycleSubprogramIsActive = false; + if (subprogramState.saveShowSequenceNumbers != undefined) { + setProperty("showSequenceNumbers", subprogramState.saveShowSequenceNumbers); + } + closeRedirection(); + } +} + +/** Returns true if the spatial vectors are significantly different. */ +function areSpatialVectorsDifferent(_vector1, _vector2) { + return (xyzFormat.getResultingValue(_vector1.x) != xyzFormat.getResultingValue(_vector2.x)) || + (xyzFormat.getResultingValue(_vector1.y) != xyzFormat.getResultingValue(_vector2.y)) || + (xyzFormat.getResultingValue(_vector1.z) != xyzFormat.getResultingValue(_vector2.z)); +} + +/** Returns true if the spatial boxes are a pure translation. */ +function areSpatialBoxesTranslated(_box1, _box2) { + return !areSpatialVectorsDifferent(Vector.diff(_box1[1], _box1[0]), Vector.diff(_box2[1], _box2[0])) && + !areSpatialVectorsDifferent(Vector.diff(_box2[0], _box1[0]), Vector.diff(_box2[1], _box1[1])); +} + +/** Returns true if the spatial boxes are same. */ +function areSpatialBoxesSame(_box1, _box2) { + return !areSpatialVectorsDifferent(_box1[0], _box2[0]) && !areSpatialVectorsDifferent(_box1[1], _box2[1]); +} + +/** + * Search defined pattern subprogram by the given id. + * @param {number} subprogramId Subprogram Id + * @returns {Object} Returns defined subprogram if found, otherwise returns undefined + */ +function getDefinedPatternSubprogram(subprogramId) { + for (var i = 0; i < subprogramState.definedSubprograms.length; ++i) { + if ((SUB_PATTERN == subprogramState.definedSubprograms[i].type) && (subprogramId == subprogramState.definedSubprograms[i].id)) { + return subprogramState.definedSubprograms[i]; + } + } + return undefined; +} + +/** + * Search defined cycle subprogram pattern by the given id, initialPosition, finalPosition. + * @param {number} subprogramId Subprogram Id + * @param {Vector} initialPosition Initial position of the cycle + * @param {Vector} finalPosition Final position of the cycle + * @returns {Object} Returns defined subprogram if found, otherwise returns undefined + */ +function getDefinedCycleSubprogram(subprogramId, initialPosition, finalPosition) { + for (var i = 0; i < subprogramState.definedSubprograms.length; ++i) { + if ((SUB_CYCLE == subprogramState.definedSubprograms[i].type) && (subprogramId == subprogramState.definedSubprograms[i].id) && + !areSpatialVectorsDifferent(initialPosition, subprogramState.definedSubprograms[i].initialPosition) && + !areSpatialVectorsDifferent(finalPosition, subprogramState.definedSubprograms[i].finalPosition)) { + return subprogramState.definedSubprograms[i]; + } + } + return undefined; +} + +/** + * Creates and returns new defined subprogram + * @param {Section} section The section to create subprogram + * @param {number} subprogramId Subprogram Id + * @param {number} subprogramType Subprogram type, can be SUB_UNKNOWN, SUB_PATTERN or SUB_CYCLE + * @param {Vector} initialPosition Initial position + * @param {Vector} finalPosition Final position + * @returns {Object} Returns new defined subprogram + */ +function defineNewSubprogram(section, subprogramId, subprogramType, initialPosition, finalPosition) { + // determine if this is valid for creating a subprogram + isValid = subprogramIsValid(section, subprogramId, subprogramType); + var subprogram = isValid ? subprogram = ++subprogramState.lastSubprogram : undefined; + subprogramState.definedSubprograms.push({ + type : subprogramType, + id : subprogramId, + subProgram : subprogram, + isValid : isValid, + initialPosition: initialPosition, + finalPosition : finalPosition + }); + return subprogramState.definedSubprograms[subprogramState.definedSubprograms.length - 1]; +} + +/** Returns true if the given section is a pattern **/ +function isPatternOperation(section) { + return section.isPatterned && section.isPatterned(); +} + +/** Returns true if the given section is a cycle operation **/ +function isCycleOperation(section, minimumCyclePoints) { + return section.doesStrictCycle && + (section.getNumberOfCycles() == 1) && (section.getNumberOfCyclePoints() >= minimumCyclePoints); +} + +/** Returns true if the subroutine bit flag is enabled **/ +function isSubProgramEnabledFor(subroutine) { + return subroutineBitmasks[getProperty("useSubroutines")] & subroutine; +} + +/** + * Define subprogram based on the property "useSubroutines" + * @param {Vector} _initialPosition Initial position + * @param {Vector} _abc Machine axis angles + */ +function subprogramDefine(_initialPosition, _abc) { + if (isSubProgramEnabledFor(NONE)) { + // Return early + return; + } + + if (subprogramState.lastSubprogram == undefined) { // initialize first subprogram number + if (settings.subprograms.initialSubprogramNumber == undefined) { + try { + subprogramState.lastSubprogram = getAsInt(programName); + subprogramState.mainProgramNumber = subprogramState.lastSubprogram; // mainProgramNumber must be a number + } catch (e) { + error(localize("Program name must be a number when using subprograms.")); + return; + } + } else { + subprogramState.lastSubprogram = settings.subprograms.initialSubprogramNumber - 1; + // if programName is a string set mainProgramNumber to undefined, if programName is a number set mainProgramNumber to programName + subprogramState.mainProgramNumber = (!isNaN(programName) && !isNaN(parseInt(programName, 10))) ? getAsInt(programName) : undefined; + } + } + + // convert patterns into subprograms + subprogramState.patternIsActive = false; + if (isSubProgramEnabledFor(PATTERNS) && isPatternOperation(currentSection)) { + var subprogramId = currentSection.getPatternId(); + var subprogramType = SUB_PATTERN; + var subprogramDefinition = getDefinedPatternSubprogram(subprogramId); + + subprogramState.newSubprogram = !subprogramDefinition; + if (subprogramState.newSubprogram) { + subprogramDefinition = defineNewSubprogram(currentSection, subprogramId, subprogramType, _initialPosition, _initialPosition); + } + + subprogramState.currentSubprogram = subprogramDefinition.subProgram; + if (subprogramDefinition.isValid) { + // make sure Z-position is output prior to subprogram call + var z = zOutput.format(_initialPosition.z); + if (!state.retractedZ && z) { + validate(!validateLengthCompensation || state.lengthCompensationActive, "Tool length compensation is not active."); // make sure that length compensation is enabled + var block = ""; + if (typeof gAbsIncModal != "undefined") { + block += gAbsIncModal.format(90); + } + if (typeof gPlaneModal != "undefined") { + block += gPlaneModal.format(17); + } + writeBlock(block); + zOutput.reset(); + invokeOnRapid(xOutput.getCurrent(), yOutput.getCurrent(), _initialPosition.z); + } + + // call subprogram + subprogramCall(); + subprogramState.patternIsActive = true; + + if (subprogramState.newSubprogram) { + subprogramStart(_initialPosition, _abc, subprogramState.incrementalSubprogram); + } else { + skipRemainingSection(); + setCurrentPosition(getFramePosition(currentSection.getFinalPosition())); + } + } + } + + // Patterns are not used, check other cases + if (!subprogramState.patternIsActive) { + // Output cycle operation as subprogram + if (isSubProgramEnabledFor(CYCLES) && isCycleOperation(currentSection, settings.subprograms.minimumCyclePoints)) { + var finalPosition = getFramePosition(currentSection.getFinalPosition()); + var subprogramId = currentSection.getNumberOfCyclePoints(); + var subprogramType = SUB_CYCLE; + var subprogramDefinition = getDefinedCycleSubprogram(subprogramId, _initialPosition, finalPosition); + subprogramState.newSubprogram = !subprogramDefinition; + if (subprogramState.newSubprogram) { + subprogramDefinition = defineNewSubprogram(currentSection, subprogramId, subprogramType, _initialPosition, finalPosition); + } + subprogramState.currentSubprogram = subprogramDefinition.subProgram; + subprogramState.cycleSubprogramIsActive = subprogramDefinition.isValid; + } + + // Neither patterns and cycles are used, check other operations + if (!subprogramState.cycleSubprogramIsActive && isSubProgramEnabledFor(ALLOPERATIONS)) { + // Output all operations as subprograms + subprogramState.currentSubprogram = ++subprogramState.lastSubprogram; + if (subprogramState.mainProgramNumber != undefined && (subprogramState.currentSubprogram == subprogramState.mainProgramNumber)) { + subprogramState.currentSubprogram = ++subprogramState.lastSubprogram; // avoid using main program number for current subprogram + } + subprogramCall(); + subprogramState.newSubprogram = true; + subprogramStart(_initialPosition, _abc, false); + } + } +} + +/** + * Determine if this is valid for creating a subprogram + * @param {Section} section The section to create subprogram + * @param {number} subprogramId Subprogram Id + * @param {number} subprogramType Subprogram type, can be SUB_UNKNOWN, SUB_PATTERN or SUB_CYCLE + * @returns {boolean} If this is valid for creating a subprogram + */ +function subprogramIsValid(_section, subprogramId, subprogramType) { + var sectionId = _section.getId(); + var numberOfSections = getNumberOfSections(); + var validSubprogram = subprogramType != SUB_CYCLE; + + var masterPosition = new Array(); + masterPosition[0] = getFramePosition(_section.getInitialPosition()); + masterPosition[1] = getFramePosition(_section.getFinalPosition()); + var tempBox = _section.getBoundingBox(); + var masterBox = new Array(); + masterBox[0] = getFramePosition(tempBox[0]); + masterBox[1] = getFramePosition(tempBox[1]); + + var rotation = getRotation(); + var translation = getTranslation(); + subprogramState.incrementalSubprogram = undefined; + + for (var i = 0; i < numberOfSections; ++i) { + var section = getSection(i); + if (section.getId() != sectionId) { + defineWorkPlane(section, false); + + // check for valid pattern + if (subprogramType == SUB_PATTERN) { + if (section.getPatternId() == subprogramId) { + var patternPosition = new Array(); + patternPosition[0] = getFramePosition(section.getInitialPosition()); + patternPosition[1] = getFramePosition(section.getFinalPosition()); + tempBox = section.getBoundingBox(); + var patternBox = new Array(); + patternBox[0] = getFramePosition(tempBox[0]); + patternBox[1] = getFramePosition(tempBox[1]); + + if (areSpatialBoxesSame(masterPosition, patternPosition) && areSpatialBoxesSame(masterBox, patternBox) && !section.isMultiAxis()) { + subprogramState.incrementalSubprogram = subprogramState.incrementalSubprogram ? subprogramState.incrementalSubprogram : false; + } else if (!areSpatialBoxesTranslated(masterPosition, patternPosition) || !areSpatialBoxesTranslated(masterBox, patternBox)) { + validSubprogram = false; + break; + } else { + subprogramState.incrementalSubprogram = true; + } + } + + // check for valid cycle operation + } else if (subprogramType == SUB_CYCLE) { + if ((section.getNumberOfCyclePoints() == subprogramId) && (section.getNumberOfCycles() == 1)) { + var patternInitial = getFramePosition(section.getInitialPosition()); + var patternFinal = getFramePosition(section.getFinalPosition()); + if (!areSpatialVectorsDifferent(patternInitial, masterPosition[0]) && !areSpatialVectorsDifferent(patternFinal, masterPosition[1])) { + validSubprogram = true; + break; + } + } + } + } + } + setRotation(rotation); + setTranslation(translation); + return (validSubprogram); +} + +/** + * Sets xyz and abc output formats to incremental or absolute type + * @param {boolean} incremental true: Sets incremental mode, false: Sets absolute mode + * @param {Vector} xyz Linear axis values for formating + * @param {Vector} abc Rotary axis values for formating +*/ +function setAbsIncMode(incremental, xyz, abc) { + var outputFormats = [xOutput, yOutput, zOutput, aOutput, bOutput, cOutput]; + for (var i = 0; i < outputFormats.length; ++i) { + outputFormats[i].setType(incremental ? TYPE_INCREMENTAL : TYPE_ABSOLUTE); + if (typeof incPrefix != "undefined" && typeof absPrefix != "undefined") { + outputFormats[i].setPrefix(incremental ? incPrefix[i] : absPrefix[i]); + } + if (i <= 2) { // xyz + outputFormats[i].setCurrent(xyz.getCoordinate(i)); + } else { // abc + outputFormats[i].setCurrent(abc.getCoordinate(i - 3)); + } + } + subprogramState.incrementalMode = incremental; + if (typeof gAbsIncModal != "undefined") { + if (incremental) { + forceModals(gAbsIncModal); + } + writeBlock(gAbsIncModal.format(incremental ? 91 : 90)); + } +} + +function setCyclePosition(_position) { + var _spindleAxis; + if (typeof gPlaneModal != "undefined") { + _spindleAxis = gPlaneModal.getCurrent() == 17 ? Z : (gPlaneModal.getCurrent() == 18 ? Y : X); + } else { + var _spindleDirection = machineConfiguration.getSpindleAxis().getAbsolute(); + _spindleAxis = isSameDirection(_spindleDirection, new Vector(0, 0, 1)) ? Z : isSameDirection(_spindleDirection, new Vector(0, 1, 0)) ? Y : X; + } + switch (_spindleAxis) { + case Z: + zOutput.format(_position); + break; + case Y: + yOutput.format(_position); + break; + case X: + xOutput.format(_position); + break; + } +} + +/** + * Place cycle operation in subprogram + * @param {Vector} initialPosition Initial position + * @param {Vector} abc Machine axis angles + * @param {boolean} incremental If the subprogram needs to go incremental mode + */ +function handleCycleSubprogram(initialPosition, abc, incremental) { + subprogramState.cycleSubprogramIsActive &= !(cycleExpanded || isProbeOperation()); + if (subprogramState.cycleSubprogramIsActive) { + // call subprogram + subprogramCall(); + subprogramStart(initialPosition, abc, incremental); + } +} + +function writeSubprograms() { + if (subprogramState.subprograms.length > 0) { + writeln(""); + write(subprogramState.subprograms); + } +} +// <<<<< INCLUDED FROM include_files/subprograms.cpi + +// >>>>> INCLUDED FROM include_files/onRapid_fanuc.cpi +function onRapid(_x, _y, _z) { + var x = xOutput.format(_x); + var y = yOutput.format(_y); + var z = zOutput.format(_z); + if (x || y || z) { + if (pendingRadiusCompensation >= 0) { + error(localize("Radius compensation mode cannot be changed at rapid traversal.")); + return; + } + writeBlock(gMotionModal.format(0), x, y, z); + forceFeed(); + } +} +// <<<<< INCLUDED FROM include_files/onRapid_fanuc.cpi +// >>>>> INCLUDED FROM include_files/onLinear_fanuc.cpi +function onLinear(_x, _y, _z, feed) { + if (pendingRadiusCompensation >= 0) { + xOutput.reset(); + yOutput.reset(); + } + var x = xOutput.format(_x); + var y = yOutput.format(_y); + var z = zOutput.format(_z); + var f = getFeed(feed); + if (x || y || z) { + if (pendingRadiusCompensation >= 0) { + pendingRadiusCompensation = -1; + var d = getSetting("outputToolDiameterOffset", true) ? diameterOffsetFormat.format(tool.diameterOffset) : ""; + writeBlock(gPlaneModal.format(17)); + switch (radiusCompensation) { + case RADIUS_COMPENSATION_LEFT: + writeBlock(gMotionModal.format(1), gFormat.format(41), x, y, z, d, f); + break; + case RADIUS_COMPENSATION_RIGHT: + writeBlock(gMotionModal.format(1), gFormat.format(42), x, y, z, d, f); + break; + default: + writeBlock(gMotionModal.format(1), gFormat.format(40), x, y, z, f); + } + } else { + writeBlock(gMotionModal.format(1), x, y, z, f); + } + } else if (f) { + if (getNextRecord().isMotion()) { // try not to output feed without motion + forceFeed(); // force feed on next line + } else { + writeBlock(gMotionModal.format(1), f); + } + } +} +// <<<<< INCLUDED FROM include_files/onLinear_fanuc.cpi +// >>>>> INCLUDED FROM include_files/onRapid5D_fanuc.cpi +function onRapid5D(_x, _y, _z, _a, _b, _c) { + if (pendingRadiusCompensation >= 0) { + error(localize("Radius compensation mode cannot be changed at rapid traversal.")); + return; + } + if (!currentSection.isOptimizedForMachine()) { + forceXYZ(); + } + var x = xOutput.format(_x); + var y = yOutput.format(_y); + var z = zOutput.format(_z); + var a = currentSection.isOptimizedForMachine() ? aOutput.format(_a) : toolVectorOutputI.format(_a); + var b = currentSection.isOptimizedForMachine() ? bOutput.format(_b) : toolVectorOutputJ.format(_b); + var c = currentSection.isOptimizedForMachine() ? cOutput.format(_c) : toolVectorOutputK.format(_c); + + if (x || y || z || a || b || c) { + writeBlock(gMotionModal.format(0), x, y, z, a, b, c); + forceFeed(); + } +} +// <<<<< INCLUDED FROM include_files/onRapid5D_fanuc.cpi +// >>>>> INCLUDED FROM include_files/onLinear5D_fanuc.cpi +function onLinear5D(_x, _y, _z, _a, _b, _c, feed, feedMode) { + if (pendingRadiusCompensation >= 0) { + error(localize("Radius compensation cannot be activated/deactivated for 5-axis move.")); + return; + } + if (!currentSection.isOptimizedForMachine()) { + forceXYZ(); + } + var x = xOutput.format(_x); + var y = yOutput.format(_y); + var z = zOutput.format(_z); + var a = currentSection.isOptimizedForMachine() ? aOutput.format(_a) : toolVectorOutputI.format(_a); + var b = currentSection.isOptimizedForMachine() ? bOutput.format(_b) : toolVectorOutputJ.format(_b); + var c = currentSection.isOptimizedForMachine() ? cOutput.format(_c) : toolVectorOutputK.format(_c); + if (feedMode == FEED_INVERSE_TIME) { + forceFeed(); + } + var f = feedMode == FEED_INVERSE_TIME ? inverseTimeOutput.format(feed) : getFeed(feed); + var fMode = feedMode == FEED_INVERSE_TIME ? 93 : getProperty("useG95") ? 95 : 94; + + if (x || y || z || a || b || c) { + writeBlock(gFeedModeModal.format(fMode), gMotionModal.format(1), x, y, z, a, b, c, f); + } else if (f) { + if (getNextRecord().isMotion()) { // try not to output feed without motion + forceFeed(); // force feed on next line + } else { + writeBlock(gFeedModeModal.format(fMode), gMotionModal.format(1), f); + } + } +} +// <<<<< INCLUDED FROM include_files/onLinear5D_fanuc.cpi +// >>>>> INCLUDED FROM include_files/onCircular_fanuc.cpi +function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { + if (pendingRadiusCompensation >= 0) { + error(localize("Radius compensation cannot be activated/deactivated for a circular move.")); + return; + } + + var start = getCurrentPosition(); + + if (isFullCircle()) { + if (getProperty("useRadius") || isHelical()) { // radius mode does not support full arcs + linearize(tolerance); + return; + } + switch (getCircularPlane()) { + case PLANE_XY: + writeBlock(gPlaneModal.format(17), gMotionModal.format(clockwise ? 2 : 3), iOutput.format(cx - start.x), jOutput.format(cy - start.y), getFeed(feed)); + break; + case PLANE_ZX: + writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), iOutput.format(cx - start.x), kOutput.format(cz - start.z), getFeed(feed)); + break; + case PLANE_YZ: + writeBlock(gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), jOutput.format(cy - start.y), kOutput.format(cz - start.z), getFeed(feed)); + break; + default: + linearize(tolerance); + } + } else if (!getProperty("useRadius")) { + switch (getCircularPlane()) { + case PLANE_XY: + writeBlock(gPlaneModal.format(17), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x), jOutput.format(cy - start.y), getFeed(feed)); + break; + case PLANE_ZX: + writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x), kOutput.format(cz - start.z), getFeed(feed)); + break; + case PLANE_YZ: + writeBlock(gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), jOutput.format(cy - start.y), kOutput.format(cz - start.z), getFeed(feed)); + break; + default: + if (getProperty("allow3DArcs")) { + // make sure maximumCircularSweep is well below 360deg + // we could use G02.4 or G03.4 - direction is calculated + var ip = getPositionU(0.5); + writeBlock(gMotionModal.format(clockwise ? 2.4 : 3.4), xOutput.format(ip.x), yOutput.format(ip.y), zOutput.format(ip.z), getFeed(feed)); + writeBlock(xOutput.format(x), yOutput.format(y), zOutput.format(z)); + } else { + linearize(tolerance); + } + } + } else { // use radius mode + var r = getCircularRadius(); + if (toDeg(getCircularSweep()) > (180 + 1e-9)) { + r = -r; // allow up to <360 deg arcs + } + switch (getCircularPlane()) { + case PLANE_XY: + writeBlock(gPlaneModal.format(17), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed)); + break; + case PLANE_ZX: + writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed)); + break; + case PLANE_YZ: + writeBlock(gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed)); + break; + default: + if (getProperty("allow3DArcs")) { + // make sure maximumCircularSweep is well below 360deg + // we could use G02.4 or G03.4 - direction is calculated + var ip = getPositionU(0.5); + writeBlock(gMotionModal.format(clockwise ? 2.4 : 3.4), xOutput.format(ip.x), yOutput.format(ip.y), zOutput.format(ip.z), getFeed(feed)); + writeBlock(xOutput.format(x), yOutput.format(y), zOutput.format(z)); + } else { + linearize(tolerance); + } + } + } +} +// <<<<< INCLUDED FROM include_files/onCircular_fanuc.cpi +// >>>>> INCLUDED FROM include_files/workPlaneFunctions_fanuc.cpi +var gRotationModal = createOutputVariable({current : 69, + onchange: function () { + state.twpIsActive = gRotationModal.getCurrent() != 69; + if (typeof probeVariables != "undefined") { + probeVariables.outputRotationCodes = probeVariables.probeAngleMethod == "G68"; + } + }}, gFormat); + +var currentWorkPlaneABC = undefined; +function forceWorkPlane() { + currentWorkPlaneABC = undefined; +} + +function cancelWCSRotation() { + if (typeof gRotationModal != "undefined" && gRotationModal.getCurrent() == 68) { + cancelWorkPlane(true); + } +} + +function cancelWorkPlane(force) { + if (typeof gRotationModal != "undefined") { + if (force) { + gRotationModal.reset(); + } + var command = gRotationModal.format(69); + if (command) { + writeBlock(command); // cancel frame + forceWorkPlane(); + } + } +} + +function setWorkPlane(abc) { + if (!settings.workPlaneMethod.forceMultiAxisIndexing && is3D() && !machineConfiguration.isMultiAxisConfiguration()) { + return; // ignore + } + var workplaneIsRequired = (currentWorkPlaneABC == undefined) || + abcFormat.areDifferent(abc.x, currentWorkPlaneABC.x) || + abcFormat.areDifferent(abc.y, currentWorkPlaneABC.y) || + abcFormat.areDifferent(abc.z, currentWorkPlaneABC.z); + + writeStartBlocks(workplaneIsRequired, function () { + writeRetract(Z); + if (getSetting("retract.homeXY.onIndexing", false)) { + writeRetract(settings.retract.homeXY.onIndexing); + } + if (currentSection.getId() > 0 && (isTCPSupportedByOperation(getSection(currentSection.getId() - 1) || tcp.isSupportedByOperation)) && typeof disableLengthCompensation == "function") { + disableLengthCompensation(); // cancel TCP + } + + if (settings.workPlaneMethod.useTiltedWorkplane) { + onCommand(COMMAND_UNLOCK_MULTI_AXIS); + cancelWorkPlane(); + if (machineConfiguration.isMultiAxisConfiguration()) { + var machineABC = abc.isNonZero() ? (currentSection.isMultiAxis() ? getCurrentDirection() : getWorkPlaneMachineABC(currentSection, false)) : abc; + if (settings.workPlaneMethod.useABCPrepositioning || machineABC.isZero()) { + positionABC(machineABC, false); + } else { + setCurrentABC(machineABC); + } + } + if (abc.isNonZero() || !machineConfiguration.isMultiAxisConfiguration()) { + gRotationModal.reset(); + writeBlock( + gRotationModal.format(68.2), "X" + xyzFormat.format(currentSection.workOrigin.x), "Y" + xyzFormat.format(currentSection.workOrigin.y), "Z" + xyzFormat.format(currentSection.workOrigin.z), + "I" + abcFormat.format(abc.x), "J" + abcFormat.format(abc.y), "K" + abcFormat.format(abc.z) + ); // set frame + writeBlock(gFormat.format(53.1)); // turn machine + machineSimulation({a:getCurrentABC().x, b:getCurrentABC().y, c:getCurrentABC().z, coordinates:MACHINE, eulerAngles:abc}); + } + } else { + positionABC(abc, true); + } + if (!currentSection.isMultiAxis()) { + onCommand(COMMAND_LOCK_MULTI_AXIS); + } + currentWorkPlaneABC = abc; + }); +} +// <<<<< INCLUDED FROM include_files/workPlaneFunctions_fanuc.cpi +// >>>>> INCLUDED FROM include_files/writeRetract_fanuc.cpi +function writeRetract() { + var retract = getRetractParameters.apply(this, arguments); + if (retract && retract.words.length > 0) { + if (typeof cancelWCSRotation == "function" && getSetting("retract.cancelRotationOnRetracting", false)) { // cancel rotation before retracting + cancelWCSRotation(); + } + if (typeof disableLengthCompensation == "function" && getSetting("allowCancelTCPBeforeRetracting", false) && state.tcpIsActive) { + disableLengthCompensation(); // cancel TCP before retracting + } + for (var i in retract.words) { + var words = retract.singleLine ? retract.words : retract.words[i]; + switch (retract.method) { + case "G28": + forceModals(gMotionModal, gAbsIncModal); + writeBlock(gFormat.format(28), gAbsIncModal.format(91), words); + writeBlock(gAbsIncModal.format(90)); + break; + case "G30": + forceModals(gMotionModal, gAbsIncModal); + writeBlock(gFormat.format(30), gAbsIncModal.format(91), words); + writeBlock(gAbsIncModal.format(90)); + break; + case "G53": + forceModals(gMotionModal); + writeBlock(gAbsIncModal.format(90), gFormat.format(53), gMotionModal.format(0), words); + break; + default: + if (typeof writeRetractCustom == "function") { + writeRetractCustom(retract); + } else { + error(subst(localize("Unsupported safe position method '%1'"), retract.method)); + return; + } + } + machineSimulation({ + x : retract.singleLine || words.indexOf("X") != -1 ? retract.positions.x : undefined, + y : retract.singleLine || words.indexOf("Y") != -1 ? retract.positions.y : undefined, + z : retract.singleLine || words.indexOf("Z") != -1 ? retract.positions.z : undefined, + coordinates: MACHINE + }); + if (retract.singleLine) { + break; + } + } + } +} +// <<<<< INCLUDED FROM include_files/writeRetract_fanuc.cpi +// >>>>> INCLUDED FROM include_files/initialPositioning_fanuc.cpi +/** + * Writes the initial positioning procedure for a section to get to the start position of the toolpath. + * @param {Vector} position The initial position to move to + * @param {boolean} isRequired true: Output full positioning, false: Output full positioning in optional state or output simple positioning only + * @param {String} codes1 Allows to add additional code to the first positioning line + * @param {String} codes2 Allows to add additional code to the second positioning line (if applicable) + * @example + var myVar1 = formatWords("T" + tool.number, currentSection.wcs); + var myVar2 = getCoolantCodes(tool.coolant); + writeInitialPositioning(initialPosition, isRequired, myVar1, myVar2); +*/ +function writeInitialPositioning(position, isRequired, codes1, codes2) { + var motionCode = {single:0, multi:0}; + switch (highFeedMapping) { + case HIGH_FEED_MAP_ANY: + motionCode = {single:1, multi:1}; // map all rapid traversals to high feed + break; + case HIGH_FEED_MAP_MULTI: + motionCode = {single:0, multi:1}; // map rapid traversal along more than one axis to high feed + break; + } + var feed = (highFeedMapping != HIGH_FEED_NO_MAPPING) ? getFeed(highFeedrate) : ""; + var hOffset = getSetting("outputToolLengthOffset", true) ? hFormat.format(tool.lengthOffset) : ""; + var additionalCodes = [formatWords(codes1), formatWords(codes2)]; + + forceModals(gMotionModal); + writeStartBlocks(isRequired, function() { + var modalCodes = formatWords(gAbsIncModal.format(90), gPlaneModal.format(17)); + if (typeof disableLengthCompensation == "function") { + disableLengthCompensation(!isRequired); // cancel tool length compensation prior to enabling it, required when switching G43/G43.4 modes + } + + // multi axis prepositioning with TWP + if (currentSection.isMultiAxis() && getSetting("workPlaneMethod.prepositionWithTWP", true) && getSetting("workPlaneMethod.useTiltedWorkplane", false) && + tcp.isSupportedByOperation && getCurrentDirection().isNonZero()) { + var W = machineConfiguration.isMultiAxisConfiguration() ? machineConfiguration.getOrientation(getCurrentDirection()) : + Matrix.getOrientationFromDirection(getCurrentDirection()); + var prePosition = W.getTransposed().multiply(position); + var angles = W.getEuler2(settings.workPlaneMethod.eulerConvention); + setWorkPlane(angles); + writeBlock(modalCodes, gMotionModal.format(motionCode.multi), xOutput.format(prePosition.x), yOutput.format(prePosition.y), feed, additionalCodes[0]); + machineSimulation({x:prePosition.x, y:prePosition.y}); + cancelWorkPlane(); + writeBlock(getOffsetCode(), hOffset, additionalCodes[1]); // omit Z-axis output is desired + forceAny(); // required to output XYZ coordinates in the following line + } else { + if (machineConfiguration.isHeadConfiguration()) { + writeBlock(modalCodes, gMotionModal.format(motionCode.multi), getOffsetCode(), + xOutput.format(position.x), yOutput.format(position.y), zOutput.format(position.z), + hOffset, feed, additionalCodes + ); + machineSimulation({x:position.x, y:position.y, z:position.z}); + } else { + writeBlock(modalCodes, gMotionModal.format(motionCode.multi), xOutput.format(position.x), yOutput.format(position.y), feed, additionalCodes[0]); + machineSimulation({x:position.x, y:position.y}); + writeBlock(gMotionModal.format(motionCode.single), getOffsetCode(), zOutput.format(position.z), hOffset, additionalCodes[1]); + machineSimulation(tcp.isSupportedByOperation ? {x:position.x, y:position.y, z:position.z} : {z:position.z}); + } + } + forceModals(gMotionModal); + if (isRequired) { + additionalCodes = []; // clear additionalCodes buffer + } + }); + + validate(!validateLengthCompensation || state.lengthCompensationActive, "Tool length compensation is not active."); // make sure that lenght compensation is enabled + if (!isRequired) { // simple positioning + var modalCodes = formatWords(gAbsIncModal.format(90), gPlaneModal.format(17)); + if (!state.retractedZ && xyzFormat.getResultingValue(getCurrentPosition().z) < xyzFormat.getResultingValue(position.z)) { + writeBlock(modalCodes, gMotionModal.format(motionCode.single), zOutput.format(position.z), feed); + machineSimulation({z:position.z}); + } + forceXYZ(); + writeBlock(modalCodes, gMotionModal.format(motionCode.multi), xOutput.format(position.x), yOutput.format(position.y), feed, additionalCodes); + machineSimulation({x:position.x, y:position.y}); + } +} + +Matrix.getOrientationFromDirection = function (ijk) { + var forward = ijk; + var unitZ = new Vector(0, 0, 1); + var W; + if (Math.abs(Vector.dot(forward, unitZ)) < 0.5) { + var imX = Vector.cross(forward, unitZ).getNormalized(); + W = new Matrix(imX, Vector.cross(forward, imX), forward); + } else { + var imX = Vector.cross(new Vector(0, 1, 0), forward).getNormalized(); + W = new Matrix(imX, Vector.cross(forward, imX), forward); + } + return W; +}; +// <<<<< INCLUDED FROM include_files/initialPositioning_fanuc.cpi +// >>>>> INCLUDED FROM include_files/getOffsetCode_fanuc.cpi +var toolLengthCompOutput = createOutputVariable({control : CONTROL_FORCE, + onchange: function() { + state.tcpIsActive = toolLengthCompOutput.getCurrent() == 43.4 || toolLengthCompOutput.getCurrent() == 43.5; + state.lengthCompensationActive = toolLengthCompOutput.getCurrent() != 49; + } +}, gFormat); + +function getOffsetCode() { + if (!getSetting("outputToolLengthCompensation", true) && toolLengthCompOutput.isEnabled()) { + state.lengthCompensationActive = true; // always assume that length compensation is active + toolLengthCompOutput.disable(); + } + var offsetCode = 43; + if (tcp.isSupportedByOperation) { + offsetCode = machineConfiguration.isMultiAxisConfiguration() ? 43.4 : 43.5; + } + return toolLengthCompOutput.format(offsetCode); +} +// <<<<< INCLUDED FROM include_files/getOffsetCode_fanuc.cpi +// >>>>> INCLUDED FROM include_files/disableLengthCompensation_fanuc.cpi +function disableLengthCompensation(force) { + if (state.lengthCompensationActive || force) { + if (force) { + toolLengthCompOutput.reset(); + } + if (!getSetting("allowCancelTCPBeforeRetracting", false)) { + validate(state.retractedZ, "Cannot cancel tool length compensation if the machine is not fully retracted."); + } + writeBlock(toolLengthCompOutput.format(49)); + } +} +// <<<<< INCLUDED FROM include_files/disableLengthCompensation_fanuc.cpi +// >>>>> INCLUDED FROM include_files/getProgramNumber_fanuc.cpi +function getProgramNumber() { + if (typeof oFormat != "undefined" && getProperty("o8")) { + oFormat.setMinDigitsLeft(8); + } + var minimumProgramNumber = getSetting("programNumber.min", 1); + var maximumProgramNumber = getSetting("programNumber.max", getProperty("o8") ? 99999999 : 9999); + var reservedProgramNumbers = getSetting("programNumber.reserved", [8000, 9999]); + if (programName) { + var _programNumber; + try { + _programNumber = getAsInt(programName); + } catch (e) { + error(localize("Program name must be a number.")); + } + if (!((_programNumber >= minimumProgramNumber) && (_programNumber <= maximumProgramNumber))) { + error(subst(localize("Program number '%1' is out of range. Please enter a program number between '%2' and '%3'."), _programNumber, minimumProgramNumber, maximumProgramNumber)); + } + if ((_programNumber >= reservedProgramNumbers[0]) && (_programNumber <= reservedProgramNumbers[1])) { + warning(subst(localize("Program number '%1' is potentially reserved by the machine tool builder. Reserved range is '%2' to '%3'."), _programNumber, reservedProgramNumbers[0], reservedProgramNumbers[1])); + } + } else { + error(localize("Program name has not been specified.")); + } + return _programNumber; +} +// <<<<< INCLUDED FROM include_files/getProgramNumber_fanuc.cpi +// >>>>> INCLUDED FROM include_files/drillCycles_fanuc.cpi +function writeDrillCycle(cycle, x, y, z) { + if (!isSameDirection(machineConfiguration.getSpindleAxis(), getForwardDirection(currentSection))) { + expandCyclePoint(x, y, z); + return; + } + if (isFirstCyclePoint()) { + // return to initial Z which is clearance plane and set absolute mode + repositionToCycleClearance(cycle, x, y, z); + + var F = getProperty("useG95") ? (cycle.feedrate / spindleSpeed) : cycle.feedrate; + var P = !cycle.dwell ? 0 : clamp(1, cycle.dwell * 1000, 99999999); // in milliseconds + switch (cycleType) { + case "drilling": + writeBlock( + gRetractModal.format(98), gCycleModal.format(81), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + feedOutput.format(F) + ); + break; + case "counter-boring": + if (P > 0) { + writeBlock( + gRetractModal.format(98), gCycleModal.format(82), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), + feedOutput.format(F) + ); + } else { + writeBlock( + gRetractModal.format(98), gCycleModal.format(81), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + feedOutput.format(F) + ); + } + break; + case "chip-breaking": + if ((cycle.accumulatedDepth < cycle.depth) || (P > 0)) { + expandCyclePoint(x, y, z); + } else { + writeBlock( + gRetractModal.format(98), gCycleModal.format(73), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + peckOutput.format(cycle.incrementalDepth), + feedOutput.format(F) + ); + } + break; + case "deep-drilling": + if (P > 0) { + expandCyclePoint(x, y, z); + } else { + writeBlock( + gRetractModal.format(98), gCycleModal.format(83), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + peckOutput.format(cycle.incrementalDepth), + // conditional(P > 0, "P" + milliFormat.format(P)), + feedOutput.format(F) + ); + } + break; + case "tapping": + if (getProperty("useRigidTapping") != "no") { + writeBlock(mFormat.format(29), sOutput.format(spindleSpeed)); + } + if (getProperty("usePitchForTapping")) { + writeBlock( + gRetractModal.format(98), gFeedModeModal.format(95), gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND) ? 74 : 84), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), + pitchOutput.format(tool.threadPitch) + ); + forceFeed(); + } else { + var tappingFPM = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); + F = (getProperty("useG95") ? tool.getThreadPitch() : tappingFPM); + writeBlock( + gRetractModal.format(98), gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND) ? 74 : 84), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), + feedOutput.format(F) + ); + } + break; + case "left-tapping": + if (getProperty("useRigidTapping") != "no") { + writeBlock(mFormat.format(29), sOutput.format(spindleSpeed)); + } + if (getProperty("usePitchForTapping")) { + writeBlock( + gRetractModal.format(98), gFeedModeModal.format(95), gCycleModal.format(74), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), + pitchOutput.format(tool.threadPitch) + ); + forceFeed(); + } else { + var tappingFPM = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); + F = (getProperty("useG95") ? tool.getThreadPitch() : tappingFPM); + writeBlock( + gRetractModal.format(98), gCycleModal.format(74), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), + feedOutput.format(F) + ); + } + break; + case "right-tapping": + if (getProperty("useRigidTapping") != "no") { + writeBlock(mFormat.format(29), sOutput.format(spindleSpeed)); + } + if (getProperty("usePitchForTapping")) { + writeBlock( + gRetractModal.format(98), gFeedModeModal.format(95), gCycleModal.format(84), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), + pitchOutput.format(tool.threadPitch) + ); + forceFeed(); + } else { + var tappingFPM = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); + F = (getProperty("useG95") ? tool.getThreadPitch() : tappingFPM); + writeBlock( + gRetractModal.format(98), gCycleModal.format(84), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), + feedOutput.format(F) + ); + } + break; + case "tapping-with-chip-breaking": + case "left-tapping-with-chip-breaking": + case "right-tapping-with-chip-breaking": + if (cycle.accumulatedDepth < cycle.depth) { + error(localize("Accumulated pecking depth is not supported for tapping cycles with chip breaking.")); + return; + } else { + if (getProperty("useRigidTapping") != "no") { + writeBlock(mFormat.format(29), sOutput.format(spindleSpeed)); + } + if (getProperty("usePitchForTapping")) { + writeBlock( + gRetractModal.format(98), gFeedModeModal.format(95), gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND ? 74 : 84)), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), + peckOutput.format(cycle.incrementalDepth), + pitchOutput.format(tool.threadPitch) + ); + forceFeed(); + } else { + var tappingFPM = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); + F = (getProperty("useG95") ? tool.getThreadPitch() : tappingFPM); + writeBlock( + gRetractModal.format(98), gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND ? 74 : 84)), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), + peckOutput.format(cycle.incrementalDepth), + feedOutput.format(F) + ); + } + } + break; + case "fine-boring": + writeBlock( + gRetractModal.format(98), gCycleModal.format(76), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), // not optional + "Q" + xyzFormat.format(cycle.shift), + feedOutput.format(F) + ); + break; + case "back-boring": + var dx = (gPlaneModal.getCurrent() == 19) ? cycle.backBoreDistance : 0; + var dy = (gPlaneModal.getCurrent() == 18) ? cycle.backBoreDistance : 0; + var dz = (gPlaneModal.getCurrent() == 17) ? cycle.backBoreDistance : 0; + writeBlock( + gRetractModal.format(98), gCycleModal.format(87), + getCommonCycle(x - dx, y - dy, z - dz, cycle.bottom, cycle.clearance), + "Q" + xyzFormat.format(cycle.shift), + "P" + milliFormat.format(P), // not optional + feedOutput.format(F) + ); + break; + case "reaming": + if (feedFormat.getResultingValue(cycle.feedrate) != feedFormat.getResultingValue(cycle.retractFeedrate)) { + expandCyclePoint(x, y, z); + break; + } + if (P > 0) { + writeBlock( + gRetractModal.format(98), gCycleModal.format(89), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), + feedOutput.format(F) + ); + } else { + writeBlock( + gRetractModal.format(98), gCycleModal.format(85), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + feedOutput.format(F) + ); + } + break; + case "stop-boring": + if (P > 0) { + expandCyclePoint(x, y, z); + } else { + writeBlock( + gRetractModal.format(98), gCycleModal.format(86), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + feedOutput.format(F) + ); + } + break; + case "manual-boring": + writeBlock( + gRetractModal.format(98), gCycleModal.format(88), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), // not optional + feedOutput.format(F) + ); + break; + case "boring": + if (feedFormat.getResultingValue(cycle.feedrate) != feedFormat.getResultingValue(cycle.retractFeedrate)) { + expandCyclePoint(x, y, z); + break; + } + if (P > 0) { + writeBlock( + gRetractModal.format(98), gCycleModal.format(89), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), // not optional + feedOutput.format(F) + ); + } else { + writeBlock( + gRetractModal.format(98), gCycleModal.format(85), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + feedOutput.format(F) + ); + } + break; + default: + expandCyclePoint(x, y, z); + } + if (subprogramsAreSupported()) { + // place cycle operation in subprogram + handleCycleSubprogram(new Vector(x, y, z), new Vector(0, 0, 0), false); + if (subprogramState.incrementalMode) { // set current position to clearance height + setCyclePosition(cycle.clearance); + } + } + } else { + if (cycleExpanded) { + expandCyclePoint(x, y, z); + } else { + if (!xyzFormat.areDifferent(x, xOutput.getCurrent()) && + !xyzFormat.areDifferent(y, yOutput.getCurrent()) && + !xyzFormat.areDifferent(z, zOutput.getCurrent())) { + switch (gPlaneModal.getCurrent()) { + case 17: // XY + xOutput.reset(); // at least one axis is required + break; + case 18: // ZX + zOutput.reset(); // at least one axis is required + break; + case 19: // YZ + yOutput.reset(); // at least one axis is required + break; + } + } + if (subprogramsAreSupported() && subprogramState.incrementalMode) { // set current position to retract height + setCyclePosition(cycle.retract); + } + writeBlock(xOutput.format(x), yOutput.format(y), zOutput.format(z)); + if (subprogramsAreSupported() && subprogramState.incrementalMode) { // set current position to clearance height + setCyclePosition(cycle.clearance); + } + } + } +} + +function getCommonCycle(x, y, z, r, c) { + forceXYZ(); // force xyz on first drill hole of any cycle + if (subprogramsAreSupported() && subprogramState.incrementalMode) { + zOutput.format(c); + return [xOutput.format(x), yOutput.format(y), + "Z" + xyzFormat.format(z - r), + "R" + xyzFormat.format(r - c)]; + } else { + return [xOutput.format(x), yOutput.format(y), + zOutput.format(z), + "R" + xyzFormat.format(r)]; + } +} +// <<<<< INCLUDED FROM include_files/drillCycles_fanuc.cpi +// >>>>> INCLUDED FROM include_files/commonInspectionFunctions_fanuc.cpi +var macroFormat = createFormat({prefix:(typeof inspectionVariables == "undefined" ? "#" : inspectionVariables.localVariablePrefix), decimals:0}); +var macroRoundingFormat = (unit == MM) ? "[53]" : "[44]"; +var isDPRNTopen = false; + +var WARNING_OUTDATED = 0; +var toolpathIdFormat = createFormat({decimals:5, forceDecimal:true}); +var patternInstances = new Array(); +var initializePatternInstances = true; // initialize patternInstances array the first time inspectionGetToolpathId is called +function inspectionGetToolpathId(section) { + if (initializePatternInstances) { + for (var i = 0; i < getNumberOfSections(); ++i) { + var _section = getSection(i); + if (_section.getInternalPatternId) { + var sectionId = _section.getId(); + var patternId = _section.getInternalPatternId(); + var isPatterned = _section.isPatterned && _section.isPatterned(); + var isMirrored = patternId != _section.getPatternId(); + if (isPatterned || isMirrored) { + var isKnownPatternId = false; + for (var j = 0; j < patternInstances.length; j++) { + if (patternId == patternInstances[j].patternId) { + patternInstances[j].patternIndex++; + patternInstances[j].sections.push(sectionId); + isKnownPatternId = true; + break; + } + } + if (!isKnownPatternId) { + patternInstances.push({patternId:patternId, patternIndex:1, sections:[sectionId]}); + } + } + } + } + initializePatternInstances = false; + } + + var _operationId = section.getParameter("autodeskcam:operation-id", ""); + var key = -1; + for (k in patternInstances) { + if (patternInstances[k].patternId == _operationId) { + key = k; + break; + } + } + var _patternId = (key > -1) ? patternInstances[key].sections.indexOf(section.getId()) + 1 : 0; + var _cycleId = cycle && ("cycleID" in cycle) ? cycle.cycleID : section.getParameter("cycleID", 0); + if (isProbeOperation(section) && _cycleId == 0 && getGlobalParameter("product-id").toLowerCase().indexOf("fusion") > -1) { + // we expect the cycleID to be non zero always for macro probing toolpaths, Fusion only + warningOnce(localize("Outdated macro probing operations detected. Please regenerate all macro probing operations."), WARNING_OUTDATED); + } + if (_patternId > 99) { + error(subst(localize("The maximum number of pattern instances is limited to 99" + EOL + + "You need to split operation '%1' into separate pattern groups." + ), section.getParameter("operation-comment", ""))); + } + if (_cycleId > 99) { + error(subst(localize("The maximum number of probing cycles is limited to 99" + EOL + + "You need to split operation '%1' to multiple operations with less than 100 cycles in each operation." + ), section.getParameter("operation-comment", ""))); + } + return toolpathIdFormat.format(_operationId + (_cycleId * 0.01) + (_patternId * 0.0001) + 0.00001); +} + +var localVariableStart = 19; +var localVariable = [ + macroFormat.format(localVariableStart + 1), + macroFormat.format(localVariableStart + 2), + macroFormat.format(localVariableStart + 3), + macroFormat.format(localVariableStart + 4), + macroFormat.format(localVariableStart + 5), + macroFormat.format(localVariableStart + 6) +]; + +function defineLocalVariable(indx, value) { + writeln(localVariable[indx - 1] + " = " + value); +} + +function formatLocalVariable(prefix, indx, rnd) { + return prefix + localVariable[indx - 1] + rnd; +} + +function inspectionCreateResultsFileHeader() { + if (isDPRNTopen) { + if (!getProperty("singleResultsFile")) { + writeln("DPRNT[END]"); + writeBlock("PCLOS"); + isDPRNTopen = false; + } + } + + if (isProbeOperation() && !printProbeResults()) { + return; // if print results is not desired by probe/ probeWCS + } + + if (!isDPRNTopen) { + writeBlock("PCLOS"); + writeBlock("POPEN"); + // check for existence of none alphanumeric characters but not spaces + var resFile; + if (getProperty("singleResultsFile")) { + resFile = getParameter("job-description") + "-RESULTS"; + } else { + resFile = getParameter("operation-comment") + "-RESULTS"; + } + resFile = resFile.replace(/:/g, "-"); + resFile = resFile.replace(/[^a-zA-Z0-9 -]/g, ""); + resFile = resFile.replace(/\s/g, "-"); + resFile = resFile.toUpperCase(); + writeln("DPRNT[START]"); + writeln("DPRNT[RESULTSFILE*" + resFile + "]"); + if (hasGlobalParameter("document-id")) { + writeln("DPRNT[DOCUMENTID*" + getGlobalParameter("document-id").toUpperCase() + "]"); + } + if (hasGlobalParameter("model-version")) { + writeln("DPRNT[MODELVERSION*" + getGlobalParameter("model-version").toUpperCase() + "]"); + } + } + if (isProbeOperation() && printProbeResults()) { + isDPRNTopen = true; + } +} + +function getPointNumber() { + if (typeof inspectionWriteVariables == "function") { + return (inspectionVariables.pointNumber); + } else { + return ("#122[60]"); + } +} + +function inspectionWriteCADTransform() { + var cadOrigin = currentSection.getModelOrigin(); + var cadWorkPlane = currentSection.getModelPlane().getTransposed(); + var cadEuler = cadWorkPlane.getEuler2(EULER_XYZ_S); + defineLocalVariable(1, abcFormat.format(cadEuler.x)); + defineLocalVariable(2, abcFormat.format(cadEuler.y)); + defineLocalVariable(3, abcFormat.format(cadEuler.z)); + defineLocalVariable(4, xyzFormat.format(-cadOrigin.x)); + defineLocalVariable(5, xyzFormat.format(-cadOrigin.y)); + defineLocalVariable(6, xyzFormat.format(-cadOrigin.z)); + writeln( + "DPRNT[G331" + + "*N" + getPointNumber() + + formatLocalVariable("*A", 1, macroRoundingFormat) + + formatLocalVariable("*B", 2, macroRoundingFormat) + + formatLocalVariable("*C", 3, macroRoundingFormat) + + formatLocalVariable("*X", 4, macroRoundingFormat) + + formatLocalVariable("*Y", 5, macroRoundingFormat) + + formatLocalVariable("*Z", 6, macroRoundingFormat) + + "]" + ); +} + +function inspectionWriteWorkplaneTransform() { + var orientation = machineConfiguration.isMultiAxisConfiguration() ? machineConfiguration.getOrientation(getCurrentDirection()) : currentSection.workPlane; + var abc = orientation.getEuler2(EULER_XYZ_S); + if (getProperty("useLiveConnection")) { + liveConnectorInterface("WORKPLANE"); + writeBlock(inspectionVariables.liveConnectionWPA, "=", abcFormat.format(abc.x)); + writeBlock(inspectionVariables.liveConnectionWPB, "=", abcFormat.format(abc.y)); + writeBlock(inspectionVariables.liveConnectionWPC, "=", abcFormat.format(abc.z)); + forceSequenceNumbers(true); + writeBlock("IF [" + inspectionVariables.workplaneStartAddress, "NE -1] GOTO" + skipNLines(2)); + writeBlock(inspectionVariables.workplaneStartAddress, "=", inspectionGetToolpathId(currentSection)); + writeBlock(" "); + forceSequenceNumbers(false); + } + + defineLocalVariable(1, abcFormat.format(abc.x)); + defineLocalVariable(2, abcFormat.format(abc.y)); + defineLocalVariable(3, abcFormat.format(abc.z)); + writeln("DPRNT[G330" + + "*N" + getPointNumber() + + formatLocalVariable("*A", 1, macroRoundingFormat) + + formatLocalVariable("*B", 2, macroRoundingFormat) + + formatLocalVariable("*C", 3, macroRoundingFormat) + + "*X0*Y0*Z0*I0*R0]" + ); +} + +function writeProbingToolpathInformation(cycleDepth) { + defineLocalVariable(1, inspectionGetToolpathId(currentSection)); + writeln(formatLocalVariable("DPRNT[TOOLPATHID*", 1, "[35]]")); + if (isInspectionOperation()) { + writeln("DPRNT[TOOLPATH*" + getParameter("operation-comment").toUpperCase().replace(/[()]/g, "") + "]"); + } else { + defineLocalVariable(2, xyzFormat.format(cycleDepth)); + writeln(formatLocalVariable("DPRNT[CYCLEDEPTH*", 2, macroRoundingFormat + "]")); + } +} +// <<<<< INCLUDED FROM include_files/commonInspectionFunctions_fanuc.cpi +// >>>>> INCLUDED FROM include_files/probeCycles_renishaw.cpi +validate(settings.probing, "Setting 'probing' is required but not defined."); +var probeVariables = { + outputRotationCodes: false, // determines if it is required to output rotation codes + compensationXY : undefined, + probeAngleMethod : undefined, + rotaryTableAxis : -1 +}; +function writeProbeCycle(cycle, x, y, z, P, F) { + var openString = "OPEN[0,1,\"" + programName + "_inspection_report" + "_@980" + "_@981" + "_@982" + "_@983" + "_@984" + "_@985" + "\"]"; + if (isProbeOperation()) { + if (!settings.workPlaneMethod.useTiltedWorkplane && !isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, 1))) { + if (!settings.probing.allowIndexingWCSProbing && currentSection.strategy == "probe") { + error(localize("Updating WCS / work offset using probing is only supported by the CNC in the WCS frame.")); + return; + } + } + if (printProbeResults()) { + writeProbingToolpathInformation(z - cycle.depth + tool.diameter / 2); + inspectionWriteCADTransform(); + inspectionWriteWorkplaneTransform(); + if (typeof inspectionWriteVariables == "function") { + inspectionVariables.pointNumber += 1; + } + } + protectedProbeMove(cycle, x, y, z); + } + + var macroCall = settings.probing.macroCall; + switch (cycleType) { + case "probing-x": + forceXYZ(); + protectedProbeMove(cycle, x, y, z - cycle.depth); + + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + EXPECTED_Y = yOutput.format(y + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)); + EXPECTED_X = xOutput.format(x + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)); + EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); + DISTANCE = approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2 + cycle.probeOvertravel); + B_ARG = "B" + xyzFormat.format(DISTANCE); + + writeBlock(macroCall, "\"PROBEX\"", WCS_CODE[7], WCS_CODE[8], B_ARG); + writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V1", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + + if (WCS_CODE[7] === "I1.") { + writeBlock(openString); + writeBlock("PRINT[\"PROBED X POINT: @996\"]"); + writeBlock("CLOSE[]"); + } + break; + case "probing-y": + forceXYZ(); + protectedProbeMove(cycle, x, y, z - cycle.depth); + + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + EXPECTED_Y = yOutput.format(y + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)); + EXPECTED_X = xOutput.format(x + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)); + EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); + DISTANCE = approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2 + cycle.probeOvertravel); + B_ARG = "B" + xyzFormat.format(DISTANCE); + + writeBlock(macroCall, "\"PROBEY\"", WCS_CODE[7], WCS_CODE[8], B_ARG); + writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V2", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + + if (WCS_CODE[7] === "I1.") { + writeBlock(openString); + writeBlock("PRINT[\"PROBED Y POINT: @996\"]"); + writeBlock("CLOSE[]"); + } + break; + case "probing-z": + forceXYZ(); + protectedProbeMove(cycle, x, y, Math.min(z - cycle.depth + cycle.probeClearance, cycle.retract)); + + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + EXPECTED_X = xOutput.format(x); + EXPECTED_Y = yOutput.format(y); + EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); + B_ARG = "B" + xyzFormat.format(-cycle.depth - cycle.probeOvertravel); + + writeBlock(macroCall, "\"PROBEZ\"", WCS_CODE[7], WCS_CODE[8], B_ARG); + writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V3", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + + if (WCS_CODE[7] === "I1.") { + writeBlock(openString); + writeBlock("PRINT[\"PROBED Z POINT: @996\"]"); + writeBlock("CLOSE[]"); + } + break; + case "probing-x-wall": + forceXYZ(); + protectedProbeMove(cycle, x, y, z); + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + WEB_WIDTH = "B" + xyzFormat.format(cycle.width1); + Z_DROP = "C" + xyzFormat.format(cycle.depth); + + writeBlock(macroCall, "\"PROBEXWEB\"", WCS_CODE[7], WCS_CODE[8], WEB_WIDTH, Z_DROP, "Q0", WCS_CODE[2]); + + if (WCS_CODE[7] === "I1.") { + writeBlock(openString); + writeBlock("PRINT[\"MEASURED X WEB WIDTH: @998\"]"); + writeBlock("CLOSE[]"); + } + break; + case "probing-y-wall": + forceXYZ(); + protectedProbeMove(cycle, x, y, z); + + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + WEB_WIDTH = "B" + xyzFormat.format(cycle.width1); + Z_DROP = "C" + xyzFormat.format(cycle.depth); + + writeBlock(macroCall, "\"PROBEYWEB\"", WCS_CODE[7], WCS_CODE[8], WEB_WIDTH, Z_DROP, "Q0", WCS_CODE[2]); + + if (WCS_CODE[7] === "I1.") { + writeBlock(openString); + writeBlock("PRINT[\"MEASURED Y WEB WIDTH: @999\"]"); + writeBlock("CLOSE[]"); + } + break; + case "probing-x-channel": + forceXYZ(); + protectedProbeMove(cycle, x, y, z - cycle.depth); + + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + SLOT_WIDTH = "B" + xyzFormat.format(cycle.width1); + + writeBlock(macroCall, "\"PROBEXSLOT\"", WCS_CODE[7], WCS_CODE[8], SLOT_WIDTH, "Q0", WCS_CODE[2]); + + if (WCS_CODE[7] === "I1.") { + writeBlock(openString); + writeBlock("PRINT[\"MEASURED X SLOT WIDTH: @998\"]"); + writeBlock("CLOSE[]"); + } + break; + case "probing-x-channel-with-island": + error(localize("probing-x-channel-with-island is unsupported")); + /*protectedProbeMove(cycle, x, y, z); + writeBlock( + macroCall, "P" + 9812, + "X" + xyzFormat.format(cycle.width1), + zOutput.format(z - cycle.depth), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(-cycle.probeClearance), + getProbingArguments(cycle, true) + ); */ + break; + case "probing-y-channel": + forceXYZ(); + protectedProbeMove(cycle, x, y, z - cycle.depth); + + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + SLOT_WIDTH = "B" + xyzFormat.format(cycle.width1); + + writeBlock(macroCall, "\"PROBEYSLOT\"", WCS_CODE[7], WCS_CODE[8], SLOT_WIDTH, "Q0", WCS_CODE[2]); + + if (WCS_CODE[7] === "I1.") { + writeBlock(openString); + writeBlock("PRINT[\"MEASURED Y SLOT WIDTH: @999\"]"); + writeBlock("CLOSE[]"); + } + break; + case "probing-y-channel-with-island": + error(localize("probing-y-channel-with-island is unsupported")); + /*protectedProbeMove(cycle, x, y, z); + writeBlock( + macroCall, "P" + 9812, + "Y" + xyzFormat.format(cycle.width1), + zOutput.format(z - cycle.depth), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(-cycle.probeClearance), + getProbingArguments(cycle, true) + ); */ + break; + case "probing-xy-circular-boss": + forceXYZ(); + protectedProbeMove(cycle, x, y, z); + + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + BOSS_DIAMETER = "B" + xyzFormat.format(cycle.width1); + Z_DROP = "C" + xyzFormat.format(cycle.depth); + EXPECTED_X = xOutput.format(x); + EXPECTED_Y = yOutput.format(y); + EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); + + writeBlock(macroCall, "\"PROBECIRCULARBOSS\"", WCS_CODE[7], WCS_CODE[8], BOSS_DIAMETER, Z_DROP, "Q0", WCS_CODE[2]); + writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V4", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + if (getProperty("EnableZeroPointCompensation") == true && WCS_CODE[7] === null) { + writeBlock(macroCall, "\"COMPZEROPOINT\"", WCS_CODE[8], WCS_CODE[9], EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + } + + if (WCS_CODE[7] === "I1.") { + writeBlock(openString); + writeBlock("PRINT[\"MEASURED CIRCULAR BOSS DIAMETER IN X: @998\"]"); + writeBlock("PRINT[\"MEASURED CIRCULAR BOSS DIAMETER IN Y: @999\"]"); + writeBlock("PRINT[\"MEASURED CIRCULAR BOSS AVG DIAMETER : @997\"]"); + writeBlock("CLOSE[]"); + } + break; + case "probing-xy-circular-partial-boss": + error(localize("probing-xy-circular-partial-boss is unsupported")); + /*protectedProbeMove(cycle, x, y, z); + writeBlock( + macroCall, "P" + 9823, + "A" + xyzFormat.format(cycle.partialCircleAngleA), + "B" + xyzFormat.format(cycle.partialCircleAngleB), + "C" + xyzFormat.format(cycle.partialCircleAngleC), + "D" + xyzFormat.format(cycle.width1), + "Z" + xyzFormat.format(z - cycle.depth), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(cycle.probeClearance), + getProbingArguments(cycle, true) + ); */ + break; + case "probing-xy-circular-hole": + forceXYZ(); + protectedProbeMove(cycle, x, y, z - cycle.depth); + + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + BORE_DIAMETER = "B" + xyzFormat.format(cycle.width1); + EXPECTED_X = xOutput.format(x); + EXPECTED_Y = yOutput.format(y); + EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); + + writeBlock(macroCall, "\"PROBEBORE\"", WCS_CODE[7], WCS_CODE[8], BORE_DIAMETER, "Q0", WCS_CODE[2]); + writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V4", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + if (getProperty("EnableZeroPointCompensation") == true && WCS_CODE[7] === null) { + writeBlock(macroCall, "\"COMPZEROPOINT\"", WCS_CODE[8], WCS_CODE[9], EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + } + + if (WCS_CODE[7] === "I1.") { + writeBlock(openString); + writeBlock("PRINT[\"MEASURED BORE DIAMETER IN X: @998\"]"); + writeBlock("PRINT[\"MEASURED BORE DIAMETER IN Y: @999\"]"); + writeBlock("PRINT[\"MEASURED BORE AVG DIAMETER : @997\"]"); + writeBlock("CLOSE[]"); + } + break; + case "probing-xy-circular-partial-hole": + error(localize("probing-xy-circular-partial-hole is unsupported")); + /* protectedProbeMove(cycle, x, y, z - cycle.depth); + writeBlock( + macroCall, "P" + 9823, + "A" + xyzFormat.format(cycle.partialCircleAngleA), + "B" + xyzFormat.format(cycle.partialCircleAngleB), + "C" + xyzFormat.format(cycle.partialCircleAngleC), + "D" + xyzFormat.format(cycle.width1), + "Q" + xyzFormat.format(cycle.probeOvertravel), + getProbingArguments(cycle, true) + ); */ + break; + case "probing-xy-circular-hole-with-island": + error(localize("probing-xy-circular-hole-with-island is unsupported")); + /* protectedProbeMove(cycle, x, y, z); + writeBlock( + macroCall, "P" + 9814, + "Z" + xyzFormat.format(z - cycle.depth), + "D" + xyzFormat.format(cycle.width1), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(-cycle.probeClearance), + getProbingArguments(cycle, true) + ); */ + break; + case "probing-xy-circular-partial-hole-with-island": + error(localize("probing-xy-circular-partial-hole-with-island is unsupported")); + /* protectedProbeMove(cycle, x, y, z); + writeBlock( + macroCall, "P" + 9823, + "Z" + xyzFormat.format(z - cycle.depth), + "A" + xyzFormat.format(cycle.partialCircleAngleA), + "B" + xyzFormat.format(cycle.partialCircleAngleB), + "C" + xyzFormat.format(cycle.partialCircleAngleC), + "D" + xyzFormat.format(cycle.width1), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(-cycle.probeClearance), + getProbingArguments(cycle, true) + ); */ + break; + case "probing-xy-rectangular-hole": + forceXYZ(); + protectedProbeMove(cycle, x, y, z - cycle.depth); + + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + XWEB_WIDTH = "B" + xyzFormat.format(cycle.width1); + YWEB_WIDTH = "C" + xyzFormat.format(cycle.width2); + EXPECTED_X = xOutput.format(x); + EXPECTED_Y = yOutput.format(y); + EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); + + writeBlock(macroCall, "\"PROBEPOCKET\"", WCS_CODE[7], WCS_CODE[8], XWEB_WIDTH, YWEB_WIDTH, "Q0", WCS_CODE[2]); + writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V4", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + if (getProperty("EnableZeroPointCompensation") == true && WCS_CODE[7] === null) { + writeBlock(macroCall, "\"COMPZEROPOINT\"", WCS_CODE[8], WCS_CODE[9], EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + } + + if (WCS_CODE[7] === "I1.") { + writeBlock(openString); + writeBlock("PRINT[\"MEASURED POCKET LENGTH IN X: @998\"]"); + writeBlock("PRINT[\"MEASURED POCKET WIDTH IN Y: @999\"]"); + writeBlock("CLOSE[]"); + } + break; + case "probing-xy-rectangular-boss": + forceXYZ(); + protectedProbeMove(cycle, x, y, z); + + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + XWEB_WIDTH = "B" + xyzFormat.format(cycle.width1); + YWEB_WIDTH = "C" + xyzFormat.format(cycle.width2); + EXPECTED_X = xOutput.format(x); + EXPECTED_Y = yOutput.format(y); + EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); + Z_DROP = "D" + xyzFormat.format(cycle.depth); + + writeBlock(macroCall, "\"PROBERECTANGULARBOSS\"", WCS_CODE[7], WCS_CODE[8], XWEB_WIDTH, YWEB_WIDTH, Z_DROP, "Q0", WCS_CODE[2]); + writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V4", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + if (getProperty("EnableZeroPointCompensation") == true && WCS_CODE[7] === null) { + writeBlock(macroCall, "\"COMPZEROPOINT\"", WCS_CODE[8], WCS_CODE[9], EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + } + + if (WCS_CODE[7] === "I1.") { + writeBlock(openString); + writeBlock("PRINT[\"MEASURED RECTANGULAR BOSS LENGTH IN X: @998\"]"); + writeBlock("PRINT[\"MEASURED RECTANGULAR BOSS WIDTH IN Y: @999\"]"); + writeBlock("CLOSE[]"); + } + break; + case "probing-xy-rectangular-hole-with-island": + error(localize("probing-xy-rectangular-hole-with-island is unsupported")); + /* protectedProbeMove(cycle, x, y, z); + writeBlock( + macroCall, "P" + 9812, + "Z" + xyzFormat.format(z - cycle.depth), + "X" + xyzFormat.format(cycle.width1), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(-cycle.probeClearance), + getProbingArguments(cycle, true) + ); + if (getProperty("useLiveConnection") && (typeof liveConnectionStoreResults == "function")) { + liveConnectionStoreResults(); + } + writeBlock( + macroCall, "P" + 9812, + "Z" + xyzFormat.format(z - cycle.depth), + "Y" + xyzFormat.format(cycle.width2), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(-cycle.probeClearance), + getProbingArguments(cycle, true) + ); */ + break; + + case "probing-xy-inner-corner": + forceXYZ(); + protectedProbeMove(cycle, x, y, z - cycle.depth); + + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + CORNER_POSITION = "B" + xyzFormat.format(cycle.width1); + PROBING_DISTANCE = "C" + xyzFormat.format(cycle.width2); + + writeBlock(macroCall, "\"PROBEINSIDECORNER\"", WCS_CODE[8], CORNER_POSITION, PROBING_DISTANCE, "Q0"); + break; + case "probing-xy-outer-corner": + forceXYZ(); + protectedProbeMove(cycle, x, y, z - cycle.depth); + xdir = approach(cycle.approach1); + ydir = approach(cycle.approach2); + var CORNER_NUM = 0; + if (xdir == 1 && ydir == 1) {CORNER_NUM = 3;} else if (xdir == 1 && ydir == -1) {CORNER_NUM = 1;} else if (xdir == -1 && ydir == 1) {CORNER_NUM = 4;} else if (xdir == -1 && ydir == -1) {CORNER_NUM = 2;} + + WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); + CORNER_POSITION = "B" + CORNER_NUM; + TRAVEL_DISTANCE = "C" + xyzFormat.format(2 * cycle.probeClearance + tool.diameter / 2); + PROBING_DISTANCE = "D" + xyzFormat.format(cycle.probeClearance + cycle.probeOvertravel); + + writeBlock(macroCall, "\"PROBEOUTSIDECORNER\"", + WCS_CODE[8], + CORNER_POSITION, + TRAVEL_DISTANCE, + PROBING_DISTANCE, "Q0"); + break; + case "probing-x-plane-angle": + error(localize("probing-x-plane-angle - Unsupported Probing Cycle")); + /*protectedProbeMove(cycle, x, y, z - cycle.depth); + writeBlock( + macroCall, "P" + 9843, + "X" + xyzFormat.format(x + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)), + "D" + xyzFormat.format(cycle.probeSpacing), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "A" + xyzFormat.format(cycle.nominalAngle != undefined ? cycle.nominalAngle : 90), + getProbingArguments(cycle, false) + ); + if (currentSection.strategy == "probe") { + setProbeAngleMethod(); + probeVariables.compensationXY = "X" + xyzFormat.format(0) + " Y" + xyzFormat.format(0); + } */ + break; + case "probing-y-plane-angle": + error(localize("probing-y-plane-angle - Unsupported Probing Cycle")); + /* protectedProbeMove(cycle, x, y, z - cycle.depth); + writeBlock( + macroCall, "P" + 9843, + "Y" + xyzFormat.format(y + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)), + "D" + xyzFormat.format(cycle.probeSpacing), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "A" + xyzFormat.format(cycle.nominalAngle != undefined ? cycle.nominalAngle : 0), + getProbingArguments(cycle, false) + ); + if (currentSection.strategy == "probe") { + setProbeAngleMethod(); + probeVariables.compensationXY = "X" + xyzFormat.format(0) + " Y" + xyzFormat.format(0); + } */ + break; + case "probing-xy-pcd-hole": + error(localize("probing-xy-pcd-hole - Unsupported Probing Cycle")); + /* protectedProbeMove(cycle, x, y, z); + writeBlock( + macroCall, "P" + 9819, + "A" + xyzFormat.format(cycle.pcdStartingAngle), + "B" + xyzFormat.format(cycle.numberOfSubfeatures), + "C" + xyzFormat.format(cycle.widthPCD), + "D" + xyzFormat.format(cycle.widthFeature), + "K" + xyzFormat.format(z - cycle.depth), + "Q" + xyzFormat.format(cycle.probeOvertravel), + getProbingArguments(cycle, false) + ); + if (cycle.updateToolWear) { + error(localize("Action -Update Tool Wear- is not supported with this cycle.")); + return; + } */ + break; + case "probing-xy-pcd-boss": + error(localize("probing-xy-pcd-boss - Unsupported Probing Cycle")); + /* protectedProbeMove(cycle, x, y, z); + writeBlock( + macroCall, "P" + 9819, + "A" + xyzFormat.format(cycle.pcdStartingAngle), + "B" + xyzFormat.format(cycle.numberOfSubfeatures), + "C" + xyzFormat.format(cycle.widthPCD), + "D" + xyzFormat.format(cycle.widthFeature), + "Z" + xyzFormat.format(z - cycle.depth), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(cycle.probeClearance), + getProbingArguments(cycle, false) + ); + if (cycle.updateToolWear) { + error(localize("Action -Update Tool Wear- is not supported with this cycle.")); + return; + } */ + break; + } +} + +function printProbeResults() { + return currentSection.getParameter("printResults", 0) == 1; +} + +/** Convert approach to sign. */ +function approach(value) { + validate((value == "positive") || (value == "negative"), "Invalid approach."); + return (value == "positive") ? 1 : -1; +} +// <<<<< INCLUDED FROM include_files/probeCycles_renishaw.cpi +// >>>>> INCLUDED FROM include_files/getProbingArguments_renishaw.cpi +/* function getProbingArguments(cycle, updateWCS) { // new Autodesk function + var outputWCSCode = updateWCS && currentSection.strategy == "probe"; + if (outputWCSCode) { + var maximumWcsNumber = 0; + for (var i in wcsDefinitions.wcs) { + maximumWcsNumber = Math.max(maximumWcsNumber, wcsDefinitions.wcs[i].range[1]); + } + maximumWcsNumber = probeExtWCSFormat.getResultingValue(maximumWcsNumber); + var resultingWcsNumber = probeExtWCSFormat.getResultingValue(currentSection.probeWorkOffset - 6); + validate(resultingWcsNumber <= maximumWcsNumber, subst("Probe work offset %1 is out of range, maximum value is %2.", resultingWcsNumber, maximumWcsNumber)); + var probeOutputWorkOffset = currentSection.probeWorkOffset > 6 ? probeExtWCSFormat.format(currentSection.probeWorkOffset - 6) : probeWCSFormat.format(currentSection.probeWorkOffset); + + var nextWorkOffset = hasNextSection() ? getNextSection().workOffset == 0 ? 1 : getNextSection().workOffset : -1; + if (currentSection.probeWorkOffset == nextWorkOffset) { + currentWorkOffset = undefined; + } + } + return [ + (cycle.angleAskewAction == "stop-message" ? "B" + xyzFormat.format(cycle.toleranceAngle ? cycle.toleranceAngle : 0) : undefined), + ((cycle.updateToolWear && cycle.toolWearErrorCorrection < 100) ? "F" + xyzFormat.format(cycle.toolWearErrorCorrection ? cycle.toolWearErrorCorrection / 100 : 100) : undefined), + (cycle.wrongSizeAction == "stop-message" ? "H" + xyzFormat.format(cycle.toleranceSize ? cycle.toleranceSize : 0) : undefined), + (cycle.outOfPositionAction == "stop-message" ? "M" + xyzFormat.format(cycle.tolerancePosition ? cycle.tolerancePosition : 0) : undefined), + ((cycle.updateToolWear && cycleType == "probing-z") ? "T" + xyzFormat.format(cycle.toolLengthOffset) : undefined), + ((cycle.updateToolWear && cycleType !== "probing-z") ? "T" + xyzFormat.format(cycle.toolDiameterOffset) : undefined), + (cycle.updateToolWear ? "V" + xyzFormat.format(cycle.toolWearUpdateThreshold ? cycle.toolWearUpdateThreshold : 0) : undefined), + (cycle.printResults ? "W" + xyzFormat.format(1 + cycle.incrementComponent) : undefined), // 1 for advance feature, 2 for reset feature count and advance component number. first reported result in a program should use W2. + conditional(outputWCSCode, probeOutputWorkOffset) + ]; +} */ +function getProbingArguments(cycle, probeWorkOffsetCode) { // Old Toolpath Syil function + var probeWCS = hasParameter("operation-strategy") && (getParameter("operation-strategy") == "probe"); + + var PROBE_ARGS = ""; + if (probeOutputWorkOffset < 7) { + var WCS_NUM = 53 + probeOutputWorkOffset; + PROBE_ARGS = "A" + WCS_NUM; + } else { + var WCS_NUM = probeOutputWorkOffset - 6; + PROBE_ARGS = "A54." + WCS_NUM; + } + + var PROBE_OVERRIDE_ARGS = ""; + if (currentWorkOffset < 7) { + var WCS_NUM = 53 + currentWorkOffset; + PROBE_OVERRIDE_ARGS = "B" + WCS_NUM; + } else { + var WCS_NUM = currentWorkOffset - 6; + PROBE_OVERRIDE_ARGS = "B54." + WCS_NUM; + } + + return [ + (cycle.angleAskewAction == "stop-message" ? "B" + xyzFormat.format(cycle.toleranceAngle ? cycle.toleranceAngle : 0) : undefined), + ((cycle.updateToolWear && cycle.toolWearErrorCorrection < 100) ? "F" + xyzFormat.format(cycle.toolWearErrorCorrection ? cycle.toolWearErrorCorrection / 100 : 100) : undefined), + (cycle.wrongSizeAction == "stop-message" ? "R" + xyzFormat.format(cycle.toleranceSize ? cycle.toleranceSize : 0) + " S1" : undefined), + (cycle.outOfPositionAction == "stop-message" ? "T" + xyzFormat.format(cycle.tolerancePosition ? cycle.tolerancePosition : 0) + " U1" : undefined), + ((cycle.updateToolWear && cycleType == "probing-z") ? "T" + xyzFormat.format(cycle.toolLengthOffset) : undefined), + ((cycle.updateToolWear && cycleType !== "probing-z") ? "T" + xyzFormat.format(cycle.toolDiameterOffset) : undefined), + (cycle.updateToolWear ? "V" + xyzFormat.format(cycle.toolWearUpdateThreshold ? cycle.toolWearUpdateThreshold : 0) : undefined), + (cycle.printResults ? "I" + xyzFormat.format(1 + cycle.incrementComponent) : undefined), // 1 for advance feature, 2 for reset feature count and advance component number. first reported result in a program should use W2. + conditional(probeWorkOffsetCode && probeWCS, PROBE_ARGS), + conditional(probeWorkOffsetCode && probeWCS, PROBE_OVERRIDE_ARGS) + ]; +} +// <<<<< INCLUDED FROM include_files/getProbingArguments_renishaw.cpi +// >>>>> INCLUDED FROM include_files/protectedProbeMove_renishaw.cpi +function protectedProbeMove(_cycle, x, y, z) { + var _x = xOutput.format(x); + var _y = yOutput.format(y); + var _z = zOutput.format(z - cycle.depth); + var macroCall = settings.probing.macroCall; + if (_z && z >= getCurrentPosition().z) { + writeBlock(macroCall, "\"PROTECTEDMOVE\"", _z, getFeed(cycle.feedrate)); // protected positioning move + } + if (_x || _y) { + writeBlock(macroCall, "\"PROTECTEDMOVE\"", _x, _y, getFeed(highFeedrate)); // protected positioning move + } + if (_z && z < getCurrentPosition().z) { + writeBlock(macroCall, "\"PROTECTEDMOVE\"", _z, getFeed(cycle.feedrate)); // protected positioning move + } +} +// <<<<< INCLUDED FROM include_files/protectedProbeMove_renishaw.cpi +// >>>>> INCLUDED FROM include_files/setProbeAngle_fanuc.cpi +function setProbeAngle() { + if (probeVariables.outputRotationCodes) { + validate(settings.probing.probeAngleVariables, localize("Setting 'probing.probeAngleVariables' is required for angular probing.")); + var probeAngleVariables = settings.probing.probeAngleVariables; + var px = probeAngleVariables.x; + var py = probeAngleVariables.y; + var pz = probeAngleVariables.z; + var pi = probeAngleVariables.i; + var pj = probeAngleVariables.j; + var pk = probeAngleVariables.k; + var pr = probeAngleVariables.r; + var baseParamG54x4 = probeAngleVariables.baseParamG54x4; + var baseParamAxisRot = probeAngleVariables.baseParamAxisRot; + var probeOutputWorkOffset = currentSection.probeWorkOffset; + + validate(probeOutputWorkOffset <= 6, "Angular Probing only supports work offsets 1-6."); + if (probeVariables.probeAngleMethod == "G68" && (Vector.diff(currentSection.getGlobalInitialToolAxis(), new Vector(0, 0, 1)).length > 1e-4)) { + error(localize("You cannot use multi axis toolpaths while G68 Rotation is in effect.")); + } + var validateWorkOffset = false; + switch (probeVariables.probeAngleMethod) { + case "G54.4": + var param = baseParamG54x4 + (probeOutputWorkOffset * 10); + writeBlock("#" + param + "=" + px); + writeBlock("#" + (param + 1) + "=" + py); + writeBlock("#" + (param + 5) + "=" + pr); + writeBlock(gFormat.format(54.4), "P" + probeOutputWorkOffset); + break; + case "G68": + gRotationModal.reset(); + gAbsIncModal.reset(); + var xy = probeVariables.compensationXY || formatWords(formatCompensationParameter("X", px), formatCompensationParameter("Y", py)); + writeBlock( + gRotationModal.format(68), gAbsIncModal.format(90), + xy, + formatCompensationParameter("Z", pz), + formatCompensationParameter("I", pi), + formatCompensationParameter("J", pj), + formatCompensationParameter("K", pk), + formatCompensationParameter("R", pr) + ); + validateWorkOffset = true; + break; + case "AXIS_ROT": + var param = baseParamAxisRot + probeOutputWorkOffset * 20 + probeVariables.rotaryTableAxis + 4; + writeBlock("#" + param + " = " + "[#" + param + " + " + pr + "]"); + forceWorkPlane(); // force workplane to rotate ABC in order to apply rotation offsets + currentWorkOffset = undefined; // force WCS output to make use of updated parameters + validateWorkOffset = true; + break; + default: + error(localize("Angular Probing is not supported for this machine configuration.")); + return; + } + if (validateWorkOffset) { + for (var i = currentSection.getId(); i < getNumberOfSections(); ++i) { + if (getSection(i).workOffset != currentSection.workOffset) { + error(localize("WCS offset cannot change while using angle rotation compensation.")); + return; + } + } + } + probeVariables.outputRotationCodes = false; + } +} + +function formatCompensationParameter(label, value) { + return typeof value == "string" ? label + "[" + value + "]" : typeof value == "number" ? label + xyzFormat.format(value) : ""; +} +// <<<<< INCLUDED FROM include_files/setProbeAngle_fanuc.cpi +// >>>>> INCLUDED FROM include_files/setProbeAngleMethod.cpi +function setProbeAngleMethod() { + var axisRotIsSupported = false; + var axes = [machineConfiguration.getAxisU(), machineConfiguration.getAxisV(), machineConfiguration.getAxisW()]; + for (var i = 0; i < axes.length; ++i) { + if (axes[i].isEnabled() && isSameDirection((axes[i].getAxis()).getAbsolute(), new Vector(0, 0, 1)) && axes[i].isTable()) { + axisRotIsSupported = true; + if (settings.probing.probeAngleVariables.method == 0) { // Fanuc + validate(i < 2, localize("Rotary table axis is invalid.")); + probeVariables.rotaryTableAxis = i; + } else { // Haas + probeVariables.rotaryTableAxis = axes[i].getCoordinate(); + } + break; + } + } + if (settings.probing.probeAngleMethod == undefined) { + probeVariables.probeAngleMethod = axisRotIsSupported ? "AXIS_ROT" : getProperty("useG54x4") ? "G54.4" : "G68"; // automatic selection + } else { + probeVariables.probeAngleMethod = settings.probing.probeAngleMethod; // use probeAngleMethod from settings + if (probeVariables.probeAngleMethod == "AXIS_ROT" && !axisRotIsSupported) { + error(localize("Setting probeAngleMethod 'AXIS_ROT' is not supported on this machine.")); + } + } + probeVariables.outputRotationCodes = true; +} +// <<<<< INCLUDED FROM include_files/setProbeAngleMethod.cpi + +var now = new Date(); // BJE diff --git a/syil_x7_three_axis_machine_model.f3d b/Fusion Posts & Machine Model/syil_x7_three_axis_machine_model.f3d similarity index 100% rename from syil_x7_three_axis_machine_model.f3d rename to Fusion Posts & Machine Model/syil_x7_three_axis_machine_model.f3d diff --git a/SPINDLE_WARMUP.NC b/Helpful NC Programs/SPINDLE_WARMUP.NC similarity index 100% rename from SPINDLE_WARMUP.NC rename to Helpful NC Programs/SPINDLE_WARMUP.NC diff --git a/SPINDLE_WARMUP_FAST.NC b/Helpful NC Programs/SPINDLE_WARMUP_FAST.NC similarity index 100% rename from SPINDLE_WARMUP_FAST.NC rename to Helpful NC Programs/SPINDLE_WARMUP_FAST.NC diff --git a/probingSetupHelp_v0.1.nc b/Helpful NC Programs/probingSetupHelp_v0.1.nc similarity index 100% rename from probingSetupHelp_v0.1.nc rename to Helpful NC Programs/probingSetupHelp_v0.1.nc diff --git a/CALIBRATEPROBEBLOCK b/Macros for Controller/CALIBRATEPROBEBLOCK similarity index 100% rename from CALIBRATEPROBEBLOCK rename to Macros for Controller/CALIBRATEPROBEBLOCK diff --git a/CALIBRATEPROBERING b/Macros for Controller/CALIBRATEPROBERING similarity index 100% rename from CALIBRATEPROBERING rename to Macros for Controller/CALIBRATEPROBERING diff --git a/CALIBRATEPROBEZ b/Macros for Controller/CALIBRATEPROBEZ similarity index 100% rename from CALIBRATEPROBEZ rename to Macros for Controller/CALIBRATEPROBEZ diff --git a/CALIBRATETOOLSET b/Macros for Controller/CALIBRATETOOLSET similarity index 100% rename from CALIBRATETOOLSET rename to Macros for Controller/CALIBRATETOOLSET diff --git a/CHECKPOSITIONALTOLERANCE b/Macros for Controller/CHECKPOSITIONALTOLERANCE similarity index 100% rename from CHECKPOSITIONALTOLERANCE rename to Macros for Controller/CHECKPOSITIONALTOLERANCE diff --git a/COMPZEROPOINT b/Macros for Controller/COMPZEROPOINT similarity index 100% rename from COMPZEROPOINT rename to Macros for Controller/COMPZEROPOINT diff --git a/COPYWCS b/Macros for Controller/COPYWCS similarity index 100% rename from COPYWCS rename to Macros for Controller/COPYWCS diff --git a/FINDCOR b/Macros for Controller/FINDCOR similarity index 100% rename from FINDCOR rename to Macros for Controller/FINDCOR diff --git a/LOADTOOL b/Macros for Controller/LOADTOOL similarity index 100% rename from LOADTOOL rename to Macros for Controller/LOADTOOL diff --git a/PROBEBORE b/Macros for Controller/PROBEBORE similarity index 100% rename from PROBEBORE rename to Macros for Controller/PROBEBORE diff --git a/PROBECIRCULARBOSS b/Macros for Controller/PROBECIRCULARBOSS similarity index 100% rename from PROBECIRCULARBOSS rename to Macros for Controller/PROBECIRCULARBOSS diff --git a/PROBECONFIG b/Macros for Controller/PROBECONFIG similarity index 100% rename from PROBECONFIG rename to Macros for Controller/PROBECONFIG diff --git a/PROBEINSIDECORNER b/Macros for Controller/PROBEINSIDECORNER similarity index 100% rename from PROBEINSIDECORNER rename to Macros for Controller/PROBEINSIDECORNER diff --git a/PROBEOUTSIDECORNER b/Macros for Controller/PROBEOUTSIDECORNER similarity index 100% rename from PROBEOUTSIDECORNER rename to Macros for Controller/PROBEOUTSIDECORNER diff --git a/PROBEPOCKET b/Macros for Controller/PROBEPOCKET similarity index 100% rename from PROBEPOCKET rename to Macros for Controller/PROBEPOCKET diff --git a/PROBERECTANGULARBOSS b/Macros for Controller/PROBERECTANGULARBOSS similarity index 100% rename from PROBERECTANGULARBOSS rename to Macros for Controller/PROBERECTANGULARBOSS diff --git a/PROBEX b/Macros for Controller/PROBEX similarity index 100% rename from PROBEX rename to Macros for Controller/PROBEX diff --git a/PROBEXSLOT b/Macros for Controller/PROBEXSLOT similarity index 100% rename from PROBEXSLOT rename to Macros for Controller/PROBEXSLOT diff --git a/PROBEXWEB b/Macros for Controller/PROBEXWEB similarity index 100% rename from PROBEXWEB rename to Macros for Controller/PROBEXWEB diff --git a/PROBEXYANGLE b/Macros for Controller/PROBEXYANGLE similarity index 100% rename from PROBEXYANGLE rename to Macros for Controller/PROBEXYANGLE diff --git a/PROBEY b/Macros for Controller/PROBEY similarity index 100% rename from PROBEY rename to Macros for Controller/PROBEY diff --git a/PROBEYSLOT b/Macros for Controller/PROBEYSLOT similarity index 100% rename from PROBEYSLOT rename to Macros for Controller/PROBEYSLOT diff --git a/PROBEYWEB b/Macros for Controller/PROBEYWEB similarity index 100% rename from PROBEYWEB rename to Macros for Controller/PROBEYWEB diff --git a/PROBEZ b/Macros for Controller/PROBEZ similarity index 100% rename from PROBEZ rename to Macros for Controller/PROBEZ diff --git a/PROTECTEDMOVE b/Macros for Controller/PROTECTEDMOVE similarity index 100% rename from PROTECTEDMOVE rename to Macros for Controller/PROTECTEDMOVE diff --git a/SAFESPIN b/Macros for Controller/SAFESPIN similarity index 100% rename from SAFESPIN rename to Macros for Controller/SAFESPIN diff --git a/TOOLSET b/Macros for Controller/TOOLSET similarity index 100% rename from TOOLSET rename to Macros for Controller/TOOLSET diff --git a/UNLOADTOOL b/Macros for Controller/UNLOADTOOL similarity index 100% rename from UNLOADTOOL rename to Macros for Controller/UNLOADTOOL diff --git a/LNC-Operation Manual.compressed.pdf b/Support Docs/LNC-Operation Manual.compressed.pdf similarity index 100% rename from LNC-Operation Manual.compressed.pdf rename to Support Docs/LNC-Operation Manual.compressed.pdf diff --git a/LNC-Programming Manual.compressed.pdf b/Support Docs/LNC-Programming Manual.compressed.pdf similarity index 100% rename from LNC-Programming Manual.compressed.pdf rename to Support Docs/LNC-Programming Manual.compressed.pdf diff --git a/LinuxMACROManualV0100ENG.pdf b/Support Docs/LinuxMACROManualV0100ENG.pdf similarity index 100% rename from LinuxMACROManualV0100ENG.pdf rename to Support Docs/LinuxMACROManualV0100ENG.pdf From 2c7e9cf271c39f40ecc5e76169ff9a57eb59f431 Mon Sep 17 00:00:00 2001 From: Jestah Carnie Date: Wed, 2 Apr 2025 16:20:20 +1300 Subject: [PATCH 09/21] Update changelog.md Updates in this last batch of mods --- changelog.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/changelog.md b/changelog.md index 3d83150..20bda74 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,15 @@ +# V1.2.3 +- Updated the macro set for compatibility with post-processor Revision 44168. +- Added a wide range of user messages to provide extra control information during probing. +- Implemented support for switching between metric and freedom (imperial) units in ProbingConfig. +- Added logic to run all extended work offsets, with an option to protect any offset above a specified number. +- Implemented support for probe spin-on and spin-off M commands. +- Removed unnecessary spindle orientations to speed up probing cycles. +- Added an experimental post based on Scott Moyse's last post, featuring numerous changes and tested for compatibility with this macro set. +- Machine simulation and connection moves now display correctly in the new post—refer to the post's changelog for a full list of changes. +- Added top-level folders to simplify the setup process for new users. +- Added a helper NC file that guides new users through the process of calibrating their probe and tool setter. + # V1.2.2 - Post properties table renamed and reordered - G30 option added to safePositionMethod() From ee49362c04cc5e08b217f3ad9845b977aba0dd16 Mon Sep 17 00:00:00 2001 From: Robot Oblivion Date: Thu, 3 Apr 2025 01:33:22 +1300 Subject: [PATCH 10/21] image for readme --- images/DisplayProbedResults.png | Bin 0 -> 10415 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/DisplayProbedResults.png diff --git a/images/DisplayProbedResults.png b/images/DisplayProbedResults.png new file mode 100644 index 0000000000000000000000000000000000000000..33b3c352de2e7c3fe4883b4b300bb21eb66b9040 GIT binary patch literal 10415 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 literal 0 HcmV?d00001 From 11553cbef1b0b76b516c35989638b586e3687a34 Mon Sep 17 00:00:00 2001 From: Jestah Carnie Date: Thu, 3 Apr 2025 01:38:03 +1300 Subject: [PATCH 11/21] image for read me for displaying probe results --- images/DisplayProbedResults.png | Bin 0 -> 10415 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/DisplayProbedResults.png diff --git a/images/DisplayProbedResults.png b/images/DisplayProbedResults.png new file mode 100644 index 0000000000000000000000000000000000000000..33b3c352de2e7c3fe4883b4b300bb21eb66b9040 GIT binary patch literal 10415 zcmaL7bySFuWtIQ{GguBRuIX)j z4D)d(nh$0_t7&Uv2tyeH);4`WXF1QnA4F$Sr(vdwur%(qIim5-A>~SCuEXd+&OxT& zqo+`Qq+#{x78I8>uCzo=;bgTi=yMbLorD}WT^~nOJG?2CAjUGlN@zZJB>nOxX_iJXm??0%RjO=j=mtq*6=D@WUr&q|A9^iNMfC@ecOctzGkl{ zJZ?{^WH{}#_1_2i(-z;c#(1L?w<4>T_ePl$Z9Kexr@td#)FS!Uw#y9TK`QnMn!ulA zzWf;FoljR$ZOHemVfO*X-Fs}`dWTBTm_h`IY3>Nj_0Ajeo-HOly;tvjqzO>~nO3Bi zIPlgM+?p@1g=QhzTE5@#;!o3^OW^Sad#YsTT2b^J6^xD8tIZVDRf>tOMW|{;!(FjG46$zof$u&4np0*M7??r*&EteH4%Tvhc&ABm%DNcOvBglL4@Y(_RgGkmK2SE)b#g+PZFAZeTt$u0*Ha z6?NQ44GFN$&k$YxhQcCx*N>&Lm>$&Xb4H8i1O#fDZ5*97Pm^tO9@EW9QGe$8#6U$e z)Ax?p^dNaQSOEc2bdrCx*=jSu zX}6gX#z;mn;|q%Bu`LSXq5DAw3-tcL@JR1qjblrM?C;M4#6z74NjY|ad*SoCa^>_v z6GQ*K_F%||_PTOi9c;j#UI_6d^2965x2g>RR2Mj-Svgp#$H2rIqC*{agufgEZFJ8J z@^uj3=;q0TPpVBlq`D?5mCIfEGS(3bjQH*oN^58g@w%_Qq-Eux!p&Dyy zaUeCv<#@S}V+b3=9=w&yZu+-(%H9Y&-o2(x;VOyU>o1~d)|U+pm5lgtYR7wDb7Su8 z{0mJHCS zPr1x62!$J>0=kDqbfM$cBQ)#N#X$cTWg1bAv#m7$0thWyDpq4ih~ajV*B^Ev5a+!>@;LVBFps4bZ1^3}= zfA5*Tz%QzW@1&`huU*FGqo=;;*D6gQEG;#KkKg>*jUq9mjOTmpE!n(z7GcdQqNLQ{ z25~UfWCQ$-xDBHy^y`FMX}6C{;V?Zp8A=*i%k>M>UTXZAF)c0O(N&7>>y3DTB$GVp zezSpUuoPcd041H&TrWkb-j`s~1_gmS-jumoW$wXcNEeANzR}HLZOtnmE{L?J6tV0` z?b6%(^TZ$u?)^O`{f#lu_MtxApFjP!TOb?9L$EPKPZSo*|Bc_qDfUX~cY^k|DJFo3 zsJO8cDbl0rd#`_?a%uqL4Da#kUy!D@Z(oNTJQlTY-DT(x2c@6rgL>*ch#KDK);@MN zy(zy5K1I2`_=r6534Wi(hu6}(Oqx_3=&LgAMFPgRwWX_V=|ofTz`*|;O{_&D$Ic5_ z|52KU`St43Vh@@lb@}-|qI;Ob$CvlOZr0W#kS=5Cew&J`{<%RnO!|mGpXmPnuzXxZ zP2c6a(P7b@fn=NZG(5hp<60Ab_L1lHwCP-O`i;BJRO%)0OOQ(J^a(Un7sp@sQ7ZsZ zh;@yo%0B%Ld-doG9dX8PbCj<Yi zy0K#cP$x8znt2ApV?n@08c2%%0~+}iM^LqC1I6_B_oM(14cfUDH`ck1GJQSdwT!dF zaNkaID?U^hhZ%fNHb(g!Q|e9MJ{1#Z4Q*X1Y@ZLz$jhgcAr1@Mu^Q%K*8zW3*Z-7> ze-%qt6r@(}9$?YAE8Jwm;bRCan`u)Q5I17Z-4z~Gqn6UpbimCt_Z*hJEu*!XBH~?S za;xHlp~jwkqpYjuVD?*a|1}$zJ3l(LO|fBTY-#RG-AJK|W=~3NOU+scbEfZ2}H9_lKqvX({*<{%-EKvDlaQ zk$ajuJr9Xgv7;!r0QjapTVw^#K07#YpdHMAHDqW2&NSCSsw}uPc#s%=PS?GyJ#n0w zb(Bco2WEzcV9v~(NMAqNJBVgj;OeV2xRa`0*cTjXEI~%Mv*=!pKhUfX;cAkd>_;ap zx_nJ1)1EQ{MoTCT9y(d==&xA-EnRW($I-lq>|sE%{Z3>sk-pguW97g^H%_xMkM%g? z*o9P(LiEePa4QTb2R@(eux9dS7zKUu_%5;N$|~V7V@C7_l~7H-vFM{M+j>{wTyjTN z>RNQX+KRd9z{JqIc6)G|>NC5+B-Cx=c_E(-UZ3-vtLRY)2^h4>RLyA!k}blpOSmi= z;MKV(Dq7EcRvwc~77UIyCy}SEsrM-r`Mf#`lWQO0`F19f;}~ebs?6;8-sL;dDiaBV zRDEKqgj>5+99eew-|5q+hLGwuJ=7Frn*882{FRTJCFa>g`ekAv`10S4cpAPF5vYOw zTn=z2MMZ5YW3DZk(GaM)-i6AMsy^quqm;aujI+a*BjX9APALMUV5QKDtA+4bnYO%$ z9(ndL2p!Xlsr{PwLejWwNXkvclAGuj9Jl`Eb{Er1kKe;1HGUV{U-Vh9+6(mXs8+{E zGv#oS_t2qhY3BlaWv(XH>M-Gb8~C`}WlR{$_B6g0h&!kPVIUz7Ti(6SYXJV~dP`z( zQ34B&bGeCvqHZ+H4U+;T1uR4&kmIoFzn~I=C}xyZE(?xQ6HNj zi3&;|2rU=m6B^iv(M=4ji-}6Nvu{SO1rbhD z`Cxy>T6cvaMM$=HyII+DvEsXWGW}A0 zl4OQVzTENH)%PBQwQkzB`hvCq@ zR!RJ%A6qeK+f3+ktmS+r)ue|P0>RcYxtGxlxT8KFcdG6t-4zY4tSdgNiv&H@>r%?~ z)*cNk;ss&D7Ex?o{uBd;TKj&z)+kut{Moe``Er<@rF})l-1qe7^yz&B+Sau$<00or zs|7cp;JK(Xa(9uShBGG87B5JM6FS|_M%m2N29={l9By2+EG#QSZxH>U!HPRHI^J{P zjU z!g%GyYvxVUjHVN_%J0Qy<6FGr-`gvz7NJawZ-z&DWLEyy~HgP@!jI zZns=S(evDh$J#n?nm@%;>{hx)Vq^p16Yq8F z&r-cFDolFaUM@iF?i4aXlW&+qceiAcUsI_L3JQ@GE0uZ^^!<6p3u3l;O?P8{Fk*I_ z(1E>{oLR_BVqr(%3qRDp5++nlp;jxh&=|D#)$A}FYNtUJYe=LO^*x{ysrbzDDG~ut zKZ?>q(N)W|=PE@gq+M;?8FN2xJZQ4&iK<|Cn2-wLz4P&)dkV<2Xjl9X6ph-lO{cT%_Z;Taq7P?F z*_r(ZARf3kA#@yDPNEs{FPBq43vAc#Ke(iq-J;dLH-ZhhdsxJ+#3tN4<8vz+{XpUR z9Ln*etRrcz8?ITo;z+jVSZ0>T>xgd>cx`;-?*&peq6mdq9ncY3E?Pa@ox8im{-msA z#+>MU5uuj_Qc(@WAI@{}@u6obguD|9+c5iZc5v{Fb<%j-1bQTr>bbjFK5ya>PAG-k zix#Zd^pMAMY#gpV5$Ln8#qR})lH{q?3Hx_bO9N`HecntwUtvYO$s?H;4u*QDtjBT$ zplayg8Yl-2qZflOT47l^-;BBM)(32ka*G37~Y}{lEQAcw*x!)PD8uh*GgzxVUB$-`y{0KqtABC z!;W~q946A@Jw*Oj#dsSVw$wf3O7VPte_83@uxBFxunkWJy4y>gt1hvt#ihNTJO5Do zF)@Bj=worhmW1@hUR`0!vR{83)9t*R=NTP7rCX$WymYED4KgDA{(Q~fcmEr|h0gK4 znpqeTww>RKqxXsNfNM-fELUx0f5HR`+wn zwpG#CX9)SGIe`WdijHslZ?{6M@X*W+vee+4bOdZ{9J8aJxN(O+KV!UV;1Y17pwGn0 zWDG)oDjw{ABr?hzMS+LfcFIi9x8#=xwl|ca)B$Effmh+@5gx@1aw%;_a=G*l586G? zT`l$zqi&J96gt|p#4L$212ik%&9>Zu0yl3DNDK$sWSk00*FrmAe#N$-9I%mxn$p0o z>Gwp0F^&1-ICdIRCoenHMP!Gh9Ei|*W&p0O;v0t0$MHpaV zsda>iXBZuLT6wsBTIOvhWinoFbe+t6F=CBjNnDPvUgZXe^&n%o-6TTq=Vc1(-s4cU zkh|Sf)T}LFC(y#)Ng!*S2@0W({NfCJs>u8W3&3Df&g=emqTqcnT-pyUddJO&&hQEG z{(Xb<-vOF7N9;|zC1&@;iT*`A70JEOMBw*By)74q6>oRgjms5`Ab|OYSxHxmJQm}| zJ9nW_anIq1<8tw`h!kU?mVGby#$cR!>Co6^wqnze`Lp6eg!WA;vH(oj)^EW|isW8W(Ob+ojPvRsi z+4{J`RTeQ7ypvXUs$xHOAmh&(ybCeWfzGvv#!tW3fNw_MS+2=(SHH01~&$FY!9| zdMjc3e;_^V%T;64+AcUH8yjXFPZP_nGq89a<0oOjb>h=jPbv?l*H1&B{k<@IzKxhl zG2RF@`9`NFijPx1cr_a*;>~3*zoLx~mREC&*u~m7CCUph#Q+PfWzN^dwkjQr92%5e zFN)m6o+B8%+(>u|AiR5V->$<$s`0l4)&xoAQsshBo?q^DB3y1376uT9$@*8n-ZpSo z*?hOM^ez>#IjnhlS`FMHwpz$E&+ ztW&>_XE9{_AnF#pMlc96tYGf@b9x-|j+JIo z#DDn0zA4}pEOz~bcQy9;k$)o?w}~qbn=zIrKG`6~l+sZvEf_+OBCGz=S{ec1SZvqU z;RXAF-EnWS?9>~d;XYs$v2s-e?|8XUwZ3xnK*+{};M>BG&H{wey}cMHvipXXoj8L2 zXHo|L@OCT;eTkJaCV?~~rfV`Gk9O=ehc& z6%k4-9qj`AsxrMck_Q0*_ffB50B}ETosTDjV_?cbX(+#D_Q&w#VgJCzKdyxoDS0ee z)&_@emsjqMPSbPCbI~cKnT6%u_JX3_ZK@9xRD`7q1zYT z@9)_qzgS-xB^myO4DbX!Hyi+`{`!dZvD>dq$Mk-Y8iKpcjx7P+lb4|-WuBt^<3hSl zuShoVd7QZLsNY|UP=7_>rsfw>FE#O#DacEDDB!A4FjB#(X>q7YU!H+$AG%Ns4UNC-2&lu*Blu@}_#U^o%NXE1QadLw=Edu!t&F2e81 z+eN$otBC`c{JTXmPq&e-UIL+e&rLZ`pvD8M_8zY(Y|6U!$~3jrSC#>5#!<;^5jzcF z<1{@GfJ}QMZlRsoX3Qf``a@?NlZCgi+LM15d9I$r(ugY$4a5}fM{_rr3VO|3KjjJ_ zZ=pn#Z>%2iF9=*#_ULZj0q{6}LTs!yzJ8>bp`O_-gu|Hj&zlTo6+F}`Kb$6e4*vN= z0PPxWUf*OKvkC9@blc;DP6vJMDuh_jS=XdRJSqTJOK0d(%-t>dJF%XjRp?WNJumS~ zI@il=g>HWXdyzrf^IHQx7n=cm0_foJyacGIB&H*LJBTORn;Z_Q34a15z}rL=k|5Ba z>3=$1bo$XcM^I51C#pJ4=ve++IdGaRBO84L0l~Kjd|7NdkUZswBq9K2UsRO(C<+7a znxF)j2rZbM+&~7LX2%%11P1?rr-c7nj`M#cg&6Wo?l{F84{ubCu$*_o^Rx;bvtc1} z(=i|4*0vtyi(ZQdTF@^RV_VqkQ$L@aip0vLGDf@MOymkinmip?8Ip~yuc5A>f?ft> zH-6i9Xr+KYj1(7?*$7-*TqI>=d=!vN39B+_0kN^+K=YZU+x&DZBOKk%PwUg!bn?Z> zv)u96Sj)uXZ=B*pH zw;TZv%$OomXHx+Do2c1e4(!jt$j5hA&rFroHsF2F|TPC>ePc@8pjZ9v+@#MMl+P@NY}e81$VPNDIrHlno)L zzw4P#gVw11wY6Fc7UBAV?|PYYCYC}o=1|gx_+SL- zT2mA^fDM6hnWu(j=I)~9b4OYEoT!8!_H*El(DvShq(_+>m5gJHV3}50US2|lPL28D zT-7aHvB&yc?$QbiQ`WP_R=i@MO#`0gPL`5#5_E#tx9rfaV z?tH4_aEh+W)=&+eg_HL3DjgFcBsT!XsvkP~%!br#$bQ+)ojZ$Nbu8Ozg{oE4l+^ zWUc!?0=JBojOCcVEL9>}HjjgZwl)dmGWQgDgiO|w5lq8yb};xwxzRQ;yxIV%l4V}l zysel(#v`$h2U%|vLDK<28(wsbjtSFf;LIJ+$lX1^;S^3>OcYr=cqCV^?SVFepg18O z*yrL9cgrdaf3DymAO<2PGtxr`E6Wrm?foV;GfM$X&bmHq2+Jzh3>X6zd zk;l=#sU`!gXWi-z$I@-KCu28k{d{%h-f`B8#pkk#-0TR8aoHL`(N}WxoF594qJi?p zec!e&?yT}CDcAv&kC0lN#7G945E>vs;FF3LVKl!dwvz5R?U^Gd2|3#zuaU2DhAB&@ z62GK#NY7Hi>ZC_1*$wts@Qf?8f#!UB1kUX+Sp@}29UW50{cKI|-lf^Y-{ad8udY}$ zD(~)J@fKLoV_C@R{(b0h+N*iwq*vz3!uw;3Zi!=f7qyB30Qf1DWdr~ikFgVkU;`ej zGV95he`iwjC){tkR+n9ZVKlLzrPN;4QWf#FZ0e1Fcqaj)1A2wYZ=F(Dk^(K`Td?!DbKve~2!1 zTb<2RbrOQXAH&3AG=O*Qs7>u^EuH8P;(-(K!943)GP=>q5y7zdXZ-y?VO~3Mb|?}X ze%xNGyml?%N^$+%rV#A=r(Hwjh#!5s<)PhxQDXLZ9-dF}c1_dg*!r8TRku#nJ-89D z!mbVAQv?Gh5=T6C>K~;PK9s$lW4bf5_8yQ%EYu1+uVP0l+$E?(qkDl7`AmcsrOT$L zALqw0U`c7|)~eqrv?mnpe8D1d15NZ+{1=Uvudl#B0wq?m4N4?|<9D&Q1_^DYr4?HoWc^m~CR!@P_H1PmDey`BH)&;PauDBCe44Sut24j@odU+|ux`v-i5 z%<{xX;TCN-pfkXK`Yl3^nF}s|J;MG0Up2e^f%HnG;Szo+a2lt28N8gyzq=GOKZMu3 zZlJ8$2>}gAo?eG03<$T=eAkEvR7CWj>It`uS+2k46~=Q#;J;NDWI5rh4$%_*+YQ=3 z@BTk+{NIO=(l^j&6R%QD%mga(#!O|irzKEJ`2)dFw|`^?5JkiNH2m@Dy7AvA8R5yx zIrMqQ7{iR}KV=-@@}F73>;Iow{lNcRELj$PW0FZykZIF^s^Bz3MkAi)j40+0iipwhPJup%=G;}3;9JZ|`^zF+SkO=5pzVhY zO@2@}eU}-)f}6@jchC4t(-7vvOko?9hwnloK+3GnA89a*DOn< zjc`qpH(bC2Kd=8oNJ%@>+;ug8H%%U1sky>chKQ{z%mjz-bOsFp5GpCz>kk6?t<+-! zYy_V&_*kOkXyO~=PI8iv06+>$cnG+!IDSZKdkKl)Cfc7U8n3lFrA;q|1b zf00UyoDz>t2a1uurKSDXIz>xF64unKtym>cMm|vGMAYed#WYY9!rAxg{T7B{yQ@@= zRqS*khgy-a6P?cD>U{dwn*pFKkyoO>Imx}FVPC#7Pjmyt1|1%0PikJmE1WJ;>&4Bh zErm3j$!s5*JF>0F%%?Xe16J@3+hk5O&mKIN>lF=c=6|{+WSG1B$bMEzE9OiCcS=k@ z{Al-np%AuzfKpOfq&^dwEuhq}? zc(c#`4zCqHguVw-vO(Pj5d4s;l%H==Ffp@g*3K)lvv@t~>%8DeUZR1c1 zS)=3A*MXkxuq@Fa5vqVIwH$u80ZtXe3>)y9kHlVNh~MvquomW%+58Z_q0+OQ>9aNH#~`ldFIRBJZ77UIfp*LZiY4Z?hjxD!F5BaSkslRdj<&xJPC zl!u2c%As2em=t{xDzB(W&d+zsVq#YyQca2#s>810n`X~IaGPTlm+ND%6a-DUa87Ss zeuCPXRL!~S#|C62NZtPu=aIiiw6M4{A2V`6&+1bA^x;0#r)q9fAYqz~ZfBt;eSXh$ zR%xm!o<9lP^>plX{!0??-^ie^uW!@7C~JE%hy<=(nt4)7+M+*DpWCvPYEx95N(4f< zAO`_Uj~Teg2_5#R@&dSKlLQ_^^s14%kW!NCpZr;yCX+qpxFx^07+(j9z@g=;ufo&G z3Z4jOb5y@oG-y6NVEL*l%pjOl3(keE{jbec60iH^^1&2UVl}0$&j=iY$?<9^8eO0`kbrk zlyh$G2^lAuO5Q4)%#9p*cYRY+t5{*cEE60kI6>k@BL_Ii*AAELPgRJ6I71nxK9_O1D?0411W489+VJ8Dh*uFbsCBH`9N~^#GM?RXfZ8#8rXub_sf|hL89j_X!{Es> z(gjC~SBl|)*vYfyI9LX1Oe5v1OlOpbeUuMz=6dBA=*<rB_Tat)u>(12f2j{;a2Sr-7=v zC>{!kQ>@uGSH##H4S7}(pu`oiWn*fyVGW;57;sf^_l)=>!rXl|eQj^C2 literal 0 HcmV?d00001 From 8c0c0d0e88fc92e4cd98f122a057250ec40dfe1d Mon Sep 17 00:00:00 2001 From: Jestah Carnie Date: Thu, 3 Apr 2025 01:42:12 +1300 Subject: [PATCH 12/21] Update README.md First pass at an update to read me to account for changes I have made to the macros. A slight rearrangement of the order to walk a new user through the process of getting the probe working. --- README.md | 238 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 131 insertions(+), 107 deletions(-) diff --git a/README.md b/README.md index 130bb81..c5f2fd9 100644 --- a/README.md +++ b/README.md @@ -1,62 +1,103 @@ # SYIL X7 LNC6800 Probing Macro Guide -Justin Gray, Joshua Smith +Justin Gray, Joshua Smith and Robot Oblivion ![syil_x7](images/syil_x7.png) ## Introduction -The objective of this document is to provide guidance on the use of the provided open-source probing macros. The macros are meant to provide basic probing routines and support WCS probing within fusion360. They also serve as a reference for anyone interested in making their own custom macros. Community support and feedback is highly recommended, we are all in this together. +The objective of this document is to provide guidance on the use of the provided open-source probing macros. The macros are meant to provide basic probing routines and support WCS probing within fusion 360. They also serve as a reference for anyone interested in making their own custom macros. Community support and feedback is highly recommended, we are all in this together. ## Important Precautions -The probing routines only support probes that don't require special macros to turn them on. -They will work for both wired and (some wireless probes). - Recommend probes included the drewtronics wireless probe or the Silver CNC Infrared Touch probe. The tormach wired probe works, with and without the xoomspeed wireless kit. -All the macros need to be stored in the same file as your posted gcode programs. Always test the macros with MPG DRN the first time. SYIL configurations may change and we're not responsible for broken tips or machine crashes. +All the macros need to be stored in the same file as your posted gcode programs. Always test the macros with MPG DRN the first time. SYIL configurations may change and we're not responsible for broken tips or machine crashes. +This macro set will work for both wired and (some wireless probes) and now supports probes that require special macros to turn on and off. ## Probe Configuration Macro -Every probing routine calls the configuration macro to initialize global variables. -This is contained in `PROBECONFIG` -It allows all probing parameters to be specified in one place. -The probe configuration macro must be opened and customized to your specific needs. - ### Imperial vs Metric units -The various probing parameters must be set in your desired units in the `PROBECONFIG` file. -No other other changes are needed to configure the units. -The default parameters are in inches but comments provide suggested metric values. +The various probing parameters must be set in your desired units sections in the `PROBECONFIG` file. +No other changes are needed to configure the units. +The default parameters are provide as a suggested starting value. ### Customize Settings - Start with the recommended settings and fine tune from there. -Please set your fusion360 probing feed rate to the same value that you use in the config macro. -In you decide to change feed rates, you should always run calibration again. +Please set your fusion 360 probing feed rate to the same value that you use in the config macro. +If you decide to change feed rates, you should always run calibration again. ### Configuration setup +Every probing routine calls the configuration macro to initialize global variables. +This is contained in `PROBECONFIG` +It allows all probing parameters to be specified in one place. + +Using the editor of your choice, open `PROBECONFIG` and update the following parameters: + +- **`@100`** – Set this to the tool number you want to use for your probe. Common choices include Tool 12 or Tool 99. +- **`@111`** – Extended work offset number used to store the Z calibration artifact WCS, aiding in faster recalibration. +- **`@112`** – Extended work offset number used to store the tool setter's XY center location. +- **`@113`** – Extended work offset number used to store the 4th-axis corner probing start point. +- **`@137`** – Highest offset that can be updated, defining a protected WCS range. + > **Note:** Any WCS number from 01-09 should be entered with a leading zero. + +- **`@128`** – Disables extra spindle orientation calls for probes that spin on/off. +- **`@109`** – Calibrated length of your master gauge tool. +- **`@129`** – Calibrated diameter of your ring gauge. + > **These dimensions are critical for calibrating your tool setter and ensuring accurate tool length measurements. Default values are provided, but you should input the exact values from your gauge tool's certificate.** + +- **`@103`, `@104`, `@105`, `@116`, `@117`** – Probing and tool-setting speeds are separated into metric and imperial sections, with safe default values that can be adjusted if needed. + +- **`@106`** – Probe clearance distance. This is the extra distance the probe moves beyond what the macro expects as the edge of the surface. + > *Example:* If probing a circular boss with a specified diameter of 1", the probe will move `[0.5" + @106]` away from the initial point. + +- **`@108`** – Probe backoff distance. Probing routines use a double-touch method: + 1. The first touch is fast. + 2. The second touch is slow (for higher accuracy). + After the first touch, the probe will back off by `@108` (in inches or mm, depending on your control setup). + > This value must be large enough to allow the probe to fully disengage from the surface, plus some clearance, but no larger than necessary. + +- **`@110`** – Default value used when a tolerance argument is required but not provided. +- **`@11`** – Rounding multiplier for many probing messages. Adjust as needed to control the precision of user messages. + +Once you have saved your changes to `PROBECONFIG` copy all files within the **`Macros for controller`** folder to the LNC main NC files directory. + +## Pre-calibration tasks + +### Backup your controller and prep for running the calibration + +1. Backup your tool table, offset table and @10, @11, @100-@117, @127-@133, @980-@987 and @1508 variables in case of wanting to revert +2. Clear as many items as possible from the table to prevent collisions with stock, jigs, fixtures, or vices. +3. Ensure the table zero point or area to place your calibration object is empty, lightly stoned, and free of coolant. +4. Have your master tool, probe, and ring gauge/gauge block ready. + +### Basic Probe Setup + +Before performing any calibration routines your probe must be concentric. +To make your probe concentric you must place a dial indicator on the ruby tip and rotate the probe in the spindle by hand. +Adjust your probe until the dial indicator doesn't move or is within a few tenths. + +![probeIndicate](images/probeIndicate.jpg) -You need to manually set the value of `@100` inthe `PROBECONFIG` file to the tool number you want to use for your probe. -Tool 12 or Tool 99 are common choices. +_Figure 2. Indicating Probe_ + +## toolsetter Calibration -`@106` is the probe clearance distance --- the extra distance the probe will move past what the macro thinks is the edge of the surface. -For example, if you are probing a circular boss and you tell the macro the boss is 1" in diameter then starting from whatever the initial location is, the probe would move `[0.5" + @106]` away from that initial point. +### Basic toolsetter Setup -`@108` is the probe backoff distance --- these probing routines use a double touch method. -The first touch is a fast one. -The second touch is a slow one (for better accuracy). -After the first touch, the probe will back off by `@108` (inches of mm depending on how you have your control setup). -This value needs to be large enough to allow the probe to fully disengage from the surface + some amount of clearance, -but no larger than that. +Before you do any toolsetting, you need to tell the control where the toolsetter is. + +You should manually move your spindle to be located over the center of your toolsetter. +You can do this by eye, using the MPG to drive the gauge tool till it looks centered. +If you want a more precise location, +you can use a dial indicator or coaxial indicator and sweep it around until you are prefectly centered. -`@109` is the calibrated length of your master a gauge tool. -This length is critical in calibrating your tool setter and getting accurate tool lengths using it. -A default of 2.9997 inches is given, -but you really should input the specific value from the certificate of your gague tool. +Once you find your location, you will use the `TEACH IN` function in the offsets page to save that location as +The XY origin of extended work offset set in `@111 PROBECONFIG`. -Reasonable defaults for `@106`, `@108`, and `@109` are provided and you don't need to edit them, but you can. +The toolsetting location will be X0 Y0 in G54 P`@111`. +--- **Macro Syntax** Macros are called with G65 as opposed to M codes to speed up execution. G65 is followed by the macro name and whatever arguments need passed into the macro. The example below shows how to probe the side of a part along the X axis. The A argument is the work offset and the B argument is the probing distance. Each argument starts with a letter followed by a value. For example, a macro requiring three arguments will have A#, B# and C# after the macro name. Simply copy the macro examples into your MDI and adjust the arguments according to your needs. A table mapping the macro arguments to local variables is also provided below. Extended G54 work offsets are supported with the use of a decimal point. For example, G54P5 can be entered into the A argument as G54.5. @@ -67,28 +108,32 @@ Macros are called with G65 as opposed to M codes to speed up execution. G65 is f _Table 1: Macro Syntax and Example_ -Example MDI Command: G65 "PROBEX" A54. B2. +Example MDI Command: G65 "PROBEX" A56. B2. -Example MDI Command: G65 "PROBEX" A54.5 B2. +Example MDI Command: G65 "PROBEX" A54.09 B2. ![lnc_macro_variables](images/lnc_macro_variables.png) _Figure 1. Macro Argument to local variable mapping_ +--- -## Probe Calibration -### Basic Probe Setup +### CALIBRATETOOLSET -Before performing any calibration routines your probe must be concentric. -To make your probe concentric you must place a dial indicator on the ruby tip and rotate the probe in the spindle by hand. -Adjust your probe until the dial indicator doesn't move or is within a few tenths. +This macro will use a master gauge tool to find the trigger height of your tool setter. +Once you have set the G54P100 WCS to locate the tool setter, +you can run this macro with the gauge tool in the spindle to calibrate the tool setter. -The height of your probe can be found using a tool setter if the force to trigger the tool setter is less than the probe. The Syil TTC-200 works with this method. If you don't have a tool setter, you can use a tool of known length and a 123 block. we recommend using a Maritool probe calibrator in this case. +The toolsetter trigger height will be saved to the tool height offset of tool 199. -![probeIndicate](images/probeIndicate.jpg) +| G Code | "Macro Name" | +| --- | --- | +| G65 | "CALIBRATETOOLSET" | -_Figure 2. Indicating Probe_ +Example MDI Command: G65 "CALIBRATETOOLSET" + +## Probe Calibration ### Probe Length Calibration @@ -104,9 +149,9 @@ The important thing is that this reference artifact doesn't change (or you redo | GCode | "Macro Name" | Macro Argument | | --- | --- | --- | -| G65 | "CALIBRATEPROBEZ" | A | +| G65 | "CALIBRATEPROBEZ" | A* | -This macro has an optional argument `A`. +*This macro has an optional argument `A`. By default you can call the macro without any arguments, which does a quick calibration using an stored location/height for the artifact. The first time you call it make sure to include the `A` argument and run the full calibration procedure. @@ -177,10 +222,10 @@ Example MDI Command: G65 "CALIBRATEPROBEBLOCK" A1.0002 B2.0001 C-0.5 #### CALIBRATEPROBERING -This macro uses a ring guage to calibrate the diameter of a probes ruby tip. +This macro uses a ring gauge to calibrate the diameter of a probes ruby tip. It's important that the probe is concentric before beginning. -`A`is the inside diameter of the ring guage. -The probe must be inside of the guage and roughly centered. +`A`is the inside diameter of the ring gauge. +The probe must be inside of the gauge and roughly centered. The routine will set the diameter of your probe tip and the radius can been seen in the tool table. ![CALIBRATEPROBERING](images/probeRingGuage.PNG) @@ -188,41 +233,16 @@ The routine will set the diameter of your probe tip and the radius can been seen _Figure 3. Probe Diameter Calibration_ -| G Code | "Macro Name" | Macro Argument | Macro Argument | -| --- | --- | --- | --- | -| G65 | "CALIBRATEPROBERING" | A | +| G Code | "Macro Name" | Macro Argument | +| --- | --- | --- | +| G65 | "CALIBRATEPROBERING" | A* | _Table 4. Calibrate Probe Radius Syntax_ -Example MDI Command: G65 "CALIBRATEPROBERING" A1.5 - -## Calibrating a toolsetter +*This macro has an optional argument `A`. +By default you can call the macro without any arguments, which pulls the diameter stored in `PROBECONFIG @129` or have the option to over ride -Before you do any toolsetting, you need to tell the control where the toolsetter is. - -You should manually move your spindle to be located over the center of your toolsetter. -You can do this by eye, using the MPG to drive the gauge tool till it looks centered. -If you want a more precise location, -you can use a dial indicator or coaxial indicator and sweep it around untill you are prefectly centered. - -Once you find your location, you will use the `TEACH IN` function in the offsets page to save that location as -The origin for G54P100. -The toolsetting location will be X0 Y0 in G54P100. - - -### CALIBRATETOOLSET - -This macro will use a master gauge tool to find the trigger height of your tool setter. -Once you have set the G54P100 WCS to locate the tool setter, -you can run this macro with the gauge tool in the spindle to calibrate the tool setter. - -The toolsetter trigger height will be saved to the tool height offset of tool 199. - -| G Code | "Macro Name" | -| --- | --- | -| G65 | "CALIBRATETOOLSET" | - -Example MDI Command: G65 "CALIBRATETOOLSET" +Example MDI Command: G65 "CALIBRATEPROBERING" ### FINDCOR @@ -247,7 +267,7 @@ Example MDI Command to run in re-find mode with a larger artifact: G65 "FINDCOR" ### PROBEX The Probe X macro probes the side of a part in the X direction. -`A` is the selected work coordinate(G54-59). +`A` is the selected work coordinate(54-59 or 54.01-54.99). `B` is the distance to probe in X. `B` can be a positive or negative value depending on which side of the stock you would like to probe. If `B` is too small, the macro will report an error at the end of the routine. @@ -262,14 +282,14 @@ _Figure 4. Probe X Routine_ _Table 5. Probe X Syntax_ -Example MDI Command To Probe Right Side: G65 "PROBEX" A54. B-1 +Example MDI Command To Probe Right Side: G65 "PROBEX" A54.0 B-1 -Example MDI Command To Probe Left Side: G65 "PROBEX" A54. B1 +Example MDI Command To Probe Left Side: G65 "PROBEX" A54.0 B1 ### PROBEY The Probe Y macro probes the side of a part in the Y direction. -`A` is the selected work coordinate(G54-59). +`A` is the selected work coordinate(54-59 or 54.01-54.99). `B` is the distance to probe in Y. `B` can be a positive or negative value depending on which side of the stock you would like to probe. If `B` is too small, the macro will report an error at the end of the routine. @@ -284,15 +304,15 @@ _Figure 5. Probe Y Routine_ _Table 6. Probe Y Syntax_ -Example MDI Command To Probe the Front : G65 "PROBEY" A54.2 B1. +Example MDI Command To Probe the Front : G65 "PROBEY" A54.02 B1. -Example MDI Command To Probe the Back : G65 "PROBEY" A54.2 B-1. +Example MDI Command To Probe the Back : G65 "PROBEY" A54.02 B-1. ### PROBEZ The Probe Z macro probes the top surface of a part in the negative Z direction. -`A` is the selected work coordinate(G54-59). +`A` is the selected work coordinate(54-59 or 54.01-54.99). `B` is the distance to probe in Z and should be a negative value. `B` is too small or a positive value, the macro will report an error at the end of the routine. @@ -306,13 +326,13 @@ _Figure 6. Probe Z Routine_ _Table 7. Probe Z Syntax_ -Example MDI Command: G65 "PROBEZ" A54. B-.5 +Example MDI Command: G65 "PROBEZ" A54. B-0.5 ### PROBEXWEB The Probe X Web macro probes two sides of the stock in the X direction and calculates the center. -`A` is the selected work coordinate(G54-59). +`A` is the selected work coordinate(54-59 or 54.01-54.99). `B` is the length of the stock. `C` is the distance the probe should move in Z below the edges of the stock. `Q` enables inspection reporting which pops up a calculated length after the routine finishes. @@ -328,14 +348,14 @@ _Figure 7. Probe X Web Routine_ _Table 8. Probe X Web Syntax_ -Example MDI Command Without Inspection Report: G65 "PROBEXWEB" A54. B3. C-.5 Q0. +Example MDI Command Without Inspection Report: G65 "PROBEXWEB" A54.12 B3. C-.5 Q0. -Example MDI Command With Inspection Report: G65 "PROBEXWEB" A54. B3. C-.5 Q1. +Example MDI Command With Inspection Report: G65 "PROBEXWEB" A54.12 B3. C-.5 Q1. ### PROBEYWEB The Probe Y Web macro probes two sides of the stock in the Y direction and calculates the center. -`A` is the selected work coordinate(G54-59). +`A` is the selected work coordinate(54-59 or 54.01-54.99). `B` is the width of the stock. `C` is the distance the probe should move in Z below the edges of the stock. `Q` enables inspection reporting which pops up a calculated width after the routine finishes. @@ -351,15 +371,15 @@ _Figure 8. Probe Y Web Routine_ _Table 9. Probe Y Web Syntax_ -Example MDI Command Without Inspection Report: G65 "PROBEYWEB" A54. B2. C-.5 Q0. +Example MDI Command Without Inspection Report: G65 "PROBEYWEB" A58. B2. C-.5 Q0. -Example MDI Command With Inspection Report: G65 "PROBEYWEB" A54. B2. C-.5 Q1. +Example MDI Command With Inspection Report: G65 "PROBEYWEB" A58. B2. C-.5 Q1. ### PROBECIRCULARBOSS The Probe Circular Boss macro probes 4 points of a circular boss and calculates the center. -`A` is the selected work coordinate(G54-59). +`A` is the selected work coordinate(54-59 or 54.01-54.99). `B` is the diameter of the stock. `C` is the distance the probe should move in Z below the edges of the stock. `D` turns on a second @@ -375,14 +395,14 @@ _Figure 9. Probe Circular Boss Routine_ _Table 10. Probe Circular Boss Syntax_ -Example MDI Command Without Inspection Report: G65 "PROBECIRCULARBOSS" A54. B2. C-.5 Q0. +Example MDI Command Without Inspection Report: G65 "PROBECIRCULARBOSS" A54.01 B2. C-.5 Q0. -Example MDI Command With Inspection Report: G65 "PROBECIRCULARBOSS" A54. B2. C-.5 Q1. +Example MDI Command With Inspection Report: G65 "PROBECIRCULARBOSS" A54.01 B2. C-.5 Q1. ### PROBEBORE The Probe Bore macro probes 4 points inside of a bore and calculates the center. -`A` is the selected work coordinate(G54-59). +`A` is the selected work coordinate(54-59 or 54.01-54.99). `B` is the diameter of the bore. `Q` enables inspection reporting which pops up a calculated diameter after the routine finishes. The Probe should be roughly centered and inside of the bore before beginning. @@ -397,15 +417,15 @@ _Figure 10. Probe Bore Routine_ _Table 11. Probe Bore Syntax_ -Example MDI Command Without Inspection Reporting: G65 "PROBEBORE" A54. B1. Q0. +Example MDI Command Without Inspection Reporting: G65 "PROBEBORE" A54.02 B1. Q0. -Example MDI Command With Inspection Reporting: G65 "PROBEBORE" A54. B1. Q1. +Example MDI Command With Inspection Reporting: G65 "PROBEBORE" A54.02 B1. Q1. ### PROBERECTANGULARBOSS The Probe Rectangular Boss macro probes all sides of the stock and calculates the center. -`A` is the selected work coordinate(G54-59). +`A` is the selected work coordinate(54-59 or 54.01-54.99). `B` is the length of the boss in X `C` is the width of the boss in Y. `D` is the distance the probe should move in Z below the edges of the bodd and should be a negative value. @@ -431,7 +451,7 @@ Example MDI Command Without Inspect Reporting: G65 "PROBERECTANGULARBOSS" A54. B ### PROBEPOCKET The Probe Pocket macro probes all internal sides of a pocket and calculates the center. -`A` is the selected work coordinate(G54-59). +`A` is the selected work coordinate(54-59 or 54.01-54.99). `B` is the length of the pocket in X `C` is the width of the pocket in Y. `Q` enables inspection reporting which pops up a calculated length and width after the routine finishes. @@ -448,15 +468,15 @@ _Figure 12. Probe Pocket Routine_ _Table 13. Probe Rectangular Pocket Syntax_ -Example MDI Command Without Inspection Reporting: G65 "PROBERECTANGULARPOCKET" A54. B2. C3. Q0. +Example MDI Command Without Inspection Reporting: G65 "PROBERECTANGULARPOCKET" A54.05 B2. C3. Q0. -Example MDI Command Without Inspection Reporting: G65 "PROBERECTANGULARPOCKET" A54. B2. C3. Q1. +Example MDI Command Without Inspection Reporting: G65 "PROBERECTANGULARPOCKET" A54.05 B2. C3. Q1. ### PROBEXSLOT The Probe Slot X macro probes the internal sides of a pocket in the X direction and calculates the center. -`A` is the selected work coordinate(G54-59). +`A` is the selected work coordinate(54-59 or 54.01-54.99). `B` is the length of the pocket in X. `Q` enables inspection reporting which pops up a calculated length after the routine finishes. The Probe should be roughly centered and inside of the slot before beginning. @@ -478,7 +498,7 @@ Example MDI Command Without Inspectioning: G65 "PROBESLOTX" A54. B3. Q1. ### PROBEYSLOT The Probe Slot Y macro probes the internal sides of a pocket in the Y direction and calculates the center. -`A` is the selected work coordinate(G54-59). +`A` is the selected work coordinate(54-59 or 54.01-54.99). `B` is the width of the pocket in Y. `Q` enables inspection reporting which pops up a calculated width after the routine finishes. The Probe should be roughly centered and inside of the slot before beginning. @@ -501,7 +521,7 @@ Example MDI Command With Inspection Reporting: G65 "PROBESLOTY" A54. B3. Q1. ### PROBEOUTSIDECORNER The Probe Outside Corner macro probes the outside edges of the stock and calculates the center. -`A`is the selected work coordinate(G54-59). +`A`is the selected work coordinate(54-59 or 54.01-54.99). `B` Selects the desired corner to probe. `C` is the distance to travel away from the inital location before probing begins. `D` is the probing distance for both X and Y. @@ -523,7 +543,7 @@ Example MDI Command: G65 "PROBEOUTSIDECORNER" A54. B1. C1 D.5 ### PROBEINSIDECORNER The Probe inside Corner macro probes the inside edges of a pocket and calculates the center. -`A` is the selected work coordinate(G54-59). +`A` is the selected work coordinate(54-59 or 54.01-54.99). `B` the desired corner to probe. `C` is the probing distance. The Probe should be roughly centered, diagonaly from the corner before beginning. @@ -562,6 +582,10 @@ Print results is used to support basic inspection. When enabled, the probing rou ![PrintResults](images/print_results.PNG) +All probing operations include an additional post-properties tab that can issue a Q1 argument in applicable probing cycles, forcing a pause to display the results on the screen before proceeding to the next cycle + +![DisplayResults](images/DisplayProbedResults.png) + Zero point compensation is supported and enabled via the post as shown below. Zero point compensation makes probing in fusion easier by allowing you to use a fixed zero point as the work WCS in every setup. When we say zero point, we're reffering to a fixed point on vise or zero point fixture that never moves. All of our operations are in reference to that zero point. The compensation functions by calculating the XY delta between where your workpiece is and where it's expected to be in reference to the zero point. After probing, the work WCS becomes the zero point offset plus the calculated delta. For example if your work WCS is G54, G54 becomes G59 plus the probed XY deltas. Z doesn't change and is always equal to the zero point Z. WCS override must be enabled when using zero point compensation. PROBERECTANGULARBOSS, PROBEPOCKET, PROBECIRCULARBOSS and PROBEBORE all support zero point compensation. ![ZeroPointCompensation](images/zero_point_comp.PNG) @@ -598,7 +622,7 @@ Both the load and unload macros have the option to set the tool gauge length to | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | -| G65 | "LOADTOOL" | T | O | M | +| G65 | "LOADTOOL" | T | O* | M* | Example MDI Command: G65 "LOADTOOL" T10 O12 From 6e26f856a461420862e0dcf460bf55f19118df89 Mon Sep 17 00:00:00 2001 From: Robot Oblivion Date: Thu, 3 Apr 2025 01:54:43 +1300 Subject: [PATCH 13/21] PROBECONFIG - Slight reordering to improve clarity for new users, making essential settings easier to find. - Moved gauge lengths into common offsets. - Added gauge block size for future use. CALIBRATEPROBERING - Added an override for the ring gauge A argument. ProbingConfigHelper.NC - Reordered prep list to align with a method found to be faster and more consistent. Syil_LNC_RobotOblivion - updated menu for the word results to avoid confusion with a saved or printed inspection report. --- .../Syil_LNC_RobotOblivion.cps | 2 +- Helpful NC Programs/probingSetupHelp_v0.1.nc | 10 ++--- Macros for Controller/CALIBRATEPROBERING | 9 +++- Macros for Controller/PROBECONFIG | 43 ++++++++++--------- 4 files changed, 36 insertions(+), 28 deletions(-) diff --git a/Fusion Posts & Machine Model/Syil_LNC_RobotOblivion.cps b/Fusion Posts & Machine Model/Syil_LNC_RobotOblivion.cps index 08d875e..52446af 100644 --- a/Fusion Posts & Machine Model/Syil_LNC_RobotOblivion.cps +++ b/Fusion Posts & Machine Model/Syil_LNC_RobotOblivion.cps @@ -224,7 +224,7 @@ properties = { scope : "post" }, probeScreenPrint: { - title : "Display probed report", + title : "Display probed results", description: "Enable inspection reporting in compatible cycles to pause after probing and display the results at the control", group : "multiAxis", type : "boolean", diff --git a/Helpful NC Programs/probingSetupHelp_v0.1.nc b/Helpful NC Programs/probingSetupHelp_v0.1.nc index a9133ca..379dfcb 100644 --- a/Helpful NC Programs/probingSetupHelp_v0.1.nc +++ b/Helpful NC Programs/probingSetupHelp_v0.1.nc @@ -5,14 +5,14 @@ ; Initial Coding: Robot Oblivion ; Before running, ensure the following: -; - backup your tool table, offset table and @1-200 variables in case of wanting to revert -; - Clear as many items as possible from the table to prevent collisions with stock, jigs, fixtures, or vices. -; - Ensure the table zero point is empty, lightly stoned, and free of coolant. -; - Have your master tool, probe, and ring gauge ready. +; - backup your tool table, offset table and @10, @11, @100-@117, @127-@133, @980-@987 and @1508 variables in case of wanting to revert ; - Set all user inputs in the ProbeConfig file. ; - copy all macro files CNC control +; - Clear as many items as possible from the table to prevent collisions with stock, jigs, fixtures, or vices. +; - Ensure the table zero point is empty, lightly stoned, and free of coolant. +; - Find the tool setter's centre and store this location to the extended work offset chosen in @111 PROBECONFIG. ; - Copy the table zero point (XYZ) offsets to the extended work offsets that will store the calibration artifact location. -; - Find the tool setter's centre and zero out the extended work offsets that will store this location. +; - Have your master tool, probe, and ring gauge ready. G65 "PROBECONFIG" T1 diff --git a/Macros for Controller/CALIBRATEPROBERING b/Macros for Controller/CALIBRATEPROBERING index 999a865..c5feed6 100644 --- a/Macros for Controller/CALIBRATEPROBERING +++ b/Macros for Controller/CALIBRATEPROBERING @@ -5,6 +5,8 @@ // Your probe must be concentric and you must use a ring guage!!!!!!!!!! // **Ring gauge ID set in ProbeConfig file +// Argument A -> #1 is optional and the expected inside diameter of the ring guage. Will over ride value in ProbeConfig if called + // Initial coding 1/14/2024: Joshua Smith // Modified 31/03/2025: Robot Oblivion @@ -15,8 +17,13 @@ M19 // ORIENT SPINDLE // important local variables #100 = @100 // TOOL NUMBER PROVIDED BY PROBECONFIG MACRO -#129 = @129 // Calibrated ring gauge diameter provided by PROBECONFIG MACRO +#129 = @129 // Calibrated ring gauge diameter provided by PROBECONFIG MACRO +// Over ride probeConfig gauge ID A argument used +IF [#1 != #0] + #129 = #1 +END_IF + // Make sure diameter is zero when calibrating W_TOOL_DATA[0,#100,3,0] // store tool diameter diff --git a/Macros for Controller/PROBECONFIG b/Macros for Controller/PROBECONFIG index 9b0465c..6928aab 100644 --- a/Macros for Controller/PROBECONFIG +++ b/Macros for Controller/PROBECONFIG @@ -9,39 +9,33 @@ // Initial Coding 1/25/2024: Joshua Smith // Modified 31/03/2025: Robot Oblivion -// important global variables -@100 = -1 // PROBE TOOL NUMBER, EX: 99 - -IF [@100==-1] - ALARM["Hard code probe number in PROBECONFIG macro"] -END_IF - -@10 = R_G_GROUP[0,6] // Metric or freedom units check, DO NOT TOUCH!!! -@101 = R_TOOL_DATA[0,@100,3] // TOOL DIAMETER, DO NOT TOUCH!!! -@102 = @101/2 // TOOL RADIUS, DO NOT TOUCH!!! -@107 = [R_TOOL_DATA[0,@100,203]] // TOOL LENGHT OFFSET, DO NOT TOUCH!!! +// DO NOT TOUCH!!! Metric or freedom units check +@10 = R_G_GROUP[0,6] +// important global variables to update below: +@100 = -1 // PROBE TOOL NUMBER, EX: 99 @111 = 97 // EXTENDED WORKOFFSET TO STORE PROBE Z CALIBRATION LOCATION @112 = 98 // EXTENDED WORKOFFSET TO STORE TOOLSETTER LOCATION @113 = 99 // EXTENDED WORKOFFSET TO STORE THE 4TH COR PROBING START POINT -@110 = 1.0 // DEFAULT POSITION TOLERANCE -@128 = 0 // ORIENT SPINDLE SWITCH 0=OFF 1=ON #137 = 95 // The highest WCS that can be used. Any above are protected from changes via these macros +@128 = 0 // ORIENT SPINDLE SWITCH 0=OFF 1=ON +@109 = 93.896 // CALIBRATED LENGTH OF YOUR MASTER GAUGE TOOL +@129 = 24.998 // Calibrated diameter of the master ring gauge tool +// @130 = 50.000 // Calibrated X size of gauge block +// @131 = 25.000 // Calibrated Y size of gauge block // metric settings IF[@10 == 21] @103 = 2500 // FEED SPEED mm/m, @104 = 1250 // FAST PROBE SPEED mm/m, @105 = 60 // SLOW PROBE SPEED mm/m, - @106 = 10 // PROBE CLEARANCE DISTANCE mm, + @106 = 10 // PROBE CLEARANCE DISTANCE mm, @108 = 2 // PROBE BACKOFF DISTANCE mm, - - @109 = 93.896 // CALIBRATED LENGTH OF YOUR MASTER GAUGE TOOL - @129 = 24.998 // Calibrated diameter of the master ring gauge tool @110 = 1.0 // DEFAULT PART TOLERANCE - + @117 = 750 // FAST Tool Probe SPEED mm/m, @116 = 40 // SLOW Tool Probe SPEED mm/m, + @11 = 1000 // rounding multiplier for 3 decimal places END_IF; @@ -53,15 +47,22 @@ IF[@10 == 20] @106 = 0.5 // PROBE CLEARANCE DISTANCE in, @108 = 0.125 // PROBE BACKOFF DISTANCE, - @109 = 2.9997 // CALIBRATED LENGTH OF YOUR MASTER GAUGE TOOL - @129 = 0.9999 // Calibrated diameter of the master ring gauge tool @110 = 0.05 // DEFAULT PART TOLERANCE @117 = 30 // FAST Tool Probe SPEED in/m, @116 = 1.5 // SLOW Tool Probe SPEED in/m, - @11 = 10000 // rounding multiplier for 4 decimal places + + @11 = 10000 // rounding multiplier for 4 decimal places END_IF; +@101 = R_TOOL_DATA[0,@100,3] // TOOL DIAMETER, DO NOT TOUCH!!! +@102 = @101/2 // TOOL RADIUS, DO NOT TOUCH!!! +@107 = [R_TOOL_DATA[0,@100,203]] // TOOL LENGHT OFFSET, DO NOT TOUCH!!! + +IF [@100==-1] + ALARM["Hard code probe number in PROBECONFIG macro"] +END_IF + #120=R_SYS_INFO[0,2] // CURRENT TOOL NUMBER IF [@100 != #120 && #20==#0] // THE PROBE IS NOT LOADED ALARM["Error: Protected move without probe - change to T#100 "] From 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 Mon Sep 17 00:00:00 2001 From: Jestah Carnie Date: Thu, 3 Apr 2025 14:37:45 +1300 Subject: [PATCH 14/21] second pass at an updated README.md Second pass picking up a few small issues and adding a bit of colour and layout styling for ease of reading --- README.md | 401 +++++++++++++++++++++++++++++------------------------- 1 file changed, 218 insertions(+), 183 deletions(-) diff --git a/README.md b/README.md index c5f2fd9..1f7051d 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,6 @@ The tormach wired probe works, with and without the xoomspeed wireless kit. All the macros need to be stored in the same file as your posted gcode programs. Always test the macros with MPG DRN the first time. SYIL configurations may change and we're not responsible for broken tips or machine crashes. This macro set will work for both wired and (some wireless probes) and now supports probes that require special macros to turn on and off. -## Probe Configuration Macro - ### Imperial vs Metric units The various probing parameters must be set in your desired units sections in the `PROBECONFIG` file. No other changes are needed to configure the units. @@ -27,55 +25,73 @@ Start with the recommended settings and fine tune from there. Please set your fusion 360 probing feed rate to the same value that you use in the config macro. If you decide to change feed rates, you should always run calibration again. -### Configuration setup +## Probe Configuration + +### Configuration Macro setup Every probing routine calls the configuration macro to initialize global variables. This is contained in `PROBECONFIG` It allows all probing parameters to be specified in one place. -Using the editor of your choice, open `PROBECONFIG` and update the following parameters: +Using the editor of your choice, in the **`Macros for controller`** folder open `PROBECONFIG` and update the following parameters: -- **`@100`** – Set this to the tool number you want to use for your probe. Common choices include Tool 12 or Tool 99. -- **`@111`** – Extended work offset number used to store the Z calibration artifact WCS, aiding in faster recalibration. -- **`@112`** – Extended work offset number used to store the tool setter's XY center location. -- **`@113`** – Extended work offset number used to store the 4th-axis corner probing start point. -- **`@137`** – Highest offset that can be updated, defining a protected WCS range. - > **Note:** Any WCS number from 01-09 should be entered with a leading zero. +**`@100`** – Set this to the tool number you want to use for your probe. Common choices include Tool 12 or Tool 99. +**`@111`** – Extended work offset number used to store the Z calibration artifact WCS, aiding in faster recalibration. +**`@112`** – Extended work offset number used to store the tool setter's XY center location. +**`@113`** – Extended work offset number used to store the 4th-axis corner probing start point. +**`@137`** – Highest offset that can be updated, defining a protected WCS range. +> [!NOTE] +> Extended WCS numbers G54 P01-09 require a leading zero -- **`@128`** – Disables extra spindle orientation calls for probes that spin on/off. -- **`@109`** – Calibrated length of your master gauge tool. -- **`@129`** – Calibrated diameter of your ring gauge. - > **These dimensions are critical for calibrating your tool setter and ensuring accurate tool length measurements. Default values are provided, but you should input the exact values from your gauge tool's certificate.** +**`@128`** – Disables extra spindle orientation calls for probes that spin on/off. +**`@109`** – Calibrated length of your master gauge tool. +**`@129`** – Calibrated diameter of your ring gauge. +> [!IMPORTANT] +> These dimensions are critical for calibrating your tool setter and ensuring accurate tool length measurements. +> Default values are provided, but you should input the exact values from your gauge tool's certificate. -- **`@103`, `@104`, `@105`, `@116`, `@117`** – Probing and tool-setting speeds are separated into metric and imperial sections, with safe default values that can be adjusted if needed. +**`@103`, `@104`, `@105`, `@116`, `@117`** – Probing and tool-setting speeds are separated into metric and imperial sections, with safe default values that can be adjusted if needed. -- **`@106`** – Probe clearance distance. This is the extra distance the probe moves beyond what the macro expects as the edge of the surface. +**`@106`** – Probe clearance distance. This is the extra distance the probe moves beyond what the macro expects as the edge of the surface. > *Example:* If probing a circular boss with a specified diameter of 1", the probe will move `[0.5" + @106]` away from the initial point. -- **`@108`** – Probe backoff distance. Probing routines use a double-touch method: +**`@108`** – Probe backoff distance. Probing routines use a double-touch method: 1. The first touch is fast. 2. The second touch is slow (for higher accuracy). After the first touch, the probe will back off by `@108` (in inches or mm, depending on your control setup). > This value must be large enough to allow the probe to fully disengage from the surface, plus some clearance, but no larger than necessary. -- **`@110`** – Default value used when a tolerance argument is required but not provided. -- **`@11`** – Rounding multiplier for many probing messages. Adjust as needed to control the precision of user messages. +**`@110`** – Default value used when a tolerance argument is required but not provided. +**`@11`** – Rounding multiplier for many probing messages. Adjust as needed to control the precision of user messages. + +> [!TIP] +> Once you have saved your changes to `PROBECONFIG` copy all files within the **`Macros for controller`** folder to the LNC main NC files directory. -Once you have saved your changes to `PROBECONFIG` copy all files within the **`Macros for controller`** folder to the LNC main NC files directory. -## Pre-calibration tasks +## **Backup and Preparation for Calibration** -### Backup your controller and prep for running the calibration +Before running the calibration process, follow these steps to ensure a smooth setup: -1. Backup your tool table, offset table and @10, @11, @100-@117, @127-@133, @980-@987 and @1508 variables in case of wanting to revert -2. Clear as many items as possible from the table to prevent collisions with stock, jigs, fixtures, or vices. -3. Ensure the table zero point or area to place your calibration object is empty, lightly stoned, and free of coolant. -4. Have your master tool, probe, and ring gauge/gauge block ready. +1. **Backup Your Controller Data:** + - Save a copy of your tool table, offset table, and the following variables in case you need to revert: + `@10`, `@11`, `@100-@117`, `@127-@133`, `@980-@987`, `@1508` +2. **Prepare the Work Area:** + - Clear as many items as possible from the table to avoid collisions with stock, jigs, fixtures, or vices. + - Ensure the table zero point or the area where you will place the calibration object is **empty, lightly stoned, and free of coolant**. + +3. **Gather Required Tools:** + - Have your **master tool, probe, and ring gauge/gauge block** ready. -### Basic Probe Setup +### **Basic Probe Setup** + +Before running any calibration routines, you must ensure that your probe is concentric. + +. **Check Concentricity:** + - Place a **dial indicator** on the ruby tip of the probe. + - Rotate the probe in the spindle **by hand** while observing the dial indicator. -Before performing any calibration routines your probe must be concentric. -To make your probe concentric you must place a dial indicator on the ruby tip and rotate the probe in the spindle by hand. -Adjust your probe until the dial indicator doesn't move or is within a few tenths. +. **Adjust the Probe:** + - Adjust the probe until the dial indicator **does not move** or shows deviation within a few tenths. + - This step is crucial for accurate probing results. ![probeIndicate](images/probeIndicate.jpg) @@ -85,22 +101,28 @@ _Figure 2. Indicating Probe_ ### Basic toolsetter Setup -Before you do any toolsetting, you need to tell the control where the toolsetter is. +Before performing any tool setting, you must define the tool setter's location in the control system. -You should manually move your spindle to be located over the center of your toolsetter. -You can do this by eye, using the MPG to drive the gauge tool till it looks centered. -If you want a more precise location, -you can use a dial indicator or coaxial indicator and sweep it around until you are prefectly centered. + A. **If the tool setter's location is known**, copy its XY offset to the extended work offset specified in `PROBECONFIG @112`. -Once you find your location, you will use the `TEACH IN` function in the offsets page to save that location as -The XY origin of extended work offset set in `@111 PROBECONFIG`. + B. **If the tool setter's location is unknown, manually position the spindle over its center:** + - Use the MPG to move the gauge tool until it appears centered by eye. + - For higher precision, use a dial indicator or coaxial indicator to sweep around until perfectly centered. -The toolsetting location will be X0 Y0 in G54 P`@111`. + B. **Once the correct location is found, save it using the `TEACH IN` function** in the offsets page. + - Store this location as the XY origin of the extended work offset specified in `PROBECONFIG @112`. + +> [!TIP] +>The toolsetting location will be X0 Y0 in G54 P`@112`. --- -**Macro Syntax** +## **Macro Syntax** + +Macros are called with G65 as opposed to M codes to speed up execution. G65 is followed by the macro name and whatever arguments need passed into the macro. The example below shows how to probe the side of a part along the X axis. The A argument is the work offset and the B argument is the probing distance. Each argument starts with a letter followed by a value. For example, a macro requiring three arguments will have A#, B# and C# after the macro name. Simply copy the macro examples into your MDI and adjust the arguments according to your needs. A table mapping the macro arguments to local variables is also provided below. -Macros are called with G65 as opposed to M codes to speed up execution. G65 is followed by the macro name and whatever arguments need passed into the macro. The example below shows how to probe the side of a part along the X axis. The A argument is the work offset and the B argument is the probing distance. Each argument starts with a letter followed by a value. For example, a macro requiring three arguments will have A#, B# and C# after the macro name. Simply copy the macro examples into your MDI and adjust the arguments according to your needs. A table mapping the macro arguments to local variables is also provided below. Extended G54 work offsets are supported with the use of a decimal point. For example, G54P5 can be entered into the A argument as G54.5. +> [!IMPORTANT] +> Extended G54 work offsets are supported with the use of a decimal point. +> For example, G54 P5 can be entered into the A argument as **A54.05** (_G54 P01-09 require a leading zero_). | G Code | "Macro Name" | Macro Argument | Macro Argument | | --- | --- | --- | --- | @@ -154,7 +176,8 @@ The important thing is that this reference artifact doesn't change (or you redo *This macro has an optional argument `A`. By default you can call the macro without any arguments, which does a quick calibration using an stored location/height for the artifact. -The first time you call it make sure to include the `A` argument and run the full calibration procedure. +> [!IMPORTANT] +> The first time you call it make sure to include the `A` argument and run the full calibration procedure. ### Full Probe Z Height Calibration @@ -186,9 +209,7 @@ Once you have done the full calibration one time, you can use a quick version of the macro to recalibrate the probe offset without the need to use the master tool. But you must re-install your calibration artifact onto your table before calling this macro. -This will move the table to the origin of the saved WCS (default is G54P99) and then do a protected move to calibrate the probe offset. - - +This will move the table to the origin of the saved WCS specified in (`PROBECONFIG @111`) and then do a protected move to calibrate the probe offset. ### Probe Tip Diameter Calibration @@ -204,10 +225,10 @@ It's important that the probe is concentric before beginning. Any good quality reference block artifact would be used, such as an actual gauge block or a high quality 123 block. If you are not using a calibrated reference artifact, you should use a well calibrated micrometer to measure your 123 block to get its true dimensions. 123 blocks, even high quality ones, are commonly sold a few ten thousandths of an inch oversized to allow for lapping -and you want to put the true dimension into the macro arguments. -`A` is the gauge block's true X dimension -`B` is the gauge block's true Y dimension -`C` is the amount of Z drop you want between your initial position and the measurement height. It needs to be a negative value. +and you want to put the true dimension into the macro arguments. +`A` is the gauge block's true X dimension +`B` is the gauge block's true Y dimension +`C` is the amount of Z drop you want between your initial position and the measurement height. It needs to be a negative value. ![CALIBRATEPROBEBLOCK](images/calibrateprobeblock.png) @@ -222,11 +243,9 @@ Example MDI Command: G65 "CALIBRATEPROBEBLOCK" A1.0002 B2.0001 C-0.5 #### CALIBRATEPROBERING -This macro uses a ring gauge to calibrate the diameter of a probes ruby tip. -It's important that the probe is concentric before beginning. -`A`is the inside diameter of the ring gauge. -The probe must be inside of the gauge and roughly centered. -The routine will set the diameter of your probe tip and the radius can been seen in the tool table. +This macro uses a ring gauge to calibrate the diameter of a probes ruby tip. It's important that the probe is concentric before beginning. The probe must be inside of the gauge and roughly centered. The routine will set the diameter of your probe tip and the radius can been seen in the tool table. + +`A`is the inside diameter of the ring gauge. ![CALIBRATEPROBERING](images/probeRingGuage.PNG) @@ -239,8 +258,7 @@ _Figure 3. Probe Diameter Calibration_ _Table 4. Calibrate Probe Radius Syntax_ -*This macro has an optional argument `A`. -By default you can call the macro without any arguments, which pulls the diameter stored in `PROBECONFIG @129` or have the option to over ride +*This macro has an optional argument `A`. By default, you can call the macro without any arguments, which pulls the diameter stored in `PROBECONFIG @129` or have the option to override Example MDI Command: G65 "CALIBRATEPROBERING" @@ -251,13 +269,13 @@ It has two run modes: one where you set the probing location, and once where the | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | -| G65 | "FINDCOR" | A | W | S | +| G65 | "FINDCOR" | A | W | S* | -The `A` argument lists the WCS to save the COR into. -The `W` argument is optional, but sets the width of the reference artifact. The default value is 1.0. -The `S` argument is optional, and determines which mode the macro runs in. -If not provided, then the macro uses the saved probing location to re-find the COR regardless of where the A axis or probe is located when starting the macro. -If provided, then the probe's initial location is saved before running the macro. +The `A` argument lists the WCS to save the COR into. +The `W` argument is optional, but sets the width of the reference artifact. The default value is 1.0. +*The `S` argument is optional, and determines which mode the macro runs in. + - If not provided, then the macro uses the saved probing location to re-find the COR regardless of where the A axis or probe is located when starting the macro. + - If provided, then the probe's initial location is saved before running the macro. Example MDI Command to run in saving mode: G65 "FINDCOR" A58. S1.0 Example MDI Command to run in re-find mode with a larger artifact: G65 "FINDCOR" A58. W2.0 @@ -266,77 +284,82 @@ Example MDI Command to run in re-find mode with a larger artifact: G65 "FINDCOR" ### PROBEX -The Probe X macro probes the side of a part in the X direction. -`A` is the selected work coordinate(54-59 or 54.01-54.99). -`B` is the distance to probe in X. -`B` can be a positive or negative value depending on which side of the stock you would like to probe. -If `B` is too small, the macro will report an error at the end of the routine. +The Probe X macro probes the side of a part in the X direction. + +`A` is the selected work coordinate (54-59 or 54.01-54.99). +`B` is the distance to probe in X. +`B` can be a positive or negative value depending on which side of the stock you would like to probe. + - If `B` is too small, the macro will report an error at the end of the routine. ![probeX](images/probeX.png) -_Figure 4. Probe X Routine_ +_Figure 4. Probe X Routine_ | G Code | "Macro Name" | Macro Argument | Macro Argument | | --- | --- | --- | --- | | G65 | "PROBEX" | A | B | -_Table 5. Probe X Syntax_ +_Table 5. Probe X Syntax_ -Example MDI Command To Probe Right Side: G65 "PROBEX" A54.0 B-1 +Example MDI Command To Probe Right Side: G65 "PROBEX" A54.0 B-1 -Example MDI Command To Probe Left Side: G65 "PROBEX" A54.0 B1 +Example MDI Command To Probe Left Side: G65 "PROBEX" A54.0 B1 +*** ### PROBEY -The Probe Y macro probes the side of a part in the Y direction. -`A` is the selected work coordinate(54-59 or 54.01-54.99). -`B` is the distance to probe in Y. -`B` can be a positive or negative value depending on which side of the stock you would like to probe. -If `B` is too small, the macro will report an error at the end of the routine. +The Probe Y macro probes the side of a part in the Y direction. + +`A` is the selected work coordinate (54-59 or 54.01-54.99). +`B` is the distance to probe in Y. +`B` can be a positive or negative value depending on which side of the stock you would like to probe. + - If `B` is too small, the macro will report an error at the end of the routine. ![probeY](images/probeY.png) -_Figure 5. Probe Y Routine_ +_Figure 5. Probe Y Routine_ | G Code | "Macro Name" | Macro Argument | Macro Argument | | --- | --- | --- | --- | | G65 | "PROBEY" | A | B | -_Table 6. Probe Y Syntax_ - -Example MDI Command To Probe the Front : G65 "PROBEY" A54.02 B1. +_Table 6. Probe Y Syntax_ -Example MDI Command To Probe the Back : G65 "PROBEY" A54.02 B-1. +Example MDI Command To Probe the Front: G65 "PROBEY" A54.02 B1. +Example MDI Command To Probe the Back : G65 "PROBEY" A54.02 B-1. +*** ### PROBEZ -The Probe Z macro probes the top surface of a part in the negative Z direction. -`A` is the selected work coordinate(54-59 or 54.01-54.99). -`B` is the distance to probe in Z and should be a negative value. -`B` is too small or a positive value, the macro will report an error at the end of the routine. +The Probe Z macro probes the top surface of a part in the negative Z direction. + +`A` is the selected work coordinate (54-59 or 54.01-54.99). +`B` is the distance to probe in Z and should be a negative value. + - `B` is too small or a positive value, the macro will report an error at the end of the routine. ![probeZ](images/probeZ.png) -_Figure 6. Probe Z Routine_ +_Figure 6. Probe Z Routine_ | G Code | "Macro Name" | Macro Argument | Macro Argument | | --- | --- | --- | --- | | G65 | "PROBEZ" | A | B | -_Table 7. Probe Z Syntax_ - -Example MDI Command: G65 "PROBEZ" A54. B-0.5 +_Table 7. Probe Z Syntax_ +Example MDI Command: G65 "PROBEZ" A54. B-0.5 +*** ### PROBEXWEB -The Probe X Web macro probes two sides of the stock in the X direction and calculates the center. -`A` is the selected work coordinate(54-59 or 54.01-54.99). -`B` is the length of the stock. -`C` is the distance the probe should move in Z below the edges of the stock. -`Q` enables inspection reporting which pops up a calculated length after the routine finishes. -The Probe should be roughly centered and above the stock before beginning. +The Probe X Web macro probes two sides of the stock in the X direction and calculates the center. + +`A` is the selected work coordinate (54-59 or 54.01-54.99). +`B` is the length of the stock. +`C` is the distance the probe should move in Z below the edges of the stock. +`Q` enables inspection reporting, which pops up a calculated length after the routine finishes. + - The Probe should be roughly centered and above the stock before beginning. ![probeXweb](images/probeXweb.png) @@ -351,87 +374,93 @@ _Table 8. Probe X Web Syntax_ Example MDI Command Without Inspection Report: G65 "PROBEXWEB" A54.12 B3. C-.5 Q0. Example MDI Command With Inspection Report: G65 "PROBEXWEB" A54.12 B3. C-.5 Q1. - +*** + ### PROBEYWEB -The Probe Y Web macro probes two sides of the stock in the Y direction and calculates the center. -`A` is the selected work coordinate(54-59 or 54.01-54.99). -`B` is the width of the stock. -`C` is the distance the probe should move in Z below the edges of the stock. -`Q` enables inspection reporting which pops up a calculated width after the routine finishes. -The Probe should be roughly centered and above the stock before beginning. +The Probe Y Web macro probes two sides of the stock in the Y direction and calculates the center. + +`A` is the selected work coordinate (54-59 or 54.01-54.99). +`B` is the width of the stock. +`C` is the distance the probe should move in Z below the edges of the stock. +`Q` enables inspection reporting which pops up a calculated width after the routine finishes. + - The Probe should be roughly centered and above the stock before beginning. ![probeYweb](images/probeYweb.png) -_Figure 8. Probe Y Web Routine_ +_Figure 8. Probe Y Web Routine_ | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | --- | | G65 | "PROBEYWEB" | A | B | C | Q | -_Table 9. Probe Y Web Syntax_ +_Table 9. Probe Y Web Syntax_ -Example MDI Command Without Inspection Report: G65 "PROBEYWEB" A58. B2. C-.5 Q0. - -Example MDI Command With Inspection Report: G65 "PROBEYWEB" A58. B2. C-.5 Q1. +Example MDI Command Without Inspection Report: G65 "PROBEYWEB" A58. B2. C-.5 Q0. +Example MDI Command With Inspection Report: G65 "PROBEYWEB" A58. B2. C-.5 Q1. +*** ### PROBECIRCULARBOSS -The Probe Circular Boss macro probes 4 points of a circular boss and calculates the center. -`A` is the selected work coordinate(54-59 or 54.01-54.99). -`B` is the diameter of the stock. -`C` is the distance the probe should move in Z below the edges of the stock. -`D` turns on a second -`Q` enables inspection reporting which pops up a calculated diameter after the routine finishes. The Probe should be roughly centered and above the stock before beginning. +The Probe Circular Boss macro probes 4 points of a circular boss and calculates the center. + +`A` is the selected work coordinate (54-59 or 54.01-54.99). +`B` is the diameter of the stock. +`C` is the distance the probe should move in Z below the edges of the stock. +`D` turns on a second +`Q` enables inspection reporting, which pops up a calculated diameter after the routine finishes. + - The Probe should be roughly centered and above the stock before beginning. ![probeCircularBoss](images/probeCircularBoss.png) -_Figure 9. Probe Circular Boss Routine_ +_Figure 9. Probe Circular Boss Routine_ | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | --- | | G65 | "PROBECIRCULARBOSS" | A | B | C | Q | -_Table 10. Probe Circular Boss Syntax_ +_Table 10. Probe Circular Boss Syntax_ -Example MDI Command Without Inspection Report: G65 "PROBECIRCULARBOSS" A54.01 B2. C-.5 Q0. +Example MDI Command Without Inspection Report: G65 "PROBECIRCULARBOSS" A54.01 B2. C-.5 Q0. + +Example MDI Command With Inspection Report: G65 "PROBECIRCULARBOSS" A54.01 B2. C-.5 Q1. +*** -Example MDI Command With Inspection Report: G65 "PROBECIRCULARBOSS" A54.01 B2. C-.5 Q1. - ### PROBEBORE -The Probe Bore macro probes 4 points inside of a bore and calculates the center. -`A` is the selected work coordinate(54-59 or 54.01-54.99). -`B` is the diameter of the bore. -`Q` enables inspection reporting which pops up a calculated diameter after the routine finishes. -The Probe should be roughly centered and inside of the bore before beginning. +The Probe Bore macro probes 4 points inside a bore and calculates the center. + +`A` is the selected work coordinate (54-59 or 54.01-54.99). +`B` is the diameter of the bore. +`Q` enables inspection reporting, which pops up a calculated diameter after the routine finishes. + - The Probe should be roughly centered and inside the bore before beginning. ![probeBore](images/probeBore.png) -_Figure 10. Probe Bore Routine_ +_Figure 10. Probe Bore Routine_ | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | | G65 | "PROBEBORE" | A | B | Q | -_Table 11. Probe Bore Syntax_ +_Table 11. Probe Bore Syntax_ -Example MDI Command Without Inspection Reporting: G65 "PROBEBORE" A54.02 B1. Q0. - -Example MDI Command With Inspection Reporting: G65 "PROBEBORE" A54.02 B1. Q1. +Example MDI Command Without Inspection Reporting: G65 "PROBEBORE" A54.02 B1. Q0. +Example MDI Command With Inspection Reporting: G65 "PROBEBORE" A54.02 B1. Q1. +*** ### PROBERECTANGULARBOSS The Probe Rectangular Boss macro probes all sides of the stock and calculates the center. -`A` is the selected work coordinate(54-59 or 54.01-54.99). -`B` is the length of the boss in X -`C` is the width of the boss in Y. -`D` is the distance the probe should move in Z below the edges of the bodd and should be a negative value. -`Q` enables inspection reporting which pops up a calculated length and width after the routine finishes. -The Probe should be roughly centered and above the stock before beginning. +`A` is the selected work coordinate (54-59 or 54.01-54.99). +`B` is the length of the boss in X +`C` is the width of the boss in Y. +`D` is the distance the probe should move in Z below the edges of the body and should be a negative value. +`Q` enables inspection reporting, which pops up a calculated length and width after the routine finishes. + - The Probe should be roughly centered and above the stock before beginning. ![probeRectangularBoss](images/probeRectangularBoss.png) @@ -443,89 +472,93 @@ _Figure 11. Probe Rectangular Boss Routine_ _Table 12. Probe Rectangular Boss Syntax_ -Example MDI Command Without Inspect Reporting: G65 "PROBERECTANGULARBOSS" A54. B3. C2. D-.5 Q0. - -Example MDI Command Without Inspect Reporting: G65 "PROBERECTANGULARBOSS" A54. B3. C2. D-.5 Q1. +Example MDI Command Without Inspect Reporting: G65 "PROBERECTANGULARBOSS" A54. B3. C2. D-.5 Q0. +Example MDI Command Without Inspect Reporting: G65 "PROBERECTANGULARBOSS" A54. B3. C2. D-.5 Q1. +*** ### PROBEPOCKET -The Probe Pocket macro probes all internal sides of a pocket and calculates the center. -`A` is the selected work coordinate(54-59 or 54.01-54.99). -`B` is the length of the pocket in X -`C` is the width of the pocket in Y. -`Q` enables inspection reporting which pops up a calculated length and width after the routine finishes. +The Probe Pocket macro probes all internal sides of a pocket and calculates the center. -The Probe should be roughly centered and inside of the pocket before beginning. +`A` is the selected work coordinate (54-59 or 54.01-54.99). +`B` is the length of the pocket in X +`C` is the width of the pocket in Y. +`Q` enables inspection reporting, which pops up a calculated length and width after the routine finishes. + - The Probe should be roughly centered and inside the pocket before beginning. ![probeRectangularPocket](images/probeRectangularPocket.png) -_Figure 12. Probe Pocket Routine_ +_Figure 12. Probe Pocket Routine_ | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | --- | | G65 | "PROBEPOCKET" | A | B | C | Q | -_Table 13. Probe Rectangular Pocket Syntax_ +_Table 13. Probe Rectangular Pocket Syntax_ -Example MDI Command Without Inspection Reporting: G65 "PROBERECTANGULARPOCKET" A54.05 B2. C3. Q0. - -Example MDI Command Without Inspection Reporting: G65 "PROBERECTANGULARPOCKET" A54.05 B2. C3. Q1. +Example MDI Command Without Inspection Reporting: G65 "PROBERECTANGULARPOCKET" A54.05 B2. C3. Q0. +Example MDI Command Without Inspection Reporting: G65 "PROBERECTANGULARPOCKET" A54.05 B2. C3. Q1. +*** ### PROBEXSLOT -The Probe Slot X macro probes the internal sides of a pocket in the X direction and calculates the center. -`A` is the selected work coordinate(54-59 or 54.01-54.99). -`B` is the length of the pocket in X. -`Q` enables inspection reporting which pops up a calculated length after the routine finishes. -The Probe should be roughly centered and inside of the slot before beginning. +The Probe Slot X macro probes the internal sides of a pocket in the X direction and calculates the center. + +`A` is the selected work coordinate (54-59 or 54.01-54.99). +`B` is the length of the pocket in X. +`Q` enables inspection reporting, which pops up a calculated length after the routine finishes. + - The Probe should be roughly centered and inside the slot before beginning. ![probeSlot](images/probeSlot.png) -_Figure 13. Probe Slot Routine_ +_Figure 13. Probe Slot Routine_ | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | | G65 | "PROBESLOTX" | A | B | Q | -_Table 14. Probe Slot Syntax_ +_Table 14. Probe Slot Syntax_ -Example MDI Command Without Inspectioning: G65 "PROBESLOTX" A54. B3. Q0. +Example MDI Command Without Inspectioning: G65 "PROBESLOTX" A54. B3. Q0. + +Example MDI Command Without Inspectioning: G65 "PROBESLOTX" A54. B3. Q1. +*** -Example MDI Command Without Inspectioning: G65 "PROBESLOTX" A54. B3. Q1. - ### PROBEYSLOT -The Probe Slot Y macro probes the internal sides of a pocket in the Y direction and calculates the center. -`A` is the selected work coordinate(54-59 or 54.01-54.99). -`B` is the width of the pocket in Y. -`Q` enables inspection reporting which pops up a calculated width after the routine finishes. -The Probe should be roughly centered and inside of the slot before beginning. +The Probe Slot Y macro probes the internal sides of a pocket in the Y direction and calculates the center. + +`A` is the selected work coordinate (54-59 or 54.01-54.99). +`B` is the width of the pocket in Y. +`Q` enables inspection reporting, which pops up a calculated width after the routine finishes. + - The Probe should be roughly centered and inside the slot before beginning. ![probeSlotY](images/probeSlotY.PNG) -_Figure 14. Probe Slot Routine_ +_Figure 14. Probe Slot Routine_ | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | | G65 | "PROBESLOTY" | A | B | Q | -_Table 15. Probe Slot Syntax_ +_Table 15. Probe Slot Syntax_ -Example MDI Command Without Inspection Reporting: G65 "PROBESLOTY" A54. B3. Q0. - -Example MDI Command With Inspection Reporting: G65 "PROBESLOTY" A54. B3. Q1. +Example MDI Command Without Inspection Reporting: G65 "PROBESLOTY" A54. B3. Q0. +Example MDI Command With Inspection Reporting: G65 "PROBESLOTY" A54. B3. Q1. +*** ### PROBEOUTSIDECORNER -The Probe Outside Corner macro probes the outside edges of the stock and calculates the center. -`A`is the selected work coordinate(54-59 or 54.01-54.99). -`B` Selects the desired corner to probe. -`C` is the distance to travel away from the inital location before probing begins. -`D` is the probing distance for both X and Y. -The Probe should be roughly centered, diagonaly from the corner befor beginning. +The Probe Outside Corner macro probes the outside edges of the stock and calculates the center. + +`A`is the selected work coordinate (54-59 or 54.01-54.99). +`B` Selects the desired corner to probe. +`C` is the distance to travel away from the initial location before probing begins. +`D` is the probing distance for both X and Y. + - The Probe should be roughly centered, diagonally from the corner before beginning. ![probeExternalCorner](images/probeExternalCorner.png) @@ -538,29 +571,31 @@ _Figure 15. Probe Outside Corner Routine_ _Table 16. Probe Outer Corner Syntax_ Example MDI Command: G65 "PROBEOUTSIDECORNER" A54. B1. C1 D.5 - +*** ### PROBEINSIDECORNER -The Probe inside Corner macro probes the inside edges of a pocket and calculates the center. -`A` is the selected work coordinate(54-59 or 54.01-54.99). -`B` the desired corner to probe. -`C` is the probing distance. -The Probe should be roughly centered, diagonaly from the corner before beginning. +The Probe inside Corner macro probes the inside edges of a pocket and calculates the center. + +`A` is the selected work coordinate (54-59 or 54.01-54.99). +`B` is the desired corner to probe. +`C` is the probing distance. + - The Probe should be roughly centered, diagonally from the corner before beginning. ![probeInternalCorner](images/probeInternalCorner.png) -_Figure 16. Probe Inside Corner Routine_ +_Figure 16. Probe Inside Corner Routine_ | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | | G65 | "PROBEINSIDECORNER" | A | B | C | -_Table 17. Probe Inner Corner Syntax_ +_Table 17. Probe Inner Corner Syntax_ + +Example MDI Command: G65 "PROBEINSIDECORNER" A54. B1. C.5 -Example MDI Command: G65 "PROBEINSIDECORNER" A54. B1. C.5 -### SUPPORTED FUSION 360 PROBING FEATURES +## SUPPORTED FUSION 360 PROBING FEATURES WCS override provides a known coordinate system for the probe to safely drive to a desired probing location. The override offset specifies which work offset should be used to drive the probe. In the below example, the value 6 corresponds to G59. WCS override must be enabled when using out of postion checks or zero point compensation. From 8d261d101502171d700a98994a3207ddb7173ef4 Mon Sep 17 00:00:00 2001 From: Robot Oblivion Date: Tue, 15 Apr 2025 18:24:16 +1200 Subject: [PATCH 15/21] TL;DR Mcode version of the probing macros available. Rebuild probing macros to swap any arguments to their axis letter. a few small bug finds and fixes. --------------------------------------------------- Syil_LNC_RobotOblivion.cps - Logic to swap between string and number-based macro calls (line 56) - onSectionEnd() bug fix for programs that end in an optional strategy that was causing the post to fail - Probing arguments updated to match the new naming conversion. LOADTOOL - waits added to make sure the controller holds for an OK to be pressed before moving on PROBECONFIG - moved -1 tool check above tool offsets as will stop a valid tool offset from being cleared if the macro is run with -1 - added gauge block XY size inputs - added manual tool change location extended offset - global variables changed to values not used by the stock Syil macros - switch for turning off size tolerance alarms added CALIBRATEZ - Second confirmation message added to make sure the controller holds for an OK to stop an incorrect value being stored if OK is pressed before the master tool is fully gauged in on the top of the artifact. - removed [ ] around a few variable numbers - added missing # on / PROBE Z AT SLOW SPEED line build_maker_macro.py - Reorder the Mcode with numbering to aid in calling them without string names. - added a reminder to open a workspace with the top-level folder set to "Macros for Controller" - Added and ran to generate a macro_macro set of macros README.md - 3rd pass with updated arguments ChangeLog.md - updated with an overview of changes The below macros were updated to move axis arguments to letters that match the axis being called: CALIBRATEPROBEBLOCK Arguments A and B swapped to X and Z PROBEYWEB Arguments B and C swapped to Y and Z switch for turning off size tolerance alarms added PROBEXWEB Arguments B and C swapped to X and Z switch for turning off size tolerance alarms added PROBEBORE Argument B swapped to D PROBEX Argument B swapped to X PROBEXSLOT Argument B swapped to X switch for turning off size tolerance alarms added PROBEY Argument B swapped to Y PROBEYSLOT Argument B swapped to Y switch for turning off size tolerance alarms added PROBECIRCULARBOSS Arguments B and C swapped to X and Z PROBERECTANGULARBOSS Arguments B, C and D swapped to X, Y and Z PROBEPOCKET Arguments B and C swapped to X and Y PROBEZ Argument B swapped to Z TOOLSET Arguments A and B swapped to D and A PROBEOUTSIDECORNER Arguments B, C and D swapped to C, D and E PROBEINSIDECORNER Arguments C and D swapped to D and E --- .vscode/settings.json | 5 + .../Syil_LNC_RobotOblivion.cps | 159 +++-- .../syil_lnc_toolpath.cps | 2 +- Helpful NC Programs/probingSetupHelp_v0.1.nc | 65 -- Macros for Controller/CALIBRATEPROBEBLOCK | 29 +- Macros for Controller/CALIBRATEPROBERING | 16 +- Macros for Controller/CALIBRATEPROBEZ | 33 +- Macros for Controller/CALIBRATETOOLSET | 6 +- .../CHECKPOSITIONALTOLERANCE | 32 +- Macros for Controller/COMPZEROPOINT | 22 +- Macros for Controller/COPYWCS | 12 +- Macros for Controller/FINDCOR | 18 +- Macros for Controller/LOADTOOL | 26 +- Macros for Controller/PROBEBORE | 20 +- Macros for Controller/PROBECIRCULARBOSS | 18 +- Macros for Controller/PROBECONFIG | 74 +- Macros for Controller/PROBEINSIDECORNER | 46 +- Macros for Controller/PROBEOUTSIDECORNER | 52 +- Macros for Controller/PROBEPOCKET | 14 +- Macros for Controller/PROBERECTANGULARBOSS | 14 +- Macros for Controller/PROBEX | 18 +- Macros for Controller/PROBEXSLOT | 34 +- Macros for Controller/PROBEXWEB | 50 +- Macros for Controller/PROBEXYANGLE | 20 +- Macros for Controller/PROBEY | 18 +- Macros for Controller/PROBEYSLOT | 34 +- Macros for Controller/PROBEYWEB | 50 +- Macros for Controller/PROBEZ | 16 +- Macros for Controller/PROTECTEDMOVE | 2 +- Macros for Controller/SAFESPIN | 2 +- Macros for Controller/TOOLSET | 16 +- Macros for Controller/build_maker_macros.py | 145 ++++ .../maker_macros/MAKER_MACRO_M800 | 109 +++ .../maker_macros/MAKER_MACRO_M801 | 50 ++ .../maker_macros/MAKER_MACRO_M802 | 88 +++ .../maker_macros/MAKER_MACRO_M803 | 54 ++ .../maker_macros/MAKER_MACRO_M804 | 55 ++ .../maker_macros/MAKER_MACRO_M805 | 35 + .../maker_macros/MAKER_MACRO_M806 | 99 +++ .../maker_macros/MAKER_MACRO_M807 | 66 ++ .../maker_macros/MAKER_MACRO_M808 | 84 +++ .../maker_macros/MAKER_MACRO_M809 | 43 ++ .../maker_macros/MAKER_MACRO_M810 | 54 ++ .../maker_macros/MAKER_MACRO_M811 | 106 +++ .../maker_macros/MAKER_MACRO_M813 | 36 + .../maker_macros/MAKER_MACRO_M814 | 71 ++ .../maker_macros/MAKER_MACRO_M815 | 71 ++ .../maker_macros/MAKER_MACRO_M816 | 74 ++ .../maker_macros/MAKER_MACRO_M820 | 39 + .../maker_macros/MAKER_MACRO_M821 | 45 ++ .../maker_macros/MAKER_MACRO_M824 | 173 +++++ .../maker_macros/MAKER_MACRO_M825 | 173 +++++ .../maker_macros/MAKER_MACRO_M827 | 191 +++++ .../maker_macros/MAKER_MACRO_M830 | 48 ++ .../maker_macros/MAKER_MACRO_M831 | 49 ++ .../maker_macros/MAKER_MACRO_M834 | 132 ++++ .../maker_macros/MAKER_MACRO_M835 | 130 ++++ .../maker_macros/MAKER_MACRO_M837 | 76 ++ .../maker_macros/MAKER_MACRO_M839 | 99 +++ .../maker_macros/MAKER_MACRO_M840 | 160 +++++ README.md | 671 +++++++++--------- changelog.md | 13 +- images/DisplayProbedResults.png | Bin 10415 -> 0 bytes images/DisplayProbedResults_light.png | Bin 0 -> 7797 bytes images/zero_point_comp_RO_post.png | Bin 0 -> 81257 bytes 65 files changed, 3376 insertions(+), 786 deletions(-) create mode 100644 .vscode/settings.json delete mode 100644 Helpful NC Programs/probingSetupHelp_v0.1.nc create mode 100644 Macros for Controller/build_maker_macros.py create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M800 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M801 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M802 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M803 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M804 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M805 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M806 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M807 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M808 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M809 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M810 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M811 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M813 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M814 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M815 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M816 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M820 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M821 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M824 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M825 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M827 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M830 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M831 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M834 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M835 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M837 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M839 create mode 100644 Macros for Controller/maker_macros/MAKER_MACRO_M840 delete mode 100644 images/DisplayProbedResults.png create mode 100644 images/DisplayProbedResults_light.png create mode 100644 images/zero_point_comp_RO_post.png diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..e11c735 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "githubPullRequests.ignoredPullRequestBranches": [ + "main" + ] +} \ No newline at end of file diff --git a/Fusion Posts & Machine Model/Syil_LNC_RobotOblivion.cps b/Fusion Posts & Machine Model/Syil_LNC_RobotOblivion.cps index 52446af..17210a7 100644 --- a/Fusion Posts & Machine Model/Syil_LNC_RobotOblivion.cps +++ b/Fusion Posts & Machine Model/Syil_LNC_RobotOblivion.cps @@ -25,6 +25,7 @@ Post setup --This position becomes the default toolchange location if the force toolchange position flags are turned off - Link this post to a machine and then in the machine setup Multi-axis tab choose the feedrate method to Inverse time (minutes) drop down - Debug markers can be turned on and changed @ line 55 + - Swap between macros posting as M codes or G65 "string" @ line 56 ----------------------------------------------------------------------------------------------------------*/ description = "SYIL LNC 6800"; @@ -52,7 +53,8 @@ allowHelicalMoves = true; allowedCircularPlanes = undefined; // allow any circular motion highFeedrate = (unit == MM) ? 5000 : 200; -var debugByCarnie = 0; // 0 = off, 1 = section markers, 2 = section and sim, 3 = sim debug only // go to line 55 to set debug level +var debugByCarnie = 0; // 0 = off, 1 = section markers, 2 = section and sim, 3 = sim debug only // go to line 55 to set debug level +var macroAreWords = true // switch between macros being word or number // user-defined properties properties = { @@ -230,8 +232,8 @@ properties = { type : "boolean", value : false, scope : "operation", - enable : "probing", - disabled : "milling" + enable : "probe", + disabled : ["milling", "turning", "drilling", "additive"] }, safePositionMethod: { title : "Safe Retracts", @@ -801,8 +803,8 @@ function onSectionEnd() { var nextSection = getNextSection(); //---- reworked onSectionEnd below --v - var forceSectionRestartNext = currentSection.isOptional() && !nextSection.isOptional(); - optionalSection = forceSectionRestartNext && !getNextSection().isOptional || forceSectionRestartNext ? false : optionalSection ; + var forceSectionRestartNext = isLastSection() ||currentSection.isOptional() && !nextSection.isOptional(); + optionalSection = isLastSection() || forceSectionRestartNext && !getNextSection().isOptional || forceSectionRestartNext ? false : optionalSection ; var insertToolCallNext = isLastSection() || isToolChangeNeeded(nextSection,"number","description") || forceSectionRestartNext; var newWorkOffsetNext = isLastSection() || isNewWorkOffset(nextSection) || forceSectionRestartNext; var newWorkPlaneNext = isLastSection() || isNewWorkPlane(nextSection) || forceSectionRestartNext; @@ -832,7 +834,7 @@ function onSectionEnd() { onCommand(COMMAND_STOP_SPINDLE); writeRetract(Z); if (getSetting("retract.homeXY.onToolChange", false)) { - writeRetract(settings.retract.homeXY.onToolChange); // KC needs switch to turn off + writeRetract(settings.retract.homeXY.onToolChange); } machineSimulation({x:toPreciseUnit(getProperty("_2TCposX"), MM), y:toPreciseUnit(getProperty("_2TCposY"), MM), coordinates:MACHINE}); // simulate manual tool change position onCommand(COMMAND_BREAK_CONTROL); @@ -841,7 +843,7 @@ function onSectionEnd() { if (tool.manualToolChange && isToolChangeNeeded(nextSection, getProperty("toolAsName") ? "description" : "number")) { setCoolant(COOLANT_OFF); onCommand(COMMAND_STOP_SPINDLE); - writeRetract(Z); + writeRetract(Z); if (getProperty("_3forceManualTCPosition")) { forceModals(gMotionModal); writeBlock(gAbsIncModal.format(90), gFormat.format(53), gMotionModal.format(0), xOutput.format(getProperty("_4manual_TCposX")), yOutput.format(getProperty("_4manual_TCposY"))); @@ -3227,14 +3229,16 @@ function writeInitialPositioning(position, isRequired, codes1, codes2) { // Probe to be sent to initial position using protected moves !isProbeOperation() ? writeBlock(modalCodes, gMotionModal.format(motionCode.single), zOutput.format(position.z), feed) - : writeBlock(macroCall, "\"PROTECTEDMOVE\"", zOutput.format(position.z), feed) ; //, additionalCodes + : macroAreWords ? writeBlock(macroCall, "\"PROTECTEDMOVE\"", zOutput.format(position.z), feed): + writeBlock( mFormat.format(810), zOutput.format(position.z), feed, additionalCodes, "; PROTECTED MOVE"); ; writeln(feed) machineSimulation({z:position.z}); } !isProbeOperation() ? writeBlock(modalCodes, gMotionModal.format(motionCode.multi), xOutput.format(position.x), yOutput.format(position.y), feed, additionalCodes) - : writeBlock(macroCall, "\"PROTECTEDMOVE\"", xOutput.format(position.x), yOutput.format(position.y), feed, additionalCodes) ; - machineSimulation({x:position.x, y:position.y}); + : macroAreWords ? writeBlock(macroCall, "\"PROTECTEDMOVE\"", xOutput.format(position.x), yOutput.format(position.y), feed, additionalCodes): + writeBlock(mFormat.format(810), xOutput.format(position.x), yOutput.format(position.y), feed, additionalCodes, "; PROTECTED MOVE" ) ; ; + machineSimulation({x:position.x, y:position.y}); } } @@ -3853,10 +3857,12 @@ function writeProbeCycle(cycle, x, y, z, P, F) { //EXPECTED_X = "X" + xyzFormat.format(x + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)); EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); DISTANCE = approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2 + cycle.probeOvertravel); - B_ARG = "B" + xyzFormat.format(DISTANCE); + B_ARG = "X" + xyzFormat.format(DISTANCE); - writeBlock(macroCall, "\"PROBEX\"", WCS_CODE[7], WCS_CODE[8], B_ARG); - writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V1", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + macroAreWords ? writeBlock(macroCall, "\"PROBEX\"", WCS_CODE[7], WCS_CODE[8], B_ARG): + writeBlock(mFormat.format(814), WCS_CODE[7], WCS_CODE[8], B_ARG, "; PROBE X"); + macroAreWords ? writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V1", EXPECTED_X, EXPECTED_Y, EXPECTED_Z): + writeBlock(mFormat.format(811), WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V1", EXPECTED_X, EXPECTED_Y, EXPECTED_Z, "; CHECKPOSITIONAL TOLERANCE"); if (WCS_CODE[7] === "I1.") { writeBlock(openString); @@ -3873,10 +3879,12 @@ function writeProbeCycle(cycle, x, y, z, P, F) { EXPECTED_X = "X" + xyzFormat.format(x + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)); // xOutput.format EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); DISTANCE = approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2 + cycle.probeOvertravel); - B_ARG = "B" + xyzFormat.format(DISTANCE); + B_ARG = "Y" + xyzFormat.format(DISTANCE); - writeBlock(macroCall, "\"PROBEY\"", WCS_CODE[7], WCS_CODE[8], B_ARG); - writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V2", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + macroAreWords ? writeBlock(macroCall, "\"PROBEY\"", WCS_CODE[7], WCS_CODE[8], B_ARG): + writeBlock(mFormat.format(815), WCS_CODE[7], WCS_CODE[8], B_ARG, "; PROBE Y"); + macroAreWords ? writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V2", EXPECTED_X, EXPECTED_Y, EXPECTED_Z): + writeBlock(mFormat.format(811), WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V2", EXPECTED_X, EXPECTED_Y, EXPECTED_Z), "; CHECKPOSITIONAL TOLERANCE"; if (WCS_CODE[7] === "I1.") { writeBlock(openString); @@ -3892,10 +3900,12 @@ function writeProbeCycle(cycle, x, y, z, P, F) { EXPECTED_X = "X" + xyzFormat.format(x); // xOutput.format(x); EXPECTED_Y = "Y" + xyzFormat.format(y); // yOutput.format(y); EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); - B_ARG = "B" + xyzFormat.format(-cycle.depth - cycle.probeOvertravel); + B_ARG = "Z" + xyzFormat.format(-cycle.depth - cycle.probeOvertravel); - writeBlock(macroCall, "\"PROBEZ\"", WCS_CODE[7], WCS_CODE[8], B_ARG); - writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V3", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + macroAreWords ? writeBlock(macroCall, "\"PROBEZ\"", WCS_CODE[7], WCS_CODE[8], B_ARG): + writeBlock(mFormat.format(816), WCS_CODE[7], WCS_CODE[8], B_ARG, "; PROBE Z"); + macroAreWords ? writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V3", EXPECTED_X, EXPECTED_Y, EXPECTED_Z): + writeBlock(mFormat.format(811), WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V3", EXPECTED_X, EXPECTED_Y, EXPECTED_Z, "; CHECKPOSITIONAL TOLERANCE"); if (WCS_CODE[7] === "I1.") { open_string = "OPEN[0,1,\"" + programName + "_inspection_report" + "_@980" + "_@981" + "_@982" + "_@983" + "_@984" + "_@985" +"\"]"; @@ -3910,10 +3920,11 @@ function writeProbeCycle(cycle, x, y, z, P, F) { //forceXYZ(); protectedProbeMove(cycle, x, y, z); WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); - WEB_WIDTH = "B" + xyzFormat.format(cycle.width1); - Z_DROP = "C" + xyzFormat.format(cycle.depth); + WEB_WIDTH = "X" + xyzFormat.format(cycle.width1); + Z_DROP = "Z" + xyzFormat.format(cycle.depth); - writeBlock(macroCall, "\"PROBEXWEB\"", WCS_CODE[7], WCS_CODE[8], WEB_WIDTH, Z_DROP, WCS_CODE[10], WCS_CODE[2]); + macroAreWords ? writeBlock(macroCall, "\"PROBEXWEB\"", WCS_CODE[7], WCS_CODE[8], WEB_WIDTH, Z_DROP, WCS_CODE[10], WCS_CODE[2]): + writeBlock(mFormat.format(824), WCS_CODE[7], WCS_CODE[8], WEB_WIDTH, Z_DROP, WCS_CODE[10], WCS_CODE[2], "; PROBE X WEB"); if (WCS_CODE[7] === "I1.") { writeBlock(openString); @@ -3926,10 +3937,11 @@ function writeProbeCycle(cycle, x, y, z, P, F) { protectedProbeMove(cycle, x, y, z); WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); - WEB_WIDTH = "B" + xyzFormat.format(cycle.width1); - Z_DROP = "C" + xyzFormat.format(cycle.depth); + WEB_WIDTH = "Y" + xyzFormat.format(cycle.width1); + Z_DROP = "Z" + xyzFormat.format(cycle.depth); - writeBlock(macroCall, "\"PROBEYWEB\"", WCS_CODE[7], WCS_CODE[8], WEB_WIDTH, Z_DROP, WCS_CODE[10], WCS_CODE[2]); + macroAreWords ? writeBlock(macroCall, "\"PROBEYWEB\"", WCS_CODE[7], WCS_CODE[8], WEB_WIDTH, Z_DROP, WCS_CODE[10], WCS_CODE[2]): + writeBlock(mFormat.format(825), WCS_CODE[7], WCS_CODE[8], WEB_WIDTH, Z_DROP, WCS_CODE[10], WCS_CODE[2], "; PROBE Y WEB"); if (WCS_CODE[7] === "I1.") { writeBlock(openString); @@ -3942,9 +3954,10 @@ function writeProbeCycle(cycle, x, y, z, P, F) { protectedProbeMove(cycle, x, y, z - cycle.depth); WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); - SLOT_WIDTH = "B" + xyzFormat.format(cycle.width1); + SLOT_WIDTH = "X" + xyzFormat.format(cycle.width1); - writeBlock(macroCall, "\"PROBEXSLOT\"", WCS_CODE[7], WCS_CODE[8], SLOT_WIDTH, WCS_CODE[10], WCS_CODE[2]); + macroAreWords ? writeBlock(macroCall, "\"PROBEXSLOT\"", WCS_CODE[7], WCS_CODE[8], SLOT_WIDTH, WCS_CODE[10], WCS_CODE[2]): + writeBlock(mFormat.format(834), WCS_CODE[7], WCS_CODE[8], SLOT_WIDTH, WCS_CODE[10], WCS_CODE[2], "; PROBE X SLOT"); if (WCS_CODE[7] === "I1.") { writeBlock(openString); @@ -3969,9 +3982,10 @@ function writeProbeCycle(cycle, x, y, z, P, F) { protectedProbeMove(cycle, x, y, z - cycle.depth); WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); - SLOT_WIDTH = "B" + xyzFormat.format(cycle.width1); + SLOT_WIDTH = "Y" + xyzFormat.format(cycle.width1); - writeBlock(macroCall, "\"PROBEYSLOT\"", WCS_CODE[7], WCS_CODE[8], SLOT_WIDTH, WCS_CODE[10], WCS_CODE[2]); + macroAreWords ? writeBlock(macroCall, "\"PROBEYSLOT\"", WCS_CODE[7], WCS_CODE[8], SLOT_WIDTH, WCS_CODE[10], WCS_CODE[2]): + writeBlock(mFormat.format(835), WCS_CODE[7], WCS_CODE[8], SLOT_WIDTH, WCS_CODE[10], WCS_CODE[2], "; PROBE Y SLOT"); if (WCS_CODE[7] === "I1.") { writeBlock(openString); @@ -3996,16 +4010,20 @@ function writeProbeCycle(cycle, x, y, z, P, F) { protectedProbeMove(cycle, x, y, z); WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); - BOSS_DIAMETER = "B" + xyzFormat.format(cycle.width1); - Z_DROP = "C" + xyzFormat.format(cycle.depth); + BOSS_DIAMETER = "D" + xyzFormat.format(cycle.width1); + Z_DROP = "Z" + xyzFormat.format(cycle.depth); EXPECTED_X = "X" + xyzFormat.format(x); //xOutput.format EXPECTED_Y = "Y" + xyzFormat.format(y); //yOutput.format EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); - writeBlock(macroCall, "\"PROBECIRCULARBOSS\"", WCS_CODE[7], WCS_CODE[8], BOSS_DIAMETER, Z_DROP, WCS_CODE[10], WCS_CODE[2]); - writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V4", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + macroAreWords ? writeBlock(macroCall, "\"PROBECIRCULARBOSS\"", WCS_CODE[7], WCS_CODE[8], BOSS_DIAMETER, Z_DROP, WCS_CODE[10], WCS_CODE[2]): + writeBlock(mFormat.format(831), WCS_CODE[7], WCS_CODE[8], BOSS_DIAMETER, Z_DROP, WCS_CODE[10], WCS_CODE[2], "; PROBE CIRCULAR BOSS"); + macroAreWords ? writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V4", EXPECTED_X, EXPECTED_Y, EXPECTED_Z): + writeBlock(mFormat.format(811), WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V4", EXPECTED_X, EXPECTED_Y, EXPECTED_Z, "; CHECKPOSITIONAL TOLERANCE"); + if (getProperty("EnableZeroPointCompensation") == true && WCS_CODE[7] === null) { - writeBlock(macroCall, "\"COMPZEROPOINT\"", WCS_CODE[8], WCS_CODE[9], EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + macroAreWords ? writeBlock(macroCall, "\"COMPZEROPOINT\"", WCS_CODE[8], WCS_CODE[9], EXPECTED_X, EXPECTED_Y, EXPECTED_Z) : + writeBlock(mFormat.format(808), WCS_CODE[8], WCS_CODE[9], EXPECTED_X, EXPECTED_Y, EXPECTED_Z, "; COMP ZERO POINT"); } if (WCS_CODE[7] === "I1.") { @@ -4036,15 +4054,19 @@ function writeProbeCycle(cycle, x, y, z, P, F) { protectedProbeMove(cycle, x, y, z - cycle.depth); WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); - BORE_DIAMETER = "B" + xyzFormat.format(cycle.width1); + BORE_DIAMETER = "D" + xyzFormat.format(cycle.width1); EXPECTED_X = "X" + xyzFormat.format(x); //xOutput.format EXPECTED_Y = "Y" + xyzFormat.format(y); //yOutput.format EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); - writeBlock(macroCall, "\"PROBEBORE\"", WCS_CODE[7], WCS_CODE[8], BORE_DIAMETER, WCS_CODE[10], WCS_CODE[2]); - writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V4", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + macroAreWords ? writeBlock(macroCall, "\"PROBEBORE\"", WCS_CODE[7], WCS_CODE[8], BORE_DIAMETER, WCS_CODE[10], WCS_CODE[2]): + writeBlock(mFormat.format(830), WCS_CODE[7], WCS_CODE[8], BORE_DIAMETER, WCS_CODE[10], WCS_CODE[2], "; PROBE BORE"); + macroAreWords ? writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V4", EXPECTED_X, EXPECTED_Y, EXPECTED_Z): + writeBlock(mFormat.format(811), WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V4", EXPECTED_X, EXPECTED_Y, EXPECTED_Z, "; CHECKPOSITIONAL TOLERANCE"); + if (getProperty("EnableZeroPointCompensation") == true && WCS_CODE[7] === null) { - writeBlock(macroCall, "\"COMPZEROPOINT\"", WCS_CODE[8], WCS_CODE[9], EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + macroAreWords ? writeBlock(macroCall, "\"COMPZEROPOINT\"", WCS_CODE[8], WCS_CODE[9], EXPECTED_X, EXPECTED_Y, EXPECTED_Z) : + writeBlock(mFormat.format(808), WCS_CODE[8], WCS_CODE[9], EXPECTED_X, EXPECTED_Y, EXPECTED_Z, "; COMP ZERO POINT"); } if (WCS_CODE[7] === "I1.") { @@ -4100,16 +4122,20 @@ function writeProbeCycle(cycle, x, y, z, P, F) { protectedProbeMove(cycle, x, y, z - cycle.depth); WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); - XWEB_WIDTH = "B" + xyzFormat.format(cycle.width1); - YWEB_WIDTH = "C" + xyzFormat.format(cycle.width2); + XWEB_WIDTH = "X" + xyzFormat.format(cycle.width1); + YWEB_WIDTH = "Y" + xyzFormat.format(cycle.width2); EXPECTED_X = "X" + xyzFormat.format(x); //xOutput.format EXPECTED_Y = "Y" + xyzFormat.format(y); //yOutput.format EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); - writeBlock(macroCall, "\"PROBEPOCKET\"", WCS_CODE[7], WCS_CODE[8], XWEB_WIDTH, YWEB_WIDTH, WCS_CODE[10], WCS_CODE[2]); - writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V4", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + macroAreWords ? writeBlock(macroCall, "\"PROBEPOCKET\"", WCS_CODE[7], WCS_CODE[8], XWEB_WIDTH, YWEB_WIDTH, WCS_CODE[10], WCS_CODE[2]): + writeBlock(mFormat.format(820), WCS_CODE[7], WCS_CODE[8], XWEB_WIDTH, YWEB_WIDTH, WCS_CODE[10], WCS_CODE[2], "; PROBE POCKET"); + macroAreWords ? writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V4", EXPECTED_X, EXPECTED_Y, EXPECTED_Z, "; CHECKPOSITIONAL TOLERANCE"): + writeBlock(mFormat.format(811), WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V4", EXPECTED_X, EXPECTED_Y, EXPECTED_Z, "; CHECKPOSITIONAL TOLERANCE"); + if (getProperty("EnableZeroPointCompensation") == true && WCS_CODE[7] === null) { - writeBlock(macroCall, "\"COMPZEROPOINT\"", WCS_CODE[8], WCS_CODE[9], EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + macroAreWords ? writeBlock(macroCall, "\"COMPZEROPOINT\"", WCS_CODE[8], WCS_CODE[9], EXPECTED_X, EXPECTED_Y, EXPECTED_Z) : + writeBlock(mFormat.format(808), WCS_CODE[8], WCS_CODE[9], EXPECTED_X, EXPECTED_Y, EXPECTED_Z, "; COMP ZERO POINT"); } if (WCS_CODE[7] === "I1.") { @@ -4124,17 +4150,21 @@ function writeProbeCycle(cycle, x, y, z, P, F) { protectedProbeMove(cycle, x, y, z); WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); - XWEB_WIDTH = "B" + xyzFormat.format(cycle.width1); - YWEB_WIDTH = "C" + xyzFormat.format(cycle.width2); + XWEB_WIDTH = "X" + xyzFormat.format(cycle.width1); + YWEB_WIDTH = "Y" + xyzFormat.format(cycle.width2); EXPECTED_X = "X" + xyzFormat.format(x); //xOutput.format EXPECTED_Y = "Y" + xyzFormat.format(y); //yOutput.format EXPECTED_Z = "Z" + xyzFormat.format(cycle.stock - cycle.depth); - Z_DROP = "D" + xyzFormat.format(cycle.depth); + Z_DROP = "Z" + xyzFormat.format(cycle.depth); + + macroAreWords ? writeBlock(macroCall, "\"PROBERECTANGULARBOSS\"", WCS_CODE[7], WCS_CODE[8], XWEB_WIDTH, YWEB_WIDTH, Z_DROP, WCS_CODE[10], WCS_CODE[2]): + writeBlock(mFormat.format(821), WCS_CODE[7], WCS_CODE[8], XWEB_WIDTH, YWEB_WIDTH, Z_DROP, WCS_CODE[10], WCS_CODE[2], "; PROBERECT ANGULARBOSS"); + macroAreWords ? writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V4", EXPECTED_X, EXPECTED_Y, EXPECTED_Z): + writeBlock(mFormat.format(811), WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V4", EXPECTED_X, EXPECTED_Y, EXPECTED_Z, "; CHECKPOSITIONAL TOLERANCE"); - writeBlock(macroCall, "\"PROBERECTANGULARBOSS\"", WCS_CODE[7], WCS_CODE[8], XWEB_WIDTH, YWEB_WIDTH, Z_DROP, WCS_CODE[10], WCS_CODE[2]); - writeBlock(macroCall, "\"CHECKPOSITIONALTOLERANCE\"", WCS_CODE[8], WCS_CODE[9], WCS_CODE[3], "V4", EXPECTED_X, EXPECTED_Y, EXPECTED_Z); if (getProperty("EnableZeroPointCompensation") == true && WCS_CODE[7] === null) { - writeBlock(macroCall, "\"COMPZEROPOINT\"", WCS_CODE[8], WCS_CODE[9], EXPECTED_X, EXPECTED_Y, EXPECTED_Z); + macroAreWords ? writeBlock(macroCall, "\"COMPZEROPOINT\"", WCS_CODE[8], WCS_CODE[9], EXPECTED_X, EXPECTED_Y, EXPECTED_Z) : + writeBlock(mFormat.format(808), WCS_CODE[8], WCS_CODE[9], EXPECTED_X, EXPECTED_Y, EXPECTED_Z, "; COMP ZERO POINT"); } if (WCS_CODE[7] === "I1.") { @@ -4189,10 +4219,11 @@ function writeProbeCycle(cycle, x, y, z, P, F) { if (xdir == 1 && ydir == 1) {CORNER_NUM = 2;} else if (xdir == 1 && ydir == -1) {CORNER_NUM = 4;} else if (xdir == -1 && ydir == 1) {CORNER_NUM = 1;} else if (xdir == -1 && ydir == -1) {CORNER_NUM = 3;} WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); - CORNER_POSITION = "B" + CORNER_NUM; - PROBING_DISTANCE = "C" + xyzFormat.format(cycle.probeClearance + cycle.probeOvertravel); + CORNER_POSITION = "C" + CORNER_NUM; + PROBING_DISTANCE = "E" + xyzFormat.format(cycle.probeClearance + cycle.probeOvertravel); - writeBlock(macroCall, "\"PROBEINSIDECORNER\"", WCS_CODE[8], CORNER_POSITION, PROBING_DISTANCE, WCS_CODE[10]); + macroAreWords ? writeBlock(macroCall, "\"PROBEINSIDECORNER\"", WCS_CODE[8], CORNER_POSITION, PROBING_DISTANCE, WCS_CODE[10]): + writeBlock(mFormat.format(837), WCS_CODE[8], CORNER_POSITION, PROBING_DISTANCE, WCS_CODE[10], "; PROBE INSIDE CORNER"); break; case "probing-xy-outer-corner": //forceXYZ(); @@ -4203,15 +4234,12 @@ function writeProbeCycle(cycle, x, y, z, P, F) { if (xdir == 1 && ydir == 1) {CORNER_NUM = 3;} else if (xdir == 1 && ydir == -1) {CORNER_NUM = 1;} else if (xdir == -1 && ydir == 1) {CORNER_NUM = 4;} else if (xdir == -1 && ydir == -1) {CORNER_NUM = 2;} WCS_CODE = getProbingArguments(cycle, probeWorkOffsetCode); - CORNER_POSITION = "B" + CORNER_NUM; - TRAVEL_DISTANCE = "C" + xyzFormat.format(2 * cycle.probeClearance + tool.diameter / 2); - PROBING_DISTANCE = "D" + xyzFormat.format(cycle.probeClearance + cycle.probeOvertravel); - - writeBlock(macroCall, "\"PROBEOUTSIDECORNER\"", - WCS_CODE[8], - CORNER_POSITION, - TRAVEL_DISTANCE, - PROBING_DISTANCE, "Q0"); + CORNER_POSITION = "C" + CORNER_NUM; + TRAVEL_DISTANCE = "D" + xyzFormat.format(2 * cycle.probeClearance + tool.diameter / 2); + PROBING_DISTANCE = "E" + xyzFormat.format(cycle.probeClearance + cycle.probeOvertravel); + + macroAreWords ? writeBlock(macroCall, "\"PROBEOUTSIDECORNER\"", WCS_CODE[8], CORNER_POSITION, TRAVEL_DISTANCE, PROBING_DISTANCE, "Q0"): + writeBlock(mFormat.format(839), WCS_CODE[8], CORNER_POSITION, TRAVEL_DISTANCE, PROBING_DISTANCE, "Q0", "; PROBE OUTSIDE CORNER"); break; case "probing-x-plane-angle": error(localize("probing-x-plane-angle - Unsupported Probing Cycle")); @@ -4376,13 +4404,16 @@ function protectedProbeMove(_cycle, x, y, z) { var _z = zOutput.format(z); var macroCall = settings.probing.macroCall; if (_z && z >= getCurrentPosition().z) { - writeBlock(macroCall, "\"PROTECTEDMOVE\"", _z, getFeed(cycle.feedrate)); // protected positioning move + macroAreWords ? writeBlock(macroCall, "\"PROTECTEDMOVE\"", _z, getFeed(cycle.feedrate)): + writeBlock(mFormat.format(810), _z, getFeed(cycle.feedrate), "; PROTECTED MOVE"); // protected positioning move } if (_x || _y) { - writeBlock(macroCall, "\"PROTECTEDMOVE\"", _x, _y, getFeed(highFeedrate)); // protected positioning move + macroAreWords ? writeBlock(macroCall, "\"PROTECTEDMOVE\"", _x, _y, getFeed(highFeedrate)): + writeBlock(mFormat.format(810), _x, _y, getFeed(highFeedrate), "; PROTECTED MOVE"); // protected positioning move } if (_z && z < getCurrentPosition().z) { - writeBlock(macroCall, "\"PROTECTEDMOVE\"", _z, getFeed(cycle.feedrate)); // protected positioning move + macroAreWords ? writeBlock(macroCall, "\"PROTECTEDMOVE\"", _z, getFeed(cycle.feedrate)): + writeBlock(mFormat.format(810), _z, getFeed(cycle.feedrate), "; PROTECTED MOVE") ; // protected positioning move } } // <<<<< INCLUDED FROM include_files/protectedProbeMove_renishaw.cpi diff --git a/Fusion Posts & Machine Model/syil_lnc_toolpath.cps b/Fusion Posts & Machine Model/syil_lnc_toolpath.cps index 5035aa8..a32951a 100644 --- a/Fusion Posts & Machine Model/syil_lnc_toolpath.cps +++ b/Fusion Posts & Machine Model/syil_lnc_toolpath.cps @@ -3489,7 +3489,7 @@ function getPointNumber() { if (typeof inspectionWriteVariables == "function") { return (inspectionVariables.pointNumber); } else { - return ("#122[60]"); + return ("#102[60]"); } } diff --git a/Helpful NC Programs/probingSetupHelp_v0.1.nc b/Helpful NC Programs/probingSetupHelp_v0.1.nc deleted file mode 100644 index 379dfcb..0000000 --- a/Helpful NC Programs/probingSetupHelp_v0.1.nc +++ /dev/null @@ -1,65 +0,0 @@ -; Copyright 2025 Robot Oblivion - -; ProbingConfigHelper -; A NC program to suport the process of doing the first full probing calibration -; Initial Coding: Robot Oblivion - -; Before running, ensure the following: -; - backup your tool table, offset table and @10, @11, @100-@117, @127-@133, @980-@987 and @1508 variables in case of wanting to revert -; - Set all user inputs in the ProbeConfig file. -; - copy all macro files CNC control -; - Clear as many items as possible from the table to prevent collisions with stock, jigs, fixtures, or vices. -; - Ensure the table zero point is empty, lightly stoned, and free of coolant. -; - Find the tool setter's centre and store this location to the extended work offset chosen in @111 PROBECONFIG. -; - Copy the table zero point (XYZ) offsets to the extended work offsets that will store the calibration artifact location. -; - Have your master tool, probe, and ring gauge ready. - -G65 "PROBECONFIG" T1 - -G90 G94 G17 G49 G40 G80 -G53 G00 Z0 - -; toolchange to probe tool pocket -IF [@100 != R_SYS_INFO[0,2]] - G53 G00 X-390 Y0 - G65 "LOADTOOL" M0 T@100 -END_IF - -#96 = MSG_YES["Ready to start?", "Is the master tool loaded in the spindle",""] -IF [#96 == 0] - MSG_OK["Install the master tool", "Switch to MPG mode and install the master tool (T@100) then switch back to auto and retry calibration", ""] - M30 -END_IF - -#96 = MSG_YES["Calibrate Tool Setter?", "would you like to run the tool setter calibration?",""] -IF [#96 == 1] - #96 = MSG_YES["Tool setter WCS set?", "Is the tool setter centre location loaded into G54 P@112?",""] - IF [#96 == 0] - MSG_OK["Set missing WCS", "Make sure to find the tool setters center and update offsets G54 P@112", ""] - M30 - END_IF - G65 "CALIBRATETOOLSET" -END_IF - -#96 = MSG_YES["Probing WCS set?", "Is the location of the Z probing object loaded into G54 P@111?",""] -IF [#96 == 0] - M1430 -END_IF - -G54 P@111 -G1 F2000 X0 Y0 - -;G65 "CALIBRATEPROBEZ" A1 ; full Z calibration - -G43 H@100 -G65 "PROTECTEDMOVE" Z100 - -; swap out block for ring gauge -MSG_OK["Load ring gauge", "Switch to MPG mode and install the ring gauge onto the table. Lower the probe tip into the ring gauge, then press Cycle Start only when ready to proceed. ",""] -M00 - -G65 "CALIBRATEPROBERING" - -G53 G00 Z0. -G53 G00 X-390 Y0 -M30 \ No newline at end of file diff --git a/Macros for Controller/CALIBRATEPROBEBLOCK b/Macros for Controller/CALIBRATEPROBEBLOCK index 35815a7..280b3eb 100644 --- a/Macros for Controller/CALIBRATEPROBEBLOCK +++ b/Macros for Controller/CALIBRATEPROBEBLOCK @@ -3,11 +3,13 @@ //CALIBRATEPROBEBLOCK //CALIBRATE PROBE TIP DIAMETER using a rectanglar object -// Argument A -> #1 is the expected X length of the artifact -// Argument B -> #2 is the expected Y length of the artifact -// Argument C -> #3 is the Z drop height +// Argument X -> #24* is optional and the expected X length of the artifact. Will over ride value in ProbeConfig if called +// Argument Y -> #25* is optional and the expected Y length of the artifact. Will over ride value in ProbeConfig if called +// Argument Z -> #26 is the Z drop height +// **Gauge block size set in ProbeConfig file // Initial Coding: Justin Gray +// Modified 08/04/2025: Robot Oblivion G90 G94 G17 G49 G40 G80 @@ -17,20 +19,31 @@ G65 "PROBECONFIG" M19 // ORIENT SPINDLE // important local variables -#100 = @100 // TOOL NUMBER PROVIDED BY PROBECONFIG MACRO +#100 = @100 // TOOL NUMBER PROVIDED BY PROBECONFIG MACRO +#124 = @94 // Calibrated X size of gauge block +#125 = @95 // Calibrated Y size of gauge block + +// Over ride probeConfig gauge X size if X argument used +IF [#24 != #0] + #124 = #24 +END_IF +// Over ride probeConfig gauge Y size if Y argument used +IF [#25 != #0] + #125 = #25 +END_IF // Make sure diameter is zero when calibrating W_TOOL_DATA[0,#100,3,0] // store tool diameter // calling web probe macros macros to measure the rectangle -G65 "PROBEXWEB" A0 B#1 C#3 Q0 -G65 "PROBEYWEB" A0 B#2 C#3 Q0 +G65 "PROBEXWEB" A0 X#124 Z#26 Q0 +G65 "PROBEYWEB" A0 Y#125 Z#26 Q0 #131 = @998 // stored value of the measured X distance #132 = @999 // stored valued of the measured Y distance -#133 = #1-#131 // error in x -#134 = #2-#132 // error in y +#133 = #24-#131 // error in x +#134 = #25-#132 // error in y #135 = ABS[#133 + #134]/2 // average error W_TOOL_DATA[0,#100,3,#135] // store tool diameter diff --git a/Macros for Controller/CALIBRATEPROBERING b/Macros for Controller/CALIBRATEPROBERING index c5feed6..e109363 100644 --- a/Macros for Controller/CALIBRATEPROBERING +++ b/Macros for Controller/CALIBRATEPROBERING @@ -5,7 +5,7 @@ // Your probe must be concentric and you must use a ring guage!!!!!!!!!! // **Ring gauge ID set in ProbeConfig file -// Argument A -> #1 is optional and the expected inside diameter of the ring guage. Will over ride value in ProbeConfig if called +// Argument D -> #4 is optional and the expected inside diameter of the ring guage. Will over ride value in ProbeConfig if called // Initial coding 1/14/2024: Joshua Smith // Modified 31/03/2025: Robot Oblivion @@ -17,11 +17,11 @@ M19 // ORIENT SPINDLE // important local variables #100 = @100 // TOOL NUMBER PROVIDED BY PROBECONFIG MACRO -#129 = @129 // Calibrated ring gauge diameter provided by PROBECONFIG MACRO +#129 = @93 // Calibrated ring gauge diameter provided by PROBECONFIG MACRO // Over ride probeConfig gauge ID A argument used -IF [#1 != #0] - #129 = #1 +IF [#4 != #0] + #129 = #4 END_IF // Make sure diameter is zero when calibrating @@ -29,12 +29,12 @@ W_TOOL_DATA[0,#100,3,0] // store tool diameter // G54 is used below to pass ProbeConfig WCS checks, but I1 calls ensure that G54 remains unchanged. // calling our slot macros the first time centers probe -G65 "PROBEXSLOT" A54 B#129 Q0 I1 -G65 "PROBEYSLOT" A54 B#129 Q0 I1 +G65 "PROBEXSLOT" A54 X#129 Q0 I1 +G65 "PROBEYSLOT" A54 Y#129 Q0 I1 // calling our slot macros a second time gives an accurate inspection -G65 "PROBEXSLOT" A#111 B#129 Q0 I1 -G65 "PROBEYSLOT" A#111 B#129 Q0 I1 +G65 "PROBEXSLOT" A#111 X#129 Q0 I1 +G65 "PROBEYSLOT" A#111 Y#129 Q0 I1 // average Diameter calculation // @999 and @998 are set in the slot macros diff --git a/Macros for Controller/CALIBRATEPROBEZ b/Macros for Controller/CALIBRATEPROBEZ index bd8d0aa..1be1fec 100644 --- a/Macros for Controller/CALIBRATEPROBEZ +++ b/Macros for Controller/CALIBRATEPROBEZ @@ -18,16 +18,20 @@ G65 "PROBECONFIG" #104 = @104 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO #105 = @105 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO #106 = @106 // PROBE CLEARANCE DISTANCE -#108 = @108 // PROBE BACKOFF DISTANCE -#109 = @109 // MASTER TOOL GAUGE LENGTH -#111 = @111 // PROBE CALIBRATION EXTENDED WORKOFFSET NUMBER +#108 = @107 // PROBE BACKOFF DISTANCE +#109 = @92 // MASTER TOOL GAUGE LENGTH +#111 = @113 // PROBE CALIBRATION EXTENDED WORKOFFSET NUMBER // NOTE: @5109 will be used to save reference block height M19 // ORIENT SPINDLE IF [#1!=#0] - MSG_OK["Calibrate probe", "Switch to MPG mode and zero the master gauge tool on the calibration artifact. Only press Cycle Start when ready to proceed. The measured value will be stored in G@111", ""] - + MSG_OK["Calibrate probe", "Switch to MPG mode and carefully zero the master tool on the calibration artifact. Only press Cycle Start when you're ready to proceed.", ""] + M00 + WAIT[0,0] + MSG_OK["Update @5109", "Once accurately gauged in, press OK to store the current machine position in G@113. Only press OK when the tool is correctly positioned as the Z axis will retract immediately after.", ""] + WAIT[0,0] + @5109 = R_MACH_COOR[0,3] // GET MACHINE Z COORDINATE WHICH SHOULD BE THE TOP OF A 123 BLOCK #140 = @5109 @@ -44,29 +48,30 @@ T#100 M6 // COMMAND A TOOL CHANGE G53 G90 G00 Z0 // BRING THE MACHINE UP TO TOOL CHANGE HEIGHT -#121 = R_MACH_COOR[0,3] // GET MACHINE Z COORDINATE AFTER TOOL CHANGE +#101 = R_MACH_COOR[0,3] // GET MACHINE Z COORDINATE AFTER TOOL CHANGE IF [#1!=#0] // TELL THE PERSON TO PUT THE PROBE INTO THE SPINDLE MSG_OK["Install probe", "Switch to MPG mode and install the probe (T@100). Then, switch back before pressing Cycle Start.", ""] END_IF -G54 P#111 // LOCATION OF PROBE CALIBARTION IS X0 Y0 ON G54P#111 +G54 P#111 // LOCATION OF PROBE CALIBARTION IS X0 Y0 ON G54 P#111 G90 G0 X0. Y0. // MOVE TO TOOLSETTER #123 = #140 - #109 // DELTA DISTANCE WE HAVE MOVED PLUS SOME INCASE PROBE IS SHORTER THAN GAUGE TOOL // Probe Z ALL THE WAY BACK TO 123 BLOCK -G31 G91 P2 Z[#123] F#104 +G31 G91 P2 Z#123 F#104 // Check that the probe has triggered IF[R_SKIP[0,1] == 1] - G91 G01 Z[#108] // BACK OFF + G91 G01 Z#108 // PROBE BACKOFF DISTANCE FIX_CUT_OR_ON - G31 G91 P2 Z-[1.5*108] F#105 // PROBE Z AT SLOW SPEED + G31 G91 P2 Z-[1.5*#108] F#105 // PROBE Z AT SLOW SPEED FIX_CUT_OR_OFF #125 = R_SKIP[0,203] // GET MACHINE Z COORDINATE - G91 G01 Z[#108] // BACK OFF + @996 = #125 // Store for Setup Helper + G91 G01 Z#108 // BACK OFF #126 = [#125-#140+#109] // PROBE LENGTH CALCULATION, ACCOUNTING FOR GAUGE TOOL LENGTH W_TOOL_DATA[0,#100,203,#126] // STORE PROBE LENGTH ELSE @@ -76,4 +81,8 @@ END_IF G53 G90 G00 Z0 // retract to top of Z M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY -M99 \ No newline at end of file +M99 + + G91 G01 Z+[#108] //back off distance provided by ProbeConfig macro + #143 = [#142-#107] //current position - probe length + @996 = #143 \ No newline at end of file diff --git a/Macros for Controller/CALIBRATETOOLSET b/Macros for Controller/CALIBRATETOOLSET index 7eb88be..8f5b323 100644 --- a/Macros for Controller/CALIBRATETOOLSET +++ b/Macros for Controller/CALIBRATETOOLSET @@ -12,9 +12,9 @@ // load probe config G65 "PROBECONFIG" T#100 -#115 = @117 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO -#116 = @116 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO -#109 = @109 // MASTER GAUGE LENGTH PROVIDED BY PROBECONFIG MACRO +#115 = @109 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#116 = @110 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#109 = @92 // MASTER GAUGE LENGTH PROVIDED BY PROBECONFIG MACRO #112 = @112 // EXTENDED WCS TO STORE TOOLSETTER LOCATION PROVIDED BY PROBECONFIG MACRO G94 G17 G49 G40 G80 diff --git a/Macros for Controller/CHECKPOSITIONALTOLERANCE b/Macros for Controller/CHECKPOSITIONALTOLERANCE index ca61ccc..a7c7bd3 100644 --- a/Macros for Controller/CHECKPOSITIONALTOLERANCE +++ b/Macros for Controller/CHECKPOSITIONALTOLERANCE @@ -18,9 +18,9 @@ // load probe config G65 "PROBECONFIG" A#1 B#2 -#114 = @114 // processed extended WCS number provided by ProbeConfig macro -#115 = @115 // processed extended WCS number provided by ProbeConfig macro -#128 = @128 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO +#114 = @121 // processed extended WCS number provided by ProbeConfig macro +#115 = @122 // processed extended WCS number provided by ProbeConfig macro +#128 = @96 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO IF[#128 == 1] M19 // ORIENT SPINDLE @@ -45,24 +45,24 @@ IF [#2 == #0] ELSEIF [#115 < 1] #119 = R_G53G59_COOR[0,#2,1] // x override zero #120 = R_G53G59_COOR[0,#2,2] // y override zero - #121 = R_G53G59_COOR[0,#2,3] // z override zero + #101 = R_G53G59_COOR[0,#2,3] // z override zero ELSE #119 = R_G54EXP_COOR[0,#115,1] // x work zero #120 = R_G54EXP_COOR[0,#115,2] // y work zero - #121 = R_G54EXP_COOR[0,#115,3] // z work zero + #101 = R_G54EXP_COOR[0,#115,3] // z work zero END_IF // error = probed point - expected point -#122 = #116 - [#24 + #119] // x error calculation between selected wcs and expected probe point +#102 = #116 - [#24 + #119] // x error calculation between selected wcs and expected probe point #123 = #117 - [#25 + #120] // y error calculation between selected wcs and expected probe point -#124 = #118 - [#26 + #121] // z error calculation between selected wcs and expected probe point +#124 = #118 - [#26 + #101] // z error calculation between selected wcs and expected probe point // if the tolorance is null, default it to global variable from the probe config IF[#20==#0] - #20 = @110 + #20 = @108 END_IF -#130 = ABS[#122] // absolute x error +#130 = ABS[#102] // absolute x error #131 = ABS[#123] // absolute y error #132 = ABS[#124] // absolute z error @@ -70,8 +70,8 @@ END_IF IF[#21!=#0 && #1==#2 ] ALARM["WCS override must be enabled in the Fusion probing routine and the override WCS must be different than the work WCS."] ELSEIF[#21!=#0 && #130 > #20 && [#22 == 1 || #22 == 4 || #22 == 5]] - #130 = ROUND[#130 * @11] / @11 // Round to 3/4 decimal places - #116 = ROUND[#116 * @11] / @11 // Round to 3/4 decimal places + #130 = ROUND[#130 * @91] / @91 // Round to 3/4 decimal places + #116 = ROUND[#116 * @91] / @91 // Round to 3/4 decimal places MENU_ADD["Override point: #119",""]; MENU_ADD["Probed point: #116",""]; MENU_ADD["Limit / expected: #20 / #24",""]; @@ -79,8 +79,8 @@ ELSEIF[#21!=#0 && #130 > #20 && [#22 == 1 || #22 == 4 || #22 == 5]] MENU["Error","Stock out of position X","",4]; ALARM["ERROR: Stock outside of positional tolerance in X"] ELSEIF [#21!=#0 && #131 > #20 && [#22 == 2 || #22 == 4 || #22 == 5]] - #131 = ROUND[#131 * @11] / @11 // Round to 3/4 decimal places - #117 = ROUND[#117 * @11] / @11 // Round to 3/4 decimal places + #131 = ROUND[#131 * @91] / @91 // Round to 3/4 decimal places + #117 = ROUND[#117 * @91] / @91 // Round to 3/4 decimal places MENU_ADD["Override point: #120",""]; MENU_ADD["Probed point: #117",""]; MENU_ADD["Limit / expected: #20 / #25",""]; @@ -88,9 +88,9 @@ ELSEIF [#21!=#0 && #131 > #20 && [#22 == 2 || #22 == 4 || #22 == 5]] MENU["Error","Stock out of position Y","",1]; ALARM["ERROR: Stock outside of positional tolerance in Y"] ELSEIF [#21!=#0 && #132 > #20 && [#22 == 3 || #22 == 5]] - #132 = ROUND[#132 * @11] / @11 // Round to 3/4 decimal places - #118 = ROUND[#118 * @11] / @11 // Round to 3/4 decimal places - MENU_ADD["Override point: #121",""]; + #132 = ROUND[#132 * @91] / @91 // Round to 3/4 decimal places + #118 = ROUND[#118 * @91] / @91 // Round to 3/4 decimal places + MENU_ADD["Override point: #101",""]; MENU_ADD["Probed point: #118",""]; MENU_ADD["Limit / expected: #20 / #26",""]; MENU_ADD["Out of position Z: #132",""]; diff --git a/Macros for Controller/COMPZEROPOINT b/Macros for Controller/COMPZEROPOINT index 59427ae..97d266a 100644 --- a/Macros for Controller/COMPZEROPOINT +++ b/Macros for Controller/COMPZEROPOINT @@ -15,9 +15,9 @@ // load probe config G65 "PROBECONFIG" A#1 B#2 -#114 = @114 // processed extended WCS number provided by ProbeConfig macro -#115 = @115 // processed extended WCS number provided by ProbeConfig macro -#128 = @128 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO +#114 = @121 // processed extended WCS number provided by ProbeConfig macro +#115 = @122 // processed extended WCS number provided by ProbeConfig macro +#128 = @96 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO IF[#128 == 1] M19 // ORIENT SPINDLE @@ -43,21 +43,21 @@ END_IF ELSEIF [#115 < 1] #119 = R_G53G59_COOR[0,#2,1] // x override zero #120 = R_G53G59_COOR[0,#2,2] // y override zero - #121 = R_G53G59_COOR[0,#2,3] // z override zero + #101 = R_G53G59_COOR[0,#2,3] // z override zero ELSE #119 = R_G54EXP_COOR[0,#115,1] // x work zero #120 = R_G54EXP_COOR[0,#115,2] // y work zero - #121 = R_G54EXP_COOR[0,#115,3] // z work zero + #101 = R_G54EXP_COOR[0,#115,3] // z work zero END_IF // error = probed point - expected point - #122 = #116 - [#24 + #119] // x error calculation between selected wcs and expected probe point + #102 = #116 - [#24 + #119] // x error calculation between selected wcs and expected probe point #123 = #117 - [#25 + #120] // y error calculation between selected wcs and expected probe point - #124 = #118 - [#26 + #121] // z error calculation between selected wcs and expected probe point + #124 = #118 - [#26 + #101] // z error calculation between selected wcs and expected probe point - #125 = #119 + #122 // translate x wcs by the error + #125 = #119 + #102 // translate x wcs by the error #126 = #120 + #123 // translate y wcs by the error - #127 = #121 + #124 // translate z wcs by the error + #127 = #101 + #124 // translate z wcs by the error // Compensate WCS For ZeroPoint IF [#1 == #0 || #1 == #2] @@ -67,13 +67,13 @@ ELSEIF [#114 < 1] W_G53G59_COOR[0,#1,2,#126] // Z should always be the zero point Z // If not, we couldn't have driven our probe to the probing position - W_G53G59_COOR[0,#1,3,#121] + W_G53G59_COOR[0,#1,3,#101] ELSE W_G54EXP_COOR[0,#114,1,#125] W_G54EXP_COOR[0,#114,2,#126] // Z should always be the zero point Z // If not, we couldn't have driven our probe to the probing position - W_G54EXP_COOR[0,#114,3,#121] + W_G54EXP_COOR[0,#114,3,#101] END_IF IF[#128 == 1] diff --git a/Macros for Controller/COPYWCS b/Macros for Controller/COPYWCS index a8dbd65..8b5160a 100644 --- a/Macros for Controller/COPYWCS +++ b/Macros for Controller/COPYWCS @@ -10,8 +10,8 @@ // Modified 31/03/2025: Robot Oblivion G65 "PROBECONFIG" A#1 B#2 -#114 = @114 // processed extended WCS number provided by ProbeConfig macro -#115 = @115 // processed extended WCS number provided by ProbeConfig macro +#114 = @121 // processed extended WCS number provided by ProbeConfig macro +#115 = @122 // processed extended WCS number provided by ProbeConfig macro // Get Argument B WCS IF [#2 == #0] @@ -19,11 +19,11 @@ G65 "PROBECONFIG" A#1 B#2 ELSEIF [#115 < 1] #119 = R_G53G59_COOR[0,#2,1] // x override zero #120 = R_G53G59_COOR[0,#2,2] // y override zero - #121 = R_G53G59_COOR[0,#2,3] // z override zero + #101 = R_G53G59_COOR[0,#2,3] // z override zero ELSE #119 = R_G54EXP_COOR[0,#115,1] // x work zero #120 = R_G54EXP_COOR[0,#115,2] // y work zero - #121 = R_G54EXP_COOR[0,#115,3] // z work zero + #101 = R_G54EXP_COOR[0,#115,3] // z work zero END_IF // Copy one wcs into another @@ -32,11 +32,11 @@ IF [#1 == #0 || #1 == #2] ELSEIF [#114 < 1] W_G53G59_COOR[0,#1,1,#119] W_G53G59_COOR[0,#1,2,#120] - W_G53G59_COOR[0,#1,3,#121] + W_G53G59_COOR[0,#1,3,#101] ELSE W_G54EXP_COOR[0,#114,1,#119] W_G54EXP_COOR[0,#114,2,#120] - W_G54EXP_COOR[0,#114,3,#121] + W_G54EXP_COOR[0,#114,3,#101] END_IF G90 diff --git a/Macros for Controller/FINDCOR b/Macros for Controller/FINDCOR index 3baa139..1fe2ed6 100644 --- a/Macros for Controller/FINDCOR +++ b/Macros for Controller/FINDCOR @@ -25,17 +25,17 @@ END_IF // load probe config G65 "PROBECONFIG" A#1 -#114 = @114 // processed extended WCS number provided by ProbeConfig macro +#114 = @121 // processed extended WCS number provided by ProbeConfig macro M19 // ORIENT SPINDLE -#105 = @107 //TOOL LENGTH PROVIDED BY PROBECONFIG MACRO -#108 = @108 //PROBE BACK OFF DISTANCE -#109 = @113 //WCS TO STORE THE INITIAL PROBING LOCATION INTO +#105 = @133 //TOOL LENGTH PROVIDED BY PROBECONFIG MACRO +#108 = @107 //PROBE BACK OFF DISTANCE +#109 = @114 //WCS TO STORE THE INITIAL PROBING LOCATION INTO #110 = @103 //FEED SPEED PROVIDED BY PROBECONFIG MACRO #111 = @104 //FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO #112 = @105 //SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO -#121 = @101 //TOOL DIAMETER PROVIDED BY PROBECONFIG MACRO +#101 = @130 //TOOL DIAMETER PROVIDED BY PROBECONFIG MACRO // CONVINIENT TO WORK IN PROBE 0 WCS @@ -108,13 +108,13 @@ G65 "PROTECTEDMOVE" Z0 // PROBE PART IN -Y DIRECTION G65 "PROBEY" B-0.5 -#121 = @996 +#101 = @996 // GET THE PROBE CLEAR G65 "PROTECTEDMOVE" Z[2+4*#131] // COMPUTE THE DIAMETER -#130 = [#121 - #120] +#130 = [#101 - #120] // COMPUTE THE RADIUS #131 = [#130 / 2.] // Compute THE Y-COR IN MACHINE COORDS @@ -132,10 +132,10 @@ M11 // PROBE IN Z G65 "PROBEZ" B-[10*#131] -#122 = @996 +#102 = @996 // COMPUTE THE Z-COR -#133 = [#122 - #131] +#133 = [#102 - #131] // WRITE IT TO GLOBAL VARIABLES JUST IN CASE diff --git a/Macros for Controller/LOADTOOL b/Macros for Controller/LOADTOOL index 2180c15..0c83a47 100644 --- a/Macros for Controller/LOADTOOL +++ b/Macros for Controller/LOADTOOL @@ -3,9 +3,9 @@ // LOADTOOL // LOAD A NEW TOOL INTO THE CAROUSEL +// Argument M* -> #13 Flag to reset tool offsets then call TOOLSET (not required and defaults on) +// Argument O* -> #15 tool number in carousel to swap out (not required) // Argument T -> #20 IS THE TOOL NUMBER TO LOAD -// Argument M -> #13 Flag to reset tool offsets then call TOOLSET (not required and defaults on) -// Argument O -> #15 tool number in carousel to swap out (not required) // THE TOOL TABLE IS VARIABLES 7000-7011 // Initial Coding: Justin Gray @@ -45,19 +45,19 @@ END_IF // IF #120 IS STILL 0 THEN THERE WAS NO EMPTY POCKET // AND WE WILL SWAP WITH A DIFFERENT TOOL NUMBER IF[#120 == 0] - #121 = #15 // pull in O argument - IF[#121 == #0] - #121 = INPUT["Choose a tool to swap","Choose a tool in the carousel to swap out?","",1,196,13]; + #101 = #15 // pull in O argument + IF[#101 == #0] + #101 = INPUT["Choose a tool to swap","Choose a tool in the carousel to swap out?","",1,196,13]; END_IF // CHECK THAT THE TOOL THE USER PICKED IS ACTUALLY IN THE CAROUSEL FOR #100=7000 TO 7011 - IF[R_REG[#100]==#121] - IF[#121 == R_REG[7813]] // check if tool to swap is tool in spindle + IF[R_REG[#100]==#101] + IF[#101 == R_REG[7813]] // check if tool to swap is tool in spindle W_REG[7813, #20] // push new tool to tool in spindle to skip tool drop in below M6 END_IF // PUSH THE NEW TOOL NUMBER INTO THE TOOL TABLE - #120 = #121 + #120 = #101 W_REG[#100, #20] #119 = 2 // Swap tool message flag EXIT_FOR @@ -65,13 +65,11 @@ IF[#120 == 0] END_FOR IF[#120 == 0] - ALARM["T#121 NOT IN CAROUSEL. CANT SWAP FOR T#20"] + ALARM["Tool T#101 not found in carousel. Can't swap out for T#20."] END_IF END_IF - // NOW WE ARE SURE THAT THE NEW TOOL HAS BEEN PUSHED INTO THE TOOL TABLE - // COMMAND A TOOL CHANGE T#20 M6 @@ -80,9 +78,11 @@ SELECT[#119] CASE 0: ; no message is required CASE 1: - MSG_OK["Install Tool", "Switch to MPG mode and install T#20 in pocket #101",""] + MSG_OK["Install Tool", "Switch to MPG mode, install tool #20 in pocket #101, and press OK only after the manual tool change is complete.",""] + WAIT[0,0] CASE 2 : - MSG_OK["Swap Tools", "Switch to MPG mode, remove T#121 and swap with T#20",""] + MSG_OK["Swap Tools", "Switch to MPG mode, swap tool #101 with tool #20, and press OK only after the manual tool change is complete.",""] + WAIT[0,0] END_SELECT IF[#13 == 1] diff --git a/Macros for Controller/PROBEBORE b/Macros for Controller/PROBEBORE index ae72040..69e3e99 100644 --- a/Macros for Controller/PROBEBORE +++ b/Macros for Controller/PROBEBORE @@ -4,11 +4,11 @@ // Probe a bore in X and Y // Argument A -> #1 is the work coordinate system to store offsets in -// Argument B -> #2 is the expected DIAMETER +// Argument D -> #4 is the expected DIAMETER // Argument I -> #9 print results enabled by fusion360 // Argument Q -> #17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on -// Argument S -> #19 oversize tolorance -// Argument T -> #20 enable oversize check +// Argument R -> #18 oversize tolorance +// Argument S -> #19 enable oversize check // Initial Coding: Justin Gray // Modified 1/14/2024: Joshua Smith @@ -16,12 +16,12 @@ // Modified 31/03/2025: Robot Oblivion //calling our slot macros the first time centers probe - G65 "PROBEXSLOT" A#1 B#2 I#9 Q0 R#18 S#19 - G65 "PROBEYSLOT" A#1 B#2 I#9 Q0 R#18 S#19 + G65 "PROBEXSLOT" A#1 X#4 I#9 Q0 R#18 S#19 + G65 "PROBEYSLOT" A#1 Y#4 I#9 Q0 R#18 S#19 //calling our slot macros a second time gives an accurate inspection - G65 "PROBEXSLOT" A#1 B#2 I#9 Q0 R#18 S#19 - G65 "PROBEYSLOT" A#1 B#2 I#9 Q0 R#18 S#19 + G65 "PROBEXSLOT" A#1 X#4 I#9 Q0 R#18 S#19 + G65 "PROBEYSLOT" A#1 Y#4 I#9 Q0 R#18 S#19 //average Diameter calculation //@999 and @998 are set in the web macros @@ -29,9 +29,9 @@ //simple inspection reporting IF [#17 > 0] - #97 = ROUND[@997 * @11] / @11 // Round to 3/4 decimal places - #98 = ROUND[@998 * @11] / @11 // Round to 3/4 decimal places - #99 = ROUND[@999 * @11] / @11 // Round to 3/4 decimal places + #97 = ROUND[@997 * @91] / @91 // Round to 3/4 decimal places + #98 = ROUND[@998 * @91] / @91 // Round to 3/4 decimal places + #99 = ROUND[@999 * @91] / @91 // Round to 3/4 decimal places IF[@10 == 21] MENU_ADD["Part Diameter mm X: #98",""]; MENU_ADD["Part Diameter mm Y: #99",""]; diff --git a/Macros for Controller/PROBECIRCULARBOSS b/Macros for Controller/PROBECIRCULARBOSS index 5c5ac06..abde69e 100644 --- a/Macros for Controller/PROBECIRCULARBOSS +++ b/Macros for Controller/PROBECIRCULARBOSS @@ -4,8 +4,8 @@ // Probe a circular boss in X and Y // Argument A -> #1 is the work coordinate system to store offsets in -// Argument B -> #2 is the expected DIAMETER -// Argument C -> #3 is the Z drop height +// Argument D -> #4 is the expected DIAMETER +// Argument Z -> #26 is the Z drop height // Argument I -> #9 print results enabled by fusion360 // Argument Q -> #17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on // Argument R -> #18 oversize tolorance @@ -17,12 +17,12 @@ // Modified 31/03/2025: Robot Oblivion //calling our web macros the first time centers us -G65 "PROBEXWEB" A#1 B#2 C#3 I#9 Q0 R#18 S#19 -G65 "PROBEYWEB" A#1 B#2 C#3 I#9 Q0 R#18 S#19 +G65 "PROBEXWEB" A#1 X#4 Z#26 I#9 Q0 R#18 S#19 +G65 "PROBEYWEB" A#1 Y#4 Z#26 I#9 Q0 R#18 S#19 //calling our web macros the second time gives an accurate center -G65 "PROBEXWEB" A#1 B#2 C#3 I#9 Q0 R#18 S#19 -G65 "PROBEYWEB" A#1 B#2 C#3 I#9 Q0 R#18 S#19 +G65 "PROBEXWEB" A#1 X#4 Z#26 I#9 Q0 R#18 S#19 +G65 "PROBEYWEB" A#1 Y#4 Z#26 I#9 Q0 R#18 S#19 //average Diameter calculation //@999 and @998 are set in the web macros @@ -30,9 +30,9 @@ G65 "PROBEYWEB" A#1 B#2 C#3 I#9 Q0 R#18 S#19 //simple inspection reporting IF [#17 > 0] - #97 = ROUND[@997 * @11] / @11 // Round to 3/4 decimal places - #98 = ROUND[@998 * @11] / @11 // Round to 3/4 decimal places - #99 = ROUND[@999 * @11] / @11 // Round to 3/4 decimal places + #97 = ROUND[@997 * @91] / @91 // Round to 3/4 decimal places + #98 = ROUND[@998 * @91] / @91 // Round to 3/4 decimal places + #99 = ROUND[@999 * @91] / @91 // Round to 3/4 decimal places IF[@10 == 21] MENU_ADD["Part Diameter mm X: #98",""]; MENU_ADD["Part Diameter mm Y: #99",""]; diff --git a/Macros for Controller/PROBECONFIG b/Macros for Controller/PROBECONFIG index 6928aab..fd2b0a9 100644 --- a/Macros for Controller/PROBECONFIG +++ b/Macros for Controller/PROBECONFIG @@ -13,16 +13,18 @@ @10 = R_G_GROUP[0,6] // important global variables to update below: -@100 = -1 // PROBE TOOL NUMBER, EX: 99 -@111 = 97 // EXTENDED WORKOFFSET TO STORE PROBE Z CALIBRATION LOCATION -@112 = 98 // EXTENDED WORKOFFSET TO STORE TOOLSETTER LOCATION -@113 = 99 // EXTENDED WORKOFFSET TO STORE THE 4TH COR PROBING START POINT -#137 = 95 // The highest WCS that can be used. Any above are protected from changes via these macros -@128 = 0 // ORIENT SPINDLE SWITCH 0=OFF 1=ON -@109 = 93.896 // CALIBRATED LENGTH OF YOUR MASTER GAUGE TOOL -@129 = 24.998 // Calibrated diameter of the master ring gauge tool -// @130 = 50.000 // Calibrated X size of gauge block -// @131 = 25.000 // Calibrated Y size of gauge block +@100 = -1 // PROBE TOOL NUMBER, EX: 99 +@92 = 93.896 // CALIBRATED LENGTH OF YOUR MASTER GAUGE TOOL +@93 = 24.998 // Calibrated diameter of the master ring gauge tool +@94 = 50.000 // Calibrated X size of gauge block +@95 = 25.000 // Calibrated Y size of gauge block +@96 = 0 // ORIENT SPINDLE SWITCH 1=ON 0=OFF (probes that spin on/off) +@97 = 0 // turn on alarms for out of tolerance or off to display user message only +#111 = 95 // The highest WCS that can be used. Any above are protected from changes via these macros +@112 = 97 // EXTENDED WORKOFFSET TO STORE TOOLSETTER LOCATION +@113 = 96 // EXTENDED WORKOFFSET TO STORE PROBE Z CALIBRATION LOCATION +@114 = 98 // EXTENDED WORKOFFSET TO STORE THE 4TH COR PROBING START POINT +@115 = 99 // extended workoffset to store the manual tool change location // metric settings IF[@10 == 21] @@ -30,13 +32,13 @@ IF[@10 == 21] @104 = 1250 // FAST PROBE SPEED mm/m, @105 = 60 // SLOW PROBE SPEED mm/m, @106 = 10 // PROBE CLEARANCE DISTANCE mm, - @108 = 2 // PROBE BACKOFF DISTANCE mm, - @110 = 1.0 // DEFAULT PART TOLERANCE + @107 = 2 // PROBE BACKOFF DISTANCE mm, + @108 = 1.0 // DEFAULT PART TOLERANCE - @117 = 750 // FAST Tool Probe SPEED mm/m, - @116 = 40 // SLOW Tool Probe SPEED mm/m, + @109 = 750 // FAST Tool Probe SPEED mm/m, + @110 = 40 // SLOW Tool Probe SPEED mm/m, - @11 = 1000 // rounding multiplier for 3 decimal places + @91 = 1000 // rounding multiplier for 3 decimal places END_IF; // Freedom unit settings @@ -45,24 +47,24 @@ IF[@10 == 20] @104 = 50 // FAST PROBE SPEED in/m, @105 = 2.5 // SLOW PROBE SPEED in/m, @106 = 0.5 // PROBE CLEARANCE DISTANCE in, - @108 = 0.125 // PROBE BACKOFF DISTANCE, + @107 = 0.125 // PROBE BACKOFF DISTANCE, - @110 = 0.05 // DEFAULT PART TOLERANCE + @108 = 0.05 // DEFAULT PART TOLERANCE - @117 = 30 // FAST Tool Probe SPEED in/m, - @116 = 1.5 // SLOW Tool Probe SPEED in/m, + @109 = 30 // FAST Tool Probe SPEED in/m, + @110 = 1.5 // SLOW Tool Probe SPEED in/m, - @11 = 10000 // rounding multiplier for 4 decimal places + @91 = 10000 // rounding multiplier for 4 decimal places END_IF; -@101 = R_TOOL_DATA[0,@100,3] // TOOL DIAMETER, DO NOT TOUCH!!! -@102 = @101/2 // TOOL RADIUS, DO NOT TOUCH!!! -@107 = [R_TOOL_DATA[0,@100,203]] // TOOL LENGHT OFFSET, DO NOT TOUCH!!! - IF [@100==-1] ALARM["Hard code probe number in PROBECONFIG macro"] END_IF +@130 = R_TOOL_DATA[0,@100,3] // TOOL DIAMETER, DO NOT TOUCH!!! +@131 = @130/2 // TOOL RADIUS, DO NOT TOUCH!!! +@133 = [R_TOOL_DATA[0,@100,203]] // TOOL LENGHT OFFSET, DO NOT TOUCH!!! + #120=R_SYS_INFO[0,2] // CURRENT TOOL NUMBER IF [@100 != #120 && #20==#0] // THE PROBE IS NOT LOADED ALARM["Error: Protected move without probe - change to T#100 "] @@ -72,34 +74,34 @@ G90 IF [#1 != #0] IF [ROUND[MOD[#1,1] * 100] > 0] - @114 = ROUND[MOD[#1,1] * 100] // Extract the decimal part and multiply by 100 - IF [@114 < 1 || @114 >= #137] - ALARM["ERROR: Probe WCS G54 P@114 protected via ProbeConfig Macro"] + @121 = ROUND[MOD[#1,1] * 100] // Extract the decimal part and multiply by 100 + IF [@121 < 1 || @121 >= #111] + ALARM["ERROR: Probe WCS G54 P@121 protected via ProbeConfig Macro"] END_IF IF [FIX[#1] != 54] ALARM["ERROR: G54 must be used when calling extended work offsets"] END_IF ELSE - @114 = #1 - IF [@114 < 54 || @114 > 59] - ALARM["ERROR: Probe WCS G@114 out of range"] + @121 = #1 + IF [@121 < 54 || @121 > 59] + ALARM["ERROR: Probe WCS G@121 out of range"] END_IF END_IF END_IF IF [#2 != #0] IF [ROUND[MOD[#2,1] * 100] > 0] - @115 = ROUND[MOD[#2,1] * 100] // Extract the decimal part and multiply by 100 - IF [@115 < 1 || @115 >= #137] - ALARM["ERROR: Override WCS G54 P@115 protected via ProbeConfig Macro"] + @122 = ROUND[MOD[#2,1] * 100] // Extract the decimal part and multiply by 100 + IF [@122 < 1 || @122 >= #111] + ALARM["ERROR: Override WCS G54 P@122 protected via ProbeConfig Macro"] END_IF IF [FIX[#2] != 54] ALARM["ERROR: G54 must be used when calling extended work offsets"] END_IF ELSE - @115 = #2 - IF [@115 < 54 || @115 > 59] - ALARM["ERROR: Override WCS G@115 out of range"] + @122 = #2 + IF [@122 < 54 || @122 > 59] + ALARM["ERROR: Override WCS G@122 out of range"] END_IF END_IF END_IF diff --git a/Macros for Controller/PROBEINSIDECORNER b/Macros for Controller/PROBEINSIDECORNER index 2f31a96..ce6f3c4 100644 --- a/Macros for Controller/PROBEINSIDECORNER +++ b/Macros for Controller/PROBEINSIDECORNER @@ -5,10 +5,10 @@ // Probe ONE OF 4 INSIDE CORNERS // Argument A -> #1 is the work coordinate system to store offsets in. The format for extended G54 offsets would be a period followed by the offset// G54.5 -// Argument B -> #2 defines which corner +// Argument C -> #3 defines which corner // 1 2 // 3 4 -// Argument C -> #3 is the desired distance to probe part +// Argument E -> #5 engage distance to probe part // Simplified WCS extended number math, added probe error checking, added probe distance argument // Modified 31/03/2025: Robot Oblivion @@ -16,7 +16,7 @@ // load probe config G65 "PROBECONFIG" -#128 = @128 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO +#128 = @96 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO IF[#128 == 1] M19 // ORIENT SPINDLE END_IF @@ -26,47 +26,47 @@ END_IF #110 = @103 // FEED SPEED PROVIDED BY PROBECONFIG MACRO #111 = @104 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO #112 = @105 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO -#105 = @102 // TOOL RADIUS PROVIDED BY PROBECONFIG MACRO -#108 = @108*[#2/ABS[#2]] // PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO * the sign// +1 or -1 of probe distance +#105 = @131 // TOOL RADIUS PROVIDED BY PROBECONFIG MACRO +#108 = @107*[#3/ABS[#3]] // PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO * the sign// +1 or -1 of probe distance // #120 is X APPROACH DIRECTION -// #121 is Y APPROACH DIRECTION -IF[#2==1] +// #101 is Y APPROACH DIRECTION +IF[#3==1] #120 = -1 - #121 = 1 -ELSEIF[#2==2] + #101 = 1 +ELSEIF[#3==2] #120 = 1 - #121 = 1 -ELSEIF[#2==3] + #101 = 1 +ELSEIF[#3==3] #120 = -1 - #121 = -1 -ELSEIF[#2==4] + #101 = -1 +ELSEIF[#3==4] #120 = 1 - #121 = -1 + #101 = -1 END_IF // RECORD INITIAL POSITION SO WE CAN TOGGLE BACK TO IT -#122 = R_MACH_COOR[0,1] // MACHINE X COORDINATE +#102 = R_MACH_COOR[0,1] // MACHINE X COORDINATE #123 = R_MACH_COOR[0,2] // MACHINE Y COORDINATE // PROBE PART IN X -G65 "PROBEX" A#1 B#120*#3 +G65 "PROBEX" A#1 X[#120*#5] // MOVE BACK TO ORIGINAL XY LOCATION -#126 = [#122-R_MACH_COOR[0,1]] +#126 = [#102-R_MACH_COOR[0,1]] #127 = [#123-R_MACH_COOR[0,2]] -G31 G91 P2 X[#126] F#111 // PROTECTED MOVE -G31 G91 P2 Y[#127] F#111 // PROTECTED MOVE +G31 G91 P2 X#126 F#111 // PROTECTED MOVE +G31 G91 P2 Y#127 F#111 // PROTECTED MOVE // PROBE PART IN Y -G65 "PROBEY" A#1 B#121*#3 +G65 "PROBEY" A#1 Y[#101*#5] // MOVE BACK TO ORIGINAL XY LOCATION -#126 = [#122-R_MACH_COOR[0,1]] +#126 = [#102-R_MACH_COOR[0,1]] #127 = [#123-R_MACH_COOR[0,2]] -G31 G91 P2 Y[#127] F#111 // PROTECTED MOVE -G31 G91 P2 X[#126] F#111 // PROTECTED MOVE +G31 G91 P2 Y#127 F#111 // PROTECTED MOVE +G31 G91 P2 X#126 F#111 // PROTECTED MOVE IF[#128 == 1] M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY diff --git a/Macros for Controller/PROBEOUTSIDECORNER b/Macros for Controller/PROBEOUTSIDECORNER index 4fea02a..9c51a56 100644 --- a/Macros for Controller/PROBEOUTSIDECORNER +++ b/Macros for Controller/PROBEOUTSIDECORNER @@ -4,11 +4,11 @@ // Probe ONE OF 4 OUTSIDE CORNERS // Argument A -> #1 is the work coordinate system to store offsets in. The format for extended G54 offsets would be a period followed by the offset -- G54.5 -// Argument B -> #2 defines which corner +// Argument C -> #3 defines which corner // 1 2 // 3 4 -// Argument C -> #3 is the desired probing distance from the corner -// Argument D -> #4 is the desired distance to probe part +// Argument D -> #4 is the desired probing distance from the corner +// Argument E -> #5 engage distance to probe part // Simplified WCS extended number math, added probe error checking, added probe distance argument // Modified 31/03/2025: Robot Oblivion @@ -16,7 +16,7 @@ // load probe config G65 "PROBECONFIG" -#128 = @128 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO +#128 = @96 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO IF[#128 == 1] M19 // ORIENT SPINDLE END_IF @@ -26,32 +26,32 @@ END_IF #110 = @103 // FEED SPEED PROVIDED BY PROBECONFIG MACRO #111 = @104 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO #112 = @105 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO -#105 = @102 // TOOL RADIUS PROVIDED BY PROBECONFIG MACRO -#108 = @108*[#2/ABS[#2]] // PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO * the sign// +1 or -1 of probe distance +#105 = @131 // TOOL RADIUS PROVIDED BY PROBECONFIG MACRO +#108 = @107*[#3/ABS[#3]] // PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO * the sign// +1 or -1 of probe distance // #120 is X APPROACH DIRECTION -// #121 is Y APPROACH DIRECTION -IF[#2==1] +// #101 is Y APPROACH DIRECTION +IF[#3==1] #120 = 1 - #121 = -1 -ELSEIF[#2==2] + #101 = -1 +ELSEIF[#3==2] #120 = -1 - #121 = -1 -ELSEIF[#2==3] + #101 = -1 +ELSEIF[#3==3] #120 = 1 - #121 = 1 -ELSEIF[#2==4] + #101 = 1 +ELSEIF[#3==4] #120 = -1 - #121 = 1 + #101 = 1 END_IF // RECORD INITIAL POSITION SO WE CAN TOGGLE BACK TO IT -#122 = R_MACH_COOR[0,1] // MACHINE X COORDINATE +#102 = R_MACH_COOR[0,1] // MACHINE X COORDINATE #123 = R_MACH_COOR[0,2] // MACHINE Y COORDINATE // MOVE TO THE X PROBE LOCATION -G31 G91 P2 Y[#121*#3] F#111 // PROTECTED MOVE +G31 G91 P2 Y[#101*#4] F#111 // PROTECTED MOVE // Error Checking IF[R_SKIP[0,1] == 1] @@ -60,17 +60,17 @@ IF[R_SKIP[0,1] == 1] END_IF // PROBE PART IN X -G65 "PROBEX" A#1 B#120*#4 +G65 "PROBEX" A#1 X[#120*#5] // MOVE BACK TO ORIGINAL XY LOCATION -#126 = [#122-R_MACH_COOR[0,1]] +#126 = [#102-R_MACH_COOR[0,1]] #127 = [#123-R_MACH_COOR[0,2]] -G31 G91 P2 X[#126] F#111 // PROTECTED MOVE -G31 G91 P2 Y[#127] F#111 // PROTECTED MOVE +G31 G91 P2 X#126 F#111 // PROTECTED MOVE +G31 G91 P2 Y#127 F#111 // PROTECTED MOVE // MOVE TO THE Y PROBE LOCATION -G31 G91 P2 X[#120*#3] F#111 // PROTECTED MOVE +G31 G91 P2 X[#120*#4] F#111 // PROTECTED MOVE // Error Checking @@ -80,13 +80,13 @@ IF[R_SKIP[0,1] == 1] END_IF // PROBE PART IN Y -G65 "PROBEY" A#1 B#121*#4 +G65 "PROBEY" A#1 Y[#101*#5] // MOVE BACK TO ORIGINAL XY LOCATION -#126 = [#122-R_MACH_COOR[0,1]] +#126 = [#102-R_MACH_COOR[0,1]] #127 = [#123-R_MACH_COOR[0,2]] -G31 G91 P2 Y[#127] F#111 // PROTECTED MOVE -G31 G91 P2 X[#126] F#111 // PROTECTED MOVE +G31 G91 P2 Y#127 F#111 // PROTECTED MOVE +G31 G91 P2 X#126 F#111 // PROTECTED MOVE N1 diff --git a/Macros for Controller/PROBEPOCKET b/Macros for Controller/PROBEPOCKET index 8646d9c..720445d 100644 --- a/Macros for Controller/PROBEPOCKET +++ b/Macros for Controller/PROBEPOCKET @@ -1,11 +1,11 @@ // Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion -// PROBEBORE +// PROBEPOCKET // Probe a bore in X and Y // Argument A -> #1 is the work coordinate system to store offsets in -// Argument B -> #2 is the expected length -// Argument C -> #3 is the expected width +// Argument X -> #24 is the expected width +// Argument Y -> #25 is the expected length // Argument I -> #9 print results enabled by fusion360 // Argument Q -> #17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on // Argument R -> #18 oversize tolorance @@ -18,13 +18,13 @@ @10 = R_G_GROUP[0,6] // pull in metric or freedom units - G65 "PROBEXSLOT" A#1 B#2 Q0 I#9 R#18 S#19 - G65 "PROBEYSLOT" A#1 B#3 Q0 I#9 R#18 S#19 + G65 "PROBEXSLOT" A#1 X#24 Q0 I#9 R#18 S#19 + G65 "PROBEYSLOT" A#1 Y#25 Q0 I#9 R#18 S#19 //simple inspection reporting IF [#17 > 0] - #98 = ROUND[@998 * @11] / @11 // Round to 3/4 decimal places - #99 = ROUND[@999 * @11] / @11 // Round to 3/4 decimal places + #98 = ROUND[@998 * @91] / @91 // Round to 3/4 decimal places + #99 = ROUND[@999 * @91] / @91 // Round to 3/4 decimal places IF[@10 == 21] MENU_ADD["Part Width mm X: #98",""]; MENU_ADD["Part Length mm Y: #99",""]; diff --git a/Macros for Controller/PROBERECTANGULARBOSS b/Macros for Controller/PROBERECTANGULARBOSS index 3e87fae..f6e7ebb 100644 --- a/Macros for Controller/PROBERECTANGULARBOSS +++ b/Macros for Controller/PROBERECTANGULARBOSS @@ -4,9 +4,9 @@ // Probe a rectangular boss in X and Y // Argument A -> #1 is the work coordinate system to store offsets in -// Argument B -> #2 is the expected length of the web in the X direction //KC -// Argument C -> #3 is the expected width of the web in the Y direction //KC -// Argument D -> #4 is the Z drop height //KC +// Argument X -> #24 is the expected length of the web in the X direction //KC +// Argument Y -> #25 is the expected width of the web in the Y direction //KC +// Argument Z -> #26 is the Z drop height //KC // Argument I -> #9 print results enabled by fusion360 // Argument Q -> #17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on // Argument R -> #18 oversize tolorance @@ -19,14 +19,14 @@ @10 = R_G_GROUP[0,6] // pull in metric or freedom units -G65 "PROBEXWEB" A#1 B#2 C#4 I#9 Q0 R#18 S#19 -G65 "PROBEYWEB" A#1 B#3 C#4 I#9 Q0 R#18 S#19 +G65 "PROBEXWEB" A#1 X#24 Z#26 I#9 Q0 R#18 S#19 +G65 "PROBEYWEB" A#1 Y#25 Z#26 I#9 Q0 R#18 S#19 //simple inspection reporting //@999 and @998 are set in the web macros IF [#17 > 0] - #98 = ROUND[@998 * @11] / @11 // Round to 3/4 decimal places - #99 = ROUND[@999 * @11] / @11 // Round to 3/4 decimal places + #98 = ROUND[@998 * @91] / @91 // Round to 3/4 decimal places + #99 = ROUND[@999 * @91] / @91 // Round to 3/4 decimal places IF[@10 == 21] MENU_ADD["Part Width mm X: #98",""]; MENU_ADD["Part Length mm Y: #99",""]; diff --git a/Macros for Controller/PROBEX b/Macros for Controller/PROBEX index d4dc98d..9aa9354 100644 --- a/Macros for Controller/PROBEX +++ b/Macros for Controller/PROBEX @@ -4,7 +4,7 @@ // Probe in X from the left or right side // Argument A -> #1 is the work coordinate system to store offsets in. The format for extended G54 offsets would be a period followed by the offset G54.5 -// Argument B -> #2 is the desired probing distance. Enter a positive value to probe on the left side and a negative value to probe on the right side +// Argument X -> #24 is the desired probing distance. Enter a positive value to probe on the left side and a negative value to probe on the right side // Argument I -> #9 print results enabled by fusion360 // Initial Coding: Justin Gray @@ -18,30 +18,30 @@ G65 "PROBECONFIG" A#1 // important local variables #111 = @104 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO #112 = @105 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO -#105 = @102 // TOOL RADIUS PROVIDED BY PROBECONFIG MACRO -#108 = @108*[#2/ABS[#2]] // PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO * the sign +1 or -1 of probe distance -#114 = @114 // processed extended WCS number provided by ProbeConfig macro -#128 = @128 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO +#105 = @131 // TOOL RADIUS PROVIDED BY PROBECONFIG MACRO +#108 = @107*[#24/ABS[#24]] // PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO * the sign +1 or -1 of probe distance +#114 = @121 // processed extended WCS number provided by ProbeConfig macro +#128 = @96 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO M20 // UNLOCK SPINDLE ORIENT -IF[#2 < 0] +IF[#24 < 0] M19 P180 // ORIENT SPINDLE 180 DEGREES ELSE M19 P0 // ORIENT SPINDLE 0 DEGREES END_IF //Probe X the desired distance and at fast feed -G31 G91 P2 X[#2] F#111 //FEED UNTIL SKIP FAST +G31 G91 P2 X[#24] F#111 //FEED UNTIL SKIP FAST //Check that the probe has triggered IF[R_SKIP[0,1] == 1] G91 G01 X-[#108] //back off distance provided by ProbeConfig macro FIX_CUT_OR_ON - G31 G91 P2 X[#2] F#112 //Probe X the desired distance at slow feed + G31 G91 P2 X[#24] F#112 //Probe X the desired distance at slow feed FIX_CUT_OR_OFF #104=R_SKIP[0,201] //GET MACHINE X COORDINATE G91 G01 X-[#108] //back off distance provided by ProbeConfig macro - #106 = [#104+[[#2/abs[#2]]*#105]] //current position +/- probe radius + #106 = [#104+[[#24/abs[#24]]*#105]] //current position +/- probe radius @996 = #106 //safety check for inspection variable diff --git a/Macros for Controller/PROBEXSLOT b/Macros for Controller/PROBEXSLOT index e9366d7..7c75220 100644 --- a/Macros for Controller/PROBEXSLOT +++ b/Macros for Controller/PROBEXSLOT @@ -4,7 +4,7 @@ // Probe a SLOT in X from left to right // Argument A -> #1 is the work coordinate system to store offsets in -// Argument B -> #2 is the expected width of the web in the X direction +// Argument X -> #24 is the expected width of the web in the X direction // Argument I -> #9 print results enabled by fusion360 // Argument Q -> #17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on // Argument R -> #18 oversize tolorance @@ -25,16 +25,16 @@ M19 P180 // ORIENT SPINDLE 180 DEGREES TO KEEP THE POBIN #100 = @100 //TOOL NUMBER PROVIDED BY PROBECONFIG MACRO #111 = @104 //FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO #112 = @105 //SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO -#121 = @101 //TOOL DIAMETER PROVIDED BY PROBECONFIG MACRO -#122 = @106 //WEB PROBE DISTANCE PROVIDED BY PROBECONFIG MACRO -#108 = @108 //PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO -#2 = ABS[#2] -#114 = @114 // processed extended WCS number provided by ProbeConfig macro +#101 = @130 //TOOL DIAMETER PROVIDED BY PROBECONFIG MACRO +#102 = @106 //WEB PROBE DISTANCE PROVIDED BY PROBECONFIG MACRO +#108 = @107 //PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO +#24 = ABS[#24] +#114 = @121 // processed extended WCS number provided by ProbeConfig macro //probe X starting from a negative offset and probing in the positive direction //MOVE TO -X SIDE OF THE PART, BEFORE STARTING TO PROBE -G31 G91 P2 X-[#2/2+#122] F#111 +G31 G91 P2 X-[#24/2+#102] F#111 //Error Checking IF[R_SKIP[0,1] == 0] @@ -53,7 +53,7 @@ M20 // UNLOCK SPINDLE ORIENT M19 P0 // ORIENT SPINDLE 0 DEGREES TO KEEP THE POBING POINT THE SAME //Move to opposite side of part -G31 G91 P2 X[#2+#122-#108] F#111 //move to other side of the part, probe distance away +G31 G91 P2 X[#24+#102-#108] F#111 //move to other side of the part, probe distance away //Error Checking IF[R_SKIP[0,1] == 0] @@ -70,27 +70,29 @@ G91 G01 X[-#108] //BACK OFF //COMPUTE RELATIVE DISTANCE TO CENTER OF THE PART #106=[[#105-#104]/2] //center point calculation -#107= ABS[[#105-#104]]+#121 //calculate width of part: distance + diameter +#107= ABS[[#105-#104]]+#101 //calculate width of part: distance + diameter @998 = #107 //save distance to a global variable for use with other macros G91 G01 X[-#106 + #108] //MOVE TO CENTER OF THE PART #104=R_MACH_COOR[0,1] //GET MACHINE Y COORDINATE -#126=ABS[#107-#2] //expected stock error +#126=ABS[#107-#24] //expected stock error //if the tolorance is null, default it to global variable from the probe config IF[#18==#0] - #18 = @110 + #18 = @108 END_IF //oversized stock alarm if stock error is greater than tolorance IF[#19!=#0 && #126>#18 ] - #136 = ROUND[[#107-#2] * @11] / @11 // Round to 3/4 decimal places - #107 = ROUND[#107 * @11] / @11 // Round to 3/4 decimal places - MENU_ADD["Expected size: #2",""]; + #136 = ROUND[[#107-#24] * @91] / @91 // Round to 3/4 decimal places + #107 = ROUND[#107 * @91] / @91 // Round to 3/4 decimal places + MENU_ADD["Expected size: #24",""]; MENU_ADD["Probed size: #107",""]; MENU_ADD["Tolerance: #18",""]; MENU_ADD["Off-target: #136",""]; MENU["Error","Stock outside of tolerance in X","",1]; - ALARM["Error: Stock outside of tolerance in X"] + IF[@97 == 1] + ALARM["Error: Stock outside of tolerance in X"] + END_IF END_IF //safety check for inspection variable @@ -110,7 +112,7 @@ END_IF //simple inspection reporting IF [#17 > 0] - #98 = ROUND[@998 * @11] / @11 // Round to 3/4 decimal places + #98 = ROUND[@998 * @91] / @91 // Round to 3/4 decimal places IF[@10 == 21] MENU_ADD["Part Width mm X: #98",""]; ELSE diff --git a/Macros for Controller/PROBEXWEB b/Macros for Controller/PROBEXWEB index 7e0483d..0401d18 100644 --- a/Macros for Controller/PROBEXWEB +++ b/Macros for Controller/PROBEXWEB @@ -4,8 +4,8 @@ // Probe a web in X from left to right // Argument A -> #1 is the work coordinate system to store offsets in -// Argument B -> #2 is the expected width of the web in the X direction -// Argument C -> #3 is the Z drop height +// Argument X -> #24 is the expected width of the web in the X direction +// Argument Z -> #26 is the Z drop height // Argument I -> #9 print results enabled by fusion360 // Argument Q -> #17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on // Argument R -> #18 oversize tolorance @@ -24,16 +24,16 @@ G65 "PROBECONFIG" A#1 #110 = @103 //FEED SPEED PROVIDED BY PROBECONFIG MACRO #111 = @104 //FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO #112 = @105 //SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO -#121 = @101 //TOOL DIAMETER PROVIDED BY PROBECONFIG MACRO -#122 = @106 //WEB PROBE DISTANCE PROVIDED BY PROBECONFIG MACRO -#108 = @108 //PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO -#2 = ABS[#2] -#3 = ABS[#3] -#114 = @114 // processed extended WCS number provided by ProbeConfig macro +#101 = @130 //TOOL DIAMETER PROVIDED BY PROBECONFIG MACRO +#102 = @106 //WEB PROBE DISTANCE PROVIDED BY PROBECONFIG MACRO +#108 = @107 //PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO +#24 = ABS[#24] +#26 = ABS[#26] +#114 = @121 // processed extended WCS number provided by ProbeConfig macro //probe X starting from a negative offset and probing in the positive direction //MOVE TO -X SIDE OF THE PART, BEFORE STARTING TO PROBE -G31 G91 P2 X-[#2/2+#122] F#110 +G31 G91 P2 X-[#24/2+#102] F#110 //Error Checking IF[R_SKIP[0,1] == 1] @@ -45,7 +45,7 @@ M20 // UNLOCK SPINDLE ORIENT M19 P0 // ORIENT SPINDLE 0 DEGREES TO KEEP THE POBING POINT THE SAME //DROP TO PROBING HEIGHT -G31 G91 P2 Z-#3 F#110 +G31 G91 P2 Z-#26 F#110 //Error Checking IF[R_SKIP[0,1] == 1] @@ -54,7 +54,7 @@ IF[R_SKIP[0,1] == 1] END_IF //Probe X on left side -G31 G91 P2 X[#122+#108] F#111 //FEED PROBING DINSTANCE + BACK OFF UNTIL SKIP FAST +G31 G91 P2 X[#102+#108] F#111 //FEED PROBING DINSTANCE + BACK OFF UNTIL SKIP FAST //Error Checking IF[R_SKIP[0,1] == 0] @@ -70,10 +70,10 @@ FIX_CUT_OR_OFF G91 G01 X-[#108] //Back off //lift Z after probe -G31 G91 P2 Z#3 F#110 //move above the part +G31 G91 P2 Z#26 F#110 //move above the part //Move to opposite side of part -G31 G91 P2 X[#2+#122+#108] F#110 //move to other side of the part, probe distance away +G31 G91 P2 X[#24+#102+#108] F#110 //move to other side of the part, probe distance away //Error Checking IF[R_SKIP[0,1] == 1] @@ -85,7 +85,7 @@ M20 // UNLOCK SPINDLE ORIENT M19 P180 // ORIENT SPINDLE 180 DEGREES TO KEEP THE POBING POINT THE SAME //Drop to Probing Height -G31 G91 P2 Z-#3 F#110 //move back down to probe height +G31 G91 P2 Z-#26 F#110 //move back down to probe height //Error Checking IF[R_SKIP[0,1] == 1] @@ -94,7 +94,7 @@ IF[R_SKIP[0,1] == 1] END_IF //Probe X on right side -G31 G91 P2 X[-1*[#122+#108]] F#111 //FEED PROBING DINSTANCE + BACK OFF UNTIL SKIP FAST +G31 G91 P2 X[-1*[#102+#108]] F#111 //FEED PROBING DINSTANCE + BACK OFF UNTIL SKIP FAST //Error Checking IF[R_SKIP[0,1] == 0] @@ -108,31 +108,33 @@ G31 G91 P2 X[-#108] F#112 //FEED UNTIL SKIP SLOW FIX_CUT_OR_OFF #105=R_SKIP[0,201] //GET SECOND MACHINE X COORDINATE G91 G01 X[#108] F#110 //BACK OFF -G91 G01 Z#3 //MOVE UP CLEAR OF THE PART +G91 G01 Z#26 //MOVE UP CLEAR OF THE PART //COMPUTE RELATIVE DISTANCE TO CENTER OF THE PART #106=[[#105-#104]/2] //center point calculation -#107= ABS[[#105-#104]]-#121 //calculate width of part: distance - diameter +#107= ABS[[#105-#104]]-#101 //calculate width of part: distance - diameter @998 = #107 //save distance to a global variable for use with other macros G91 G01 X[-#108 - #106] //MOVE TO CENTER OF THE PART #104=R_MACH_COOR[0,1] //GET MACHINE X COORDINATE -#126=ABS[#107-#2] //expected stock error +#126=ABS[#107-#24] //expected stock error //if the tolorance is null, default it to global variable from the probe config IF[#18==#0] - #18 = @110 + #18 = @108 END_IF //oversized stock alarm if stock error is greater than tolorance IF[#19!=#0 && #126>#18 ] -#136 = ROUND[[#107-#2] * @11] / @11 // Round to 3/4 decimal places -#107 = ROUND[#107 * @11] / @11 // Round to 3/4 decimal places - MENU_ADD["Expected size: #2",""]; +#136 = ROUND[[#107-#24] * @91] / @91 // Round to 3/4 decimal places +#107 = ROUND[#107 * @91] / @91 // Round to 3/4 decimal places + MENU_ADD["Expected size: #24",""]; MENU_ADD["Probed size: #107",""]; MENU_ADD["Tolerance: #18",""]; MENU_ADD["Off-target: #136",""]; MENU["Error","Stock outside of tolerance in X","",1]; - ALARM["Error: Stock outside of tolerance in X"] + IF[@97 == 1] + ALARM["Error: Stock outside of tolerance in X"] + END_IF END_IF //safety check for inspection variable @@ -151,7 +153,7 @@ END_IF //simple inspection reporting IF [#17 > 0] - #98 = ROUND[@998 * @11] / @11 // Round to 3/4 decimal places + #98 = ROUND[@998 * @91] / @91 // Round to 3/4 decimal places IF[@10 == 21] MENU_ADD["Part Width mm X: #98",""]; ELSE diff --git a/Macros for Controller/PROBEXYANGLE b/Macros for Controller/PROBEXYANGLE index 381a86c..42eecc1 100644 --- a/Macros for Controller/PROBEXYANGLE +++ b/Macros for Controller/PROBEXYANGLE @@ -20,12 +20,12 @@ G65 "PROBECONFIG" A#1 #110 = @103 // FEED SPEED PROVIDED BY PROBECONFIG MACRO #111 = @104 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO #112 = @105 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO -#108 = @108 // PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO +#108 = @107 // PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO #109 = R_MACH_COOR[0,1] // GET MACHINE X COORDINATE #110 = R_MACH_COOR[0,2] // GET MACHINE y COORDINATE #111 = R_MACH_COOR[0,3] // GET MACHINE z COORDINATE -#128 = @128 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO -#114 = @114 // processed extended WCS number provided by ProbeConfig macro +#128 = @96 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO +#114 = @121 // processed extended WCS number provided by ProbeConfig macro IF[#128 == 1] M19 // ORIENT SPINDLE @@ -48,8 +48,8 @@ IF[#4== 1] G31 G91 P2 X[#108] F#112 // Probe X the desired distance at slow feed FIX_CUT_OR_OFF #120 = R_SKIP[0,201] // GET MACHINE X COORDINATE - #121 = R_SKIP[0,202] // GET MACHINE Y COORDINATE - #122 = R_SKIP[0,202] // GET MACHINE Y COORDINATE + #101 = R_SKIP[0,202] // GET MACHINE Y COORDINATE + #102 = R_SKIP[0,202] // GET MACHINE Y COORDINATE G91 G01 X-[#108] // back off 1/4 the probing distance // move to original X position @@ -100,7 +100,7 @@ IF[#4== 1] END_IF // angle claculation - #126 = ATAN[[#123-#120],[#124-#121]] + #126 = ATAN[[#123-#120],[#124-#101]] ELSE // Probe Y the desired distance and at fast feed @@ -118,12 +118,12 @@ ELSE G31 G91 P2 Y[#108] F#112 // Probe X the desired distance at slow feed FIX_CUT_OR_OFF #120 = R_SKIP[0,201] // GET MACHINE X COORDINATE - #121 = R_SKIP[0,202] // GET MACHINE Y COORDINATE - #122 = R_SKIP[0,202] // GET MACHINE Z COORDINATE + #101 = R_SKIP[0,202] // GET MACHINE Y COORDINATE + #102 = R_SKIP[0,202] // GET MACHINE Z COORDINATE G91 G01 Y-[#108] // back off 1/4 the probing distance // move to original Y position - G31 G91 P2 Y[-#110+#121+#108] F#111 + G31 G91 P2 Y[-#110+#101+#108] F#111 // Error Checking IF[R_SKIP[0,1] == 1] @@ -170,7 +170,7 @@ ELSE END_IF // angle claculation - #126 = ATAN[[#124-#121],[#123-#120]] + #126 = ATAN[[#124-#101],[#123-#120]] END_IF diff --git a/Macros for Controller/PROBEY b/Macros for Controller/PROBEY index 03d2a6e..9bb798c 100644 --- a/Macros for Controller/PROBEY +++ b/Macros for Controller/PROBEY @@ -4,7 +4,7 @@ // Probe in Y from the front or back // Argument A -> #1 is the work coordinate system to store offsets in. The format for extended G54 offsets would be a period followed by the offset G54.5 -// Argument B -> #2 is the desired probing distance. Enter a positive value to probe the front and a negative value to probe the back +// Argument Y -> #25 is the desired probing distance. Enter a positive value to probe the front and a negative value to probe the back // Argument I -> #9 print results enabled by fusion360 // Initial Coding: Justin Gray @@ -18,30 +18,30 @@ G65 "PROBECONFIG" A#1 // important local variables #111 = @104 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO #112 = @105 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO -#105 = @102 // TOOL RADIUS PROVIDED BY PROBECONFIG MACRO -#108 = @108*[#2/ABS[#2]] // PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO * the sign +1 or -1 of probe distance -#114 = @114 // processed extended WCS number provided by ProbeConfig macro -#128 = @128 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO +#105 = @131 // TOOL RADIUS PROVIDED BY PROBECONFIG MACRO +#108 = @107*[#25/ABS[#25]] // PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO * the sign +1 or -1 of probe distance +#114 = @121 // processed extended WCS number provided by ProbeConfig macro +#128 = @96 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO M20 // UNLOCK SPINDLE ORIENT -IF[#2 < 0] +IF[#25 < 0] M19 P270 // ORIENT SPINDLE 270 DEGREES ELSE M19 P90 // ORIENT SPINDLE 0 DEGREES END_IF //Probe X the desired distance and at fast feed -G31 G91 P2 Y[#2] F#111 //FEED UNTIL SKIP FAST +G31 G91 P2 Y[#25] F#111 //FEED UNTIL SKIP FAST //Check that the probe has triggered IF[R_SKIP[0,1] == 1] G91 G01 Y-[#108] //back off distance provided by ProbeConfig macro FIX_CUT_OR_ON - G31 G91 P2 Y[#2] F#112 //Probe Y the desired distance at slow feed + G31 G91 P2 Y[#25] F#112 //Probe Y the desired distance at slow feed FIX_CUT_OR_OFF #104=R_SKIP[0,202] //GET MACHINE Y COORDINATE G91 G01 Y-[#108] //back off distance provided by ProbeConfig macro - #106 = [#104+[[#2/abs[#2]]*#105]] //current position +/- probe radius + #106 = [#104+[[#25/abs[#25]]*#105]] //current position +/- probe radius @996 = #106 //safety check for inspection variable diff --git a/Macros for Controller/PROBEYSLOT b/Macros for Controller/PROBEYSLOT index 05e429a..266f23b 100644 --- a/Macros for Controller/PROBEYSLOT +++ b/Macros for Controller/PROBEYSLOT @@ -4,7 +4,7 @@ // Probe a web in X from left to right // Argument A -> #1 is the work coordinate system to store offsets in -// Argument B -> #2 is the expected length of the web in the Y direction +// Argument Y -> #25 is the expected length of the web in the Y direction // Argument I -> #9 print results enabled by fusion360 // Argument Q -> #17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on // Argument R -> #18 oversize tolorance @@ -26,15 +26,15 @@ M19 P270 // ORIENT SPINDLE 270 DEGREES TO KEEP THE POBIN #110 = @103 //FEED SPEED PROVIDED BY PROBECONFIG MACRO #111 = @104 //FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO #112 = @105 //SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO -#121 = @101 //TOOL DIAMETER PROVIDED BY PROBECONFIG MACRO -#122 = @106 //WEB PROBE DISTANCE PROVIDED BY PROBECONFIG MACRO -#108 = @108 //PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO -#2 = ABS[#2] -#114 = @114 // processed extended WCS number provided by ProbeConfig macro +#101 = @130 //TOOL DIAMETER PROVIDED BY PROBECONFIG MACRO +#102 = @106 //WEB PROBE DISTANCE PROVIDED BY PROBECONFIG MACRO +#108 = @107 //PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO +#25 = ABS[#25] +#114 = @121 // processed extended WCS number provided by ProbeConfig macro //probe Y starting from a negative offset and probing in the positive direction //MOVE TO -Y SIDE OF THE PART, BEFORE STARTING TO PROBE -G31 G91 P2 Y-[#2/2+#122] F#111 +G31 G91 P2 Y-[#25/2+#102] F#111 //Error Checking IF[R_SKIP[0,1] == 0] @@ -53,7 +53,7 @@ M20 // UNLOCK SPINDLE ORIENT M19 P90 // ORIENT SPINDLE 90 DEGREES TO KEEP THE POBING POINT THE SAME //move to the opposite side of the part -G31 G91 P2 Y[#2+#122-#108] F#111 //move to other side of the part,pobe distance away +G31 G91 P2 Y[#25+#102-#108] F#111 //move to other side of the part,pobe distance away //Error Checking IF[R_SKIP[0,1] == 0] @@ -70,27 +70,29 @@ G91 G01 Y[-#108] F#110 //back off //COMPUTE RELATIVE DISTANCE TO CENTER OF THE PART #106 = [[#105-#104]/2] //calculate center -#107 = ABS[#105-#104]+#121 //calculate distance: distance - diameter +#107 = ABS[#105-#104]+#101 //calculate distance: distance - diameter @999 = #107 //save distance to a global variable for use with other macros G91 G01 Y[-#106 + #108] //MOVE TO CENTER OF THE PART #104=R_MACH_COOR[0,2] //GET MACHINE Y COORDINATE -#126=ABS[#107-#2] //expected stock error +#126=ABS[#107-#25] //expected stock error //if the tolorance is null, default it to global variable from the probe config IF[#18==#0] - #18 = @110 + #18 = @108 END_IF //oversized stock alarm if stock error is greater than tolorance IF[#19!=#0 && #126>#18 ] - #136 = ROUND[[#107-#2] * @11] / @11 // Round to 3/4 decimal places - #107 = ROUND[#107 * @11] / @11 // Round to 3/4 decimal places - MENU_ADD["Expected size: #2",""]; + #136 = ROUND[[#107-#25] * @91] / @91 // Round to 3/4 decimal places + #107 = ROUND[#107 * @91] / @91 // Round to 3/4 decimal places + MENU_ADD["Expected size: #25",""]; MENU_ADD["Probed size: #107",""]; MENU_ADD["Tolerance: #18",""]; MENU_ADD["Off-target: #136",""]; MENU["Error","Stock outside of tolerance in Y","",1]; - ALARM["Error: Stock outside of tolerance in Y"] + IF[@97 == 1] + ALARM["Error: Stock outside of tolerance in Y"] + END_IF END_IF //safety check for inspection variable @@ -109,7 +111,7 @@ END_IF //simple inspection reporting IF [#17 > 0] - #99 = ROUND[@999 * @11] / @11 // Round to 3/4 decimal places + #99 = ROUND[@999 * @91] / @91 // Round to 3/4 decimal places IF[@10 == 21] MENU_ADD["Part Length mm Y: #99",""]; ELSE diff --git a/Macros for Controller/PROBEYWEB b/Macros for Controller/PROBEYWEB index 19e7886..7b144b9 100644 --- a/Macros for Controller/PROBEYWEB +++ b/Macros for Controller/PROBEYWEB @@ -4,8 +4,8 @@ // Probe a web in Y from Front to back // Argument A -> #1 is the work coordinate system to store offsets in -// Argument B -> #2 is the expected length of the web in the Y direction -// Argument C -> #3 is the Z drop height +// Argument Y -> #25 is the expected length of the web in the Y direction +// Argument Z -> #26 is the Z drop height // Argument I -> #9 print results enabled by fusion360 // Argument Q -> #17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on // Argument R -> #18 oversize tolorance @@ -24,16 +24,16 @@ G65 "PROBECONFIG" A#1 #110 = @103 //FEED SPEED PROVIDED BY PROBECONFIG MACRO #111 = @104 //FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO #112 = @105 //SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO -#121 = @101 //TOOL DIAMETER PROVIDED BY PROBECONFIG MACRO -#122 = @106 //WEB PROBE DISTANCE PROVIDED BY PROBECONFIG MACRO -#108 = @108 //PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO -#2 = ABS[#2] -#3 = ABS[#3] -#114 = @114 // processed extended WCS number provided by ProbeConfig macro +#101 = @130 //TOOL DIAMETER PROVIDED BY PROBECONFIG MACRO +#102 = @106 //WEB PROBE DISTANCE PROVIDED BY PROBECONFIG MACRO +#108 = @107 //PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO +#25 = ABS[#25] +#26 = ABS[#26] +#114 = @121 // processed extended WCS number provided by ProbeConfig macro //probe Y starting from a negative offset and probing in the positive direction //MOVE TO -Y SIDE OF THE PART, BEFORE STARTING TO PROBE -G31 G91 P2 Y-[#2/2+#122] F#110 +G31 G91 P2 Y-[#25/2+#102] F#110 //Error Checking IF[R_SKIP[0,1] == 1] @@ -45,7 +45,7 @@ M20 // UNLOCK SPINDLE ORIENT M19 P90 // ORIENT SPINDLE 0 DEGREES TO KEEP THE POBING POINT THE SAME //DROP TO PROBING HEIGHT -G31 G91 P2 Z-#3 F#110 +G31 G91 P2 Z-#26 F#110 //Error Checking IF[R_SKIP[0,1] == 1] @@ -54,7 +54,7 @@ IF[R_SKIP[0,1] == 1] END_IF //probe y from the front -G31 G91 P2 Y[#122+#108] F#111 //FEED PROBING DINSTANCE + BACK OFF UNTIL SKIP FAST +G31 G91 P2 Y[#102+#108] F#111 //FEED PROBING DINSTANCE + BACK OFF UNTIL SKIP FAST //Error Checking IF[R_SKIP[0,1] == 0] @@ -70,10 +70,10 @@ FIX_CUT_OR_OFF G91 G01 Y[-#108] //back off //lift Z after probe -G31 G91 P2 Z#3 F#110 //move above the part +G31 G91 P2 Z#26 F#110 //move above the part //move to the opposite side of the part -G31 G91 P2 Y[#2+#122+#108] F#110 //move to other side of the part,pobe distance away +G31 G91 P2 Y[#25+#102+#108] F#110 //move to other side of the part,pobe distance away //Error Checking IF[R_SKIP[0,1] == 1] @@ -85,7 +85,7 @@ M20 // UNLOCK SPINDLE ORIENT M19 P270 // ORIENT SPINDLE 270 DEGREES TO KEEP THE POBING POINT THE SAME //Move Z down to probe hight -G31 G91 P2 Z-#3 F#110 //move back down to probe height +G31 G91 P2 Z-#26 F#110 //move back down to probe height //Error Checking IF[R_SKIP[0,1] == 1] @@ -94,7 +94,7 @@ IF[R_SKIP[0,1] == 1] END_IF //probe back side of part -G31 G91 P2 Y[-1*[#122+#108]] F#111 //FEED PROBING DINSTANCE + BACK OFF UNTIL SKIP FAST +G31 G91 P2 Y[-1*[#102+#108]] F#111 //FEED PROBING DINSTANCE + BACK OFF UNTIL SKIP FAST //Error Checking IF[R_SKIP[0,1] == 0] @@ -108,31 +108,33 @@ G31 G91 P2 Y[-#108] F#112 //FEED UNTIL SKIP SLOW FIX_CUT_OR_OFF #105=R_SKIP[0,202] //GET SECOND MACHINE Y COORDINATE G91 G01 Y[#108] F#110 //back off -G91 G01 Z#3 //MOVE UP CLEAR OF THE PART +G91 G01 Z#26 //MOVE UP CLEAR OF THE PART //COMPUTE RELATIVE DISTANCE TO CENTER OF THE PART #106 = [[#105-#104]/2] //calculate center -#107 = ABS[#105-#104]-#121 //calculate distance: distance - diameter +#107 = ABS[#105-#104]-#101 //calculate distance: distance - diameter @999 = #107 //save distance to a global variable for use with other macros G91 G01 Y[-#108 - #106] //MOVE TO CENTER OF THE PART #104=R_MACH_COOR[0,2] //GET MACHINE Y COORDINATE -#126=ABS[#107-#2] //expected stock error +#126=ABS[#107-#25] //expected stock error //if the tolorance is null, default it to global variable from the probe config IF[#18==#0] - #18 = @110 + #18 = @108 END_IF //oversized stock alarm if stock error is greater than tolorance IF[#19!=#0 && #126>#18 ] -#136 = ROUND[[#107-#2] * @11] / @11 // Round to 3/4 decimal places -#107 = ROUND[#107 * @11] / @11 // Round to 3/4 decimal places - MENU_ADD["Expected size: #2",""]; +#136 = ROUND[[#107-#25] * @91] / @91 // Round to 3/4 decimal places +#107 = ROUND[#107 * @91] / @91 // Round to 3/4 decimal places + MENU_ADD["Expected size: #25",""]; MENU_ADD["Probed size: #107",""]; MENU_ADD["Tolerance: #18",""]; MENU_ADD["Off-target: #136",""]; MENU["Error","Stock outside of tolerance in Y","",1]; - ALARM["Error: Stock outside of tolerance in Y"] + IF[@97 == 1] + ALARM["Error: Stock outside of tolerance in Y"] + END_IF END_IF //safety check for inspection variable @@ -151,7 +153,7 @@ END_IF //simple inspection reporting IF [#17 > 0] - #99 = ROUND[@999 * @11] / @11 // Round to 3/4 decimal places + #99 = ROUND[@999 * @91] / @91 // Round to 3/4 decimal places IF[@10 == 21] MENU_ADD["Part Length mm Y: #99",""]; ELSE diff --git a/Macros for Controller/PROBEZ b/Macros for Controller/PROBEZ index 10124ac..2be8cc2 100644 --- a/Macros for Controller/PROBEZ +++ b/Macros for Controller/PROBEZ @@ -4,7 +4,7 @@ // Probe in Z from the above stock // Argument A -> #1 is the work coordinate system to store offsets in. The format for extended G54 offsets would be a period followed by the offset G54.5 -// Argument B -> #2 is the desired probing distance and should be negative +// Argument Z -> #26 is the desired probing distance and should be negative // Argument I -> #9 print results enabled by fusion360 // Initial Coding: Justin Gray @@ -18,26 +18,26 @@ G65 "PROBECONFIG" A#1 // important local variables #104 = @104 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO #105 = @105 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO -#107 = @107 // TOOL LENGTH PROVIDED BY PROBECONFIG MACRO -#108 = @108 // PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO -#114 = @114 // processed extended WCS number provided by ProbeConfig macro -#128 = @128 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO +#107 = @133 // TOOL LENGTH PROVIDED BY PROBECONFIG MACRO +#108 = @107 // PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO +#114 = @121 // processed extended WCS number provided by ProbeConfig macro +#128 = @96 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO IF[#128 == 1] M19 // ORIENT SPINDLE END_IF //Check that the probe distance is negative -IF[#2<0] +IF[#26<0] //Probe Z the desired distance and at fast feed -G31 G91 P2 Z[#2] F#104 +G31 G91 P2 Z[#26] F#104 //Check that the probe has triggered IF[R_SKIP[0,1] == 1] G91 G01 Z+[#108] //back off distance provided by ProbeConfig macro FIX_CUT_OR_ON - G31 G91 P2 Z[#2] F#105 //Probe X the desired distance at slow feed + G31 G91 P2 Z[#26] F#105 //Probe Z the desired distance at slow feed FIX_CUT_OR_OFF #142=R_SKIP[0,203] //GET MACHINE Z COORDINATE G91 G01 Z+[#108] //back off distance provided by ProbeConfig macro diff --git a/Macros for Controller/PROTECTEDMOVE b/Macros for Controller/PROTECTEDMOVE index eb0df8e..1daff50 100644 --- a/Macros for Controller/PROTECTEDMOVE +++ b/Macros for Controller/PROTECTEDMOVE @@ -16,7 +16,7 @@ G65 "PROBECONFIG" #100 = @100 // TOOL NUMBER PROVIDED BY PROBECONFIG MACRO #103 = @103 // FEED SPEED PROVIDED BY PROBECONFIG MACRO -#128 = @128 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO +#128 = @96 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO IF[#128 == 1] M19 // ORIENT SPINDLE END_IF diff --git a/Macros for Controller/SAFESPIN b/Macros for Controller/SAFESPIN index c854443..a7ae64e 100644 --- a/Macros for Controller/SAFESPIN +++ b/Macros for Controller/SAFESPIN @@ -11,7 +11,7 @@ // load probe config G65 "PROBECONFIG" -#128 = @128 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO +#128 = @96 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO IF[#128 == 1] M19 // ORIENT SPINDLE END_IF diff --git a/Macros for Controller/TOOLSET b/Macros for Controller/TOOLSET index fe50e66..5dc7127 100644 --- a/Macros for Controller/TOOLSET +++ b/Macros for Controller/TOOLSET @@ -3,8 +3,8 @@ // TOOLSET // measure the tool length offset using the tool setter -// Argument A -> #1 is the tool diameter -// Argument B -> #2 is the tool angle +// Argument A -> #1 is the tool angle +// Argument D -> #4 is the tool diameter // Initial Coding: Justin Gray @@ -15,8 +15,8 @@ G65 "PROBECONFIG" T#100 -#104 = @117 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO -#105 = @116 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#104 = @109 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#105 = @110 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO #110 = R_TOOL_DATA[0,199,203] // TOOLSETTER - T199 - REFERENCE HEIGHT #112 = @112 // TOOLSETTER EXTENDED WORKOFFSET NUMBER @@ -24,10 +24,10 @@ G65 "PROBECONFIG" T#100 G90 G94 G17 G49 G40 G80 G53 G90 G00 Z0 // Move the spindle all the way up before xy movement for safety G54 P#112 // LOCATION OF TOOL SETTER IS X0 Y0 ON G54P100 -G90 G0 X[0+#1/2] Y0 // MOVE TO TOOLSETTER + TOOL RADIUS OFFSET +G90 G0 X[0+#4/2] Y0 // MOVE TO TOOLSETTER + TOOL RADIUS OFFSET M20 // UNLOCK SPINDLE ORIENT -M19 P#2 // ORIENT SPINDLE TO THE GIVEN ANGLE +M19 P#1 // ORIENT SPINDLE TO THE GIVEN ANGLE G91 // RELATIVE MODE @@ -50,9 +50,9 @@ FIX_CUT_OR_OFF // NOTE: LENGTH OF MASTER GAUGE TOOL IS ACOUNTED FOR IN CALIBRATION // MAKE SURE THE CORRECT VALUE IS SET IN PROBECONFIG -#121 = [#120 - #110] // COMPUTE TOOL LENGTH +#101 = [#120 - #110] // COMPUTE TOOL LENGTH -W_TOOL_DATA[0,#100,203,#121] // WRITE TOOL Z LENGTH +W_TOOL_DATA[0,#100,203,#101] // WRITE TOOL Z LENGTH W_TOOL_DATA[0,#100,101,0] // SET TOOL RADIUS AND ALL WEAR OFFSETS TO 0 W_TOOL_DATA[0,#100,102,0] W_TOOL_DATA[0,#100,103,0] diff --git a/Macros for Controller/build_maker_macros.py b/Macros for Controller/build_maker_macros.py new file mode 100644 index 0000000..26800c2 --- /dev/null +++ b/Macros for Controller/build_maker_macros.py @@ -0,0 +1,145 @@ +import os +import sys +import re + + +MACRO_FILES_NAME_MAP = { + 'PROBECONFIG':800, + 'CALIBRATETOOLSET':801, + 'CALIBRATEPROBEZ':802, + 'CALIBRATEPROBERING':803, + 'CALIBRATEPROBEBLOCK':804, + 'UNLOADTOOL':805, + 'LOADTOOL':806, + 'TOOLSET':807, + 'COMPZEROPOINT':808, + 'COPYWCS':809, + 'PROTECTEDMOVE':810, + 'CHECKPOSITIONALTOLERANCE':811, + 'SAFESPIN':813, + 'PROBEX':814, + 'PROBEY':815, + 'PROBEZ':816, + 'PROBEPOCKET':820, + 'PROBERECTANGULARBOSS':821, + 'PROBEXWEB':824, + 'PROBEYWEB':825, + 'PROBEXYANGLE':827, + 'PROBEBORE':830, + 'PROBECIRCULARBOSS':831, + 'PROBEXSLOT':834, + 'PROBEYSLOT':835, + 'PROBEINSIDECORNER':837, + 'PROBEOUTSIDECORNER':839, + 'FINDCOR':840 +} + + +MAKER_MACRO_FOLDER = 'maker_macros' +## Make sure to open a workspace with the top level folder set to "Macros for Controller" + +######################################################## +# Helper functions +######################################################## + +# we'll use these regex's a lot, so we want to precompile them +# instead of building them on the fly each time +def build_regexs(name_map): + """ + make a precompiled regex for each macro file + and store it with the macro name and new number. + """ + regex_map = [] + for name, number in name_map.items(): + pattern = re.compile(r'(G65\s+")' + re.escape(name) + r'(")') + regex_map.append((name, number, pattern)) + + return regex_map + + +def find_all_caps_no_ext(directory="."): + """ + Return a list of filenames in the specified directory that: + - Have no file extension. + - Have a name that is entirely uppercase letters. + """ + matching_files = [] + # Loop through all entries in the directory + for filename in os.listdir(directory): + full_path = os.path.join(directory, filename) + # Ensure that we're checking only files, not directories. + if os.path.isfile(full_path): + # Split the filename into base and extension + base, ext = os.path.splitext(filename) + # Check for no extension and all uppercase letters in the base name. + if ext == "" and base and base == base.upper(): + matching_files.append(filename) + return matching_files + + +######################################################## +# Build the make_macro_m## files +######################################################## + +#empty out the maker_macro folder of any existing file + +# Loop through all entries in the folder +for filename in os.listdir(MAKER_MACRO_FOLDER): + file_path = os.path.join(MAKER_MACRO_FOLDER, filename) + # Check if it is a file (ignoring directories) + if os.path.isfile(file_path): + os.remove(file_path) + +MACRO_TO_MAKER_MACRO_LIST = build_regexs(MACRO_FILES_NAME_MAP) + +for (file_name, file_m_number, _) in MACRO_TO_MAKER_MACRO_LIST: + # Read the file contents + # print ("editing ", file_name) + with open(file_name, 'r') as file: + content = file.read() + + # fond all instances of G65 calls and replace with M calls + for (name, m_number, pattern) in MACRO_TO_MAKER_MACRO_LIST: + # Replace occurrences of the old file name with the new one + content = pattern.sub(f'M{m_number}', content) + + # write the new maker macro file + file_path = os.path.join(MAKER_MACRO_FOLDER, f'MAKER_MACRO_M{file_m_number}') + with open(file_path, "w") as file: + # print("writing ", file_path) + file.write(content) + + +################################################################### +# Testing to make sure we didn't miss any files, or add extra ones +################################################################### + +# Compare computed file list to the dictionary keys by converting both to sets. +computed_files_set = set(find_all_caps_no_ext()) +provided_files_set = set(MACRO_FILES_NAME_MAP.keys()) + +macro_files_found = find_all_caps_no_ext() + +# MACROS in the folder, but missing from the MAP +missing_files = computed_files_set - provided_files_set +# MACROS in the map, but missing from the folder +extra_files = provided_files_set - computed_files_set + +if missing_files: + print('###############################################################') + print("ERROR: The MACRO_FILES_NAME_MAP is missing the following files: ") + for name in missing_files: + print(' ', name) + print('###############################################################') + print() +if extra_files: + print('###############################################################') + print("ERROR: The MACRO_FILES_NAME_MAP has following non existent files: ") + for name in extra_files: + print(' ', name) + print('###############################################################') + print() +# give a return code of 1 so the test fail +if (missing_files or extra_files): + print("Self Tests Failed") + sys.exit(1) \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M800 b/Macros for Controller/maker_macros/MAKER_MACRO_M800 new file mode 100644 index 0000000..fd2b0a9 --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M800 @@ -0,0 +1,109 @@ +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// PROBECONFIG +// Probe Configuration file to setup probe specs and units, called by every macro + +// Argument T -> #20 turns off probe tool number checking : VACANT leaves it on ; non VACANT turns it off +// NOTE: @5109 STORES THE REFERENCE HEIGHT FOR FAST PROBE Z CALIBRATION + +// Initial Coding 1/25/2024: Joshua Smith +// Modified 31/03/2025: Robot Oblivion + +// DO NOT TOUCH!!! Metric or freedom units check +@10 = R_G_GROUP[0,6] + +// important global variables to update below: +@100 = -1 // PROBE TOOL NUMBER, EX: 99 +@92 = 93.896 // CALIBRATED LENGTH OF YOUR MASTER GAUGE TOOL +@93 = 24.998 // Calibrated diameter of the master ring gauge tool +@94 = 50.000 // Calibrated X size of gauge block +@95 = 25.000 // Calibrated Y size of gauge block +@96 = 0 // ORIENT SPINDLE SWITCH 1=ON 0=OFF (probes that spin on/off) +@97 = 0 // turn on alarms for out of tolerance or off to display user message only +#111 = 95 // The highest WCS that can be used. Any above are protected from changes via these macros +@112 = 97 // EXTENDED WORKOFFSET TO STORE TOOLSETTER LOCATION +@113 = 96 // EXTENDED WORKOFFSET TO STORE PROBE Z CALIBRATION LOCATION +@114 = 98 // EXTENDED WORKOFFSET TO STORE THE 4TH COR PROBING START POINT +@115 = 99 // extended workoffset to store the manual tool change location + +// metric settings +IF[@10 == 21] + @103 = 2500 // FEED SPEED mm/m, + @104 = 1250 // FAST PROBE SPEED mm/m, + @105 = 60 // SLOW PROBE SPEED mm/m, + @106 = 10 // PROBE CLEARANCE DISTANCE mm, + @107 = 2 // PROBE BACKOFF DISTANCE mm, + @108 = 1.0 // DEFAULT PART TOLERANCE + + @109 = 750 // FAST Tool Probe SPEED mm/m, + @110 = 40 // SLOW Tool Probe SPEED mm/m, + + @91 = 1000 // rounding multiplier for 3 decimal places +END_IF; + +// Freedom unit settings +IF[@10 == 20] + @103 = 50 // FEED SPEED in/m, + @104 = 50 // FAST PROBE SPEED in/m, + @105 = 2.5 // SLOW PROBE SPEED in/m, + @106 = 0.5 // PROBE CLEARANCE DISTANCE in, + @107 = 0.125 // PROBE BACKOFF DISTANCE, + + @108 = 0.05 // DEFAULT PART TOLERANCE + + @109 = 30 // FAST Tool Probe SPEED in/m, + @110 = 1.5 // SLOW Tool Probe SPEED in/m, + + @91 = 10000 // rounding multiplier for 4 decimal places +END_IF; + +IF [@100==-1] + ALARM["Hard code probe number in PROBECONFIG macro"] +END_IF + +@130 = R_TOOL_DATA[0,@100,3] // TOOL DIAMETER, DO NOT TOUCH!!! +@131 = @130/2 // TOOL RADIUS, DO NOT TOUCH!!! +@133 = [R_TOOL_DATA[0,@100,203]] // TOOL LENGHT OFFSET, DO NOT TOUCH!!! + +#120=R_SYS_INFO[0,2] // CURRENT TOOL NUMBER +IF [@100 != #120 && #20==#0] // THE PROBE IS NOT LOADED + ALARM["Error: Protected move without probe - change to T#100 "] +END_IF + +G90 + +IF [#1 != #0] + IF [ROUND[MOD[#1,1] * 100] > 0] + @121 = ROUND[MOD[#1,1] * 100] // Extract the decimal part and multiply by 100 + IF [@121 < 1 || @121 >= #111] + ALARM["ERROR: Probe WCS G54 P@121 protected via ProbeConfig Macro"] + END_IF + IF [FIX[#1] != 54] + ALARM["ERROR: G54 must be used when calling extended work offsets"] + END_IF + ELSE + @121 = #1 + IF [@121 < 54 || @121 > 59] + ALARM["ERROR: Probe WCS G@121 out of range"] + END_IF + END_IF +END_IF + +IF [#2 != #0] + IF [ROUND[MOD[#2,1] * 100] > 0] + @122 = ROUND[MOD[#2,1] * 100] // Extract the decimal part and multiply by 100 + IF [@122 < 1 || @122 >= #111] + ALARM["ERROR: Override WCS G54 P@122 protected via ProbeConfig Macro"] + END_IF + IF [FIX[#2] != 54] + ALARM["ERROR: G54 must be used when calling extended work offsets"] + END_IF + ELSE + @122 = #2 + IF [@122 < 54 || @122 > 59] + ALARM["ERROR: Override WCS G@122 out of range"] + END_IF + END_IF +END_IF + +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M801 b/Macros for Controller/maker_macros/MAKER_MACRO_M801 new file mode 100644 index 0000000..883a843 --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M801 @@ -0,0 +1,50 @@ +// Copyright 2024 Toolpath Labs Inc., Justin Gray, and Josh Smith + +// CALIBRATETOOLSET +// use a master gauge tool to find the trigger height of a tool setter. + +// Initial Coding: Justin Gray +// Modified 31/03/2025: Robot Oblivion + +#100=R_SYS_INFO[0,2] // SAVE CURRENT TOOL NUMBER TO #100 +@10 = R_G_GROUP[0,6] // pull in metric or freedom units + +// load probe config +M800 T#100 + +#115 = @109 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#116 = @110 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#109 = @92 // MASTER GAUGE LENGTH PROVIDED BY PROBECONFIG MACRO +#112 = @112 // EXTENDED WCS TO STORE TOOLSETTER LOCATION PROVIDED BY PROBECONFIG MACRO + +G94 G17 G49 G40 G80 +G53 G90 G00 Z0 // Move the spindle all the way up before xy movement for safety +G54 P#112 // Extended LOCATION OF TOOL SETTER +G90 X0 Y0 // MOVE TO TOOLSETTER + +M19 // ORIENT SPINDLE + +G91 // RELATIVE MODE + +IF[@10 == 21] + G21 // Metric + G31 Z-400.0 F#115 // FEED UNTIL INPUT SIGNAL AKA SKIP + G91 G0 Z5.0 // MOVE UP + FIX_CUT_OR_ON + G31 Z-5.5 F#116 // FEED UNTIL SKIP SLOWER +ELSEIF[@10 == 20] + G20 // fREEDOM UNITS (INCH) + G31 Z-20 F#115 // FEED UNTIL INPUT SIGNAL AKA SKIP + G91 G0 Z0.2 // MOVE UP + FIX_CUT_OR_ON + G31 Z-.21 F#116 // FEED UNTIL SKIP SLOWER +END_IF +FIX_CUT_OR_OFF + +#141=[R_SKIP[0,103]-#109] // MACHINE Z COORDINATE WITH - MASTER TOOL LENGTH + +W_TOOL_DATA[0,199,203,#141] // STORE THE TOOL LENGTH OFFSET + +G53 G90 G00 Z0 // Move the spindle all the way up before xy movement for safety +M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M802 b/Macros for Controller/maker_macros/MAKER_MACRO_M802 new file mode 100644 index 0000000..b0f29b0 --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M802 @@ -0,0 +1,88 @@ +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// CALIBRATEZ +// THIS MACRO ASSUMES THAT YOU HAVE PUT YOUR GAUGE TOOL IN THE SPINDLE +// AND positioned slightly above your REFERENCE ARTIFACT. +// THE MACRO WILL SAVE THE XY LOCATION FOR FUTURE USE AND STORE THE REFERENCE HEIGHT OFFSET + +// Argument A -> #1 turns on/off full calibration: default is quick calibration + +// Initial Coding: Justin Gray +// Modified 31/03/2025: Robot Oblivion + +// load probe config +M800 + +// important local variables +#100 = @100 // TOOL NUMBER PROVIDED BY PROBECONFIG MACRO +#104 = @104 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#105 = @105 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#106 = @106 // PROBE CLEARANCE DISTANCE +#108 = @107 // PROBE BACKOFF DISTANCE +#109 = @92 // MASTER TOOL GAUGE LENGTH +#111 = @113 // PROBE CALIBRATION EXTENDED WORKOFFSET NUMBER + // NOTE: @5109 will be used to save reference block height + +M19 // ORIENT SPINDLE + +IF [#1!=#0] + MSG_OK["Calibrate probe", "Switch to MPG mode and carefully zero the master tool on the calibration artifact. Only press Cycle Start when you're ready to proceed.", ""] + M00 + WAIT[0,0] + MSG_OK["Update @5109", "Once accurately gauged in, press OK to store the current machine position in G@113. Only press OK when the tool is correctly positioned as the Z axis will retract immediately after.", ""] + WAIT[0,0] + + @5109 = R_MACH_COOR[0,3] // GET MACHINE Z COORDINATE WHICH SHOULD BE THE TOP OF A 123 BLOCK + #140 = @5109 + + // STORE THE CURRENT POSITION TO PROBE CALIBRATION EXTENDED WORKOFFSET NUMBER FOR FUTURE FAST CALIBRATION + W_G54EXP_COOR[0,#111,1,R_MACH_COOR[0,1]] + W_G54EXP_COOR[0,#111,2,R_MACH_COOR[0,2]] +ELSE // FAST CALIBRATION + MSG_OK["Calibrate probe", "Install calibration artifact in reference location", ""] +END_IF + +#140 = @5109 // PREVIOUSLY STORED REFERENCE HEIGHT + +T#100 M6 // COMMAND A TOOL CHANGE + +G53 G90 G00 Z0 // BRING THE MACHINE UP TO TOOL CHANGE HEIGHT + +#101 = R_MACH_COOR[0,3] // GET MACHINE Z COORDINATE AFTER TOOL CHANGE + +IF [#1!=#0] + // TELL THE PERSON TO PUT THE PROBE INTO THE SPINDLE + MSG_OK["Install probe", "Switch to MPG mode and install the probe (T@100). Then, switch back before pressing Cycle Start.", ""] +END_IF + +G54 P#111 // LOCATION OF PROBE CALIBARTION IS X0 Y0 ON G54 P#111 + +G90 G0 X0. Y0. // MOVE TO TOOLSETTER + +#123 = #140 - #109 // DELTA DISTANCE WE HAVE MOVED PLUS SOME INCASE PROBE IS SHORTER THAN GAUGE TOOL +// Probe Z ALL THE WAY BACK TO 123 BLOCK +G31 G91 P2 Z#123 F#104 + +// Check that the probe has triggered +IF[R_SKIP[0,1] == 1] + G91 G01 Z#108 // PROBE BACKOFF DISTANCE + FIX_CUT_OR_ON + G31 G91 P2 Z-[1.5*#108] F#105 // PROBE Z AT SLOW SPEED + FIX_CUT_OR_OFF + #125 = R_SKIP[0,203] // GET MACHINE Z COORDINATE + @996 = #125 // Store for Setup Helper + G91 G01 Z#108 // BACK OFF + #126 = [#125-#140+#109] // PROBE LENGTH CALCULATION, ACCOUNTING FOR GAUGE TOOL LENGTH + W_TOOL_DATA[0,#100,203,#126] // STORE PROBE LENGTH +ELSE + ALARM["Failed to probe part within specified distance"] +END_IF + +G53 G90 G00 Z0 // retract to top of Z + +M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +M99 + + G91 G01 Z+[#108] //back off distance provided by ProbeConfig macro + #143 = [#142-#107] //current position - probe length + @996 = #143 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M803 b/Macros for Controller/maker_macros/MAKER_MACRO_M803 new file mode 100644 index 0000000..fcc2b9c --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M803 @@ -0,0 +1,54 @@ +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// CALIBRATEPROBERING +// Calibrate the Diameter of the probe using a ring guage +// Your probe must be concentric and you must use a ring guage!!!!!!!!!! +// **Ring gauge ID set in ProbeConfig file + +// Argument D -> #4 is optional and the expected inside diameter of the ring guage. Will over ride value in ProbeConfig if called + +// Initial coding 1/14/2024: Joshua Smith +// Modified 31/03/2025: Robot Oblivion + +// load probe config +M800 + +M19 // ORIENT SPINDLE + +// important local variables +#100 = @100 // TOOL NUMBER PROVIDED BY PROBECONFIG MACRO +#129 = @93 // Calibrated ring gauge diameter provided by PROBECONFIG MACRO + +// Over ride probeConfig gauge ID A argument used +IF [#4 != #0] + #129 = #4 +END_IF + +// Make sure diameter is zero when calibrating +W_TOOL_DATA[0,#100,3,0] // store tool diameter + +// G54 is used below to pass ProbeConfig WCS checks, but I1 calls ensure that G54 remains unchanged. +// calling our slot macros the first time centers probe +M834 A54 X#129 Q0 I1 +M835 A54 Y#129 Q0 I1 + +// calling our slot macros a second time gives an accurate inspection +M834 A#111 X#129 Q0 I1 +M835 A#111 Y#129 Q0 I1 + +// average Diameter calculation +// @999 and @998 are set in the slot macros +// this could be improved by keeping track of both X and Y diameters and controling probe orientation +#131 = @998 // measured ring guage diameter x +#132 = @999 // measured ring guage diameter y +#133 = #129 - #131 // error in x +#134 = #129 - #132 // error in y +#135 = ABS[#133 + #134]/2 // average error +W_TOOL_DATA[0,#100,3,#135] // store tool diameter + +MENU_ADD["Ruby Diameter Set To: #135",""]; +MENU["Calibration report","Results","",1]; + +M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +G90 // return to absolute mode +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M804 b/Macros for Controller/maker_macros/MAKER_MACRO_M804 new file mode 100644 index 0000000..ce2c679 --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M804 @@ -0,0 +1,55 @@ +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +//CALIBRATEPROBEBLOCK +//CALIBRATE PROBE TIP DIAMETER using a rectanglar object + +// Argument X -> #24* is optional and the expected X length of the artifact. Will over ride value in ProbeConfig if called +// Argument Y -> #25* is optional and the expected Y length of the artifact. Will over ride value in ProbeConfig if called +// Argument Z -> #26 is the Z drop height +// **Gauge block size set in ProbeConfig file + +// Initial Coding: Justin Gray +// Modified 08/04/2025: Robot Oblivion + +G90 G94 G17 G49 G40 G80 + +// load probe config +M800 + +M19 // ORIENT SPINDLE + +// important local variables +#100 = @100 // TOOL NUMBER PROVIDED BY PROBECONFIG MACRO +#124 = @94 // Calibrated X size of gauge block +#125 = @95 // Calibrated Y size of gauge block + +// Over ride probeConfig gauge X size if X argument used +IF [#24 != #0] + #124 = #24 +END_IF +// Over ride probeConfig gauge Y size if Y argument used +IF [#25 != #0] + #125 = #25 +END_IF + +// Make sure diameter is zero when calibrating +W_TOOL_DATA[0,#100,3,0] // store tool diameter + +// calling web probe macros macros to measure the rectangle +M824 A0 X#124 Z#26 Q0 +M825 A0 Y#125 Z#26 Q0 + +#131 = @998 // stored value of the measured X distance +#132 = @999 // stored valued of the measured Y distance + +#133 = #24-#131 // error in x +#134 = #25-#132 // error in y +#135 = ABS[#133 + #134]/2 // average error +W_TOOL_DATA[0,#100,3,#135] // store tool diameter + +MENU_ADD["Ruby Diameter Set To: #135",""]; +MENU["Calibration report", "Results", "", 1]; + +M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +G90 +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M805 b/Macros for Controller/maker_macros/MAKER_MACRO_M805 new file mode 100644 index 0000000..c33b7b0 --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M805 @@ -0,0 +1,35 @@ +// Copyright 2024 Toolpath Labs Inc., Justin Gray + +// REMOVE A TOOL FROM THE CAROUSEL + +// #20 IS THE TOOL NUMBER TO REMOVE + +// MAKE SURE #20 IS IN THE TOOL TABLE +#120 = 0 // POCKET ADDRESS +FOR #100=7000 to 7011 + IF [R_REG[#100] == #20] // IN THE TOOL TABLE + #120 = #100 + EXIT_FOR + END_IF +END_FOR + +IF[#120 == 0] // TOOL WAS NOT FOUND + ALARM["T#20 NOT IN CAROUSEL"] +END_IF + +// SET THE LENGTH OFFSET TO 999 SO WE CAN'T USE IT WITHOUT TOOLSETTING +W_TOOL_DATA[0, #20, 203, 999] +// CLEAR ANY WEAR OFFSETS FOR RADIUS OR LENGTH +W_TOOL_DATA[0, #20, 2, 0] // RADIAL WEAR +W_TOOL_DATA[0, #20, 103, 0] // LENGTH WEAR + +// TOOL CHANGE TO THAT TOOL NUMBER +T#20 M6 + +// SET THE TOOL TABLE FOR THAT TOOL TO 199 TO LABEL IT AS EMPTY +W_REG[#120, 199] + +// ASK THE USER TO REMOVE IT +MSG_OK["REMOVE TOOL", "SWITCH TO MPG MODE AND REMOVE T#20 THEN HIT CYCLE STOP",""] + +M99 diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M806 b/Macros for Controller/maker_macros/MAKER_MACRO_M806 new file mode 100644 index 0000000..ff14e66 --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M806 @@ -0,0 +1,99 @@ +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// LOADTOOL +// LOAD A NEW TOOL INTO THE CAROUSEL + +// Argument M* -> #13 Flag to reset tool offsets then call TOOLSET (not required and defaults on) +// Argument O* -> #15 tool number in carousel to swap out (not required) +// Argument T -> #20 IS THE TOOL NUMBER TO LOAD +// THE TOOL TABLE IS VARIABLES 7000-7011 + +// Initial Coding: Justin Gray +// Modified 31/03/2025: Robot Oblivion + +#120 = 0 // STORES THE OLD TOOL NUMBER + +IF[#20 == R_REG[7813]] + MSG_OK["Tool In spindle", "T#20 already loaded in the spindle",""] + M99 +END_IF + +// IF THE TOOL NUMBER IS ALREADY IN THE CAROUSEL WE SWAP THEM +FOR #100=7000 TO 7011 + IF[R_REG[#100]==#20] + #120 = #20 + #119 = 0 // Swap tool message flag + EXIT_FOR + END_IF +END_FOR + +// IF NOT ALREADY THERE, THEN FIND AN OPEN POCKET +IF[#120 == 0 && #15 == #0] + // FIND THE FIRST EMPTY POCKET + FOR #100=7000 TO 7011 + IF[R_REG[#100]==199] + #120 = #100 + // WRITE THE NEW TOOL NUMBER INTO THE TOOL TABLE + W_REG[#100, #20] + #101 = #100-6999 // store empty tool pocket number + #119 = 1 // Swap tool message flag + EXIT_FOR + END_IF + END_FOR +END_IF + +// IF #120 IS STILL 0 THEN THERE WAS NO EMPTY POCKET +// AND WE WILL SWAP WITH A DIFFERENT TOOL NUMBER +IF[#120 == 0] + #101 = #15 // pull in O argument + IF[#101 == #0] + #101 = INPUT["Choose a tool to swap","Choose a tool in the carousel to swap out?","",1,196,13]; + END_IF + + // CHECK THAT THE TOOL THE USER PICKED IS ACTUALLY IN THE CAROUSEL + FOR #100=7000 TO 7011 + IF[R_REG[#100]==#101] + IF[#101 == R_REG[7813]] // check if tool to swap is tool in spindle + W_REG[7813, #20] // push new tool to tool in spindle to skip tool drop in below M6 + END_IF + // PUSH THE NEW TOOL NUMBER INTO THE TOOL TABLE + #120 = #101 + W_REG[#100, #20] + #119 = 2 // Swap tool message flag + EXIT_FOR + END_IF + END_FOR + + IF[#120 == 0] + ALARM["Tool T#101 not found in carousel. Can't swap out for T#20."] + END_IF +END_IF + +// NOW WE ARE SURE THAT THE NEW TOOL HAS BEEN PUSHED INTO THE TOOL TABLE +// COMMAND A TOOL CHANGE +T#20 M6 + +// TELL THE PERSON TO PUT THE TOOL INTO THE SPINDLE +SELECT[#119] + CASE 0: + ; no message is required + CASE 1: + MSG_OK["Install Tool", "Switch to MPG mode, install tool #20 in pocket #101, and press OK only after the manual tool change is complete.",""] + WAIT[0,0] + CASE 2 : + MSG_OK["Swap Tools", "Switch to MPG mode, swap tool #101 with tool #20, and press OK only after the manual tool change is complete.",""] + WAIT[0,0] +END_SELECT + +IF[#13 == 1] + // SET THE LENGTH OFFSET TO 999 SO WE CAN'T USE IT WITHOUT TOOLSETTING + W_TOOL_DATA[0, #20, 203, 999] + // CLEAR ANY WEAR OFFSETS FOR RADIUS OR LENGTH + W_TOOL_DATA[0, #20, 2, 0] // RADIAL WEAR + W_TOOL_DATA[0, #20, 103, 0] // LENGTH WEAR + + // TOOLSET THE TOOL + M807 A0.0 +END_IF + +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M807 b/Macros for Controller/maker_macros/MAKER_MACRO_M807 new file mode 100644 index 0000000..9a898b3 --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M807 @@ -0,0 +1,66 @@ +// Copyright 2024 Toolpath Labs Inc., Justin Gray + +// TOOLSET +// measure the tool length offset using the tool setter + +// Argument A -> #1 is the tool angle +// Argument D -> #4 is the tool diameter + +// Initial Coding: Justin Gray + +#100=R_SYS_INFO[0,2] // SAVE CURRENT TOOL NUMBER TO #100 +@10 = R_G_GROUP[0,6] // pull in metric or freedom units + +// load probe config +M800 T#100 + + +#104 = @109 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#105 = @110 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#110 = R_TOOL_DATA[0,199,203] // TOOLSETTER - T199 - REFERENCE HEIGHT +#112 = @112 // TOOLSETTER EXTENDED WORKOFFSET NUMBER + + +G90 G94 G17 G49 G40 G80 +G53 G90 G00 Z0 // Move the spindle all the way up before xy movement for safety +G54 P#112 // LOCATION OF TOOL SETTER IS X0 Y0 ON G54P100 +G90 G0 X[0+#4/2] Y0 // MOVE TO TOOLSETTER + TOOL RADIUS OFFSET + +M20 // UNLOCK SPINDLE ORIENT +M19 P#1 // ORIENT SPINDLE TO THE GIVEN ANGLE + +G91 // RELATIVE MODE + +IF[@10 == 21] + G21 // Metric + G31 Z-400.0 F#104 // FEED UNTIL INPUT SIGNAL AKA SKIP + G91 G0 Z5.0 // MOVE UP + FIX_CUT_OR_ON + G31 Z-5.5 F#105 // FEED UNTIL SKIP SLOWER +ELSEIF[@10 == 20] + G20 // fREEDOM UNITS (INCH) + G31 Z-20 F#104 // FEED UNTIL INPUT SIGNAL AKA SKIP + G91 G0 Z0.2 // MOVE UP + FIX_CUT_OR_ON + G31 Z-.21 F#105 // FEED UNTIL SKIP SLOWER +END_IF +FIX_CUT_OR_OFF + +#120= R_SKIP[0,103] // GET MACHINE Z COORDINATE + +// NOTE: LENGTH OF MASTER GAUGE TOOL IS ACOUNTED FOR IN CALIBRATION +// MAKE SURE THE CORRECT VALUE IS SET IN PROBECONFIG +#101 = [#120 - #110] // COMPUTE TOOL LENGTH + +W_TOOL_DATA[0,#100,203,#101] // WRITE TOOL Z LENGTH +W_TOOL_DATA[0,#100,101,0] // SET TOOL RADIUS AND ALL WEAR OFFSETS TO 0 +W_TOOL_DATA[0,#100,102,0] +W_TOOL_DATA[0,#100,103,0] +W_TOOL_DATA[0,#100,2,0] +W_TOOL_DATA[0,#100,3,0] +W_TOOL_DATA[0,#100,202,0] +W_TOOL_DATA[0,#100,201,0] + +G53 G90 G00 Z0 // Move the spindle all the way up before xy movement for safety +M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M808 b/Macros for Controller/maker_macros/MAKER_MACRO_M808 new file mode 100644 index 0000000..3f3b0b1 --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M808 @@ -0,0 +1,84 @@ +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// COMPZEROPOINT +// set probing wcs to probed part deltas plus zero point origin + +// Argument A -> #1 is the work coordinate system to store offsets in. The format for extended G54 offsets would be a period followed by the offset// G54.5 +// Argument B -> #2 is the override coordinate system. The format for extended G54 offsets would be a period followed by the offset// G54.5 +// Argument X -> #24 expected X +// Argument Y -> #25 expected Y +// Argument Z -> #26 expected Z + +// Modified 2/10/2024: Joshua Smith +// Simplified WCS extended number math, added probe error checking, added probe distance argument +// Modified 31/03/2025: Robot Oblivion + +// load probe config +M800 A#1 B#2 +#114 = @121 // processed extended WCS number provided by ProbeConfig macro +#115 = @122 // processed extended WCS number provided by ProbeConfig macro +#128 = @96 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO + +IF[#128 == 1] + M19 // ORIENT SPINDLE +END_IF + + // get WCS ZERO + IF [#1 == #0 ] + ALARM["ERROR: PROBE WCS NOT PROVIDED"] + ELSEIF [#114 < 1] + #116 = R_G53G59_COOR[0,#1,1] // x work zero + #117 = R_G53G59_COOR[0,#1,2] // y work zero + #118 = R_G53G59_COOR[0,#1,3] // z work zero + ELSE + #116 = R_G54EXP_COOR[0,#114,1] // x work zero + #117 = R_G54EXP_COOR[0,#114,2] // y work zero + #118 = R_G54EXP_COOR[0,#114,3] // z work zero + END_IF + + + // Get override ZERO + IF [#2 == #0] + ALARM["ERROR: OVERRIDE WCS NOT PROVIDED"] + ELSEIF [#115 < 1] + #119 = R_G53G59_COOR[0,#2,1] // x override zero + #120 = R_G53G59_COOR[0,#2,2] // y override zero + #101 = R_G53G59_COOR[0,#2,3] // z override zero + ELSE + #119 = R_G54EXP_COOR[0,#115,1] // x work zero + #120 = R_G54EXP_COOR[0,#115,2] // y work zero + #101 = R_G54EXP_COOR[0,#115,3] // z work zero + END_IF + + // error = probed point - expected point + #102 = #116 - [#24 + #119] // x error calculation between selected wcs and expected probe point + #123 = #117 - [#25 + #120] // y error calculation between selected wcs and expected probe point + #124 = #118 - [#26 + #101] // z error calculation between selected wcs and expected probe point + + #125 = #119 + #102 // translate x wcs by the error + #126 = #120 + #123 // translate y wcs by the error + #127 = #101 + #124 // translate z wcs by the error + +// Compensate WCS For ZeroPoint +IF [#1 == #0 || #1 == #2] + // DO NOT SET ANYTHING INTO WCS +ELSEIF [#114 < 1] + W_G53G59_COOR[0,#1,1,#125] + W_G53G59_COOR[0,#1,2,#126] + // Z should always be the zero point Z + // If not, we couldn't have driven our probe to the probing position + W_G53G59_COOR[0,#1,3,#101] +ELSE + W_G54EXP_COOR[0,#114,1,#125] + W_G54EXP_COOR[0,#114,2,#126] + // Z should always be the zero point Z + // If not, we couldn't have driven our probe to the probing position + W_G54EXP_COOR[0,#114,3,#101] +END_IF + +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +END_IF + +G90 +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M809 b/Macros for Controller/maker_macros/MAKER_MACRO_M809 new file mode 100644 index 0000000..8e46f4d --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M809 @@ -0,0 +1,43 @@ +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// COMPZEROPOINT +// copy wcs B into A + +// Argument A -> #1 is the work coordinate system to store offsets in. The format for extended G54 offsets would be a period followed by the offset// G54.5 +// Argument B -> #2 is the override coordinate system. The format for extended G54 offsets would be a period followed by the offset// G54.5 + +// Modified 2/10/2024: Joshua Smith +// Modified 31/03/2025: Robot Oblivion + +M800 A#1 B#2 +#114 = @121 // processed extended WCS number provided by ProbeConfig macro +#115 = @122 // processed extended WCS number provided by ProbeConfig macro + + // Get Argument B WCS + IF [#2 == #0] + ALARM["ERROR: OVERRIDE WCS NOT PROVIDED"] + ELSEIF [#115 < 1] + #119 = R_G53G59_COOR[0,#2,1] // x override zero + #120 = R_G53G59_COOR[0,#2,2] // y override zero + #101 = R_G53G59_COOR[0,#2,3] // z override zero + ELSE + #119 = R_G54EXP_COOR[0,#115,1] // x work zero + #120 = R_G54EXP_COOR[0,#115,2] // y work zero + #101 = R_G54EXP_COOR[0,#115,3] // z work zero + END_IF + +// Copy one wcs into another +IF [#1 == #0 || #1 == #2] + // DO NOT SET ANYTHING INTO WCS +ELSEIF [#114 < 1] + W_G53G59_COOR[0,#1,1,#119] + W_G53G59_COOR[0,#1,2,#120] + W_G53G59_COOR[0,#1,3,#101] +ELSE + W_G54EXP_COOR[0,#114,1,#119] + W_G54EXP_COOR[0,#114,2,#120] + W_G54EXP_COOR[0,#114,3,#101] +END_IF + +G90 +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M810 b/Macros for Controller/maker_macros/MAKER_MACRO_M810 new file mode 100644 index 0000000..3dc3edb --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M810 @@ -0,0 +1,54 @@ +// Copyright 2024 Toolpath Labs Inc., Justin Gray + +// PROTECTEDMOVE +// Move to target position using G31 to stop should an unexpected collision occurs + +// Argument X -> #24 ABSOLUTE X POSITION TO MOVE TO +// Argument Y -> #25 ABSOLUTE X POSITION TO MOVE TO +// Argument Z -> #26 ABSOLUTE X POSITION TO MOVE TO + +// Initial Coding: Justin Gray +// Modified 31/03/2025: Robot Oblivion + +// load probe config +M800 + +#100 = @100 // TOOL NUMBER PROVIDED BY PROBECONFIG MACRO +#103 = @103 // FEED SPEED PROVIDED BY PROBECONFIG MACRO + +#128 = @96 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO +IF[#128 == 1] + M19 // ORIENT SPINDLE +END_IF + +#120=R_SYS_INFO[0,2] // CURRENT TOOL NUMBER + +// NOTE: #0 IS ALWAYS VACANT, SO YOU CAN CHECK AGAINST IT TO SEE IF AN ARGUMENT WAS PASSED + +G90 +IF[#24==#0 && #25==#0 && #26!=#0] // Z ONLY + G31 P2 Z[#26] F#103 +ELSEIF[#24!=#0 && #25==#0 && #26==#0] // X ONLY + G31 P2 X[#24] F#103 +ELSEIF[#24==#0 && #25!=#0 && #26==#0] // Y ONLY + G31 P2 Y[#25] F#103 +ELSEIF[#24!=#0 && #25==#0 && #26!=#0] // X + Z + G31 P2 X[#24] Z[#26] F#103 +ELSEIF[#24==#0 && #25!=#0 && #26!=#0] // Y + Z + G31 P2 Y[#25] Z[#26] F#103 +ELSEIF[#24!=#0 && #25!=#0 && #26==#0] // X + Y + G31 P2 X[#24] Y[#25] F#103 +ELSEIF[#24!=#0 && #25!=#0 && #26!=#0] // X+ Y + Z + G31 P2 X[#24] Y[#25] Z[#26] F#103 +END_IF + +// Error Checking +IF[R_SKIP[0,1] == 1] + ALARM["ERROR: Protected move triggered probe - unexpected obstacle"] +END_IF + +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +END_IF + +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M811 b/Macros for Controller/maker_macros/MAKER_MACRO_M811 new file mode 100644 index 0000000..c3c608d --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M811 @@ -0,0 +1,106 @@ +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// CHECKPOSITIONALTOLERANCE +// Check the XYZ positional tolerance based on the probed points and expected points + +// Argument A -> #1 is the work coordinate system to store offsets in. The format for extended G54 offsets would be a period followed by the offset// G54.5 +// Argument B -> #2 is the override coordinate system. The format for extended G54 offsets would be a period followed by the offset// G54.5 +// Argument T -> #20 positional tolerance +// Argument U -> #21 positional tolerance enable +// Argument V -> #22 Axis to check 1 =X, 2 = Y, 3 = Z, 4 = XY, 5 = XYZ +// Argument X -> #24 expected X +// Argument Y -> #25 expected Y +// Argument Z -> #26 expected Z + +// Modified 02/10/2024: Joshua Smith +// Modified 31/03/2025: Robot Oblivion + +// load probe config +M800 A#1 B#2 + +#114 = @121 // processed extended WCS number provided by ProbeConfig macro +#115 = @122 // processed extended WCS number provided by ProbeConfig macro +#128 = @96 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO + +IF[#128 == 1] + M19 // ORIENT SPINDLE +END_IF + +// get WCS ZERO +IF [#1 == #0] + ALARM["ERROR: Probe WCS not provided"] +ELSEIF [#114 < 1] + #116 = R_G53G59_COOR[0,#1,1] // x work zero + #117 = R_G53G59_COOR[0,#1,2] // y work zero + #118 = R_G53G59_COOR[0,#1,3] // z work zero +ELSE + #116 = R_G54EXP_COOR[0,#114,1] // x work zero + #117 = R_G54EXP_COOR[0,#114,2] // y work zero + #118 = R_G54EXP_COOR[0,#114,3] // z work zero +END_IF + +// Get override ZERO +IF [#2 == #0] + ALARM["ERROR: Override WCS not provided"] +ELSEIF [#115 < 1] + #119 = R_G53G59_COOR[0,#2,1] // x override zero + #120 = R_G53G59_COOR[0,#2,2] // y override zero + #101 = R_G53G59_COOR[0,#2,3] // z override zero +ELSE + #119 = R_G54EXP_COOR[0,#115,1] // x work zero + #120 = R_G54EXP_COOR[0,#115,2] // y work zero + #101 = R_G54EXP_COOR[0,#115,3] // z work zero +END_IF + +// error = probed point - expected point +#102 = #116 - [#24 + #119] // x error calculation between selected wcs and expected probe point +#123 = #117 - [#25 + #120] // y error calculation between selected wcs and expected probe point +#124 = #118 - [#26 + #101] // z error calculation between selected wcs and expected probe point + +// if the tolorance is null, default it to global variable from the probe config +IF[#20==#0] + #20 = @108 +END_IF + +#130 = ABS[#102] // absolute x error +#131 = ABS[#123] // absolute y error +#132 = ABS[#124] // absolute z error + +// out of postion alarm if error is greater than tolorance +IF[#21!=#0 && #1==#2 ] + ALARM["WCS override must be enabled in the Fusion probing routine and the override WCS must be different than the work WCS."] +ELSEIF[#21!=#0 && #130 > #20 && [#22 == 1 || #22 == 4 || #22 == 5]] + #130 = ROUND[#130 * @91] / @91 // Round to 3/4 decimal places + #116 = ROUND[#116 * @91] / @91 // Round to 3/4 decimal places + MENU_ADD["Override point: #119",""]; + MENU_ADD["Probed point: #116",""]; + MENU_ADD["Limit / expected: #20 / #24",""]; + MENU_ADD["Out of position X: #130",""]; + MENU["Error","Stock out of position X","",4]; + ALARM["ERROR: Stock outside of positional tolerance in X"] +ELSEIF [#21!=#0 && #131 > #20 && [#22 == 2 || #22 == 4 || #22 == 5]] + #131 = ROUND[#131 * @91] / @91 // Round to 3/4 decimal places + #117 = ROUND[#117 * @91] / @91 // Round to 3/4 decimal places + MENU_ADD["Override point: #120",""]; + MENU_ADD["Probed point: #117",""]; + MENU_ADD["Limit / expected: #20 / #25",""]; + MENU_ADD["Out of position Y: #131",""]; + MENU["Error","Stock out of position Y","",1]; + ALARM["ERROR: Stock outside of positional tolerance in Y"] +ELSEIF [#21!=#0 && #132 > #20 && [#22 == 3 || #22 == 5]] + #132 = ROUND[#132 * @91] / @91 // Round to 3/4 decimal places + #118 = ROUND[#118 * @91] / @91 // Round to 3/4 decimal places + MENU_ADD["Override point: #101",""]; + MENU_ADD["Probed point: #118",""]; + MENU_ADD["Limit / expected: #20 / #26",""]; + MENU_ADD["Out of position Z: #132",""]; + MENU["Error","Stock out of position Z","",1]; + ALARM["ERROR: Stock outside of positional tolerance in Z"] +END_IF + +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +END_IF + +G90 +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M813 b/Macros for Controller/maker_macros/MAKER_MACRO_M813 new file mode 100644 index 0000000..d039409 --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M813 @@ -0,0 +1,36 @@ +// Copyright 2024 Toolpath Labs Inc., Justin Gray + +// SAFESPIN +// TURN ON SPINDLE AFTER SAFTEY CHECK + +// Argument A -> #1 is the commanded RPM + +// Initial Coding: Justin Gray +// Modified 31/03/2025: Robot Oblivion + +// load probe config +M800 + +#128 = @96 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO +IF[#128 == 1] + M19 // ORIENT SPINDLE +END_IF + +#110 = @100 // PROBE TOOL NUMBER + +#100=R_SYS_INFO[0,2] // CURRENT TOOL NUMBER + +IF [#100 == #110] // THE PROBE IS LOADED + #101 = INPUT["CHANGE TO ANOTHER TOOL","Tool number?","",1,97,4]; + T#101 M6; +ELSE + S#1 M3 +END_IF + +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +END_IF + +N1 + +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M814 b/Macros for Controller/maker_macros/MAKER_MACRO_M814 new file mode 100644 index 0000000..04290a6 --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M814 @@ -0,0 +1,71 @@ +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// PROBEX +// Probe in X from the left or right side + +// Argument A -> #1 is the work coordinate system to store offsets in. The format for extended G54 offsets would be a period followed by the offset G54.5 +// Argument X -> #24 is the desired probing distance. Enter a positive value to probe on the left side and a negative value to probe on the right side +// Argument I -> #9 print results enabled by fusion360 + +// Initial Coding: Justin Gray +// Modified 1/14/2024: Joshua Smith +// Simplified WCS extended number math, added probe error checking, added probe distance argument +// Modified 31/03/2025: Robot Oblivion + +// load probe config +M800 A#1 + +// important local variables +#111 = @104 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#112 = @105 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#105 = @131 // TOOL RADIUS PROVIDED BY PROBECONFIG MACRO +#108 = @107*[#24/ABS[#24]] // PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO * the sign +1 or -1 of probe distance +#114 = @121 // processed extended WCS number provided by ProbeConfig macro +#128 = @96 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO + +M20 // UNLOCK SPINDLE ORIENT +IF[#24 < 0] + M19 P180 // ORIENT SPINDLE 180 DEGREES +ELSE + M19 P0 // ORIENT SPINDLE 0 DEGREES +END_IF + +//Probe X the desired distance and at fast feed +G31 G91 P2 X[#24] F#111 //FEED UNTIL SKIP FAST + +//Check that the probe has triggered +IF[R_SKIP[0,1] == 1] + G91 G01 X-[#108] //back off distance provided by ProbeConfig macro + FIX_CUT_OR_ON + G31 G91 P2 X[#24] F#112 //Probe X the desired distance at slow feed + FIX_CUT_OR_OFF + #104=R_SKIP[0,201] //GET MACHINE X COORDINATE + G91 G01 X-[#108] //back off distance provided by ProbeConfig macro + #106 = [#104+[[#24/abs[#24]]*#105]] //current position +/- probe radius + @996 = #106 + + //safety check for inspection variable + IF[#9 == #0] + #9 = 0 + END_IF + + //STORE X OFFSET FOR WCS ZERO + IF [#1 == #0 || #9 > 0] + //DO NOT WRITE ANYTHING TO WCS + ELSEIF [#114 < 1] + W_G53G59_COOR[0,#1,1,#106] + ELSE + W_G54EXP_COOR[0,#114,1,#106] + END_IF + +ELSE + ALARM["ERROR: FAILED TO PROBE PART WITHIN SPECIFIED DISTANCE"] +END_IF + +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +END_IF + +G90 +G00 // return to rapid speed +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M815 b/Macros for Controller/maker_macros/MAKER_MACRO_M815 new file mode 100644 index 0000000..abaed1c --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M815 @@ -0,0 +1,71 @@ +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// PROBEY +// Probe in Y from the front or back + +// Argument A -> #1 is the work coordinate system to store offsets in. The format for extended G54 offsets would be a period followed by the offset G54.5 +// Argument Y -> #25 is the desired probing distance. Enter a positive value to probe the front and a negative value to probe the back +// Argument I -> #9 print results enabled by fusion360 + +// Initial Coding: Justin Gray +// Modified 1/14/2024: Joshua Smith +// Simplified WCS extended number math, added probe error checking, added probe distance argument +// Modified 31/03/2025: Robot Oblivion + +// load probe config +M800 A#1 + +// important local variables +#111 = @104 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#112 = @105 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#105 = @131 // TOOL RADIUS PROVIDED BY PROBECONFIG MACRO +#108 = @107*[#25/ABS[#25]] // PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO * the sign +1 or -1 of probe distance +#114 = @121 // processed extended WCS number provided by ProbeConfig macro +#128 = @96 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO + +M20 // UNLOCK SPINDLE ORIENT +IF[#25 < 0] + M19 P270 // ORIENT SPINDLE 270 DEGREES +ELSE + M19 P90 // ORIENT SPINDLE 0 DEGREES +END_IF + +//Probe X the desired distance and at fast feed +G31 G91 P2 Y[#25] F#111 //FEED UNTIL SKIP FAST + +//Check that the probe has triggered +IF[R_SKIP[0,1] == 1] + G91 G01 Y-[#108] //back off distance provided by ProbeConfig macro + FIX_CUT_OR_ON + G31 G91 P2 Y[#25] F#112 //Probe Y the desired distance at slow feed + FIX_CUT_OR_OFF + #104=R_SKIP[0,202] //GET MACHINE Y COORDINATE + G91 G01 Y-[#108] //back off distance provided by ProbeConfig macro + #106 = [#104+[[#25/abs[#25]]*#105]] //current position +/- probe radius + @996 = #106 + + //safety check for inspection variable + IF[#9 == #0] + #9 = 0 + END_IF + + //STORE Y OFFSET For WCS Zero + IF [#1 == #0 || #9 > 0] + //DO NOT WRITE ANYTHING TO WCS + ELSEIF [#114 < 1] + W_G53G59_COOR[0,#1,2,#106] + ELSE + W_G54EXP_COOR[0,#114,2,#106] + END_IF + +ELSE + ALARM["ERROR: FAILED TO PROBE PART WITHIN SPECIFIED DISTANCE"] +END_IF + +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +END_IF + +G90 +G00 // return to rapid speed +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M816 b/Macros for Controller/maker_macros/MAKER_MACRO_M816 new file mode 100644 index 0000000..7ee093e --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M816 @@ -0,0 +1,74 @@ +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// PROBEZ +// Probe in Z from the above stock + +// Argument A -> #1 is the work coordinate system to store offsets in. The format for extended G54 offsets would be a period followed by the offset G54.5 +// Argument Z -> #26 is the desired probing distance and should be negative +// Argument I -> #9 print results enabled by fusion360 + +// Initial Coding: Justin Gray +// Modified 1/14/2024: Joshua Smith +// Simplified WCS extended number math, added probe error checking, added probe distance argument,removed air blast +// Modified 31/03/2025: Robot Oblivion + +// load probe config +M800 A#1 + +// important local variables +#104 = @104 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#105 = @105 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#107 = @133 // TOOL LENGTH PROVIDED BY PROBECONFIG MACRO +#108 = @107 // PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO +#114 = @121 // processed extended WCS number provided by ProbeConfig macro +#128 = @96 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO + +IF[#128 == 1] + M19 // ORIENT SPINDLE +END_IF + +//Check that the probe distance is negative +IF[#26<0] + +//Probe Z the desired distance and at fast feed +G31 G91 P2 Z[#26] F#104 + +//Check that the probe has triggered +IF[R_SKIP[0,1] == 1] + G91 G01 Z+[#108] //back off distance provided by ProbeConfig macro + FIX_CUT_OR_ON + G31 G91 P2 Z[#26] F#105 //Probe Z the desired distance at slow feed + FIX_CUT_OR_OFF + #142=R_SKIP[0,203] //GET MACHINE Z COORDINATE + G91 G01 Z+[#108] //back off distance provided by ProbeConfig macro + #143 = [#142-#107] //current position - probe length + @996 = #143 + + //safety check for inspection variable + IF[#9 == #0] + #9 = 0 + END_IF + + //STORE Z OFFSET for WCS Zero + IF [#1 == #0 || #9 > 0] + //DO NOT WRITE ANYTHING TO WCS + ELSEIF [#114 < 1] + W_G53G59_COOR[0,#1,3,#143] + ELSE + W_G54EXP_COOR[0,#114,3,#143] + END_IF + ELSE + ALARM["Error: Failed to probe part within specified distance"] + END_IF + +ELSE + ALARM["Error: Probe distance must be negative"] +END_IF + +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +END_IF + +G90 +G00 // return to rapid speed +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M820 b/Macros for Controller/maker_macros/MAKER_MACRO_M820 new file mode 100644 index 0000000..e566cb3 --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M820 @@ -0,0 +1,39 @@ +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// PROBEPOCKET +// Probe a bore in X and Y + +// Argument A -> #1 is the work coordinate system to store offsets in +// Argument X -> #24 is the expected width +// Argument Y -> #25 is the expected length +// Argument I -> #9 print results enabled by fusion360 +// Argument Q -> #17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on +// Argument R -> #18 oversize tolorance +// Argument S -> #19 enable oversize check + +// Initial Coding: Justin Gray +// Modified 1/14/2024: Joshua Smith +// Simplified WCS extended number math, added probe error checking, added probe inspection report +// Modified 31/03/2025: Robot Oblivion + +@10 = R_G_GROUP[0,6] // pull in metric or freedom units + + M834 A#1 X#24 Q0 I#9 R#18 S#19 + M835 A#1 Y#25 Q0 I#9 R#18 S#19 + +//simple inspection reporting +IF [#17 > 0] + #98 = ROUND[@998 * @91] / @91 // Round to 3/4 decimal places + #99 = ROUND[@999 * @91] / @91 // Round to 3/4 decimal places + IF[@10 == 21] + MENU_ADD["Part Width mm X: #98",""]; + MENU_ADD["Part Length mm Y: #99",""]; + ELSE + MENU_ADD["Part Width In X: #98",""]; + MENU_ADD["Part Length In Y: #99",""]; + END_IF + MENU["INSPECTION REPORT","RESULTS","",1]; +END_IF + +G90 +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M821 b/Macros for Controller/maker_macros/MAKER_MACRO_M821 new file mode 100644 index 0000000..b2eea4a --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M821 @@ -0,0 +1,45 @@ +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// PROBERECTANGULARBOSS +// Probe a rectangular boss in X and Y + +// Argument A -> #1 is the work coordinate system to store offsets in +// Argument X -> #24 is the expected length of the web in the X direction //KC +// Argument Y -> #25 is the expected width of the web in the Y direction //KC +// Argument Z -> #26 is the Z drop height //KC +// Argument I -> #9 print results enabled by fusion360 +// Argument Q -> #17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on +// Argument R -> #18 oversize tolorance +// Argument S -> #19 enable oversize check + +// Initial Coding: Justin Gray +// Modified 1/14/2024: Joshua Smith +// Simplified WCS extended number math, added probe error checking, added probe inspection report +// Modified 31/03/2025: Robot Oblivion + +@10 = R_G_GROUP[0,6] // pull in metric or freedom units + +M824 A#1 X#24 Z#26 I#9 Q0 R#18 S#19 +M825 A#1 Y#25 Z#26 I#9 Q0 R#18 S#19 + +//simple inspection reporting +//@999 and @998 are set in the web macros +IF [#17 > 0] + #98 = ROUND[@998 * @91] / @91 // Round to 3/4 decimal places + #99 = ROUND[@999 * @91] / @91 // Round to 3/4 decimal places + IF[@10 == 21] + MENU_ADD["Part Width mm X: #98",""]; + MENU_ADD["Part Length mm Y: #99",""]; + ELSE + MENU_ADD["Part Width In X: #98",""]; + MENU_ADD["Part Length In Y: #99",""]; + END_IF + MENU["INSPECTION REPORT","RESULTS","",1]; +END_IF + +G90 +G4 P100 +M20 // UNLOCK SPINDLE ORIENT +M19 P0 // ORIENT SPINDLE 0 DEGREES TO LEAVE AS IT ENTERED + +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M824 b/Macros for Controller/maker_macros/MAKER_MACRO_M824 new file mode 100644 index 0000000..b49fd93 --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M824 @@ -0,0 +1,173 @@ +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// PROBEXWEB +// Probe a web in X from left to right + +// Argument A -> #1 is the work coordinate system to store offsets in +// Argument X -> #24 is the expected width of the web in the X direction +// Argument Z -> #26 is the Z drop height +// Argument I -> #9 print results enabled by fusion360 +// Argument Q -> #17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on +// Argument R -> #18 oversize tolorance +// Argument S -> #19 enable oversize check + +// Initial Coding: Justin Gray +// Modified 1/14/2024: Joshua Smith +// Simplified WCS extended number math, added probe error checking, added probe inspection report +// Modified 31/03/2025: Robot Oblivion + +// load probe config +M800 A#1 + +// important local variables +#100 = @100 //TOOL NUMBER PROVIDED BY PROBECONFIG MACRO +#110 = @103 //FEED SPEED PROVIDED BY PROBECONFIG MACRO +#111 = @104 //FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#112 = @105 //SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#101 = @130 //TOOL DIAMETER PROVIDED BY PROBECONFIG MACRO +#102 = @106 //WEB PROBE DISTANCE PROVIDED BY PROBECONFIG MACRO +#108 = @107 //PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO +#24 = ABS[#24] +#26 = ABS[#26] +#114 = @121 // processed extended WCS number provided by ProbeConfig macro + +//probe X starting from a negative offset and probing in the positive direction +//MOVE TO -X SIDE OF THE PART, BEFORE STARTING TO PROBE +G31 G91 P2 X-[#24/2+#102] F#110 + +//Error Checking +IF[R_SKIP[0,1] == 1] + ALARM["ERROR: PREMATURE PROBE COLLISION"] + GOTO1 //go to line with N1 and quit +END_IF + +M20 // UNLOCK SPINDLE ORIENT +M19 P0 // ORIENT SPINDLE 0 DEGREES TO KEEP THE POBING POINT THE SAME + +//DROP TO PROBING HEIGHT +G31 G91 P2 Z-#26 F#110 + +//Error Checking +IF[R_SKIP[0,1] == 1] + ALARM["ERROR: PREMATURE PROBE COLLISION"] + GOTO1 //go to line with N1 and quit +END_IF + +//Probe X on left side +G31 G91 P2 X[#102+#108] F#111 //FEED PROBING DINSTANCE + BACK OFF UNTIL SKIP FAST + +//Error Checking +IF[R_SKIP[0,1] == 0] + ALARM["ERROR: FAILED TO PROBE PART WITHIN SPECIFIED DISTANCE"] + GOTO1 //go to line with N1 and quit +END_IF + +G91 G01 X[-#108] //Back OFF +FIX_CUT_OR_ON +G31 G91 P2 X[#108] F#112 //FEED UNTIL SKIP SLOW +FIX_CUT_OR_OFF +#104=R_SKIP[0,201] //GET FIRST MACHINE X COORDINATE +G91 G01 X-[#108] //Back off + +//lift Z after probe +G31 G91 P2 Z#26 F#110 //move above the part + +//Move to opposite side of part +G31 G91 P2 X[#24+#102+#108] F#110 //move to other side of the part, probe distance away + +//Error Checking +IF[R_SKIP[0,1] == 1] + ALARM["ERROR: PREMATURE PROBE COLLISION"] + GOTO1 //go to line with N1 and quit +END_IF + +M20 // UNLOCK SPINDLE ORIENT +M19 P180 // ORIENT SPINDLE 180 DEGREES TO KEEP THE POBING POINT THE SAME + +//Drop to Probing Height +G31 G91 P2 Z-#26 F#110 //move back down to probe height + +//Error Checking +IF[R_SKIP[0,1] == 1] + ALARM["ERROR: PREMATURE PROBE COLLISION"] + GOTO1 //go to line with N1 and quit +END_IF + +//Probe X on right side +G31 G91 P2 X[-1*[#102+#108]] F#111 //FEED PROBING DINSTANCE + BACK OFF UNTIL SKIP FAST + +//Error Checking +IF[R_SKIP[0,1] == 0] + ALARM["ERROR: FAILED TO PROBE PART WITHIN SPECIFIED DISTANCE"] + GOTO1 //go to line with N1 and quit +END_IF + +G91 G01 X[#108] //BACK OFF +FIX_CUT_OR_ON +G31 G91 P2 X[-#108] F#112 //FEED UNTIL SKIP SLOW +FIX_CUT_OR_OFF +#105=R_SKIP[0,201] //GET SECOND MACHINE X COORDINATE +G91 G01 X[#108] F#110 //BACK OFF +G91 G01 Z#26 //MOVE UP CLEAR OF THE PART + +//COMPUTE RELATIVE DISTANCE TO CENTER OF THE PART +#106=[[#105-#104]/2] //center point calculation +#107= ABS[[#105-#104]]-#101 //calculate width of part: distance - diameter +@998 = #107 //save distance to a global variable for use with other macros +G91 G01 X[-#108 - #106] //MOVE TO CENTER OF THE PART +#104=R_MACH_COOR[0,1] //GET MACHINE X COORDINATE +#126=ABS[#107-#24] //expected stock error + +//if the tolorance is null, default it to global variable from the probe config +IF[#18==#0] + #18 = @108 +END_IF + +//oversized stock alarm if stock error is greater than tolorance +IF[#19!=#0 && #126>#18 ] +#136 = ROUND[[#107-#24] * @91] / @91 // Round to 3/4 decimal places +#107 = ROUND[#107 * @91] / @91 // Round to 3/4 decimal places + MENU_ADD["Expected size: #24",""]; + MENU_ADD["Probed size: #107",""]; + MENU_ADD["Tolerance: #18",""]; + MENU_ADD["Off-target: #136",""]; + MENU["Error","Stock outside of tolerance in X","",1]; + IF[@97 == 1] + ALARM["Error: Stock outside of tolerance in X"] + END_IF +END_IF + +//safety check for inspection variable +IF[#9 == #0] + #9 = 0 +END_IF + +//STORE X OFFSET +IF [#1 == #0 || #9>0] + //DO NOT SET ANYTHING INTO WCS +ELSEIF [#114 < 1] + W_G53G59_COOR[0,#1,1,#104] +ELSE + W_G54EXP_COOR[0,#114,1,#104] +END_IF + +//simple inspection reporting +IF [#17 > 0] + #98 = ROUND[@998 * @91] / @91 // Round to 3/4 decimal places + IF[@10 == 21] + MENU_ADD["Part Width mm X: #98",""]; + ELSE + MENU_ADD["Part Width In X: #98",""]; + END_IF + MENU["INSPECTION REPORT","RESULTS","",1]; +END_IF + + +N1 + +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +END_IF + +G90 +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M825 b/Macros for Controller/maker_macros/MAKER_MACRO_M825 new file mode 100644 index 0000000..9bfa74c --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M825 @@ -0,0 +1,173 @@ +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// PROBEYWEB +// Probe a web in Y from Front to back + +// Argument A -> #1 is the work coordinate system to store offsets in +// Argument Y -> #25 is the expected length of the web in the Y direction +// Argument Z -> #26 is the Z drop height +// Argument I -> #9 print results enabled by fusion360 +// Argument Q -> #17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on +// Argument R -> #18 oversize tolorance +// Argument S -> #19 enable oversize check + +// Initial Coding: Justin Gray +// Modified 1/14/2024: Joshua Smith +// Simplified WCS extended number math, added probe error checking, added probe inspection report +// Modified 31/03/2025: Robot Oblivion + +// load probe config +M800 A#1 + +// important local variables +#100 = @100 //TOOL NUMBER PROVIDED BY PROBECONFIG MACRO +#110 = @103 //FEED SPEED PROVIDED BY PROBECONFIG MACRO +#111 = @104 //FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#112 = @105 //SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#101 = @130 //TOOL DIAMETER PROVIDED BY PROBECONFIG MACRO +#102 = @106 //WEB PROBE DISTANCE PROVIDED BY PROBECONFIG MACRO +#108 = @107 //PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO +#25 = ABS[#25] +#26 = ABS[#26] +#114 = @121 // processed extended WCS number provided by ProbeConfig macro + +//probe Y starting from a negative offset and probing in the positive direction +//MOVE TO -Y SIDE OF THE PART, BEFORE STARTING TO PROBE +G31 G91 P2 Y-[#25/2+#102] F#110 + +//Error Checking +IF[R_SKIP[0,1] == 1] + ALARM["ERROR: PREMATURE PROBE COLLISION"] + GOTO1 //go to line with N1 and quit +END_IF + +M20 // UNLOCK SPINDLE ORIENT +M19 P90 // ORIENT SPINDLE 0 DEGREES TO KEEP THE POBING POINT THE SAME + +//DROP TO PROBING HEIGHT +G31 G91 P2 Z-#26 F#110 + +//Error Checking +IF[R_SKIP[0,1] == 1] + ALARM["ERROR: PREMATURE PROBE COLLISION"] + GOTO1 //go to line with N1 and quit +END_IF + +//probe y from the front +G31 G91 P2 Y[#102+#108] F#111 //FEED PROBING DINSTANCE + BACK OFF UNTIL SKIP FAST + +//Error Checking +IF[R_SKIP[0,1] == 0] + ALARM["ERROR: FAILED TO PROBE PART WITHIN SPECIFIED DISTANCE"] + GOTO1 //go to line with N1 and quit +END_IF + +G91 G01 Y[-#108] //back off +FIX_CUT_OR_ON +G31 G91 P2 Y[#108] F#112 //FEED UNTIL SKIP SLOW +FIX_CUT_OR_OFF +#104=R_SKIP[0,202] //GET FIRST MACHINE Y COORDINATE +G91 G01 Y[-#108] //back off + +//lift Z after probe +G31 G91 P2 Z#26 F#110 //move above the part + +//move to the opposite side of the part +G31 G91 P2 Y[#25+#102+#108] F#110 //move to other side of the part,pobe distance away + +//Error Checking +IF[R_SKIP[0,1] == 1] + ALARM["ERROR: PREMATURE PROBE COLLISION"] + GOTO1 //go to line with N1 and quit +END_IF + +M20 // UNLOCK SPINDLE ORIENT +M19 P270 // ORIENT SPINDLE 270 DEGREES TO KEEP THE POBING POINT THE SAME + +//Move Z down to probe hight +G31 G91 P2 Z-#26 F#110 //move back down to probe height + +//Error Checking +IF[R_SKIP[0,1] == 1] + ALARM["ERROR: PREMATURE PROBE COLLISION"] + GOTO1 //go to line with N1 and quit +END_IF + +//probe back side of part +G31 G91 P2 Y[-1*[#102+#108]] F#111 //FEED PROBING DINSTANCE + BACK OFF UNTIL SKIP FAST + +//Error Checking +IF[R_SKIP[0,1] == 0] + ALARM["ERROR: FAILED TO PROBE PART WITHIN SPECIFIED DISTANCE"] + GOTO1 //go to line with N1 and quit +END_IF + +G91 G01 Y[#108] //back off +FIX_CUT_OR_ON +G31 G91 P2 Y[-#108] F#112 //FEED UNTIL SKIP SLOW +FIX_CUT_OR_OFF +#105=R_SKIP[0,202] //GET SECOND MACHINE Y COORDINATE +G91 G01 Y[#108] F#110 //back off +G91 G01 Z#26 //MOVE UP CLEAR OF THE PART + +//COMPUTE RELATIVE DISTANCE TO CENTER OF THE PART +#106 = [[#105-#104]/2] //calculate center +#107 = ABS[#105-#104]-#101 //calculate distance: distance - diameter +@999 = #107 //save distance to a global variable for use with other macros +G91 G01 Y[-#108 - #106] //MOVE TO CENTER OF THE PART +#104=R_MACH_COOR[0,2] //GET MACHINE Y COORDINATE +#126=ABS[#107-#25] //expected stock error + +//if the tolorance is null, default it to global variable from the probe config +IF[#18==#0] + #18 = @108 +END_IF + +//oversized stock alarm if stock error is greater than tolorance +IF[#19!=#0 && #126>#18 ] +#136 = ROUND[[#107-#25] * @91] / @91 // Round to 3/4 decimal places +#107 = ROUND[#107 * @91] / @91 // Round to 3/4 decimal places + MENU_ADD["Expected size: #25",""]; + MENU_ADD["Probed size: #107",""]; + MENU_ADD["Tolerance: #18",""]; + MENU_ADD["Off-target: #136",""]; + MENU["Error","Stock outside of tolerance in Y","",1]; + IF[@97 == 1] + ALARM["Error: Stock outside of tolerance in Y"] + END_IF +END_IF + +//safety check for inspection variable +IF[#9 == #0] + #9 = 0 +END_IF + +//STORE Y OFFSET +IF [#1 == #0 || #9 > 0] + //DO NOT SET ANYTHING INTO WCS +ELSEIF [#114 < 1] + W_G53G59_COOR[0,#1,2,#104] +ELSE + W_G54EXP_COOR[0,#114,2,#104] +END_IF + +//simple inspection reporting +IF [#17 > 0] + #99 = ROUND[@999 * @91] / @91 // Round to 3/4 decimal places + IF[@10 == 21] + MENU_ADD["Part Length mm Y: #99",""]; + ELSE + MENU_ADD["Part Length In Y: #99",""]; + END_IF + MENU["INSPECTION REPORT","RESULTS","",1]; +END_IF + + +N1 + +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +END_IF + +G90 +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M827 b/Macros for Controller/maker_macros/MAKER_MACRO_M827 new file mode 100644 index 0000000..aa709a0 --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M827 @@ -0,0 +1,191 @@ +// Copyright 2024 Toolpath Labs Inc., Justin Gray, and Josh Smith + +// PROBEXYANGLE +// Probe and report an angle measured in the XY plane + +// Argument A -> #1 is the work coordinate system to store offsets in +// Argument B -> #2 is the distance between probing points +// Argument C -> #3 is the probing distance +// Argument D -> #4 is the probing axis 1=X, 2=Y +// Argument Q -> #17 turns on inspection report on/off: 0 leaves it off ; 1 turns it on ; it is off by default + +// Initial Coding: Joshua Smith +// Modified 31/03/2025: Robot Oblivion + +// load probe config +M800 A#1 + +// important local variables +#100 = @100 // TOOL NUMBER PROVIDED BY PROBECONFIG MACRO +#110 = @103 // FEED SPEED PROVIDED BY PROBECONFIG MACRO +#111 = @104 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#112 = @105 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#108 = @107 // PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO +#109 = R_MACH_COOR[0,1] // GET MACHINE X COORDINATE +#110 = R_MACH_COOR[0,2] // GET MACHINE y COORDINATE +#111 = R_MACH_COOR[0,3] // GET MACHINE z COORDINATE +#128 = @96 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO +#114 = @121 // processed extended WCS number provided by ProbeConfig macro + +IF[#128 == 1] + M19 // ORIENT SPINDLE +END_IF + + +IF[#4== 1] + // Probe X the desired distance and at fast feed + G31 G91 P2 X[#3] F#111 + + // Error Checking + IF[R_SKIP[0,1] == 0] + ALARM["ERROR: FAILED TO PROBE PART WITHIN SPECIFIED DISTANCE"] + GOTO1 // go to line with N1 and quit + END_IF + + // Start probing in X + G91 G01 X-[#108] // back off 1/4 the probing distance + FIX_CUT_OR_ON + G31 G91 P2 X[#108] F#112 // Probe X the desired distance at slow feed + FIX_CUT_OR_OFF + #120 = R_SKIP[0,201] // GET MACHINE X COORDINATE + #101 = R_SKIP[0,202] // GET MACHINE Y COORDINATE + #102 = R_SKIP[0,202] // GET MACHINE Y COORDINATE + G91 G01 X-[#108] // back off 1/4 the probing distance + + // move to original X position + G31 G91 P2 X[-#109+#120+#108] F#111 + + // Error Checking + IF[R_SKIP[0,1] == 1] + ALARM["ERROR: PREMATURE PROBE COLLISION"] + GOTO1 // go to line with N1 and quit + END_IF + + // Move disired probe distance + G31 G91 P2 Y[#2] F#111 + + // Error Checking + IF[R_SKIP[0,1] == 1] + ALARM["ERROR: PREMATURE PROBE COLLISION"] + GOTO1 // go to line with N1 and quit + END_IF + + // Probe X the desired distance and at fast feed + G31 G91 P2 X[#3] F#111 + + // Error Checking + IF[R_SKIP[0,1] == 0] + ALARM["ERROR: FAILED TO PROBE PART WITHIN SPECIFIED DISTANCE"] + GOTO1 // go to line with N1 and quit + END_IF + + + // Start probing in X + G91 G01 X-[#108] // back off 1/4 the probing distance + FIX_CUT_OR_ON + G31 G91 P2 X[#108] F#112 // Probe X the desired distance at slow feed + FIX_CUT_OR_OFF + #123 = R_SKIP[0,201] // GET MACHINE X COORDINATE + #124 = R_SKIP[0,202] // GET MACHINE Y COORDINATE + #125 = R_SKIP[0,202] // GET MACHINE Y COORDINATE + G91 G01 X-[#108] // back off 1/4 the probing distance + + // move to original X position + G31 G91 P2 X[-#109+#123+#108] F#111 + + // Error Checking + IF[R_SKIP[0,1] == 1] + ALARM["ERROR: PREMATURE PROBE COLLISION"] + GOTO1 // go to line with N1 and quit + END_IF + + // angle claculation + #126 = ATAN[[#123-#120],[#124-#101]] + +ELSE + // Probe Y the desired distance and at fast feed + G31 G91 P2 Y[#3] F#111 + + // Error Checking + IF[R_SKIP[0,1] == 0] + ALARM["ERROR: FAILED TO PROBE PART WITHIN SPECIFIED DISTANCE"] + GOTO1 // go to line with N1 and quit + END_IF + + // Start probing in Y + G91 G01 Y-[#108] // back off 1/4 the probing distance + FIX_CUT_OR_ON + G31 G91 P2 Y[#108] F#112 // Probe X the desired distance at slow feed + FIX_CUT_OR_OFF + #120 = R_SKIP[0,201] // GET MACHINE X COORDINATE + #101 = R_SKIP[0,202] // GET MACHINE Y COORDINATE + #102 = R_SKIP[0,202] // GET MACHINE Z COORDINATE + G91 G01 Y-[#108] // back off 1/4 the probing distance + + // move to original Y position + G31 G91 P2 Y[-#110+#101+#108] F#111 + + // Error Checking + IF[R_SKIP[0,1] == 1] + ALARM["ERROR: PREMATURE PROBE COLLISION"] + GOTO1 // go to line with N1 and quit + END_IF + + // Move disired probe distance + G31 G91 P2 X[#2] F#111 + + // Error Checking + IF[R_SKIP[0,1] == 1] + ALARM["ERROR: PREMATURE PROBE COLLISION"] + GOTO1 // go to line with N1 and quit + END_IF + + // Probe Y the desired distance and at fast feed + G31 G91 P2 Y[#3] F#111 + + // Error Checking + IF[R_SKIP[0,1] == 0] + ALARM["ERROR: FAILED TO PROBE PART WITHIN SPECIFIED DISTANCE"] + GOTO1 // go to line with N1 and quit + END_IF + + + // Start probing in Y + G91 G01 Y-[#108] // back off 1/4 the probing distance + FIX_CUT_OR_ON + G31 G91 P2 Y[#108] F#112 // Probe X the desired distance at slow feed + FIX_CUT_OR_OFF + #123 = R_SKIP[0,201] // GET MACHINE X COORDINATE + #124 = R_SKIP[0,202] // GET MACHINE Y COORDINATE + #125 = R_SKIP[0,202] // GET MACHINE Z COORDINATE + G91 G01 Y-[#108] // back off 1/4 the probing distance + + // move to original X position + G31 G91 P2 Y[-#110+#124+#108] F#111 + + // Error Checking + IF[R_SKIP[0,1] == 1] + ALARM["ERROR: PREMATURE PROBE COLLISION"] + GOTO1 // go to line with N1 and quit + END_IF + + // angle claculation + #126 = ATAN[[#124-#101],[#123-#120]] + +END_IF + +// simple inspection reporting +IF [#17 > 0] + MENU_ADD["MEASURED ANGLE: #126",""]; + MENU["INSPECTION REPORT","RESULTS","",1]; +END_IF + + +N1 + +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +END_IF + +G90 +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M830 b/Macros for Controller/maker_macros/MAKER_MACRO_M830 new file mode 100644 index 0000000..a07e892 --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M830 @@ -0,0 +1,48 @@ +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// PROBEBORE +// Probe a bore in X and Y + +// Argument A -> #1 is the work coordinate system to store offsets in +// Argument D -> #4 is the expected DIAMETER +// Argument I -> #9 print results enabled by fusion360 +// Argument Q -> #17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on +// Argument R -> #18 oversize tolorance +// Argument S -> #19 enable oversize check + +// Initial Coding: Justin Gray +// Modified 1/14/2024: Joshua Smith +// Simplified WCS extended number math, added probe error checking, added probe inspection report +// Modified 31/03/2025: Robot Oblivion + + //calling our slot macros the first time centers probe + M834 A#1 X#4 I#9 Q0 R#18 S#19 + M835 A#1 Y#4 I#9 Q0 R#18 S#19 + + //calling our slot macros a second time gives an accurate inspection + M834 A#1 X#4 I#9 Q0 R#18 S#19 + M835 A#1 Y#4 I#9 Q0 R#18 S#19 + +//average Diameter calculation +//@999 and @998 are set in the web macros +@997 = [@998 + @999]/2 + +//simple inspection reporting +IF [#17 > 0] + #97 = ROUND[@997 * @91] / @91 // Round to 3/4 decimal places + #98 = ROUND[@998 * @91] / @91 // Round to 3/4 decimal places + #99 = ROUND[@999 * @91] / @91 // Round to 3/4 decimal places + IF[@10 == 21] + MENU_ADD["Part Diameter mm X: #98",""]; + MENU_ADD["Part Diameter mm Y: #99",""]; + MENU_ADD["AVG Diameter mm: #97",""]; //THE WORD AVERAGE IS TO LONG FOR THE MENU + ELSE + MENU_ADD["Part Diameter In X: #98",""]; + MENU_ADD["Part Diameter In Y: #99",""]; + MENU_ADD["AVG Diameter In: #97",""]; //THE WORD AVERAGE IS TO LONG FOR THE MENU + END_IF + MENU["INSPECTION REPORT","RESULTS","",1]; +END_IF + +G90 +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M831 b/Macros for Controller/maker_macros/MAKER_MACRO_M831 new file mode 100644 index 0000000..bd75bc8 --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M831 @@ -0,0 +1,49 @@ +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// PROBECIRCULARBOSS +// Probe a circular boss in X and Y + +// Argument A -> #1 is the work coordinate system to store offsets in +// Argument D -> #4 is the expected DIAMETER +// Argument Z -> #26 is the Z drop height +// Argument I -> #9 print results enabled by fusion360 +// Argument Q -> #17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on +// Argument R -> #18 oversize tolorance +// Argument S -> #19 enable oversize check + +// Initial Coding: Justin Gray +// Modified 1/14/2024: Joshua Smith +// Simplified WCS extended number math, added probe error checking, added probe inspection report +// Modified 31/03/2025: Robot Oblivion + +//calling our web macros the first time centers us +M824 A#1 X#4 Z#26 I#9 Q0 R#18 S#19 +M825 A#1 Y#4 Z#26 I#9 Q0 R#18 S#19 + +//calling our web macros the second time gives an accurate center +M824 A#1 X#4 Z#26 I#9 Q0 R#18 S#19 +M825 A#1 Y#4 Z#26 I#9 Q0 R#18 S#19 + +//average Diameter calculation +//@999 and @998 are set in the web macros +@997 = [@998 + @999]/2 + +//simple inspection reporting +IF [#17 > 0] + #97 = ROUND[@997 * @91] / @91 // Round to 3/4 decimal places + #98 = ROUND[@998 * @91] / @91 // Round to 3/4 decimal places + #99 = ROUND[@999 * @91] / @91 // Round to 3/4 decimal places + IF[@10 == 21] + MENU_ADD["Part Diameter mm X: #98",""]; + MENU_ADD["Part Diameter mm Y: #99",""]; + MENU_ADD["AVG Diameter mm: #97",""]; //THE WORD AVERAGE IS TO LONG FOR THE MENU + ELSE + MENU_ADD["Part Diameter In X: #98",""]; + MENU_ADD["Part Diameter In Y: #99",""]; + MENU_ADD["AVG Diameter In: #97",""]; //THE WORD AVERAGE IS TO LONG FOR THE MENU + END_IF + MENU["INSPECTION REPORT","RESULTS","",1]; +END_IF + +G90 +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M834 b/Macros for Controller/maker_macros/MAKER_MACRO_M834 new file mode 100644 index 0000000..4861152 --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M834 @@ -0,0 +1,132 @@ +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// PROBEXSLOT +// Probe a SLOT in X from left to right + +// Argument A -> #1 is the work coordinate system to store offsets in +// Argument X -> #24 is the expected width of the web in the X direction +// Argument I -> #9 print results enabled by fusion360 +// Argument Q -> #17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on +// Argument R -> #18 oversize tolorance +// Argument S -> #19 enable oversize check + +// Initial Coding: Justin Gray +// Modified 1/14/2024: Joshua Smith +// Simplified WCS extended number math, added probe error checking, added probe inspection report +// Modified 31/03/2025: Robot Oblivion + +// load probe config +M800 A#1 + +M20 // UNLOCK SPINDLE ORIENT +M19 P180 // ORIENT SPINDLE 180 DEGREES TO KEEP THE POBING POINT THE SAME + +// important local variables +#100 = @100 //TOOL NUMBER PROVIDED BY PROBECONFIG MACRO +#111 = @104 //FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#112 = @105 //SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#101 = @130 //TOOL DIAMETER PROVIDED BY PROBECONFIG MACRO +#102 = @106 //WEB PROBE DISTANCE PROVIDED BY PROBECONFIG MACRO +#108 = @107 //PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO +#24 = ABS[#24] +#114 = @121 // processed extended WCS number provided by ProbeConfig macro + + +//probe X starting from a negative offset and probing in the positive direction +//MOVE TO -X SIDE OF THE PART, BEFORE STARTING TO PROBE +G31 G91 P2 X-[#24/2+#102] F#111 + +//Error Checking +IF[R_SKIP[0,1] == 0] + ALARM["ERROR: FAILED TO PROBE PART WITHIN SPECIFIED DISTANCE"] + GOTO1 //go to line with N1 and quit +END_IF + +G91 G01 X[#108] //Back OFF +FIX_CUT_OR_ON +G31 G91 P2 X-[#108] F#112 //FEED UNTIL SKIP SLOW +FIX_CUT_OR_OFF +#104=R_SKIP[0,201] //GET FIRST MACHINE X COORDINATE +G91 G01 X[#108] //Back off + +M20 // UNLOCK SPINDLE ORIENT +M19 P0 // ORIENT SPINDLE 0 DEGREES TO KEEP THE POBING POINT THE SAME + +//Move to opposite side of part +G31 G91 P2 X[#24+#102-#108] F#111 //move to other side of the part, probe distance away + +//Error Checking +IF[R_SKIP[0,1] == 0] + ALARM["ERROR: FAILED TO PROBE PART WITHIN SPECIFIED DISTANCE"] + GOTO1 //go to line with N1 and quit +END_IF + +G91 G01 X[-#108] //BACK OFF +FIX_CUT_OR_ON +G31 G91 P2 X[#108] F#112 //FEED UNTIL SKIP SLOW +FIX_CUT_OR_OFF +#105=R_SKIP[0,201] //GET SECOND MACHINE X COORDINATE +G91 G01 X[-#108] //BACK OFF + +//COMPUTE RELATIVE DISTANCE TO CENTER OF THE PART +#106=[[#105-#104]/2] //center point calculation +#107= ABS[[#105-#104]]+#101 //calculate width of part: distance + diameter +@998 = #107 //save distance to a global variable for use with other macros +G91 G01 X[-#106 + #108] //MOVE TO CENTER OF THE PART +#104=R_MACH_COOR[0,1] //GET MACHINE Y COORDINATE +#126=ABS[#107-#24] //expected stock error + +//if the tolorance is null, default it to global variable from the probe config +IF[#18==#0] + #18 = @108 +END_IF + +//oversized stock alarm if stock error is greater than tolorance +IF[#19!=#0 && #126>#18 ] + #136 = ROUND[[#107-#24] * @91] / @91 // Round to 3/4 decimal places + #107 = ROUND[#107 * @91] / @91 // Round to 3/4 decimal places + MENU_ADD["Expected size: #24",""]; + MENU_ADD["Probed size: #107",""]; + MENU_ADD["Tolerance: #18",""]; + MENU_ADD["Off-target: #136",""]; + MENU["Error","Stock outside of tolerance in X","",1]; + IF[@97 == 1] + ALARM["Error: Stock outside of tolerance in X"] + END_IF +END_IF + +//safety check for inspection variable +IF[#9 == #0] + #9 = 0 +END_IF + +//STORE X OFFSET + +IF [#1 == #0 || #9 > 0] + //DO NOT WRITE ANYTHING TO WCS +ELSEIF [#114 < 1] + W_G53G59_COOR[0,#1,1,#104] +ELSE + W_G54EXP_COOR[0,#114,1,#104] +END_IF + +//simple inspection reporting +IF [#17 > 0] + #98 = ROUND[@998 * @91] / @91 // Round to 3/4 decimal places + IF[@10 == 21] + MENU_ADD["Part Width mm X: #98",""]; + ELSE + MENU_ADD["Part Width In X: #98",""]; + END_IF + MENU["INSPECTION REPORT","RESULTS","",1]; +END_IF + + +N1 + +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +END_IF + +G90 +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M835 b/Macros for Controller/maker_macros/MAKER_MACRO_M835 new file mode 100644 index 0000000..4d6429a --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M835 @@ -0,0 +1,130 @@ +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// PROBEYSLOT +// Probe a web in X from left to right + +// Argument A -> #1 is the work coordinate system to store offsets in +// Argument Y -> #25 is the expected length of the web in the Y direction +// Argument I -> #9 print results enabled by fusion360 +// Argument Q -> #17 turns on inspection report on/off: 0 leaves it off default; 1 turns it on +// Argument R -> #18 oversize tolorance +// Argument S -> #19 enable oversize check + +// Initial Coding: Justin Gray +// Modified 1/14/2024: Joshua Smith +// Simplified WCS extended number math, added probe error checking, added probe inspection report +// Modified 31/03/2025: Robot Oblivion + +// load probe config +M800 A#1 + +M20 // UNLOCK SPINDLE ORIENT +M19 P270 // ORIENT SPINDLE 270 DEGREES TO KEEP THE POBING POINT THE SAME + +// important local variables +#100 = @100 //TOOL NUMBER PROVIDED BY PROBECONFIG MACRO +#110 = @103 //FEED SPEED PROVIDED BY PROBECONFIG MACRO +#111 = @104 //FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#112 = @105 //SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#101 = @130 //TOOL DIAMETER PROVIDED BY PROBECONFIG MACRO +#102 = @106 //WEB PROBE DISTANCE PROVIDED BY PROBECONFIG MACRO +#108 = @107 //PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO +#25 = ABS[#25] +#114 = @121 // processed extended WCS number provided by ProbeConfig macro + +//probe Y starting from a negative offset and probing in the positive direction +//MOVE TO -Y SIDE OF THE PART, BEFORE STARTING TO PROBE +G31 G91 P2 Y-[#25/2+#102] F#111 + +//Error Checking +IF[R_SKIP[0,1] == 0] + ALARM["ERROR: FAILED TO PROBE PART WITHIN SPECIFIED DISTANCE"] + GOTO1 //go to line with N1 and quit +END_IF + +G91 G01 Y[#108] //back off +FIX_CUT_OR_ON +G31 G91 P2 Y[-#108] F#112 //FEED UNTIL SKIP SLOW +FIX_CUT_OR_OFF +#104=R_SKIP[0,202] //GET FIRST MACHINE Y COORDINATE +G91 G01 Y[#108] //back off + +M20 // UNLOCK SPINDLE ORIENT +M19 P90 // ORIENT SPINDLE 90 DEGREES TO KEEP THE POBING POINT THE SAME + +//move to the opposite side of the part +G31 G91 P2 Y[#25+#102-#108] F#111 //move to other side of the part,pobe distance away + +//Error Checking +IF[R_SKIP[0,1] == 0] + ALARM["ERROR: FAILED TO PROBE PART WITHIN SPECIFIED DISTANCE"] + GOTO1 //go to line with N1 and quit +END_IF + +G91 G01 Y[-#108] //back off +FIX_CUT_OR_ON +G31 G91 P2 Y[#108] F#112 //FEED UNTIL SKIP SLOW +FIX_CUT_OR_OFF +#105=R_SKIP[0,202] //GET SECOND MACHINE Y COORDINATE +G91 G01 Y[-#108] F#110 //back off + +//COMPUTE RELATIVE DISTANCE TO CENTER OF THE PART +#106 = [[#105-#104]/2] //calculate center +#107 = ABS[#105-#104]+#101 //calculate distance: distance - diameter +@999 = #107 //save distance to a global variable for use with other macros +G91 G01 Y[-#106 + #108] //MOVE TO CENTER OF THE PART +#104=R_MACH_COOR[0,2] //GET MACHINE Y COORDINATE +#126=ABS[#107-#25] //expected stock error + +//if the tolorance is null, default it to global variable from the probe config +IF[#18==#0] + #18 = @108 +END_IF + +//oversized stock alarm if stock error is greater than tolorance +IF[#19!=#0 && #126>#18 ] + #136 = ROUND[[#107-#25] * @91] / @91 // Round to 3/4 decimal places + #107 = ROUND[#107 * @91] / @91 // Round to 3/4 decimal places + MENU_ADD["Expected size: #25",""]; + MENU_ADD["Probed size: #107",""]; + MENU_ADD["Tolerance: #18",""]; + MENU_ADD["Off-target: #136",""]; + MENU["Error","Stock outside of tolerance in Y","",1]; + IF[@97 == 1] + ALARM["Error: Stock outside of tolerance in Y"] + END_IF +END_IF + +//safety check for inspection variable +IF[#9 == #0] + #9 = 0 +END_IF + +//STORE Y OFFSET +IF [#1 == #0 || #9 > 0] + //DO NOT WRITE ANYTHING TO WCS +ELSEIF [#114 < 1] + W_G53G59_COOR[0,#1,2,#104] +ELSE + W_G54EXP_COOR[0,#114,2,#104] +END_IF + +//simple inspection reporting +IF [#17 > 0] + #99 = ROUND[@999 * @91] / @91 // Round to 3/4 decimal places + IF[@10 == 21] + MENU_ADD["Part Length mm Y: #99",""]; + ELSE + MENU_ADD["Part Length In Y: #99",""]; + END_IF + MENU["INSPECTION REPORT","RESULTS","",1]; +END_IF + +N1 + +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +END_IF + +G90 +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M837 b/Macros for Controller/maker_macros/MAKER_MACRO_M837 new file mode 100644 index 0000000..dc5d7c0 --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M837 @@ -0,0 +1,76 @@ +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// PROBEINSIDECORNER +// Probe ONE OF 4 INSIDE CORNERS + +// Probe ONE OF 4 INSIDE CORNERS +// Argument A -> #1 is the work coordinate system to store offsets in. The format for extended G54 offsets would be a period followed by the offset// G54.5 +// Argument C -> #3 defines which corner +// 1 2 +// 3 4 +// Argument E -> #5 engage distance to probe part + +// Simplified WCS extended number math, added probe error checking, added probe distance argument +// Modified 31/03/2025: Robot Oblivion + +// load probe config +M800 + +#128 = @96 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO +IF[#128 == 1] + M19 // ORIENT SPINDLE +END_IF + +// important local variables +#100 = @100 // TOOL NUMBER PROVIDED BY PROBECONFIG MACRO +#110 = @103 // FEED SPEED PROVIDED BY PROBECONFIG MACRO +#111 = @104 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#112 = @105 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#105 = @131 // TOOL RADIUS PROVIDED BY PROBECONFIG MACRO +#108 = @107*[#3/ABS[#3]] // PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO * the sign// +1 or -1 of probe distance + + +// #120 is X APPROACH DIRECTION +// #101 is Y APPROACH DIRECTION +IF[#3==1] + #120 = -1 + #101 = 1 +ELSEIF[#3==2] + #120 = 1 + #101 = 1 +ELSEIF[#3==3] + #120 = -1 + #101 = -1 +ELSEIF[#3==4] + #120 = 1 + #101 = -1 +END_IF + +// RECORD INITIAL POSITION SO WE CAN TOGGLE BACK TO IT +#102 = R_MACH_COOR[0,1] // MACHINE X COORDINATE +#123 = R_MACH_COOR[0,2] // MACHINE Y COORDINATE + +// PROBE PART IN X +M814 A#1 X[#120*#5] + +// MOVE BACK TO ORIGINAL XY LOCATION +#126 = [#102-R_MACH_COOR[0,1]] +#127 = [#123-R_MACH_COOR[0,2]] +G31 G91 P2 X#126 F#111 // PROTECTED MOVE +G31 G91 P2 Y#127 F#111 // PROTECTED MOVE + +// PROBE PART IN Y +M815 A#1 Y[#101*#5] + +// MOVE BACK TO ORIGINAL XY LOCATION +#126 = [#102-R_MACH_COOR[0,1]] +#127 = [#123-R_MACH_COOR[0,2]] +G31 G91 P2 Y#127 F#111 // PROTECTED MOVE +G31 G91 P2 X#126 F#111 // PROTECTED MOVE + +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +END_IF + +G90 +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M839 b/Macros for Controller/maker_macros/MAKER_MACRO_M839 new file mode 100644 index 0000000..e4542dd --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M839 @@ -0,0 +1,99 @@ +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +// PROBEOUTSIDECORNER +// Probe ONE OF 4 OUTSIDE CORNERS + +// Argument A -> #1 is the work coordinate system to store offsets in. The format for extended G54 offsets would be a period followed by the offset -- G54.5 +// Argument C -> #3 defines which corner +// 1 2 +// 3 4 +// Argument D -> #4 is the desired probing distance from the corner +// Argument E -> #5 engage distance to probe part + +// Simplified WCS extended number math, added probe error checking, added probe distance argument +// Modified 31/03/2025: Robot Oblivion + +// load probe config +M800 + +#128 = @96 // ORIENT SPINDLE ON PROVIDED BY PROBECONFIG MACRO +IF[#128 == 1] + M19 // ORIENT SPINDLE +END_IF + +// important local variables +#100 = @100 // TOOL NUMBER PROVIDED BY PROBECONFIG MACRO +#110 = @103 // FEED SPEED PROVIDED BY PROBECONFIG MACRO +#111 = @104 // FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#112 = @105 // SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#105 = @131 // TOOL RADIUS PROVIDED BY PROBECONFIG MACRO +#108 = @107*[#3/ABS[#3]] // PROBE BACKOFF DISTANCE PROVIDED BY PROBECONFIG MACRO * the sign// +1 or -1 of probe distance + +// #120 is X APPROACH DIRECTION +// #101 is Y APPROACH DIRECTION +IF[#3==1] + #120 = 1 + #101 = -1 +ELSEIF[#3==2] + #120 = -1 + #101 = -1 +ELSEIF[#3==3] + #120 = 1 + #101 = 1 +ELSEIF[#3==4] + #120 = -1 + #101 = 1 +END_IF + +// RECORD INITIAL POSITION SO WE CAN TOGGLE BACK TO IT +#102 = R_MACH_COOR[0,1] // MACHINE X COORDINATE +#123 = R_MACH_COOR[0,2] // MACHINE Y COORDINATE + + +// MOVE TO THE X PROBE LOCATION +G31 G91 P2 Y[#101*#4] F#111 // PROTECTED MOVE + +// Error Checking +IF[R_SKIP[0,1] == 1] + ALARM["ERROR: PREMATURE PROBE COLLISION"] + GOTO1 // go to line with N1 and quit +END_IF + +// PROBE PART IN X +M814 A#1 X[#120*#5] + +// MOVE BACK TO ORIGINAL XY LOCATION +#126 = [#102-R_MACH_COOR[0,1]] +#127 = [#123-R_MACH_COOR[0,2]] +G31 G91 P2 X#126 F#111 // PROTECTED MOVE +G31 G91 P2 Y#127 F#111 // PROTECTED MOVE + + +// MOVE TO THE Y PROBE LOCATION +G31 G91 P2 X[#120*#4] F#111 // PROTECTED MOVE + + +// Error Checking +IF[R_SKIP[0,1] == 1] + ALARM["ERROR: PREMATURE PROBE COLLISION"] + GOTO1 // go to line with N1 and quit +END_IF + +// PROBE PART IN Y +M815 A#1 Y[#101*#5] + +// MOVE BACK TO ORIGINAL XY LOCATION +#126 = [#102-R_MACH_COOR[0,1]] +#127 = [#123-R_MACH_COOR[0,2]] +G31 G91 P2 Y#127 F#111 // PROTECTED MOVE +G31 G91 P2 X#126 F#111 // PROTECTED MOVE + +N1 + +IF[#128 == 1] + M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY +END_IF + +G90 +G00 // return to rapid speed +M99 \ No newline at end of file diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M840 b/Macros for Controller/maker_macros/MAKER_MACRO_M840 new file mode 100644 index 0000000..bc2366a --- /dev/null +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M840 @@ -0,0 +1,160 @@ +// Copyright 2025 Toolpath Labs Inc., Justin Gray, Josh Smith, and Robot Oblivion + +//FINDCOR +// Process is based on a rectangular artifact +// mounted to the 4th axis +// STEPS +// 1) Position gauge surface of the artifact aligned vertically +// 2) Probe -Y at a given (X,Z) near the top of the artifact +// 3) Rotate the artifact 180 degrees +// 4) Reposition and probe at + Y at the same Z height as (2) +// 5) Y-COR is computed as the avg. of two positions. Diameter is also computed as the delta +// 6) Rotate the artifact -90 degrees (gauging surface is now level with table) +// 7) Reposition to Y=COR, then probe Z. +// 8) With diameter + Z probe point compute the Z-COR + +// Argument A -> #1 is the WCS to store the COR into +// Argument S -> #19 tuns on saving of the starting probe location +// Argument W -> #23 is the approximate width of the reference artifact + +// Initial Coding: Justin Gray, Josh Smith + +IF[#23==#0] // null check + #23 = 1.0 // assume the narrow side of a 123 block +END_IF + +// load probe config +M800 A#1 +#114 = @121 // processed extended WCS number provided by ProbeConfig macro + +M19 // ORIENT SPINDLE + +#105 = @133 //TOOL LENGTH PROVIDED BY PROBECONFIG MACRO +#108 = @107 //PROBE BACK OFF DISTANCE +#109 = @114 //WCS TO STORE THE INITIAL PROBING LOCATION INTO +#110 = @103 //FEED SPEED PROVIDED BY PROBECONFIG MACRO +#111 = @104 //FAST PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#112 = @105 //SLOW PROBE SPEED PROVIDED BY PROBECONFIG MACRO +#101 = @130 //TOOL DIAMETER PROVIDED BY PROBECONFIG MACRO + +// CONVINIENT TO WORK IN PROBE 0 WCS + +G54 P#109 + +// store current X,Y,Z +// ASSUME THE PROBE IS AT -Y +// AT THE Z HEIGHT YOU WANT TO PROBE AT +#117 = R_MACH_COOR[0,1] // MACHINE X COORDINATE +#118 = R_MACH_COOR[0,2] // MACHINE Y COORDINATE +#119 = R_MACH_COOR[0,3] // MACHINE Z COORDINATE + +//PULL A0 FROM G59 +#120 = R_G53G59_COOR[0,59,4] +W_G54EXP_COOR[0,#109,4,#120] + +IF[#19 != #0] // null check + // SAVE THE INITIAL POSITION OF THE PROBE AS THE WCS 0 + + W_G54EXP_COOR[0,#109,1,#117] + W_G54EXP_COOR[0,#109,2,#118] + W_G54EXP_COOR[0,#109,3,#119] + + + // XYZ ABS IS NOW 0 + + // GET THE PROBE CLEAR + M810 Z2.0 + + // ROTATE THE ARTIFACT + // THIS ASSUMES YOUR CURRENT WCS HAS A0 SET + M10 + G0 A0. + M11 + + // PUT THE PROBE BACK IN PLACE + M810 Z0 + +ELSE + // RETRACT TO SAFE Z +G53 G90 G00 Z0 + // POSITION THE ROTATRY AXIS AT A0 + M10 + G0 A0. + M11 + + // MOVE PROBE TO 0 + M810 X0 Y0 + M810 Z0 +END_IF + + +// PROBE PART IN +Y DIRECTION +M815 B0.5 +// probe value stored in @996, so we make a copy +#120 = @996 + +// GET THE PROBE CLEAR +M810 Y-0.25 +M810 Z2.0 + +// ROTATE THE ARTIFACT +M10 +G0 A180. +M11 + +// REPOSITION THE PROBE +M810 Y[#23+0.5+#108] +M810 Z0 + +// PROBE PART IN -Y DIRECTION +M815 B-0.5 +#101 = @996 + +// GET THE PROBE CLEAR +M810 Z[2+4*#131] + +// COMPUTE THE DIAMETER +#130 = [#101 - #120] +// COMPUTE THE RADIUS +#131 = [#130 / 2.] +// Compute THE Y-COR IN MACHINE COORDS +#132 = [#120 + #131] + +// NEED TO CONVERT MACHINE COORDINATES TO ABS +#133 = R_G54EXP_COOR[0,#109,2] // Y WCS OFFSET +// REPOSITION THE PROBE OVER THE Y-COR +M810 Y[#132-#133] + +// ROTATE THE ARTIFACT +M10 +G0 A90. +M11 + +// PROBE IN Z +M816 B-[10*#131] +#102 = @996 + +// COMPUTE THE Z-COR +#133 = [#102 - #131] + + +// WRITE IT TO GLOBAL VARIABLES JUST IN CASE +@901 = #132 // Y +@902 = #133 // Z + + +//STORE COR OFFSET FOR WCS ZERO +IF [#1 == #0] + //DO NOT SET ANYTHING INTO WCS +ELSEIF [#114 < 1] + W_G53G59_COOR[0,#1,2,#132] + W_G53G59_COOR[0,#1,3,#133] +ELSE + W_G54EXP_COOR[0,#114,2,#132] + W_G54EXP_COOR[0,#114,3,#133] +END_IF + +M20 // UNLOCK SPINDLE ORIENTATION FOR SAFETY + +G53 G90 G00 Z0 +M99 \ No newline at end of file diff --git a/README.md b/README.md index c5f2fd9..32a4ffd 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ This macro set will work for both wired and (some wireless probes) and now suppo ## Probe Configuration Macro ### Imperial vs Metric units -The various probing parameters must be set in your desired units sections in the `PROBECONFIG` file. +The various probing parameters must be set in your desired units sections in the configuration file. No other changes are needed to configure the units. The default parameters are provide as a suggested starting value. @@ -28,45 +28,49 @@ Please set your fusion 360 probing feed rate to the same value that you use in t If you decide to change feed rates, you should always run calibration again. ### Configuration setup -Every probing routine calls the configuration macro to initialize global variables. -This is contained in `PROBECONFIG` -It allows all probing parameters to be specified in one place. +Every probing routine calls the configuration macro to initialize global variables to allow all probing parameters to be specified in one place. -Using the editor of your choice, open `PROBECONFIG` and update the following parameters: +Using the editor of your choice, open `PROBECONFIG` or `M800` and update the following parameters: - **`@100`** – Set this to the tool number you want to use for your probe. Common choices include Tool 12 or Tool 99. -- **`@111`** – Extended work offset number used to store the Z calibration artifact WCS, aiding in faster recalibration. +- **`@92`** – Calibrated length of your master gauge tool. +- **`@93`** – Calibrated diameter of your ring gauge. +- **`@94`** – Calibrated X size of your gauge block. +- **`@95`** – Calibrated Y size of your gauge block. + > **These dimensions are critical for calibrating your tool setter and ensuring accurate tool length measurements. Default values are provided, but you should input the exact values from your gauge tool's certificate.** + +- **`@96`** – Disables extra spindle orientation calls for probes that spin on/off. +- **`@97`** – Demotes out-of-tolerance alarms to warning messages, allowing machining to continue without requiring a controller reset 0 or 1 to keep alarms on. + +- **`#111`** – Highest offset that can be updated, defining a protected WCS range. - **`@112`** – Extended work offset number used to store the tool setter's XY center location. -- **`@113`** – Extended work offset number used to store the 4th-axis corner probing start point. -- **`@137`** – Highest offset that can be updated, defining a protected WCS range. - > **Note:** Any WCS number from 01-09 should be entered with a leading zero. +- **`@113`** – Extended work offset number used to store the Z calibration artifact WCS, aiding in faster recalibration. +- **`@114`** – Extended work offset number used to store the 4th-axis corner probing start point. +- **`@115`** – Extended work offset number used to store the manual tool change location. -- **`@128`** – Disables extra spindle orientation calls for probes that spin on/off. -- **`@109`** – Calibrated length of your master gauge tool. -- **`@129`** – Calibrated diameter of your ring gauge. - > **These dimensions are critical for calibrating your tool setter and ensuring accurate tool length measurements. Default values are provided, but you should input the exact values from your gauge tool's certificate.** + > **Note:** Any WCS number from 01-09 should be entered with a leading zero. -- **`@103`, `@104`, `@105`, `@116`, `@117`** – Probing and tool-setting speeds are separated into metric and imperial sections, with safe default values that can be adjusted if needed. +- **`@103`, `@104`, `@105`, `@109`, `@110`** – Probing and tool-setting speeds are separated into metric and imperial sections, with safe default values that can be adjusted if needed. - **`@106`** – Probe clearance distance. This is the extra distance the probe moves beyond what the macro expects as the edge of the surface. > *Example:* If probing a circular boss with a specified diameter of 1", the probe will move `[0.5" + @106]` away from the initial point. -- **`@108`** – Probe backoff distance. Probing routines use a double-touch method: +- **`@107`** – Probe backoff distance. Probing routines use a double-touch method: 1. The first touch is fast. 2. The second touch is slow (for higher accuracy). - After the first touch, the probe will back off by `@108` (in inches or mm, depending on your control setup). + After the first touch, the probe will back off by `@107` (in inches or mm, depending on your control setup). > This value must be large enough to allow the probe to fully disengage from the surface, plus some clearance, but no larger than necessary. -- **`@110`** – Default value used when a tolerance argument is required but not provided. -- **`@11`** – Rounding multiplier for many probing messages. Adjust as needed to control the precision of user messages. +- **`@108`** – Default value used when a tolerance argument is required but not provided. +- **`@91`** – Rounding multiplier for many probing messages. Adjust as needed to control the precision of user messages. -Once you have saved your changes to `PROBECONFIG` copy all files within the **`Macros for controller`** folder to the LNC main NC files directory. +Once you have saved your changes to `PROBECONFIG` or `M800` copy all files within the **`Macros for controller`** folder to the LNC main NC files directory or copy all files within the **`maker_macros`** folder to the LNC Maker_Macro folder if you would prefer to run Mcode based macros ## Pre-calibration tasks ### Backup your controller and prep for running the calibration -1. Backup your tool table, offset table and @10, @11, @100-@117, @127-@133, @980-@987 and @1508 variables in case of wanting to revert +1. Backup your tool table, offset table and `@10`, `@91-@98`, `@100-@110`, `@112-@115`,`@130-@134`, `@980-@987` and `@5109` variables in case of wanting to revert 2. Clear as many items as possible from the table to prevent collisions with stock, jigs, fixtures, or vices. 3. Ensure the table zero point or area to place your calibration object is empty, lightly stoned, and free of coolant. 4. Have your master tool, probe, and ring gauge/gauge block ready. @@ -78,74 +82,75 @@ To make your probe concentric you must place a dial indicator on the ruby tip an Adjust your probe until the dial indicator doesn't move or is within a few tenths. ![probeIndicate](images/probeIndicate.jpg) - _Figure 2. Indicating Probe_ -## toolsetter Calibration +## Toolsetter Calibration -### Basic toolsetter Setup +### Basic toolsetter setup -Before you do any toolsetting, you need to tell the control where the toolsetter is. +Before you do any toolsetting, you need to tell the control where the toolsetter is. You should manually move your spindle to be located over the center of your toolsetter. You can do this by eye, using the MPG to drive the gauge tool till it looks centered. -If you want a more precise location, -you can use a dial indicator or coaxial indicator and sweep it around until you are prefectly centered. +If you want a more precise location, you can use a dial indicator or coaxial indicator and sweep it around until you are prefectly centered. -Once you find your location, you will use the `TEACH IN` function in the offsets page to save that location as -The XY origin of extended work offset set in `@111 PROBECONFIG`. +Once you find your location, you will use the `TEACH IN` function in the offsets page to save that location as the XY origin of extended work offset set in `@113 PROBECONFIG/M800`. -The toolsetting location will be X0 Y0 in G54 P`@111`. +The toolsetting location will be X0 Y0 in G54 P`@113`. ---- -**Macro Syntax** +## Macro Syntax -Macros are called with G65 as opposed to M codes to speed up execution. G65 is followed by the macro name and whatever arguments need passed into the macro. The example below shows how to probe the side of a part along the X axis. The A argument is the work offset and the B argument is the probing distance. Each argument starts with a letter followed by a value. For example, a macro requiring three arguments will have A#, B# and C# after the macro name. Simply copy the macro examples into your MDI and adjust the arguments according to your needs. A table mapping the macro arguments to local variables is also provided below. Extended G54 work offsets are supported with the use of a decimal point. For example, G54P5 can be entered into the A argument as G54.5. +Depending on which file pack is installed, macros are called using either `G65 "FILENAME"` or M-code numbers (if you've installed the Maker_macro version). -| G Code | "Macro Name" | Macro Argument | Macro Argument | -| --- | --- | --- | --- | -| G65 | "PROBEX" | A | B | +To pass data into a macro arguments are used and starts with a letter followed by a value. For example, a macro requiring three arguments will have `A#`, `B#` and `C#` after the macro name. Simply copy the macro examples into your MDI and adjust the arguments according to your needs. +> **Note:** Both G65 and M-code macros accept the same arguments -_Table 1: Macro Syntax and Example_ + The example below demonstrates how to probe the side of a part along the X axis: -Example MDI Command: G65 "PROBEX" A56. B2. +Example MDI Command: `G65 "PROBEX" A56 X2.` +Example MDI Command: `M814 A54.09 X2.` -Example MDI Command: G65 "PROBEX" A54.09 B2. +`A` argument is the work offset +`X` argument is the probing distance. -![lnc_macro_variables](images/lnc_macro_variables.png) + A table mapping each macro arguments to local variables is provided with the one below for this example: + +| G Code | "Macro Name" | Macro Argument | Macro Argument | +| --- | --- | --- | --- | +| G65 | "PROBEX" | A | X | -_Figure 1. Macro Argument to local variable mapping_ +_Table 1: Macro Syntax_ ---- +![lnc_macro_variables](images/lnc_macro_variables.png) +_Figure 1. Macro Argument to local variable mapping_ -### CALIBRATETOOLSET +## Toolsetter Calibration -This macro will use a master gauge tool to find the trigger height of your tool setter. -Once you have set the G54P100 WCS to locate the tool setter, -you can run this macro with the gauge tool in the spindle to calibrate the tool setter. +Run `CALIBRATETOOLSET` or `M801` to use a master gauge tool to find the trigger height of your tool setter. -The toolsetter trigger height will be saved to the tool height offset of tool 199. +You can run this macro with the gauge tool in the spindle to calibrate the tool setter. The toolsetter trigger height will be saved to the tool height offset of tool 199. | G Code | "Macro Name" | | --- | --- | | G65 | "CALIBRATETOOLSET" | -Example MDI Command: G65 "CALIBRATETOOLSET" +Example MDI Command: G65 "CALIBRATETOOLSET" +Example MDI Command: M801 -## Probe Calibration +--- +# Probe Calibration -### Probe Length Calibration +### Full Probe Z Height Calibration -Length calibration is done with the `CALIBRATEPROBEZ` macro. +Length calibration is done with the `CALIBRATEPROBEZ` or `M802` macro. -To use this macro, you need to first toolchange to your probe tool (i.e. the tool number you set as your probe in the `PROBECONFIG` file.). +To use this macro, you need to first toolchange to your probe tool (i.e. the tool number you set as your probe in the `PROBECONFIG` or `M800`. The macro assumes you are on that tool number, even if you are using your gauge tool. -The first time you use this macro, you will start by setting the calibration height of your reference artifact. -The artifact can be nearly anything for this, as it's precise dimensions don't matter. -Its common to choose either a 123 block or a gauge ring. -The important thing is that this reference artifact doesn't change (or you redo the initial calibration if it does) from use to use. +The first time you use this macro, you will start by setting the calibration height of your reference artifact. The artifact can be nearly anything for this, as it's precise dimensions don't matter. Its common to choose either a 123 block or a gauge ring. +> [!NOTE] +>The important thing is that this reference artifact doesn't change (or you redo the initial calibration if it does) from use to use. | GCode | "Macro Name" | Macro Argument | | --- | --- | --- | @@ -154,97 +159,98 @@ The important thing is that this reference artifact doesn't change (or you redo *This macro has an optional argument `A`. By default you can call the macro without any arguments, which does a quick calibration using an stored location/height for the artifact. -The first time you call it make sure to include the `A` argument and run the full calibration procedure. +Example MDI Command: G65 "CALIBRATEPROBEZ" A1 +Example MDI Command: M803 A1 -### Full Probe Z Height Calibration +> [!WARNING] +>The first time you call it make sure to include the `A` argument and run the full calibration procedure. + +Put your master tool into the spindle and lower it untill it is just below the top edge of your reference artifact. -Example MDI Command: G65 "CALIBRATEPROBEZ" A1 +Slowly raise the spindle till the artifact can just barely pass beneath the master tool (you should be in X1 mode on the MPG for this). -![calibrateProbeZ](images/calibrateprobez.png) -Put your master tool into the spindle and lower it untill it is just below the top edge of your reference artifact. -Slowly raise the spindle till the artifact can just barely pass beneath the master tool (you should be in X1 mode on the MPG for this). -Make careful note of where you do this calibration, so you'll be able to place the calibration artifact in the same place later when you want to recalibrate your probe offset --- for example if you change the probe tip. +![masterToolCalibration](images/master_tool_z_calibration.jpg) +> [!CAUTION] +>DO NOT lower the spindle onto the reference artifact. You must start with the tool below the artifact and raise it till you can just barely pass the artifact underneath it. Then switch from MPG mode to MDI mode and run the macro. This means the macro starts with the gauge tool in the spindle and it just resting on the reference artifact. -Note: DO NOT lower the spindle onto the reference artifact. You must start with the tool below the artifact and raise it till you can just barely pass the artifact underneath it. +The macro will record the reference height of that artifact in the global variable @5109 and the XY position into the extended work offset you configured in the `PROBECONFIG` or `M800` macro). -![masterToolCalibration](images/master_tool_z_calibration.jpg) +Then it will raise the spindle and ask you to do a manual tool change to the probe (i.e. remove the master gauge tool). -The macro will record the reference height of that artifact in the global variable @5109. -It will also record the XY position into the extended work offset you configured in the `PROBECONFIG` macro (default is G54P99). -Then it will raise the spindle and ask you to do a manual tool change to the probe (i.e. remove the master gauge tool). -Finally it will do a protected move down toward the artifact to calibrate the probe z offset and store it in the tool length of your perscribed probe tool number. +Finally it will do a protected move down toward the artifact to calibrate the probe z offset and store it in the tool length of your perscribed probe tool number. -### Quick Probe Z Height Calibration - -Example MDI Command: G65 "CALIBRATEPROBEZ" +## Quick Probe Z Height Calibration Once you have done the full calibration one time, you can use a quick version of the macro to recalibrate the probe offset without the need to use the master tool. But you must re-install your calibration artifact onto your table before calling this macro. -This will move the table to the origin of the saved WCS (default is G54P99) and then do a protected move to calibrate the probe offset. +This will move the table to the origin configured in the `PROBECONFIG` or `M800` macro and then do a protected move to calibrate the probe offset. +Example MDI Command: G65 "CALIBRATEPROBEZ" +Example MDI Command: M803 -### Probe Tip Diameter Calibration +## Probe Tip Diameter Calibration You can use one of the two provided calibration methods: - * `CALIBRATEPROBEBLOCK` - * `CALIBRATEPROBERING` +> 1. CALIBRATEPROBERING or M803 +> 2. CALIBRATEPROBEBLOCK or M804 -#### CALIBRATEPROBEBLOCK +### CALIBRATEPROBERING ( M803 ) -This macro uses a gauge block to calibrate the diameter of a probes ruby tip. -It's important that the probe is concentric before beginning. -Any good quality reference block artifact would be used, such as an actual gauge block or a high quality 123 block. -If you are not using a calibrated reference artifact, you should use a well calibrated micrometer to measure your 123 block to get its true dimensions. -123 blocks, even high quality ones, are commonly sold a few ten thousandths of an inch oversized to allow for lapping -and you want to put the true dimension into the macro arguments. -`A` is the gauge block's true X dimension -`B` is the gauge block's true Y dimension -`C` is the amount of Z drop you want between your initial position and the measurement height. It needs to be a negative value. +This macro uses a ring gauge to calibrate the diameter of the probe's ruby tip. The routine will determine the diameter of the probe tip, and the calculated radius will be visible in the tool table. +* Before starting, ensure that the probe is concentric and positioned inside the ring gauge, roughly centered. -![CALIBRATEPROBEBLOCK](images/calibrateprobeblock.png) +![CALIBRATEPROBERING](images/probeRingGuage.PNG) +_Figure 3a. Probe Diameter Calibration (ring gauge)_ -| GCode | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | -| --- | --- | --- | --- | --- | -| G65 | "CALIBRATEPROBEBLOCK" | A | B | C | -_Table 2. Calibrate Probe X Syntax_ +| G Code | "Macro Name" | Macro Argument | +| --- | --- | --- | +| G65 | "CALIBRATEPROBERING" | A* | -Example MDI Command: G65 "CALIBRATEPROBEBLOCK" A1.0002 B2.0001 C-0.5 +_Table 4. Calibrate Probe Radius Syntax_ +*This macro has an optional argument `A`. +By default you can call the macro without any arguments, which pulls the diameter stored in `PROBECONFIG/M800 @93` or have the option to temporarily override this using the optional D argument. -#### CALIBRATEPROBERING +Example MDI Command: G65 "CALIBRATEPROBERING" +Example MDI Command: M803 D19.998 -This macro uses a ring gauge to calibrate the diameter of a probes ruby tip. -It's important that the probe is concentric before beginning. -`A`is the inside diameter of the ring gauge. -The probe must be inside of the gauge and roughly centered. -The routine will set the diameter of your probe tip and the radius can been seen in the tool table. +--- +#### CALIBRATEPROBEBLOCK ( M804 ) -![CALIBRATEPROBERING](images/probeRingGuage.PNG) +This macro uses a gauge block to calibrate the diameter of a probes ruby tip. -_Figure 3. Probe Diameter Calibration_ +It's important that the probe is concentric before beginning. Any good quality reference block artifact would be used, such as an actual gauge block or a high quality 123 block. +If you are not using a calibrated reference artifact, you should use a well calibrated micrometer to measure your 123 block to get its true dimensions. +* 123 blocks, even high quality ones, are commonly sold a few ten thousandths of an inch oversized to allow for lapping +and you want to put the true dimension into the macro arguments. +`X` is the gauge block's true X dimension +`Y` is the gauge block's true Y dimension +`Z` is the amount of Z drop you want between your initial position and the measurement height. It needs to be a negative value. -| G Code | "Macro Name" | Macro Argument | -| --- | --- | --- | -| G65 | "CALIBRATEPROBERING" | A* | +![CALIBRATEPROBEBLOCK](images/calibrateprobeblock.png) +_Figure 3b. Probe Diameter Calibration (gauge block)_ -_Table 4. Calibrate Probe Radius Syntax_ +| GCode | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | +| --- | --- | --- | --- | --- | +| G65 | "CALIBRATEPROBEBLOCK" | X | Y | Z | -*This macro has an optional argument `A`. -By default you can call the macro without any arguments, which pulls the diameter stored in `PROBECONFIG @129` or have the option to over ride +_Table 2. Calibrate Probe X Syntax_ -Example MDI Command: G65 "CALIBRATEPROBERING" +Example MDI Command: G65 "CALIBRATEPROBEBLOCK" X1.0002 Y2.0001 Z-0.5 +Example MDI Command: M804 X75.001 Y50.001 Z-10 -### FINDCOR +--- +### FINDCOR ( M840 ) This macro uses probing with a 4th axis and a reference artifact to compute the center of rotation (COR). It has two run modes: one where you set the probing location, and once where the location is already known and you're just recalibrating the COR. @@ -253,324 +259,326 @@ It has two run modes: one where you set the probing location, and once where the | --- | --- | --- | --- | --- | | G65 | "FINDCOR" | A | W | S | -The `A` argument lists the WCS to save the COR into. -The `W` argument is optional, but sets the width of the reference artifact. The default value is 1.0. -The `S` argument is optional, and determines which mode the macro runs in. -If not provided, then the macro uses the saved probing location to re-find the COR regardless of where the A axis or probe is located when starting the macro. +The `A` argument lists the WCS to save the COR into. +The `W` argument is optional, but sets the width of the reference artifact. The default value is 1.0. +The `S` argument is optional, and determines which mode the macro runs in. If not provided, then the macro uses the saved probing location to re-find the COR regardless of where the A axis or probe is located when starting the macro. If provided, then the probe's initial location is saved before running the macro. -Example MDI Command to run in saving mode: G65 "FINDCOR" A58. S1.0 -Example MDI Command to run in re-find mode with a larger artifact: G65 "FINDCOR" A58. W2.0 +Example MDI Command to run in saving mode: G65 "FINDCOR" A58. S1.0 +Example MDI Command to run in re-find mode with a larger artifact: G65 "FINDCOR" A58. W2.0 -## Probing Routines +--- +# Probing Routines -### PROBEX +### PROBEX ( M814 ) -The Probe X macro probes the side of a part in the X direction. -`A` is the selected work coordinate(54-59 or 54.01-54.99). -`B` is the distance to probe in X. -`B` can be a positive or negative value depending on which side of the stock you would like to probe. -If `B` is too small, the macro will report an error at the end of the routine. +The Probe X macro probes the side of a part in the X direction. -![probeX](images/probeX.png) +`A` is the selected work coordinate ( 54-59 or 54.01-54.99 ). +`X` is the distance to probe : +* `X` Can be a positive or negative value depending on which side of the stock you would like to probe. +* If `X` is too small, the macro will report an error at the end of the routine. +![probeX](images/probeX.png) _Figure 4. Probe X Routine_ | G Code | "Macro Name" | Macro Argument | Macro Argument | | --- | --- | --- | --- | -| G65 | "PROBEX" | A | B | +| G65 | "PROBEX" | A | X | _Table 5. Probe X Syntax_ -Example MDI Command To Probe Right Side: G65 "PROBEX" A54.0 B-1 +Example MDI Command To Probe Right Side: G65 "PROBEX" A54.0 X-1 +Example MDI Command To Probe Left Side: M814 A54.0 X1 -Example MDI Command To Probe Left Side: G65 "PROBEX" A54.0 B1 +--- -### PROBEY +### PROBEY ( M815 ) -The Probe Y macro probes the side of a part in the Y direction. -`A` is the selected work coordinate(54-59 or 54.01-54.99). -`B` is the distance to probe in Y. -`B` can be a positive or negative value depending on which side of the stock you would like to probe. -If `B` is too small, the macro will report an error at the end of the routine. +The Probe Y macro probes the side of a part in the Y direction. -![probeY](images/probeY.png) +`A` is the selected work coordinate ( 54-59 or 54.01-54.99 ). +`Y` is the distance to probe: +* `Y` Can be a positive or negative value depending on which side of the stock you would like to probe. +* If `Y` is too small, the macro will report an error at the end of the routine. +![probeY](images/probeY.png) _Figure 5. Probe Y Routine_ | G Code | "Macro Name" | Macro Argument | Macro Argument | | --- | --- | --- | --- | -| G65 | "PROBEY" | A | B | +| G65 | "PROBEY" | A | Y | _Table 6. Probe Y Syntax_ -Example MDI Command To Probe the Front : G65 "PROBEY" A54.02 B1. - -Example MDI Command To Probe the Back : G65 "PROBEY" A54.02 B-1. +Example MDI Command To Probe the Front : G65 "PROBEY" A54.02 Y1. +Example MDI Command To Probe the Back : M815 A54.02 Y-1. +--- +### PROBEZ ( M816 ) -### PROBEZ - -The Probe Z macro probes the top surface of a part in the negative Z direction. -`A` is the selected work coordinate(54-59 or 54.01-54.99). -`B` is the distance to probe in Z and should be a negative value. -`B` is too small or a positive value, the macro will report an error at the end of the routine. +The Probe Z macro probes the top surface of a part in the negative Z direction. -![probeZ](images/probeZ.png) +`A` is the selected work coordinate ( 54-59 or 54.01-54.99 ). +`Z` is the distance to probe in Z +* `Z` Can be a positive or negative value depending on which side of the stock you would like to probe. +* If `Z` is too small, the macro will report an error at the end of the routine. +![probeZ](images/probeZ.png) _Figure 6. Probe Z Routine_ | G Code | "Macro Name" | Macro Argument | Macro Argument | | --- | --- | --- | --- | -| G65 | "PROBEZ" | A | B | +| G65 | "PROBEZ" | A | Z | _Table 7. Probe Z Syntax_ -Example MDI Command: G65 "PROBEZ" A54. B-0.5 +Example MDI Command: G65 "PROBEZ" A54. Z-0.5 +Example MDI Command: M816 A54. Z-0.5 +--- +### PROBEXWEB ( M824 ) -### PROBEXWEB - -The Probe X Web macro probes two sides of the stock in the X direction and calculates the center. -`A` is the selected work coordinate(54-59 or 54.01-54.99). -`B` is the length of the stock. -`C` is the distance the probe should move in Z below the edges of the stock. -`Q` enables inspection reporting which pops up a calculated length after the routine finishes. -The Probe should be roughly centered and above the stock before beginning. +The Probe X Web macro probes two sides of the stock in the X direction and calculates the center. -![probeXweb](images/probeXweb.png) +`A` is the selected work coordinate ( 54-59 or 54.01-54.99 ). +`X` is the length of the stock. +`Z` is the distance the probe should move in Z below the edges of the stock. +`Q` enables inspection reporting which pops up a calculated length after the routine finishes. +* The Probe should be roughly centered and above the stock before beginning. +![probeXweb](images/probeXweb.png) _Figure 7. Probe X Web Routine_ | GCode | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | ---| -| G65 | "PROBEXWEB" | A | B | C | Q | +| G65 | "PROBEXWEB" | A | X | Z | Q | _Table 8. Probe X Web Syntax_ -Example MDI Command Without Inspection Report: G65 "PROBEXWEB" A54.12 B3. C-.5 Q0. +Example MDI Command With Inspection Report: M824 A54.12 X3. Z-.5 Q1. +Example MDI Command : G65 "PROBEXWEB" A54.12 X3. Z-.5 Q0. -Example MDI Command With Inspection Report: G65 "PROBEXWEB" A54.12 B3. C-.5 Q1. - -### PROBEYWEB +--- +### PROBEYWEB ( M825 ) -The Probe Y Web macro probes two sides of the stock in the Y direction and calculates the center. -`A` is the selected work coordinate(54-59 or 54.01-54.99). -`B` is the width of the stock. -`C` is the distance the probe should move in Z below the edges of the stock. -`Q` enables inspection reporting which pops up a calculated width after the routine finishes. -The Probe should be roughly centered and above the stock before beginning. +The Probe Y Web macro probes two sides of the stock in the Y direction and calculates the center. -![probeYweb](images/probeYweb.png) +`A` is the selected work coordinate ( 54-59 or 54.01-54.99 ). +`Y` is the width of the stock. +`Z` is the distance the probe should move in Z below the edges of the stock. +`Q` enables inspection reporting which pops up a calculated width after the routine finishes. +* The Probe should be roughly centered and above the stock before beginning. +![probeYweb](images/probeYweb.png) _Figure 8. Probe Y Web Routine_ | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | --- | -| G65 | "PROBEYWEB" | A | B | C | Q | +| G65 | "PROBEYWEB" | A | Y | Z | Q | _Table 9. Probe Y Web Syntax_ -Example MDI Command Without Inspection Report: G65 "PROBEYWEB" A58. B2. C-.5 Q0. +Example MDI Command: G65 "PROBEYWEB" A58. Y2. Z-.5 Q0. +Example MDI Command With Inspection Report: M825 A58. Y2. Z-.5 Q1. -Example MDI Command With Inspection Report: G65 "PROBEYWEB" A58. B2. C-.5 Q1. +--- +### PROBEBORE ( M830 ) +The Probe Bore macro probes 4 points inside of a bore and calculates the center. -### PROBECIRCULARBOSS +`A` is the selected work coordinate ( 54-59 or 54.01-54.99 ). +`D` is the diameter of the bore. +`Q` enables inspection reporting which pops up a calculated diameter after the routine finishes. +* The Probe should be roughly centered and inside of the bore before beginning. -The Probe Circular Boss macro probes 4 points of a circular boss and calculates the center. -`A` is the selected work coordinate(54-59 or 54.01-54.99). -`B` is the diameter of the stock. -`C` is the distance the probe should move in Z below the edges of the stock. -`D` turns on a second -`Q` enables inspection reporting which pops up a calculated diameter after the routine finishes. The Probe should be roughly centered and above the stock before beginning. +![probeBore](images/probeBore.png) +_Figure 10. Probe Bore Routine_ -![probeCircularBoss](images/probeCircularBoss.png) +| G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | +| --- | --- | --- | --- | --- | +| G65 | "PROBEBORE" | A | D | Q | + +_Table 11. Probe Bore Syntax_ +Example MDI Command : G65 "PROBEBORE" A54.02 D1. Q0. +Example MDI Command With Inspection Reporting: M830 A54.02 D1. Q1. + +--- +### PROBECIRCULARBOSS ( M831 ) + +The Probe Circular Boss macro probes 4 points of a circular boss and calculates the center. + +`A` is the selected work coordinate ( 54-59 or 54.01-54.99 ). +`D` is the diameter of the stock. +`Z` is the distance the probe should move in Z below the edges of the stock. +`Q` enables inspection reporting which pops up a calculated diameter after the routine finishes. +* The Probe should be roughly centered and above the stock before beginning. + +![probeCircularBoss](images/probeCircularBoss.png) _Figure 9. Probe Circular Boss Routine_ | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | --- | -| G65 | "PROBECIRCULARBOSS" | A | B | C | Q | +| G65 | "PROBECIRCULARBOSS" | A | D | Z | Q | _Table 10. Probe Circular Boss Syntax_ -Example MDI Command Without Inspection Report: G65 "PROBECIRCULARBOSS" A54.01 B2. C-.5 Q0. - -Example MDI Command With Inspection Report: G65 "PROBECIRCULARBOSS" A54.01 B2. C-.5 Q1. - -### PROBEBORE - -The Probe Bore macro probes 4 points inside of a bore and calculates the center. -`A` is the selected work coordinate(54-59 or 54.01-54.99). -`B` is the diameter of the bore. -`Q` enables inspection reporting which pops up a calculated diameter after the routine finishes. -The Probe should be roughly centered and inside of the bore before beginning. +Example MDI Command: G65 "PROBECIRCULARBOSS" A54.01 D2. Z-.5 Q0. +Example MDI Command With Inspection Report: M831 A54.01 D2. Z-.5 Q1. -![probeBore](images/probeBore.png) +--- +### PROBEPOCKET ( M820 ) -_Figure 10. Probe Bore Routine_ +The Probe Pocket macro probes all internal sides of a pocket and calculates the center. -| G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | -| --- | --- | --- | --- | --- | -| G65 | "PROBEBORE" | A | B | Q | +`A` is the selected work coordinate ( 54-59 or 54.01-54.99 ). +`X` is the length of the pocket in X +`Y` is the width of the pocket in Y. +`Q` enables inspection reporting which pops up a calculated length and width after the routine finishes. +* The Probe should be roughly centered and inside of the pocket before beginning. -_Table 11. Probe Bore Syntax_ +![probeRectangularPocket](images/probeRectangularPocket.png) +_Figure 12. Probe Pocket Routine_ -Example MDI Command Without Inspection Reporting: G65 "PROBEBORE" A54.02 B1. Q0. +| G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | Macro Argument | +| --- | --- | --- | --- | --- | --- | +| G65 | "PROBEPOCKET" | A | X | Y | Q | -Example MDI Command With Inspection Reporting: G65 "PROBEBORE" A54.02 B1. Q1. +_Table 13. Probe Rectangular Pocket Syntax_ - -### PROBERECTANGULARBOSS +Example MDI Command: G65 "PROBERECTANGULARPOCKET" A54.05 X2. Y3. Q0. +Example MDI Command Without Inspection Reporting: M820 A54.05 X2. Y3. Q1. -The Probe Rectangular Boss macro probes all sides of the stock and calculates the center. -`A` is the selected work coordinate(54-59 or 54.01-54.99). -`B` is the length of the boss in X -`C` is the width of the boss in Y. -`D` is the distance the probe should move in Z below the edges of the bodd and should be a negative value. -`Q` enables inspection reporting which pops up a calculated length and width after the routine finishes. +--- +### PROBERECTANGULARBOSS ( M821 ) -The Probe should be roughly centered and above the stock before beginning. +The Probe Rectangular Boss macro probes all sides of the stock and calculates the center. -![probeRectangularBoss](images/probeRectangularBoss.png) +`A` is the selected work coordinate ( 54-59 or 54.01-54.99 ). +`X` is the length of the boss in X +`Y` is the width of the boss in Y. +`Z` is the distance the probe should move in Z below the edges of the body and should be a negative value. +`Q` enables inspection reporting which pops up a calculated length and width after the routine finishes. +* The Probe should be roughly centered and above the stock before beginning. +![probeRectangularBoss](images/probeRectangularBoss.png) _Figure 11. Probe Rectangular Boss Routine_ | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | --- | --- | -| G65 | "PROBERECTANGULARBOSS" | A | B | C | D | Q | +| G65 | "PROBERECTANGULARBOSS" | A | X | Y | Z | Q | _Table 12. Probe Rectangular Boss Syntax_ -Example MDI Command Without Inspect Reporting: G65 "PROBERECTANGULARBOSS" A54. B3. C2. D-.5 Q0. - -Example MDI Command Without Inspect Reporting: G65 "PROBERECTANGULARBOSS" A54. B3. C2. D-.5 Q1. - - -### PROBEPOCKET +Example MDI Command: G65 "PROBERECTANGULARBOSS" A54. X3. Y2. Z-.5 Q0. +Example MDI Command Without Inspect Reporting: M821 A54. X3. Y2. Z-.5 Q1. -The Probe Pocket macro probes all internal sides of a pocket and calculates the center. -`A` is the selected work coordinate(54-59 or 54.01-54.99). -`B` is the length of the pocket in X -`C` is the width of the pocket in Y. -`Q` enables inspection reporting which pops up a calculated length and width after the routine finishes. - -The Probe should be roughly centered and inside of the pocket before beginning. +--- +### PROBEXSLOT ( M834 ) -![probeRectangularPocket](images/probeRectangularPocket.png) +The Probe Slot X macro probes the internal sides of a pocket in the X direction and calculates the center. -_Figure 12. Probe Pocket Routine_ +`A` is the selected work coordinate ( 54-59 or 54.01-54.99 ). +`X` is the length of the pocket in X. +`Q` enables inspection reporting which pops up a calculated length after the routine finishes. +* The Probe should be roughly centered and inside of the slot before beginning. -| G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | Macro Argument | -| --- | --- | --- | --- | --- | --- | -| G65 | "PROBEPOCKET" | A | B | C | Q | +![probeSlot](images/probeSlot.png) +_Figure 13. Probe Slot Routine_ -_Table 13. Probe Rectangular Pocket Syntax_ +| G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | +| --- | --- | --- | --- | --- | +| G65 | "PROBESLOTX" | A | X | Q | -Example MDI Command Without Inspection Reporting: G65 "PROBERECTANGULARPOCKET" A54.05 B2. C3. Q0. +_Table 14. Probe Slot Syntax_ -Example MDI Command Without Inspection Reporting: G65 "PROBERECTANGULARPOCKET" A54.05 B2. C3. Q1. +Example MDI Command With Inspectioning: G65 "PROBESLOTX" A54. X3. Q1. +Example MDI Command Without Inspectioning: M834 A54. X3. Q0. - -### PROBEXSLOT +--- +### PROBEYSLOT ( M835 ) -The Probe Slot X macro probes the internal sides of a pocket in the X direction and calculates the center. -`A` is the selected work coordinate(54-59 or 54.01-54.99). -`B` is the length of the pocket in X. -`Q` enables inspection reporting which pops up a calculated length after the routine finishes. -The Probe should be roughly centered and inside of the slot before beginning. +The Probe Slot Y macro probes the internal sides of a pocket in the Y direction and calculates the center. -![probeSlot](images/probeSlot.png) +`A` is the selected work coordinate ( 54-59 or 54.01-54.99 ). +`Y` is the width of the pocket in Y. +`Q` enables inspection reporting which pops up a calculated width after the routine finishes. +* The Probe should be roughly centered and inside of the slot before beginning. -_Figure 13. Probe Slot Routine_ +![probeSlotY](images/probeSlotY.PNG) +_Figure 14. Probe Slot Routine_ | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | -| G65 | "PROBESLOTX" | A | B | Q | +| G65 | "PROBESLOTY" | A | Y | Q | -_Table 14. Probe Slot Syntax_ +_Table 15. Probe Slot Syntax_ -Example MDI Command Without Inspectioning: G65 "PROBESLOTX" A54. B3. Q0. +Example MDI Command: G65 "PROBESLOTY" A54. YB3. Q0. +Example MDI Command With Inspection Reporting: M835 A54. Y3. Q1. -Example MDI Command Without Inspectioning: G65 "PROBESLOTX" A54. B3. Q1. - -### PROBEYSLOT +--- +### PROBEINSIDECORNER ( M837 ) -The Probe Slot Y macro probes the internal sides of a pocket in the Y direction and calculates the center. -`A` is the selected work coordinate(54-59 or 54.01-54.99). -`B` is the width of the pocket in Y. -`Q` enables inspection reporting which pops up a calculated width after the routine finishes. -The Probe should be roughly centered and inside of the slot before beginning. +The Probe inside Corner macro probes the inside edges of a pocket and calculates the center. -![probeSlotY](images/probeSlotY.PNG) +`A` is the selected work coordinate ( 54-59 or 54.01-54.99 ). +`C` the desired corner to probe. +`E` is the engage distance to probe part. +* The Probe should be roughly centered, diagonaly from the corner before beginning. -_Figure 14. Probe Slot Routine_ +![probeInternalCorner](images/probeInternalCorner.png) +_Figure 16. Probe Inside Corner Routine_ | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | -| G65 | "PROBESLOTY" | A | B | Q | - -_Table 15. Probe Slot Syntax_ +| G65 | "PROBEINSIDECORNER" | A | C | E | -Example MDI Command Without Inspection Reporting: G65 "PROBESLOTY" A54. B3. Q0. +_Table 17. Probe Inner Corner Syntax_ -Example MDI Command With Inspection Reporting: G65 "PROBESLOTY" A54. B3. Q1. +Example MDI Command: G65 "PROBEINSIDECORNER" A54. C1. E.5 +Example MDI Command: M837 A54. C1. E.5 - -### PROBEOUTSIDECORNER +--- +### PROBEOUTSIDECORNER ( M838 ) The Probe Outside Corner macro probes the outside edges of the stock and calculates the center. -`A`is the selected work coordinate(54-59 or 54.01-54.99). -`B` Selects the desired corner to probe. -`C` is the distance to travel away from the inital location before probing begins. -`D` is the probing distance for both X and Y. -The Probe should be roughly centered, diagonaly from the corner befor beginning. -![probeExternalCorner](images/probeExternalCorner.png) +`A`is the selected work coordinate ( 54-59 or 54.01-54.99 ). +`C` Selects the desired corner to probe. +`D` is the distance to travel away from the inital location before probing begins. +`E` is the probing distance for both X and Y. +* The Probe should be roughly centered, diagonaly from the corner befor beginning. +![probeExternalCorner](images/probeExternalCorner.png) _Figure 15. Probe Outside Corner Routine_ | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | --- | -| G65 | "PROBEOUTSIDECORNER" | A | B | C | D | +| G65 | "PROBEOUTSIDECORNER" | A | C | D | E | _Table 16. Probe Outer Corner Syntax_ -Example MDI Command: G65 "PROBEOUTSIDECORNER" A54. B1. C1 D.5 - - -### PROBEINSIDECORNER - -The Probe inside Corner macro probes the inside edges of a pocket and calculates the center. -`A` is the selected work coordinate(54-59 or 54.01-54.99). -`B` the desired corner to probe. -`C` is the probing distance. -The Probe should be roughly centered, diagonaly from the corner before beginning. - -![probeInternalCorner](images/probeInternalCorner.png) - -_Figure 16. Probe Inside Corner Routine_ - -| G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | -| --- | --- | --- | --- | --- | -| G65 | "PROBEINSIDECORNER" | A | B | C | - -_Table 17. Probe Inner Corner Syntax_ +Example MDI Command: G65 "PROBEOUTSIDECORNER" A54. C1. D1 E.5 +Example MDI Command: M838 A54. C1. D1 E.5 -Example MDI Command: G65 "PROBEINSIDECORNER" A54. B1. C.5 +--- +## SUPPORTED FUSION 360 PROBING FEATURES -### SUPPORTED FUSION 360 PROBING FEATURES +### WCS override -WCS override provides a known coordinate system for the probe to safely drive to a desired probing location. The override offset specifies which work offset should be used to drive the probe. In the below example, the value 6 corresponds to G59. WCS override must be enabled when using out of postion checks or zero point compensation. +provides a known coordinate system for the probe to safely drive to a desired probing location. The override offset specifies which work offset should be used to drive the probe. In the below example, the value 6 corresponds to G59. WCS override must be enabled when using out of postion checks or zero point compensation. ![WcsOverRide](images/WCS_OVERRIDE.PNG) -Out of postion checks are supported with all probing routines except for inside/outside corners. WCS override must be enabled when using them to provide an expected position. The expected position will be in reference to the chosen override offset and to your fusion360 model. The delta between the expected position and the probe postion is compared to the tolerance specified in the geometry tab. The program will alarm out if the tolerance is not within spec. +### Out of postion +checks are supported with all probing routines except for inside/outside corners. WCS override must be enabled when using them to provide an expected position. The expected position will be in reference to the chosen override offset and to your fusion360 model. The delta between the expected position and the probe postion is compared to the tolerance specified in the geometry tab. The program will alarm out if the tolerance is not within spec. ![OutOfPosition](images/out_of_position.PNG) -Wrong size checks are supported for PROBERECTANGULARBOSS, PROBEPOCKET, PROBECIRCULARBOSS, PROBEBORE, PROBEXWEB, PROBEYWEB, PROBEXSLOT and PROBEYSLOT. The tolerance is once again chosen in the geometry tab of the probing routine in fusion360. The measured length, width or diameter is compared to the user specifed tolerance. If the tolerance is out spec, the program will alarm out. +### Wrong size +checks are supported for PROBERECTANGULARBOSS, PROBEPOCKET, PROBECIRCULARBOSS, PROBEBORE, PROBEXWEB, PROBEYWEB, PROBEXSLOT and PROBEYSLOT. The tolerance is once again chosen in the geometry tab of the probing routine in fusion360. The measured length, width or diameter is compared to the user specifed tolerance. If the tolerance is out spec, the program will alarm out. ![WrongSize](images/wrong_size.PNG) @@ -578,38 +586,23 @@ As mentioned above, the tolerances are specifed in the probing routine geometry ![Tolerance](images/position_tolerance.PNG) -Print results is used to support basic inspection. When enabled, the probing routines WILL NOT ZERO THE WCS. They will instead save the probed measurements to a Probe_Inspection_report file. The file is date coded and all probing routines will open and append to that file. If you run a program 100 times in a day with the feature enabled, you'll get a file with 100 measurements in it. The file can also be deleted or renamed after each run if you wish to keep measurements seperate. Unfortunately, the LNC macros don't support passing in a string as an argument, so this is our approach for now. It could become more robust in the future. Print results is very useful for taking measurements after machining. The inside and outside corner routines are not supported, but all the other routines are. Increment component is not supported as well. +### Print results +is used to support basic inspection. When enabled, the probing routines WILL NOT ZERO THE WCS. They will instead save the probed measurements to a Probe_Inspection_report file. The file is date coded and all probing routines will open and append to that file. If you run a program 100 times in a day with the feature enabled, you'll get a file with 100 measurements in it. The file can also be deleted or renamed after each run if you wish to keep measurements seperate. Unfortunately, the LNC macros don't support passing in a string as an argument, so this is our approach for now. It could become more robust in the future. Print results is very useful for taking measurements after machining. The inside and outside corner routines are not supported, but all the other routines are. Increment component is not supported as well. ![PrintResults](images/print_results.PNG) +### At control report All probing operations include an additional post-properties tab that can issue a Q1 argument in applicable probing cycles, forcing a pause to display the results on the screen before proceeding to the next cycle -![DisplayResults](images/DisplayProbedResults.png) - -Zero point compensation is supported and enabled via the post as shown below. Zero point compensation makes probing in fusion easier by allowing you to use a fixed zero point as the work WCS in every setup. When we say zero point, we're reffering to a fixed point on vise or zero point fixture that never moves. All of our operations are in reference to that zero point. The compensation functions by calculating the XY delta between where your workpiece is and where it's expected to be in reference to the zero point. After probing, the work WCS becomes the zero point offset plus the calculated delta. For example if your work WCS is G54, G54 becomes G59 plus the probed XY deltas. Z doesn't change and is always equal to the zero point Z. WCS override must be enabled when using zero point compensation. PROBERECTANGULARBOSS, PROBEPOCKET, PROBECIRCULARBOSS and PROBEBORE all support zero point compensation. - -![ZeroPointCompensation](images/zero_point_comp.PNG) - -## SAFESPIN macro - -You might occationally command a spindle RPM speed from MDI. -However, if you forget to comment/delete that RPM command before calling a probing routine ... -wekk bad things happen when you spin probes real fast (especially if they are wired) :( +![DisplayResults](images/DisplayProbedResults_light.png) -I could not find any kind of tool-number based RPM limits to ensure the probe never spins. -Maybe I'm just missing it, but failing that I keep a bit in one of the wear values for the probe that flips to true whenever a probing routine is called. -The `SAFESPIN` macro checks that bit before calling any spindle rotations commands, and gives a big flashy warning message to help you remember not to spin you probe. - -Why did I keep the bit in the wear table? I couldn't figure out where else to store it persistantly. I think there are some parameters memory locations I can get access to, but I haven't spent the time to figure out that syntax. - -## Tool Loading/Unloading Macros +--- +# Tool Loading/Unloading Macros These macros are for the 12 tool carousel ATC specifically, and if your controller has been updated to allow tool numbers higher than 12. +> [!NOTE] +> I think that as of late 2023 LNC controllers shipped with the firmware that allows arbitrary tool numbers. But older X7's did not, and required a firmware update that can be aquired by emailing the support team. - ``` - I think that as of late 2023 LNC controllers shipped with the firmware that allows arbitrary tool numbers. - But older X7's did not, and required a firmware update that can be aquired by emailing the support team. - ``` These macros allow you to add and remove tools without having to manually modify the tool table. Use any tool number you want, up to 198. @@ -618,13 +611,27 @@ Tool number 199 is used to signify an empty pocket in the tool table. Both the load and unload macros have the option to set the tool gauge length to 999 and clear any tool wear compensation values. 999 was chosen because it's safe. If you don't toolset the tool before use, then you'll get a z-height error when you try to run. -### LOADTOOL +--- +### UNLOADTOOL ( M805 ) +The unload tool macro will change to the tool to be remvoed then lables the tool pocket "empty" after prompting to remove the tool from the spindle. + +`T` is the tool number to unload -| G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | -| --- | --- | --- | --- | --- | -| G65 | "LOADTOOL" | T | O* | M* | +| G Code | "Macro Name" | Macro Argument | +| --- | --- | --- | +| G65 | "UNLOADTOOL" | T | -Example MDI Command: G65 "LOADTOOL" T10 O12 +Example MDI Command: G65 "UNLOAD" T10 +Example MDI Command: M805 T10 + +--- +### LOADTOOL ( M806 ) +The load tool macro manages the changing of tools and updating of the LNC pocket tool numbers + +`T` is the tool number to load +`0` *optional and is the tool number in carousel to swap out +`M` *optional and is the flag to reset tool offsets then call TOOLSET (defaults on if omitted or called as M1. M0 will skip the reset and measure) +`A` *optional and used to send the the spindle to a set manual tool change location (defaults off if omitted) There are three conditions considered: @@ -637,24 +644,40 @@ In this case, assign the new tool to an empty pocket. 3) The tool number does not exist in the tool table, but there is no empty tool pocket. In this case, prompt the user for which number tool they want to remove if an optional O argument was not sent. Then re-assign that tool pocket to the new tool number. -After you have loaded the tool, if no M argument (default) or an M1 argument is used the macro will run the TOOLSET macro to measure the installed tools' gauge length. An M0 argument will cancel the calling of TOOLSET, and skip the measuring of the installed tool allowing the use of the previously measured offsets stored in the tool table. +> [!IMPORTANT] +>After you have loaded the tool, if no M argument (default) or an M1 argument is used the macro will run the TOOLSET macro to measure the installed tools' gauge length. An M0 argument will cancel the calling of TOOLSET, and skip the measuring of the installed tool allowing the use of the previously measured offsets stored in the tool table. + +| G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | Macro Argument | +| --- | --- | --- | --- | --- | --- | +| G65 | "LOADTOOL" | T | O* | M* | A* | -### UNLOADTOOL +Example MDI Command: G65 "LOADTOOL" T10 O12 -| G Code | "Macro Name" | Macro Argument | -| --- | --- | --- | -| G65 | "UNLOADTOOL" | T | +--- +### Zero point compensation ( M808 ) +is supported and enabled via the post as shown below. Zero point compensation makes probing in fusion easier by allowing you to use a fixed zero point as the work WCS in every setup. When we say zero point, we're reffering to a fixed point on vise or zero point fixture that never moves. All of our operations are in reference to that zero point. The compensation functions by calculating the XY delta between where your workpiece is and where it's expected to be in reference to the zero point. After probing, the work WCS becomes the zero point offset plus the calculated delta. For example if your work WCS is G54, G54 becomes G59 plus the probed XY deltas. Z doesn't change and is always equal to the zero point Z. WCS override must be enabled when using zero point compensation. PROBERECTANGULARBOSS, PROBEPOCKET, PROBECIRCULARBOSS and PROBEBORE all support zero point compensation. -Example MDI Command: G65 "UNLOAD" T10 +![ZeroPointCompensation](images/zero_point_comp_RO_post.PNG) + +--- +## SAFESPIN macro ( M813 ) +You might occationally command a spindle RPM speed from MDI. +However, if you forget to comment/delete that RPM command before calling a probing routine ... +wekk bad things happen when you spin probes real fast (especially if they are wired) :( + +I could not find any kind of tool-number based RPM limits to ensure the probe never spins. +Maybe I'm just missing it, but failing that I keep a bit in one of the wear values for the probe that flips to true whenever a probing routine is called. +The `SAFESPIN` macro checks that bit before calling any spindle rotations commands, and gives a big flashy warning message to help you remember not to spin you probe. +Why did I keep the bit in the wear table? I couldn't figure out where else to store it persistantly. I think there are some parameters memory locations I can get access to, but I haven't spent the time to figure out that syntax. +---- ## TODO ** Contributions Welcome! ** - Add a `CHECKTOOL` macro that can look at the tool table and see if a tool number is present (would like to add this to the top of my postprocessor!) - - Add a macro to check min/max values against soft-limits (would also like to add this to my post processor) - Add probe runout compensation into the calibration: Rotate the spindle 180 degrees with M19P180. Then re-do calibration and compare results to compute runout. Need to figure out the math for how to compensate for it during probing. - Add probe Angle routines (i.e. probe a wall and compute its angle, so you can rotate the X/Y axes) - Add 4th Axis probing routines diff --git a/changelog.md b/changelog.md index 20bda74..4f228c9 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,13 @@ +# V1.3.0 +- created Maker_macro pack and updated the post and macros to suit +- Probe operations have a post tab to add a Q1 call to display probed results at the machine. +- Milling operations have a post tab with a drop-down to select HSHP level. +- Probing arguments reworked to use the axis being measured rather than ABC ie PROBEX A54 X10 +- Reworking of @ variables to avoid conflicts with stock Syil macros +- Gauge block and manual tool change locations added to PROBECONFIG +- ReadMe updated with all the above changes and additions +- assorted bug fixes + # V1.2.3 - Updated the macro set for compatibility with post-processor Revision 44168. - Added a wide range of user messages to provide extra control information during probing. @@ -31,6 +41,5 @@ - bug fix in docs and macro for the CALIBRATEPROBEZ macro - bug fix in all macros for picking extended work offsets - # v1.0.0 -Initial functional release! +- Initial functional release! diff --git a/images/DisplayProbedResults.png b/images/DisplayProbedResults.png deleted file mode 100644 index 33b3c352de2e7c3fe4883b4b300bb21eb66b9040..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10415 zcmaL7bySFuWtIQ{GguBRuIX)j z4D)d(nh$0_t7&Uv2tyeH);4`WXF1QnA4F$Sr(vdwur%(qIim5-A>~SCuEXd+&OxT& zqo+`Qq+#{x78I8>uCzo=;bgTi=yMbLorD}WT^~nOJG?2CAjUGlN@zZJB>nOxX_iJXm??0%RjO=j=mtq*6=D@WUr&q|A9^iNMfC@ecOctzGkl{ zJZ?{^WH{}#_1_2i(-z;c#(1L?w<4>T_ePl$Z9Kexr@td#)FS!Uw#y9TK`QnMn!ulA zzWf;FoljR$ZOHemVfO*X-Fs}`dWTBTm_h`IY3>Nj_0Ajeo-HOly;tvjqzO>~nO3Bi zIPlgM+?p@1g=QhzTE5@#;!o3^OW^Sad#YsTT2b^J6^xD8tIZVDRf>tOMW|{;!(FjG46$zof$u&4np0*M7??r*&EteH4%Tvhc&ABm%DNcOvBglL4@Y(_RgGkmK2SE)b#g+PZFAZeTt$u0*Ha z6?NQ44GFN$&k$YxhQcCx*N>&Lm>$&Xb4H8i1O#fDZ5*97Pm^tO9@EW9QGe$8#6U$e z)Ax?p^dNaQSOEc2bdrCx*=jSu zX}6gX#z;mn;|q%Bu`LSXq5DAw3-tcL@JR1qjblrM?C;M4#6z74NjY|ad*SoCa^>_v z6GQ*K_F%||_PTOi9c;j#UI_6d^2965x2g>RR2Mj-Svgp#$H2rIqC*{agufgEZFJ8J z@^uj3=;q0TPpVBlq`D?5mCIfEGS(3bjQH*oN^58g@w%_Qq-Eux!p&Dyy zaUeCv<#@S}V+b3=9=w&yZu+-(%H9Y&-o2(x;VOyU>o1~d)|U+pm5lgtYR7wDb7Su8 z{0mJHCS zPr1x62!$J>0=kDqbfM$cBQ)#N#X$cTWg1bAv#m7$0thWyDpq4ih~ajV*B^Ev5a+!>@;LVBFps4bZ1^3}= zfA5*Tz%QzW@1&`huU*FGqo=;;*D6gQEG;#KkKg>*jUq9mjOTmpE!n(z7GcdQqNLQ{ z25~UfWCQ$-xDBHy^y`FMX}6C{;V?Zp8A=*i%k>M>UTXZAF)c0O(N&7>>y3DTB$GVp zezSpUuoPcd041H&TrWkb-j`s~1_gmS-jumoW$wXcNEeANzR}HLZOtnmE{L?J6tV0` z?b6%(^TZ$u?)^O`{f#lu_MtxApFjP!TOb?9L$EPKPZSo*|Bc_qDfUX~cY^k|DJFo3 zsJO8cDbl0rd#`_?a%uqL4Da#kUy!D@Z(oNTJQlTY-DT(x2c@6rgL>*ch#KDK);@MN zy(zy5K1I2`_=r6534Wi(hu6}(Oqx_3=&LgAMFPgRwWX_V=|ofTz`*|;O{_&D$Ic5_ z|52KU`St43Vh@@lb@}-|qI;Ob$CvlOZr0W#kS=5Cew&J`{<%RnO!|mGpXmPnuzXxZ zP2c6a(P7b@fn=NZG(5hp<60Ab_L1lHwCP-O`i;BJRO%)0OOQ(J^a(Un7sp@sQ7ZsZ zh;@yo%0B%Ld-doG9dX8PbCj<Yi zy0K#cP$x8znt2ApV?n@08c2%%0~+}iM^LqC1I6_B_oM(14cfUDH`ck1GJQSdwT!dF zaNkaID?U^hhZ%fNHb(g!Q|e9MJ{1#Z4Q*X1Y@ZLz$jhgcAr1@Mu^Q%K*8zW3*Z-7> ze-%qt6r@(}9$?YAE8Jwm;bRCan`u)Q5I17Z-4z~Gqn6UpbimCt_Z*hJEu*!XBH~?S za;xHlp~jwkqpYjuVD?*a|1}$zJ3l(LO|fBTY-#RG-AJK|W=~3NOU+scbEfZ2}H9_lKqvX({*<{%-EKvDlaQ zk$ajuJr9Xgv7;!r0QjapTVw^#K07#YpdHMAHDqW2&NSCSsw}uPc#s%=PS?GyJ#n0w zb(Bco2WEzcV9v~(NMAqNJBVgj;OeV2xRa`0*cTjXEI~%Mv*=!pKhUfX;cAkd>_;ap zx_nJ1)1EQ{MoTCT9y(d==&xA-EnRW($I-lq>|sE%{Z3>sk-pguW97g^H%_xMkM%g? z*o9P(LiEePa4QTb2R@(eux9dS7zKUu_%5;N$|~V7V@C7_l~7H-vFM{M+j>{wTyjTN z>RNQX+KRd9z{JqIc6)G|>NC5+B-Cx=c_E(-UZ3-vtLRY)2^h4>RLyA!k}blpOSmi= z;MKV(Dq7EcRvwc~77UIyCy}SEsrM-r`Mf#`lWQO0`F19f;}~ebs?6;8-sL;dDiaBV zRDEKqgj>5+99eew-|5q+hLGwuJ=7Frn*882{FRTJCFa>g`ekAv`10S4cpAPF5vYOw zTn=z2MMZ5YW3DZk(GaM)-i6AMsy^quqm;aujI+a*BjX9APALMUV5QKDtA+4bnYO%$ z9(ndL2p!Xlsr{PwLejWwNXkvclAGuj9Jl`Eb{Er1kKe;1HGUV{U-Vh9+6(mXs8+{E zGv#oS_t2qhY3BlaWv(XH>M-Gb8~C`}WlR{$_B6g0h&!kPVIUz7Ti(6SYXJV~dP`z( zQ34B&bGeCvqHZ+H4U+;T1uR4&kmIoFzn~I=C}xyZE(?xQ6HNj zi3&;|2rU=m6B^iv(M=4ji-}6Nvu{SO1rbhD z`Cxy>T6cvaMM$=HyII+DvEsXWGW}A0 zl4OQVzTENH)%PBQwQkzB`hvCq@ zR!RJ%A6qeK+f3+ktmS+r)ue|P0>RcYxtGxlxT8KFcdG6t-4zY4tSdgNiv&H@>r%?~ z)*cNk;ss&D7Ex?o{uBd;TKj&z)+kut{Moe``Er<@rF})l-1qe7^yz&B+Sau$<00or zs|7cp;JK(Xa(9uShBGG87B5JM6FS|_M%m2N29={l9By2+EG#QSZxH>U!HPRHI^J{P zjU z!g%GyYvxVUjHVN_%J0Qy<6FGr-`gvz7NJawZ-z&DWLEyy~HgP@!jI zZns=S(evDh$J#n?nm@%;>{hx)Vq^p16Yq8F z&r-cFDolFaUM@iF?i4aXlW&+qceiAcUsI_L3JQ@GE0uZ^^!<6p3u3l;O?P8{Fk*I_ z(1E>{oLR_BVqr(%3qRDp5++nlp;jxh&=|D#)$A}FYNtUJYe=LO^*x{ysrbzDDG~ut zKZ?>q(N)W|=PE@gq+M;?8FN2xJZQ4&iK<|Cn2-wLz4P&)dkV<2Xjl9X6ph-lO{cT%_Z;Taq7P?F z*_r(ZARf3kA#@yDPNEs{FPBq43vAc#Ke(iq-J;dLH-ZhhdsxJ+#3tN4<8vz+{XpUR z9Ln*etRrcz8?ITo;z+jVSZ0>T>xgd>cx`;-?*&peq6mdq9ncY3E?Pa@ox8im{-msA z#+>MU5uuj_Qc(@WAI@{}@u6obguD|9+c5iZc5v{Fb<%j-1bQTr>bbjFK5ya>PAG-k zix#Zd^pMAMY#gpV5$Ln8#qR})lH{q?3Hx_bO9N`HecntwUtvYO$s?H;4u*QDtjBT$ zplayg8Yl-2qZflOT47l^-;BBM)(32ka*G37~Y}{lEQAcw*x!)PD8uh*GgzxVUB$-`y{0KqtABC z!;W~q946A@Jw*Oj#dsSVw$wf3O7VPte_83@uxBFxunkWJy4y>gt1hvt#ihNTJO5Do zF)@Bj=worhmW1@hUR`0!vR{83)9t*R=NTP7rCX$WymYED4KgDA{(Q~fcmEr|h0gK4 znpqeTww>RKqxXsNfNM-fELUx0f5HR`+wn zwpG#CX9)SGIe`WdijHslZ?{6M@X*W+vee+4bOdZ{9J8aJxN(O+KV!UV;1Y17pwGn0 zWDG)oDjw{ABr?hzMS+LfcFIi9x8#=xwl|ca)B$Effmh+@5gx@1aw%;_a=G*l586G? zT`l$zqi&J96gt|p#4L$212ik%&9>Zu0yl3DNDK$sWSk00*FrmAe#N$-9I%mxn$p0o z>Gwp0F^&1-ICdIRCoenHMP!Gh9Ei|*W&p0O;v0t0$MHpaV zsda>iXBZuLT6wsBTIOvhWinoFbe+t6F=CBjNnDPvUgZXe^&n%o-6TTq=Vc1(-s4cU zkh|Sf)T}LFC(y#)Ng!*S2@0W({NfCJs>u8W3&3Df&g=emqTqcnT-pyUddJO&&hQEG z{(Xb<-vOF7N9;|zC1&@;iT*`A70JEOMBw*By)74q6>oRgjms5`Ab|OYSxHxmJQm}| zJ9nW_anIq1<8tw`h!kU?mVGby#$cR!>Co6^wqnze`Lp6eg!WA;vH(oj)^EW|isW8W(Ob+ojPvRsi z+4{J`RTeQ7ypvXUs$xHOAmh&(ybCeWfzGvv#!tW3fNw_MS+2=(SHH01~&$FY!9| zdMjc3e;_^V%T;64+AcUH8yjXFPZP_nGq89a<0oOjb>h=jPbv?l*H1&B{k<@IzKxhl zG2RF@`9`NFijPx1cr_a*;>~3*zoLx~mREC&*u~m7CCUph#Q+PfWzN^dwkjQr92%5e zFN)m6o+B8%+(>u|AiR5V->$<$s`0l4)&xoAQsshBo?q^DB3y1376uT9$@*8n-ZpSo z*?hOM^ez>#IjnhlS`FMHwpz$E&+ ztW&>_XE9{_AnF#pMlc96tYGf@b9x-|j+JIo z#DDn0zA4}pEOz~bcQy9;k$)o?w}~qbn=zIrKG`6~l+sZvEf_+OBCGz=S{ec1SZvqU z;RXAF-EnWS?9>~d;XYs$v2s-e?|8XUwZ3xnK*+{};M>BG&H{wey}cMHvipXXoj8L2 zXHo|L@OCT;eTkJaCV?~~rfV`Gk9O=ehc& z6%k4-9qj`AsxrMck_Q0*_ffB50B}ETosTDjV_?cbX(+#D_Q&w#VgJCzKdyxoDS0ee z)&_@emsjqMPSbPCbI~cKnT6%u_JX3_ZK@9xRD`7q1zYT z@9)_qzgS-xB^myO4DbX!Hyi+`{`!dZvD>dq$Mk-Y8iKpcjx7P+lb4|-WuBt^<3hSl zuShoVd7QZLsNY|UP=7_>rsfw>FE#O#DacEDDB!A4FjB#(X>q7YU!H+$AG%Ns4UNC-2&lu*Blu@}_#U^o%NXE1QadLw=Edu!t&F2e81 z+eN$otBC`c{JTXmPq&e-UIL+e&rLZ`pvD8M_8zY(Y|6U!$~3jrSC#>5#!<;^5jzcF z<1{@GfJ}QMZlRsoX3Qf``a@?NlZCgi+LM15d9I$r(ugY$4a5}fM{_rr3VO|3KjjJ_ zZ=pn#Z>%2iF9=*#_ULZj0q{6}LTs!yzJ8>bp`O_-gu|Hj&zlTo6+F}`Kb$6e4*vN= z0PPxWUf*OKvkC9@blc;DP6vJMDuh_jS=XdRJSqTJOK0d(%-t>dJF%XjRp?WNJumS~ zI@il=g>HWXdyzrf^IHQx7n=cm0_foJyacGIB&H*LJBTORn;Z_Q34a15z}rL=k|5Ba z>3=$1bo$XcM^I51C#pJ4=ve++IdGaRBO84L0l~Kjd|7NdkUZswBq9K2UsRO(C<+7a znxF)j2rZbM+&~7LX2%%11P1?rr-c7nj`M#cg&6Wo?l{F84{ubCu$*_o^Rx;bvtc1} z(=i|4*0vtyi(ZQdTF@^RV_VqkQ$L@aip0vLGDf@MOymkinmip?8Ip~yuc5A>f?ft> zH-6i9Xr+KYj1(7?*$7-*TqI>=d=!vN39B+_0kN^+K=YZU+x&DZBOKk%PwUg!bn?Z> zv)u96Sj)uXZ=B*pH zw;TZv%$OomXHx+Do2c1e4(!jt$j5hA&rFroHsF2F|TPC>ePc@8pjZ9v+@#MMl+P@NY}e81$VPNDIrHlno)L zzw4P#gVw11wY6Fc7UBAV?|PYYCYC}o=1|gx_+SL- zT2mA^fDM6hnWu(j=I)~9b4OYEoT!8!_H*El(DvShq(_+>m5gJHV3}50US2|lPL28D zT-7aHvB&yc?$QbiQ`WP_R=i@MO#`0gPL`5#5_E#tx9rfaV z?tH4_aEh+W)=&+eg_HL3DjgFcBsT!XsvkP~%!br#$bQ+)ojZ$Nbu8Ozg{oE4l+^ zWUc!?0=JBojOCcVEL9>}HjjgZwl)dmGWQgDgiO|w5lq8yb};xwxzRQ;yxIV%l4V}l zysel(#v`$h2U%|vLDK<28(wsbjtSFf;LIJ+$lX1^;S^3>OcYr=cqCV^?SVFepg18O z*yrL9cgrdaf3DymAO<2PGtxr`E6Wrm?foV;GfM$X&bmHq2+Jzh3>X6zd zk;l=#sU`!gXWi-z$I@-KCu28k{d{%h-f`B8#pkk#-0TR8aoHL`(N}WxoF594qJi?p zec!e&?yT}CDcAv&kC0lN#7G945E>vs;FF3LVKl!dwvz5R?U^Gd2|3#zuaU2DhAB&@ z62GK#NY7Hi>ZC_1*$wts@Qf?8f#!UB1kUX+Sp@}29UW50{cKI|-lf^Y-{ad8udY}$ zD(~)J@fKLoV_C@R{(b0h+N*iwq*vz3!uw;3Zi!=f7qyB30Qf1DWdr~ikFgVkU;`ej zGV95he`iwjC){tkR+n9ZVKlLzrPN;4QWf#FZ0e1Fcqaj)1A2wYZ=F(Dk^(K`Td?!DbKve~2!1 zTb<2RbrOQXAH&3AG=O*Qs7>u^EuH8P;(-(K!943)GP=>q5y7zdXZ-y?VO~3Mb|?}X ze%xNGyml?%N^$+%rV#A=r(Hwjh#!5s<)PhxQDXLZ9-dF}c1_dg*!r8TRku#nJ-89D z!mbVAQv?Gh5=T6C>K~;PK9s$lW4bf5_8yQ%EYu1+uVP0l+$E?(qkDl7`AmcsrOT$L zALqw0U`c7|)~eqrv?mnpe8D1d15NZ+{1=Uvudl#B0wq?m4N4?|<9D&Q1_^DYr4?HoWc^m~CR!@P_H1PmDey`BH)&;PauDBCe44Sut24j@odU+|ux`v-i5 z%<{xX;TCN-pfkXK`Yl3^nF}s|J;MG0Up2e^f%HnG;Szo+a2lt28N8gyzq=GOKZMu3 zZlJ8$2>}gAo?eG03<$T=eAkEvR7CWj>It`uS+2k46~=Q#;J;NDWI5rh4$%_*+YQ=3 z@BTk+{NIO=(l^j&6R%QD%mga(#!O|irzKEJ`2)dFw|`^?5JkiNH2m@Dy7AvA8R5yx zIrMqQ7{iR}KV=-@@}F73>;Iow{lNcRELj$PW0FZykZIF^s^Bz3MkAi)j40+0iipwhPJup%=G;}3;9JZ|`^zF+SkO=5pzVhY zO@2@}eU}-)f}6@jchC4t(-7vvOko?9hwnloK+3GnA89a*DOn< zjc`qpH(bC2Kd=8oNJ%@>+;ug8H%%U1sky>chKQ{z%mjz-bOsFp5GpCz>kk6?t<+-! zYy_V&_*kOkXyO~=PI8iv06+>$cnG+!IDSZKdkKl)Cfc7U8n3lFrA;q|1b zf00UyoDz>t2a1uurKSDXIz>xF64unKtym>cMm|vGMAYed#WYY9!rAxg{T7B{yQ@@= zRqS*khgy-a6P?cD>U{dwn*pFKkyoO>Imx}FVPC#7Pjmyt1|1%0PikJmE1WJ;>&4Bh zErm3j$!s5*JF>0F%%?Xe16J@3+hk5O&mKIN>lF=c=6|{+WSG1B$bMEzE9OiCcS=k@ z{Al-np%AuzfKpOfq&^dwEuhq}? zc(c#`4zCqHguVw-vO(Pj5d4s;l%H==Ffp@g*3K)lvv@t~>%8DeUZR1c1 zS)=3A*MXkxuq@Fa5vqVIwH$u80ZtXe3>)y9kHlVNh~MvquomW%+58Z_q0+OQ>9aNH#~`ldFIRBJZ77UIfp*LZiY4Z?hjxD!F5BaSkslRdj<&xJPC zl!u2c%As2em=t{xDzB(W&d+zsVq#YyQca2#s>810n`X~IaGPTlm+ND%6a-DUa87Ss zeuCPXRL!~S#|C62NZtPu=aIiiw6M4{A2V`6&+1bA^x;0#r)q9fAYqz~ZfBt;eSXh$ zR%xm!o<9lP^>plX{!0??-^ie^uW!@7C~JE%hy<=(nt4)7+M+*DpWCvPYEx95N(4f< zAO`_Uj~Teg2_5#R@&dSKlLQ_^^s14%kW!NCpZr;yCX+qpxFx^07+(j9z@g=;ufo&G z3Z4jOb5y@oG-y6NVEL*l%pjOl3(keE{jbec60iH^^1&2UVl}0$&j=iY$?<9^8eO0`kbrk zlyh$G2^lAuO5Q4)%#9p*cYRY+t5{*cEE60kI6>k@BL_Ii*AAELPgRJ6I71nxK9_O1D?0411W489+VJ8Dh*uFbsCBH`9N~^#GM?RXfZ8#8rXub_sf|hL89j_X!{Es> z(gjC~SBl|)*vYfyI9LX1Oe5v1OlOpbeUuMz=6dBA=*<rB_Tat)u>(12f2j{;a2Sr-7=v zC>{!kQ>@uGSH##H4S7}(pu`oiWn*fyVGW;57;sf^_l)=>!rXl|eQj^C2 diff --git a/images/DisplayProbedResults_light.png b/images/DisplayProbedResults_light.png new file mode 100644 index 0000000000000000000000000000000000000000..a458a888765eea2fedb1218f1101b4c319f86c21 GIT binary patch literal 7797 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 literal 0 HcmV?d00001 diff --git a/images/zero_point_comp_RO_post.png b/images/zero_point_comp_RO_post.png new file mode 100644 index 0000000000000000000000000000000000000000..2be27af6865549afede833c2b1a3d2587a7af092 GIT binary patch literal 81257 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�#J8IuvgF`pBFB4jQr~dxGpf91ZK48SD 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 XG?na|^!}`V13VODRHQ2<4TJta;Wcsm literal 0 HcmV?d00001 From 45331a07408f0b1fd8fbe2ae126bd22b127d4f6b Mon Sep 17 00:00:00 2001 From: Robot Oblivion Date: Tue, 15 Apr 2025 18:35:11 +1200 Subject: [PATCH 16/21] pushing read me up again... not sure why it didnt work with the other changes --- README.md | 436 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 418 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 32a4ffd..22ef5e5 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,6 @@ The tormach wired probe works, with and without the xoomspeed wireless kit. All the macros need to be stored in the same file as your posted gcode programs. Always test the macros with MPG DRN the first time. SYIL configurations may change and we're not responsible for broken tips or machine crashes. This macro set will work for both wired and (some wireless probes) and now supports probes that require special macros to turn on and off. -## Probe Configuration Macro - ### Imperial vs Metric units The various probing parameters must be set in your desired units sections in the configuration file. No other changes are needed to configure the units. @@ -27,6 +25,7 @@ Start with the recommended settings and fine tune from there. Please set your fusion 360 probing feed rate to the same value that you use in the config macro. If you decide to change feed rates, you should always run calibration again. +<<<<<<< HEAD ### Configuration setup Every probing routine calls the configuration macro to initialize global variables to allow all probing parameters to be specified in one place. @@ -51,35 +50,93 @@ Using the editor of your choice, open `PROBECONFIG` or `M800` and update the fol > **Note:** Any WCS number from 01-09 should be entered with a leading zero. - **`@103`, `@104`, `@105`, `@109`, `@110`** – Probing and tool-setting speeds are separated into metric and imperial sections, with safe default values that can be adjusted if needed. +======= +## Probe Configuration + +### Configuration Macro setup +Every probing routine calls the configuration macro to initialize global variables. +This is contained in `PROBECONFIG` +It allows all probing parameters to be specified in one place. + +Using the editor of your choice, in the **`Macros for controller`** folder open `PROBECONFIG` and update the following parameters: + +**`@100`** – Set this to the tool number you want to use for your probe. Common choices include Tool 12 or Tool 99. +**`@111`** – Extended work offset number used to store the Z calibration artifact WCS, aiding in faster recalibration. +**`@112`** – Extended work offset number used to store the tool setter's XY center location. +**`@113`** – Extended work offset number used to store the 4th-axis corner probing start point. +**`@137`** – Highest offset that can be updated, defining a protected WCS range. +> [!NOTE] +> Extended WCS numbers G54 P01-09 require a leading zero + +**`@128`** – Disables extra spindle orientation calls for probes that spin on/off. +**`@109`** – Calibrated length of your master gauge tool. +**`@129`** – Calibrated diameter of your ring gauge. +> [!IMPORTANT] +> These dimensions are critical for calibrating your tool setter and ensuring accurate tool length measurements. +> Default values are provided, but you should input the exact values from your gauge tool's certificate. -- **`@106`** – Probe clearance distance. This is the extra distance the probe moves beyond what the macro expects as the edge of the surface. +**`@103`, `@104`, `@105`, `@116`, `@117`** – Probing and tool-setting speeds are separated into metric and imperial sections, with safe default values that can be adjusted if needed. +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 + +**`@106`** – Probe clearance distance. This is the extra distance the probe moves beyond what the macro expects as the edge of the surface. > *Example:* If probing a circular boss with a specified diameter of 1", the probe will move `[0.5" + @106]` away from the initial point. +<<<<<<< HEAD - **`@107`** – Probe backoff distance. Probing routines use a double-touch method: +======= +**`@108`** – Probe backoff distance. Probing routines use a double-touch method: +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 1. The first touch is fast. 2. The second touch is slow (for higher accuracy). After the first touch, the probe will back off by `@107` (in inches or mm, depending on your control setup). > This value must be large enough to allow the probe to fully disengage from the surface, plus some clearance, but no larger than necessary. +<<<<<<< HEAD - **`@108`** – Default value used when a tolerance argument is required but not provided. - **`@91`** – Rounding multiplier for many probing messages. Adjust as needed to control the precision of user messages. Once you have saved your changes to `PROBECONFIG` or `M800` copy all files within the **`Macros for controller`** folder to the LNC main NC files directory or copy all files within the **`maker_macros`** folder to the LNC Maker_Macro folder if you would prefer to run Mcode based macros +======= +**`@110`** – Default value used when a tolerance argument is required but not provided. +**`@11`** – Rounding multiplier for many probing messages. Adjust as needed to control the precision of user messages. + +> [!TIP] +> Once you have saved your changes to `PROBECONFIG` copy all files within the **`Macros for controller`** folder to the LNC main NC files directory. +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 -## Pre-calibration tasks -### Backup your controller and prep for running the calibration +## **Backup and Preparation for Calibration** +<<<<<<< HEAD 1. Backup your tool table, offset table and `@10`, `@91-@98`, `@100-@110`, `@112-@115`,`@130-@134`, `@980-@987` and `@5109` variables in case of wanting to revert 2. Clear as many items as possible from the table to prevent collisions with stock, jigs, fixtures, or vices. 3. Ensure the table zero point or area to place your calibration object is empty, lightly stoned, and free of coolant. 4. Have your master tool, probe, and ring gauge/gauge block ready. +======= +Before running the calibration process, follow these steps to ensure a smooth setup: + +1. **Backup Your Controller Data:** + - Save a copy of your tool table, offset table, and the following variables in case you need to revert: + `@10`, `@11`, `@100-@117`, `@127-@133`, `@980-@987`, `@1508` +2. **Prepare the Work Area:** + - Clear as many items as possible from the table to avoid collisions with stock, jigs, fixtures, or vices. + - Ensure the table zero point or the area where you will place the calibration object is **empty, lightly stoned, and free of coolant**. + +3. **Gather Required Tools:** + - Have your **master tool, probe, and ring gauge/gauge block** ready. +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 -### Basic Probe Setup +### **Basic Probe Setup** + +Before running any calibration routines, you must ensure that your probe is concentric. + +. **Check Concentricity:** + - Place a **dial indicator** on the ruby tip of the probe. + - Rotate the probe in the spindle **by hand** while observing the dial indicator. -Before performing any calibration routines your probe must be concentric. -To make your probe concentric you must place a dial indicator on the ruby tip and rotate the probe in the spindle by hand. -Adjust your probe until the dial indicator doesn't move or is within a few tenths. +. **Adjust the Probe:** + - Adjust the probe until the dial indicator **does not move** or shows deviation within a few tenths. + - This step is crucial for accurate probing results. ![probeIndicate](images/probeIndicate.jpg) _Figure 2. Indicating Probe_ @@ -88,6 +145,7 @@ _Figure 2. Indicating Probe_ ### Basic toolsetter setup +<<<<<<< HEAD Before you do any toolsetting, you need to tell the control where the toolsetter is. You should manually move your spindle to be located over the center of your toolsetter. @@ -101,6 +159,30 @@ The toolsetting location will be X0 Y0 in G54 P`@113`. ## Macro Syntax Depending on which file pack is installed, macros are called using either `G65 "FILENAME"` or M-code numbers (if you've installed the Maker_macro version). +======= +Before performing any tool setting, you must define the tool setter's location in the control system. + + A. **If the tool setter's location is known**, copy its XY offset to the extended work offset specified in `PROBECONFIG @112`. + + B. **If the tool setter's location is unknown, manually position the spindle over its center:** + - Use the MPG to move the gauge tool until it appears centered by eye. + - For higher precision, use a dial indicator or coaxial indicator to sweep around until perfectly centered. + + B. **Once the correct location is found, save it using the `TEACH IN` function** in the offsets page. + - Store this location as the XY origin of the extended work offset specified in `PROBECONFIG @112`. + +> [!TIP] +>The toolsetting location will be X0 Y0 in G54 P`@112`. + +--- +## **Macro Syntax** + +Macros are called with G65 as opposed to M codes to speed up execution. G65 is followed by the macro name and whatever arguments need passed into the macro. The example below shows how to probe the side of a part along the X axis. The A argument is the work offset and the B argument is the probing distance. Each argument starts with a letter followed by a value. For example, a macro requiring three arguments will have A#, B# and C# after the macro name. Simply copy the macro examples into your MDI and adjust the arguments according to your needs. A table mapping the macro arguments to local variables is also provided below. + +> [!IMPORTANT] +> Extended G54 work offsets are supported with the use of a decimal point. +> For example, G54 P5 can be entered into the A argument as **A54.05** (_G54 P01-09 require a leading zero_). +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 To pass data into a macro arguments are used and starts with a letter followed by a value. For example, a macro requiring three arguments will have `A#`, `B#` and `C#` after the macro name. Simply copy the macro examples into your MDI and adjust the arguments according to your needs. > **Note:** Both G65 and M-code macros accept the same arguments @@ -159,8 +241,13 @@ The first time you use this macro, you will start by setting the calibration hei *This macro has an optional argument `A`. By default you can call the macro without any arguments, which does a quick calibration using an stored location/height for the artifact. +<<<<<<< HEAD Example MDI Command: G65 "CALIBRATEPROBEZ" A1 Example MDI Command: M803 A1 +======= +> [!IMPORTANT] +> The first time you call it make sure to include the `A` argument and run the full calibration procedure. +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 > [!WARNING] >The first time you call it make sure to include the `A` argument and run the full calibration procedure. @@ -189,11 +276,15 @@ Once you have done the full calibration one time, you can use a quick version of the macro to recalibrate the probe offset without the need to use the master tool. But you must re-install your calibration artifact onto your table before calling this macro. +<<<<<<< HEAD This will move the table to the origin configured in the `PROBECONFIG` or `M800` macro and then do a protected move to calibrate the probe offset. Example MDI Command: G65 "CALIBRATEPROBEZ" Example MDI Command: M803 +======= +This will move the table to the origin of the saved WCS specified in (`PROBECONFIG @111`) and then do a protected move to calibrate the probe offset. +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 ## Probe Tip Diameter Calibration @@ -204,11 +295,44 @@ You can use one of the two provided calibration methods: ### CALIBRATEPROBERING ( M803 ) +<<<<<<< HEAD This macro uses a ring gauge to calibrate the diameter of the probe's ruby tip. The routine will determine the diameter of the probe tip, and the calculated radius will be visible in the tool table. * Before starting, ensure that the probe is concentric and positioned inside the ring gauge, roughly centered. ![CALIBRATEPROBERING](images/probeRingGuage.PNG) _Figure 3a. Probe Diameter Calibration (ring gauge)_ +======= +This macro uses a gauge block to calibrate the diameter of a probes ruby tip. +It's important that the probe is concentric before beginning. +Any good quality reference block artifact would be used, such as an actual gauge block or a high quality 123 block. +If you are not using a calibrated reference artifact, you should use a well calibrated micrometer to measure your 123 block to get its true dimensions. +123 blocks, even high quality ones, are commonly sold a few ten thousandths of an inch oversized to allow for lapping +and you want to put the true dimension into the macro arguments. +`A` is the gauge block's true X dimension +`B` is the gauge block's true Y dimension +`C` is the amount of Z drop you want between your initial position and the measurement height. It needs to be a negative value. + +![CALIBRATEPROBEBLOCK](images/calibrateprobeblock.png) + +| GCode | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | +| --- | --- | --- | --- | --- | +| G65 | "CALIBRATEPROBEBLOCK" | A | B | C | + +_Table 2. Calibrate Probe X Syntax_ + +Example MDI Command: G65 "CALIBRATEPROBEBLOCK" A1.0002 B2.0001 C-0.5 + + +#### CALIBRATEPROBERING + +This macro uses a ring gauge to calibrate the diameter of a probes ruby tip. It's important that the probe is concentric before beginning. The probe must be inside of the gauge and roughly centered. The routine will set the diameter of your probe tip and the radius can been seen in the tool table. + +`A`is the inside diameter of the ring gauge. + +![CALIBRATEPROBERING](images/probeRingGuage.PNG) + +_Figure 3. Probe Diameter Calibration_ +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 | G Code | "Macro Name" | Macro Argument | @@ -217,8 +341,12 @@ _Figure 3a. Probe Diameter Calibration (ring gauge)_ _Table 4. Calibrate Probe Radius Syntax_ +<<<<<<< HEAD *This macro has an optional argument `A`. By default you can call the macro without any arguments, which pulls the diameter stored in `PROBECONFIG/M800 @93` or have the option to temporarily override this using the optional D argument. +======= +*This macro has an optional argument `A`. By default, you can call the macro without any arguments, which pulls the diameter stored in `PROBECONFIG @129` or have the option to override +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 Example MDI Command: G65 "CALIBRATEPROBERING" Example MDI Command: M803 D19.998 @@ -257,12 +385,18 @@ It has two run modes: one where you set the probing location, and once where the | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | -| G65 | "FINDCOR" | A | W | S | +| G65 | "FINDCOR" | A | W | S* | The `A` argument lists the WCS to save the COR into. The `W` argument is optional, but sets the width of the reference artifact. The default value is 1.0. +<<<<<<< HEAD The `S` argument is optional, and determines which mode the macro runs in. If not provided, then the macro uses the saved probing location to re-find the COR regardless of where the A axis or probe is located when starting the macro. If provided, then the probe's initial location is saved before running the macro. +======= +*The `S` argument is optional, and determines which mode the macro runs in. + - If not provided, then the macro uses the saved probing location to re-find the COR regardless of where the A axis or probe is located when starting the macro. + - If provided, then the probe's initial location is saved before running the macro. +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 Example MDI Command to run in saving mode: G65 "FINDCOR" A58. S1.0 Example MDI Command to run in re-find mode with a larger artifact: G65 "FINDCOR" A58. W2.0 @@ -272,45 +406,78 @@ Example MDI Command to run in re-find mode with a larger artifact: G65 "FINDCOR" ### PROBEX ( M814 ) +<<<<<<< HEAD The Probe X macro probes the side of a part in the X direction. +======= +The Probe X macro probes the side of a part in the X direction. + +`A` is the selected work coordinate (54-59 or 54.01-54.99). +`B` is the distance to probe in X. +`B` can be a positive or negative value depending on which side of the stock you would like to probe. + - If `B` is too small, the macro will report an error at the end of the routine. +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 `A` is the selected work coordinate ( 54-59 or 54.01-54.99 ). `X` is the distance to probe : * `X` Can be a positive or negative value depending on which side of the stock you would like to probe. * If `X` is too small, the macro will report an error at the end of the routine. +<<<<<<< HEAD ![probeX](images/probeX.png) _Figure 4. Probe X Routine_ +======= +_Figure 4. Probe X Routine_ +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 | G Code | "Macro Name" | Macro Argument | Macro Argument | | --- | --- | --- | --- | | G65 | "PROBEX" | A | X | -_Table 5. Probe X Syntax_ +_Table 5. Probe X Syntax_ +<<<<<<< HEAD Example MDI Command To Probe Right Side: G65 "PROBEX" A54.0 X-1 Example MDI Command To Probe Left Side: M814 A54.0 X1 --- +======= +Example MDI Command To Probe Right Side: G65 "PROBEX" A54.0 B-1 + +Example MDI Command To Probe Left Side: G65 "PROBEX" A54.0 B1 +*** +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 ### PROBEY ( M815 ) The Probe Y macro probes the side of a part in the Y direction. +<<<<<<< HEAD +======= + +`A` is the selected work coordinate (54-59 or 54.01-54.99). +`B` is the distance to probe in Y. +`B` can be a positive or negative value depending on which side of the stock you would like to probe. + - If `B` is too small, the macro will report an error at the end of the routine. +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 `A` is the selected work coordinate ( 54-59 or 54.01-54.99 ). `Y` is the distance to probe: * `Y` Can be a positive or negative value depending on which side of the stock you would like to probe. * If `Y` is too small, the macro will report an error at the end of the routine. +<<<<<<< HEAD ![probeY](images/probeY.png) _Figure 5. Probe Y Routine_ +======= +_Figure 5. Probe Y Routine_ +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 | G Code | "Macro Name" | Macro Argument | Macro Argument | | --- | --- | --- | --- | | G65 | "PROBEY" | A | Y | -_Table 6. Probe Y Syntax_ +_Table 6. Probe Y Syntax_ +<<<<<<< HEAD Example MDI Command To Probe the Front : G65 "PROBEY" A54.02 Y1. Example MDI Command To Probe the Back : M815 A54.02 Y-1. @@ -326,11 +493,30 @@ The Probe Z macro probes the top surface of a part in the negative Z direction. ![probeZ](images/probeZ.png) _Figure 6. Probe Z Routine_ +======= +Example MDI Command To Probe the Front: G65 "PROBEY" A54.02 B1. + +Example MDI Command To Probe the Back : G65 "PROBEY" A54.02 B-1. +*** + +### PROBEZ + +The Probe Z macro probes the top surface of a part in the negative Z direction. + +`A` is the selected work coordinate (54-59 or 54.01-54.99). +`B` is the distance to probe in Z and should be a negative value. + - `B` is too small or a positive value, the macro will report an error at the end of the routine. + +![probeZ](images/probeZ.png) + +_Figure 6. Probe Z Routine_ +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 | G Code | "Macro Name" | Macro Argument | Macro Argument | | --- | --- | --- | --- | | G65 | "PROBEZ" | A | Z | +<<<<<<< HEAD _Table 7. Probe Z Syntax_ Example MDI Command: G65 "PROBEZ" A54. Z-0.5 @@ -338,14 +524,32 @@ Example MDI Command: M816 A54. Z-0.5 --- ### PROBEXWEB ( M824 ) +======= +_Table 7. Probe Z Syntax_ + +Example MDI Command: G65 "PROBEZ" A54. B-0.5 +*** +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 The Probe X Web macro probes two sides of the stock in the X direction and calculates the center. +<<<<<<< HEAD `A` is the selected work coordinate ( 54-59 or 54.01-54.99 ). `X` is the length of the stock. `Z` is the distance the probe should move in Z below the edges of the stock. `Q` enables inspection reporting which pops up a calculated length after the routine finishes. * The Probe should be roughly centered and above the stock before beginning. +======= +The Probe X Web macro probes two sides of the stock in the X direction and calculates the center. + +`A` is the selected work coordinate (54-59 or 54.01-54.99). +`B` is the length of the stock. +`C` is the distance the probe should move in Z below the edges of the stock. +`Q` enables inspection reporting, which pops up a calculated length after the routine finishes. + - The Probe should be roughly centered and above the stock before beginning. + +![probeXweb](images/probeXweb.png) +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 ![probeXweb](images/probeXweb.png) _Figure 7. Probe X Web Routine_ @@ -359,10 +563,25 @@ _Table 8. Probe X Web Syntax_ Example MDI Command With Inspection Report: M824 A54.12 X3. Z-.5 Q1. Example MDI Command : G65 "PROBEXWEB" A54.12 X3. Z-.5 Q0. +<<<<<<< HEAD --- ### PROBEYWEB ( M825 ) The Probe Y Web macro probes two sides of the stock in the Y direction and calculates the center. +======= +Example MDI Command With Inspection Report: G65 "PROBEXWEB" A54.12 B3. C-.5 Q1. +*** + +### PROBEYWEB + +The Probe Y Web macro probes two sides of the stock in the Y direction and calculates the center. + +`A` is the selected work coordinate (54-59 or 54.01-54.99). +`B` is the width of the stock. +`C` is the distance the probe should move in Z below the edges of the stock. +`Q` enables inspection reporting which pops up a calculated width after the routine finishes. + - The Probe should be roughly centered and above the stock before beginning. +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 `A` is the selected work coordinate ( 54-59 or 54.01-54.99 ). `Y` is the width of the stock. @@ -370,15 +589,20 @@ The Probe Y Web macro probes two sides of the stock in the Y direction and calcu `Q` enables inspection reporting which pops up a calculated width after the routine finishes. * The Probe should be roughly centered and above the stock before beginning. +<<<<<<< HEAD ![probeYweb](images/probeYweb.png) _Figure 8. Probe Y Web Routine_ +======= +_Figure 8. Probe Y Web Routine_ +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | --- | | G65 | "PROBEYWEB" | A | Y | Z | Q | -_Table 9. Probe Y Web Syntax_ +_Table 9. Probe Y Web Syntax_ +<<<<<<< HEAD Example MDI Command: G65 "PROBEYWEB" A58. Y2. Z-.5 Q0. Example MDI Command With Inspection Report: M825 A58. Y2. Z-.5 Q1. @@ -394,13 +618,59 @@ The Probe Bore macro probes 4 points inside of a bore and calculates the center. ![probeBore](images/probeBore.png) _Figure 10. Probe Bore Routine_ +======= +Example MDI Command Without Inspection Report: G65 "PROBEYWEB" A58. B2. C-.5 Q0. + +Example MDI Command With Inspection Report: G65 "PROBEYWEB" A58. B2. C-.5 Q1. +*** + +### PROBECIRCULARBOSS + +The Probe Circular Boss macro probes 4 points of a circular boss and calculates the center. + +`A` is the selected work coordinate (54-59 or 54.01-54.99). +`B` is the diameter of the stock. +`C` is the distance the probe should move in Z below the edges of the stock. +`D` turns on a second +`Q` enables inspection reporting, which pops up a calculated diameter after the routine finishes. + - The Probe should be roughly centered and above the stock before beginning. + +![probeCircularBoss](images/probeCircularBoss.png) + +_Figure 9. Probe Circular Boss Routine_ + +| G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | Macro Argument | +| --- | --- | --- | --- | --- | --- | +| G65 | "PROBECIRCULARBOSS" | A | B | C | Q | + +_Table 10. Probe Circular Boss Syntax_ + +Example MDI Command Without Inspection Report: G65 "PROBECIRCULARBOSS" A54.01 B2. C-.5 Q0. + +Example MDI Command With Inspection Report: G65 "PROBECIRCULARBOSS" A54.01 B2. C-.5 Q1. +*** + +### PROBEBORE + +The Probe Bore macro probes 4 points inside a bore and calculates the center. + +`A` is the selected work coordinate (54-59 or 54.01-54.99). +`B` is the diameter of the bore. +`Q` enables inspection reporting, which pops up a calculated diameter after the routine finishes. + - The Probe should be roughly centered and inside the bore before beginning. + +![probeBore](images/probeBore.png) + +_Figure 10. Probe Bore Routine_ +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | | G65 | "PROBEBORE" | A | D | Q | -_Table 11. Probe Bore Syntax_ +_Table 11. Probe Bore Syntax_ +<<<<<<< HEAD Example MDI Command : G65 "PROBEBORE" A54.02 D1. Q0. Example MDI Command With Inspection Reporting: M830 A54.02 D1. Q1. @@ -417,6 +687,23 @@ The Probe Circular Boss macro probes 4 points of a circular boss and calculates ![probeCircularBoss](images/probeCircularBoss.png) _Figure 9. Probe Circular Boss Routine_ +======= +Example MDI Command Without Inspection Reporting: G65 "PROBEBORE" A54.02 B1. Q0. + +Example MDI Command With Inspection Reporting: G65 "PROBEBORE" A54.02 B1. Q1. +*** + +### PROBERECTANGULARBOSS + +The Probe Rectangular Boss macro probes all sides of the stock and calculates the center. + +`A` is the selected work coordinate (54-59 or 54.01-54.99). +`B` is the length of the boss in X +`C` is the width of the boss in Y. +`D` is the distance the probe should move in Z below the edges of the body and should be a negative value. +`Q` enables inspection reporting, which pops up a calculated length and width after the routine finishes. + - The Probe should be roughly centered and above the stock before beginning. +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | --- | @@ -427,6 +714,7 @@ _Table 10. Probe Circular Boss Syntax_ Example MDI Command: G65 "PROBECIRCULARBOSS" A54.01 D2. Z-.5 Q0. Example MDI Command With Inspection Report: M831 A54.01 D2. Z-.5 Q1. +<<<<<<< HEAD --- ### PROBEPOCKET ( M820 ) @@ -440,13 +728,36 @@ The Probe Pocket macro probes all internal sides of a pocket and calculates the ![probeRectangularPocket](images/probeRectangularPocket.png) _Figure 12. Probe Pocket Routine_ +======= +_Table 12. Probe Rectangular Boss Syntax_ + +Example MDI Command Without Inspect Reporting: G65 "PROBERECTANGULARBOSS" A54. B3. C2. D-.5 Q0. + +Example MDI Command Without Inspect Reporting: G65 "PROBERECTANGULARBOSS" A54. B3. C2. D-.5 Q1. +*** + +### PROBEPOCKET + +The Probe Pocket macro probes all internal sides of a pocket and calculates the center. + +`A` is the selected work coordinate (54-59 or 54.01-54.99). +`B` is the length of the pocket in X +`C` is the width of the pocket in Y. +`Q` enables inspection reporting, which pops up a calculated length and width after the routine finishes. + - The Probe should be roughly centered and inside the pocket before beginning. + +![probeRectangularPocket](images/probeRectangularPocket.png) + +_Figure 12. Probe Pocket Routine_ +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | --- | | G65 | "PROBEPOCKET" | A | X | Y | Q | -_Table 13. Probe Rectangular Pocket Syntax_ +_Table 13. Probe Rectangular Pocket Syntax_ +<<<<<<< HEAD Example MDI Command: G65 "PROBERECTANGULARPOCKET" A54.05 X2. Y3. Q0. Example MDI Command Without Inspection Reporting: M820 A54.05 X2. Y3. Q1. @@ -461,10 +772,26 @@ The Probe Rectangular Boss macro probes all sides of the stock and calculates th `Z` is the distance the probe should move in Z below the edges of the body and should be a negative value. `Q` enables inspection reporting which pops up a calculated length and width after the routine finishes. * The Probe should be roughly centered and above the stock before beginning. +======= +Example MDI Command Without Inspection Reporting: G65 "PROBERECTANGULARPOCKET" A54.05 B2. C3. Q0. + +Example MDI Command Without Inspection Reporting: G65 "PROBERECTANGULARPOCKET" A54.05 B2. C3. Q1. +*** + +### PROBEXSLOT + +The Probe Slot X macro probes the internal sides of a pocket in the X direction and calculates the center. + +`A` is the selected work coordinate (54-59 or 54.01-54.99). +`B` is the length of the pocket in X. +`Q` enables inspection reporting, which pops up a calculated length after the routine finishes. + - The Probe should be roughly centered and inside the slot before beginning. +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 ![probeRectangularBoss](images/probeRectangularBoss.png) _Figure 11. Probe Rectangular Boss Routine_ +<<<<<<< HEAD | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | --- | --- | | G65 | "PROBERECTANGULARBOSS" | A | X | Y | Z | Q | @@ -486,13 +813,17 @@ The Probe Slot X macro probes the internal sides of a pocket in the X direction ![probeSlot](images/probeSlot.png) _Figure 13. Probe Slot Routine_ +======= +_Figure 13. Probe Slot Routine_ +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | | G65 | "PROBESLOTX" | A | X | Q | -_Table 14. Probe Slot Syntax_ +_Table 14. Probe Slot Syntax_ +<<<<<<< HEAD Example MDI Command With Inspectioning: G65 "PROBESLOTX" A54. X3. Q1. Example MDI Command Without Inspectioning: M834 A54. X3. Q0. @@ -500,21 +831,41 @@ Example MDI Command Without Inspectioning: M834 A54. X3. Q0. ### PROBEYSLOT ( M835 ) The Probe Slot Y macro probes the internal sides of a pocket in the Y direction and calculates the center. +======= +Example MDI Command Without Inspectioning: G65 "PROBESLOTX" A54. B3. Q0. + +Example MDI Command Without Inspectioning: G65 "PROBESLOTX" A54. B3. Q1. +*** + +### PROBEYSLOT + +The Probe Slot Y macro probes the internal sides of a pocket in the Y direction and calculates the center. + +`A` is the selected work coordinate (54-59 or 54.01-54.99). +`B` is the width of the pocket in Y. +`Q` enables inspection reporting, which pops up a calculated width after the routine finishes. + - The Probe should be roughly centered and inside the slot before beginning. +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 `A` is the selected work coordinate ( 54-59 or 54.01-54.99 ). `Y` is the width of the pocket in Y. `Q` enables inspection reporting which pops up a calculated width after the routine finishes. * The Probe should be roughly centered and inside of the slot before beginning. +<<<<<<< HEAD ![probeSlotY](images/probeSlotY.PNG) _Figure 14. Probe Slot Routine_ +======= +_Figure 14. Probe Slot Routine_ +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | | G65 | "PROBESLOTY" | A | Y | Q | -_Table 15. Probe Slot Syntax_ +_Table 15. Probe Slot Syntax_ +<<<<<<< HEAD Example MDI Command: G65 "PROBESLOTY" A54. YB3. Q0. Example MDI Command With Inspection Reporting: M835 A54. Y3. Q1. @@ -522,26 +873,75 @@ Example MDI Command With Inspection Reporting: M835 A54. Y3. Q1. ### PROBEINSIDECORNER ( M837 ) The Probe inside Corner macro probes the inside edges of a pocket and calculates the center. +======= +Example MDI Command Without Inspection Reporting: G65 "PROBESLOTY" A54. B3. Q0. + +Example MDI Command With Inspection Reporting: G65 "PROBESLOTY" A54. B3. Q1. +*** + +### PROBEOUTSIDECORNER + +The Probe Outside Corner macro probes the outside edges of the stock and calculates the center. + +`A`is the selected work coordinate (54-59 or 54.01-54.99). +`B` Selects the desired corner to probe. +`C` is the distance to travel away from the initial location before probing begins. +`D` is the probing distance for both X and Y. + - The Probe should be roughly centered, diagonally from the corner before beginning. + +![probeExternalCorner](images/probeExternalCorner.png) + +_Figure 15. Probe Outside Corner Routine_ + +| G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | Macro Argument | +| --- | --- | --- | --- | --- | --- | +| G65 | "PROBEOUTSIDECORNER" | A | B | C | D | + +_Table 16. Probe Outer Corner Syntax_ + +Example MDI Command: G65 "PROBEOUTSIDECORNER" A54. B1. C1 D.5 +*** + +### PROBEINSIDECORNER + +The Probe inside Corner macro probes the inside edges of a pocket and calculates the center. + +`A` is the selected work coordinate (54-59 or 54.01-54.99). +`B` is the desired corner to probe. +`C` is the probing distance. + - The Probe should be roughly centered, diagonally from the corner before beginning. +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 `A` is the selected work coordinate ( 54-59 or 54.01-54.99 ). `C` the desired corner to probe. `E` is the engage distance to probe part. * The Probe should be roughly centered, diagonaly from the corner before beginning. +<<<<<<< HEAD ![probeInternalCorner](images/probeInternalCorner.png) _Figure 16. Probe Inside Corner Routine_ +======= +_Figure 16. Probe Inside Corner Routine_ +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | | G65 | "PROBEINSIDECORNER" | A | C | E | -_Table 17. Probe Inner Corner Syntax_ +_Table 17. Probe Inner Corner Syntax_ +<<<<<<< HEAD Example MDI Command: G65 "PROBEINSIDECORNER" A54. C1. E.5 Example MDI Command: M837 A54. C1. E.5 --- ### PROBEOUTSIDECORNER ( M838 ) +======= +Example MDI Command: G65 "PROBEINSIDECORNER" A54. B1. C.5 + + +## SUPPORTED FUSION 360 PROBING FEATURES +>>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 The Probe Outside Corner macro probes the outside edges of the stock and calculates the center. From d16479622946f5eb42605423c85eac503a0b07d5 Mon Sep 17 00:00:00 2001 From: Robot Oblivion Date: Tue, 15 Apr 2025 19:41:47 +1200 Subject: [PATCH 17/21] 2nd try and getting this to upload... --- README.md | 436 +++--------------------------------------------------- 1 file changed, 18 insertions(+), 418 deletions(-) diff --git a/README.md b/README.md index 22ef5e5..32a4ffd 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ The tormach wired probe works, with and without the xoomspeed wireless kit. All the macros need to be stored in the same file as your posted gcode programs. Always test the macros with MPG DRN the first time. SYIL configurations may change and we're not responsible for broken tips or machine crashes. This macro set will work for both wired and (some wireless probes) and now supports probes that require special macros to turn on and off. +## Probe Configuration Macro + ### Imperial vs Metric units The various probing parameters must be set in your desired units sections in the configuration file. No other changes are needed to configure the units. @@ -25,7 +27,6 @@ Start with the recommended settings and fine tune from there. Please set your fusion 360 probing feed rate to the same value that you use in the config macro. If you decide to change feed rates, you should always run calibration again. -<<<<<<< HEAD ### Configuration setup Every probing routine calls the configuration macro to initialize global variables to allow all probing parameters to be specified in one place. @@ -50,93 +51,35 @@ Using the editor of your choice, open `PROBECONFIG` or `M800` and update the fol > **Note:** Any WCS number from 01-09 should be entered with a leading zero. - **`@103`, `@104`, `@105`, `@109`, `@110`** – Probing and tool-setting speeds are separated into metric and imperial sections, with safe default values that can be adjusted if needed. -======= -## Probe Configuration - -### Configuration Macro setup -Every probing routine calls the configuration macro to initialize global variables. -This is contained in `PROBECONFIG` -It allows all probing parameters to be specified in one place. - -Using the editor of your choice, in the **`Macros for controller`** folder open `PROBECONFIG` and update the following parameters: - -**`@100`** – Set this to the tool number you want to use for your probe. Common choices include Tool 12 or Tool 99. -**`@111`** – Extended work offset number used to store the Z calibration artifact WCS, aiding in faster recalibration. -**`@112`** – Extended work offset number used to store the tool setter's XY center location. -**`@113`** – Extended work offset number used to store the 4th-axis corner probing start point. -**`@137`** – Highest offset that can be updated, defining a protected WCS range. -> [!NOTE] -> Extended WCS numbers G54 P01-09 require a leading zero - -**`@128`** – Disables extra spindle orientation calls for probes that spin on/off. -**`@109`** – Calibrated length of your master gauge tool. -**`@129`** – Calibrated diameter of your ring gauge. -> [!IMPORTANT] -> These dimensions are critical for calibrating your tool setter and ensuring accurate tool length measurements. -> Default values are provided, but you should input the exact values from your gauge tool's certificate. -**`@103`, `@104`, `@105`, `@116`, `@117`** – Probing and tool-setting speeds are separated into metric and imperial sections, with safe default values that can be adjusted if needed. ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 - -**`@106`** – Probe clearance distance. This is the extra distance the probe moves beyond what the macro expects as the edge of the surface. +- **`@106`** – Probe clearance distance. This is the extra distance the probe moves beyond what the macro expects as the edge of the surface. > *Example:* If probing a circular boss with a specified diameter of 1", the probe will move `[0.5" + @106]` away from the initial point. -<<<<<<< HEAD - **`@107`** – Probe backoff distance. Probing routines use a double-touch method: -======= -**`@108`** – Probe backoff distance. Probing routines use a double-touch method: ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 1. The first touch is fast. 2. The second touch is slow (for higher accuracy). After the first touch, the probe will back off by `@107` (in inches or mm, depending on your control setup). > This value must be large enough to allow the probe to fully disengage from the surface, plus some clearance, but no larger than necessary. -<<<<<<< HEAD - **`@108`** – Default value used when a tolerance argument is required but not provided. - **`@91`** – Rounding multiplier for many probing messages. Adjust as needed to control the precision of user messages. Once you have saved your changes to `PROBECONFIG` or `M800` copy all files within the **`Macros for controller`** folder to the LNC main NC files directory or copy all files within the **`maker_macros`** folder to the LNC Maker_Macro folder if you would prefer to run Mcode based macros -======= -**`@110`** – Default value used when a tolerance argument is required but not provided. -**`@11`** – Rounding multiplier for many probing messages. Adjust as needed to control the precision of user messages. - -> [!TIP] -> Once you have saved your changes to `PROBECONFIG` copy all files within the **`Macros for controller`** folder to the LNC main NC files directory. ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 +## Pre-calibration tasks -## **Backup and Preparation for Calibration** +### Backup your controller and prep for running the calibration -<<<<<<< HEAD 1. Backup your tool table, offset table and `@10`, `@91-@98`, `@100-@110`, `@112-@115`,`@130-@134`, `@980-@987` and `@5109` variables in case of wanting to revert 2. Clear as many items as possible from the table to prevent collisions with stock, jigs, fixtures, or vices. 3. Ensure the table zero point or area to place your calibration object is empty, lightly stoned, and free of coolant. 4. Have your master tool, probe, and ring gauge/gauge block ready. -======= -Before running the calibration process, follow these steps to ensure a smooth setup: - -1. **Backup Your Controller Data:** - - Save a copy of your tool table, offset table, and the following variables in case you need to revert: - `@10`, `@11`, `@100-@117`, `@127-@133`, `@980-@987`, `@1508` -2. **Prepare the Work Area:** - - Clear as many items as possible from the table to avoid collisions with stock, jigs, fixtures, or vices. - - Ensure the table zero point or the area where you will place the calibration object is **empty, lightly stoned, and free of coolant**. - -3. **Gather Required Tools:** - - Have your **master tool, probe, and ring gauge/gauge block** ready. ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 -### **Basic Probe Setup** - -Before running any calibration routines, you must ensure that your probe is concentric. - -. **Check Concentricity:** - - Place a **dial indicator** on the ruby tip of the probe. - - Rotate the probe in the spindle **by hand** while observing the dial indicator. +### Basic Probe Setup -. **Adjust the Probe:** - - Adjust the probe until the dial indicator **does not move** or shows deviation within a few tenths. - - This step is crucial for accurate probing results. +Before performing any calibration routines your probe must be concentric. +To make your probe concentric you must place a dial indicator on the ruby tip and rotate the probe in the spindle by hand. +Adjust your probe until the dial indicator doesn't move or is within a few tenths. ![probeIndicate](images/probeIndicate.jpg) _Figure 2. Indicating Probe_ @@ -145,7 +88,6 @@ _Figure 2. Indicating Probe_ ### Basic toolsetter setup -<<<<<<< HEAD Before you do any toolsetting, you need to tell the control where the toolsetter is. You should manually move your spindle to be located over the center of your toolsetter. @@ -159,30 +101,6 @@ The toolsetting location will be X0 Y0 in G54 P`@113`. ## Macro Syntax Depending on which file pack is installed, macros are called using either `G65 "FILENAME"` or M-code numbers (if you've installed the Maker_macro version). -======= -Before performing any tool setting, you must define the tool setter's location in the control system. - - A. **If the tool setter's location is known**, copy its XY offset to the extended work offset specified in `PROBECONFIG @112`. - - B. **If the tool setter's location is unknown, manually position the spindle over its center:** - - Use the MPG to move the gauge tool until it appears centered by eye. - - For higher precision, use a dial indicator or coaxial indicator to sweep around until perfectly centered. - - B. **Once the correct location is found, save it using the `TEACH IN` function** in the offsets page. - - Store this location as the XY origin of the extended work offset specified in `PROBECONFIG @112`. - -> [!TIP] ->The toolsetting location will be X0 Y0 in G54 P`@112`. - ---- -## **Macro Syntax** - -Macros are called with G65 as opposed to M codes to speed up execution. G65 is followed by the macro name and whatever arguments need passed into the macro. The example below shows how to probe the side of a part along the X axis. The A argument is the work offset and the B argument is the probing distance. Each argument starts with a letter followed by a value. For example, a macro requiring three arguments will have A#, B# and C# after the macro name. Simply copy the macro examples into your MDI and adjust the arguments according to your needs. A table mapping the macro arguments to local variables is also provided below. - -> [!IMPORTANT] -> Extended G54 work offsets are supported with the use of a decimal point. -> For example, G54 P5 can be entered into the A argument as **A54.05** (_G54 P01-09 require a leading zero_). ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 To pass data into a macro arguments are used and starts with a letter followed by a value. For example, a macro requiring three arguments will have `A#`, `B#` and `C#` after the macro name. Simply copy the macro examples into your MDI and adjust the arguments according to your needs. > **Note:** Both G65 and M-code macros accept the same arguments @@ -241,13 +159,8 @@ The first time you use this macro, you will start by setting the calibration hei *This macro has an optional argument `A`. By default you can call the macro without any arguments, which does a quick calibration using an stored location/height for the artifact. -<<<<<<< HEAD Example MDI Command: G65 "CALIBRATEPROBEZ" A1 Example MDI Command: M803 A1 -======= -> [!IMPORTANT] -> The first time you call it make sure to include the `A` argument and run the full calibration procedure. ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 > [!WARNING] >The first time you call it make sure to include the `A` argument and run the full calibration procedure. @@ -276,15 +189,11 @@ Once you have done the full calibration one time, you can use a quick version of the macro to recalibrate the probe offset without the need to use the master tool. But you must re-install your calibration artifact onto your table before calling this macro. -<<<<<<< HEAD This will move the table to the origin configured in the `PROBECONFIG` or `M800` macro and then do a protected move to calibrate the probe offset. Example MDI Command: G65 "CALIBRATEPROBEZ" Example MDI Command: M803 -======= -This will move the table to the origin of the saved WCS specified in (`PROBECONFIG @111`) and then do a protected move to calibrate the probe offset. ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 ## Probe Tip Diameter Calibration @@ -295,44 +204,11 @@ You can use one of the two provided calibration methods: ### CALIBRATEPROBERING ( M803 ) -<<<<<<< HEAD This macro uses a ring gauge to calibrate the diameter of the probe's ruby tip. The routine will determine the diameter of the probe tip, and the calculated radius will be visible in the tool table. * Before starting, ensure that the probe is concentric and positioned inside the ring gauge, roughly centered. ![CALIBRATEPROBERING](images/probeRingGuage.PNG) _Figure 3a. Probe Diameter Calibration (ring gauge)_ -======= -This macro uses a gauge block to calibrate the diameter of a probes ruby tip. -It's important that the probe is concentric before beginning. -Any good quality reference block artifact would be used, such as an actual gauge block or a high quality 123 block. -If you are not using a calibrated reference artifact, you should use a well calibrated micrometer to measure your 123 block to get its true dimensions. -123 blocks, even high quality ones, are commonly sold a few ten thousandths of an inch oversized to allow for lapping -and you want to put the true dimension into the macro arguments. -`A` is the gauge block's true X dimension -`B` is the gauge block's true Y dimension -`C` is the amount of Z drop you want between your initial position and the measurement height. It needs to be a negative value. - -![CALIBRATEPROBEBLOCK](images/calibrateprobeblock.png) - -| GCode | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | -| --- | --- | --- | --- | --- | -| G65 | "CALIBRATEPROBEBLOCK" | A | B | C | - -_Table 2. Calibrate Probe X Syntax_ - -Example MDI Command: G65 "CALIBRATEPROBEBLOCK" A1.0002 B2.0001 C-0.5 - - -#### CALIBRATEPROBERING - -This macro uses a ring gauge to calibrate the diameter of a probes ruby tip. It's important that the probe is concentric before beginning. The probe must be inside of the gauge and roughly centered. The routine will set the diameter of your probe tip and the radius can been seen in the tool table. - -`A`is the inside diameter of the ring gauge. - -![CALIBRATEPROBERING](images/probeRingGuage.PNG) - -_Figure 3. Probe Diameter Calibration_ ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 | G Code | "Macro Name" | Macro Argument | @@ -341,12 +217,8 @@ _Figure 3. Probe Diameter Calibration_ _Table 4. Calibrate Probe Radius Syntax_ -<<<<<<< HEAD *This macro has an optional argument `A`. By default you can call the macro without any arguments, which pulls the diameter stored in `PROBECONFIG/M800 @93` or have the option to temporarily override this using the optional D argument. -======= -*This macro has an optional argument `A`. By default, you can call the macro without any arguments, which pulls the diameter stored in `PROBECONFIG @129` or have the option to override ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 Example MDI Command: G65 "CALIBRATEPROBERING" Example MDI Command: M803 D19.998 @@ -385,18 +257,12 @@ It has two run modes: one where you set the probing location, and once where the | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | -| G65 | "FINDCOR" | A | W | S* | +| G65 | "FINDCOR" | A | W | S | The `A` argument lists the WCS to save the COR into. The `W` argument is optional, but sets the width of the reference artifact. The default value is 1.0. -<<<<<<< HEAD The `S` argument is optional, and determines which mode the macro runs in. If not provided, then the macro uses the saved probing location to re-find the COR regardless of where the A axis or probe is located when starting the macro. If provided, then the probe's initial location is saved before running the macro. -======= -*The `S` argument is optional, and determines which mode the macro runs in. - - If not provided, then the macro uses the saved probing location to re-find the COR regardless of where the A axis or probe is located when starting the macro. - - If provided, then the probe's initial location is saved before running the macro. ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 Example MDI Command to run in saving mode: G65 "FINDCOR" A58. S1.0 Example MDI Command to run in re-find mode with a larger artifact: G65 "FINDCOR" A58. W2.0 @@ -406,78 +272,45 @@ Example MDI Command to run in re-find mode with a larger artifact: G65 "FINDCOR" ### PROBEX ( M814 ) -<<<<<<< HEAD The Probe X macro probes the side of a part in the X direction. -======= -The Probe X macro probes the side of a part in the X direction. - -`A` is the selected work coordinate (54-59 or 54.01-54.99). -`B` is the distance to probe in X. -`B` can be a positive or negative value depending on which side of the stock you would like to probe. - - If `B` is too small, the macro will report an error at the end of the routine. ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 `A` is the selected work coordinate ( 54-59 or 54.01-54.99 ). `X` is the distance to probe : * `X` Can be a positive or negative value depending on which side of the stock you would like to probe. * If `X` is too small, the macro will report an error at the end of the routine. -<<<<<<< HEAD ![probeX](images/probeX.png) _Figure 4. Probe X Routine_ -======= -_Figure 4. Probe X Routine_ ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 | G Code | "Macro Name" | Macro Argument | Macro Argument | | --- | --- | --- | --- | | G65 | "PROBEX" | A | X | -_Table 5. Probe X Syntax_ +_Table 5. Probe X Syntax_ -<<<<<<< HEAD Example MDI Command To Probe Right Side: G65 "PROBEX" A54.0 X-1 Example MDI Command To Probe Left Side: M814 A54.0 X1 --- -======= -Example MDI Command To Probe Right Side: G65 "PROBEX" A54.0 B-1 - -Example MDI Command To Probe Left Side: G65 "PROBEX" A54.0 B1 -*** ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 ### PROBEY ( M815 ) The Probe Y macro probes the side of a part in the Y direction. -<<<<<<< HEAD -======= - -`A` is the selected work coordinate (54-59 or 54.01-54.99). -`B` is the distance to probe in Y. -`B` can be a positive or negative value depending on which side of the stock you would like to probe. - - If `B` is too small, the macro will report an error at the end of the routine. ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 `A` is the selected work coordinate ( 54-59 or 54.01-54.99 ). `Y` is the distance to probe: * `Y` Can be a positive or negative value depending on which side of the stock you would like to probe. * If `Y` is too small, the macro will report an error at the end of the routine. -<<<<<<< HEAD ![probeY](images/probeY.png) _Figure 5. Probe Y Routine_ -======= -_Figure 5. Probe Y Routine_ ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 | G Code | "Macro Name" | Macro Argument | Macro Argument | | --- | --- | --- | --- | | G65 | "PROBEY" | A | Y | -_Table 6. Probe Y Syntax_ +_Table 6. Probe Y Syntax_ -<<<<<<< HEAD Example MDI Command To Probe the Front : G65 "PROBEY" A54.02 Y1. Example MDI Command To Probe the Back : M815 A54.02 Y-1. @@ -493,30 +326,11 @@ The Probe Z macro probes the top surface of a part in the negative Z direction. ![probeZ](images/probeZ.png) _Figure 6. Probe Z Routine_ -======= -Example MDI Command To Probe the Front: G65 "PROBEY" A54.02 B1. - -Example MDI Command To Probe the Back : G65 "PROBEY" A54.02 B-1. -*** - -### PROBEZ - -The Probe Z macro probes the top surface of a part in the negative Z direction. - -`A` is the selected work coordinate (54-59 or 54.01-54.99). -`B` is the distance to probe in Z and should be a negative value. - - `B` is too small or a positive value, the macro will report an error at the end of the routine. - -![probeZ](images/probeZ.png) - -_Figure 6. Probe Z Routine_ ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 | G Code | "Macro Name" | Macro Argument | Macro Argument | | --- | --- | --- | --- | | G65 | "PROBEZ" | A | Z | -<<<<<<< HEAD _Table 7. Probe Z Syntax_ Example MDI Command: G65 "PROBEZ" A54. Z-0.5 @@ -524,32 +338,14 @@ Example MDI Command: M816 A54. Z-0.5 --- ### PROBEXWEB ( M824 ) -======= -_Table 7. Probe Z Syntax_ - -Example MDI Command: G65 "PROBEZ" A54. B-0.5 -*** ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 The Probe X Web macro probes two sides of the stock in the X direction and calculates the center. -<<<<<<< HEAD `A` is the selected work coordinate ( 54-59 or 54.01-54.99 ). `X` is the length of the stock. `Z` is the distance the probe should move in Z below the edges of the stock. `Q` enables inspection reporting which pops up a calculated length after the routine finishes. * The Probe should be roughly centered and above the stock before beginning. -======= -The Probe X Web macro probes two sides of the stock in the X direction and calculates the center. - -`A` is the selected work coordinate (54-59 or 54.01-54.99). -`B` is the length of the stock. -`C` is the distance the probe should move in Z below the edges of the stock. -`Q` enables inspection reporting, which pops up a calculated length after the routine finishes. - - The Probe should be roughly centered and above the stock before beginning. - -![probeXweb](images/probeXweb.png) ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 ![probeXweb](images/probeXweb.png) _Figure 7. Probe X Web Routine_ @@ -563,25 +359,10 @@ _Table 8. Probe X Web Syntax_ Example MDI Command With Inspection Report: M824 A54.12 X3. Z-.5 Q1. Example MDI Command : G65 "PROBEXWEB" A54.12 X3. Z-.5 Q0. -<<<<<<< HEAD --- ### PROBEYWEB ( M825 ) The Probe Y Web macro probes two sides of the stock in the Y direction and calculates the center. -======= -Example MDI Command With Inspection Report: G65 "PROBEXWEB" A54.12 B3. C-.5 Q1. -*** - -### PROBEYWEB - -The Probe Y Web macro probes two sides of the stock in the Y direction and calculates the center. - -`A` is the selected work coordinate (54-59 or 54.01-54.99). -`B` is the width of the stock. -`C` is the distance the probe should move in Z below the edges of the stock. -`Q` enables inspection reporting which pops up a calculated width after the routine finishes. - - The Probe should be roughly centered and above the stock before beginning. ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 `A` is the selected work coordinate ( 54-59 or 54.01-54.99 ). `Y` is the width of the stock. @@ -589,20 +370,15 @@ The Probe Y Web macro probes two sides of the stock in the Y direction and calcu `Q` enables inspection reporting which pops up a calculated width after the routine finishes. * The Probe should be roughly centered and above the stock before beginning. -<<<<<<< HEAD ![probeYweb](images/probeYweb.png) _Figure 8. Probe Y Web Routine_ -======= -_Figure 8. Probe Y Web Routine_ ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | --- | | G65 | "PROBEYWEB" | A | Y | Z | Q | -_Table 9. Probe Y Web Syntax_ +_Table 9. Probe Y Web Syntax_ -<<<<<<< HEAD Example MDI Command: G65 "PROBEYWEB" A58. Y2. Z-.5 Q0. Example MDI Command With Inspection Report: M825 A58. Y2. Z-.5 Q1. @@ -618,59 +394,13 @@ The Probe Bore macro probes 4 points inside of a bore and calculates the center. ![probeBore](images/probeBore.png) _Figure 10. Probe Bore Routine_ -======= -Example MDI Command Without Inspection Report: G65 "PROBEYWEB" A58. B2. C-.5 Q0. - -Example MDI Command With Inspection Report: G65 "PROBEYWEB" A58. B2. C-.5 Q1. -*** - -### PROBECIRCULARBOSS - -The Probe Circular Boss macro probes 4 points of a circular boss and calculates the center. - -`A` is the selected work coordinate (54-59 or 54.01-54.99). -`B` is the diameter of the stock. -`C` is the distance the probe should move in Z below the edges of the stock. -`D` turns on a second -`Q` enables inspection reporting, which pops up a calculated diameter after the routine finishes. - - The Probe should be roughly centered and above the stock before beginning. - -![probeCircularBoss](images/probeCircularBoss.png) - -_Figure 9. Probe Circular Boss Routine_ - -| G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | Macro Argument | -| --- | --- | --- | --- | --- | --- | -| G65 | "PROBECIRCULARBOSS" | A | B | C | Q | - -_Table 10. Probe Circular Boss Syntax_ - -Example MDI Command Without Inspection Report: G65 "PROBECIRCULARBOSS" A54.01 B2. C-.5 Q0. - -Example MDI Command With Inspection Report: G65 "PROBECIRCULARBOSS" A54.01 B2. C-.5 Q1. -*** - -### PROBEBORE - -The Probe Bore macro probes 4 points inside a bore and calculates the center. - -`A` is the selected work coordinate (54-59 or 54.01-54.99). -`B` is the diameter of the bore. -`Q` enables inspection reporting, which pops up a calculated diameter after the routine finishes. - - The Probe should be roughly centered and inside the bore before beginning. - -![probeBore](images/probeBore.png) - -_Figure 10. Probe Bore Routine_ ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | | G65 | "PROBEBORE" | A | D | Q | -_Table 11. Probe Bore Syntax_ +_Table 11. Probe Bore Syntax_ -<<<<<<< HEAD Example MDI Command : G65 "PROBEBORE" A54.02 D1. Q0. Example MDI Command With Inspection Reporting: M830 A54.02 D1. Q1. @@ -687,23 +417,6 @@ The Probe Circular Boss macro probes 4 points of a circular boss and calculates ![probeCircularBoss](images/probeCircularBoss.png) _Figure 9. Probe Circular Boss Routine_ -======= -Example MDI Command Without Inspection Reporting: G65 "PROBEBORE" A54.02 B1. Q0. - -Example MDI Command With Inspection Reporting: G65 "PROBEBORE" A54.02 B1. Q1. -*** - -### PROBERECTANGULARBOSS - -The Probe Rectangular Boss macro probes all sides of the stock and calculates the center. - -`A` is the selected work coordinate (54-59 or 54.01-54.99). -`B` is the length of the boss in X -`C` is the width of the boss in Y. -`D` is the distance the probe should move in Z below the edges of the body and should be a negative value. -`Q` enables inspection reporting, which pops up a calculated length and width after the routine finishes. - - The Probe should be roughly centered and above the stock before beginning. ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | --- | @@ -714,7 +427,6 @@ _Table 10. Probe Circular Boss Syntax_ Example MDI Command: G65 "PROBECIRCULARBOSS" A54.01 D2. Z-.5 Q0. Example MDI Command With Inspection Report: M831 A54.01 D2. Z-.5 Q1. -<<<<<<< HEAD --- ### PROBEPOCKET ( M820 ) @@ -728,36 +440,13 @@ The Probe Pocket macro probes all internal sides of a pocket and calculates the ![probeRectangularPocket](images/probeRectangularPocket.png) _Figure 12. Probe Pocket Routine_ -======= -_Table 12. Probe Rectangular Boss Syntax_ - -Example MDI Command Without Inspect Reporting: G65 "PROBERECTANGULARBOSS" A54. B3. C2. D-.5 Q0. - -Example MDI Command Without Inspect Reporting: G65 "PROBERECTANGULARBOSS" A54. B3. C2. D-.5 Q1. -*** - -### PROBEPOCKET - -The Probe Pocket macro probes all internal sides of a pocket and calculates the center. - -`A` is the selected work coordinate (54-59 or 54.01-54.99). -`B` is the length of the pocket in X -`C` is the width of the pocket in Y. -`Q` enables inspection reporting, which pops up a calculated length and width after the routine finishes. - - The Probe should be roughly centered and inside the pocket before beginning. - -![probeRectangularPocket](images/probeRectangularPocket.png) - -_Figure 12. Probe Pocket Routine_ ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | --- | | G65 | "PROBEPOCKET" | A | X | Y | Q | -_Table 13. Probe Rectangular Pocket Syntax_ +_Table 13. Probe Rectangular Pocket Syntax_ -<<<<<<< HEAD Example MDI Command: G65 "PROBERECTANGULARPOCKET" A54.05 X2. Y3. Q0. Example MDI Command Without Inspection Reporting: M820 A54.05 X2. Y3. Q1. @@ -772,26 +461,10 @@ The Probe Rectangular Boss macro probes all sides of the stock and calculates th `Z` is the distance the probe should move in Z below the edges of the body and should be a negative value. `Q` enables inspection reporting which pops up a calculated length and width after the routine finishes. * The Probe should be roughly centered and above the stock before beginning. -======= -Example MDI Command Without Inspection Reporting: G65 "PROBERECTANGULARPOCKET" A54.05 B2. C3. Q0. - -Example MDI Command Without Inspection Reporting: G65 "PROBERECTANGULARPOCKET" A54.05 B2. C3. Q1. -*** - -### PROBEXSLOT - -The Probe Slot X macro probes the internal sides of a pocket in the X direction and calculates the center. - -`A` is the selected work coordinate (54-59 or 54.01-54.99). -`B` is the length of the pocket in X. -`Q` enables inspection reporting, which pops up a calculated length after the routine finishes. - - The Probe should be roughly centered and inside the slot before beginning. ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 ![probeRectangularBoss](images/probeRectangularBoss.png) _Figure 11. Probe Rectangular Boss Routine_ -<<<<<<< HEAD | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | --- | --- | | G65 | "PROBERECTANGULARBOSS" | A | X | Y | Z | Q | @@ -813,17 +486,13 @@ The Probe Slot X macro probes the internal sides of a pocket in the X direction ![probeSlot](images/probeSlot.png) _Figure 13. Probe Slot Routine_ -======= -_Figure 13. Probe Slot Routine_ ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | | G65 | "PROBESLOTX" | A | X | Q | -_Table 14. Probe Slot Syntax_ +_Table 14. Probe Slot Syntax_ -<<<<<<< HEAD Example MDI Command With Inspectioning: G65 "PROBESLOTX" A54. X3. Q1. Example MDI Command Without Inspectioning: M834 A54. X3. Q0. @@ -831,41 +500,21 @@ Example MDI Command Without Inspectioning: M834 A54. X3. Q0. ### PROBEYSLOT ( M835 ) The Probe Slot Y macro probes the internal sides of a pocket in the Y direction and calculates the center. -======= -Example MDI Command Without Inspectioning: G65 "PROBESLOTX" A54. B3. Q0. - -Example MDI Command Without Inspectioning: G65 "PROBESLOTX" A54. B3. Q1. -*** - -### PROBEYSLOT - -The Probe Slot Y macro probes the internal sides of a pocket in the Y direction and calculates the center. - -`A` is the selected work coordinate (54-59 or 54.01-54.99). -`B` is the width of the pocket in Y. -`Q` enables inspection reporting, which pops up a calculated width after the routine finishes. - - The Probe should be roughly centered and inside the slot before beginning. ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 `A` is the selected work coordinate ( 54-59 or 54.01-54.99 ). `Y` is the width of the pocket in Y. `Q` enables inspection reporting which pops up a calculated width after the routine finishes. * The Probe should be roughly centered and inside of the slot before beginning. -<<<<<<< HEAD ![probeSlotY](images/probeSlotY.PNG) _Figure 14. Probe Slot Routine_ -======= -_Figure 14. Probe Slot Routine_ ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | | G65 | "PROBESLOTY" | A | Y | Q | -_Table 15. Probe Slot Syntax_ +_Table 15. Probe Slot Syntax_ -<<<<<<< HEAD Example MDI Command: G65 "PROBESLOTY" A54. YB3. Q0. Example MDI Command With Inspection Reporting: M835 A54. Y3. Q1. @@ -873,75 +522,26 @@ Example MDI Command With Inspection Reporting: M835 A54. Y3. Q1. ### PROBEINSIDECORNER ( M837 ) The Probe inside Corner macro probes the inside edges of a pocket and calculates the center. -======= -Example MDI Command Without Inspection Reporting: G65 "PROBESLOTY" A54. B3. Q0. - -Example MDI Command With Inspection Reporting: G65 "PROBESLOTY" A54. B3. Q1. -*** - -### PROBEOUTSIDECORNER - -The Probe Outside Corner macro probes the outside edges of the stock and calculates the center. - -`A`is the selected work coordinate (54-59 or 54.01-54.99). -`B` Selects the desired corner to probe. -`C` is the distance to travel away from the initial location before probing begins. -`D` is the probing distance for both X and Y. - - The Probe should be roughly centered, diagonally from the corner before beginning. - -![probeExternalCorner](images/probeExternalCorner.png) - -_Figure 15. Probe Outside Corner Routine_ - -| G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | Macro Argument | -| --- | --- | --- | --- | --- | --- | -| G65 | "PROBEOUTSIDECORNER" | A | B | C | D | - -_Table 16. Probe Outer Corner Syntax_ - -Example MDI Command: G65 "PROBEOUTSIDECORNER" A54. B1. C1 D.5 -*** - -### PROBEINSIDECORNER - -The Probe inside Corner macro probes the inside edges of a pocket and calculates the center. - -`A` is the selected work coordinate (54-59 or 54.01-54.99). -`B` is the desired corner to probe. -`C` is the probing distance. - - The Probe should be roughly centered, diagonally from the corner before beginning. ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 `A` is the selected work coordinate ( 54-59 or 54.01-54.99 ). `C` the desired corner to probe. `E` is the engage distance to probe part. * The Probe should be roughly centered, diagonaly from the corner before beginning. -<<<<<<< HEAD ![probeInternalCorner](images/probeInternalCorner.png) _Figure 16. Probe Inside Corner Routine_ -======= -_Figure 16. Probe Inside Corner Routine_ ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 | G Code | "Macro Name" | Macro Argument | Macro Argument | Macro Argument | | --- | --- | --- | --- | --- | | G65 | "PROBEINSIDECORNER" | A | C | E | -_Table 17. Probe Inner Corner Syntax_ +_Table 17. Probe Inner Corner Syntax_ -<<<<<<< HEAD Example MDI Command: G65 "PROBEINSIDECORNER" A54. C1. E.5 Example MDI Command: M837 A54. C1. E.5 --- ### PROBEOUTSIDECORNER ( M838 ) -======= -Example MDI Command: G65 "PROBEINSIDECORNER" A54. B1. C.5 - - -## SUPPORTED FUSION 360 PROBING FEATURES ->>>>>>> 906c17ff5ec1ff1c43d489d23a23cae2fa3f5522 The Probe Outside Corner macro probes the outside edges of the stock and calculates the center. From 87db85738d4c175205e1e0a319b42f8cfe3e85af Mon Sep 17 00:00:00 2001 From: Jestah Carnie Date: Tue, 15 Apr 2025 20:41:07 +1200 Subject: [PATCH 18/21] fixed broken image fixed broken image in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e595878..e2d32c2 100644 --- a/README.md +++ b/README.md @@ -669,7 +669,7 @@ Example MDI Command: G65 "LOADTOOL" T10 O12 ### Zero point compensation ( M808 ) is supported and enabled via the post as shown below. Zero point compensation makes probing in fusion easier by allowing you to use a fixed zero point as the work WCS in every setup. When we say zero point, we're reffering to a fixed point on vise or zero point fixture that never moves. All of our operations are in reference to that zero point. The compensation functions by calculating the XY delta between where your workpiece is and where it's expected to be in reference to the zero point. After probing, the work WCS becomes the zero point offset plus the calculated delta. For example if your work WCS is G54, G54 becomes G59 plus the probed XY deltas. Z doesn't change and is always equal to the zero point Z. WCS override must be enabled when using zero point compensation. PROBERECTANGULARBOSS, PROBEPOCKET, PROBECIRCULARBOSS and PROBEBORE all support zero point compensation. -![ZeroPointCompensation](images/zero_point_comp_RO_post.PNG) +![ZeroPointCompensation](images/zero_point_comp_RO_post.png) --- ## SAFESPIN macro ( M813 ) From 305504b9dff91319c84b21247b13dbb4850f106d Mon Sep 17 00:00:00 2001 From: Jestah Carnie Date: Wed, 16 Apr 2025 15:59:45 +1200 Subject: [PATCH 19/21] Update MAKER_MACRO_M800 bug fix in extended offset calc --- Macros for Controller/maker_macros/MAKER_MACRO_M800 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Macros for Controller/maker_macros/MAKER_MACRO_M800 b/Macros for Controller/maker_macros/MAKER_MACRO_M800 index fd2b0a9..acf403f 100644 --- a/Macros for Controller/maker_macros/MAKER_MACRO_M800 +++ b/Macros for Controller/maker_macros/MAKER_MACRO_M800 @@ -82,8 +82,8 @@ IF [#1 != #0] ALARM["ERROR: G54 must be used when calling extended work offsets"] END_IF ELSE - @121 = #1 - IF [@121 < 54 || @121 > 59] + @121 = 0 + IF [#1 < 54 || #1 > 59] ALARM["ERROR: Probe WCS G@121 out of range"] END_IF END_IF @@ -99,11 +99,11 @@ IF [#2 != #0] ALARM["ERROR: G54 must be used when calling extended work offsets"] END_IF ELSE - @122 = #2 - IF [@122 < 54 || @122 > 59] + @122 = 0 + IF [#2 < 54 || #2 > 59] ALARM["ERROR: Override WCS G@122 out of range"] END_IF END_IF END_IF -M99 \ No newline at end of file +M99 From 982dbfd9250a8475d4ceea20caaf9acb22a89a53 Mon Sep 17 00:00:00 2001 From: Jestah Carnie Date: Wed, 16 Apr 2025 16:01:04 +1200 Subject: [PATCH 20/21] Update PROBECONFIG bug fix in extened offset calc --- Macros for Controller/PROBECONFIG | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Macros for Controller/PROBECONFIG b/Macros for Controller/PROBECONFIG index fd2b0a9..acf403f 100644 --- a/Macros for Controller/PROBECONFIG +++ b/Macros for Controller/PROBECONFIG @@ -82,8 +82,8 @@ IF [#1 != #0] ALARM["ERROR: G54 must be used when calling extended work offsets"] END_IF ELSE - @121 = #1 - IF [@121 < 54 || @121 > 59] + @121 = 0 + IF [#1 < 54 || #1 > 59] ALARM["ERROR: Probe WCS G@121 out of range"] END_IF END_IF @@ -99,11 +99,11 @@ IF [#2 != #0] ALARM["ERROR: G54 must be used when calling extended work offsets"] END_IF ELSE - @122 = #2 - IF [@122 < 54 || @122 > 59] + @122 = 0 + IF [#2 < 54 || #2 > 59] ALARM["ERROR: Override WCS G@122 out of range"] END_IF END_IF END_IF -M99 \ No newline at end of file +M99 From 888e8902ff470913daa925a9745cf72f473ad331 Mon Sep 17 00:00:00 2001 From: Robot Oblivion Date: Wed, 16 Apr 2025 16:11:17 +1200 Subject: [PATCH 21/21] small update to read me to correct for correct numbers --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e595878..97e9b85 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ Once you have saved your changes to `PROBECONFIG` or `M800` copy all files withi ## **Backup and Preparation for Calibration** -1. Backup your tool table, offset table and `@10`, `@91-@98`, `@100-@110`, `@112-@115`,`@130-@134`, `@980-@987` and `@5109` variables in case of wanting to revert +1. Backup your tool table, offset table and `@10`, `@91-@98`, `@100-@110`, `@112-@115`,`@130-@134`, `@980-@985`, `@996-@999` and `@5109` variables in case of wanting to revert 2. Clear as many items as possible from the table to prevent collisions with stock, jigs, fixtures, or vices. 3. Ensure the table zero point or area to place your calibration object is empty, lightly stoned, and free of coolant. 4. Have your master tool, probe, and ring gauge/gauge block ready.