/** Copyright (C) 2012-2016 by Autodesk, Inc. All rights reserved. Tormach PathPilot / Mach3Mill post processor configuration. $Revision: 41373 64da4e7ccbf4ee6cacddc63e18ad48000fe875fd $ $Date: 2017-03-23 12:25:10 $ FORKID {AE2102AB-B86A-4aa7-8E9B-F0B6935D4E9F} */ description = "Generic Tormach PathPilot"; vendor = "Tormach"; vendorUrl = "http://www.tormach.com"; legal = "Copyright (C) 2012-2016 by Autodesk, Inc."; certificationLevel = 2; minimumRevision = 24000; longDescription = "Tormach PathPilot post for 3-axis and 4-axis milling with SmartCool support."; extension = "nc"; setCodePage("ascii"); capabilities = CAPABILITY_MILLING; tolerance = spatial(0.002, MM); minimumChordLength = spatial(0.01, 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: true, // write machine writeTools: true, // writes the tools writeVersion: false, // include version info useG30: true, // disable to avoid G30 output useM6: true, // disable to avoid M6 output - preload is also disabled when M6 is disabled preloadTool: false, // preloads next tool on tool change if any showSequenceNumbers: true, // show sequence numbers sequenceNumberStart: 10, // first sequence number sequenceNumberIncrement: 10, // increment for sequence numbers optionalStop: true, // optional stop separateWordsWithSpace: true, // specifies that the words should be separated with a white space useRadius: false, // specifies that arcs should be output using the radius (R word) instead of the I, J, and K words. dwellInSeconds: true, // specifies the unit for dwelling: true:seconds and false:milliseconds. forceWorkOffset: false, // forces the work offset code at tool changes rotaryTableAxis: "None", // None, X, Y, Z, -X, -Y, -Z smartCoolEquipped: false, // machine has smart coolant attachment smartCoolToolSweepPercentage: 100, // tool length percentage to sweep coolant neglectSpindle: false // Leave spindle off for drag engraving. }; 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 ? 0 : 1), forceDecimal:true}); var inverseTimeFormat = createFormat({decimals:4, forceDecimal:true}); 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 xOutput = createVariable({prefix:"X"}, xyzFormat); var yOutput = createVariable({prefix:"Y"}, xyzFormat); var zOutput = createVariable({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 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 var WARNING_WORK_OFFSET = 0; // collected state var sequenceNumber; var currentWorkOffset; var previousCoolantMode; var coolantZHeight; var masterAxis; var maxInverseTime = 9999.9999; var previousABC = new Vector(0, 0, 0); /** Writes the specified block. */ function writeBlock() { if (properties.showSequenceNumbers) { writeWords2(nFormat.format(sequenceNumber % 100000), arguments); sequenceNumber += properties.sequenceNumberIncrement; } else { writeWords(arguments); } } function formatComment(text) { return("(" + filterText(String(text), permittedCommentChars) + ")"); } /** Output a comment. */ function writeComment(text) { writeln(formatComment(text)); } /** 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; } function onOpen() { if (properties.useRadius) { maximumCircularSweep = toRad(90); // avoid potential center calculation errors for CNC } // Define rotary attributes from properties var rotary = parseChoice(properties.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:masterAxis, table:true, axis:rotaryVector, cyclic:true, preference:1}); machineConfiguration = new MachineConfiguration(aAxis); setMachineConfiguration(machineConfiguration); // Single rotary does not use TCP mode optimizeMachineAngles2(1); // 0 = TCP Mode ON, 1 = TCP Mode OFF } if (!machineConfiguration.isMachineCoordinate(0)) { aOutput.disable(); } if (!machineConfiguration.isMachineCoordinate(1)) { bOutput.disable(); } if (!machineConfiguration.isMachineCoordinate(2)) { cOutput.disable(); } if (!properties.separateWordsWithSpace) { setWordSeparator(""); } sequenceNumber = properties.sequenceNumberStart; writeln("%"); if (programName) { writeComment(programName); } if (programComment) { writeComment(programComment); } if (properties.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 (properties.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 (properties.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; } } } // 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 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(); feedOutput.reset(); } var currentWorkPlaneABC = undefined; function forceWorkPlane() { currentWorkPlaneABC = undefined; } 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 } onCommand(COMMAND_UNLOCK_MULTI_AXIS); // NOTE: add retract here writeBlock( gMotionModal.format(0), 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)) ); onCommand(COMMAND_LOCK_MULTI_AXIS); currentWorkPlaneABC = abc; previousABC = abc; } var closestABC = false; // choose closest machine angles var currentMachineABC; function getWorkPlaneMachineABC(workPlane) { var W = workPlane; // map to global frame 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); 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)) ); } 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; } function onSection() { var insertToolCall = isFirstSection() || currentSection.getForceToolChange && currentSection.getForceToolChange() || (tool.number != getPreviousSection().getTool().number); var 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()); if (insertToolCall || newWorkOffset || newWorkPlane) { /* // stop spindle before retract during tool change if (insertToolCall && !isFirstSection()) { onCommand(COMMAND_STOP_SPINDLE); } */ if (properties.useG30) { // retract to safe plane retracted = true; writeBlock(gFormat.format(30)); // retract writeBlock(gAbsIncModal.format(90)); zOutput.reset(); } } writeln(""); if (hasParameter("operation-comment")) { var comment = getParameter("operation-comment"); if (comment) { writeComment(comment); } } if (insertToolCall) { forceWorkPlane(); // onCommand(COMMAND_COOLANT_OFF); if (!isFirstSection() && properties.optionalStop) { onCommand(COMMAND_OPTIONAL_STOP); } if (tool.number > 256) { warning(localize("Tool number exceeds maximum value.")); } var lengthOffset = tool.lengthOffset; if (lengthOffset > 256) { error(localize("Length offset out of range.")); return; } // writeBlock(mFormat.format(998)); if (properties.useG30) { writeBlock(gFormat.format(30)); } if (properties.useM6) { writeBlock("T" + toolFormat.format(tool.number), gFormat.format(43), hFormat.format(lengthOffset), mFormat.format(6)); } else { writeBlock("T" + toolFormat.format(tool.number), gFormat.format(43), hFormat.format(lengthOffset)); } if (tool.comment) { writeComment(tool.comment); } 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 (properties.preloadTool && properties.useM6) { 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)); } } } } // Define coolant code var topOfPart = undefined; if (hasParameter("operation:surfaceZHigh")) { topOfPart = getParameter("operation:surfaceZHigh"); // TAG: not safe } var c = setCoolant(tool.coolant, topOfPart); if (true || insertToolCall || isFirstSection() || (rpmFormat.areDifferent(tool.spindleRPM, sOutput.getCurrent())) || (tool.clockwise != getPreviousSection().getTool().clockwise)) { if (tool.spindleRPM < 1) { error(localize("Spindle speed out of range.")); return; } if (tool.spindleRPM > 99999) { warning(localize("Spindle speed exceeds maximum value.")); } if (!properties.neglectSpindle) { writeBlock( sOutput.format(tool.spindleRPM), mFormat.format(tool.clockwise ? 3 : 4), c[0], c[1], c[2] ); if ((tool.spindleRPM > 5000) && properties.waitForSpindle) { onDwell(properties.waitForSpindle); } } } // wcs if (insertToolCall && properties.forceWorkOffset) { // force work offset when changing tool currentWorkOffset = undefined; } var workOffset = currentSection.workOffset; if (workOffset == 0) { warningOnce(localize("Work offset has not been specified. Using G54 as WCS."), WARNING_WORK_OFFSET); workOffset = 1; } if (workOffset > 0) { if (workOffset > 6) { var p = workOffset; // 1->... // G59 P1 is the same as G54 and so on if (p > 254) { error(localize("Work offset out of range.")); } else { if (workOffset != currentWorkOffset) { writeBlock(gFormat.format(59), "P" + p); // G59 P currentWorkOffset = workOffset; } } } else { if (workOffset != currentWorkOffset) { writeBlock(gFormat.format(53 + workOffset)); // G54->G59 currentWorkOffset = workOffset; } } } forceXYZ(); if (machineConfiguration.isMultiAxisConfiguration()) { // use 5-axis indexing for multi-axis mode // set working plane after datum shift var abc = new Vector(0, 0, 0); if (currentSection.isMultiAxis()) { forceWorkPlane(); cancelTransformation(); } else { abc = getWorkPlaneMachineABC(currentSection.workPlane); } 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); } forceAny(); gMotionModal.reset(); var initialPosition = getFramePosition(currentSection.getInitialPosition()); if (!retracted) { 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 > 256) { 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) ); } } function onDwell(seconds) { if (seconds > 99999.999) { warning(localize("Dwelling time is out of range.")); } if (properties.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; // Smart coolant is not enabled if (!properties.smartCoolEquipped) { previousCoolantMode = 8; coolCodes[0] = mFormat.format(previousCoolantMode); if (coolant != COOLANT_FLOOD) { warning(localize("Unsupported coolant setting. Defaulting to FLOOD")); } } else { // Smart coolant is enabled if ((coolant == COOLANT_MIST) || (coolant == COOLANT_AIR)) { previousCoolantMode = 7; coolCodes[0] = mFormat.format(previousCoolantMode); } else { previousCoolantMode = 8; coolCodes[0] = mFormat.format(previousCoolantMode); 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 * (properties.smartCoolToolSweepPercentage/100.0)); } } } } 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 onCyclePoint(x, y, z) { if (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) ? 0 : cycle.dwell; // in seconds // Adjust SmartCool to top of part if it changes if (properties.smartCoolEquipped && xyzFormat.areDifferent((z + cycle.depth), coolantZHeight)) { var c = setCoolant(previousCoolantMode, z + cycle.depth); if (c) { writeBlock(c[0], c[1], c[2]); } } 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": // cycle.accumulatedDepth is ignored if (P > 0) { 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": if (P > 0) { expandCyclePoint(x, y, z); } else { 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": if (tool.type == TOOL_TAP_LEFT_HAND) { expandCyclePoint(x, y, z); } else { if (!F) { F = tool.getTappingFeedrate(); } writeBlock(sOutput.format(tool.spindleRPM)); writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(84), getCommonCycle(x, y, z, cycle.retract), conditional(P > 0, "P" + secFormat.format(P)), feedOutput.format(F) ); } break; case "left-tapping": expandCyclePoint(x, y, z); break; case "right-tapping": if (!F) { F = tool.getTappingFeedrate(); } writeBlock(mFormat.format(29), sOutput.format(tool.spindleRPM)); writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(84), getCommonCycle(x, y, z, cycle.retract), conditional(P > 0, "P" + secFormat.format(P)), feedOutput.format(F) ); break; case "fine-boring": writeBlock( gRetractModal.format(98), gAbsIncModal.format(90), gCycleModal.format(76), getCommonCycle(x, y, z, cycle.retract), "P" + secFormat.format(P), "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), "I" + xyzFormat.format(cycle.shift), "J" + xyzFormat.format(0), "P" + secFormat.format(P), feedOutput.format(F) ); break; case "reaming": 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) ); 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 (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 { 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) { 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); var fmode = 94; if (x || y || z) { if (pendingRadiusCompensation >= 0) { pendingRadiusCompensation = -1; var d = tool.diameterOffset; if (d > 256) { 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); // error(localize("Radius compensation mode is not supported by the CNC control.")); break; case RADIUS_COMPENSATION_RIGHT: dOutput.reset(); writeBlock(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(fmode), gMotionModal.format(1), gFormat.format(40), x, y, z, f); } } else { writeBlock(gFeedModeModal.format(fmode), 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(fmode), 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); writeBlock(gMotionModal.format(0), x, y, z, a, b, c); feedOutput.reset(); previousABC = new Vector(_a, _b, _c); } function onLinear5D(_x, _y, _z, _a, _b, _c, feed) { 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); // Calculate Inverse Time Feedrates var f; var fmode; if (a || b || c) { var length = getMoveLength(_x, _y, _z, _a, _b, _c, false); var inverseTime = getInverseTime(length, feed); f = inverseTimeOutput.format(inverseTime); fmode = 93; feedOutput.reset(); } else { f = feedOutput.format(feed); fmode = 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); } } previousABC = new Vector(_a, _b, _c); } function getMoveLength(_x, _y, _z, _a, _b, _c, _tcpMode) { // get starting and ending positions var startTool; var endTool; var startXYZ; var endXYZ; var startABC = previousABC; var endABC = new Vector(_a, _b, _c); if (_tcpMode) { startTool = getCurrentPosition(); endTool = new Vector(_x, _y, _z); startXYZ = machineConfiguration.getOrientation(startABC).getTransposed().multiply(startTool); endXYZ = machineConfiguration.getOrientation(endABC).getTransposed().multiply(endTool); } else { startXYZ = getCurrentPosition(); endXYZ = new Vector(_x, _y, _z); startTool = machineConfiguration.getOrientation(startABC).multiply(startXYZ); endTool = machineConfiguration.getOrientation(endABC).multiply(endXYZ); } // calculate the radial portion of the move var workStart = new Array(startTool.x, startTool.y, startTool.z); var workEnd = new Array(endTool.x, endTool.y, endTool.z); workStart[masterAxis] = 0; workEnd[masterAxis] = 0; var startRadius = new Vector(workStart[0], workStart[1], workStart[2]).length; var endRadius = new Vector(workEnd[0], workEnd[1], workEnd[2]).length; var radius = Math.max(startRadius, endRadius); var deltaABC = Vector.diff(endABC, startABC).length; if (deltaABC > Math.PI) { deltaABC = 2*Math.PI - deltaABC; } var radialLength = (2 * Math.PI * radius) * (deltaABC / (2 * Math.PI)); // calculate the move distance based on a combination of linear and rotary axes movement var linearLength = Vector.diff(endXYZ, startXYZ).length; var moveLength = linearLength + radialLength; return moveLength; } function getInverseTime(_length, _feed) { if (_feed <= 0) { error(localize("Feedrate is less than or equal to 0.")); return 0; } if (_length < 1.e-6) { return maxInverseTime; } else { var inverseTime = _feed / _length; // length is the tip distance if (inverseTime > maxInverseTime) { // TAG: limit given by CNC control inverseTime = maxInverseTime; } return inverseTime; // unit in 1/min } } 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 (properties.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), feedOutput.format(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), feedOutput.format(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), feedOutput.format(feed)); break; default: linearize(tolerance); } } else if (!properties.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), feedOutput.format(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), feedOutput.format(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), 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), 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), 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), 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_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, COMMAND_LOAD_TOOL:6, COMMAND_COOLANT_ON:8, // flood COMMAND_COOLANT_OFF:9 }; function onCommand(command) { switch (command) { 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: 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() { writeBlock(gPlaneModal.format(17)); if (((getCurrentSectionId() + 1) >= getNumberOfSections()) || (tool.number != getNextSection().getTool().number)) { onCommand(COMMAND_BREAK_CONTROL); } forceAny(); if (((getCurrentSectionId() + 1) >= getNumberOfSections()) || (tool.number != getNextSection().getTool().number)) { if (!properties.neglectSpindle) { writeBlock(mFormat.format(5)); } writeBlock(mFormat.format(9)); } } function onClose() { writeln(""); // onCommand(COMMAND_COOLANT_OFF); setWorkPlane(new Vector(0, 0, 0)); // reset working plane if (properties.useG30) { writeBlock(gFormat.format(30)); zOutput.reset(); } onImpliedCommand(COMMAND_END); onImpliedCommand(COMMAND_STOP_SPINDLE); writeBlock(mFormat.format(30)); // stop program, spindle stop, coolant off writeln("%"); }