From b9f4179e86004837353e6bf7ae898db2ac78edbd Mon Sep 17 00:00:00 2001 From: Jaun Terblanche Date: Wed, 13 Aug 2025 07:14:48 +0800 Subject: [PATCH 1/5] Initial Fusion Probing Implementation --- .../Fusion360-profiles/Carvera.cps | 2159 +++++++++++++---- 1 file changed, 1662 insertions(+), 497 deletions(-) diff --git a/CAM_Post_Processors/Fusion360-profiles/Carvera.cps b/CAM_Post_Processors/Fusion360-profiles/Carvera.cps index 290d614..9e6e724 100644 --- a/CAM_Post_Processors/Fusion360-profiles/Carvera.cps +++ b/CAM_Post_Processors/Fusion360-profiles/Carvera.cps @@ -21,7 +21,8 @@ minimumRevision = 45702; extension = "cnc"; setCodePage("ascii"); -capabilities = CAPABILITY_MILLING | CAPABILITY_JET | CAPABILITY_MACHINE_SIMULATION; +capabilities = + CAPABILITY_MILLING | CAPABILITY_JET | CAPABILITY_MACHINE_SIMULATION; tolerance = spatial(0.002, MM); /////////////////////////////////////////////////////////////////////////////// @@ -34,13 +35,11 @@ tolerance = spatial(0.002, MM); // Tool Break Control -run a tool break test. Requires the community firmware // Pass Through -send the contents of the input box directly to the machine - // Useful Pass Through Commands // M98.1 "nameOfFile" // M98 P2002 // - // The following ACTION commands are supported by this post. // // RapidA:# -rapids the a axis to degree position @@ -66,7 +65,6 @@ tolerance = spatial(0.002, MM); // /////////////////////////////////////////////////////////////////////////////// - minimumChordLength = spatial(0.25, MM); minimumCircularRadius = spatial(0.01, MM); maximumCircularRadius = spatial(1000, MM); @@ -75,143 +73,171 @@ maximumCircularSweep = toRad(180); allowHelicalMoves = true; allowedCircularPlanes = undefined; // allow any circular motion -highFeedrate = (unit == MM ? 3000 : 140); +highFeedrate = unit == MM ? 3000 : 140; // user-defined properties properties = { writeMachine: { - title : "Write machine", + title: "Write machine", description: "Output the machine settings in the header of the code.", - group : "formats", - type : "boolean", - value : true, - scope : "post" + group: "formats", + type: "boolean", + value: true, + scope: "post", }, writeTools: { - title : "Write tool list", + title: "Write tool list", description: "Output a tool list in the header of the code.", - group : "formats", - type : "boolean", - value : true, - scope : "post" + group: "formats", + type: "boolean", + value: true, + scope: "post", }, returnClearance: { - title : "Return Clearance", + title: "Return Clearance", description: "Return to clearance position when the job is finished.", - group : "homePositions", - type : "boolean", - value : true, - scope : "post" + group: "homePositions", + 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"} + 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: "false", - scope: "post" + scope: "post", }, sequenceNumberStart: { - title : "Start sequence number", + title: "Start sequence number", description: "The number at which to start the sequence numbers.", - group : "formats", - type : "integer", - value : 10, - scope : "post" + 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 : 1, - scope : "post" + title: "Sequence number increment", + description: + "The amount by which the sequence number is incremented by in each block.", + group: "formats", + type: "integer", + value: 1, + scope: "post", }, separateWordsWithSpace: { - title : "Separate words with space", + title: "Separate words with space", description: "Adds spaces between words if 'yes' is selected.", - group : "formats", - type : "boolean", - value : true, - scope : "post" + group: "formats", + type: "boolean", + value: true, + scope: "post", }, splitFile: { - title : "Split file", + title: "Split file", description: "Select your desired file splitting option.", - group : "preferences", - type : "enum", - values : [ - {title:"No splitting", id:"none"}, - {title:"Split by tool", id:"tool"}, - {title:"Split by toolpath", id:"toolpath"} + group: "preferences", + type: "enum", + values: [ + { title: "No splitting", id: "none" }, + { title: "Split by tool", id: "tool" }, + { title: "Split by toolpath", id: "toolpath" }, ], value: "none", - scope: "post" + scope: "post", }, splitFileHeader: { - title : "Write Tool# and Header To Each Split By Toolpath File", + title: "Write Tool# and Header To Each Split By Toolpath File", description: "Write Tool# and Header To Each Split By Toolpath File", - group : "preferences", - type : "boolean", + group: "preferences", + type: "boolean", value: true, - scope: "post" + scope: "post", }, defaultUseExternalControl: { - title : "Spindle-based External Control", - description: "Turn the external PWM control on/off when the spindle is turned on/off.", - group : "preferences", - type : "boolean", + title: "Spindle-based External Control", + description: + "Turn the external PWM control on/off when the spindle is turned on/off.", + group: "preferences", + type: "boolean", value: true, - scope: "post" + scope: "post", }, useExtForAirCoolant: { - title : "Use Ext For Air Coolant", - description: "Turn the external PWM control on/off when the air coolant is turned on/off.", - group : "preferences", - type : "boolean", + title: "Use Ext For Air Coolant", + description: + "Turn the external PWM control on/off when the air coolant is turned on/off.", + group: "preferences", + type: "boolean", value: false, - scope: "post" + scope: "post", }, - manualToolChangeBehavior: { - title : "Manual Tool Change Behavior", - description: "If you are using the Carvera Air, choose the Carvera Air option. If you are using the carvera community firmware, that option will allow you to use tools 0-99. If you are using the stock carvera firmware on the non air variant, choose the fusion manual tool changes to generate tool changes when a tool number is greater than 6, the shank size changes, or the tool is marked for manual tool change. If you want the default behavior for the Carvera where it alarms on any tool number greater than 6, choose the first option", - group : "preferences", - type : "enum", - values : [ - {title:"Error On More Than 6 Tools", id:"error6"}, - {title:"Fusion Manual Tool Changes", id:"fusionMtc"}, - {title:"Carvera Community Tool Changes", id:"carvcomMtc"}, - {title:"Carvera Air Tool Changes", id:"carvAirMtc"} + manualToolChangeBehavior: { + title: "Manual Tool Change Behavior", + description: + "If you are using the Carvera Air, choose the Carvera Air option. If you are using the carvera community firmware, that option will allow you to use tools 0-99. If you are using the stock carvera firmware on the non air variant, choose the fusion manual tool changes to generate tool changes when a tool number is greater than 6, the shank size changes, or the tool is marked for manual tool change. If you want the default behavior for the Carvera where it alarms on any tool number greater than 6, choose the first option", + group: "preferences", + type: "enum", + values: [ + { title: "Error On More Than 6 Tools", id: "error6" }, + { title: "Fusion Manual Tool Changes", id: "fusionMtc" }, + { title: "Carvera Community Tool Changes", id: "carvcomMtc" }, + { title: "Carvera Air Tool Changes", id: "carvAirMtc" }, ], value: "carvAirMtc", - - scope: "post" + scope: "post", }, useShankSizeForManualChange: { - title : "Write Manual Tool Changes when Shank Size Changes", + title: "Write Manual Tool Changes when Shank Size Changes", description: "", - group : "preferences", - type : "boolean", - value : true, - scope : "post" + group: "preferences", + type: "boolean", + value: true, + scope: "post", + }, + firmwareType: { + title: "Carvera Machine Firmware Type", + description: "Select the firmware type installed on your machine.", + group: "preferences", + type: "enum", + values: [ + { title: "Stock Firmware", id: "stock" }, + { title: "Community Firmware", id: "community" }, + ], + value: "community", + scope: "post", + }, + probeSensorType: { + title: "Probe Sensor Type", + description: + "Set to NO (normally open) or NC (normally closed). If this value does not match the probe sensor it is guaranteed to cause a crash.", + group: "preferences", + type: "enum", + values: [ + { title: "NC (normally closed)", id: "NC" }, + { title: "NO (normally open)", id: "NO" }, + ], + value: "NO", + scope: "post", }, }; // wcs definiton wcsDefinitions = { useZeroOffset: false, - wcs : [ - {name:"Standard", format:"G", range:[54, 59]} - ] + // @TODO: Fusion does not accept decimals, i.e. 59.1-3, which are the temporary WCS values (not stored in the machine and not persisted across reboots/restarts + wcs: [{ name: "Standard", format: "G", range: [54, 59] }], }; -var numberOfToolSlots = 9999; +var numberOfToolSlots = 999999; var previousToolChangeWasManual = false; var subprograms = new Array(); @@ -221,50 +247,80 @@ var singleLineCoolant = false; // specifies to output multiple coolant codes in // {id: COOLANT_THROUGH_TOOL, on: [8, 88], off: [9, 89]} // {id: COOLANT_THROUGH_TOOL, on: "M88 P3 (myComment)", off: "M89"} var coolants = [ - {id:COOLANT_FLOOD, on:8}, - {id:COOLANT_MIST}, - {id:COOLANT_THROUGH_TOOL}, - {id:COOLANT_AIR, on:7}, - {id:COOLANT_AIR_THROUGH_TOOL}, - {id:COOLANT_SUCTION}, - {id:COOLANT_FLOOD_MIST}, - {id:COOLANT_FLOOD_THROUGH_TOOL}, - {id:COOLANT_OFF, off:9} + { id: COOLANT_FLOOD, on: 8 }, + { id: COOLANT_MIST }, + { id: COOLANT_THROUGH_TOOL }, + { id: COOLANT_AIR, on: 7 }, + { id: COOLANT_AIR_THROUGH_TOOL }, + { id: COOLANT_SUCTION }, + { id: COOLANT_FLOOD_MIST }, + { id: COOLANT_FLOOD_THROUGH_TOOL }, + { id: COOLANT_OFF, off: 9 }, ]; -var gFormat = createFormat({prefix:"G", decimals:0}); -var mFormat = createFormat({prefix:"M", decimals:0}); +var gFormat = createFormat({ prefix: "G", decimals: 1 }); +var mFormat = createFormat({ prefix: "M", decimals: 0 }); -var xyzFormat = createFormat({decimals:(unit == MM ? 3 : 4), type:FORMAT_REAL}); +var xyzFormat = createFormat({ + decimals: unit == MM ? 3 : 4, + type: FORMAT_REAL, + minDigitsRight: 1, +}); var rFormat = xyzFormat; //radius -var abcFormat = createFormat({decimals:3, forceDecimal:true, scale:DEG}); -var feedFormat = createFormat({decimals:(unit == MM ? 1 : 2), type:FORMAT_REAL}); -var inverseTimeFormat = createFormat({decimals:3, forceDecimal:true}); -var toolFormat = createFormat({decimals:0}); -var rpmFormat = createFormat({decimals:0}); -var pwmFormat = createFormat({decimals:0, maximum:100, minimum:0}); -var secFormat = createFormat({decimals:3, forceDecimal:true}); // seconds - range 0.001-1000 -var taperFormat = createFormat({decimals:1, scale:DEG}); -var integerFormat = createFormat({decimals:0}); - -var xOutput = createVariable({prefix:"X"}, xyzFormat); -var yOutput = createVariable({prefix:"Y"}, xyzFormat); -var zOutput = createVariable({onchange:function () {retracted = false;}, prefix:"Z"}, xyzFormat); -var aOutput = createVariable({prefix:"A"}, abcFormat); -var bOutput = createVariable({prefix:"B"}, abcFormat); -var cOutput = createVariable({prefix:"C"}, abcFormat); -var feedOutput = createVariable({prefix:"F"}, feedFormat); -var inverseTimeOutput = createVariable({prefix:"F", force:true}, inverseTimeFormat); -var pwmOutput = createVariable({prefix:"S", force:true}, pwmFormat); -var sOutput = createVariable({prefix:"S"}, rpmFormat); +var abcFormat = createFormat({ decimals: 3, forceDecimal: true, scale: DEG }); +var feedFormat = createFormat({ + decimals: unit == MM ? 1 : 2, + type: FORMAT_REAL, + minDigitsRight: 1, +}); +var inverseTimeFormat = createFormat({ decimals: 3, forceDecimal: true }); +var toolFormat = createFormat({ decimals: 0 }); +var toolDiameterFormat = createFormat({ + decimals: unit == MM ? 3 : 4, +}); +var rpmFormat = createFormat({ decimals: 0 }); +var pwmFormat = createFormat({ decimals: 0, maximum: 100, minimum: 0 }); +var secFormat = createFormat({ decimals: 3, forceDecimal: true }); // seconds - range 0.001-1000 +var taperFormat = createFormat({ decimals: 1, scale: DEG }); +var integerFormat = createFormat({ decimals: 0 }); +var angleFormat = createFormat({ decimals: 0, scale: DEG }); + +var xOutput = createVariable({ prefix: "X" }, xyzFormat); +var yOutput = createVariable({ prefix: "Y" }, xyzFormat); +var zOutput = createVariable( + { + onchange: function () { + retracted = false; + }, + prefix: "Z", + }, + xyzFormat +); +var aOutput = createVariable({ prefix: "A" }, abcFormat); +var bOutput = createVariable({ prefix: "B" }, abcFormat); +var cOutput = createVariable({ prefix: "C" }, abcFormat); +var feedOutput = createVariable({ prefix: "F" }, feedFormat); +var inverseTimeOutput = createVariable( + { prefix: "F", force: true }, + inverseTimeFormat +); +var pwmOutput = createVariable({ prefix: "S", force: true }, pwmFormat); +var sOutput = createVariable({ prefix: "S", force: true }, rpmFormat); // circular output -var iOutput = createVariable({prefix:"I"}, xyzFormat); -var jOutput = createVariable({prefix:"J"}, xyzFormat); -var kOutput = createVariable({prefix:"K"}, xyzFormat); +var iOutput = createVariable({ prefix: "I" }, xyzFormat); +var jOutput = createVariable({ prefix: "J" }, xyzFormat); +var kOutput = createVariable({ prefix: "K" }, xyzFormat); var gMotionModal = createModal({}, gFormat); // modal group 1 // G0-G3, ... -var gPlaneModal = createModal({onchange:function () {gMotionModal.reset();}}, gFormat); // modal group 2 // G17-19 +var gPlaneModal = createModal( + { + onchange: function () { + gMotionModal.reset(); + }, + }, + gFormat +); // modal group 2 // G17-19 var gAbsIncModal = createModal({}, gFormat); // modal group 3 // G90-91 var gFeedModeModal = createModal({}, gFormat); // modal group 5 // G93-94 var gUnitModal = createModal({}, gFormat); // modal group 6 // G20-21 @@ -275,7 +331,9 @@ var WARNING_WORK_OFFSET = 0; var sequenceNumber; var forceSpindleSpeed = false; var currentWorkOffset; -var retracted = false; // specifies that the tool has been retracted to the safe plane +// specifies that the tool has been retracted to the safe plane +// NB: writeRetract() is what sets this to true +var retracted = false; /** Writes the specified block. @@ -302,7 +360,10 @@ function formatComment(text) { */ function writeToolBlock() { var show = getProperty("showSequenceNumbers"); - setProperty("showSequenceNumbers", (show == "true" || show == "toolChange") ? "true" : "false"); + setProperty( + "showSequenceNumbers", + show == "true" || show == "toolChange" ? "true" : "false" + ); writeBlock(arguments); setProperty("showSequenceNumbers", show); } @@ -323,75 +384,77 @@ function onPassThrough(text) { function onParameter(name, value) { var invalid = false; if (name == "action") { - - if (String(value).toUpperCase() == "SPINDLEOFF"){ - writeBlock("M5 (Spindle Off)") - } else if (String(value).toUpperCase() == "CLEARANCE"){ - writeBlock("G28 (Go to clearance)") - } else if (String(value).toUpperCase() == "CLEARAUTOLEVEL"){ - writeBlock("M370 (clear autolevel)") - } else if (String(value).toUpperCase() == "RESETFEEDOVERRIDE"){ - writeBlock("M220 S100 (Reset Feed Speed override)") - } else if (String(value).toUpperCase() == "AIRON"){ - writeBlock("M7 (Compressed Air On)") - } else if (String(value).toUpperCase() == "AIROFF"){ - writeBlock("M9 (Compressed Air Off)") - } else if (String(value).toUpperCase() == "VACON"){ - writeBlock("M801 S100 (Vacuum On)") - } else if (String(value).toUpperCase() == "VACOFF"){ - writeBlock("M802 (Vacuum Off)") - } else if (String(value).toUpperCase() == "AUTOVACON"){ - writeBlock("M331 (Turn On Auto Vacuum)") - } else if (String(value).toUpperCase() == "AUTOVACOFF"){ - writeBlock("M332 (Turn Off Auto Vacuum)") - } else if (String(value).toUpperCase() == "LIGHTON"){ - writeBlock("M821 (Turn On Light)") - } else if (String(value).toUpperCase() == "LIGHTOFF"){ - writeBlock("M822 (Turn Off Light)") - } else if (String(value).toUpperCase() == "EXTON"){ - writeBlock("M851 S100 (External Control On 100)") - } else if (String(value).toUpperCase() == "EXTOFF"){ - writeBlock("M852 (External Control Off)") - } else if (String(value).toUpperCase() == "SHRINKA"){ - writeBlock("G92.4 A0 S0 (shrink the a axis so A365 becomes A5)") - } else if (String(value).toUpperCase() == "SAFEZ"){ - writeBlock("G53 G0 Z -2. (Goto Safe Height In Z)") + if (String(value).toUpperCase() == "SPINDLEOFF") { + writeBlock("M5 (Spindle Off)"); + } else if (String(value).toUpperCase() == "CLEARANCE") { + writeBlock("G28 (Go to clearance)"); + } else if (String(value).toUpperCase() == "CLEARAUTOLEVEL") { + writeBlock("M370 (clear autolevel)"); + } else if (String(value).toUpperCase() == "RESETFEEDOVERRIDE") { + writeBlock("M220 S100 (Reset Feed Speed override)"); + } else if (String(value).toUpperCase() == "AIRON") { + writeBlock("M7 (Compressed Air On)"); + } else if (String(value).toUpperCase() == "AIROFF") { + writeBlock("M9 (Compressed Air Off)"); + } else if (String(value).toUpperCase() == "VACON") { + writeBlock("M801 S100 (Vacuum On)"); + } else if (String(value).toUpperCase() == "VACOFF") { + writeBlock("M802 (Vacuum Off)"); + } else if (String(value).toUpperCase() == "AUTOVACON") { + writeBlock("M331 (Turn On Auto Vacuum)"); + } else if (String(value).toUpperCase() == "AUTOVACOFF") { + writeBlock("M332 (Turn Off Auto Vacuum)"); + } else if (String(value).toUpperCase() == "LIGHTON") { + writeBlock("M821 (Turn On Light)"); + } else if (String(value).toUpperCase() == "LIGHTOFF") { + writeBlock("M822 (Turn Off Light)"); + } else if (String(value).toUpperCase() == "EXTON") { + writeBlock("M851 S100 (External Control On 100)"); + } else if (String(value).toUpperCase() == "EXTOFF") { + writeBlock("M852 (External Control Off)"); + } else if (String(value).toUpperCase() == "SHRINKA") { + writeBlock("G92.4 A0 S0 (shrink the a axis so A365 becomes A5)"); + } else if (String(value).toUpperCase() == "SAFEZ") { + writeBlock("G53 G0 Z -2. (Goto Safe Height In Z)"); } else { var sText1 = String(value); var sText2 = new Array(); sText2 = sText1.split(":"); if (sText2.length == 2) { if (sText2[0].toUpperCase() == "RAPIDA") { - if (sText2[1].match(/^-?\d+$/)){ - writeBlock("G0A"+sText2[1] + "(Rapid movement on a axis)") - } else{ + if (sText2[1].match(/^-?\d+$/)) { + writeBlock("G0A" + sText2[1] + "(Rapid movement on a axis)"); + } else { invalid = true; } - } else if (sText2[0].toUpperCase() == "SAFERA") { - if (sText2[1].match(/^-?\d+$/)){ - writeBlock("G53 G0 Z -2. (Goto Safe Height In Z)") - writeBlock("G0A"+sText2[1] + "(Rapid movement on a axis)") - } else{ + if (sText2[1].match(/^-?\d+$/)) { + writeBlock("G53 G0 Z -2. (Goto Safe Height In Z)"); + writeBlock("G0A" + sText2[1] + "(Rapid movement on a axis)"); + } else { invalid = true; } } else if (sText2[0].toUpperCase() == "FEEDOVERRIDE") { - if (sText2[1].match(/^-?\d+$/)){ - writeBlock("M220 S"+sText2[1] + "(Globally sets the feed speed to "+ sText2[1] +" percent. Useful for vetting a program the first time you run it. Remember to run M220 S100 when you are done with the program or restart the machine)") - } else{ + if (sText2[1].match(/^-?\d+$/)) { + writeBlock( + "M220 S" + + sText2[1] + + "(Globally sets the feed speed to " + + sText2[1] + + " percent. Useful for vetting a program the first time you run it. Remember to run M220 S100 when you are done with the program or restart the machine)" + ); + } else { invalid = true; } } - - - } else { invalid = true; } - } if (invalid) { - error(localize("Invalid action parameter: ") + sText2[0] + ":" + sText2[1]); + error( + localize("Invalid action parameter: ") + sText2[0] + ":" + sText2[1] + ); return; } } @@ -407,21 +470,38 @@ var multiAxisFeedrate; function activateMachine() { // disable unsupported rotary axes output - if (!machineConfiguration.isMachineCoordinate(0) && (typeof aOutput != "undefined")) { + if ( + !machineConfiguration.isMachineCoordinate(0) && + typeof aOutput != "undefined" + ) { aOutput.disable(); } - if (!machineConfiguration.isMachineCoordinate(1) && (typeof bOutput != "undefined")) { + if ( + !machineConfiguration.isMachineCoordinate(1) && + typeof bOutput != "undefined" + ) { bOutput.disable(); } - if (!machineConfiguration.isMachineCoordinate(2) && (typeof cOutput != "undefined")) { + if ( + !machineConfiguration.isMachineCoordinate(2) && + typeof cOutput != "undefined" + ) { cOutput.disable(); } // setup usage of multiAxisFeatures - useMultiAxisFeatures = getProperty("useMultiAxisFeatures") != undefined ? getProperty("useMultiAxisFeatures") : - (typeof useMultiAxisFeatures != "undefined" ? useMultiAxisFeatures : false); - useABCPrepositioning = getProperty("useABCPrepositioning") != undefined ? getProperty("useABCPrepositioning") : - (typeof useABCPrepositioning != "undefined" ? useABCPrepositioning : false); + useMultiAxisFeatures = + getProperty("useMultiAxisFeatures") != undefined + ? getProperty("useMultiAxisFeatures") + : typeof useMultiAxisFeatures != "undefined" + ? useMultiAxisFeatures + : false; + useABCPrepositioning = + getProperty("useABCPrepositioning") != undefined + ? getProperty("useABCPrepositioning") + : typeof useABCPrepositioning != "undefined" + ? useABCPrepositioning + : false; if (!machineConfiguration.isMultiAxisConfiguration()) { return; // don't need to modify any settings for 3-axis machines @@ -429,14 +509,24 @@ function activateMachine() { // 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); + 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 + 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 @@ -445,12 +535,17 @@ function activateMachine() { safePlungeFeed = machineConfiguration.getSafePlungeFeedrate(); safeRetractFeed = machineConfiguration.getSafeRetractFeedrate(); } - if (typeof safeRetractDistance == "number" && getProperty("safeRetractDistance") != undefined && getProperty("safeRetractDistance") != 0) { + if ( + typeof safeRetractDistance == "number" && + getProperty("safeRetractDistance") != undefined && + getProperty("safeRetractDistance") != 0 + ) { safeRetractDistance = getProperty("safeRetractDistance"); } if (machineConfiguration.isHeadConfiguration()) { - compensateToolLength = typeof compensateToolLength == "undefined" ? false : compensateToolLength; + compensateToolLength = + typeof compensateToolLength == "undefined" ? false : compensateToolLength; } if (machineConfiguration.isHeadConfiguration() && compensateToolLength) { @@ -458,7 +553,10 @@ function activateMachine() { var section = getSection(i); if (section.isMultiAxis()) { machineConfiguration.setToolLength(getBodyLength(section.getTool())); // define the tool length for head adjustments - section.optimizeMachineAnglesByMachine(machineConfiguration, OPTIMIZE_AXIS); + section.optimizeMachineAnglesByMachine( + machineConfiguration, + OPTIMIZE_AXIS + ); } } } else { @@ -470,60 +568,95 @@ 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 section.getParameter( + "operation:tool_overallLength", + tool.bodyLength + tool.holderLength + ); } } return tool.bodyLength + tool.holderLength; } function dumpToolInformation() { - // dump tool information - - 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; - } - } + // dump tool information + writeln(""); // empty line + writeComment("Tool Information:"); + 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 = "T" + toolFormat.format(tool.number) + " " + - tool.description + " " + - tool.vendor + " " + - tool.productId + " " + - "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); - } + var tools = getToolTable(); + if (tools.getNumberOfTools() > 0) { + for (var i = 0; i < tools.getNumberOfTools(); ++i) { + var tool = tools.getTool(i); + var comment = + "T" + + toolFormat.format(tool.number) + + " " + + tool.description + + " " + + tool.vendor + + " " + + tool.productId + + " " + + "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); + } + } + writeln(""); // empty line } function defineMachine() { - if (false) { // note: setup your machine here - var aAxis = createAxis({coordinate:0, table:true, axis:[1, 0, 0], cyclic:true, tcp:false}); + if (false) { + // note: setup your machine here + var aAxis = createAxis({ + coordinate: 0, + table: true, + axis: [1, 0, 0], + cyclic: true, + tcp: false, + }); machineConfiguration = new MachineConfiguration(aAxis); setMachineConfiguration(machineConfiguration); if (receivedMachineConfiguration) { - warning(localize("The provided CAM machine configuration is overwritten by the postprocessor.")); + warning( + localize( + "The provided CAM machine configuration is overwritten by the postprocessor." + ) + ); receivedMachineConfiguration = false; // CAM provided machine configuration is overwritten } } @@ -538,13 +671,17 @@ function defineMachine() { 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 + 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 + var stockExpansion = new Vector( + toPreciseUnit(0.1, IN), + toPreciseUnit(0.1, IN), + toPreciseUnit(0.1, IN) + ); // expand stock XYZ values machineConfiguration.setRewindStockExpansion(stockExpansion); } @@ -584,10 +721,10 @@ function onOpen() { sequenceNumber = getProperty("sequenceNumberStart"); if (programName) { - writeComment(programName); + writeComment("Program Name: " + programName); } if (programComment) { - writeComment(programComment); + writeComment("Program Comment: " + programComment); } // dump machine configuration @@ -604,7 +741,7 @@ function onOpen() { writeComment(" " + localize("model") + ": " + model); } if (description) { - writeComment(" " + localize("description") + ": " + description); + writeComment(" " + localize("description") + ": " + description); } } @@ -613,10 +750,14 @@ function onOpen() { dumpToolInformation(); } - if ((getNumberOfSections() > 0) && (getSection(0).workOffset == 0)) { + if (getNumberOfSections() > 0 && getSection(0).workOffset == 0) { for (var i = 0; i < getNumberOfSections(); ++i) { if (getSection(i).workOffset > 0) { - error(localize("Using multiple work offsets is not possible if the initial work offset is 0.")); + error( + localize( + "Using multiple work offsets is not possible if the initial work offset is 0." + ) + ); return; } } @@ -632,12 +773,12 @@ function onOpen() { writeBlock(gPlaneModal.format(17)); switch (unit) { - case IN: - writeBlock(gUnitModal.format(20)); - break; - case MM: - writeBlock(gUnitModal.format(21)); - break; + case IN: + writeBlock(gUnitModal.format(20)); + break; + case MM: + writeBlock(gUnitModal.format(21)); + break; } } @@ -666,8 +807,10 @@ function forceAny() { } function isProbeOperation() { - return hasParameter("operation-strategy") && - (getParameter("operation-strategy") == "probe"); + return ( + hasParameter("operation-strategy") && + getParameter("operation-strategy") == "probe" + ); } var currentWorkPlaneABC = undefined; @@ -678,8 +821,11 @@ function forceWorkPlane() { function defineWorkPlane(_section, _setWorkPlane) { var abc = new Vector(0, 0, 0); - if (machineConfiguration.isMultiAxisConfiguration()) { // use 5-axis indexing for multi-axis mode - abc = _section.isMultiAxis() ? _section.getInitialToolAxisABC() : getWorkPlaneMachineABC(_section.workPlane); + if (machineConfiguration.isMultiAxisConfiguration()) { + // use 5-axis indexing for multi-axis mode + abc = _section.isMultiAxis() + ? _section.getInitialToolAxisABC() + : getWorkPlaneMachineABC(_section.workPlane); if (_section.isMultiAxis()) { cancelTransformation(); if (_setWorkPlane) { @@ -692,7 +838,8 @@ function defineWorkPlane(_section, _setWorkPlane) { setWorkPlane(abc); } } - } else { // pure 3D + } else { + // pure 3D var remaining = _section.workPlane; if (!isSameDirection(remaining.forward, new Vector(0, 0, 1))) { error(localize("Tool orientation is not supported.")); @@ -700,9 +847,17 @@ function defineWorkPlane(_section, _setWorkPlane) { } setRotation(remaining); } - if (currentSection && (currentSection.getId() == _section.getId())) { - operationSupportsTCP = currentSection.getOptimizedTCPMode() == OPTIMIZE_NONE; - if (!currentSection.isMultiAxis() && (useMultiAxisFeatures || isSameDirection(machineConfiguration.getSpindleAxis(), currentSection.workPlane.forward))) { + if (currentSection && currentSection.getId() == _section.getId()) { + operationSupportsTCP = + currentSection.getOptimizedTCPMode() == OPTIMIZE_NONE; + if ( + !currentSection.isMultiAxis() && + (useMultiAxisFeatures || + isSameDirection( + machineConfiguration.getSpindleAxis(), + currentSection.workPlane.forward + )) + ) { operationSupportsTCP = false; } } @@ -714,10 +869,14 @@ function setWorkPlane(abc) { return; // ignore } - if (!((currentWorkPlaneABC == undefined) || - abcFormat.areDifferent(abc.x, currentWorkPlaneABC.x) || - abcFormat.areDifferent(abc.y, currentWorkPlaneABC.y) || - abcFormat.areDifferent(abc.z, currentWorkPlaneABC.z))) { + if ( + !( + currentWorkPlaneABC == undefined || + abcFormat.areDifferent(abc.x, currentWorkPlaneABC.x) || + abcFormat.areDifferent(abc.y, currentWorkPlaneABC.y) || + abcFormat.areDifferent(abc.z, currentWorkPlaneABC.z) + ) + ) { return; // no change } @@ -756,8 +915,16 @@ function positionABC(abc, force) { function getWorkPlaneMachineABC(workPlane) { var W = workPlane; // map to global frame - var currentABC = isFirstSection() ? new Vector(0, 0, 0) : getCurrentDirection(); - var abc = machineConfiguration.getABCByPreference(W, currentABC, ABC, PREFER_PREFERENCE, ENABLE_ALL); + var currentABC = isFirstSection() + ? new Vector(0, 0, 0) + : getCurrentDirection(); + var abc = machineConfiguration.getABCByPreference( + W, + currentABC, + ABC, + PREFER_PREFERENCE, + ENABLE_ALL + ); var direction = machineConfiguration.getDirection(abc); if (!isSameDirection(direction, W.forward)) { @@ -767,10 +934,20 @@ function getWorkPlaneMachineABC(workPlane) { if (!machineConfiguration.isABCSupported(abc)) { error( - localize("Work plane is not supported") + ":" - + conditional(machineConfiguration.isMachineCoordinate(0), " A" + abcFormat.format(abc.x)) - + conditional(machineConfiguration.isMachineCoordinate(1), " B" + abcFormat.format(abc.y)) - + conditional(machineConfiguration.isMachineCoordinate(2), " C" + abcFormat.format(abc.z)) + localize("Work plane is not supported") + + ":" + + conditional( + machineConfiguration.isMachineCoordinate(0), + " A" + abcFormat.format(abc.x) + ) + + conditional( + machineConfiguration.isMachineCoordinate(1), + " B" + abcFormat.format(abc.y) + ) + + conditional( + machineConfiguration.isMachineCoordinate(2), + " C" + abcFormat.format(abc.z) + ) ); } @@ -789,36 +966,51 @@ function getWorkPlaneMachineABC(workPlane) { // Parse the TLO value from a comment function parseTLO(comment) { if (!comment) { - return null; // Return null if no comment exists + return null; // Return null if no comment exists } // Match the pattern TLO:X, where X is a letter or a number var match = comment.match(/TLO:([AMam0-9.-]+)/); if (match) { - return match[1]; + return match[1]; } return null; } function onSection() { - var insertToolCall = isFirstSection() || - currentSection.getForceToolChange && currentSection.getForceToolChange() || - (tool.number != getPreviousSection().getTool().number) || (getProperty("splitFile") == "toolpath" && getProperty("splitFileHeader")); + var insertToolCall = + isFirstSection() || + (currentSection.getForceToolChange && + currentSection.getForceToolChange()) || + tool.number != getPreviousSection().getTool().number || + (getProperty("splitFile") == "toolpath" && getProperty("splitFileHeader")); - var splitHere = getProperty("splitFile") == "toolpath" || (getProperty("splitFile") == "tool" && insertToolCall); + var splitHere = + getProperty("splitFile") == "toolpath" || + (getProperty("splitFile") == "tool" && insertToolCall); retracted = false; // specifies that the tool has been retracted to the safe plane - var newWorkOffset = isFirstSection() || - (getPreviousSection().workOffset != currentSection.workOffset) || + var newWorkOffset = + isFirstSection() || + getPreviousSection().workOffset != currentSection.workOffset || splitHere; // work offset changes - var newWorkPlane = isFirstSection() || - !isSameDirection(getPreviousSection().getGlobalFinalToolAxis(), currentSection.getGlobalInitialToolAxis()) || - (currentSection.isOptimizedForMachine() && getPreviousSection().isOptimizedForMachine() && - Vector.diff(getPreviousSection().getFinalToolAxisABC(), currentSection.getInitialToolAxisABC()).length > 1e-4) || - (!machineConfiguration.isMultiAxisConfiguration() && currentSection.isMultiAxis()) || - (!getPreviousSection().isMultiAxis() && currentSection.isMultiAxis() || - getPreviousSection().isMultiAxis() && !currentSection.isMultiAxis()) || - splitHere; // force newWorkPlane between indexing and simultaneous operations + var newWorkPlane = + isFirstSection() || + !isSameDirection( + getPreviousSection().getGlobalFinalToolAxis(), + currentSection.getGlobalInitialToolAxis() + ) || + (currentSection.isOptimizedForMachine() && + getPreviousSection().isOptimizedForMachine() && + Vector.diff( + getPreviousSection().getFinalToolAxisABC(), + currentSection.getInitialToolAxisABC() + ).length > 1e-4) || + (!machineConfiguration.isMultiAxisConfiguration() && + currentSection.isMultiAxis()) || + (!getPreviousSection().isMultiAxis() && currentSection.isMultiAxis()) || + (getPreviousSection().isMultiAxis() && !currentSection.isMultiAxis()) || + splitHere; // force newWorkPlane between indexing and simultaneous operations if (insertToolCall || newWorkOffset || newWorkPlane) { // stop spindle before retract during tool change if (insertToolCall && !isFirstSection()) { @@ -850,20 +1042,35 @@ function onSection() { var comment; if (hasParameter("operation-comment")) { comment = getParameter("operation-comment"); - } else { comment = getCurrentSectionId(); } - subprogram = programName + "_" + (subprograms.length + 1) + "_" + comment + "_" + "T" + tool.number; + subprogram = + programName + + "_" + + (subprograms.length + 1) + + "_" + + comment + + "_" + + "T" + + tool.number; } else { - subprogram = programName + "_" + (subprograms.length + 1) + "_" + "T" + tool.number; + subprogram = + programName + "_" + (subprograms.length + 1) + "_" + "T" + tool.number; } subprograms.push(subprogram); - var path = FileSystem.getCombinedPath(FileSystem.getFolderPath(getOutputPath()), String(subprogram).replace(/[<>:"/\\|?*]/g, "") + "." + extension); + var path = FileSystem.getCombinedPath( + FileSystem.getFolderPath(getOutputPath()), + String(subprogram).replace(/[<>:"/\\|?*]/g, "") + "." + extension + ); - writeComment(localize("Load tool number " + tool.number + " and subprogram " + subprogram)); + writeComment( + localize( + "Load tool number " + tool.number + " and subprogram " + subprogram + ) + ); redirectToFile(path); @@ -886,18 +1093,18 @@ function onSection() { } } - - if (hasParameter("operation-comment")) { var comment = getParameter("operation-comment"); if (comment) { - writeComment(comment); + writeComment("Start of operation: " + comment); } } if (insertToolCall) { - - if(getProperty("splitFile") == "toolpath" && getProperty("splitFileHeader")) { + if ( + getProperty("splitFile") == "toolpath" && + getProperty("splitFileHeader") + ) { dumpToolInformation(); } @@ -907,98 +1114,127 @@ function onSection() { warning(localize("Tool number exceeds maximum value.")); } - var tloValue = parseTLO(tool.comment);//A is automatic and is the default, M is manual setting (C=0), a number set the value directly (H=-14) + var tloValue = parseTLO(tool.comment); //A is automatic and is the default, M is manual setting (C=0), a number set the value directly (H=-14) var e_manualToolChangeBehavior = getProperty("manualToolChangeBehavior"); - if(tool.number > 6 && e_manualToolChangeBehavior == "error6") { - error(localize("Carvera does not support tool numbers greater than 6 by default. Use one of the manual tool change post processor settings")); + if (tool.number > 6 && e_manualToolChangeBehavior == "error6") { + error( + localize( + "Carvera does not support tool numbers greater than 6 by default. Use one of the manual tool change post processor settings" + ) + ); } - if (e_manualToolChangeBehavior == "carvAirMtc"){ //any tool number accepted + if (e_manualToolChangeBehavior == "carvAirMtc") { + //any tool number accepted writeToolBlock(mFormat.format(6), "T" + toolFormat.format(tool.number)); if (tool.comment) { writeComment(tool.comment); } - }else if (e_manualToolChangeBehavior == "carvcomMtc"){ - + } else if (e_manualToolChangeBehavior == "carvcomMtc") { if (tloValue) { if (tloValue === "A") { - writeToolBlock(mFormat.format(6), "T" + toolFormat.format(tool.number) + " C1"); + writeToolBlock( + mFormat.format(6), + "T" + toolFormat.format(tool.number) + " C1" + ); } else if (tloValue === "M") { - writeToolBlock(mFormat.format(6),"T" + toolFormat.format(tool.number) + " C0"); + writeToolBlock( + mFormat.format(6), + "T" + toolFormat.format(tool.number) + " C0" + ); } else { - var tloFloat = parseFloat(tloValue); - if (!isNaN(tloFloat)) { - writeToolBlock(mFormat.format(6), "T" + toolFormat.format(tool.number) + " H" + tloFloat); - } else { - writeToolBlock(mFormat.format(6), "T" + toolFormat.format(tool.number)); - } + var tloFloat = parseFloat(tloValue); + if (!isNaN(tloFloat)) { + writeToolBlock( + mFormat.format(6), + "T" + toolFormat.format(tool.number) + " H" + tloFloat + ); + } else { + writeToolBlock( + mFormat.format(6), + "T" + toolFormat.format(tool.number) + ); + } } } else { - writeToolBlock(mFormat.format(6), "T" + toolFormat.format(tool.number)); + writeToolBlock(mFormat.format(6), "T" + toolFormat.format(tool.number)); } - }else if (tool.number > 6 || tool.manualToolChange) { + } else if (tool.number > 6 || tool.manualToolChange) { writeComment("Manual Tool Change To #" + toolFormat.format(tool.number)); if (tool.manualToolChange) { - writeComment("as a result of manual tool change selected in tool settings"); + writeComment( + "as a result of manual tool change selected in tool settings" + ); } performStockManualToolChange(tloValue); - - } else if ((!isFirstSection() && getProperty("useShankSizeForManualChange") && Math.abs(tool.shaftDiameter - getPreviousSection().getTool().shaftDiameter) > 0.001)){ - - writeComment("Manual Tool Change To #" + toolFormat.format(tool.number)); - writeComment("as a result of tool shank size change"); - performStockManualToolChange(tloValue); - + } else if ( + !isFirstSection() && + getProperty("useShankSizeForManualChange") && + Math.abs( + tool.shaftDiameter - getPreviousSection().getTool().shaftDiameter + ) > 0.001 + ) { + writeComment("Manual Tool Change To #" + toolFormat.format(tool.number)); + writeComment("as a result of tool shank size change"); + performStockManualToolChange(tloValue); } else { - if (previousToolChangeWasManual && e_manualToolChangeBehavior == "fusionMtc") { - writeComment("Manual Tool Removal as a result of previous manual tool change"); - writeComment("setup for tool change"); - writeBlock("G28"); - writeComment("Paused. Prepare to remove tool from collet. Pressing play will release collet"); - writeBlock(mFormat.format(27)); - writeBlock(mFormat.format(600)); - writeBlock("M490.2"); - writeComment("Paused. Pressing play will resume program. The program expects an empty collet after this point."); - writeBlock(mFormat.format(27)); - writeBlock(mFormat.format(600)); - writeBlock("M493.2 T-1"); - - } - writeToolBlock(mFormat.format(6), "T" + toolFormat.format(tool.number)); + if ( + previousToolChangeWasManual && + e_manualToolChangeBehavior == "fusionMtc" + ) { + writeComment( + "Manual Tool Removal as a result of previous manual tool change" + ); + writeComment("setup for tool change"); + writeBlock("G28"); + writeComment( + "Paused. Prepare to remove tool from collet. Pressing play will release collet" + ); + writeBlock(mFormat.format(27)); + writeBlock(mFormat.format(600)); + writeBlock("M490.2"); + writeComment( + "Paused. Pressing play will resume program. The program expects an empty collet after this point." + ); + writeBlock(mFormat.format(27)); + writeBlock(mFormat.format(600)); + writeBlock("M493.2 T-1"); + } + writeToolBlock(mFormat.format(6), "T" + toolFormat.format(tool.number)); - if (tool.comment) { - writeComment(tool.comment); - } - previousToolChangeWasManual = false; - var showToolZMin = false; - if (showToolZMin) { - if (is3D()) { - var numberOfSections = getNumberOfSections(); - var zRange = currentSection.getGlobalZRange(); - var number = tool.number; - for (var i = currentSection.getId() + 1; i < numberOfSections; ++i) { - var section = getSection(i); - if (section.getTool().number != number) { - break; - } - zRange.expandToRange(section.getGlobalZRange()); + if (tool.comment) { + writeComment(tool.comment); + } + previousToolChangeWasManual = false; + var showToolZMin = false; + if (showToolZMin) { + if (is3D()) { + var numberOfSections = getNumberOfSections(); + var zRange = currentSection.getGlobalZRange(); + var number = tool.number; + for (var i = currentSection.getId() + 1; i < numberOfSections; ++i) { + var section = getSection(i); + if (section.getTool().number != number) { + break; } - writeComment(localize("ZMIN") + "=" + zRange.getMinimum()); + zRange.expandToRange(section.getGlobalZRange()); } - + writeComment(localize("ZMIN") + "=" + zRange.getMinimum()); } - } - + } } - var spindleChanged = tool.type != TOOL_PROBE && - (insertToolCall || forceSpindleSpeed || isFirstSection() || - (rpmFormat.areDifferent(spindleSpeed, sOutput.getCurrent())) || - (tool.clockwise != getPreviousSection().getTool().clockwise)); + var spindleChanged = + tool.type != TOOL_PROBE && + (insertToolCall || + forceSpindleSpeed || + isFirstSection() || + rpmFormat.areDifferent(spindleSpeed, sOutput.getCurrent()) || + tool.clockwise != getPreviousSection().getTool().clockwise); if (spindleChanged) { forceSpindleSpeed = false; if (spindleSpeed < 1) { @@ -1011,12 +1247,14 @@ function onSection() { writeBlock(mFormat.format(851), pwmOutput.format(100)); } writeBlock( - sOutput.format(spindleSpeed), mFormat.format(tool.clockwise ? 3 : 4) + sOutput.format(spindleSpeed), + mFormat.format(tool.clockwise ? 3 : 4) ); } // wcs - if (insertToolCall) { // force work offset when changing tool + if (insertToolCall) { + // force work offset when changing tool currentWorkOffset = undefined; } @@ -1052,11 +1290,15 @@ function onSection() { writeBlock(gPlaneModal.format(17)); if (!machineConfiguration.isHeadConfiguration()) { - writeBlock( - gAbsIncModal.format(90), - gMotionModal.format(0), xOutput.format(initialPosition.x), yOutput.format(initialPosition.y) - ); - writeBlock(gMotionModal.format(0), zOutput.format(initialPosition.z)); + if (!isFirstOperationProbeZ()) { + writeBlock( + gAbsIncModal.format(90), + gMotionModal.format(0), + xOutput.format(initialPosition.x), + yOutput.format(initialPosition.y) + ); + writeBlock(gMotionModal.format(0), zOutput.format(initialPosition.z)); + } } else { writeBlock( gAbsIncModal.format(90), @@ -1077,8 +1319,6 @@ function onSection() { } function performStockManualToolChange(tloValue) { - - if (tool.comment) { writeComment(tool.comment); } @@ -1086,20 +1326,22 @@ function performStockManualToolChange(tloValue) { writeComment("Setup for tool change"); if (previousToolChangeWasManual || isFirstSection()) { writeBlock("G28"); - writeComment("Paused. Prepare to remove tool from collet. Pressing play will release collet"); + writeComment( + "Paused. Prepare to remove tool from collet. Pressing play will release collet" + ); writeBlock(mFormat.format(27)); writeBlock(mFormat.format(600)); writeBlock("M490.2 (Open Collet)"); - } else { writeBlock("T-1 M6"); writeBlock("G28"); } - previousToolChangeWasManual = true; - writeComment("Paused. Prepare to add new tool to collet. Pressing play will close collet"); + writeComment( + "Paused. Prepare to add new tool to collet. Pressing play will close collet" + ); writeBlock(mFormat.format(27)); writeBlock(mFormat.format(600)); writeBlock("M490.1 (Close Collet)"); @@ -1107,14 +1349,19 @@ function performStockManualToolChange(tloValue) { var tloFloat = parseFloat(tloValue); if (tloValue == "M" || !isNaN(tloFloat)) { - writeComment("Paused. Use the manual control interface to set the tool length."); - writeComment("Pressing play will goto the clearance position, then continue the program."); + writeComment( + "Paused. Use the manual control interface to set the tool length." + ); + writeComment( + "Pressing play will goto the clearance position, then continue the program." + ); writeBlock(mFormat.format(27)); writeBlock(mFormat.format(600)); writeBlock("G28 (Move To Clearance)"); - } else { - writeComment("Paused. Pressing play will calibrate the tool length and continue the program"); + writeComment( + "Paused. Pressing play will calibrate the tool length and continue the program" + ); writeBlock(mFormat.format(27)); writeBlock(mFormat.format(600)); writeBlock("M493.2T1 (Set tool number to 1 so TLO can be set)"); @@ -1127,13 +1374,805 @@ function onDwell(seconds) { warning(localize("Dwelling time is out of range.")); } seconds = clamp(0.001, seconds, 99999.999); - writeBlock(gFormat.format(4), "P" + secFormat.format(seconds) + "(pause for "+ secFormat.format(seconds) +"seconds)"); + writeBlock( + gFormat.format(4), + "P" + + secFormat.format(seconds) + + "(pause for " + + secFormat.format(seconds) + + "seconds)" + ); } function onSpindleSpeed(spindleSpeed) { writeBlock(sOutput.format(spindleSpeed)); } +function calculateWCS(offset) { + return wcsDefinitions.wcs[0].range[0] + offset - 1; +} + +// ====================================================== // +// ================ BEGIN CYCLE HANDLERS ================ // +// ====================================================== // + +// baseCycleHandler defines all known cycle types and establishes default +// handlers. If new probe or cycle types appear, they should be added here. To +// add implementations, extend makeraFirmwareCycleHandler or +// communityFirmwareCycleHandler, or roll a new one. +// +// several pre-calculated fields are set up on handler, please refer to them in +// your implementations. +function baseCycleHandler(cycle, tool) { + var handler = { + probeRadius: tool.diameter / 2, + // Set in the UI as "Measure Feedrate" on the Tool tab. + // Note from Fusion docs: "If the probe is set up to perform two touches, + // the first touch is at the Lead-In Feedrate and the second touch is at + // the Measure Feedrate." + measureFeed: currentSection.getParameter("operation:tool_feedProbeMeasure"), + // Set in the UI as "Link Feedrate", on the Tool tab. + linkFeed: currentSection.getParameter("operation:tool_feedProbeLink"), + // Set in the UI as "Lead-In Feedrate", on the Tool tab. + entryFeed: currentSection.getParameter("operation:tool_feedEntry"), + // Shown in the UI as "WCS to be updated". This cannot be set directly in + // the operation dialog under the Actions tab, it is derived from the + // WCS of the setup that the operation is part of. + drivingWcs: currentSection.workOffset, + // Set in the UI as "WCS" on the Actions tab. + // This is the WCS that will be updated with the probe results. + // "Override Driving WCS" checkbox in the Actions tab must be checked + // for this option to be set and to have any effect. + targetWcs: currentSection.probeWorkOffset, + // Set in the UI by checking the "Override Driving WCS" checkbox in the Actions tab. + updateDrivingWCS: getParameter("operation:probe_overrideWorkOffset"), + approach1: cycle.approach1 == "positive" ? 1 : -1, + approach2: cycle.approach2 == "positive" ? 1 : -1, + // The type of sensor in use, normally open (NO), or normally closed (NC). + // This is configured in the post processor parameters. + probeSensorType: getProperty("probeSensorType"), + }; + + // probeMove constructs functions that move the probe at a specified rate in + // absolute mode. Coordinates are given as maps of the form {x:n, y:n, z:n}. + // Giving two or more coordinates will execute multiple separate moves. + // protected = true uses G moves based on sensor type, which will stop in the + // event of a collision. + const probeMove = (motion, feed, absolute = true) => { + return (...axes) => { + for (const { x, y, z } of axes) { + const args = [ + motion.startsWith("G38.") + ? null + : gAbsIncModal.format(absolute ? 90 : 91), + motion, + ].filter(Boolean); + + forceXYZ(); + x && args.push(xOutput.format(x)); + y && args.push(yOutput.format(y)); + z && args.push(zOutput.format(z)); + + feedOutput.reset(); + if (feed) args.push(feedOutput.format(feed)); + + writeBlock.apply(null, args); + } + }; + }; + + // Absolute moves + handler.absoluteRapidMove = probeMove(gFormat.format(0), null, true); + handler.absoluteMove = probeMove(gFormat.format(1), handler.entryFeed, true); + + // Relative moves without probing. + handler.relativeMove = probeMove(gFormat.format(1), handler.entryFeed, false); + handler.safeRelativeMove = probeMove( + gFormat.format(handler.probeSensorType == "NC" ? 38.5 : 38.3), + handler.entryFeed, + false + ); + + // Relative moves with probing. + handler.measureMoveFast = probeMove( + gFormat.format(handler.probeSensorType == "NC" ? 38.4 : 38.2), + handler.measureFeed * 2, + false + ); + handler.measureMoveSlow = probeMove( + gFormat.format(handler.probeSensorType == "NC" ? 38.4 : 38.2), + handler.measureFeed, + false + ); + + // updateWCS updates the WCS for this probe using the axis and WCS offset provided, + // but only if updateDrivingWCS is true. + handler.updateWCS = (axis, offset) => { + if (!handler.updateDrivingWCS) return; + + writeBlock( + gFormat.format(10), + `L20 P${handler.targetWcs}`, + axis.format(offset) + ); + }; + + handler.extractAxisAndDistance = (options) => { + const axis = ["x", "y", "z"].find( + (axis) => + Object.keys(options).includes(axis) && options[axis] !== undefined + ); + + if (!axis) { + error(localize("Error determining axis for probing operation.")); + return null; + } + + const distance = options[axis]; + if (!distance || isNaN(distance)) { + error(localize("Invalid distance for probing operation.")); + return null; + } + + return { axis, distance }; + }; + + // touchProbe measures on the provided axis in the direction indicated by the sign of the value. + // It double-taps and leaves the probe touching the material after the second touch. + handler.touchProbe = (options) => { + const { axis, distance } = handler.extractAxisAndDistance(options); + + handler.measureMoveFast({ [axis]: distance }); + handler.relativeMove({ [axis]: -Math.sign(distance) * tool.diameter }); + handler.measureMoveSlow({ + [axis]: Math.sign(distance) * tool.diameter * 2, + }); + }; + + // touchUpdateRetract probes using the handler.touchProbe function, + // then updates either the WCS or the provided variable, + // and finally retracts the probe away from the surface + // by the specified retract distance. + // If a retract distance is not specified, it defaults to the approach + // distance for the cycle. + handler.touchUpdateRetract = (options) => { + handler.touchProbe(options); + + const currentWCSPositions = { + x: "#5041", + y: "#5042", + z: "#5043", + }; + + const { axis, distance } = handler.extractAxisAndDistance(options); + + if (Object.keys(options).includes("variable")) { + // If a variable is provided, update it with the probe result. + const variable = options.variable.replace("#", ""); + const sign = distance < 0 ? "-" : "+"; + writeBlock( + `#${variable} = [${currentWCSPositions[axis]} ${sign} ${handler.probeRadius}]` + ); + } else { + // Otherwise, update the WCS for the current axis. + const output = [xOutput, yOutput, zOutput].find((o) => + o.format(0).startsWith(axis.toUpperCase()) + ); + + handler.updateWCS(output, -Math.sign(distance) * handler.probeRadius); + } + + // Retract away from the surface. + const retractDistance = + options.retractDistance || + options.approachDistance || + cycle.probeClearance || + tool.diameter || + 2; + + handler.relativeMove({ + [axis]: -Math.sign(distance) * retractDistance, + }); + }; + + var probingCycleTypes = [ + "probing-x", + "probing-y", + "probing-z", + "probing-x-wall", + "probing-y-wall", + "probing-x-channel", + "probing-y-channel", + "probing-x-channel-with-island", + "probing-y-channel-with-island", + "probing-xy-circular-boss", + "probing-xy-circular-partial-boss", + "probing-xy-circular-hole", + "probing-xy-circular-partial-hole", + "probing-xy-circular-hole-with-island", + "probing-xy-circular-partial-hole-with-island", + "probing-xy-rectangular-boss", + "probing-xy-rectangular-hole", + "probing-xy-rectangular-hole-with-island", + "probing-xy-inner-corner", + "probing-xy-outer-corner", + "probing-x-plane-angle", + "probing-y-plane-angle", + ]; + + // If a probe cycle is not implemented and falls back to the baseCycleHandler, + // we throw an error. + probingCycleTypes.forEach(function (v) { + handler[v] = (x, y, z) => { + error(localize(`Probing cycle '${v}' is not supported by Carvera.`)); + }; + }); + + var drillingCycleTypes = [ + "drilling", + "counter-boring", + "chip-breaking", + "deep-drilling", + "break-through-drilling", + "gun-drilling", + "tapping", + "left-tapping", + "right-tapping", + "tapping-with-chip-breakinreaming", + "boring", + "stop-boring", + "fine-boring", + "back-boring", + "circular-pocket-milling", + "thread-milling", + ]; + + // For drilling cycles we just call expandCyclePoint + drillingCycleTypes.forEach(function (v) { + handler[v] = function (x, y, z) { + expandCyclePoint(x, y, z); + }; + }); + + return handler; +} + +// makeraFirmwareCycleHandler sets up handlers for the probe cycle types supported by the stock firmware. +// These are limited to basic operations that set a WCS coincident to a face. +function makeraFirmwareCycleHandler(cycle, tool) { + const handler = baseCycleHandler(cycle, tool); + + const handlers = { + "probing-x": (x, y, z) => { + const probeDatum = x + handler.approach1 * cycle.probeClearance; + handler.safeRelativeMove({ z: -cycle.depth }); + handler.touchProbe({ + x: handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel), + }); + handler.updateWCS(xOutput, probeDatum); + handler.absoluteMove({ x: x }); + }, + "probing-y": (x, y, z) => { + const probeDatum = y + handler.approach1 * cycle.probeClearance; + handler.safeRelativeMove({ z: -cycle.depth }); + handler.touchProbe({ + y: handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel), + }); + handler.updateWCS(yOutput, probeDatum); + handler.absoluteMove({ y: y }); + }, + "probing-z": (x, y, z) => { + const probeDatum = z - cycle.depth; + // Prove all the way down + handler.touchProbe({ z: -120 }); + handler.updateWCS(zOutput, probeDatum); + }, + "probing-xy-outer-corner": (x, y, z) => { + const offset = cycle.probeClearance; + const probeDatumX = x + handler.approach1 * offset; + const probeDatumY = y + handler.approach2 * offset; + + // Move to start depth + handler.safeRelativeMove({ z: -cycle.depth }); + + // Probing X: move up in Y, probe in X, return to X, return to Y + writeComment(`probing x surface`); + handler.safeRelativeMove({ y: handler.approach2 * offset * 2 }); + handler.touchProbe({ + x: handler.approach1 * (offset + cycle.probeOvertravel), + }); + handler.updateWCS(xOutput, probeDatumX); + handler.absoluteMove({ x: x }, { y: y }); + + // Probing Y: move up in X, probe in Y, return to Y, return to X + writeComment(`probing y surface`); + handler.safeRelativeMove({ x: handler.approach1 * offset * 2 }); + handler.touchProbe({ + y: handler.approach2 * (offset + cycle.probeOvertravel), + }); + handler.updateWCS(yOutput, probeDatumY); + handler.absoluteMove({ y: y }, { x: x }); + }, + "probing-xy-inner-corner": (x, y, z) => { + const offset = cycle.probeClearance; + const probeDatumX = x + handler.approach1 * offset; + const probeDatumY = y + handler.approach2 * offset; + + // Move to start depth + handler.safeRelativeMove({ z: -cycle.depth }); + + writeComment(`probing x surface`); + handler.touchProbe({ + x: handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel), + }); + handler.updateWCS(xOutput, probeDatumX); + handler.absoluteMove({ x: x }); + + writeComment(`probing y surface`); + handler.touchProbe({ + y: handler.approach2 * (cycle.probeClearance + cycle.probeOvertravel), + }); + handler.updateWCS(yOutput, probeDatumY); + handler.absoluteMove({ y: y }); + }, + }; + + return { ...handler, ...handlers }; +} + +// communityFirmwareCycleHandler sets up handlers for the probe cycle types +// supported by the community firmware. +function communityFirmwareCycleHandler(cycle, tool) { + const handler = baseCycleHandler(cycle, tool); + + const widthProbe = (options) => { + writeComment(`Width probe with double tap - ${options.direction}`); + + function probeAxis(axis) { + if (!options[axis]) return; + + const value = options[axis]; + const probeApproach = + options.direction.toLowerCase() === "inward" + ? -handler.approach1 + : handler.approach1; + + // Move to the first side + handler.safeRelativeMove({ + [axis]: + handler.approach1 * + (value / 2 + probeApproach * options.approachDistance), + }); + + // Move down to probe depth + handler.safeRelativeMove({ z: -options.depth }); + + // Probe the first side and store the result in #101. + handler.touchUpdateRetract({ + [axis]: probeApproach * (options.approachDistance + options.overtravel), + variable: "#101", + }); + + // Retract up to the clearance height. + handler.relativeMove({ z: options.depth }); + + // Move across to the other side + handler.safeRelativeMove({ + [axis]: + 2 * + ((-handler.approach1 * value) / 2 + + probeApproach * options.approachDistance), + }); + + // Move down to the probing height again + handler.safeRelativeMove({ z: -options.depth }); + + // Probe the second side and store the result in #102. + handler.touchUpdateRetract({ + [axis]: -probeApproach * (value / 2 + options.approachDistance), + variable: "#102", + }); + + // Retract up to the clearance height. + handler.safeRelativeMove({ z: options.depth }); + + // Move to axis midpoint + writeBlock( + gAbsIncModal.format(90), + gFormat.format(1), + `${axis.toUpperCase()}[[#101+#102]/2]` + ); + + // WCS update + if (handler.updateDrivingWCS) { + writeBlock( + gFormat.format(10), + `L20 P${handler.targetWcs}`, + `${axis.toUpperCase()}0` + ); + } + } + + ["x", "y"].forEach(probeAxis); + }; + + const angleProbe = (options) => { + writeComment(`Angle probe with double tap`); + + // Move down to the probing height. + handler.safeRelativeMove({ z: -options.depth }); + + const angleRadians = (options.nominalAngle * Math.PI) / 180; + + const probeAxis = (axis) => { + if (!options[axis]) return; + + // Convert to cartesian. + const xTravel = (options[axis] / 2) * Math.cos(angleRadians); + const yTravel = (options[axis] / 2) * Math.sin(angleRadians); + const probeArgs = { + r: options.approachDistance, + [axis]: + handler.approach1 * (options.approachDistance + options.overtravel), + }; + + // Move to the first side. + handler.safeRelativeMove({ + x: xTravel, + y: yTravel, + }); + + // Probe with double tap. + handler.touchProbe(probeArgs); + + // Save current position x and y in #101 and #102 respectively. + writeBlock("#101 = #5021"); + writeBlock("#102 = #5022"); + + // Retract away from the surface. + handler.relativeMove({ + [axis]: -handler.approach1 * options.approachDistance, + }); + + // Move across to the other side. + handler.safeRelativeMove({ + x: -2 * xTravel, + y: -2 * yTravel, + }); + + // Probe again. + handler.touchProbe(probeArgs); + + // Store the angle in #103. + writeBlock(`#103=atan[[#5022-#102]/[#5021 - #101]]`); + + // Retract away from the surface. + handler.relativeMove({ + [axis]: -handler.approach1 * options.approachDistance, + }); + + // Return to the midpoint. + handler.relativeMove({ + x: xTravel, + y: yTravel, + }); + + // Set the WCS rotation. + if (handler.updateDrivingWCS) { + const offset = axis == "x" ? "- 90" : ""; + writeBlock( + gFormat.format(10), + `L20 P${handler.targetWcs}`, + `R[abs[#103 ${offset}]]` + ); + } + }; + + ["x", "y"].forEach(probeAxis); + }; + + const handlers = { + "probing-x": (x, y, z) => { + // Move to the probing height, stop on contact. + handler.safeRelativeMove({ z: cycle.bottom - z }); + + handler.touchUpdateRetract({ + x: handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel), + }); + }, + "probing-x-channel": (x, y, z) => { + widthProbe({ + direction: "outward", + overtravel: cycle.probeOvertravel, + depth: cycle.depth, + approachDistance: cycle.probeClearance, + x: cycle.width1, + }); + }, + "probing-x-channel-with-island": (x, y, z) => { + widthProbe({ + direction: "outward", + overtravel: cycle.probeOvertravel, + depth: cycle.depth, + approachDistance: cycle.probeClearance, + x: cycle.width1, + }); + }, + "probing-x-wall": (x, y, z) => { + widthProbe({ + direction: "inward", + overtravel: cycle.probeOvertravel, + depth: cycle.depth, + approachDistance: cycle.probeClearance, + x: cycle.width1, + }); + }, + "probing-y": (x, y, z) => { + // Move to the probing height, stop on contact. + handler.safeRelativeMove({ z: cycle.bottom - z }); + + handler.touchUpdateRetract({ + y: handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel), + }); + }, + "probing-y-channel": (x, y, z) => { + widthProbe({ + direction: "outward", + overtravel: cycle.probeOvertravel, + depth: cycle.depth, + approachDistance: cycle.probeClearance, + y: cycle.width1, + }); + }, + "probing-y-channel-with-island": (x, y, z) => { + widthProbe({ + direction: "outward", + overtravel: cycle.probeOvertravel, + depth: cycle.depth, + approachDistance: cycle.probeClearance, + y: cycle.width1, + }); + }, + "probing-y-wall": (x, y, z) => { + widthProbe({ + direction: "inward", + overtravel: cycle.probeOvertravel, + depth: cycle.depth, + approachDistance: cycle.probeClearance, + y: cycle.width1, + }); + }, + "probing-z": (x, y, z) => { + const probeDepth = isFirstOperationProbeZ() + ? handler.approach1 * 120 + : handler.approach1 * + (cycle.depth + cycle.probeClearance + cycle.probeOvertravel); + + handler.touchProbe({ + z: probeDepth, + }); + + handler.updateWCS(zOutput, 0); + }, + "probing-xy-inner-corner": (x, y, z) => { + // Move down to the probing height. + handler.safeRelativeMove({ z: cycle.bottom - z }); + + // Probe the X. + handler.touchUpdateRetract({ + x: handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel), + }); + + // Probe the Y. + handler.touchUpdateRetract({ + y: handler.approach2 * (cycle.probeClearance + cycle.probeOvertravel), + }); + }, + "probing-xy-rectangular-boss": (x, y, z) => { + widthProbe({ + direction: "inward", + overtravel: cycle.probeOvertravel, + depth: cycle.depth, + approachDistance: cycle.probeClearance, + x: cycle.width1, + y: cycle.width2, + }); + }, + "probing-xy-circular-boss": (x, y, z) => { + widthProbe({ + direction: "inward", + overtravel: cycle.probeOvertravel, + depth: cycle.depth, + approachDistance: cycle.probeClearance, + x: cycle.width1, + y: cycle.width1, + }); + }, + "probing-xy-circular-hole": (x, y, z) => { + widthProbe({ + direction: "outward", + overtravel: cycle.probeOvertravel, + depth: cycle.depth, + approachDistance: cycle.probeClearance, + x: cycle.width1, + y: cycle.width1, + }); + }, + "probing-xy-circular-hole-with-island": (x, y, z) => { + widthProbe({ + direction: "outward", + overtravel: cycle.probeOvertravel, + depth: cycle.depth, + approachDistance: cycle.probeClearance, + x: cycle.width1, + y: cycle.width1, + }); + }, + "probing-xy-rectangular-hole": (x, y, z) => { + widthProbe({ + direction: "outward", + overtravel: cycle.probeOvertravel, + depth: cycle.depth, + approachDistance: cycle.probeClearance, + x: cycle.width1, + y: cycle.width2, + }); + }, + "probing-xy-rectangular-hole-with-island": (x, y, z) => { + widthProbe({ + direction: "outward", + overtravel: cycle.probeOvertravel, + depth: cycle.depth, + approachDistance: cycle.probeClearance, + x: cycle.width1, + y: cycle.width2, + }); + }, + "probing-xy-outer-corner": (x, y, z) => { + // Move down to the probing height. + handler.safeRelativeMove({ z: cycle.bottom - z }); + + // Move along the y to the position where we'll probe the x. + handler.safeRelativeMove({ + y: handler.approach2 * (cycle.probeClearance + cycle.probeOvertravel), + }); + + handler.touchUpdateRetract({ + x: handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel), + }); + + // Move back to the original y position. + handler.relativeMove({ + y: -handler.approach2 * (cycle.probeClearance + cycle.probeOvertravel), + }); + + // Move along the x to the position where we'll probe the y. + handler.safeRelativeMove({ + x: handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel), + }); + + handler.touchUpdateRetract({ + y: handler.approach2 * (cycle.probeClearance + cycle.probeOvertravel), + }); + + // Move back to the original x position. + handler.relativeMove({ + x: -handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel), + }); + }, + "probing-x-plane-angle": (x, y, z) => { + angleProbe({ + nominalAngle: cycle.nominalAngle, + approachDistance: cycle.probeClearance, + overtravel: cycle.probeOvertravel, + depth: cycle.depth, + x: cycle.probeSpacing, + }); + }, + "probing-y-plane-angle": (x, y, z) => { + angleProbe({ + nominalAngle: cycle.nominalAngle, + approachDistance: cycle.probeClearance, + overtravel: cycle.probeOvertravel, + depth: cycle.depth, + y: cycle.probeSpacing, + }); + }, + }; + + // Set up aliases for similar probing strategies. + return { ...handler, ...handlers }; +} + +// Reference to this cycle, cleaned up at end +var cycleHandler = null; + +// onCycle will set up the global cycleHandler. +function onCycle() { + if (getProperty("firmwareType") == "community") { + cycleHandler = communityFirmwareCycleHandler(cycle, tool); + } else { + cycleHandler = makeraFirmwareCycleHandler(cycle, tool); + } + + writeComment(`Begin ${cycleType}`); + writeComment( + `WCS used during probing: G${calculateWCS(cycleHandler.drivingWcs)}` + ); + if (cycleHandler.updateDrivingWCS) { + writeComment( + `WCS that will be updated: G${calculateWCS(cycleHandler.targetWcs)}` + ); + } +} + +// onCycleEnd currently just logs. +function onCycleEnd() { + cycleHandler = null; + writeComment("End " + cycleType); + + forceAny(); +} + +// Copied from heidenhain.cps, just enough to make the test in onCyclePoint work. +function getForwardDirection(_section) { + if (_section.isMultiAxis()) { + return _section.workPlane.forward; + } + return getRotation().forward; +} + +function isFirstOperationProbeZ() { + return ( + isFirstSection() && + currentSection.getParameter("operation:probingType") == "probing-z" + ); +} + +// onCyclePoint dispatches to a cycle handler based on the cycleType. +function onCyclePoint(x, y, z) { + // Check spindle orientation vs forward direction of this section. We can't, for instance, + // have the probe attempt to come in sideways as is done in the default probing strategies sample. + if ( + !isSameDirection( + machineConfiguration.getSpindleAxis(), + getForwardDirection(currentSection) + ) + ) { + error( + localize( + "direction of " + + cycleType + + " is not in same direction as spindle axis" + ) + ); + return; + } + + if (cycleHandler[cycleType] == null) { + warning(localize(cycleType + " has no handler and will be expanded")); + expandCyclePoint(x, y, z); + } + + // If the first operation is a Z probe, we blocked the X,Y,Z rapid in onSection, so + // we need to do the initial X,Y move here. Then the probe will go do its thing. + if (isFirstOperationProbeZ()) { + cycleHandler.absoluteMove({ x: x, y: y }); + } else { + cycleHandler.absoluteMove({ x: x, y: y, z: z }); + } + + // Call the handler for this cycleType + cycleHandler[cycleType](x, y, z); + + // Retract in to the cycle clearance height. + cycleHandler.absoluteRapidMove({ z: cycle.clearance }); +} + +// ====================================================== // +// ================= END CYCLE HANDLERS ================= // +// ====================================================== // + var pendingRadiusCompensation = -1; function onRadiusCompensation() { @@ -1146,10 +2185,20 @@ function onRapid(_x, _y, _z) { var z = zOutput.format(_z); if (x || y || z) { if (pendingRadiusCompensation >= 0) { - error(localize("Radius compensation mode cannot be changed at rapid traversal.")); + error( + localize( + "Radius compensation mode cannot be changed at rapid traversal." + ) + ); return; } - writeBlock(gMotionModal.format(0), x, y, z); + + if (isFirstOperationProbeZ()) { + writeBlock(gMotionModal.format(0), x, y); + } else { + writeBlock(gMotionModal.format(0), x, y, z); + } + feedOutput.reset(); } } @@ -1173,7 +2222,8 @@ function onLinear(_x, _y, _z, feed) { writeBlock(gMotionModal.format(1), x, y, z, f); } } else if (f) { - if (getNextRecord().isMotion()) { // try not to output feed without motion + if (getNextRecord().isMotion()) { + // try not to output feed without motion feedOutput.reset(); // force feed on next line } else { writeBlock(gMotionModal.format(1), f); @@ -1194,7 +2244,10 @@ function getFeed(f) { } forceFeed(); currentFeedId = feedContext.id; - return settings.parametricFeeds.feedOutputVariable + (settings.parametricFeeds.firstFeedParameter + feedContext.id); + return ( + settings.parametricFeeds.feedOutputVariable + + (settings.parametricFeeds.firstFeedParameter + feedContext.id) + ); } } currentFeedId = undefined; // force parametric feed next time @@ -1206,7 +2259,9 @@ function getFeed(f) { // >>>>> 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.")); + error( + localize("Radius compensation mode cannot be changed at rapid traversal.") + ); return; } if (!currentSection.isOptimizedForMachine()) { @@ -1215,9 +2270,15 @@ function onRapid5D(_x, _y, _z, _a, _b, _c) { 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); + 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); @@ -1228,7 +2289,11 @@ function onRapid5D(_x, _y, _z, _a, _b, _c) { // >>>>> 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.")); + error( + localize( + "Radius compensation cannot be activated/deactivated for 5-axis move." + ) + ); return; } if (!currentSection.isOptimizedForMachine()) { @@ -1237,19 +2302,40 @@ function onLinear5D(_x, _y, _z, _a, _b, _c, feed, feedMode) { 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); + 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) { feedOutput.reset(); } - var f = feedMode == FEED_INVERSE_TIME ? inverseTimeOutput.format(feed) : getFeed(feed); - var fMode = feedMode == FEED_INVERSE_TIME ? 93 : getProperty("useG95") ? 95 : 94; + 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); + 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 + if (getNextRecord().isMotion()) { + // try not to output feed without motion feedOutput.reset(); // force feed on next line } else { writeBlock(gFeedModeModal.format(fMode), gMotionModal.format(1), f); @@ -1259,24 +2345,24 @@ function onLinear5D(_x, _y, _z, _a, _b, _c, feed, feedMode) { function forceCircular(plane) { switch (plane) { - case PLANE_XY: - xOutput.reset(); - yOutput.reset(); - iOutput.reset(); - jOutput.reset(); - break; - case PLANE_ZX: - zOutput.reset(); - xOutput.reset(); - kOutput.reset(); - iOutput.reset(); - break; - case PLANE_YZ: - yOutput.reset(); - zOutput.reset(); - jOutput.reset(); - kOutput.reset(); - break; + case PLANE_XY: + xOutput.reset(); + yOutput.reset(); + iOutput.reset(); + jOutput.reset(); + break; + case PLANE_ZX: + zOutput.reset(); + xOutput.reset(); + kOutput.reset(); + iOutput.reset(); + break; + case PLANE_YZ: + yOutput.reset(); + zOutput.reset(); + jOutput.reset(); + kOutput.reset(); + break; } } @@ -1284,7 +2370,11 @@ function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { // one of X/Y and I/J are required and likewise if (pendingRadiusCompensation >= 0) { - error(localize("Radius compensation cannot be activated/deactivated for a circular move.")); + error( + localize( + "Radius compensation cannot be activated/deactivated for a circular move." + ) + ); return; } @@ -1296,51 +2386,105 @@ function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { return; } switch (getCircularPlane()) { - case PLANE_XY: - forceCircular(getCircularPlane()); - writeBlock(gPlaneModal.format(17), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), iOutput.format(cx - start.x), jOutput.format(cy - start.y), feedOutput.format(feed)); - break; - case PLANE_ZX: - forceCircular(getCircularPlane()); - writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), zOutput.format(z), iOutput.format(cx - start.x), kOutput.format(cz - start.z), feedOutput.format(feed)); - break; - case PLANE_YZ: - forceCircular(getCircularPlane()); - writeBlock(gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), yOutput.format(y), jOutput.format(cy - start.y), kOutput.format(cz - start.z), feedOutput.format(feed)); - break; - default: - linearize(tolerance); + case PLANE_XY: + forceCircular(getCircularPlane()); + writeBlock( + gPlaneModal.format(17), + gMotionModal.format(clockwise ? 2 : 3), + xOutput.format(x), + iOutput.format(cx - start.x), + jOutput.format(cy - start.y), + feedOutput.format(feed) + ); + break; + case PLANE_ZX: + forceCircular(getCircularPlane()); + writeBlock( + gPlaneModal.format(18), + gMotionModal.format(clockwise ? 2 : 3), + zOutput.format(z), + iOutput.format(cx - start.x), + kOutput.format(cz - start.z), + feedOutput.format(feed) + ); + break; + case PLANE_YZ: + forceCircular(getCircularPlane()); + writeBlock( + gPlaneModal.format(19), + gMotionModal.format(clockwise ? 2 : 3), + yOutput.format(y), + jOutput.format(cy - start.y), + kOutput.format(cz - start.z), + feedOutput.format(feed) + ); + break; + default: + linearize(tolerance); } } else { switch (getCircularPlane()) { - case PLANE_XY: - forceCircular(getCircularPlane()); - 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), feedOutput.format(feed)); - break; - case PLANE_ZX: - forceCircular(getCircularPlane()); - 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), feedOutput.format(feed)); - break; - case PLANE_YZ: - forceCircular(getCircularPlane()); - 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), feedOutput.format(feed)); - break; - default: - linearize(tolerance); + case PLANE_XY: + forceCircular(getCircularPlane()); + 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), + feedOutput.format(feed) + ); + break; + case PLANE_ZX: + forceCircular(getCircularPlane()); + 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), + feedOutput.format(feed) + ); + break; + case PLANE_YZ: + forceCircular(getCircularPlane()); + 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), + feedOutput.format(feed) + ); + break; + default: + 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 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() { @@ -1348,60 +2492,63 @@ function forceWorkPlane() { } var mapCommand = { - COMMAND_STOP : 0, - COMMAND_END : 2, - COMMAND_SPINDLE_CLOCKWISE : 3, + COMMAND_STOP: 0, + COMMAND_END: 2, + COMMAND_SPINDLE_CLOCKWISE: 3, COMMAND_SPINDLE_COUNTERCLOCKWISE: 4, - COMMAND_STOP_SPINDLE : 5 + COMMAND_STOP_SPINDLE: 5, }; function onCommand(command) { switch (command) { - case COMMAND_STOP: - writeBlock(mFormat.format(600)); - forceSpindleSpeed = true; - forceCoolant = true; - if (getProperty("defaultUseExternalControl")) { - writeBlock(mFormat.format(852)); - } - return; - case COMMAND_STOP_SPINDLE: - writeBlock(mFormat.format(5)); - forceSpindleSpeed = true; - forceCoolant = true; - if (getProperty("defaultUseExternalControl")) { - writeBlock(mFormat.format(852)); - } - return; - case COMMAND_OPTIONAL_STOP: - writeComment("Optional Stop Start"); - writeBlock(mFormat.format(1)); - forceSpindleSpeed = true; - forceCoolant = true; - if (getProperty("defaultUseExternalControl")) { - writeBlock(mFormat.format(852)); - } - writeComment("Optional Stop End"); - return; - case COMMAND_START_SPINDLE: - if (getProperty("defaultUseExternalControl")) { - writeBlock(mFormat.format(851), pwmOutput.format(100)); - } - onCommand(tool.clockwise ? COMMAND_SPINDLE_CLOCKWISE : COMMAND_SPINDLE_COUNTERCLOCKWISE); - return; - case COMMAND_LOCK_MULTI_AXIS: - return; - case COMMAND_UNLOCK_MULTI_AXIS: - return; - case COMMAND_TOOL_MEASURE: - writeComment("Calibrate TLO"); - writeBlock(mFormat.format(490)); - return; - case COMMAND_BREAK_CONTROL: - writeComment("Tool Break Test"); - writeBlock("M491.1"); - return; - + case COMMAND_STOP: + writeBlock(mFormat.format(600)); + forceSpindleSpeed = true; + forceCoolant = true; + if (getProperty("defaultUseExternalControl")) { + writeBlock(mFormat.format(852)); + } + return; + case COMMAND_STOP_SPINDLE: + writeBlock(mFormat.format(5)); + forceSpindleSpeed = true; + forceCoolant = true; + if (getProperty("defaultUseExternalControl")) { + writeBlock(mFormat.format(852)); + } + return; + case COMMAND_OPTIONAL_STOP: + writeComment("Optional Stop Start"); + writeBlock(mFormat.format(1)); + forceSpindleSpeed = true; + forceCoolant = true; + if (getProperty("defaultUseExternalControl")) { + writeBlock(mFormat.format(852)); + } + writeComment("Optional Stop End"); + return; + case COMMAND_START_SPINDLE: + if (getProperty("defaultUseExternalControl")) { + writeBlock(mFormat.format(851), pwmOutput.format(100)); + } + onCommand( + tool.clockwise + ? COMMAND_SPINDLE_CLOCKWISE + : COMMAND_SPINDLE_COUNTERCLOCKWISE + ); + return; + case COMMAND_LOCK_MULTI_AXIS: + return; + case COMMAND_UNLOCK_MULTI_AXIS: + return; + case COMMAND_TOOL_MEASURE: + writeComment("Calibrate TLO"); + writeBlock(mFormat.format(490)); + return; + case COMMAND_BREAK_CONTROL: + writeComment("Tool Break Test"); + writeBlock("M491.1"); + return; } var stringId = getCommandStringId(command); @@ -1418,7 +2565,7 @@ function onSectionEnd() { writeBlock(gFeedModeModal.format(94)); // inverse time feed off } writeBlock(gPlaneModal.format(17)); - if (!isLastSection() && (getNextSection().getTool().coolant != tool.coolant)) { + if (!isLastSection() && getNextSection().getTool().coolant != tool.coolant) { setCoolant(COOLANT_OFF); } forceAny(); @@ -1439,7 +2586,12 @@ function writeRetract() { } } else if (retractAxes[0]) { gMotionModal.reset(); - writeBlock(gAbsIncModal.format(90), gFormat.format(53), gMotionModal.format(0), "Z" + xyzFormat.format(toPreciseUnit(-3, MM))); + writeBlock( + gAbsIncModal.format(90), + gFormat.format(53), + gMotionModal.format(0), + "Z" + xyzFormat.format(toPreciseUnit(-3, MM)) + ); } } @@ -1467,13 +2619,22 @@ function getCoolantCodes(coolant) { if (!coolants) { error(localize("Coolants have not been defined.")); } - if (tool.type == TOOL_PROBE) { // avoid coolant output for probing + if (tool.type == TOOL_PROBE) { + // avoid coolant output for probing coolant = COOLANT_OFF; } - if (coolant == currentCoolantMode && (!forceCoolant || coolant == COOLANT_OFF)) { + if ( + coolant == currentCoolantMode && + (!forceCoolant || coolant == COOLANT_OFF) + ) { return undefined; // coolant is already active } - if ((coolant != COOLANT_OFF) && (currentCoolantMode != COOLANT_OFF) && (coolantOff != undefined) && !forceCoolant) { + if ( + coolant != COOLANT_OFF && + currentCoolantMode != COOLANT_OFF && + coolantOff != undefined && + !forceCoolant + ) { if (Array.isArray(coolantOff)) { for (var i in coolantOff) { multipleCoolantBlocks.push(coolantOff[i]); @@ -1486,7 +2647,8 @@ function getCoolantCodes(coolant) { var m; var coolantCodes = {}; - for (var c in coolants) { // find required coolant codes into the coolants array + 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) { @@ -1504,7 +2666,10 @@ function getCoolantCodes(coolant) { } if (coolant == COOLANT_OFF) { m = !coolantOff ? coolantCodes.off : coolantOff; - if (currentCoolantMode == COOLANT_AIR && getProperty("useExtForAirCoolant")) { + if ( + currentCoolantMode == COOLANT_AIR && + getProperty("useExtForAirCoolant") + ) { currentCoolantMode = coolant; return [mFormat.format(852)]; } From 6c25140c2200e03fdf5033f21feacefc28ca2f3f Mon Sep 17 00:00:00 2001 From: Jaun Terblanche Date: Tue, 26 Aug 2025 13:10:36 +0800 Subject: [PATCH 2/5] Bugfix: Drilling cycles causing fusion post process error when using this post processor. --- .../Fusion360-profiles/Carvera.cps | 369 ++++++++++-------- 1 file changed, 197 insertions(+), 172 deletions(-) diff --git a/CAM_Post_Processors/Fusion360-profiles/Carvera.cps b/CAM_Post_Processors/Fusion360-profiles/Carvera.cps index 9e6e724..3551c91 100644 --- a/CAM_Post_Processors/Fusion360-profiles/Carvera.cps +++ b/CAM_Post_Processors/Fusion360-profiles/Carvera.cps @@ -1405,7 +1405,6 @@ function calculateWCS(offset) { // your implementations. function baseCycleHandler(cycle, tool) { var handler = { - probeRadius: tool.diameter / 2, // Set in the UI as "Measure Feedrate" on the Tool tab. // Note from Fusion docs: "If the probe is set up to perform two touches, // the first touch is at the Lead-In Feedrate and the second touch is at @@ -1415,22 +1414,6 @@ function baseCycleHandler(cycle, tool) { linkFeed: currentSection.getParameter("operation:tool_feedProbeLink"), // Set in the UI as "Lead-In Feedrate", on the Tool tab. entryFeed: currentSection.getParameter("operation:tool_feedEntry"), - // Shown in the UI as "WCS to be updated". This cannot be set directly in - // the operation dialog under the Actions tab, it is derived from the - // WCS of the setup that the operation is part of. - drivingWcs: currentSection.workOffset, - // Set in the UI as "WCS" on the Actions tab. - // This is the WCS that will be updated with the probe results. - // "Override Driving WCS" checkbox in the Actions tab must be checked - // for this option to be set and to have any effect. - targetWcs: currentSection.probeWorkOffset, - // Set in the UI by checking the "Override Driving WCS" checkbox in the Actions tab. - updateDrivingWCS: getParameter("operation:probe_overrideWorkOffset"), - approach1: cycle.approach1 == "positive" ? 1 : -1, - approach2: cycle.approach2 == "positive" ? 1 : -1, - // The type of sensor in use, normally open (NO), or normally closed (NC). - // This is configured in the post processor parameters. - probeSensorType: getProperty("probeSensorType"), }; // probeMove constructs functions that move the probe at a specified rate in @@ -1467,172 +1450,206 @@ function baseCycleHandler(cycle, tool) { // Relative moves without probing. handler.relativeMove = probeMove(gFormat.format(1), handler.entryFeed, false); - handler.safeRelativeMove = probeMove( - gFormat.format(handler.probeSensorType == "NC" ? 38.5 : 38.3), - handler.entryFeed, - false - ); - - // Relative moves with probing. - handler.measureMoveFast = probeMove( - gFormat.format(handler.probeSensorType == "NC" ? 38.4 : 38.2), - handler.measureFeed * 2, - false - ); - handler.measureMoveSlow = probeMove( - gFormat.format(handler.probeSensorType == "NC" ? 38.4 : 38.2), - handler.measureFeed, - false - ); - // updateWCS updates the WCS for this probe using the axis and WCS offset provided, - // but only if updateDrivingWCS is true. - handler.updateWCS = (axis, offset) => { - if (!handler.updateDrivingWCS) return; + if (isProbeOperation()) { + handler = { + ...handler, + probeRadius: tool.diameter / 2, + // Shown in the UI as "WCS to be updated". This cannot be set directly in + // the operation dialog under the Actions tab, it is derived from the + // WCS of the setup that the operation is part of. + drivingWcs: currentSection.workOffset, + // Set in the UI as "WCS" on the Actions tab. + // This is the WCS that will be updated with the probe results. + // "Override Driving WCS" checkbox in the Actions tab must be checked + // for this option to be set and to have any effect. + targetWcs: currentSection.probeWorkOffset, + // Set in the UI by checking the "Override Driving WCS" checkbox in the Actions tab. + updateDrivingWCS: getParameter("operation:probe_overrideWorkOffset"), + approach1: cycle.approach1 == "positive" ? 1 : -1, + approach2: cycle.approach2 == "positive" ? 1 : -1, + // The type of sensor in use, normally open (NO), or normally closed (NC). + // This is configured in the post processor parameters. + probeSensorType: getProperty("probeSensorType"), + }; - writeBlock( - gFormat.format(10), - `L20 P${handler.targetWcs}`, - axis.format(offset) + handler.safeRelativeMove = probeMove( + gFormat.format(handler.probeSensorType == "NC" ? 38.5 : 38.3), + handler.entryFeed, + false ); - }; - handler.extractAxisAndDistance = (options) => { - const axis = ["x", "y", "z"].find( - (axis) => - Object.keys(options).includes(axis) && options[axis] !== undefined + // Relative moves with probing. + handler.measureMoveFast = probeMove( + gFormat.format(handler.probeSensorType == "NC" ? 38.4 : 38.2), + handler.measureFeed * 2, + false + ); + handler.measureMoveSlow = probeMove( + gFormat.format(handler.probeSensorType == "NC" ? 38.4 : 38.2), + handler.measureFeed, + false ); - if (!axis) { - error(localize("Error determining axis for probing operation.")); - return null; - } + // updateWCS updates the WCS for this probe using the axis and WCS offset provided, + // but only if updateDrivingWCS is true. + handler.updateWCS = (axis, offset) => { + if (!handler.updateDrivingWCS) return; - const distance = options[axis]; - if (!distance || isNaN(distance)) { - error(localize("Invalid distance for probing operation.")); - return null; - } + writeBlock( + gFormat.format(10), + `L20 P${handler.targetWcs}`, + axis.format(offset) + ); + }; - return { axis, distance }; - }; + handler.extractAxisAndDistance = (options) => { + const axis = ["x", "y", "z"].find( + (axis) => + Object.keys(options).includes(axis) && options[axis] !== undefined + ); - // touchProbe measures on the provided axis in the direction indicated by the sign of the value. - // It double-taps and leaves the probe touching the material after the second touch. - handler.touchProbe = (options) => { - const { axis, distance } = handler.extractAxisAndDistance(options); + if (!axis) { + error(localize("Error determining axis for probing operation.")); + return null; + } - handler.measureMoveFast({ [axis]: distance }); - handler.relativeMove({ [axis]: -Math.sign(distance) * tool.diameter }); - handler.measureMoveSlow({ - [axis]: Math.sign(distance) * tool.diameter * 2, - }); - }; + const distance = options[axis]; + if (!distance || isNaN(distance)) { + error(localize("Invalid distance for probing operation.")); + return null; + } - // touchUpdateRetract probes using the handler.touchProbe function, - // then updates either the WCS or the provided variable, - // and finally retracts the probe away from the surface - // by the specified retract distance. - // If a retract distance is not specified, it defaults to the approach - // distance for the cycle. - handler.touchUpdateRetract = (options) => { - handler.touchProbe(options); - - const currentWCSPositions = { - x: "#5041", - y: "#5042", - z: "#5043", + return { axis, distance }; }; - const { axis, distance } = handler.extractAxisAndDistance(options); + // touchProbe measures on the provided axis in the direction indicated by the sign of the value. + // It double-taps and leaves the probe touching the material after the second touch. + handler.touchProbe = (options) => { + const { axis, distance } = handler.extractAxisAndDistance(options); - if (Object.keys(options).includes("variable")) { - // If a variable is provided, update it with the probe result. - const variable = options.variable.replace("#", ""); - const sign = distance < 0 ? "-" : "+"; - writeBlock( - `#${variable} = [${currentWCSPositions[axis]} ${sign} ${handler.probeRadius}]` - ); - } else { - // Otherwise, update the WCS for the current axis. - const output = [xOutput, yOutput, zOutput].find((o) => - o.format(0).startsWith(axis.toUpperCase()) - ); + handler.measureMoveFast({ [axis]: distance }); + handler.relativeMove({ [axis]: -Math.sign(distance) * tool.diameter }); + handler.measureMoveSlow({ + [axis]: Math.sign(distance) * tool.diameter * 2, + }); + }; - handler.updateWCS(output, -Math.sign(distance) * handler.probeRadius); - } + // touchUpdateRetract probes using the handler.touchProbe function, + // then updates either the WCS or the provided variable, + // and finally retracts the probe away from the surface + // by the specified retract distance. + // If a retract distance is not specified, it defaults to the approach + // distance for the cycle. + handler.touchUpdateRetract = (options) => { + handler.touchProbe(options); + + const currentWCSPositions = { + x: "#5041", + y: "#5042", + z: "#5043", + }; - // Retract away from the surface. - const retractDistance = - options.retractDistance || - options.approachDistance || - cycle.probeClearance || - tool.diameter || - 2; + const { axis, distance } = handler.extractAxisAndDistance(options); - handler.relativeMove({ - [axis]: -Math.sign(distance) * retractDistance, - }); - }; + if (Object.keys(options).includes("variable")) { + // If a variable is provided, update it with the probe result. + const variable = options.variable.replace("#", ""); + const sign = distance < 0 ? "-" : "+"; + writeBlock( + `#${variable} = [${currentWCSPositions[axis]} ${sign} ${handler.probeRadius}]` + ); + } else { + // Otherwise, update the WCS for the current axis. + const output = [xOutput, yOutput, zOutput].find((o) => + o.format(0).startsWith(axis.toUpperCase()) + ); - var probingCycleTypes = [ - "probing-x", - "probing-y", - "probing-z", - "probing-x-wall", - "probing-y-wall", - "probing-x-channel", - "probing-y-channel", - "probing-x-channel-with-island", - "probing-y-channel-with-island", - "probing-xy-circular-boss", - "probing-xy-circular-partial-boss", - "probing-xy-circular-hole", - "probing-xy-circular-partial-hole", - "probing-xy-circular-hole-with-island", - "probing-xy-circular-partial-hole-with-island", - "probing-xy-rectangular-boss", - "probing-xy-rectangular-hole", - "probing-xy-rectangular-hole-with-island", - "probing-xy-inner-corner", - "probing-xy-outer-corner", - "probing-x-plane-angle", - "probing-y-plane-angle", - ]; + handler.updateWCS(output, -Math.sign(distance) * handler.probeRadius); + } - // If a probe cycle is not implemented and falls back to the baseCycleHandler, - // we throw an error. - probingCycleTypes.forEach(function (v) { - handler[v] = (x, y, z) => { - error(localize(`Probing cycle '${v}' is not supported by Carvera.`)); + // Retract away from the surface. + const retractDistance = + options.retractDistance || + options.approachDistance || + cycle.probeClearance || + tool.diameter || + 2; + + handler.relativeMove({ + [axis]: -Math.sign(distance) * retractDistance, + }); }; - }); - - var drillingCycleTypes = [ - "drilling", - "counter-boring", - "chip-breaking", - "deep-drilling", - "break-through-drilling", - "gun-drilling", - "tapping", - "left-tapping", - "right-tapping", - "tapping-with-chip-breakinreaming", - "boring", - "stop-boring", - "fine-boring", - "back-boring", - "circular-pocket-milling", - "thread-milling", - ]; - - // For drilling cycles we just call expandCyclePoint - drillingCycleTypes.forEach(function (v) { - handler[v] = function (x, y, z) { - expandCyclePoint(x, y, z); + } + + if (isProbeOperation()) { + handler[cycleType] = (x, y, z) => { + error(localize(`Probing cycle '${v}' is not supported by Carvera.`)); }; - }); + } + + // var probingCycleTypes = [ + // "probing-x", + // "probing-y", + // "probing-z", + // "probing-x-wall", + // "probing-y-wall", + // "probing-x-channel", + // "probing-y-channel", + // "probing-x-channel-with-island", + // "probing-y-channel-with-island", + // "probing-xy-circular-boss", + // "probing-xy-circular-partial-boss", + // "probing-xy-circular-hole", + // "probing-xy-circular-partial-hole", + // "probing-xy-circular-hole-with-island", + // "probing-xy-circular-partial-hole-with-island", + // "probing-xy-rectangular-boss", + // "probing-xy-rectangular-hole", + // "probing-xy-rectangular-hole-with-island", + // "probing-xy-inner-corner", + // "probing-xy-outer-corner", + // "probing-x-plane-angle", + // "probing-y-plane-angle", + // ]; + + // If a probe cycle is not implemented and falls back to the baseCycleHandler, + // we throw an error. + // probingCycleTypes.forEach(function (v) { + // handler[v] = (x, y, z) => { + // error(localize(`Probing cycle '${v}' is not supported by Carvera.`)); + // }; + // }); + + handler.expandCyclePoint = (x, y, z) => { + expandCyclePoint(x, y, z); + }; + + // var drillingCycleTypes = [ + // "drilling", + // "counter-boring", + // "chip-breaking", + // "deep-drilling", + // "break-through-drilling", + // "gun-drilling", + // "tapping", + // "left-tapping", + // "right-tapping", + // "tapping-with-chip-breakinreaming", + // "boring", + // "stop-boring", + // "fine-boring", + // "back-boring", + // "circular-pocket-milling", + // "thread-milling", + // ]; + + // // For drilling cycles we just call expandCyclePoint + // drillingCycleTypes.forEach(function (v) { + // handler[v] = function (x, y, z) { + // expandCyclePoint(x, y, z); + // }; + // }); return handler; } @@ -2089,20 +2106,28 @@ var cycleHandler = null; // onCycle will set up the global cycleHandler. function onCycle() { - if (getProperty("firmwareType") == "community") { - cycleHandler = communityFirmwareCycleHandler(cycle, tool); + // Current cycle is not a probing cycle, so we simply provide a handler + // that expands cycle points. + if (!isProbeOperation()) { + cycleHandler = baseCycleHandler(cycle, tool); + cycleHandler[cycleType] = cycleHandler.expandCyclePoint; } else { - cycleHandler = makeraFirmwareCycleHandler(cycle, tool); - } + // Current cycle is a probing cycle. + if (getProperty("firmwareType") == "community") { + cycleHandler = communityFirmwareCycleHandler(cycle, tool); + } else { + cycleHandler = makeraFirmwareCycleHandler(cycle, tool); + } - writeComment(`Begin ${cycleType}`); - writeComment( - `WCS used during probing: G${calculateWCS(cycleHandler.drivingWcs)}` - ); - if (cycleHandler.updateDrivingWCS) { + writeComment(`Begin ${cycleType}`); writeComment( - `WCS that will be updated: G${calculateWCS(cycleHandler.targetWcs)}` + `WCS used during probing: G${calculateWCS(cycleHandler.drivingWcs)}` ); + if (cycleHandler.updateDrivingWCS) { + writeComment( + `WCS that will be updated: G${calculateWCS(cycleHandler.targetWcs)}` + ); + } } } From ccd0eff2e7f8a6c33d3ac6f61f3908ede34ac4c3 Mon Sep 17 00:00:00 2001 From: Jaun Terblanche Date: Thu, 28 Aug 2025 11:30:23 +0800 Subject: [PATCH 3/5] Add x-axis flex comp --- .../Fusion360-profiles/Carvera.cps | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/CAM_Post_Processors/Fusion360-profiles/Carvera.cps b/CAM_Post_Processors/Fusion360-profiles/Carvera.cps index 3551c91..e2c4d01 100644 --- a/CAM_Post_Processors/Fusion360-profiles/Carvera.cps +++ b/CAM_Post_Processors/Fusion360-profiles/Carvera.cps @@ -161,6 +161,14 @@ properties = { value: true, scope: "post", }, + loadFlexComp: { + title: "Load/Enable X-Axis Flex Compensation", + description: "Load and enable X-Axis Flex Compensation", + group: "preferences", + type: "boolean", + value: true, + scope: "post", + }, defaultUseExternalControl: { title: "Spindle-based External Control", description: @@ -416,6 +424,10 @@ function onParameter(name, value) { writeBlock("G92.4 A0 S0 (shrink the a axis so A365 becomes A5)"); } else if (String(value).toUpperCase() == "SAFEZ") { writeBlock("G53 G0 Z -2. (Goto Safe Height In Z)"); + } else if (String(value).toUpperCase() == "ENABLEFLEXCOMP") { + writeBlock("M380.3 (Enable Flex Compensation)"); + } else if (String(value).toUpperCase() == "DISABLEFLEXCOMP") { + writeBlock("M380 (Disable Flex Compensation)"); } else { var sText1 = String(value); var sText2 = new Array(); @@ -772,6 +784,10 @@ function onOpen() { writeBlock(gAbsIncModal.format(90), gFeedModeModal.format(94)); writeBlock(gPlaneModal.format(17)); + if (getProperty("loadFlexComp") != false) { + writeBlock("M380.3 (Enable Flex Compensation)"); + } + switch (unit) { case IN: writeBlock(gUnitModal.format(20)); From 6fb85b3d7d7135b63567978f0a27fa134abfe515 Mon Sep 17 00:00:00 2001 From: Jaun Terblanche Date: Mon, 27 Apr 2026 08:27:58 +0800 Subject: [PATCH 4/5] Update settings.json --- .vscode/settings.json | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..a06786a --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,37 @@ +{ + "workbench.colorCustomizations": { + "activityBar.background": "#05284A", + "titleBar.activeBackground": "#063867", + "titleBar.activeForeground": "#F8FBFF", + "titleBar.inactiveBackground": "#05284A", + "titleBar.inactiveForeground": "#F8FBFF", + "statusBar.background": "#05284A", + "statusBar.foreground": "#F8FBFF", + "statusBar.debuggingBackground": "#05284A", + "statusBar.debuggingForeground": "#F8FBFF", + "statusBar.noFolderBackground": "#05284A", + "statusBar.noFolderForeground": "#F8FBFF" + }, + // } + // { + // Use Prettier for JS-like files + "[javascript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.tabSize": 2, + "editor.insertSpaces": true, + "editor.detectIndentation": false + }, + // Core Prettier style to resemble paste-2.txt + "prettier.useTabs": false, + "prettier.tabWidth": 2, + "prettier.singleQuote": false, + "prettier.trailingComma": "none", + "prettier.semi": true, + "prettier.bracketSpacing": true, + "prettier.arrowParens": "always", + // Keep lines reasonably narrow so function calls wrap like paste-2.txt + "prettier.printWidth": 80, + // Make sure VS Code actually uses Prettier on save/format + "editor.formatOnSave": false, + "editor.defaultFormatter": "esbenp.prettier-vscode" +} \ No newline at end of file From 6f2165e93b5a3f2f523054ee4c80eb6623f6297c Mon Sep 17 00:00:00 2001 From: jterblanche <4882099+jterblanche@users.noreply.github.com> Date: Mon, 27 Apr 2026 08:34:28 +0800 Subject: [PATCH 5/5] Sync with upstream Fusion-1.43 --- .DS_Store | Bin 0 -> 6148 bytes .../Fusion360-profiles/Carvera.cps | 819 ++++++++++++++---- 2 files changed, 651 insertions(+), 168 deletions(-) create mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..779fa60a36cb53e64cc793494fb0ec9370a4254c GIT binary patch literal 6148 zcmeHK%Sr=55Ukc50$u`MJkBrp2Ww1@g5U=zCVCPUvhltrzspZc^#ddOzYldUEci>LGc z7Ui%mQL7Y?0>=tm=62!ze@*{o{y!#ZCk3RySt($%)zfOpSE}ARc{%U3js8OSns2%r pn<&b<<}uH^!Z9)E%m tzMax) { + tzMax = zRange.getMaximum(); + } + if (zRange.getMinimum() < tzMin) { + tzMin = zRange.getMinimum(); + } + } + } + if (Math.abs(wcsZ - stockTop) < tol) { + zRef = "Stock Top"; + } else if (Math.abs(wcsZ - stockBot) < tol) { + zRef = "Stock Bottom"; + } else { + custom = true; + var dStockTop = wcsZ - stockTop; + zRef = + "Selected Point" + + " | " + + fmtZ(Math.abs(dStockTop)) + + (dStockTop < 0 ? " below" : " above") + + " Stock Top"; + } + + var sep = "==================================================="; + wcsComment(sep); + wcsComment(" Z Origin Set To : " + zRef); + wcsComment( + " Stock Height : " + fmtZ(stockTop - stockBot) + ); + if (custom) { + wcsComment(" Stock Above Origin : " + fmtZ(stockTop)); + wcsComment(" Stock Below Origin : " + fmtZ(stockBot)); + wcsComment(" Toolpath Z Maximum from origin: " + fmtZ(tzMax)); + wcsComment(" Toolpath Z Min from origin: " + fmtZ(tzMin)); + wcsComment( + " Toolpath Z Maximum from Stock Top: " + fmtZ(tzMax + dStockTop) + ); + wcsComment(" Toolpath Z Min from Stock Top: " + fmtZ(tzMin + dStockTop)); + } else { + wcsComment(" Toolpath Z Maximum from " + zRef + ": " + fmtZ(tzMax)); + wcsComment(" Toolpath Z Min from " + zRef + ": " + fmtZ(tzMin)); + } + wcsComment(""); + wcsComment(sep); + writeln(""); + + var partAttachPoint = currentSection.getPartAttachPoint(); + var modelPlane = currentSection.getModelPlane(); + + var right = modelPlane.right; + var up = modelPlane.up; + // Derive the true Z axis from right and up instead of using forward + var forward = Vector.cross(right, up); + + var localPartAttachPoint = new Vector( + Vector.dot(partAttachPoint, right), + Vector.dot(partAttachPoint, up), + Vector.dot(partAttachPoint, forward) + ); + var xoffset = -localPartAttachPoint.x; + var yoffset = -localPartAttachPoint.y; + var zoffset = -localPartAttachPoint.z; + + wcsComment( + "The following values are based on the part position info used in fusion and can be used to roughly align the machine offset from anchor 1 if you use that feature." + ); + wcsComment(" X Offset : " + fmtZ(xoffset)); + wcsComment(" Y Offset : " + fmtZ(yoffset)); + + writeln(""); + wcsComment(sep); + writeln(""); + if (getNumberOfSections() > 0 && getSection(0).workOffset == 0) { for (var i = 0; i < getNumberOfSections(); ++i) { if (getSection(i).workOffset > 0) { @@ -835,6 +1066,10 @@ function forceWorkPlane() { currentWorkPlaneABC = undefined; } +var currentAAngle = 0; +var previousAAngle = 0; +var toolOrientationUsed = false; + function defineWorkPlane(_section, _setWorkPlane) { var abc = new Vector(0, 0, 0); if (machineConfiguration.isMultiAxisConfiguration()) { @@ -851,17 +1086,73 @@ function defineWorkPlane(_section, _setWorkPlane) { } else { abc = getWorkPlaneMachineABC(_section.workPlane); if (_setWorkPlane) { - setWorkPlane(abc); + var tol = 1e-6; + if ( + !getProperty("useManual4thAxisRotations") || + Math.abs(abc.x) > tol || + Math.abs(abc.y) > tol || + Math.abs(abc.z) > tol || + toolOrientationUsed + ) { + setWorkPlane(abc); + toolOrientationUsed = true; + } } } } else { // pure 3D - var remaining = _section.workPlane; - if (!isSameDirection(remaining.forward, new Vector(0, 0, 1))) { - error(localize("Tool orientation is not supported.")); - return abc; + // Inject a 4th axis rotation if the WCS and model plane are not aligned + if (getProperty("rotate4thAxisRelativeToModelPlane")) { + var currOrigin = currentSection.modelOrigin; + + if (!currOrigin) { + error(localize("Unable to resolve WCS origin in world space.")); + } + + if (fourthAxisRotationPreviousLocation === undefined) { + fourthAxisRotationPreviousLocation = new Vector( + currOrigin.x, + currOrigin.y, + currOrigin.z + ); + } else { + var dx = fourthAxisRotationPreviousLocation.x - currOrigin.x; + var dy = fourthAxisRotationPreviousLocation.y - currOrigin.y; + var dz = fourthAxisRotationPreviousLocation.z - currOrigin.z; + if (dx * dx + dy * dy + dz * dz > 1e-12) { + error( + localize( + "Origin must be in the same location when automatic 4th axis rotation is used" + ) + ); + } + } + + previousAAngle = currentAAngle; + currentAAngle = calculateAAxisRotation(); + + if (Math.abs(currentAAngle - previousAAngle) > 0.001) { + // Only rotate if the angle change is relevant to avoid unnecessary retracts and moves + writeComment( + "Retracting to safe position for possible A axis rotation" + ); + writeRetract(Z, Y); + var angle = Math.round(currentAAngle * 1000) / 1000; + writeBlock( + gAbsIncModal.format(90), + gFormat.format(54), + gFormat.format(0), + "A" + angle, + formatComment("Rotate the A axis to align WCS and model plane") + ); } - setRotation(remaining); + } else { + var abc = getWorkPlaneMachineABC(_section.workPlane); + + if (_setWorkPlane) { + writeRetract(Z); + positionABC(abc, true); + } } if (currentSection && currentSection.getId() == _section.getId()) { operationSupportsTCP = @@ -875,11 +1166,53 @@ function defineWorkPlane(_section, _setWorkPlane) { )) ) { operationSupportsTCP = false; + } } } return abc; } +// Calculates the angle between previous model plane and a [current] model plane for A axis rotation +function calculateAAxisRotation() { + var relativeAngle = signedXPlaneRotationDeg(currentSection.getModelPlane()); + + return normalizeDegrees(relativeAngle); +} + +var rotationStartForward = null; +function signedXPlaneRotationDeg(plane) { + if (rotationStartForward == null) { + // First setup, set the initial plane and don't rotate + rotationStartForward = plane.forward; + return 0; + } + var planeForward = plane.forward; + + var dot = Vector.dot(rotationStartForward, planeForward); + if (dot > 1) dot = 1; + if (dot < -1) dot = -1; + + var theta = Math.acos(dot); // 0..pi + + // sign by X of cross(aForward, bForward) + var cross = Vector.cross(rotationStartForward, planeForward); + var sign = cross.x >= 0 ? 1 : -1; + + return normalizeDegrees(radToDeg(theta) * sign); +} + +// Convert radians to degrees +function radToDeg(theta) { + return (theta * 180.0) / Math.PI; +} + +// normalize to (-180,180) +function normalizeDegrees(deg) { + while (deg < -180) deg += 360; + while (deg > 180) deg -= 360; + return deg; +} + function setWorkPlane(abc) { if (!machineConfiguration.isMultiAxisConfiguration()) { return; // ignore @@ -1126,10 +1459,37 @@ function onSection() { setCoolant(COOLANT_OFF); + // Shank diameter change: add S1-S5 to M6 when shaft diameter changed (S1=3.175mm, S2=4mm, S3=6mm, S4=6.35mm, S5=8mm; do not change numbering) + // Use shaft segments (Tool tab) to match standard diameter; fallback to tool.shaftDiameter + var shaftDiameterMm = getToolShaftDiameterMm(tool); + var prevShaftMm = !isFirstSection() + ? getToolShaftDiameterMm(getPreviousSection().getTool()) + : 0; + var shankDiameterChanged = + !isFirstSection() && Math.abs(shaftDiameterMm - prevShaftMm) > 0.001; + var shaftParam = + shankDiameterChanged || isFirstSection() + ? getShankSizeSuffix(shaftDiameterMm) + : ""; + if (tool.number > numberOfToolSlots) { warning(localize("Tool number exceeds maximum value.")); } + if (tool.type == TOOL_LASER_CUTTER) { + writeToolBlock(mFormat.format(321)); + writeBlock("M106"); + laser_used = true; + return; + } + + if (laser_used) { + writeBlock("M5"); + writeBlock("M107"); + writeBlock("M322"); + laser_used = false; + } + var tloValue = parseTLO(tool.comment); //A is automatic and is the default, M is manual setting (C=0), a number set the value directly (H=-14) var e_manualToolChangeBehavior = getProperty("manualToolChangeBehavior"); @@ -1144,13 +1504,24 @@ function onSection() { if (e_manualToolChangeBehavior == "carvAirMtc") { //any tool number accepted - writeToolBlock(mFormat.format(6), "T" + toolFormat.format(tool.number)); + var toolChangeParameters = ""; + if (getProperty("useToolCommentForChangeParameters")) { + toolChangeParameters = tool.comment; + } + if (getProperty("issueColletChangeOnShankSizeChange")) { + toolChangeParameters = toolChangeParameters + " " + shaftParam; + } - if (tool.comment) { + writeToolBlock( + mFormat.format(6), + "T" + toolFormat.format(tool.number) + " " + toolChangeParameters + ); + + if (tool.comment && !getProperty("useToolCommentForChangeParameters")) { writeComment(tool.comment); } } else if (e_manualToolChangeBehavior == "carvcomMtc") { - if (tloValue) { + if (tloValue && !getProperty("useToolCommentForChangeParameters")) { if (tloValue === "A") { writeToolBlock( mFormat.format(6), @@ -1176,7 +1547,18 @@ function onSection() { } } } else { - writeToolBlock(mFormat.format(6), "T" + toolFormat.format(tool.number)); + var toolChangeParameters = ""; + if (getProperty("useToolCommentForChangeParameters")) { + toolChangeParameters = tool.comment; + } + if (getProperty("issueColletChangeOnShankSizeChange")) { + toolChangeParameters = toolChangeParameters + " " + shaftParam; + } + + writeToolBlock( + mFormat.format(6), + "T" + toolFormat.format(tool.number) + " " + toolChangeParameters + ); } } else if (tool.number > 6 || tool.manualToolChange) { writeComment("Manual Tool Change To #" + toolFormat.format(tool.number)); @@ -1186,16 +1568,6 @@ function onSection() { ); } performStockManualToolChange(tloValue); - } else if ( - !isFirstSection() && - getProperty("useShankSizeForManualChange") && - Math.abs( - tool.shaftDiameter - getPreviousSection().getTool().shaftDiameter - ) > 0.001 - ) { - writeComment("Manual Tool Change To #" + toolFormat.format(tool.number)); - writeComment("as a result of tool shank size change"); - performStockManualToolChange(tloValue); } else { if ( previousToolChangeWasManual && @@ -1253,13 +1625,15 @@ function onSection() { tool.clockwise != getPreviousSection().getTool().clockwise); if (spindleChanged) { forceSpindleSpeed = false; - if (spindleSpeed < 1) { + writeComment(tool.type); + if (spindleSpeed < 1 && tool.type != TOOL_LASER_CUTTER) { error(localize("Spindle speed out of range.")); } if (spindleSpeed > 99999) { warning(localize("Spindle speed exceeds maximum value.")); } if (getProperty("defaultUseExternalControl")) { + writeBlock(mFormat.format(400)); writeBlock(mFormat.format(851), pwmOutput.format(100)); } writeBlock( @@ -1273,6 +1647,24 @@ function onSection() { // force work offset when changing tool currentWorkOffset = undefined; } + if (currentSection.type == TYPE_JET) { + if (tool.type != TOOL_LASER_CUTTER) { + error( + localize( + "The CNC does not support the required tool/process. Only laser cutting is supported." + ) + ); + } + + switch (currentSection.jetMode) { + case JET_MODE_THROUGH: + case JET_MODE_ETCHING: + case JET_MODE_VAPORIZE: + break; + default: + error(localize("Unsupported cutting mode.")); + } + } if (currentSection.workOffset != currentWorkOffset) { writeBlock(currentSection.wcs); @@ -1332,6 +1724,7 @@ function onSection() { yOutput.format(initialPosition.y) ); } + writeJetCodes(true); } function performStockManualToolChange(tloValue) { @@ -1385,6 +1778,12 @@ function performStockManualToolChange(tloValue) { } } +function writeJetCodes(mode) { + if (currentSection.type == TYPE_JET && tool.type == TOOL_LASER_CUTTER) { + writeBlock(mFormat.format(mode ? 3 : 5)); // activate/deactivate laser + } +} + function onDwell(seconds) { if (seconds > 99999.999) { warning(localize("Dwelling time is out of range.")); @@ -1401,7 +1800,10 @@ function onDwell(seconds) { } function onSpindleSpeed(spindleSpeed) { - writeBlock(sOutput.format(spindleSpeed)); + writeBlock( + sOutput.format(spindleSpeed), + mFormat.format(tool.clockwise ? 3 : 4) + ); } function calculateWCS(offset) { @@ -1429,7 +1831,7 @@ function baseCycleHandler(cycle, tool) { // Set in the UI as "Link Feedrate", on the Tool tab. linkFeed: currentSection.getParameter("operation:tool_feedProbeLink"), // Set in the UI as "Lead-In Feedrate", on the Tool tab. - entryFeed: currentSection.getParameter("operation:tool_feedEntry"), + entryFeed: currentSection.getParameter("operation:tool_feedEntry") }; // probeMove constructs functions that move the probe at a specified rate in @@ -1444,7 +1846,7 @@ function baseCycleHandler(cycle, tool) { motion.startsWith("G38.") ? null : gAbsIncModal.format(absolute ? 90 : 91), - motion, + motion ].filter(Boolean); forceXYZ(); @@ -1486,7 +1888,7 @@ function baseCycleHandler(cycle, tool) { approach2: cycle.approach2 == "positive" ? 1 : -1, // The type of sensor in use, normally open (NO), or normally closed (NC). // This is configured in the post processor parameters. - probeSensorType: getProperty("probeSensorType"), + probeSensorType: getProperty("probeSensorType") }; handler.safeRelativeMove = probeMove( @@ -1547,7 +1949,7 @@ function baseCycleHandler(cycle, tool) { handler.measureMoveFast({ [axis]: distance }); handler.relativeMove({ [axis]: -Math.sign(distance) * tool.diameter }); handler.measureMoveSlow({ - [axis]: Math.sign(distance) * tool.diameter * 2, + [axis]: Math.sign(distance) * tool.diameter * 2 }); }; @@ -1563,7 +1965,7 @@ function baseCycleHandler(cycle, tool) { const currentWCSPositions = { x: "#5041", y: "#5042", - z: "#5043", + z: "#5043" }; const { axis, distance } = handler.extractAxisAndDistance(options); @@ -1593,14 +1995,14 @@ function baseCycleHandler(cycle, tool) { 2; handler.relativeMove({ - [axis]: -Math.sign(distance) * retractDistance, + [axis]: -Math.sign(distance) * retractDistance }); }; } if (isProbeOperation()) { handler[cycleType] = (x, y, z) => { - error(localize(`Probing cycle '${v}' is not supported by Carvera.`)); + error(localize(`Probing cycle '${cycleType}' is not supported by Carvera.`)); }; } @@ -1651,7 +2053,8 @@ function baseCycleHandler(cycle, tool) { // "tapping", // "left-tapping", // "right-tapping", - // "tapping-with-chip-breakinreaming", + // "tapping-with-chip-breaking", + // "reaming", // "boring", // "stop-boring", // "fine-boring", @@ -1680,7 +2083,7 @@ function makeraFirmwareCycleHandler(cycle, tool) { const probeDatum = x + handler.approach1 * cycle.probeClearance; handler.safeRelativeMove({ z: -cycle.depth }); handler.touchProbe({ - x: handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel), + x: handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel) }); handler.updateWCS(xOutput, probeDatum); handler.absoluteMove({ x: x }); @@ -1689,7 +2092,7 @@ function makeraFirmwareCycleHandler(cycle, tool) { const probeDatum = y + handler.approach1 * cycle.probeClearance; handler.safeRelativeMove({ z: -cycle.depth }); handler.touchProbe({ - y: handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel), + y: handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel) }); handler.updateWCS(yOutput, probeDatum); handler.absoluteMove({ y: y }); @@ -1712,7 +2115,7 @@ function makeraFirmwareCycleHandler(cycle, tool) { writeComment(`probing x surface`); handler.safeRelativeMove({ y: handler.approach2 * offset * 2 }); handler.touchProbe({ - x: handler.approach1 * (offset + cycle.probeOvertravel), + x: handler.approach1 * (offset + cycle.probeOvertravel) }); handler.updateWCS(xOutput, probeDatumX); handler.absoluteMove({ x: x }, { y: y }); @@ -1721,7 +2124,7 @@ function makeraFirmwareCycleHandler(cycle, tool) { writeComment(`probing y surface`); handler.safeRelativeMove({ x: handler.approach1 * offset * 2 }); handler.touchProbe({ - y: handler.approach2 * (offset + cycle.probeOvertravel), + y: handler.approach2 * (offset + cycle.probeOvertravel) }); handler.updateWCS(yOutput, probeDatumY); handler.absoluteMove({ y: y }, { x: x }); @@ -1736,18 +2139,18 @@ function makeraFirmwareCycleHandler(cycle, tool) { writeComment(`probing x surface`); handler.touchProbe({ - x: handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel), + x: handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel) }); handler.updateWCS(xOutput, probeDatumX); handler.absoluteMove({ x: x }); writeComment(`probing y surface`); handler.touchProbe({ - y: handler.approach2 * (cycle.probeClearance + cycle.probeOvertravel), + y: handler.approach2 * (cycle.probeClearance + cycle.probeOvertravel) }); handler.updateWCS(yOutput, probeDatumY); handler.absoluteMove({ y: y }); - }, + } }; return { ...handler, ...handlers }; @@ -1774,7 +2177,7 @@ function communityFirmwareCycleHandler(cycle, tool) { handler.safeRelativeMove({ [axis]: handler.approach1 * - (value / 2 + probeApproach * options.approachDistance), + (value / 2 + probeApproach * options.approachDistance) }); // Move down to probe depth @@ -1783,7 +2186,7 @@ function communityFirmwareCycleHandler(cycle, tool) { // Probe the first side and store the result in #101. handler.touchUpdateRetract({ [axis]: probeApproach * (options.approachDistance + options.overtravel), - variable: "#101", + variable: "#101" }); // Retract up to the clearance height. @@ -1794,7 +2197,7 @@ function communityFirmwareCycleHandler(cycle, tool) { [axis]: 2 * ((-handler.approach1 * value) / 2 + - probeApproach * options.approachDistance), + probeApproach * options.approachDistance) }); // Move down to the probing height again @@ -1803,7 +2206,7 @@ function communityFirmwareCycleHandler(cycle, tool) { // Probe the second side and store the result in #102. handler.touchUpdateRetract({ [axis]: -probeApproach * (value / 2 + options.approachDistance), - variable: "#102", + variable: "#102" }); // Retract up to the clearance height. @@ -1846,13 +2249,13 @@ function communityFirmwareCycleHandler(cycle, tool) { const probeArgs = { r: options.approachDistance, [axis]: - handler.approach1 * (options.approachDistance + options.overtravel), + handler.approach1 * (options.approachDistance + options.overtravel) }; // Move to the first side. handler.safeRelativeMove({ x: xTravel, - y: yTravel, + y: yTravel }); // Probe with double tap. @@ -1864,13 +2267,13 @@ function communityFirmwareCycleHandler(cycle, tool) { // Retract away from the surface. handler.relativeMove({ - [axis]: -handler.approach1 * options.approachDistance, + [axis]: -handler.approach1 * options.approachDistance }); // Move across to the other side. handler.safeRelativeMove({ x: -2 * xTravel, - y: -2 * yTravel, + y: -2 * yTravel }); // Probe again. @@ -1881,13 +2284,13 @@ function communityFirmwareCycleHandler(cycle, tool) { // Retract away from the surface. handler.relativeMove({ - [axis]: -handler.approach1 * options.approachDistance, + [axis]: -handler.approach1 * options.approachDistance }); // Return to the midpoint. handler.relativeMove({ x: xTravel, - y: yTravel, + y: yTravel }); // Set the WCS rotation. @@ -1910,7 +2313,7 @@ function communityFirmwareCycleHandler(cycle, tool) { handler.safeRelativeMove({ z: cycle.bottom - z }); handler.touchUpdateRetract({ - x: handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel), + x: handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel) }); }, "probing-x-channel": (x, y, z) => { @@ -1919,7 +2322,7 @@ function communityFirmwareCycleHandler(cycle, tool) { overtravel: cycle.probeOvertravel, depth: cycle.depth, approachDistance: cycle.probeClearance, - x: cycle.width1, + x: cycle.width1 }); }, "probing-x-channel-with-island": (x, y, z) => { @@ -1928,7 +2331,7 @@ function communityFirmwareCycleHandler(cycle, tool) { overtravel: cycle.probeOvertravel, depth: cycle.depth, approachDistance: cycle.probeClearance, - x: cycle.width1, + x: cycle.width1 }); }, "probing-x-wall": (x, y, z) => { @@ -1937,7 +2340,7 @@ function communityFirmwareCycleHandler(cycle, tool) { overtravel: cycle.probeOvertravel, depth: cycle.depth, approachDistance: cycle.probeClearance, - x: cycle.width1, + x: cycle.width1 }); }, "probing-y": (x, y, z) => { @@ -1945,7 +2348,7 @@ function communityFirmwareCycleHandler(cycle, tool) { handler.safeRelativeMove({ z: cycle.bottom - z }); handler.touchUpdateRetract({ - y: handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel), + y: handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel) }); }, "probing-y-channel": (x, y, z) => { @@ -1954,7 +2357,7 @@ function communityFirmwareCycleHandler(cycle, tool) { overtravel: cycle.probeOvertravel, depth: cycle.depth, approachDistance: cycle.probeClearance, - y: cycle.width1, + y: cycle.width1 }); }, "probing-y-channel-with-island": (x, y, z) => { @@ -1963,7 +2366,7 @@ function communityFirmwareCycleHandler(cycle, tool) { overtravel: cycle.probeOvertravel, depth: cycle.depth, approachDistance: cycle.probeClearance, - y: cycle.width1, + y: cycle.width1 }); }, "probing-y-wall": (x, y, z) => { @@ -1972,7 +2375,7 @@ function communityFirmwareCycleHandler(cycle, tool) { overtravel: cycle.probeOvertravel, depth: cycle.depth, approachDistance: cycle.probeClearance, - y: cycle.width1, + y: cycle.width1 }); }, "probing-z": (x, y, z) => { @@ -1982,7 +2385,7 @@ function communityFirmwareCycleHandler(cycle, tool) { (cycle.depth + cycle.probeClearance + cycle.probeOvertravel); handler.touchProbe({ - z: probeDepth, + z: probeDepth }); handler.updateWCS(zOutput, 0); @@ -1993,12 +2396,12 @@ function communityFirmwareCycleHandler(cycle, tool) { // Probe the X. handler.touchUpdateRetract({ - x: handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel), + x: handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel) }); // Probe the Y. handler.touchUpdateRetract({ - y: handler.approach2 * (cycle.probeClearance + cycle.probeOvertravel), + y: handler.approach2 * (cycle.probeClearance + cycle.probeOvertravel) }); }, "probing-xy-rectangular-boss": (x, y, z) => { @@ -2008,7 +2411,7 @@ function communityFirmwareCycleHandler(cycle, tool) { depth: cycle.depth, approachDistance: cycle.probeClearance, x: cycle.width1, - y: cycle.width2, + y: cycle.width2 }); }, "probing-xy-circular-boss": (x, y, z) => { @@ -2018,7 +2421,7 @@ function communityFirmwareCycleHandler(cycle, tool) { depth: cycle.depth, approachDistance: cycle.probeClearance, x: cycle.width1, - y: cycle.width1, + y: cycle.width1 }); }, "probing-xy-circular-hole": (x, y, z) => { @@ -2028,7 +2431,7 @@ function communityFirmwareCycleHandler(cycle, tool) { depth: cycle.depth, approachDistance: cycle.probeClearance, x: cycle.width1, - y: cycle.width1, + y: cycle.width1 }); }, "probing-xy-circular-hole-with-island": (x, y, z) => { @@ -2038,7 +2441,7 @@ function communityFirmwareCycleHandler(cycle, tool) { depth: cycle.depth, approachDistance: cycle.probeClearance, x: cycle.width1, - y: cycle.width1, + y: cycle.width1 }); }, "probing-xy-rectangular-hole": (x, y, z) => { @@ -2048,7 +2451,7 @@ function communityFirmwareCycleHandler(cycle, tool) { depth: cycle.depth, approachDistance: cycle.probeClearance, x: cycle.width1, - y: cycle.width2, + y: cycle.width2 }); }, "probing-xy-rectangular-hole-with-island": (x, y, z) => { @@ -2058,7 +2461,7 @@ function communityFirmwareCycleHandler(cycle, tool) { depth: cycle.depth, approachDistance: cycle.probeClearance, x: cycle.width1, - y: cycle.width2, + y: cycle.width2 }); }, "probing-xy-outer-corner": (x, y, z) => { @@ -2067,30 +2470,30 @@ function communityFirmwareCycleHandler(cycle, tool) { // Move along the y to the position where we'll probe the x. handler.safeRelativeMove({ - y: handler.approach2 * (cycle.probeClearance + cycle.probeOvertravel), + y: handler.approach2 * (cycle.probeClearance + cycle.probeOvertravel) }); handler.touchUpdateRetract({ - x: handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel), + x: handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel) }); // Move back to the original y position. handler.relativeMove({ - y: -handler.approach2 * (cycle.probeClearance + cycle.probeOvertravel), + y: -handler.approach2 * (cycle.probeClearance + cycle.probeOvertravel) }); // Move along the x to the position where we'll probe the y. handler.safeRelativeMove({ - x: handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel), + x: handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel) }); handler.touchUpdateRetract({ - y: handler.approach2 * (cycle.probeClearance + cycle.probeOvertravel), + y: handler.approach2 * (cycle.probeClearance + cycle.probeOvertravel) }); // Move back to the original x position. handler.relativeMove({ - x: -handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel), + x: -handler.approach1 * (cycle.probeClearance + cycle.probeOvertravel) }); }, "probing-x-plane-angle": (x, y, z) => { @@ -2099,7 +2502,7 @@ function communityFirmwareCycleHandler(cycle, tool) { approachDistance: cycle.probeClearance, overtravel: cycle.probeOvertravel, depth: cycle.depth, - x: cycle.probeSpacing, + x: cycle.probeSpacing }); }, "probing-y-plane-angle": (x, y, z) => { @@ -2108,9 +2511,9 @@ function communityFirmwareCycleHandler(cycle, tool) { approachDistance: cycle.probeClearance, overtravel: cycle.probeOvertravel, depth: cycle.depth, - y: cycle.probeSpacing, + y: cycle.probeSpacing }); - }, + } }; // Set up aliases for similar probing strategies. @@ -2233,11 +2636,11 @@ function onRapid(_x, _y, _z) { ); return; } - + if (isFirstOperationProbeZ()) { writeBlock(gMotionModal.format(0), x, y); } else { - writeBlock(gMotionModal.format(0), x, y, z); + writeBlock(gMotionModal.format(0), x, y, z, currentSection.type == TYPE_JET ? powerOutput.format(0) : ""); } feedOutput.reset(); @@ -2260,18 +2663,50 @@ function onLinear(_x, _y, _z, feed) { error(localize("Radius compensation mode is not supported.")); return; } else { - writeBlock(gMotionModal.format(1), x, y, z, f); + writeBlock( + gMotionModal.format(1), + x, + y, + z, + f, + currentSection.type == TYPE_JET + ? powerOutput.format(power ? getPower() : 0) + : "" + ); } } else if (f) { if (getNextRecord().isMotion()) { // try not to output feed without motion feedOutput.reset(); // force feed on next line } else { - writeBlock(gMotionModal.format(1), f); + writeBlock( + gMotionModal.format(1), + f, + currentSection.type == TYPE_JET + ? powerOutput.format(power ? getPower() : 0) + : "" + ); } } } +function onPower(power) { + powerOutput.reset(); +} + +function getPower() { + switch (currentSection.jetMode) { + case JET_MODE_THROUGH: + return getProperty("laserPower"); + case JET_MODE_ETCHING: + return getProperty("laserEtchPower"); + case JET_MODE_VAPORIZE: + default: + error(localize("Laser cutting mode is not supported.")); + } + return 0; +} + function getFeed(f) { if (getProperty("useG95")) { return feedOutput.format(f / spindleSpeed); // use feed value @@ -2435,7 +2870,10 @@ function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { xOutput.format(x), iOutput.format(cx - start.x), jOutput.format(cy - start.y), - feedOutput.format(feed) + feedOutput.format(feed), + currentSection.type == TYPE_JET + ? powerOutput.format(power ? getPower() : 0) + : "" ); break; case PLANE_ZX: @@ -2446,7 +2884,10 @@ function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { zOutput.format(z), iOutput.format(cx - start.x), kOutput.format(cz - start.z), - feedOutput.format(feed) + feedOutput.format(feed), + currentSection.type == TYPE_JET + ? powerOutput.format(power ? getPower() : 0) + : "" ); break; case PLANE_YZ: @@ -2457,7 +2898,10 @@ function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { yOutput.format(y), jOutput.format(cy - start.y), kOutput.format(cz - start.z), - feedOutput.format(feed) + feedOutput.format(feed), + currentSection.type == TYPE_JET + ? powerOutput.format(power ? getPower() : 0) + : "" ); break; default: @@ -2475,7 +2919,10 @@ function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { zOutput.format(z), iOutput.format(cx - start.x), jOutput.format(cy - start.y), - feedOutput.format(feed) + feedOutput.format(feed), + currentSection.type == TYPE_JET + ? powerOutput.format(power ? getPower() : 0) + : "" ); break; case PLANE_ZX: @@ -2488,7 +2935,10 @@ function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { zOutput.format(z), iOutput.format(cx - start.x), kOutput.format(cz - start.z), - feedOutput.format(feed) + feedOutput.format(feed), + currentSection.type == TYPE_JET + ? powerOutput.format(power ? getPower() : 0) + : "" ); break; case PLANE_YZ: @@ -2501,7 +2951,10 @@ function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { zOutput.format(z), jOutput.format(cy - start.y), kOutput.format(cz - start.z), - feedOutput.format(feed) + feedOutput.format(feed), + currentSection.type == TYPE_JET + ? powerOutput.format(power ? getPower() : 0) + : "" ); break; default: @@ -2522,7 +2975,7 @@ var gRotationModal = createOutputVariable( probeVariables.probeAngleMethod == "G68"; } machineSimulation({}); // update machine simulation TWP state - }, + } }, gFormat ); @@ -2537,24 +2990,37 @@ var mapCommand = { COMMAND_END: 2, COMMAND_SPINDLE_CLOCKWISE: 3, COMMAND_SPINDLE_COUNTERCLOCKWISE: 4, - COMMAND_STOP_SPINDLE: 5, + COMMAND_STOP_SPINDLE: 5 }; function onCommand(command) { switch (command) { case COMMAND_STOP: + writeComment("Stop"); writeBlock(mFormat.format(600)); forceSpindleSpeed = true; forceCoolant = true; if (getProperty("defaultUseExternalControl")) { + writeBlock(mFormat.format(400)); writeBlock(mFormat.format(852)); } return; + case COMMAND_POWER_ON: + return; + case COMMAND_POWER_OFF: + return; + + case COMMAND_BREAK_CONTROL: + writeComment("Tool Break Test"); + writeBlock("M491.1"); + return; + case COMMAND_STOP_SPINDLE: writeBlock(mFormat.format(5)); forceSpindleSpeed = true; forceCoolant = true; if (getProperty("defaultUseExternalControl")) { + writeBlock(mFormat.format(400)); writeBlock(mFormat.format(852)); } return; @@ -2564,12 +3030,14 @@ function onCommand(command) { forceSpindleSpeed = true; forceCoolant = true; if (getProperty("defaultUseExternalControl")) { + writeBlock(mFormat.format(400)); writeBlock(mFormat.format(852)); } writeComment("Optional Stop End"); return; case COMMAND_START_SPINDLE: if (getProperty("defaultUseExternalControl")) { + writeBlock(mFormat.format(400)); writeBlock(mFormat.format(851), pwmOutput.format(100)); } onCommand( @@ -2609,6 +3077,7 @@ function onSectionEnd() { if (!isLastSection() && getNextSection().getTool().coolant != tool.coolant) { setCoolant(COOLANT_OFF); } + writeJetCodes(false); forceAny(); } @@ -2617,15 +3086,26 @@ function writeRetract() { var retractAxes = new Array(false, false, false); validate(arguments.length != 0, "No axis specified for writeRetract()."); - for (i in arguments) { + for (var i in arguments) { retractAxes[arguments[i]] = true; } + var safeYPosition = getProperty("yAxisSafePosition"); + if (retractAxes[0] && retractAxes[1] && retractAxes[2]) { if (getProperty("returnClearance")) { writeBlock(gFormat.format(28)); } - } else if (retractAxes[0]) { + } else if (retractAxes[1] && retractAxes[2] && safeYPosition != 0) { // Y and Z + gMotionModal.reset(); + writeBlock( + gAbsIncModal.format(90), + gFormat.format(53), + gMotionModal.format(0), + "Y" + xyzFormat.format(toPreciseUnit(safeYPosition, MM)), + "Z" + xyzFormat.format(toPreciseUnit(-3, MM)) + ); + } else if (retractAxes[2]) { // Z only gMotionModal.reset(); writeBlock( gAbsIncModal.format(90), @@ -2712,13 +3192,13 @@ function getCoolantCodes(coolant) { getProperty("useExtForAirCoolant") ) { currentCoolantMode = coolant; - return [mFormat.format(852)]; + return [mFormat.format(400), mFormat.format(852)]; } } else { coolantOff = coolantCodes.off; if (coolant == COOLANT_AIR && getProperty("useExtForAirCoolant")) { currentCoolantMode = coolant; - return ["M851S100"]; + return [mFormat.format(400), "M851S100"]; } m = coolantCodes.on; @@ -2786,6 +3266,9 @@ function onReturnFromSafeRetractPosition(_x, _y, _z) { // End of onRewindMachine logic function onClose() { + if (laser_used) { + writeBlock("M322"); + } setCoolant(COOLANT_OFF); if (machineConfiguration.isMultiAxisConfiguration()) {