/** Copyright (C) 2012-2023 by Autodesk, Inc. All rights reserved. Tormach PathPilot post processor configuration. $Revision: 44103 ba9c2f3336baedb43b59a05af9d4a8a46f5bdac4 $ $Date: 2023-12-07 14:34:35 $ FORKID {3CFDE807-BE2F-4A4C-B12A-03080F4B1285} */ description = "Tormach PathPilot"; vendor = "Tormach"; vendorUrl = "http://www.tormach.com"; legal = "Copyright (C) 2012-2023 by Autodesk, Inc."; certificationLevel = 2; minimumRevision = 45899; longDescription = "Tormach PathPilot post for 3-axis and 4-axis milling with SmartCool support."; extension = "nc"; setCodePage("ascii"); capabilities = CAPABILITY_MILLING | CAPABILITY_MACHINE_SIMULATION; tolerance = spatial(0.002, MM); minimumChordLength = spatial(0.25, MM); minimumCircularRadius = spatial(0.01, MM); maximumCircularRadius = spatial(1000, MM); minimumCircularSweep = toRad(0.01); maximumCircularSweep = toRad(180); allowHelicalMoves = true; allowedCircularPlanes = undefined; // allow any circular motion // 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" }, writeVersion: { title : "Write version", description: "Write the version number in the header of the code.", group : "formats", type : "boolean", value : false, scope : "post" }, safePositionMethod: { title : "Safe Retracts", description: "Select your desired retract option. 'Clearance Height' retracts to the operation clearance height.", group : "homePositions", type : "enum", values : [ {title:"G28", id:"G28"}, // {title: "G53", id: "G53"}, {title:"Clearance Height", id:"clearanceHeight"}, {title:"G30", id:"G30"}, {title:"G28 & G30", id:"G28G30"} ], value: "G30", scope: "post" }, useM06: { title : "Use M6", description: "Disable to avoid outputting M6.", group : "preferences", type : "boolean", value : true, scope : "post" }, showSequenceNumbers: { title : "Use sequence numbers", description: "'Yes' outputs sequence numbers on each block, 'Only on tool change' outputs sequence numbers on tool change blocks only, and 'No' disables the output of sequence numbers.", group : "formats", type : "enum", values : [ {title:"Yes", id:"true"}, {title:"No", id:"false"}, {title:"Only on tool change", id:"toolChange"} ], value: "false", 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 : 10, scope : "post" }, sequenceNumberOperation: { title : "Sequence number at operation only", description: "Use sequence numbers at start of operation only.", group : "formats", type : "boolean", value : true, scope : "post" }, optionalStop: { title : "Optional stop between tools", description: "Outputs optional stop code prior to a tool change.", group : "preferences", type : "boolean", value : true, scope : "post" }, optionalStopOperation: { title : "Optional stop between operations", description: "Outputs optional stop code prior between all operations.", 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" }, 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" }, dwellInSeconds: { title : "Dwell in seconds", description: "Specifies the unit for dwelling, set to 'Yes' for seconds and 'No' for milliseconds.", group : "preferences", type : "boolean", value : true, scope : "post" }, forceWorkOffset: { title : "Force work offset", description: "Forces the work offset code at tool changes.", group : "preferences", type : "boolean", value : false, scope : "post" }, rotaryTableAxis: { title : "Rotary table axis", description: "Select rotary table axis. Check the table direction on the machine and use the (Reversed) selection if the table is moving in the opposite direction.", group : "configuration", type : "enum", values : [ {title:"No rotary", id:"none"}, {title:"X", id:"x"}, {title:"Y", id:"y"}, {title:"Z", id:"z"}, {title:"X (Reversed)", id:"-x"}, {title:"Y (Reversed)", id:"-y"}, {title:"Z (Reversed)", id:"-z"} ], value: "none", scope: "post" }, smartCoolEquipped: { title : "SmartCool equipped", description: "Specifies if the machine has the SmartCool attachment.", group : "coolant", type : "boolean", value : false, scope : "post" }, multiCoolEquipped: { title : "Multi-Coolant equipped", description: "Specifies if the machine has the Multi-Coolant module.", group : "coolant", type : "boolean", value : false, scope : "post" }, smartCoolToolSweepPercentage: { title : "SmartCool sweep percentage", description: "Sets the tool length percentage to sweep coolant.", group : "coolant", type : "integer", value : 100, scope : "post" }, multiCoolAirBlastSeconds: { title : "Multi-Coolant air blast in seconds", description: "Sets the Multi-Coolant air blast time in seconds.", group : "coolant", type : "integer", value : 4, scope : "post" }, outputCoolants: { title : "Output coolant commands", description: "Specfies if coolant commands should be used or disabled.", group : "coolant", type : "boolean", value : true, scope : "post" }, useRigidTapping: { title : "Tapping style", description: "Choose standard (G84), Rigid (G33.1), or Self-reversing tapping head, which will expand tapping cycles.", group : "tapping", type : "enum", values : [ {title:"Rigid (G33.1)", id:"yes"}, {title:"Standard (G84)", id:"no"}, {title:"Self-reversing head", id:"reversing"} ], value: "no", scope: "post" }, reversingHeadFeed: { title : "Self-reversing head feed ratio", description: "The percentage of the tapping feedrate for retracting the tool when the Tapping style is set to 'Self-reversing head'.", group : "tapping", type : "number", value : 2, scope : "post" }, tappingSpeed: { title : "Tapping retract speed ratio", description: "The percentage of the spindle speed used when retracting the tool during a tapping cycle.", group : "tapping", type : "number", value : 1, range : [0.01, 2.0], scope : "post" }, maxTool: { title : "Maximum tool number", description: "Enter the maximum tool number allowed by the control.", group : "configuration", type : "number", value : 1000, scope : "post" }, toolBreakageTolerance: { title : "Tool breakage tolerance", description: "Specifies the tolerance for which tool break detection will raise an alarm.", group : "preferences", type : "spatial", value : 0.1, scope : "post" }, measureTools: { title : "Optionally measure tools at start", description: "Measure each tool used at the beginning of the program when the control parameter specified in 'Parameter number to enable tool measurement' is set to 0.", group : "preferences", type : "boolean", value : false, scope : "post" }, measureToolsParameter: { title : "Parameter number to enable tool measurement", description: "Enter the parameter number used to enable tool measurements when the program is run.\nThis parameter must be set to 0 to enable the tool measurement operation on the machine.\nThe 'Optionally measure tools at start' property must be enabled.", group : "preferences", type : "number", value : 1, scope : "post" }, allowAllProbeTools: { title : "Allow all tool numbers for probes", description: "FOR TESTING PURPOSES ONLY. DO NOT ENABLE.", group : "preferences", type : "boolean", value : false, scope : "post", visible : false }, }; // define the custom property groups groupDefinitions = { coolant: {title:"Coolant", order:51, collapsed:true, description:"Smart/Multi-Coolant options."}, tapping: {title:"Tapping", order:52, collapsed:true, description:"Tapping options."} }; // wcs definiton wcsDefinitions = { useZeroOffset: false, wcs : [ {name:"Standard", format:"G", range:[54, 59]}, {name:"Extended", format:"G59.", range:[1, 3]}, {name:"Extra", format:"G54.1 P", range:[10, 500]} ] }; var permittedCommentChars = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.,=_-*'#()"; var nFormat = createFormat({prefix:"N", decimals:0}); var gFormat = createFormat({prefix:"G", decimals:1}); var mFormat = createFormat({prefix:"M", decimals:0}); var hFormat = createFormat({prefix:"H", decimals:0}); var dFormat = createFormat({prefix:"D", decimals:0}); var xyzFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true}); var rFormat = xyzFormat; // radius var abcFormat = createFormat({decimals:3, forceDecimal:true, scale:DEG}); var feedFormat = createFormat({decimals:(unit == MM ? 2 : 3), forceDecimal:true}); var inverseTimeFormat = createFormat({decimals:4, forceDecimal:true}); var pitchFormat = createFormat({decimals:(unit === MM ? 3 : 4), forceDecimal:true}); // thread pitch var toolFormat = createFormat({decimals:0}); var rpmFormat = createFormat({decimals:0}); var coolantOptionFormat = 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 qFormat = createFormat({prefix:"Q", 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 pitchOutput = createVariable({prefix:"K", force:true}, pitchFormat); var sOutput = createVariable({prefix:"S", force:true}, rpmFormat); var dOutput = createVariable({}, dFormat); // circular output var iOutput = createReferenceVariable({prefix:"I", force:true}, xyzFormat); var jOutput = createReferenceVariable({prefix:"J", force:true}, xyzFormat); var kOutput = createReferenceVariable({prefix:"K", force:true}, xyzFormat); var gMotionModal = createModal({force:true}, 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 // G93-94 var gUnitModal = createModal({}, gFormat); // modal group 6 // G20-21 var gCycleModal = createModal({force:false}, gFormat); // modal group 9 // G81, ... var gRetractModal = createModal({force:true}, gFormat); // modal group 10 // G98-99 // fixed settings var maxTappingRetractSpeed = 2000; // collected state var sequenceNumber; var currentWorkOffset; var currentCoolantMode = COOLANT_OFF; var coolantZHeight; var masterAxis; var movementType; var retracted = false; // specifies that the tool has been retracted to the safe plane var toolChecked = false; // specifies that the tool has been checked with the probe var forceSpindleSpeed = false; var measureTool = false; function formatSequenceNumber() { if (sequenceNumber > 99999) { sequenceNumber = getProperty("sequenceNumberStart"); } var seqno = nFormat.format(sequenceNumber); sequenceNumber += getProperty("sequenceNumberIncrement"); return seqno; } /** Writes the specified block. */ function writeBlock() { if (!formatWords(arguments)) { return; } if (getProperty("showSequenceNumbers") == "true") { writeWords2(formatSequenceNumber(), arguments); sequenceNumber += getProperty("sequenceNumberIncrement"); } else { writeWords(arguments); } } function formatComment(text) { return ("(" + filterText(String(text), permittedCommentChars) + ")"); } /** 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 writeCommentSeqno(text) { writeln(formatSequenceNumber() + formatComment(text)); } function prepareForToolCheck() { writeBlock( mFormat.format(5), mFormat.format(9) ); } function writeToolMeasureBlock(tool, preMeasure) { var comment = measureTool ? formatComment("MEASURE TOOL") : ""; if (!preMeasure) { prepareForToolCheck(); } writeBlock("T" + toolFormat.format(tool.number), mFormat.format(6), comment); writeBlock(gFormat.format(37)); measureTool = false; } /** Compare a text string to acceptable choices. Returns -1 if there is no match. */ function parseChoice() { for (var i = 1; i < arguments.length; ++i) { if (String(arguments[0]).toUpperCase() == String(arguments[i]).toUpperCase()) { return i - 1; } } return -1; } // Start of machine configuration logic var compensateToolLength = false; // add the tool length to the pivot distance for nonTCP rotary heads // internal variables, do not change var receivedMachineConfiguration; var operationSupportsTCP; var multiAxisFeedrate; function activateMachine() { // disable unsupported rotary axes output if (!machineConfiguration.isMachineCoordinate(0) && (typeof aOutput != "undefined")) { aOutput.disable(); } if (!machineConfiguration.isMachineCoordinate(1) && (typeof bOutput != "undefined")) { bOutput.disable(); } if (!machineConfiguration.isMachineCoordinate(2) && (typeof cOutput != "undefined")) { cOutput.disable(); } // setup usage of multiAxisFeatures 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 } // save multi-axis feedrate settings from machine configuration var mode = machineConfiguration.getMultiAxisFeedrateMode(); var type = mode == FEED_INVERSE_TIME ? machineConfiguration.getMultiAxisFeedrateInverseTimeUnits() : (mode == FEED_DPM ? machineConfiguration.getMultiAxisFeedrateDPMType() : DPM_STANDARD); multiAxisFeedrate = { mode : mode, maximum : machineConfiguration.getMultiAxisFeedrateMaximum(), type : type, tolerance: mode == FEED_DPM ? machineConfiguration.getMultiAxisFeedrateOutputTolerance() : 0, bpwRatio : mode == FEED_DPM ? machineConfiguration.getMultiAxisFeedrateBpwRatio() : 1 }; // setup of retract/reconfigure TAG: Only needed until post kernel supports these machine config settings if (receivedMachineConfiguration && machineConfiguration.performRewinds()) { safeRetractDistance = machineConfiguration.getSafeRetractDistance(); safePlungeFeed = machineConfiguration.getSafePlungeFeedrate(); safeRetractFeed = machineConfiguration.getSafeRetractFeedrate(); } if (typeof safeRetractDistance == "number" && getProperty("safeRetractDistance") != undefined && getProperty("safeRetractDistance") != 0) { safeRetractDistance = getProperty("safeRetractDistance"); } if (machineConfiguration.isHeadConfiguration()) { compensateToolLength = typeof compensateToolLength == "undefined" ? false : compensateToolLength; } if (machineConfiguration.isHeadConfiguration() && compensateToolLength) { for (var i = 0; i < getNumberOfSections(); ++i) { var section = getSection(i); if (section.isMultiAxis()) { machineConfiguration.setToolLength(getBodyLength(section.getTool())); // define the tool length for head adjustments section.optimizeMachineAnglesByMachine(machineConfiguration, OPTIMIZE_AXIS); } } } else { optimizeMachineAngles2(OPTIMIZE_AXIS); } } function getBodyLength(tool) { for (var i = 0; i < getNumberOfSections(); ++i) { var section = getSection(i); if (tool.number == section.getTool().number) { return section.getParameter("operation:tool_overallLength", tool.bodyLength + tool.holderLength); } } return tool.bodyLength + tool.holderLength; } function defineMachine() { var useTCP = false; if (getProperty("rotaryTableAxis") != "none") { // Define rotary attributes from properties var rotary = parseChoice(getProperty("rotaryTableAxis"), "-Z", "-Y", "-X", "NONE", "X", "Y", "Z"); if (rotary < 0) { error(localize("Valid rotaryTableAxis values are: None, X, Y, Z, -X, -Y, -Z")); return; } rotary -= 3; // Define Master (carrier) axis masterAxis = Math.abs(rotary) - 1; if (masterAxis >= 0) { var rotaryVector = [0, 0, 0]; rotaryVector[masterAxis] = rotary / Math.abs(rotary); var aAxis = createAxis({coordinate:0, table:true, axis:rotaryVector, cyclic:true, preference:0, tcp:useTCP, reset:3}); machineConfiguration = new MachineConfiguration(aAxis); setMachineConfiguration(machineConfiguration); if (receivedMachineConfiguration) { warning(localize("The provided CAM machine configuration is overwritten by the postprocessor.")); receivedMachineConfiguration = false; // CAM provided machine configuration is overwritten } } } else { if (false) { // note: setup your machine here var aAxis = createAxis({coordinate:0, table:true, axis:[1, 0, 0], range:[-120, 120], preference:1, tcp:useTCP}); var cAxis = createAxis({coordinate:2, table:true, axis:[0, 0, 1], range:[-360, 360], preference:0, tcp:useTCP}); machineConfiguration = new MachineConfiguration(aAxis, cAxis); setMachineConfiguration(machineConfiguration); if (receivedMachineConfiguration) { warning(localize("The provided CAM machine configuration is overwritten by the postprocessor.")); receivedMachineConfiguration = false; // CAM provided machine configuration is overwritten } } } if (!receivedMachineConfiguration) { // multiaxis settings if (machineConfiguration.isHeadConfiguration()) { machineConfiguration.setVirtualTooltip(false); // translate the pivot point to the virtual tool tip for nonTCP rotary heads } // retract / reconfigure var performRewinds = false; // set to true to enable the rewind/reconfigure logic if (performRewinds) { machineConfiguration.enableMachineRewinds(); // enables the retract/reconfigure logic safeRetractDistance = (unit == IN) ? 1 : 25; // additional distance to retract out of stock, can be overridden with a property safeRetractFeed = (unit == IN) ? 20 : 500; // retract feed rate safePlungeFeed = (unit == IN) ? 10 : 250; // plunge feed rate machineConfiguration.setSafeRetractDistance(safeRetractDistance); machineConfiguration.setSafeRetractFeedrate(safeRetractFeed); machineConfiguration.setSafePlungeFeedrate(safePlungeFeed); var stockExpansion = new Vector(toPreciseUnit(0.1, IN), toPreciseUnit(0.1, IN), toPreciseUnit(0.1, IN)); // expand stock XYZ values machineConfiguration.setRewindStockExpansion(stockExpansion); } // multi-axis feedrates if (machineConfiguration.isMultiAxisConfiguration()) { machineConfiguration.setMultiAxisFeedrate( useTCP ? FEED_FPM : getProperty("useDPMFeeds") ? FEED_DPM : FEED_INVERSE_TIME, 99999.9999, // maximum output value for inverse time feed rates getProperty("useDPMFeeds") ? DPM_COMBINATION : INVERSE_MINUTES, // INVERSE_MINUTES/INVERSE_SECONDS or DPM_COMBINATION/DPM_STANDARD 0.5, // tolerance to determine when the DPM feed has changed 1.0 // ratio of rotary accuracy to linear accuracy for DPM calculations ); setMachineConfiguration(machineConfiguration); } /* home positions */ // machineConfiguration.setHomePositionX(toPreciseUnit(0, IN)); // machineConfiguration.setHomePositionY(toPreciseUnit(0, IN)); // machineConfiguration.setRetractPlane(toPreciseUnit(0, IN)); /* maximum spindle speed */ machineConfiguration.setMaximumSpindleSpeed(10000); } } // End of machine configuration logic function onOpen() { // define and enable machine configuration receivedMachineConfiguration = machineConfiguration.isReceived(); if (typeof defineMachine == "function") { defineMachine(); // hardcoded machine configuration } activateMachine(); // enable the machine optimizations and settings if (getProperty("useRadius")) { maximumCircularSweep = toRad(90); // avoid potential center calculation errors for CNC } if (getProperty("sequenceNumberOperation")) { setProperty("showSequenceNumbers", "false"); } if (!getProperty("separateWordsWithSpace")) { setWordSeparator(""); } sequenceNumber = getProperty("sequenceNumberStart"); writeln("%"); if (programName) { writeComment(programName); } if (programComment) { writeComment(programComment); } if (getProperty("writeVersion")) { if (typeof getHeaderVersion == "function" && getHeaderVersion()) { writeComment(localize("post version") + ": " + getHeaderVersion()); } if (typeof getHeaderDate == "function" && getHeaderDate()) { writeComment(localize("post modified") + ": " + getHeaderDate()); } } // 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; } } } } } // measure tools if (getProperty("measureTools")) { var tools = getToolTable(); if (tools.getNumberOfTools() > 0) { writeln(""); writeBlock(mFormat.format(0), formatComment(localize("Read note"))); // wait for operator writeComment(localize("With parameter #" + getProperty("measureToolsParameter") + " set to 0 each tool will cycle through the spindle")); writeComment(localize(" to verify that the correct tool is in the tool magazine and to automatically measure it.")); writeComment(localize("Once the tools are verified set parameter #" + getProperty("measureToolsParameter") + " to 1 with")); writeComment(localize(" an MDI command of '#" + getProperty("measureToolsParameter") + " = 1' to skip verification.")); writeComment(localize("The value of parameter #" + getProperty("measureToolsParameter") + " can be checked with a '(DEBUG, #" + getProperty("measureToolsParameter") + ")' command.")); writeComment(localize("The value will be shown on the Status page.")); writeln("o100 sub"); writeln("o110 if [#" + getProperty("measureToolsParameter") + " LT 1]"); 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); writeToolMeasureBlock(tool, true); } writeln("o110 endif"); writeln("o100 endsub"); writeln(""); writeln("o100 call"); writeln(""); } } 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; } } } // absolute coordinates and feed per min writeBlock(gAbsIncModal.format(90), gFormat.format(54), gFormat.format(64), gFormat.format(50), gPlaneModal.format(17), gFormat.format(40), gFormat.format(80), gFeedModeModal.format(94), gFormat.format(91.1), gFormat.format(49)); switch (unit) { case IN: writeBlock(gUnitModal.format(20), formatComment(localize("Inch"))); break; case MM: writeBlock(gUnitModal.format(21), formatComment(localize("Metric"))); break; } } function onParameter(name, value) { if (name == "display") { writeComment("MSG, " + value); } } 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(); } /** Force output of X, Y, Z, A, B, C, and F on next output. */ function forceAny() { forceXYZ(); forceABC(); previousDPMFeed = 0; feedOutput.reset(); } var currentWorkPlaneABC = undefined; function forceWorkPlane() { currentWorkPlaneABC = undefined; } function defineWorkPlane(_section) { if (machineConfiguration.isMultiAxisConfiguration()) { // use 5-axis indexing for multi-axis mode var abc = _section.isMultiAxis() ? _section.getInitialToolAxisABC() : getWorkPlaneMachineABC(_section.workPlane); if (_section.isMultiAxis()) { forceWorkPlane(); cancelTransformation(); positionABC(abc, true); } else { setWorkPlane(abc); } } else { // pure 3D var remaining = _section.workPlane; if (!isSameDirection(remaining.forward, new Vector(0, 0, 1))) { error(localize("Tool orientation is not supported.")); return; } setRotation(remaining); } if (_section && (currentSection.getId() == _section.getId())) { operationSupportsTCP = _section.getOptimizedTCPMode() == OPTIMIZE_NONE; if (!_section.isMultiAxis() && (useMultiAxisFeatures || isSameDirection(machineConfiguration.getSpindleAxis(), _section.workPlane.forward))) { operationSupportsTCP = false; } } } 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); } } onCommand(COMMAND_UNLOCK_MULTI_AXIS); gMotionModal.reset(); writeBlock(gMotionModal.format(0), a, b, c); setCurrentABC(abc); // required for machine simulation } } function setWorkPlane(abc) { if (!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 } positionABC(abc, true); onCommand(COMMAND_LOCK_MULTI_AXIS); currentWorkPlaneABC = abc; } 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 direction = machineConfiguration.getDirection(abc); if (!isSameDirection(direction, W.forward)) { error(localize("Orientation not supported.")); return new Vector(); } var tcp = false; if (tcp) { setRotation(W); // TCP mode } else { var O = machineConfiguration.getOrientation(abc); var R = machineConfiguration.getRemainingOrientation(abc, W); setRotation(R); } return abc; } var UNWIND_CLOSEST = 1; // rotate axes to closest 0 (eg G28) var UNWIND_CURRENT = 2; // set rotary axes origin to current position (eg G92) // var unwindSettings = {method:UNWIND_CLOSEST, codes:[gFormat.format(28), gAbsIncModal.format(91)], workOffset:undefined, outputAngles:true, resetG90:true}; // Haas var unwindSettings = {method:UNWIND_CURRENT, codes:[gFormat.format(92)], workOffset:undefined, outputAngles:true, resetG90:false}; // Fanuc var UNWIND_ZERO = 1; // rotate axes to closest 0 (eg G28) var UNWIND_STAY = 2; // set rotary axes origin to current position (eg G92) var unwindSettings = { method : UNWIND_STAY, // UNWIND_ZERO (move to closest 0 (G28)) or UNWIND_STAY (table does not move (G92)) codes : [gFormat.format(92)], // formatted code(s) that will (virtually) unwind axis (G90 G28), (G92), etc. workOffsetCode: "", // prefix for workoffset number if it is required to be output useAngle : "true", // 'true' outputs angle with standard output variable, 'prefix' uses 'anglePrefix', 'false' does not output angle anglePrefix : [], // optional prefixes for output angles specified as ["", "", "C"], use blank string if axis does not unwind resetG90 : false // set to 'true' if G90 needs to be output after the unwind block }; function unwindABC(abc) { if (typeof unwindSettings == "undefined") { return; } if (unwindSettings.method != UNWIND_ZERO && unwindSettings.method != UNWIND_STAY) { error(localize("Unsupported unwindABC method.")); return; } var axes = new Array(machineConfiguration.getAxisU(), machineConfiguration.getAxisV(), machineConfiguration.getAxisW()); var currentDirection = getCurrentDirection(); for (var i in axes) { if (axes[i].isEnabled() && (unwindSettings.useAngle != "prefix" || unwindSettings.anglePrefix[axes[i].getCoordinate] != "")) { var j = axes[i].getCoordinate(); // only use the active axis in calculations var tempABC = new Vector(0, 0, 0); tempABC.setCoordinate(j, abc.getCoordinate(j)); var tempCurrent = new Vector(0, 0, 0); // only use the active axis in calculations tempCurrent.setCoordinate(j, currentDirection.getCoordinate(j)); var orientation = machineConfiguration.getOrientation(tempCurrent); // get closest angle without respecting 'reset' flag // and distance from previous angle to closest abc var nearestABC = machineConfiguration.getABCByPreference(orientation, tempABC, ABC, PREFER_PREFERENCE, ENABLE_WCS); var distanceABC = abcFormat.getResultingValue(Math.abs(Vector.diff(getCurrentDirection(), abc).getCoordinate(j))); // calculate distance from calculated abc to closest abc // include move to origin for G28 moves var distanceOrigin = 0; if (unwindSettings.method == UNWIND_STAY) { distanceOrigin = abcFormat.getResultingValue(Math.abs(Vector.diff(nearestABC, abc).getCoordinate(j))); } else { // closest angle distanceOrigin = abcFormat.getResultingValue(Math.abs(getCurrentDirection().getCoordinate(j))) % 360; // calculate distance for unwinding axis distanceOrigin = (distanceOrigin > 180) ? 360 - distanceOrigin : distanceOrigin; // take shortest route to 0 distanceOrigin += abcFormat.getResultingValue(Math.abs(abc.getCoordinate(j))); // add distance from 0 to new position } // determine if the axis needs to be rewound and rewind it if required var revolutions = distanceABC / 360; var angle = unwindSettings.method == UNWIND_STAY ? nearestABC.getCoordinate(j) : 0; if (distanceABC > distanceOrigin && (unwindSettings.method == UNWIND_STAY || (revolutions > 1))) { // G28 method will move rotary, so make sure move is greater than 360 degrees if (!retracted) { if (typeof moveToSafeRetractPosition == "function") { moveToSafeRetractPosition(); } else { writeRetract(Z); } } onCommand(COMMAND_UNLOCK_MULTI_AXIS); var outputs = [aOutput, bOutput, cOutput]; outputs[j].reset(); writeBlock( unwindSettings.codes, unwindSettings.workOffsetCode ? unwindSettings.workOffsetCode + currentWorkOffset : "", unwindSettings.useAngle == "true" ? outputs[j].format(angle) : (unwindSettings.useAngle == "prefix" ? unwindSettings.anglePrefix[j] + abcFormat.format(angle) : "") ); if (unwindSettings.resetG90) { gAbsIncModal.reset(); writeBlock(gAbsIncModal.format(90)); } outputs[j].reset(); // set the current rotary axis angle from the unwind block currentDirection.setCoordinate(j, angle); setCurrentDirection(currentDirection); } } } } function onSection() { var insertToolCall = isFirstSection() || currentSection.getForceToolChange && currentSection.getForceToolChange() || (tool.number != getPreviousSection().getTool().number); retracted = false; // specifies that the tool has been retracted to the safe plane var newWorkOffset = isFirstSection() || (getPreviousSection().workOffset != currentSection.workOffset); // 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()); // force newWorkPlane between indexing and simultaneous operations if (insertToolCall || newWorkOffset || newWorkPlane || toolChecked) { writeRetract(Z); forceWorkPlane(); } // Process Manual NC commands executeManualNC(); writeln(""); if (hasParameter("operation-comment")) { var comment = getParameter("operation-comment"); if (comment) { if (getProperty("sequenceNumberOperation")) { writeCommentSeqno(comment); } else { writeComment(comment); } } } // optional stop if (!isFirstSection() && ((insertToolCall && getProperty("optionalStop")) || getProperty("optionalStopOperation"))) { onCommand(COMMAND_OPTIONAL_STOP); } if (insertToolCall) { forceWorkPlane(); // onCommand(COMMAND_COOLANT_OFF); if (tool.number > getProperty("maxTool")) { warning(localize("Tool number exceeds maximum value.")); } if (isProbeOperation()) { if (tool.number != 99 && !getProperty("allowAllProbeTools")) { error(subst(localize("The tool number for a probe must be 99 but is defined as %1."), tool.number)); return; } if (tool.lengthOffset != 99 && !getProperty("allowAllProbeTools")) { error(subst(localize("The tool length offset for a probe must be 99 but is defined as %1."), tool.lengthOffset)); return; } } var lengthOffset = tool.lengthOffset; if (lengthOffset > getProperty("maxTool")) { error(localize("Length offset out of range.")); return; } if (getProperty("useM06")) { writeToolBlock("T" + toolFormat.format(tool.number), gFormat.format(43), hFormat.format(lengthOffset), mFormat.format(6)); } else { writeToolBlock("T" + toolFormat.format(tool.number), gFormat.format(43), hFormat.format(lengthOffset)); } if (tool.comment) { writeComment(tool.comment); } if (measureTool) { writeToolMeasureBlock(tool, 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()); } writeComment(localize("ZMIN") + "=" + zRange.getMinimum()); } } } // Define coolant code var topOfPart = undefined; if (hasParameter("operation:surfaceZHigh")) { topOfPart = getParameter("operation:surfaceZHigh"); // TAG: not safe } var c = setCoolant(tool.coolant, topOfPart); if (toolChecked) { forceSpindleSpeed = true; // spindle must be restarted if tool is checked without a tool change toolChecked = false; // state of tool is not known at the beginning of a section since it could be broken for the previous section } var spindleChanged = tool.type != TOOL_PROBE && (true || insertToolCall || forceSpindleSpeed || isFirstSection() || (rpmFormat.areDifferent(spindleSpeed, sOutput.getCurrent())) || (tool.clockwise != getPreviousSection().getTool().clockwise)); if (spindleChanged) { forceSpindleSpeed = false; if (spindleSpeed < 0) { error(localize("Spindle speed out of range.")); return; } if (spindleSpeed > machineConfiguration.getMaximumSpindleSpeed()) { warning(localize("Spindle speed exceeds maximum value.")); } if (spindleSpeed == 0) { writeBlock(mFormat.format(5), c[0], c[1], c[2], c[3], formatComment("SPINDLE IS OFF")); } else { writeBlock( sOutput.format(spindleSpeed), mFormat.format(tool.clockwise ? 3 : 4), c[0], c[1], c[2], c[3] ); if ((spindleSpeed > 5000) && getProperty("waitForSpindle")) { onDwell(getProperty("waitForSpindle")); } } } // wcs if (insertToolCall && getProperty("forceWorkOffset")) { // force work offset when changing tool currentWorkOffset = undefined; } if (currentSection.workOffset != currentWorkOffset) { writeBlock(currentSection.wcs); currentWorkOffset = currentSection.workOffset; } forceXYZ(); var abc = defineWorkPlane(currentSection, true); forceXYZ(); 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 && retracted) { // G43 already called above on tool change var lengthOffset = tool.lengthOffset; if (lengthOffset > getProperty("maxTool")) { error(localize("Length offset out of range.")); return; } gMotionModal.reset(); 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), gFormat.format(43), zOutput.format(initialPosition.z), hFormat.format(lengthOffset)); } else { writeBlock( gAbsIncModal.format(90), gMotionModal.format(0), gFormat.format(43), xOutput.format(initialPosition.x), yOutput.format(initialPosition.y), zOutput.format(initialPosition.z), hFormat.format(lengthOffset) ); } } else { writeBlock( gAbsIncModal.format(90), gMotionModal.format(0), xOutput.format(initialPosition.x), yOutput.format(initialPosition.y) ); } } // allow manual insertion of comma delimited g-code function onPassThrough(text) { var commands = String(text).split(","); for (text in commands) { writeBlock(commands[text]); } } function onDwell(seconds) { if (seconds > 99999.999) { warning(localize("Dwelling time is out of range.")); } if (getProperty("dwellInSeconds")) { writeBlock(gFormat.format(4), "P" + secFormat.format(seconds)); } else { milliseconds = clamp(1, seconds * 1000, 99999999); writeBlock(gFormat.format(4), "P" + milliFormat.format(milliseconds)); } } function onSpindleSpeed(spindleSpeed) { writeBlock(sOutput.format(spindleSpeed)); } function setCoolant(coolant, topOfPart) { var coolCodes = ["", "", "", ""]; coolantZHeight = 9999.0; var coolantCode = 9; if (!getProperty("outputCoolants")) { return coolCodes; } // Smart coolant is not enabled if (!getProperty("smartCoolEquipped")) { if (coolant == COOLANT_OFF) { coolantCode = 9; } else if (coolant == COOLANT_MIST) { coolantCode = 7; } else { coolantCode = 8; // default all coolant modes to flood if (coolant != COOLANT_FLOOD) { warning(localize("Unsupported coolant setting. Defaulting to FLOOD.")); } } coolCodes[0] = mFormat.format(coolantCode); } else { // Smart coolant is enabled if ((coolant == COOLANT_MIST) || (coolant == COOLANT_AIR)) { coolantCode = 7; coolCodes[0] = mFormat.format(coolantCode); } else if (coolant == COOLANT_FLOOD_MIST) { // flood with air blast coolantCode = 8; coolCodes[0] = mFormat.format(coolantCode); if (getProperty("multiCoolEquipped")) { if (getProperty("multiCoolAirBlastSeconds") != 0) { coolCodes[3] = qFormat.format(getProperty("multiCoolAirBlastSeconds")); } } else { warning(localize("COOLANT_FLOOD_MIST programmed without Multi-Coolant support. Defaulting to FLOOD.")); } } else if (coolant == COOLANT_OFF) { coolantCode = 9; coolCodes[0] = mFormat.format(coolantCode); } else { coolantCode = 8; coolCodes[0] = mFormat.format(coolantCode); if (coolant != COOLANT_FLOOD) { warning(localize("Unsupported coolant setting. Defaulting to FLOOD.")); } } // Determine Smart Coolant location based on machining operation if (hasParameter("operation-strategy")) { var strategy = getParameter("operation-strategy"); if (strategy) { // Drilling strategy. Keep coolant at top of part if (strategy == "drill") { if (topOfPart != undefined) { coolantZHeight = topOfPart; coolCodes[1] = "E" + xyzFormat.format(coolantZHeight); } // Tool end point milling. Keep coolant at end of tool } else if ((strategy == "face") || (strategy == "engrave") || (strategy == "contour_new") || (strategy == "horizontal_new") || (strategy == "parallel_new") || (strategy == "scallop_new") || (strategy == "pencil_new") || (strategy == "radial_new") || (strategy == "spiral_new") || (strategy == "morphed_spiral") || (strategy == "ramp") || (strategy == "project")) { coolCodes[1] = "P" + coolantOptionFormat.format(0); // Side Milling. Sweep the coolant along the length of the tool } else { coolCodes[1] = "P" + coolantOptionFormat.format(0); coolCodes[2] = "R" + xyzFormat.format(tool.fluteLength * (getProperty("smartCoolToolSweepPercentage") / 100.0)); } } } } currentCoolantMode = coolant; return coolCodes; } function onCycle() { writeBlock(gPlaneModal.format(17)); } function getCommonCycle(x, y, z, r) { forceXYZ(); return [xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + xyzFormat.format(r)]; } function expandTappingPoint(x, y, z) { onExpandedRapid(x, y, cycle.clearance); onExpandedLinear(x, y, z, cycle.feedrate); onExpandedLinear(x, y, cycle.clearance, cycle.feedrate * getProperty("reversingHeadFeed")); } /** Convert approach to sign. */ function approach(value) { validate((value == "positive") || (value == "negative"), "Invalid approach."); return (value == "positive") ? 1 : -1; } var PROBE_RAPID = 0; var PROBE_FEED = 1; function protectedProbeMove(x, y, z, feedType) { writeBlock(gMotionModal.format(1), xOutput.format(x), yOutput.format(y), zOutput.format(z), feedType == PROBE_RAPID ? "F#<_rapid_ruff>" : "F#<_feed_ruff>"); } function onCyclePoint(x, y, z) { if (isInspectionOperation()) { if (typeof inspectionCycleInspect == "function") { inspectionCycleInspect(cycle, x, y, z); return; } else { cycleNotSupported(); } } else if (isProbeOperation()) { writeProbeCycle(cycle, x, y, z); } else { writeDrillCycle(cycle, x, y, z); } } function writeDrillCycle(cycle, x, y, z) { if (!isSameDirection(getRotation().forward, new Vector(0, 0, 1))) { expandCyclePoint(x, y, z); return; } var forceCycle = false; if ((isTappingCycle() && getProperty("useRigidTapping") == "yes") || cycleType == "tapping-with-chip-breaking") { forceCycle = true; if (!isFirstCyclePoint()) { if (getProperty("useRigidTapping") != "yes") { writeBlock(gCycleModal.format(80)); } gMotionModal.reset(); gCycleModal.reset(); } } var useTappingSpeed = false; if (isTappingCycle() && getProperty("useRigidTapping") == "yes" && getProperty("tappingSpeed") != 1) { if ((spindleSpeed * getProperty("tappingSpeed")) > maxTappingRetractSpeed) { warning(subst(localize("Tapping retract spindle speed is greater than %1."), maxTappingRetractSpeed)); } useTappingSpeed = true; } if (forceCycle || isFirstCyclePoint()) { repositionToCycleClearance(cycle, x, y, z); // return to initial Z which is clearance plane and set absolute mode var F = cycle.feedrate; var P = !cycle.dwell ? 0 : cycle.dwell; // in seconds // Adjust SmartCool to top of part if it changes if (getProperty("smartCoolEquipped") && xyzFormat.areDifferent((z + cycle.depth), coolantZHeight)) { var c = setCoolant(currentCoolantMode, z + cycle.depth); if (c) { writeBlock(c[0], c[1], c[2], c[3]); } } 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" + secFormat.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 ((P > 0) || (cycle.accumulatedDepth < cycle.depth)) { expandCyclePoint(x, y, z); } else { writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(73), getCommonCycle(x, y, z, cycle.retract), "Q" + xyzFormat.format(cycle.incrementalDepth), feedOutput.format(F) ); } break; case "deep-drilling": writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(83), getCommonCycle(x, y, z, cycle.retract), "Q" + xyzFormat.format(cycle.incrementalDepth), // conditional(P > 0, "P" + secFormat.format(P)), feedOutput.format(F) ); break; case "tapping": case "left-tapping": case "right-tapping": if (getProperty("useRigidTapping") == "reversing") { expandTappingPoint(x, y, z); } else if (getProperty("useRigidTapping") == "yes") { writeBlock( gAbsIncModal.format(90), gCycleModal.format(33.1), xOutput.format(x), yOutput.format(y), zOutput.format(z), conditional(useTappingSpeed, "I" + xyzFormat.format(getProperty("tappingSpeed"))), pitchOutput.format(tool.threadPitch) ); } else { if (!F) { F = tool.getTappingFeedrate(); } writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND) ? 74 : 84), getCommonCycle(x, y, z, cycle.retract), "P" + secFormat.format(P), // dwell is required conditional(useTappingSpeed, "I" + xyzFormat.format(getProperty("tappingSpeed"))), feedOutput.format(F) ); } break; case "tapping-with-chip-breaking": if (getProperty("useRigidTapping") == "reversing") { error(subst(localize("Tapping with chip breaking is not supported when property '%1' is set to 'Self-reversing head'."), properties.useRigidTapping.title)); return; } if (!F) { F = tool.getTappingFeedrate(); } var u = cycle.stock; var step = cycle.incrementalDepth; var first = true; while (u > cycle.bottom) { if (step < cycle.minimumIncrementalDepth) { step = cycle.minimumIncrementalDepth; } u -= step; step -= cycle.incrementalDepthReduction; gCycleModal.reset(); // required if ((u - 0.001) <= cycle.bottom) { u = cycle.bottom; } if (first) { first = false; if (getProperty("useRigidTapping") == "yes") { writeBlock( gAbsIncModal.format(90), gCycleModal.format(33.1), xOutput.format((gPlaneModal.getCurrent() == 19) ? u : x), yOutput.format((gPlaneModal.getCurrent() == 18) ? u : y), zOutput.format((gPlaneModal.getCurrent() == 17) ? u : z), conditional(useTappingSpeed, "I" + xyzFormat.format(getProperty("tappingSpeed"))), pitchOutput.format(tool.threadPitch) ); } else { writeBlock( gRetractModal.format(99), gAbsIncModal.format(90), gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND) ? 74 : 84), getCommonCycle((gPlaneModal.getCurrent() == 19) ? u : x, (gPlaneModal.getCurrent() == 18) ? u : y, (gPlaneModal.getCurrent() == 17) ? u : z, cycle.retract, cycle.clearance), "P" + secFormat.format(P), // dwell is required conditional(useTappingSpeed, "I" + xyzFormat.format(getProperty("tappingSpeed"))), feedOutput.format(F) ); } } else { var position; var depth; switch (gPlaneModal.getCurrent()) { case 17: xOutput.reset(); position = xOutput.format(x); depth = zOutput.format(u); break; case 18: zOutput.reset(); position = zOutput.format(z); depth = yOutput.format(u); break; case 19: yOutput.reset(); position = yOutput.format(y); depth = xOutput.format(u); break; } if (getProperty("useRigidTapping") != "yes") { writeBlock(conditional((u <= cycle.bottom), gRetractModal.format(98)), position, depth); } else { writeBlock( gAbsIncModal.format(90), gCycleModal.format(33.1), depth, conditional(useTappingSpeed, "I" + xyzFormat.format(getProperty("tappingSpeed"))), pitchOutput.format(tool.threadPitch) ); } } } feedOutput.reset(); break; case "fine-boring": error(localize("The fine-boring canned cycle is not supported.")); break; case "back-boring": error(localize("The back-boring canned cycle is not supported.")); 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" + secFormat.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": writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(86), getCommonCycle(x, y, z, cycle.retract), "P" + secFormat.format(P), feedOutput.format(F) ); forceSpindleSpeed = true; break; case "manual-boring": writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(88), getCommonCycle(x, y, z, cycle.retract), "P" + secFormat.format(P), 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" + secFormat.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; default: expandCyclePoint(x, y, z); } } else { if (cycleExpanded) { expandCyclePoint(x, y, z); } else if (((cycleType == "tapping") || (cycleType == "right-tapping") || (cycleType == "left-tapping")) && getProperty("useRigidTapping") == "reversingHead") { expandTappingPoint(x, y, z); } else { writeBlock(xOutput.format(x), yOutput.format(y)); } } } function writeProbeCycle(cycle, x, y, z) { if (isProbeOperation()) { var probeRadius = tool.diameter / 2; switch (cycleType) { case "probing-x": protectedProbeMove(x, y, cycle.retract, PROBE_RAPID); protectedProbeMove(x, y, z - cycle.depth, PROBE_FEED); var probeExpected = x + approach(cycle.approach1) * (cycle.probeClearance + probeRadius); writeProbePosition(probeExpected + approach(cycle.approach1) * (cycle.probeOvertravel + probeRadius)); writeProbeExpectedX(probeExpected, true); writeBlock("ocall", formatComment("Probe in X")); break; case "probing-y": protectedProbeMove(x, y, cycle.retract, PROBE_RAPID); protectedProbeMove(x, y, z - cycle.depth, PROBE_FEED); var probeExpected = y + approach(cycle.approach1) * (cycle.probeClearance + probeRadius); writeProbePosition(probeExpected + approach(cycle.approach1) * (cycle.probeOvertravel + probeRadius)); writeProbeExpectedY(probeExpected, true); writeBlock("o call", formatComment("Probe in Y")); break; case "probing-z": protectedProbeMove(x, y, cycle.retract, PROBE_RAPID); var probePosition = z - cycle.depth; writeProbePosition(probePosition - cycle.probeOvertravel); writeProbeExpectedZ(probePosition, true); writeBlock("o call", formatComment("Probe in Z")); break; case "probing-x-wall": var probeWidth = cycle.width1 / 2; var p1 = x + probeWidth + (cycle.probeClearance + probeRadius); var p2 = x - probeWidth - (cycle.probeClearance + probeRadius); onExpandedRapid(p1, y, cycle.clearance); protectedProbeMove(p1, y, cycle.retract, PROBE_RAPID); protectedProbeMove(p1, y, z - cycle.depth, PROBE_FEED); writeProbeClearance(cycle.retract); writeProbePosition(x + probeWidth - (cycle.probeOvertravel - probeRadius), x - probeWidth + (cycle.probeOvertravel - probeRadius)); writeProbeXYZPosition(p2, y, z - cycle.depth); writeProbeExpectedX(x, true); writeBlock("o call", formatComment("Probe X-Boss")); break; case "probing-y-wall": var probeWidth = cycle.width1 / 2; var p1 = y + probeWidth + (cycle.probeClearance + probeRadius); var p2 = y - probeWidth - (cycle.probeClearance + probeRadius); onExpandedRapid(x, p1, cycle.clearance); protectedProbeMove(x, p1, cycle.retract, PROBE_RAPID); protectedProbeMove(x, p1, z - cycle.depth, PROBE_FEED); writeProbeClearance(cycle.retract); writeProbePosition(y + probeWidth - (cycle.probeOvertravel - probeRadius), y - probeWidth + (cycle.probeOvertravel - probeRadius)); writeProbeXYZPosition(x, p2, z - cycle.depth); writeProbeExpectedY(y, true); writeBlock("o call", formatComment("Probe Y-Boss")); break; case "probing-x-channel": var probeWidth = cycle.width1 / 2; var p1 = x + probeWidth - (cycle.probeClearance + probeRadius); var p2 = x - probeWidth + (cycle.probeClearance + probeRadius); onExpandedRapid(p1, y, cycle.clearance); protectedProbeMove(p1, y, cycle.retract, PROBE_RAPID); protectedProbeMove(p1, y, z - cycle.depth, PROBE_FEED); writeProbeClearance(0); // no island writeProbePosition(x + probeWidth + (cycle.probeOvertravel - probeRadius), x - probeWidth - (cycle.probeOvertravel - probeRadius)); writeProbeXYZPosition(p2, y, z - cycle.depth); writeProbeExpectedX(x, true); writeBlock("o call", formatComment("Probe X-Pocket")); break; case "probing-x-channel-with-island": var probeWidth = cycle.width1 / 2; var p1 = x + probeWidth - (cycle.probeClearance + probeRadius); var p2 = x - probeWidth + (cycle.probeClearance + probeRadius); onExpandedRapid(p1, y, cycle.clearance); protectedProbeMove(p1, y, cycle.retract, PROBE_RAPID); protectedProbeMove(p1, y, z - cycle.depth, PROBE_FEED); writeProbeClearance(cycle.retract); writeProbePosition(x + probeWidth + (cycle.probeOvertravel - probeRadius), x - probeWidth - (cycle.probeOvertravel - probeRadius)); writeProbeXYZPosition(p2, y, z - cycle.depth); writeProbeExpectedX(x, true); writeBlock("o call", formatComment("Probe X-Pocket")); break; case "probing-y-channel": var probeWidth = cycle.width1 / 2; var p1 = y + probeWidth - (cycle.probeClearance + probeRadius); var p2 = y - probeWidth + (cycle.probeClearance + probeRadius); onExpandedRapid(x, p1, cycle.clearance); protectedProbeMove(x, p1, cycle.retract, PROBE_RAPID); protectedProbeMove(x, p1, z - cycle.depth, PROBE_FEED); writeProbeClearance(0); writeProbePosition(y + probeWidth + (cycle.probeOvertravel - probeRadius), y - probeWidth - (cycle.probeOvertravel - probeRadius)); writeProbeXYZPosition(x, p2, z - cycle.depth); writeProbeExpectedY(y, true); writeBlock("o call", formatComment("Probe Y-Pocket")); break; case "probing-y-channel-with-island": var probeWidth = cycle.width1 / 2; var p1 = y + probeWidth - (cycle.probeClearance + probeRadius); var p2 = y - probeWidth + (cycle.probeClearance + probeRadius); onExpandedRapid(x, p1, cycle.clearance); protectedProbeMove(x, p1, cycle.retract, PROBE_RAPID); protectedProbeMove(x, p1, z - cycle.depth, PROBE_FEED); writeProbeClearance(cycle.retract); writeProbePosition(y + probeWidth + (cycle.probeOvertravel - probeRadius), y - probeWidth - (cycle.probeOvertravel - probeRadius)); writeProbeXYZPosition(x, p2, z - cycle.depth); writeProbeExpectedY(y, true); writeBlock("o call", formatComment("Probe Y-Pocket")); break; case "probing-xy-circular-boss": protectedProbeMove(x, y, cycle.retract, PROBE_RAPID); writeProbePosition(z - cycle.depth); writeProbeClearance(cycle.retract); writeProbeDiameter(cycle.width1 - (cycle.probeOvertravel - probeRadius), cycle.width1 + (cycle.probeClearance + probeRadius)); writeProbeExpectedX(x, false); writeProbeExpectedY(y, true); writeBlock("o call", formatComment("Probe Circular Boss")); break; case "probing-xy-circular-partial-boss": protectedProbeMove(x, y, cycle.retract, PROBE_RAPID); writeProbePosition(z - cycle.depth); writeProbeClearance(cycle.retract); writeProbeDiameter(cycle.width1 - (cycle.probeOvertravel - probeRadius), cycle.width1 + (cycle.probeClearance + probeRadius)); writeProbeVector(cycle.partialCircleAngleA, cycle.partialCircleAngleB, cycle.partialCircleAngleC); writeProbeExpectedX(x, false); writeProbeExpectedY(y, true); writeBlock("o call", formatComment("Probe Partial Circular Boss")); break; case "probing-xy-circular-hole": protectedProbeMove(x, y, cycle.retract, PROBE_RAPID); protectedProbeMove(x, y, z - cycle.depth, PROBE_FEED); writeProbeClearance(0); // no island writeProbeDiameter(cycle.width1 + (cycle.probeOvertravel - probeRadius), cycle.width1 - (cycle.probeClearance + probeRadius)); writeProbeExpectedX(x, false); writeProbeExpectedY(y, true); writeBlock("o call", formatComment("Probe Circular Bore")); break; case "probing-xy-circular-partial-hole": protectedProbeMove(x, y, cycle.retract, PROBE_RAPID); protectedProbeMove(x, y, z - cycle.depth, PROBE_FEED); writeProbeDiameter(cycle.width1 + (cycle.probeOvertravel - probeRadius), cycle.width1 - (cycle.probeClearance + probeRadius)); writeProbeVector(cycle.partialCircleAngleA, cycle.partialCircleAngleB, cycle.partialCircleAngleC); writeProbeExpectedX(x, false); writeProbeExpectedY(y, true); writeBlock("o call", formatComment("Probe Partial Circular Bore")); break; case "probing-xy-circular-hole-with-island": protectedProbeMove(x, y, cycle.retract, PROBE_RAPID); protectedProbeMove(x, y, z - cycle.depth, PROBE_FEED); writeProbeClearance(cycle.retract); writeProbeDiameter(cycle.width1 + (cycle.probeOvertravel - probeRadius), cycle.width1 - (cycle.probeClearance + probeRadius)); writeProbeExpectedX(x, false); writeProbeExpectedY(y, true); writeBlock("o call", formatComment("Probe Circular Bore")); break; case "probing-xy-rectangular-hole": var probeWidth = cycle.width1 / 2; var p1 = x + probeWidth - (cycle.probeClearance + probeRadius); var p2 = x - probeWidth + (cycle.probeClearance + probeRadius); onExpandedRapid(p1, y, cycle.clearance); protectedProbeMove(p1, y, cycle.retract, PROBE_RAPID); protectedProbeMove(p1, y, z - cycle.depth, PROBE_FEED); writeProbeClearance(0); // no island writeProbePosition(x + probeWidth + (cycle.probeOvertravel - probeRadius), x - probeWidth - (cycle.probeOvertravel - probeRadius)); writeProbeXYZPosition(p2, y, z - cycle.depth); writeProbeExpectedX(x, true); writeBlock("o call", formatComment("Probe X-Pocket")); probeWidth = cycle.width2 / 2; p1 = y + probeWidth - (cycle.probeClearance + probeRadius); p2 = y - probeWidth + (cycle.probeClearance + probeRadius); protectedProbeMove(x, p1, cycle.retract, PROBE_RAPID); protectedProbeMove(x, p1, z - cycle.depth, PROBE_FEED); writeProbeClearance(0); // no island writeProbePosition(y + probeWidth + (cycle.probeOvertravel - probeRadius), y - probeWidth - (cycle.probeOvertravel - probeRadius)); writeProbeXYZPosition(x, p2, z - cycle.depth); writeProbeExpectedY(y, true); writeBlock("o call", formatComment("Probe Y-Pocket")); break; case "probing-xy-rectangular-boss": var probeWidth = cycle.width1 / 2; var p1 = x + probeWidth + (cycle.probeClearance + probeRadius); var p2 = x - probeWidth - (cycle.probeClearance + probeRadius); onExpandedRapid(p1, y, cycle.clearance); protectedProbeMove(p1, y, cycle.retract, PROBE_RAPID); protectedProbeMove(p1, y, z - cycle.depth, PROBE_FEED); writeProbeClearance(cycle.retract); writeProbePosition(x + probeWidth - (cycle.probeOvertravel - probeRadius), x - probeWidth + (cycle.probeOvertravel - probeRadius)); writeProbeXYZPosition(p2, y, z - cycle.depth); writeProbeExpectedX(x, true); writeBlock("o call", formatComment("Probe X-Boss")); probeWidth = cycle.width2 / 2; p1 = y + probeWidth + (cycle.probeClearance + probeRadius); p2 = y - probeWidth - (cycle.probeClearance + probeRadius); onExpandedRapid(x, p1, cycle.clearance); protectedProbeMove(x, p1, cycle.retract, PROBE_RAPID); protectedProbeMove(x, p1, z - cycle.depth, PROBE_FEED); writeProbeClearance(cycle.retract); writeProbePosition(y + probeWidth - (cycle.probeOvertravel - probeRadius), y - probeWidth + (cycle.probeOvertravel - probeRadius)); writeProbeXYZPosition(x, p2, z - cycle.depth); writeProbeExpectedY(y, true); writeBlock("o call", formatComment("Probe Y-Boss")); break; case "probing-xy-rectangular-hole-with-island": var probeWidth = cycle.width1 / 2; var p1 = x + probeWidth - (cycle.probeClearance + probeRadius); var p2 = x - probeWidth + (cycle.probeClearance + probeRadius); onExpandedRapid(p1, y, cycle.clearance); protectedProbeMove(p1, y, cycle.retract, PROBE_RAPID); protectedProbeMove(p1, y, z - cycle.depth, PROBE_FEED); writeProbeClearance(cycle.retract); writeProbePosition(x + probeWidth + (cycle.probeOvertravel - probeRadius), x - probeWidth - (cycle.probeOvertravel - probeRadius)); writeProbeXYZPosition(p2, y, z - cycle.depth); writeProbeExpectedX(x, true); writeBlock("o call", formatComment("Probe X-Pocket")); probeWidth = cycle.width2 / 2; p1 = y + probeWidth - (cycle.probeClearance + probeRadius); p2 = y - probeWidth + (cycle.probeClearance + probeRadius); protectedProbeMove(x, p1, cycle.retract, PROBE_RAPID); protectedProbeMove(x, p1, z - cycle.depth, PROBE_FEED); writeProbeClearance(cycle.retract); writeProbePosition(y + probeWidth + (cycle.probeOvertravel - probeRadius), y - probeWidth - (cycle.probeOvertravel - probeRadius)); writeProbeXYZPosition(x, p2, z - cycle.depth); writeProbeExpectedY(y, true); writeBlock("o call", formatComment("Probe Y-Pocket")); break; case "probing-xy-inner-corner": var probeExpectedX = x + approach(cycle.approach1) * (cycle.probeClearance + probeRadius * 2); var probeExpectedY = y + approach(cycle.approach2) * (cycle.probeClearance + probeRadius * 2); var probeX = x + approach(cycle.approach1) * (cycle.probeClearance + cycle.probeOvertravel + probeRadius * 2); var probeY = y + approach(cycle.approach2) * (cycle.probeClearance + cycle.probeOvertravel + probeRadius * 2); protectedProbeMove(x, y, cycle.retract, PROBE_RAPID); protectedProbeMove(x, y, z - cycle.depth, PROBE_FEED); writeProbeClearance(cycle.retract); writeProbePosition(probeX, probeY); writeProbeXYZPosition(x, y, z - cycle.depth); writeProbeExpectedX(probeExpectedX, false); writeProbeExpectedY(probeExpectedY, true); writeBlock("o call", formatComment("Probe XY Inner Corner")); break; case "probing-xy-outer-corner": var probeExpectedX = x + approach(cycle.approach1) * (cycle.probeClearance + probeRadius); var probeExpectedY = y + approach(cycle.approach2) * (cycle.probeClearance + probeRadius); // TAG: contact point is not provided by CAM system var px = x + approach(cycle.approach1) * ((cycle.probeOvertravel * 1.5) + cycle.probeOvertravel + probeRadius * 2); var py = y + approach(cycle.approach2) * ((cycle.probeOvertravel * 1.5) + cycle.probeOvertravel + probeRadius * 2); var probeX = x + approach(cycle.approach1) * (cycle.probeClearance + cycle.probeOvertravel + probeRadius * 2); var probeY = y + approach(cycle.approach2) * (cycle.probeClearance + cycle.probeOvertravel + probeRadius * 2); onExpandedRapid(x, py, cycle.clearance); protectedProbeMove(x, py, cycle.retract, PROBE_RAPID); protectedProbeMove(x, py, z - cycle.depth, PROBE_FEED); writeProbeClearance(cycle.retract); writeProbePosition(probeX, probeY); writeProbeXYZPosition(px, y, z - cycle.depth); writeProbeExpectedX(probeExpectedX, false); writeProbeExpectedY(probeExpectedY, true); writeBlock("o call", formatComment("Probe XY Outer Corner")); break; case "probing-x-plane-angle": error(localize("Probing cycle '" + cycleType + "' is not supported.")); break; case "probing-y-plane-angle": error(localize("Probing cycle '" + cycleType + "' is not supported.")); break; default: expandCyclePoint(x, y, z); } } } function writeProbePosition(position1, position2) { // position2 is optional writeBlock("#<_first_position_to_probe> = " + xyzFormat.format(position1)); if (typeof position2 == "number") { writeBlock("#<_second_position_to_probe> = " + xyzFormat.format(position2)); } } function writeProbeXYZPosition(x, y, z) { writeBlock("#<_second_x_position> = " + xyzFormat.format(x)); writeBlock("#<_second_y_position> = " + xyzFormat.format(y)); writeBlock("#<_second_z_position> = " + xyzFormat.format(z)); } function writeProbeExpectedX(x, updateWCS) { writeBlock("#<_x_wcs_offset> = " + xyzFormat.format(x)); writeProbeWCS(updateWCS); } function writeProbeExpectedY(y, updateWCS) { writeBlock("#<_y_wcs_offset> = " + xyzFormat.format(y)); writeProbeWCS(updateWCS); } function writeProbeExpectedZ(z, updateWCS) { writeBlock("#<_z_wcs_offset> = " + xyzFormat.format(z)); writeProbeWCS(updateWCS); } function writeProbeDiameter(probeDiameter, clearanceDiameter) { writeBlock("# = " + xyzFormat.format(probeDiameter)); writeBlock("# = " + xyzFormat.format(clearanceDiameter)); } function writeProbeVector(a, b, c) { writeBlock("# = " + xyzFormat.format(a < 0 ? a + 360 : a)); writeBlock("# = " + xyzFormat.format(b < 0 ? b + 360 : b)); writeBlock("# = " + xyzFormat.format(c < 0 ? c + 360 : c)); } function writeProbeClearance(clearance) { writeBlock("#<_z_clearance_position> = " + xyzFormat.format(clearance)); } function writeProbeWCS(updateWCS) { if (updateWCS) { if (currentSection.strategy == "probe") { // WCS probing var probeOutputWorkOffset = currentSection.probeWorkOffset; validate( probeOutputWorkOffset > 0 && (probeOutputWorkOffset > 6 ? probeOutputWorkOffset - 6 : probeOutputWorkOffset) <= 500, "Probe work offset is out of range." ); var nextWorkOffset = hasNextSection() ? getNextSection().workOffset == 0 ? 1 : getNextSection().workOffset : -1; if (probeOutputWorkOffset == nextWorkOffset) { currentWorkOffset = undefined; } writeBlock("#<_measuring_wcs> = " + probeOutputWorkOffset); } else { // Geometry probing error(localize("Geometry probing is not supported by the CNC control.")); return; // writeBlock("#<_inspect_only> = 1"); } } } function onCycleEnd() { if (!isProbeOperation()) { if (!cycleExpanded && (!isTappingCycle() || getProperty("useRigidTapping") != "yes")) { writeBlock(gCycleModal.format(80)); zOutput.reset(); } } else { if (currentSection.strategy == "probe") { // WCS probing writeBlock(currentSection.wcs); } gAbsIncModal.reset(); writeBlock(gAbsIncModal.format(90)); } } var pendingRadiusCompensation = -1; function onRadiusCompensation() { pendingRadiusCompensation = radiusCompensation; } function onMovement(movement) { movementType = movement; } function onRapid(_x, _y, _z) { var x = xOutput.format(_x); var y = yOutput.format(_y); var z = zOutput.format(_z); if (x || y || z) { if (pendingRadiusCompensation >= 0) { error(localize("Radius compensation mode cannot be changed at rapid traversal.")); return; } writeBlock(gMotionModal.format(0), x, y, z); feedOutput.reset(); } } function onLinear(_x, _y, _z, feed) { var x = xOutput.format(_x); var y = yOutput.format(_y); var z = zOutput.format(_z); var f = feedOutput.format(feed); if (x || y || z) { if (pendingRadiusCompensation >= 0) { pendingRadiusCompensation = -1; var d = tool.diameterOffset; if (d > getProperty("maxTool")) { warning(localize("The diameter offset exceeds the maximum value.")); } writeBlock(gPlaneModal.format(17)); switch (radiusCompensation) { case RADIUS_COMPENSATION_LEFT: dOutput.reset(); writeBlock(gFeedModeModal.format(94), gMotionModal.format(1), gFormat.format(41), x, y, z, dOutput.format(d), f); // error(localize("Radius compensation mode is not supported by the CNC control.")); break; case RADIUS_COMPENSATION_RIGHT: dOutput.reset(); writeBlock(gFeedModeModal.format(94), gMotionModal.format(1), gFormat.format(42), x, y, z, dOutput.format(d), f); // error(localize("Radius compensation mode is not supported by the CNC control.")); break; default: writeBlock(gFeedModeModal.format(94), gMotionModal.format(1), gFormat.format(40), x, y, z, f); } } else { writeBlock(gFeedModeModal.format(94), gMotionModal.format(1), x, y, z, f); } } else if (f) { if (getNextRecord().isMotion()) { // try not to output feed without motion feedOutput.reset(); // force feed on next line } else { writeBlock(gFeedModeModal.format(94), gMotionModal.format(1), f); } } } function onRapid5D(_x, _y, _z, _a, _b, _c) { if (!currentSection.isOptimizedForMachine()) { error(localize("This post configuration has not been customized for 5-axis simultaneous toolpath.")); return; } if (pendingRadiusCompensation >= 0) { error(localize("Radius compensation mode cannot be changed at rapid traversal.")); return; } 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); if (x || y || z || a || b || c) { writeBlock(gMotionModal.format(0), x, y, z, a, b, c); feedOutput.reset(); } } function onLinear5D(_x, _y, _z, _a, _b, _c, feed, feedMode) { if (!currentSection.isOptimizedForMachine()) { error(localize("This post configuration has not been customized for 5-axis simultaneous toolpath.")); return; } if (pendingRadiusCompensation >= 0) { error(localize("Radius compensation cannot be activated/deactivated for 5-axis move.")); return; } 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); if (feedMode == FEED_INVERSE_TIME) { feedOutput.reset(); } var f = feedMode == FEED_INVERSE_TIME ? inverseTimeOutput.format(feed) : feedOutput.format(feed); var fMode = feedMode == FEED_INVERSE_TIME ? 93 : 94; if (x || y || z || a || b || c) { writeBlock(gFeedModeModal.format(fMode), gMotionModal.format(1), x, y, z, a, b, c, f); } else if (f) { if (getNextRecord().isMotion()) { // try not to output feed without motion feedOutput.reset(); // force feed on next line } else { writeBlock(gFeedModeModal.format(fMode), gMotionModal.format(1), f); } } } 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; } // controller does not handle transition between planes well if (((movementType == MOVEMENT_LEAD_IN) || (movementType == MOVEMENT_LEAD_OUT) || (movementType == MOVEMENT_RAMP) || (movementType == MOVEMENT_PLUNGE) || (movementType == MOVEMENT_RAMP_HELIX) || (movementType == MOVEMENT_RAMP_PROFILE) || (movementType == MOVEMENT_RAMP_ZIG_ZAG)) && (getCircularPlane() != PLANE_XY)) { linearize(tolerance); 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), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), iOutput.format(cx - start.x, 0), jOutput.format(cy - start.y, 0), feedOutput.format(feed)); break; case PLANE_ZX: writeBlock(gAbsIncModal.format(90), gPlaneModal.format(18), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), iOutput.format(cx - start.x, 0), kOutput.format(cz - start.z, 0), feedOutput.format(feed)); break; case PLANE_YZ: writeBlock(gAbsIncModal.format(90), gPlaneModal.format(19), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), jOutput.format(cy - start.y, 0), kOutput.format(cz - start.z, 0), feedOutput.format(feed)); break; default: linearize(tolerance); } } else if (!getProperty("useRadius")) { switch (getCircularPlane()) { case PLANE_XY: writeBlock(gAbsIncModal.format(90), gPlaneModal.format(17), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x, 0), jOutput.format(cy - start.y, 0), feedOutput.format(feed)); break; case PLANE_ZX: writeBlock(gAbsIncModal.format(90), gPlaneModal.format(18), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x, 0), kOutput.format(cz - start.z, 0), feedOutput.format(feed)); break; case PLANE_YZ: writeBlock(gAbsIncModal.format(90), gPlaneModal.format(19), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), jOutput.format(cy - start.y, 0), kOutput.format(cz - start.z, 0), feedOutput.format(feed)); break; default: 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), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), feedOutput.format(feed)); break; case PLANE_ZX: writeBlock(gPlaneModal.format(18), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), feedOutput.format(feed)); break; case PLANE_YZ: writeBlock(gPlaneModal.format(19), gFeedModeModal.format(94), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), feedOutput.format(feed)); break; default: linearize(tolerance); } } } var mapCommand = { COMMAND_END : 2, COMMAND_SPINDLE_CLOCKWISE : 3, COMMAND_SPINDLE_COUNTERCLOCKWISE: 4, COMMAND_STOP_SPINDLE : 5, COMMAND_ORIENTATE_SPINDLE : 19, COMMAND_LOAD_TOOL : 6, COMMAND_COOLANT_ON : 8, // flood COMMAND_COOLANT_OFF : 9 }; function onCommand(command) { switch (command) { case COMMAND_STOP: writeBlock(mFormat.format(0)); forceSpindleSpeed = true; return; case COMMAND_OPTIONAL_STOP: writeBlock(mFormat.format(1)); forceSpindleSpeed = 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_BREAK_CONTROL: if (!toolChecked) { // avoid duplicate COMMAND_BREAK_CONTROL prepareForToolCheck(); writeBlock( gFormat.format(37), "P" + xyzFormat.format(getProperty("toolBreakageTolerance")) ); toolChecked = true; } return; case COMMAND_TOOL_MEASURE: return; } var stringId = getCommandStringId(command); var mcode = mapCommand[stringId]; if (mcode != undefined) { writeBlock(mFormat.format(mcode)); } else { onUnsupportedCommand(command); } } /** Buffer Manual NC commands for processing later */ var manualNC = []; function onManualNC(command, value) { if (true) { manualNC.push({command:command, value:value}); } else { expandManualNC(command, value); } } /** Processes the Manual NC commands Pass the desired command to process or leave argument list blank to process all buffered commands */ function executeManualNC(command) { for (var i = 0; i < manualNC.length; ++i) { if (!command || (command == manualNC[i].command)) { expandManualNC(manualNC[i].command, manualNC[i].value); } } for (var i = manualNC.length - 1; i >= 0; --i) { if (!command || (command == manualNC[i].command)) { manualNC.splice(i, 1); } } } function onSectionEnd() { writeBlock(gPlaneModal.format(17)); if (currentSection.isMultiAxis()) { writeBlock(gFeedModeModal.format(94)); // inverse time feed off } if ((((getCurrentSectionId() + 1) >= getNumberOfSections()) || (tool.number != getNextSection().getTool().number)) && tool.breakControl) { onCommand(COMMAND_BREAK_CONTROL); } else { toolChecked = false; } forceAny(); if ((((getCurrentSectionId() + 1) >= getNumberOfSections()) || (tool.number != getNextSection().getTool().number)) && !toolChecked) { writeBlock( mFormat.format(5), mFormat.format(9) ); } } /** Output block to do safe retract and/or move to home position. */ function writeRetract() { var words = []; // store all retracted axes in an array var retractAxes = new Array(false, false, false); var method = getProperty("safePositionMethod"); if (method == "clearanceHeight") { if (!is3D()) { error(localize("Safe retract option 'Clearance Height' is only supported when all operations are along the setup Z-axis.")); } return; } validate(arguments.length != 0, "No axis specified for writeRetract()."); for (i in arguments) { retractAxes[arguments[i]] = true; } if ((retractAxes[0] || retractAxes[1]) && !retracted) { // retract Z first before moving to X/Y home error(localize("Retracting in X/Y is not possible without being retracted in Z.")); return; } // special conditions if (retractAxes[2] && (retractAxes[0] || retractAxes[1])) { // XY don't use G28 error(localize("You cannot move home in XY & Z in the same block.")); return; } if (retractAxes[0] != retractAxes[1]) { error(localize("X & Y must be moved to home in the same block.")); } if (retractAxes[2]) { if (method == "G28") { return; } method = "G30"; } if (retractAxes[0] || retractAxes[1]) { if (method == "G30") { return; } method = "G28"; } // define home positions var _xHome; var _yHome; var _zHome; if (method == "G28") { _xHome = toPreciseUnit(0, MM); _yHome = toPreciseUnit(0, MM); _zHome = toPreciseUnit(0, MM); } else { _xHome = machineConfiguration.hasHomePositionX() ? machineConfiguration.getHomePositionX() : toPreciseUnit(0, MM); _yHome = machineConfiguration.hasHomePositionY() ? machineConfiguration.getHomePositionY() : toPreciseUnit(0, MM); _zHome = machineConfiguration.getRetractPlane() != 0 ? machineConfiguration.getRetractPlane() : toPreciseUnit(0, MM); } for (var i = 0; i < arguments.length; ++i) { switch (arguments[i]) { case X: words.push("X" + xyzFormat.format(_xHome)); xOutput.reset(); break; case Y: words.push("Y" + xyzFormat.format(_yHome)); yOutput.reset(); break; case Z: words.push("Z" + xyzFormat.format(_zHome)); zOutput.reset(); retracted = true; break; default: error(localize("Unsupported axis specified for writeRetract().")); return; } } if (words.length > 0) { switch (method) { case "G28": writeBlock(gFormat.format(28)); break; case "G53": gMotionModal.reset(); writeBlock(gAbsIncModal.format(90), gFormat.format(53), gMotionModal.format(0), words); break; case "G30": writeBlock(gFormat.format(30)); break; default: error(localize("Unsupported safe position method.")); return; } } } // Start of onRewindMachine logic /** Allow user to override the onRewind logic. */ function onRewindMachineEntry(_a, _b, _c) { return false; } /** Retract to safe position before indexing rotaries. */ function onMoveToSafeRetractPosition() { writeRetract(Z); } /** Rotate axes to new position above reentry position */ function onRotateAxes(_x, _y, _z, _a, _b, _c) { // position rotary axes xOutput.disable(); yOutput.disable(); zOutput.disable(); unwindABC(new Vector(_a, _b, _c), false); invokeOnRapid5D(_x, _y, _z, _a, _b, _c); setCurrentABC(new Vector(_a, _b, _c)); xOutput.enable(); yOutput.enable(); zOutput.enable(); } /** Return from safe position after indexing rotaries. */ function onReturnFromSafeRetractPosition(_x, _y, _z) { // position in XY forceXYZ(); xOutput.reset(); yOutput.reset(); zOutput.disable(); invokeOnRapid(_x, _y, _z); // position in Z zOutput.enable(); invokeOnRapid(_x, _y, _z); } // End of onRewindMachine logic function onClose() { writeln(""); writeRetract(Z); retracted = true; writeRetract(X, Y); if (machineConfiguration.isMultiAxisConfiguration()) { unwindABC(new Vector(0, 0, 0), true); positionABC(new Vector(0, 0, 0), true); } // Process Manual NC commands executeManualNC(); onImpliedCommand(COMMAND_END); onImpliedCommand(COMMAND_STOP_SPINDLE); writeBlock(mFormat.format(30)); // stop program, spindle stop, coolant off writeln("%"); }