/** Copyright (C) 2012-2024 by Autodesk, Inc. All rights reserved. FANUC post processor configuration. $Revision: 44115 1104db9da08471dc1d758431fd9ef8822fd95c21 $ $Date: 2024-03-12 07:10:57 $ FORKID {1DACCE16-E73F-44A2-9A23-061EE2641D05} */ description = "CR Onsrud 5-axis Router with saw blade support"; vendor = "C.R. Onsrud"; vendorUrl = "http://www.cronsrud.com"; legal = "Copyright (C) 2012-2024 by Autodesk, Inc."; certificationLevel = 2; minimumRevision = 45702; longDescription = "CR Onsrud 5-axis Router with saw blade support on a Fanuc 31i control."; extension = "nc"; programNameIsInteger = true; setCodePage("ascii"); capabilities = CAPABILITY_MILLING; tolerance = spatial(0.002, MM); minimumChordLength = spatial(0.25, MM); minimumCircularRadius = spatial(0.01, MM); maximumCircularRadius = spatial(1000, MM); minimumCircularSweep = toRad(0.01); maximumCircularSweep = toRad(180); allowHelicalMoves = true; allowedCircularPlanes = undefined; // allow any circular motion // user-defined properties properties = { writeMachine: { title : "Write machine", description: "Output the machine settings in the header of the code.", group : "formats", type : "boolean", value : true, scope : "post" }, writeTools: { title : "Write tool list", description: "Output a tool list in the header of the code.", group : "formats", type : "boolean", value : true, scope : "post" }, showSequenceNumbers: { title : "Use sequence numbers", description: "'Yes' outputs sequence numbers on each block, 'Only on tool change' outputs sequence numbers on tool change blocks only, and 'No' disables the output of sequence numbers.", group : "formats", type : "enum", values : [ {title:"Yes", id:"true"}, {title:"No", id:"false"}, {title:"Only on tool change", id:"toolChange"} ], value: "true", scope: "post" }, sequenceNumberStart: { title : "Start sequence number", description: "The number at which to start the sequence numbers.", group : "formats", type : "integer", value : 10, scope : "post" }, sequenceNumberIncrement: { title : "Sequence number increment", description: "The amount by which the sequence number is incremented by in each block.", group : "formats", type : "integer", value : 5, scope : "post" }, optionalStop: { title : "Optional stop", description: "Outputs optional stop code during when necessary in the code.", group : "preferences", type : "boolean", value : false, scope : "post" }, separateWordsWithSpace: { title : "Separate words with space", description: "Adds spaces between words if 'yes' is selected.", group : "formats", type : "boolean", value : true, scope : "post" }, allow3DArcs: { title : "Allow 3D arcs", description: "Specifies that 3D circular arcs are allowed.", group : "preferences", type : "boolean", value : false, scope : "post" }, useRadius: { title : "Radius arcs", description: "If yes is selected, arcs are outputted using radius values rather than IJK.", group : "preferences", type : "boolean", value : false, scope : "post" }, forceIJK: { title : "Force IJK", description: "Force the output of IJK for G2/G3 when not using R mode.", group : "preferences", type : "boolean", value : false, scope : "post" }, useParametricFeed: { title : "Parametric feed", description: "Specifies the feed value that should be output using a Q value.", group : "preferences", type : "boolean", value : false, scope : "post" }, showNotes: { title : "Show notes", description: "Writes operation notes as comments in the outputted code.", group : "formats", type : "boolean", value : false, scope : "post" }, useSmoothing: { title : "Use smoothing", description: "Specifies if smoothing should be used or not.", group : "preferences", type : "enum", values : [ {title:"Off", id:"-1"}, {title:"Automatic", id:"9999"}, {title:"Level 1", id:"1"}, {title:"Level 2", id:"2"}, {title:"Level 3", id:"3"}, {title:"Level 4", id:"4"}, {title:"Level 5", id:"5"}, {title:"Level 6", id:"6"}, {title:"Level 7", id:"7"}, {title:"Level 8", id:"8"}, {title:"Level 9", id:"9"}, {title:"Level 10", id:"10"}, ], value: "7", scope: "post" }, usePitchForTapping: { title : "Use pitch for tapping", description: "Enables the use of pitch instead of feed for the F-word in canned tapping cycles. Your CNC control must be setup for pitch mode!", group : "preferences", type : "boolean", value : false, scope : "post" }, useG95: { title : "Use G95", description: "Use IPR/MPR instead of IPM/MPM.", group : "preferences", type : "boolean", value : false, scope : "post" }, maxTool: { title : "Max tool number", description: "Defines the maximum tool number.", group : "configuration", type : "integer", range : [0, 999999999], value : 32, scope : "post" }, vacuumTable: { title : "Vacuum table", description: "Defines the vacuum table.", group : "configuration", type : "integer", values : [ {id:0, title:"No vacuum"}, {id:1, title:"Table"}, {id:2, title:"Table 2"}, {id:3, title:"Both tables"} ], value: 0, scope: "post" }, safeRetractDistance: { title : "Safe retract distance", description: "Adds this distance to the tool length for the C-axis rewind tool retract.", group : "multiAxis", type : "integer", value : 0, scope : "post" }, hoodControl: { title : "Hood control", description: "Turn on to use M96 hood control.", group : "preferences", type : "boolean", value : false, scope : "post" }, useRigidTapping: { title : "Use rigid tapping", description: "Select 'Yes' to enable, 'No' to disable, or 'Without spindle direction' to enable rigid tapping without outputting the spindle direction block.", group : "preferences", type : "enum", values : [ {title:"Yes", id:"yes"}, {title:"No", id:"no"}, {title:"Without spindle direction", id:"without"} ], value: "yes", scope: "post" }, sawCenterDistance: { title : "Distance from aggregate face to center in inches", description: "Enter the distance from the aggregate spindle face to the center of the aggregate in inches. Used for saws.", group : "saw", type : "spatial", value : 3.022, scope : "post" }, sawPivotDistance: { title : "Distance from aggregate center to spindle face in inches", description: "Enter the distance from the center of the aggregate to the machine spindle face in inches. Used for saws.", group : "saw", type : "spatial", value : 0.36, scope : "post" }, sawBaseAngle: { title : "Base angle of saw", description: "Enter the C-axis angle when the saw tool axis vector is pointing in the +X direction.", group : "saw", type : "spatial", value : 90, scope : "post" }, hoodPosition: { title : "Hood position in inches", description: "Enter the hood position for non-saw operations in inches. This value is stored in register #900.", group : "preferences", type : "spatial", value : 0, scope : "post" }, sawHoodPosition: { title : "Saw hood position in inches", description: "Enter the hood position for saw operations in inches. This value is stored in register #900.", group : "saw", type : "spatial", value : 3, scope : "post" }, }; groupDefinitions = { saw: {title:"Saw Aggregate", collapsed:true, description:"Settings related to an aggregate saw attachment", order:25}, }; // wcs definiton wcsDefinitions = { useZeroOffset: false, wcs : [ {name:"Standard", format:"G", range:[55, 59]} ] }; var singleLineCoolant = false; // specifies to output multiple coolant codes in one line rather than in separate lines // samples: // {id: COOLANT_THROUGH_TOOL, on: 88, off: 89} // {id: COOLANT_THROUGH_TOOL, on: [8, 88], off: [9, 89]} // {id: COOLANT_THROUGH_TOOL, on: "M88 P3 (myComment)", off: "M89"} var coolants = [ {id:COOLANT_FLOOD, on:8}, {id:COOLANT_MIST}, {id:COOLANT_THROUGH_TOOL, on:88, off:89}, {id:COOLANT_AIR, on:7}, {id:COOLANT_AIR_THROUGH_TOOL}, {id:COOLANT_SUCTION}, {id:COOLANT_FLOOD_MIST}, {id:COOLANT_FLOOD_THROUGH_TOOL}, {id:COOLANT_OFF, off:9} ]; var permittedCommentChars = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,=_-"; var gFormat = createFormat({prefix:"G", width:2, zeropad:true, decimals:1}); var mFormat = createFormat({prefix:"M", width:2, zeropad:true, decimals:1}); var hFormat = createFormat({prefix:"H", width:2, zeropad:true, decimals:1}); var dFormat = createFormat({prefix:"D", width:2, zeropad:true, decimals:1}); var xyzFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true}); var ijkFormat = createFormat({decimals:6, forceDecimal:true}); // unitless var rFormat = xyzFormat; // radius var abcFormat = createFormat({decimals:3, forceDecimal:true, scale:DEG}); var feedFormat = createFormat({decimals:(unit == MM ? 0 : 1), forceDecimal:true}); var pitchFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true}); var toolFormat = createFormat({decimals:0}); var rpmFormat = createFormat({decimals:0}); var secFormat = createFormat({decimals:3, forceDecimal:true}); // seconds - range 0.001-99999.999 var milliFormat = createFormat({decimals:0}); // milliseconds // range 1-9999 var taperFormat = createFormat({decimals:1, scale:DEG}); var peckFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true}); // var peckFormat = createFormat({decimals:0, forceDecimal:false, trim:false, width:4, zeropad:true, scale:(unit == MM ? 1000 : 10000)}); var hoodPositionFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:false}); 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 sawOutput = createVariable({prefix:"C"}, abcFormat); var feedOutput = createVariable({prefix:"F"}, feedFormat); var pitchOutput = createVariable({prefix:"F", force:true}, pitchFormat); var sOutput = createVariable({prefix:"S", force:true}, rpmFormat); var dOutput = createVariable({}, dFormat); var peckOutput = createVariable({prefix:"Q", force:true}, peckFormat); // circular output var iOutput = createReferenceVariable({prefix:"I"}, xyzFormat); var jOutput = createReferenceVariable({prefix:"J"}, xyzFormat); var kOutput = createReferenceVariable({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 gAbsIncModal = createModal({}, gFormat); // modal group 3 // G90-91 var gFeedModeModal = createModal({}, gFormat); // modal group 5 // G94-95 var gUnitModal = createModal({}, gFormat); // modal group 6 // G20-21 var gCycleModal = createModal({}, gFormat); // modal group 9 // G81, ... var gRetractModal = createModal({}, gFormat); // modal group 10 // G98-99 var gRotationModal = createModal({}, gFormat); // modal group 16 // G68-G69 // fixed settings var firstFeedParameter = 500; var useMultiAxisFeatures = true; var forceMultiAxisIndexing = false; // force multi-axis indexing for 3D programs var safeRetractFeed = (unit == IN) ? 40 : 1000; var safePlungeFeed = (unit == IN) ? 25 : 625; var cancelTiltFirst = true; // cancel G68.2 with G69 prior to G54-G59 WCS block var useABCPrepositioning = false; // position ABC axes prior to G68.2 block var WARNING_WORK_OFFSET = 0; // collected state var sequenceNumber; var forceSpindleSpeed = false; var currentWorkOffset; var optionalSection = false; var activeMovements; // do not use by default var currentFeedId; var retracted = false; // specifies that the tool has been retracted to the safe plane var sawIsActive = false; /** Writes the specified block. */ function writeBlock() { var text = formatWords(arguments); if (!text) { return; } if (getProperty("showSequenceNumbers") == "true") { if (optionalSection) { if (text) { writeWords("/", "N" + sequenceNumber, text); } } else { writeWords2("N" + sequenceNumber, arguments); } sequenceNumber += getProperty("sequenceNumberIncrement"); } else { if (optionalSection) { writeWords2("/", arguments); } else { writeWords(arguments); } } } /** Writes the specified optional block. */ function writeOptionalBlock() { if (getProperty("showSequenceNumbers") == "true") { var words = formatWords(arguments); if (words) { writeWords("/", "N" + sequenceNumber, words); sequenceNumber += getProperty("sequenceNumberIncrement"); } } else { writeWords2("/", arguments); } } function formatComment(text) { return "(" + filterText(String(text).toUpperCase(), permittedCommentChars).replace(/[()]/g, "") + ")"; } /** Writes the specified block - used for tool changes only. */ function writeToolBlock() { var show = getProperty("showSequenceNumbers"); setProperty("showSequenceNumbers", (show == "true" || show == "toolChange") ? "true" : "false"); writeBlock(arguments); setProperty("showSequenceNumbers", show); } /** Output a comment. */ function writeComment(text) { writeln(formatComment(text)); } function onOpen() { if (getProperty("useRadius")) { maximumCircularSweep = toRad(90); // avoid potential center calculation errors for CNC } gRotationModal.format(69); // Default to G69 Rotation Off if (getProperty("vacuumTable") > 3) { error(localize("Property 'vacummTable' must be set to 0-3.")); return; } if (getProperty("has5Axis")) { // note: setup your machine here var aAxis = createAxis({coordinate:0, table:false, axis:[-1, 0, 0], range:[-115, 115], cyclic:false}); var cAxis = createAxis({coordinate:2, table:false, axis:[0, 0, -1], range:[-115, 300], cyclic:false, preference:1}); machineConfiguration = new MachineConfiguration(aAxis, cAxis); setMachineConfiguration(machineConfiguration); optimizeMachineAngles2(0); // TCP mode } if (!machineConfiguration.isMachineCoordinate(0)) { aOutput.disable(); } if (!machineConfiguration.isMachineCoordinate(1)) { bOutput.disable(); } if (!machineConfiguration.isMachineCoordinate(2)) { cOutput.disable(); } if (!getProperty("separateWordsWithSpace")) { setWordSeparator(""); } if (getProperty("forceIJK")) { iOutput = createReferenceVariable({prefix:"I", force:true}, xyzFormat); jOutput = createReferenceVariable({prefix:"J", force:true}, xyzFormat); kOutput = createReferenceVariable({prefix:"K", force:true}, xyzFormat); } sequenceNumber = getProperty("sequenceNumberStart"); writeln("%"); if (programName) { var programId; try { programId = getAsInt(programName); } catch (e) { error(localize("Program name must be a number.")); return; } if (!((programId >= 1) && (programId <= 9999))) { error(localize("Program number is out of range.")); return; } if ((programId >= 8000) && (programId <= 9999)) { warning(localize("Program number is reserved by tool builder.")); } var oFormat = createFormat({width:4, zeropad:true, decimals:0}); if (programComment) { writeln("O" + oFormat.format(programId) + " (" + filterText(String(programComment).toUpperCase(), permittedCommentChars) + ")"); } else { writeln("O" + oFormat.format(programId)); } } else { error(localize("Program name has not been specified.")); return; } // dump machine configuration var vendor = machineConfiguration.getVendor(); var model = machineConfiguration.getModel(); var description = machineConfiguration.getDescription(); if (getProperty("writeMachine") && (vendor || model || description)) { writeComment(localize("Machine")); if (vendor) { writeComment(" " + localize("vendor") + ": " + vendor); } if (model) { writeComment(" " + localize("model") + ": " + model); } if (description) { writeComment(" " + localize("description") + ": " + description); } } // dump tool information if (getProperty("writeTools")) { 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) + " " + "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); } } } if (false) { // check for duplicate tool number for (var i = 0; i < getNumberOfSections(); ++i) { var sectioni = getSection(i); var tooli = sectioni.getTool(); for (var j = i + 1; j < getNumberOfSections(); ++j) { var sectionj = getSection(j); var toolj = sectionj.getTool(); if (tooli.number == toolj.number) { if (xyzFormat.areDifferent(tooli.diameter, toolj.diameter) || xyzFormat.areDifferent(tooli.cornerRadius, toolj.cornerRadius) || abcFormat.areDifferent(tooli.taperAngle, toolj.taperAngle) || (tooli.numberOfFlutes != toolj.numberOfFlutes)) { error( subst( localize("Using the same tool number for different cutter geometry for operation '%1' and '%2'."), sectioni.hasParameter("operation-comment") ? sectioni.getParameter("operation-comment") : ("#" + (i + 1)), sectionj.hasParameter("operation-comment") ? sectionj.getParameter("operation-comment") : ("#" + (j + 1)) ) ); return; } } } } } 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.")); return; } } } // Output initial safe block zOutput.reset(); writeRetract(Z); if (getProperty("has5Axis")) { forceABC(); writeBlock(gFormat.format(0), gFormat.format(91), gFormat.format(28), aOutput.format(0), cOutput.format(0)); } writeBlock(gPlaneModal.format(17), ((unit == IN) ? gUnitModal.format(20) : gUnitModal.format(21)), gFormat.format(40), gFormat.format(49)); writeBlock(gFormat.format(64), gFormat.format(69), gCycleModal.format(80), gFormat.format(90), gFeedModeModal.format(getProperty("useG95") ? 95 : 94)); gAbsIncModal.reset(); gMotionModal.reset(); // writeBlock(gFormat.format(59)); if (getProperty("vacuumTable") > 0) { var vacuumCodes = [131, 132, 130]; writeBlock(mFormat.format(vacuumCodes[getProperty("vacuumTable") - 1])); } // writeBlock(mFormat.format(124), formatComment("SPINDLE BLAST GATE OPEN")); // required for some machines if (getProperty("useG95") && getProperty("useParametricFeed")) { error(localize("Parametric feed is not supported when using G95.")); return; } if (getProperty("useG95")) { feedFormat = createFormat({decimals:(unit == MM ? 4 : 5), forceDecimal:true}); feedOutput = createVariable({prefix:"F"}, feedFormat); } } function onComment(message) { var comments = String(message).split(";"); for (comment in comments) { writeComment(comments[comment]); } } /** Force output of X, Y, and Z. */ function forceXYZ() { xOutput.reset(); yOutput.reset(); zOutput.reset(); } /** Force output of A, B, and C. */ function forceABC() { aOutput.reset(); bOutput.reset(); cOutput.reset(); } function forceFeed() { currentFeedId = undefined; feedOutput.reset(); } /** Force output of X, Y, Z, A, B, C, and F on next output. */ function forceAny() { forceXYZ(); forceABC(); forceFeed(); } function forceModals() { if (arguments.length == 0) { // reset all modal variables listed below if (typeof gMotionModal != "undefined") { gMotionModal.reset(); } if (typeof gPlaneModal != "undefined") { gPlaneModal.reset(); } if (typeof gAbsIncModal != "undefined") { gAbsIncModal.reset(); } if (typeof gFeedModeModal != "undefined") { gFeedModeModal.reset(); } } else { for (var i in arguments) { arguments[i].reset(); // only reset the modal variable passed to this function } } } var lengthCompensationActive = false; /** Disables length compensation if currently active or if forced. */ function disableLengthCompensation(force) { if (lengthCompensationActive || force) { writeBlock(gFormat.format(49)); lengthCompensationActive = false; } } // Start of smoothing logic var smoothingSettings = { roughing : 1, // roughing level for smoothing in automatic mode semi : 3, // semi-roughing level for smoothing in automatic mode semifinishing : 5, // semi-finishing level for smoothing in automatic mode finishing : 7, // finishing level for smoothing in automatic mode thresholdRoughing : toPreciseUnit(0.5, MM), // operations with stock/tolerance above that threshold will use roughing level in automatic mode thresholdFinishing : toPreciseUnit(0.05, MM), // operations with stock/tolerance below that threshold will use finishing level in automatic mode thresholdSemiFinishing: toPreciseUnit(0.1, MM), // operations with stock/tolerance above finishing and below threshold roughing that threshold will use semi finishing level in automatic mode differenceCriteria: "level", // options: "level", "tolerance", "both". Specifies criteria when output smoothing codes autoLevelCriteria : "stock", // use "stock" or "tolerance" to determine levels in automatic mode cancelCompensation: true // tool length compensation must be canceled prior to changing the smoothing level }; // collected state below, do not edit var smoothing = { cancel : false, // cancel tool length prior to update smoothing for this operation isActive : false, // the current state of smoothing isAllowed : false, // smoothing is allowed for this operation isDifferent: false, // tells if smoothing levels/tolerances/both are different between operations level : -1, // the active level of smoothing tolerance : -1, // the current operation tolerance force : false // smoothing needs to be forced out in this operation }; function initializeSmoothing() { var previousLevel = smoothing.level; var previousTolerance = smoothing.tolerance; // determine new smoothing levels and tolerances smoothing.level = parseInt(getProperty("useSmoothing"), 10); smoothing.tolerance = Math.max(getParameter("operation:tolerance"), 0); // automatically determine smoothing level if (smoothing.level == 9999) { if (smoothingSettings.autoLevelCriteria == "stock") { // determine auto smoothing level based on stockToLeave var stockToLeave = xyzFormat.getResultingValue(getParameter("operation:stockToLeave", 0)); var verticalStockToLeave = xyzFormat.getResultingValue(getParameter("operation:verticalStockToLeave", 0)); if ((stockToLeave >= smoothingSettings.thresholdRoughing) && (verticalStockToLeave >= smoothingSettings.thresholdRoughing)) { smoothing.level = smoothingSettings.roughing; // set roughing level } else { if (((stockToLeave >= smoothingSettings.thresholdSemiFinishing) && (stockToLeave < smoothingSettings.thresholdRoughing)) && ((verticalStockToLeave >= smoothingSettings.thresholdSemiFinishing) && (verticalStockToLeave < smoothingSettings.thresholdRoughing))) { smoothing.level = smoothingSettings.semi; // set semi level } else if (((stockToLeave >= smoothingSettings.thresholdFinishing) && (stockToLeave < smoothingSettings.thresholdSemiFinishing)) && ((verticalStockToLeave >= smoothingSettings.thresholdFinishing) && (verticalStockToLeave < smoothingSettings.thresholdSemiFinishing))) { smoothing.level = smoothingSettings.semifinishing; // set semi-finishing level } else { smoothing.level = smoothingSettings.finishing; // set finishing level } } } else { // detemine auto smoothing level based on operation tolerance instead of stockToLeave if (smoothing.tolerance >= smoothingSettings.thresholdRoughing) { smoothing.level = smoothingSettings.roughing; // set roughing level } else { if (((smoothing.tolerance >= smoothingSettings.thresholdSemiFinishing) && (smoothing.tolerance < smoothingSettings.thresholdRoughing))) { smoothing.level = smoothingSettings.semi; // set semi level } else if (((smoothing.tolerance >= smoothingSettings.thresholdFinishing) && (smoothing.tolerance < smoothingSettings.thresholdSemiFinishing))) { smoothing.level = smoothingSettings.semifinishing; // set semi-finishing level } else { smoothing.level = smoothingSettings.finishing; // set finishing level } } } } if (smoothing.level == -1) { // useSmoothing is disabled smoothing.isAllowed = false; } else { // do not output smoothing for the following operations smoothing.isAllowed = !(currentSection.getTool().type == TOOL_PROBE || currentSection.checkGroup(STRATEGY_DRILLING)); } if (!smoothing.isAllowed) { smoothing.level = -1; smoothing.tolerance = -1; } switch (smoothingSettings.differenceCriteria) { case "level": smoothing.isDifferent = smoothing.level != previousLevel; break; case "tolerance": smoothing.isDifferent = xyzFormat.areDifferent(smoothing.tolerance, previousTolerance); break; case "both": smoothing.isDifferent = smoothing.level != previousLevel || xyzFormat.areDifferent(smoothing.tolerance, previousTolerance); break; default: error(localize("Unsupported smoothing criteria.")); return; } // tool length compensation needs to be canceled when smoothing state/level changes if (smoothingSettings.cancelCompensation) { smoothing.cancel = !isFirstSection() && smoothing.isDifferent; } } function setSmoothing(mode) { if (mode == smoothing.isActive && (!mode || !smoothing.isDifferent) && !smoothing.force) { return; // return if smoothing is already active or is not different } if (typeof lengthCompensationActive != "undefined" && smoothingSettings.cancelCompensation) { validate(!lengthCompensationActive, "Length compensation is active while trying to update smoothing."); } if (mode) { // enable smoothing writeBlock(gFormat.format(5.1), "Q1", "R" + smoothing.level); } else { // disable smoothing writeBlock(gFormat.format(5.1), "Q0"); } smoothing.isActive = mode; smoothing.force = false; smoothing.isDifferent = false; } // End of smoothing logic function FeedContext(id, description, feed) { this.id = id; this.description = description; this.feed = feed; } function getFeed(f) { if (getProperty("useG95")) { return feedOutput.format(f / spindleSpeed); // use feed value } if (activeMovements) { var feedContext = activeMovements[movement]; if (feedContext != undefined) { if (!feedFormat.areDifferent(feedContext.feed, f)) { if (feedContext.id == currentFeedId) { return ""; // nothing has changed } forceFeed(); currentFeedId = feedContext.id; return "F#" + (firstFeedParameter + feedContext.id); } } currentFeedId = undefined; // force Q feed next time } return feedOutput.format(f); // use feed value } function initializeActiveFeeds() { activeMovements = new Array(); var movements = currentSection.getMovements(); var id = 0; var activeFeeds = new Array(); if (hasParameter("operation:tool_feedCutting")) { if (movements & ((1 << MOVEMENT_CUTTING) | (1 << MOVEMENT_LINK_TRANSITION) | (1 << MOVEMENT_EXTENDED))) { var feedContext = new FeedContext(id, localize("Cutting"), getParameter("operation:tool_feedCutting")); activeFeeds.push(feedContext); activeMovements[MOVEMENT_CUTTING] = feedContext; if (!hasParameter("operation:tool_feedTransition")) { activeMovements[MOVEMENT_LINK_TRANSITION] = feedContext; } activeMovements[MOVEMENT_EXTENDED] = feedContext; } ++id; if (movements & (1 << MOVEMENT_PREDRILL)) { feedContext = new FeedContext(id, localize("Predrilling"), getParameter("operation:tool_feedCutting")); activeMovements[MOVEMENT_PREDRILL] = feedContext; activeFeeds.push(feedContext); } ++id; } if (hasParameter("operation:finishFeedrate")) { if (movements & (1 << MOVEMENT_FINISH_CUTTING)) { var feedContext = new FeedContext(id, localize("Finish"), getParameter("operation:finishFeedrate")); activeFeeds.push(feedContext); activeMovements[MOVEMENT_FINISH_CUTTING] = feedContext; } ++id; } else if (hasParameter("operation:tool_feedCutting")) { if (movements & (1 << MOVEMENT_FINISH_CUTTING)) { var feedContext = new FeedContext(id, localize("Finish"), getParameter("operation:tool_feedCutting")); activeFeeds.push(feedContext); activeMovements[MOVEMENT_FINISH_CUTTING] = feedContext; } ++id; } if (hasParameter("operation:tool_feedEntry")) { if (movements & (1 << MOVEMENT_LEAD_IN)) { var feedContext = new FeedContext(id, localize("Entry"), getParameter("operation:tool_feedEntry")); activeFeeds.push(feedContext); activeMovements[MOVEMENT_LEAD_IN] = feedContext; } ++id; } if (hasParameter("operation:tool_feedExit")) { if (movements & (1 << MOVEMENT_LEAD_OUT)) { var feedContext = new FeedContext(id, localize("Exit"), getParameter("operation:tool_feedExit")); activeFeeds.push(feedContext); activeMovements[MOVEMENT_LEAD_OUT] = feedContext; } ++id; } if (hasParameter("operation:noEngagementFeedrate")) { if (movements & (1 << MOVEMENT_LINK_DIRECT)) { var feedContext = new FeedContext(id, localize("Direct"), getParameter("operation:noEngagementFeedrate")); activeFeeds.push(feedContext); activeMovements[MOVEMENT_LINK_DIRECT] = feedContext; } ++id; } else if (hasParameter("operation:tool_feedCutting") && hasParameter("operation:tool_feedEntry") && hasParameter("operation:tool_feedExit")) { if (movements & (1 << MOVEMENT_LINK_DIRECT)) { var feedContext = new FeedContext(id, localize("Direct"), Math.max(getParameter("operation:tool_feedCutting"), getParameter("operation:tool_feedEntry"), getParameter("operation:tool_feedExit"))); activeFeeds.push(feedContext); activeMovements[MOVEMENT_LINK_DIRECT] = feedContext; } ++id; } if (hasParameter("operation:reducedFeedrate")) { if (movements & (1 << MOVEMENT_REDUCED)) { var feedContext = new FeedContext(id, localize("Reduced"), getParameter("operation:reducedFeedrate")); activeFeeds.push(feedContext); activeMovements[MOVEMENT_REDUCED] = feedContext; } ++id; } if (hasParameter("operation:tool_feedRamp")) { if (movements & ((1 << MOVEMENT_RAMP) | (1 << MOVEMENT_RAMP_HELIX) | (1 << MOVEMENT_RAMP_PROFILE) | (1 << MOVEMENT_RAMP_ZIG_ZAG))) { var feedContext = new FeedContext(id, localize("Ramping"), getParameter("operation:tool_feedRamp")); activeFeeds.push(feedContext); activeMovements[MOVEMENT_RAMP] = feedContext; activeMovements[MOVEMENT_RAMP_HELIX] = feedContext; activeMovements[MOVEMENT_RAMP_PROFILE] = feedContext; activeMovements[MOVEMENT_RAMP_ZIG_ZAG] = feedContext; } ++id; } if (hasParameter("operation:tool_feedPlunge")) { if (movements & (1 << MOVEMENT_PLUNGE)) { var feedContext = new FeedContext(id, localize("Plunge"), getParameter("operation:tool_feedPlunge")); activeFeeds.push(feedContext); activeMovements[MOVEMENT_PLUNGE] = feedContext; } ++id; } if (true) { // high feed if ((movements & (1 << MOVEMENT_HIGH_FEED)) || (highFeedMapping != HIGH_FEED_NO_MAPPING)) { var feed; if (hasParameter("operation:highFeedrateMode") && getParameter("operation:highFeedrateMode") != "disabled") { feed = getParameter("operation:highFeedrate"); } else { feed = this.highFeedrate; } var feedContext = new FeedContext(id, localize("High Feed"), feed); activeFeeds.push(feedContext); activeMovements[MOVEMENT_HIGH_FEED] = feedContext; activeMovements[MOVEMENT_RAPID] = feedContext; } ++id; } if (hasParameter("operation:tool_feedTransition")) { if (movements & (1 << MOVEMENT_LINK_TRANSITION)) { var feedContext = new FeedContext(id, localize("Transition"), getParameter("operation:tool_feedTransition")); activeFeeds.push(feedContext); activeMovements[MOVEMENT_LINK_TRANSITION] = feedContext; } ++id; } for (var i = 0; i < activeFeeds.length; ++i) { var feedContext = activeFeeds[i]; writeBlock("#" + (firstFeedParameter + feedContext.id) + "=" + feedFormat.format(feedContext.feed), formatComment(feedContext.description)); } } var currentWorkPlaneABC = undefined; function forceWorkPlane() { currentWorkPlaneABC = undefined; } function cancelWorkPlane() { writeBlock(gRotationModal.format(69)); // cancel frame forceWorkPlane(); } function positionABC(abc, force) { if (typeof unwindABC == "function") { unwindABC(abc, false); } if (force) { forceABC(); } var a = aOutput.format(abc.x); var b = bOutput.format(abc.y); var c = cOutput.format(abc.z); if (a || b || c) { if (!retracted) { if (typeof moveToSafeRetractPosition == "function") { moveToSafeRetractPosition(); } else { writeRetract(Z); } } gMotionModal.reset(); writeBlock(gMotionModal.format(0), a, b, c); currentMachineABC = new Vector(abc); setCurrentABC(abc); // required for machine simulation } } function setWorkPlane(abc) { if (!forceMultiAxisIndexing && is3D() && !machineConfiguration.isMultiAxisConfiguration()) { return; // ignore } if (!((currentWorkPlaneABC == undefined) || abcFormat.areDifferent(abc.x, currentWorkPlaneABC.x) || abcFormat.areDifferent(abc.y, currentWorkPlaneABC.y) || abcFormat.areDifferent(abc.z, currentWorkPlaneABC.z))) { return; // no change } onCommand(COMMAND_UNLOCK_MULTI_AXIS); if (!retracted) { writeRetract(Z); } if (useMultiAxisFeatures) { if (cancelTiltFirst) { cancelWorkPlane(); } if (machineConfiguration.isMultiAxisConfiguration() && useABCPrepositioning) { var angles = abc.isNonZero() ? getWorkPlaneMachineABC(currentSection.workPlane, false, false) : abc; positionABC(angles, true); } if (abc.isNonZero()) { gRotationModal.reset(); writeBlock(gRotationModal.format(68.2), "X" + xyzFormat.format(0), "Y" + xyzFormat.format(0), "Z" + xyzFormat.format(0), "I" + abcFormat.format(abc.x), "J" + abcFormat.format(abc.y), "K" + abcFormat.format(abc.z)); // set frame writeBlock(gFormat.format(53.1)); // turn machine } else { if (!cancelTiltFirst) { cancelWorkPlane(); } } } else { positionABC(abc, false); } onCommand(COMMAND_LOCK_MULTI_AXIS); currentWorkPlaneABC = abc; } var closestABC = false; // choose closest machine angles var currentMachineABC; function getWorkPlaneMachineABC(workPlane, _setWorkPlane, rotate) { var W = workPlane; // map to global frame if (sawIsActive) { setRotation(W); // TCP mode var translation = Vector.product(workPlane.forward, toPreciseUnit(getProperty("sawCenterDistance"), IN) + tool.getBodyLength()); translation = Vector.sum(translation, Vector.product(new Vector(0, 0, 1), toPreciseUnit(getProperty("sawPivotDistance"), IN))); setTranslation(translation); return new Vector(0, 0, 0); } var abc = machineConfiguration.getABC(W); if (closestABC) { if (currentMachineABC) { abc = machineConfiguration.remapToABC(abc, currentMachineABC); } else { abc = machineConfiguration.getPreferredABC(abc); } } else { abc = machineConfiguration.getPreferredABC(abc); } try { abc = machineConfiguration.remapABC(abc); if (_setWorkPlane) { currentMachineABC = abc; } } catch (e) { error( localize("Machine angles 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)) ); } var direction = machineConfiguration.getDirection(abc); if (!isSameDirection(direction, W.forward)) { error(localize("Orientation not supported.")); } 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)) ); } if (rotate) { var tcp = true; if (tcp) { setRotation(W); // TCP mode } else { var O = machineConfiguration.getOrientation(abc); var R = machineConfiguration.getRemainingOrientation(abc, W); setRotation(R); } } return abc; } function isPerpto(a, b) { return Math.abs(Vector.dot(a, b)) < (1e-7); } function onSection() { var forceSectionRestart = optionalSection && !currentSection.isOptional(); optionalSection = currentSection.isOptional(); var insertToolCall = forceSectionRestart || isFirstSection() || currentSection.getForceToolChange && currentSection.getForceToolChange() || (tool.number != getPreviousSection().getTool().number); retracted = false; var newWorkOffset = isFirstSection() || forceSectionRestart || (getPreviousSection().workOffset != currentSection.workOffset); // work offset changes var newWorkPlane = isFirstSection() || forceSectionRestart || !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()); // force newWorkPlane between indexing and simultaneous operations // define smoothing mode initializeSmoothing(); if (insertToolCall || newWorkOffset || newWorkPlane || smoothing.cancel) { // stop spindle before retract during tool change if (insertToolCall && !isFirstSection()) { onCommand(COMMAND_STOP_SPINDLE); setCoolant(COOLANT_OFF); } // retract to safe plane if (!isFirstSection()) { disableLengthCompensation(); if (getProperty("hoodControl")) { writeBlock(mFormat.format(97), formatComment("DUST HOOD UP")); } writeRetract(Z); // retract writeBlock(gAbsIncModal.format(90)); } forceXYZ(); if (!isFirstSection()) { setSmoothing(false); } } writeln(""); if (hasParameter("operation-comment")) { var comment = getParameter("operation-comment"); if (comment) { writeComment(comment); } } if (getProperty("showNotes") && hasParameter("notes")) { var notes = getParameter("notes"); if (notes) { var lines = String(notes).split("\n"); var r1 = new RegExp("^[\\s]+", "g"); var r2 = new RegExp("[\\s]+$", "g"); for (line in lines) { var comment = lines[line].replace(r1, "").replace(r2, ""); if (comment) { writeComment(comment); } } } } // check for saw blade var sawWasActive = sawIsActive; sawIsActive = tool.type == TOOL_MILLING_SLOT; if (sawIsActive) { if (!isPerpto(currentSection.workPlane.forward, new Vector(0, 0, 1)) || machineConfiguration.isMultiAxisConfiguration()) { sawIsActive = false; } } if (insertToolCall) { forceModals(); forceWorkPlane(); if (!isFirstSection() && getProperty("optionalStop")) { onCommand(COMMAND_OPTIONAL_STOP); } if (tool.number > getProperty("maxTool")) { warning(localize("Tool number exceeds maximum value.")); } disableLengthCompensation(); writeToolBlock(mFormat.format(6), "T" + toolFormat.format(tool.number)); if (tool.comment) { writeComment(tool.comment); } if (getProperty("hoodControl")) { positionHood(0); } 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()); } writeComment(localize("ZMIN") + "=" + zRange.getMinimum()); } } if (getProperty("preloadTool")) { var nextTool = getNextTool(tool.number); if (nextTool) { writeBlock("T" + toolFormat.format(nextTool.number)); } else { // preload first tool var section = getSection(0); var firstToolNumber = section.getTool().number; if (tool.number != firstToolNumber) { writeBlock("T" + toolFormat.format(firstToolNumber)); } } } } 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) { error(localize("Spindle speed out of range.")); return; } if (spindleSpeed > 99999) { warning(localize("Spindle speed exceeds maximum value.")); } var tapping = hasParameter("operation:cycleType") && ((getParameter("operation:cycleType") == "tapping") || (getParameter("operation:cycleType") == "right-tapping") || (getParameter("operation:cycleType") == "left-tapping") || (getParameter("operation:cycleType") == "tapping-with-chip-breaking")); if (!tapping || (tapping && !(getProperty("useRigidTapping") == "without"))) { writeBlock( mFormat.format(tool.clockwise ? 3 : 4), sOutput.format(spindleSpeed) ); } onCommand(COMMAND_START_CHIP_TRANSPORT); if (forceMultiAxisIndexing || !is3D() || machineConfiguration.isMultiAxisConfiguration()) { // writeBlock(mFormat.format(xxx)); // shortest path traverse } } // Output modal commands here gMotionModal.reset(); writeBlock(gPlaneModal.format(17), gAbsIncModal.format(90), gFeedModeModal.format(getProperty("useG95") ? 95 : 94)); // wcs if (insertToolCall) { // force work offset when changing tool currentWorkOffset = undefined; } if (currentSection.workOffset != currentWorkOffset) { if (cancelTiltFirst) { cancelWorkPlane(); } forceWorkPlane(); writeBlock(currentSection.wcs); currentWorkOffset = currentSection.workOffset; } forceXYZ(); if (forceMultiAxisIndexing || !is3D() || machineConfiguration.isMultiAxisConfiguration()) { // use 5-axis indexing for multi-axis mode // set working plane after datum shift if (currentSection.isMultiAxis()) { forceWorkPlane(); cancelTransformation(); } else { var abc = new Vector(0, 0, 0); if (useMultiAxisFeatures && !sawIsActive) { var euler = currentSection.workPlane.getEuler2(EULER_ZXZ_R); abc = new Vector(euler.x, euler.y, euler.z); cancelTransformation(); } else { abc = getWorkPlaneMachineABC(currentSection.workPlane, true, true); } setWorkPlane(abc); } } else { // pure 3D var remaining = currentSection.workPlane; if (!isSameDirection(remaining.forward, new Vector(0, 0, 1))) { error(localize("Tool orientation is not supported.")); return; } setRotation(remaining); } // set coolant after we have positioned at Z setCoolant(tool.coolant); setSmoothing(smoothing.isAllowed); forceAny(); gMotionModal.reset(); var initialPosition = getFramePosition(currentSection.getInitialPosition()); if (!retracted && !insertToolCall) { if (getCurrentPosition().z < initialPosition.z) { writeBlock(gMotionModal.format(0), zOutput.format(initialPosition.z)); } } if (insertToolCall || !lengthCompensationActive || retracted || (!isFirstSection() && getPreviousSection().isMultiAxis())) { var lengthOffset = tool.lengthOffset; if (lengthOffset > 99) { error(localize("Length offset out of range.")); return; } if (!machineConfiguration.isHeadConfiguration()) { var c = ""; if (sawIsActive) { previousSawPosition = new Vector(initialPosition.x, initialPosition.y, initialPosition.z); sawOutput.reset(); c = sawOutput.format(getSawAngle(currentSection.workPlane.forward)); } if (!insertToolCall) { positionHood(0); } writeBlock( gAbsIncModal.format(90), gMotionModal.format(0), xOutput.format(initialPosition.x), yOutput.format(initialPosition.y), c ); var hoodPosition = toPreciseUnit(getProperty(sawIsActive ? "sawHoodPosition" : "hoodPosition"), IN); if (hoodPosition != 0) { positionHood(hoodPosition); // position hood } writeBlock(gMotionModal.format(0), gFormat.format(getProperty("has5Axis") ? 43.4 : 43), zOutput.format(initialPosition.z), hFormat.format(lengthOffset), conditional(getProperty("hoodControl"), mFormat.format(96)), conditional(getProperty("hoodControl"), formatComment("DUST HOOD DOWN")) ); previousSawDirection = undefined; lengthCompensationActive = true; } else { writeBlock( gMotionModal.format(0), gFormat.format(getProperty("has5Axis") ? 43.4 : 43), hFormat.format(lengthOffset), conditional(getProperty("hoodControl"), mFormat.format(96)), conditional(getProperty("hoodControl"), formatComment("DUST HOOD DOWN")) ); if (currentSection.isOptimizedForMachine() && currentSection.isMultiAxis()) { var initialDirection = currentSection.getInitialToolAxisABC(); writeBlock( gAbsIncModal.format(90), gMotionModal.format(0), xOutput.format(initialPosition.x), yOutput.format(initialPosition.y), aOutput.format(initialDirection.x), bOutput.format(initialDirection.y), cOutput.format(initialDirection.z) ); writeBlock( gMotionModal.format(0), zOutput.format(initialPosition.z) ); } else { writeBlock( gAbsIncModal.format(90), gMotionModal.format(0), xOutput.format(initialPosition.x), yOutput.format(initialPosition.y), zOutput.format(initialPosition.z) ); } lengthCompensationActive = true; } gMotionModal.reset(); } else { if (sawIsActive) { previousSawPosition = new Vector(initalPosition.x, initialPosition.y, initialPosition.z); } writeBlock( gAbsIncModal.format(90), gMotionModal.format(0), xOutput.format(initialPosition.x), yOutput.format(initialPosition.y) ); previousSawDirection = undefined; } validate(lengthCompensationActive, "Length compensation is not active."); if (getProperty("useParametricFeed") && hasParameter("operation-strategy") && (getParameter("operation-strategy") != "drill") && // legacy !(currentSection.hasAnyCycle && currentSection.hasAnyCycle())) { if (!insertToolCall && activeMovements && (getCurrentSectionId() > 0) && ((getPreviousSection().getPatternId() == currentSection.getPatternId()) && (currentSection.getPatternId() != 0))) { // use the current feeds } else { initializeActiveFeeds(); } } else { activeMovements = undefined; } } function onDwell(seconds) { if (seconds > 99999.999) { warning(localize("Dwelling time is out of range.")); } milliseconds = clamp(1, seconds * 1000, 99999999); writeBlock(gFeedModeModal.format(94), gFormat.format(4), "P" + milliFormat.format(milliseconds)); writeBlock(gFeedModeModal.format(getProperty("useG95") ? 95 : 94)); // back to G95 } function onSpindleSpeed(spindleSpeed) { writeBlock(sOutput.format(spindleSpeed)); } function onCycle() { if (sawIsActive) { error(localize("Cycles are not allowed when using a saw blade.")); return; } writeBlock(gPlaneModal.format(17)); } function getCommonCycle(x, y, z, r) { forceXYZ(); // force xyz on first drill hole of any cycle return [xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + xyzFormat.format(r)]; } function onCyclePoint(x, y, z) { if (!isSameDirection(getRotation().forward, new Vector(0, 0, 1))) { expandCyclePoint(x, y, z); return; } if (isFirstCyclePoint()) { repositionToCycleClearance(cycle, x, y, z); // return to initial Z which is clearance plane and set absolute mode var F = cycle.feedrate; if (getProperty("useG95")) { F /= spindleSpeed; } var P = !cycle.dwell ? 0 : clamp(1, cycle.dwell * 1000, 99999999); // in milliseconds switch (cycleType) { case "drilling": writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(81), getCommonCycle(x, y, z, cycle.retract), feedOutput.format(F) ); break; case "counter-boring": if (P > 0) { writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(82), getCommonCycle(x, y, z, cycle.retract), "P" + milliFormat.format(P), feedOutput.format(F) ); } else { writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(81), getCommonCycle(x, y, z, cycle.retract), feedOutput.format(F) ); } break; case "chip-breaking": if ((cycle.accumulatedDepth < cycle.depth) || (P > 0)) { expandCyclePoint(x, y, z); } else { writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(73), getCommonCycle(x, y, z, cycle.retract), peckOutput.format(cycle.incrementalDepth), feedOutput.format(F) ); } break; case "deep-drilling": if (P > 0) { expandCyclePoint(x, y, z); } else { writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(83), getCommonCycle(x, y, z, cycle.retract), peckOutput.format(cycle.incrementalDepth), // conditional(P > 0, "P" + milliFormat.format(P)), feedOutput.format(F) ); } break; case "tapping": if (getProperty("useRigidTapping") != "no") { writeBlock(mFormat.format(29), sOutput.format(spindleSpeed)); } if (getProperty("usePitchForTapping")) { writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND) ? 74 : 84), getCommonCycle(x, y, z, cycle.retract), "P" + milliFormat.format(P), pitchOutput.format(tool.threadPitch) ); forceFeed(); } else { var tappingFPM = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); F = (getProperty("useG95") ? tool.getThreadPitch() : tappingFPM); writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND) ? 74 : 84), getCommonCycle(x, y, z, cycle.retract), "P" + milliFormat.format(P), feedOutput.format(F) ); } break; case "left-tapping": if (getProperty("useRigidTapping") != "no") { writeBlock(mFormat.format(29), sOutput.format(spindleSpeed)); } if (getProperty("usePitchForTapping")) { writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(74), getCommonCycle(x, y, z, cycle.retract), "P" + milliFormat.format(P), pitchOutput.format(tool.threadPitch) ); forceFeed(); } else { var tappingFPM = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); F = (getProperty("useG95") ? tool.getThreadPitch() : tappingFPM); writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(74), getCommonCycle(x, y, z, cycle.retract), "P" + milliFormat.format(P), feedOutput.format(F) ); } break; case "right-tapping": if (getProperty("useRigidTapping") != "no") { writeBlock(mFormat.format(29), sOutput.format(spindleSpeed)); } if (getProperty("usePitchForTapping")) { writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(84), getCommonCycle(x, y, z, cycle.retract), "P" + milliFormat.format(P), pitchOutput.format(tool.threadPitch) ); forceFeed(); } else { var tappingFPM = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); F = (getProperty("useG95") ? tool.getThreadPitch() : tappingFPM); writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(84), getCommonCycle(x, y, z, cycle.retract), "P" + milliFormat.format(P), feedOutput.format(F) ); } break; case "tapping-with-chip-breaking": case "left-tapping-with-chip-breaking": case "right-tapping-with-chip-breaking": if (cycle.accumulatedDepth < cycle.depth) { error(localize("Accumulated pecking depth is not supported for tapping cycles with chip breaking.")); return; } else { if (getProperty("useRigidTapping") != "no") { writeBlock(mFormat.format(29), sOutput.format(spindleSpeed)); } if (getProperty("usePitchForTapping")) { writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND ? 74 : 84)), getCommonCycle(x, y, z, cycle.retract), "P" + milliFormat.format(P), peckOutput.format(cycle.incrementalDepth), pitchOutput.format(tool.threadPitch) ); forceFeed(); } else { var tappingFPM = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); F = (getProperty("useG95") ? tool.getThreadPitch() : tappingFPM); writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND ? 74 : 84)), getCommonCycle(x, y, z, cycle.retract), "P" + milliFormat.format(P), peckOutput.format(cycle.incrementalDepth), feedOutput.format(F) ); } } break; case "fine-boring": writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(76), getCommonCycle(x, y, z, cycle.retract), "P" + milliFormat.format(P), // not optional "Q" + xyzFormat.format(cycle.shift), feedOutput.format(F) ); break; case "back-boring": var dx = (gPlaneModal.getCurrent() == 19) ? cycle.backBoreDistance : 0; var dy = (gPlaneModal.getCurrent() == 18) ? cycle.backBoreDistance : 0; var dz = (gPlaneModal.getCurrent() == 17) ? cycle.backBoreDistance : 0; writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(87), getCommonCycle(x - dx, y - dy, z - dz, cycle.bottom), "Q" + xyzFormat.format(cycle.shift), "P" + milliFormat.format(P), // not optional feedOutput.format(F) ); break; case "reaming": if (feedFormat.getResultingValue(cycle.feedrate) != feedFormat.getResultingValue(cycle.retractFeedrate)) { expandCyclePoint(x, y, z); break; } if (P > 0) { writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(89), getCommonCycle(x, y, z, cycle.retract), "P" + milliFormat.format(P), feedOutput.format(F) ); } else { writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(85), getCommonCycle(x, y, z, cycle.retract), feedOutput.format(F) ); } break; case "stop-boring": if (P > 0) { expandCyclePoint(x, y, z); } else { writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(86), getCommonCycle(x, y, z, cycle.retract), feedOutput.format(F) ); } break; case "manual-boring": writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(88), getCommonCycle(x, y, z, cycle.retract), "P" + milliFormat.format(P), // not optional feedOutput.format(F) ); break; case "boring": if (feedFormat.getResultingValue(cycle.feedrate) != feedFormat.getResultingValue(cycle.retractFeedrate)) { expandCyclePoint(x, y, z); break; } if (P > 0) { writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(89), getCommonCycle(x, y, z, cycle.retract), "P" + milliFormat.format(P), // not optional feedOutput.format(F) ); } else { writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(85), getCommonCycle(x, y, z, cycle.retract), feedOutput.format(F) ); } break; default: expandCyclePoint(x, y, z); } } else { if (cycleExpanded) { expandCyclePoint(x, y, z); } else { writeBlock(xOutput.format(x), yOutput.format(y)); } } } function onCycleEnd() { if (!cycleExpanded) { writeBlock(gCycleModal.format(80)); zOutput.reset(); } } var pendingRadiusCompensation = -1; function onRadiusCompensation() { pendingRadiusCompensation = radiusCompensation; } function onRapid(_x, _y, _z) { if (sawIsActive) { linearSawMove(_x, _y, _z, 0); return; } var x = xOutput.format(_x); var y = yOutput.format(_y); var z = zOutput.format(_z); if (x || y || z) { if (pendingRadiusCompensation >= 0) { error(localize("Radius compensation mode cannot be changed at rapid traversal.")); return; } writeBlock(gMotionModal.format(0), x, y, z); forceFeed(); } } function onLinear(_x, _y, _z, feed) { if (sawIsActive) { linearSawMove(_x, _y, _z, feed); return; } var x = xOutput.format(_x); var y = yOutput.format(_y); var z = zOutput.format(_z); var f = getFeed(feed); if (x || y || z) { if (pendingRadiusCompensation >= 0) { pendingRadiusCompensation = -1; var d = tool.diameterOffset; if (d > 99) { warning(localize("The diameter offset exceeds the maximum value.")); } writeBlock(gPlaneModal.format(17)); switch (radiusCompensation) { case RADIUS_COMPENSATION_LEFT: dOutput.reset(); writeBlock(gMotionModal.format(1), gFormat.format(41), x, y, z, dOutput.format(d), f); break; case RADIUS_COMPENSATION_RIGHT: dOutput.reset(); writeBlock(gMotionModal.format(1), gFormat.format(42), x, y, z, dOutput.format(d), f); break; default: writeBlock(gMotionModal.format(1), gFormat.format(40), x, y, z, f); } } else { writeBlock(gMotionModal.format(1), x, y, z, f); } } else if (f) { if (getNextRecord().isMotion()) { // try not to output feed without motion forceFeed(); // force feed on next line } else { writeBlock(gMotionModal.format(1), f); } } } var previousSawDirection = undefined; var currentSawPosition = undefined; // TAG: getCurrentPostion returns wrong value when switching workPlanes function linearSawMove(_x, _y, _z, feed) { // write out saw move var x = xOutput.format(_x); var y = yOutput.format(_y); var z = zOutput.format(_z); if (x || y || z) { if (!checkSawDirection(new Vector(_x, _y, _z), feed)) { error(localize("Saw changes direction during cut")); return; } var c = getSawAngle(currentSection.workPlane.forward); // calculate saw blade angle writeBlock(gMotionModal.format(feed == 0 ? 0 : 1), x, y, z, sawOutput.format(c), (feed == 0 ? "" : feedOutput.format(feed))); previousSawPosition = new Vector(_x, _y, _z); } } function getSawAngle(direction) { var angle = toRad(getProperty("sawBaseAngle")) + direction.getXYAngle(); angle = angle < 0 ? angle + (Math.PI * 2) : angle; return angle; } function checkSawDirection(xyz, feed) { if (feed == 0) { previousSawDirection = undefined; return true; } var current = new Vector(xyz.x, xyz.y, 0); var previous = new Vector(previousSawPosition.x, previousSawPosition.y, 0); var direction = Vector.diff(current, previous).normalized; if (direction.isZero()) { // move in Z only previousSawDirection = undefined; return true; } else if (previousSawDirection == undefined) { // first cutting move previousSawDirection = new Vector(direction.x, direction.y, direction.z); return true; } else if (isSameDirection(direction, previousSawDirection)) { // saw moves in same direction return true; } else { // saw changes direction during cut previousSawDirection = new Vector(direction.x, direction.y, direction.z); return false; } } function positionHood(position) { if (getProperty("hoodControl")) { writeBlock("#990=" + hoodPositionFormat.format(position), formatComment("DUST HOOD LENGTH")); } } function onRapid5D(_x, _y, _z, _a, _b, _c) { if (pendingRadiusCompensation >= 0) { error(localize("Radius compensation mode cannot be changed at rapid traversal.")); return; } if (currentSection.isOptimizedForMachine()) { var x = xOutput.format(_x); var y = yOutput.format(_y); var z = zOutput.format(_z); var a = aOutput.format(_a); var b = bOutput.format(_b); var c = cOutput.format(_c); writeBlock(gMotionModal.format(0), x, y, z, a, b, c); } else { forceXYZ(); var x = xOutput.format(_x); var y = yOutput.format(_y); var z = zOutput.format(_z); var i = ijkFormat.format(_a); var j = ijkFormat.format(_b); var k = ijkFormat.format(_c); writeBlock(gMotionModal.format(0), x, y, z, "I" + i, "J" + j, "K" + k); } forceFeed(); } function onLinear5D(_x, _y, _z, _a, _b, _c, feed) { if (pendingRadiusCompensation >= 0) { error(localize("Radius compensation cannot be activated/deactivated for 5-axis move.")); return; } if (currentSection.isOptimizedForMachine()) { var x = xOutput.format(_x); var y = yOutput.format(_y); var z = zOutput.format(_z); var a = aOutput.format(_a); var b = bOutput.format(_b); var c = cOutput.format(_c); var f = getFeed(feed); if (x || y || z || a || b || c) { writeBlock(gMotionModal.format(1), x, y, z, a, b, c, f); } else if (f) { if (getNextRecord().isMotion()) { // try not to output feed without motion forceFeed(); // force feed on next line } else { writeBlock(gMotionModal.format(1), f); } } } else { forceXYZ(); var x = xOutput.format(_x); var y = yOutput.format(_y); var z = zOutput.format(_z); var i = ijkFormat.format(_a); var j = ijkFormat.format(_b); var k = ijkFormat.format(_c); var f = getFeed(feed); if (x || y || z || i || j || k) { writeBlock(gMotionModal.format(1), x, y, z, "I" + i, "J" + j, "K" + k, f); } else if (f) { if (getNextRecord().isMotion()) { // try not to output feed without motion forceFeed(); // force feed on next line } else { writeBlock(gMotionModal.format(1), f); } } } } // Start of onRewindMachine logic /***** Be sure to add 'safeRetractDistance' to post getProperty(" ")*****/ var performRewinds = true; // enables the onRewindMachine logic var safeRetractFeed = (unit == IN) ? 20 : 500; var safePlungeFeed = (unit == IN) ? 10 : 250; var stockAllowance = new Vector(toPreciseUnit(0.1, IN), toPreciseUnit(0.1, IN), toPreciseUnit(0.1, IN)); /** Allow user to override the onRewind logic */ function onRewindMachineEntry(_a, _b, _c) { return false; } /** Retract to safe position before indexing rotaries. */ function moveToSafeRetractPosition(isRetracted) { if (!isRetracted) { writeRetract(Z); } } /** Return from safe position after indexing rotaries. */ function returnFromSafeRetractPosition(position) { forceXYZ(); xOutput.reset(); yOutput.reset(); zOutput.disable(); onExpandedRapid(position.x, position.y, position.z); zOutput.enable(); onExpandedRapid(position.x, position.y, position.z); } /** Intersect the point-vector with the stock box. */ function intersectStock(point, direction) { var intersection = getWorkpiece().getRayIntersection(point, direction, stockAllowance); return intersection === null ? undefined : intersection.second; } /** Calculates the retract point using the stock box and safe retract distance. */ function getRetractPosition(currentPosition, currentDirection) { var retractPos = intersectStock(currentPosition, currentDirection); if (retractPos == undefined) { if (tool.getFluteLength() != 0) { retractPos = Vector.sum(currentPosition, Vector.product(currentDirection, tool.getFluteLength())); } } if ((retractPos != undefined) && getProperty("safeRetractDistance")) { retractPos = Vector.sum(retractPos, Vector.product(currentDirection, getProperty("safeRetractDistance"))); } return retractPos; } /** Determines if the angle passed to onRewindMachine is a valid starting position */ function isRewindAngleValid(_a, _b, _c) { // make sure the angles are different from the last output angles if (!abcFormat.areDifferent(getCurrentDirection().x, _a) && !abcFormat.areDifferent(getCurrentDirection().y, _b) && !abcFormat.areDifferent(getCurrentDirection().z, _c)) { error( localize("REWIND: Rewind angles are the same as the previous angles: ") + abcFormat.format(_a) + ", " + abcFormat.format(_b) + ", " + abcFormat.format(_c) ); return false; } // make sure angles are within the limits of the machine var abc = new Array(_a, _b, _c); var ix = machineConfiguration.getAxisU().getCoordinate(); var failed = false; if ((ix != -1) && !machineConfiguration.getAxisU().isSupported(abc[ix])) { failed = true; } ix = machineConfiguration.getAxisV().getCoordinate(); if ((ix != -1) && !machineConfiguration.getAxisV().isSupported(abc[ix])) { failed = true; } ix = machineConfiguration.getAxisW().getCoordinate(); if ((ix != -1) && !machineConfiguration.getAxisW().isSupported(abc[ix])) { failed = true; } if (failed) { error( localize("REWIND: Rewind angles are outside the limits of the machine: ") + abcFormat.format(_a) + ", " + abcFormat.format(_b) + ", " + abcFormat.format(_c) ); return false; } return true; } function onRewindMachine(_a, _b, _c) { if (!performRewinds) { error(localize("REWIND: Rewind of machine is required for simultaneous multi-axis toolpath and has been disabled.")); return; } // Allow user to override rewind logic if (onRewindMachineEntry(_a, _b, _c)) { return; } // Determine if input angles are valid or will cause a crash if (!isRewindAngleValid(_a, _b, _c)) { error( localize("REWIND: Rewind angles are invalid:") + abcFormat.format(_a) + ", " + abcFormat.format(_b) + ", " + abcFormat.format(_c) ); return; } // Work with the tool end point if (currentSection.getOptimizedTCPMode() == 0) { currentTool = getCurrentPosition(); } else { currentTool = machineConfiguration.getOrientation(getCurrentDirection()).multiply(getCurrentPosition()); } var currentABC = getCurrentDirection(); var currentDirection = machineConfiguration.getDirection(currentABC); // Calculate the retract position var retractPosition = getRetractPosition(currentTool, currentDirection); // Output warning that axes take longest route if (retractPosition == undefined) { error(localize("REWIND: Cannot calculate retract position.")); return; } else { var text = localize("REWIND: Tool is retracting due to rotary axes limits."); warning(text); writeComment(text); } // Move to retract position var position; if (currentSection.getOptimizedTCPMode() == 0) { position = retractPosition; } else { position = machineConfiguration.getOrientation(getCurrentDirection()).getTransposed().multiply(retractPosition); } onExpandedLinear(position.x, position.y, position.z, safeRetractFeed); //Position to safe machine position for rewinding axes moveToSafeRetractPosition(false); // Rotate axes to new position above reentry position xOutput.disable(); yOutput.disable(); zOutput.disable(); onRapid5D(position.x, position.y, position.z, _a, _b, _c); xOutput.enable(); yOutput.enable(); zOutput.enable(); // Move back to position above part if (currentSection.getOptimizedTCPMode() != 0) { position = machineConfiguration.getOrientation(new Vector(_a, _b, _c)).getTransposed().multiply(retractPosition); } returnFromSafeRetractPosition(position); // Plunge tool back to original position if (currentSection.getOptimizedTCPMode() != 0) { currentTool = machineConfiguration.getOrientation(new Vector(_a, _b, _c)).getTransposed().multiply(currentTool); } onExpandedLinear(currentTool.x, currentTool.y, currentTool.z, safePlungeFeed); } // End of onRewindMachine logic function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { if (pendingRadiusCompensation >= 0) { error(localize("Radius compensation cannot be activated/deactivated for a circular move.")); return; } var start = getCurrentPosition(); if (isFullCircle()) { if (getProperty("useRadius") || isHelical()) { // radius mode does not support full arcs linearize(tolerance); return; } switch (getCircularPlane()) { case PLANE_XY: writeBlock(gAbsIncModal.format(90), gPlaneModal.format(17), gMotionModal.format(clockwise ? 2 : 3), iOutput.format(cx - start.x, 0), jOutput.format(cy - start.y, 0), getFeed(feed)); break; case PLANE_ZX: writeBlock(gAbsIncModal.format(90), gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), iOutput.format(cx - start.x, 0), kOutput.format(cz - start.z, 0), getFeed(feed)); break; case PLANE_YZ: writeBlock(gAbsIncModal.format(90), gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), jOutput.format(cy - start.y, 0), kOutput.format(cz - start.z, 0), getFeed(feed)); break; default: linearize(tolerance); } } else if (!getProperty("useRadius")) { switch (getCircularPlane()) { case PLANE_XY: writeBlock(gAbsIncModal.format(90), gPlaneModal.format(17), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x, 0), jOutput.format(cy - start.y, 0), getFeed(feed)); break; case PLANE_ZX: writeBlock(gAbsIncModal.format(90), gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x, 0), kOutput.format(cz - start.z, 0), getFeed(feed)); break; case PLANE_YZ: writeBlock(gAbsIncModal.format(90), gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), jOutput.format(cy - start.y, 0), kOutput.format(cz - start.z, 0), getFeed(feed)); break; default: if (getProperty("allow3DArcs")) { // make sure maximumCircularSweep is well below 360deg // we could use G02.4 or G03.4 - direction is calculated var ip = getPositionU(0.5); writeBlock(gAbsIncModal.format(90), gMotionModal.format(clockwise ? 2.4 : 3.4), xOutput.format(ip.x), yOutput.format(ip.y), zOutput.format(ip.z), getFeed(feed)); writeBlock(xOutput.format(x), yOutput.format(y), zOutput.format(z)); } else { linearize(tolerance); } } } else { // use radius mode var r = getCircularRadius(); if (toDeg(getCircularSweep()) > (180 + 1e-9)) { r = -r; // allow up to <360 deg arcs } switch (getCircularPlane()) { case PLANE_XY: writeBlock(gPlaneModal.format(17), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed)); break; case PLANE_ZX: writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed)); break; case PLANE_YZ: writeBlock(gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed)); break; default: if (getProperty("allow3DArcs")) { // make sure maximumCircularSweep is well below 360deg // we could use G02.4 or G03.4 - direction is calculated var ip = getPositionU(0.5); writeBlock(gAbsIncModal.format(90), gMotionModal.format(clockwise ? 2.4 : 3.4), xOutput.format(ip.x), yOutput.format(ip.y), zOutput.format(ip.z), getFeed(feed)); writeBlock(xOutput.format(x), yOutput.format(y), zOutput.format(z)); } else { linearize(tolerance); } } } } var currentCoolantMode = COOLANT_OFF; var coolantOff = undefined; var forceCoolant = false; function setCoolant(coolant) { var coolantCodes = getCoolantCodes(coolant); if (Array.isArray(coolantCodes)) { if (singleLineCoolant) { writeBlock(coolantCodes.join(getWordSeparator())); } else { for (var c in coolantCodes) { writeBlock(coolantCodes[c]); } } return undefined; } return coolantCodes; } function getCoolantCodes(coolant) { var multipleCoolantBlocks = new Array(); // create a formatted array to be passed into the outputted line if (!coolants) { error(localize("Coolants have not been defined.")); } if (tool.type == TOOL_PROBE) { // avoid coolant output for probing 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 (Array.isArray(coolantOff)) { for (var i in coolantOff) { multipleCoolantBlocks.push(coolantOff[i]); } } else { multipleCoolantBlocks.push(coolantOff); } } forceCoolant = false; var m; var coolantCodes = {}; for (var c in coolants) { // find required coolant codes into the coolants array if (coolants[c].id == coolant) { coolantCodes.on = coolants[c].on; if (coolants[c].off != undefined) { coolantCodes.off = coolants[c].off; break; } else { for (var i in coolants) { if (coolants[i].id == COOLANT_OFF) { coolantCodes.off = coolants[i].off; break; } } } } } if (coolant == COOLANT_OFF) { m = !coolantOff ? coolantCodes.off : coolantOff; // use the default coolant off command when an 'off' value is not specified } else { coolantOff = coolantCodes.off; m = coolantCodes.on; } if (!m) { onUnsupportedCoolant(coolant); m = 9; } else { if (Array.isArray(m)) { for (var i in m) { multipleCoolantBlocks.push(m[i]); } } else { multipleCoolantBlocks.push(m); } currentCoolantMode = coolant; for (var i in multipleCoolantBlocks) { if (typeof multipleCoolantBlocks[i] == "number") { multipleCoolantBlocks[i] = mFormat.format(multipleCoolantBlocks[i]); } } return multipleCoolantBlocks; // return the single formatted coolant value } return undefined; } var mapCommand = { COMMAND_STOP : 0, COMMAND_OPTIONAL_STOP : 1, COMMAND_END : 2, COMMAND_SPINDLE_CLOCKWISE : 3, COMMAND_SPINDLE_COUNTERCLOCKWISE: 4, COMMAND_STOP_SPINDLE : 5, COMMAND_ORIENTATE_SPINDLE : 19 }; function onCommand(command) { switch (command) { case COMMAND_STOP: writeBlock(mFormat.format(0)); forceSpindleSpeed = true; forceCoolant = true; return; case COMMAND_OPTIONAL_STOP: writeBlock(mFormat.format(1)); forceSpindleSpeed = true; forceCoolant = true; return; case COMMAND_START_SPINDLE: onCommand(tool.clockwise ? COMMAND_SPINDLE_CLOCKWISE : COMMAND_SPINDLE_COUNTERCLOCKWISE); return; case COMMAND_LOCK_MULTI_AXIS: return; case COMMAND_UNLOCK_MULTI_AXIS: return; case COMMAND_START_CHIP_TRANSPORT: return; case COMMAND_STOP_CHIP_TRANSPORT: return; case COMMAND_BREAK_CONTROL: return; case COMMAND_TOOL_MEASURE: return; } var stringId = getCommandStringId(command); var mcode = mapCommand[stringId]; if (mcode != undefined) { writeBlock(mFormat.format(mcode)); } else { onUnsupportedCommand(command); } } function onSectionEnd() { if (currentSection.isMultiAxis() && !currentSection.isOptimizedForMachine()) { disableLengthCompensation(); } writeBlock(gPlaneModal.format(17)); // the code below gets the machine angles from previous operation. closestABC must also be set to true if (currentSection.isMultiAxis() && currentSection.isOptimizedForMachine()) { currentMachineABC = currentSection.getFinalToolAxisABC(); } if (((getCurrentSectionId() + 1) >= getNumberOfSections()) || (tool.number != getNextSection().getTool().number)) { onCommand(COMMAND_BREAK_CONTROL); } if (!isLastSection() && (getNextSection().getTool().coolant != tool.coolant)) { setCoolant(COOLANT_OFF); } forceAny(); } /** Output block to do safe retract and/or move to home position. */ function writeRetract() { if (arguments.length == 0) { error(localize("No axis specified for writeRetract().")); return; } var words = []; // store all retracted axes in an array for (var i = 0; i < arguments.length; ++i) { let instances = 0; // checks for duplicate retract calls for (var j = 0; j < arguments.length; ++j) { if (arguments[i] == arguments[j]) { ++instances; } } if (instances > 1) { // error if there are multiple retract calls for the same axis error(localize("Cannot retract the same axis twice in one line")); return; } switch (arguments[i]) { case X: words.push("X" + xyzFormat.format(machineConfiguration.hasHomePositionX() ? machineConfiguration.getHomePositionX() : 0)); break; case Y: words.push("Y" + xyzFormat.format(machineConfiguration.hasHomePositionY() ? machineConfiguration.getHomePositionY() : 0)); break; case Z: words.push("Z" + xyzFormat.format(machineConfiguration.getRetractPlane())); retracted = true; // specifies that the tool has been retracted to the safe plane zOutput.reset(); break; default: error(localize("Bad axis specified for writeRetract().")); return; } } if (words.length > 0) { gMotionModal.reset(); gAbsIncModal.reset(); writeBlock(gMotionModal.format(0), gAbsIncModal.format(91), gFormat.format(28), words); // retract writeBlock(gAbsIncModal.format(90)); } } function onClose() { writeln(""); optionalSection = false; setCoolant(COOLANT_OFF); onCommand(COMMAND_STOP_SPINDLE); if (getProperty("hoodControl")) { writeBlock(mFormat.format(97), formatComment("DUST HOOD UP")); } gMotionModal.reset(); writeRetract(Z); writeBlock(gAbsIncModal.format(90)); disableLengthCompensation(true); zOutput.reset(); setWorkPlane(new Vector(0, 0, 0)); // reset working plane /* writeRetract(Z); */ setSmoothing(false); if (getProperty("vacuumTable") > 0) { var vacuumCodes = [141, 142, 140]; writeBlock(mFormat.format(vacuumCodes[getProperty("vacuumTable") - 1])); } onImpliedCommand(COMMAND_END); onImpliedCommand(COMMAND_STOP_SPINDLE); // writeBlock(gFormat.format(399)); // required for some machines writeBlock(mFormat.format(30)); // stop program, spindle stop, coolant off writeln("%"); } function setProperty(property, value) { properties[property].current = value; }