diff --git a/.gitignore b/.gitignore index df06f48..6bf6f62 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ Haas_Next_Generation/Bechtel VF2HP.cps *.nc -.vscode/ \ No newline at end of file +.vscode/ +*.dmp \ No newline at end of file diff --git a/Haas_Lathes_BIDC/haas st-20.cps b/Haas_Lathes_BIDC/haas st-20.cps new file mode 100644 index 0000000..cbf7c2e --- /dev/null +++ b/Haas_Lathes_BIDC/haas st-20.cps @@ -0,0 +1,4183 @@ +/** + Copyright (C) 2012-2021 by Autodesk, Inc. + All rights reserved. + + HAAS Lathe post processor configuration. + + $Revision: 43295 06360a6b2ff0d13b975cf2a27b03d8a4d3760ca5 $ + $Date: 2021-05-27 22:34:05 $ + + FORKID {14D60AD3-4366-49dc-939C-4DB5EA48FF68} +*/ + +description = "HAAS ST-20"; + +var gotYAxis = false; +var yAxisMinimum = toPreciseUnit(gotYAxis ? -50.8 : 0, MM); // specifies the minimum range for the Y-axis +var yAxisMaximum = toPreciseUnit(gotYAxis ? 50.8 : 0, MM); // specifies the maximum range for the Y-axis +var gotBAxis = false; // B-axis always requires customization to match the machine specific functions for doing rotations +var gotMultiTurret = false; // specifies if the machine has several turrets + +var gotDoorControl = false; + +// >>>>> INCLUDED FROM ../common/haas lathe.cps +/////////////////////////////////////////////////////////////////////////////// +// MANUAL NC COMMANDS +// +// The following ACTION commands are supported by this post. +// +// partEject - Manually eject the part +// usePolarMode - Force Polar mode for next operation +// +/////////////////////////////////////////////////////////////////////////////// + +if (!description) { + description = "HAAS Lathe"; +} +vendor = "Haas Automation"; +vendorUrl = "https://www.haascnc.com"; +legal = "Copyright (C) 2012-2021 by Autodesk, Inc."; +certificationLevel = 2; +minimumRevision = 45702; + +if (!longDescription) { + longDescription = subst("Preconfigured %1 post with support for mill-turn. You can force G112 mode for a specific operation by using Manual NC Action with keyword 'usepolarmode'.", description); +} + +extension = "nc"; +programNameIsInteger = true; +setCodePage("ascii"); + +capabilities = CAPABILITY_MILLING | CAPABILITY_TURNING; +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(120); // reduced sweep due to G112 support +allowHelicalMoves = true; +allowedCircularPlanes = undefined; // allow any circular motion +allowSpiralMoves = false; +highFeedrate = (unit == IN) ? 470 : 12000; + +// user-defined properties +properties = { + writeMachine: { + title: "Write machine", + description: "Output the machine settings in the header of the code.", + group: 0, + type: "boolean", + value: false, + scope: "post" + }, + writeTools: { + title: "Write tool list", + description: "Output a tool list in the header of the code.", + group: 0, + type: "boolean", + value: false, + scope: "post" + }, + writeVersion: { + title: "Write version", + description: "Write the version number in the header of the code.", + group: 0, + type: "boolean", + value: false, + scope: "post" + }, + showSequenceNumbers: { + title: "Use sequence numbers", + description: "Use sequence numbers for each block of outputted code.", + group: 1, + type: "boolean", + value: false, + scope: "post" + }, + sequenceNumberStart: { + title: "Start sequence number", + description: "The number at which to start the sequence numbers.", + group: 1, + 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: 1, + type: "integer", + value: 1, + scope: "post" + }, + optionalStop: { + title: "Optional stop", + description: "Outputs optional stop code during when necessary in the code.", + type: "boolean", + value: true, + scope: "post" + }, + separateWordsWithSpace: { + title: "Separate words with space", + description: "Adds spaces between words if 'yes' is selected.", + type: "boolean", + value: true, + scope: "post" + }, + useRadius: { + title: "Radius arcs", + description: "If yes is selected, arcs are outputted using radius values rather than IJK.", + type: "boolean", + value: false, + scope: "post" + }, + maximumSpindleSpeed: { + title: "Max spindle speed", + description: "Defines the maximum spindle speed allowed on the main spindle.", + group: 4, + type: "integer", + range: [0, 999999999] + }, + subMaximumSpindleSpeed: { + title: "Max spindle speed for subspindle", + description: "Defines the maximum spindle speed allowed on the subspindle.", + group: 4, + type: "integer", + range: [0, 999999999] + }, + useParametricFeed: { + title: "Parametric feed", + description: "Specifies the feed value that should be output using a Q value.", + type: "boolean", + value: false, + scope: "post" + }, + showNotes: { + title: "Show notes", + description: "Writes operation notes as comments in the outputted code.", + type: "boolean", + value: false, + scope: "post" + }, + useCycles: { + title: "Use cycles", + description: "Specifies if canned drilling cycles should be used.", + type: "boolean", + value: true, + scope: "post" + }, + autoEject: { + title: "Auto eject", + description: "Specifies whether the part should automatically eject at the end of a program.", + type: "boolean", + value: false, + scope: "post" + }, + g53HomePositionX: { + title: "G53 home position X", + description: "G53 X-axis home position.", + type: "number", + value: 0, + scope: "post" + }, + g53HomePositionY: { + title: "G53 home position Y", + description: "G53 Y-axis home position.", + type: "number", + value: 0, + scope: "post" + }, + g53HomePositionZ: { + title: "G53 home position Z", + description: "G53 Z-axis home position.", + type: "number", + value: 0, + scope: "post" + }, + g53HomePositionSubZ: { + title: "G53 home position subspindle Z", + description: "G53 Z-axis home position when Secondary Spindle is active.", + type: "number", + value: 0, + scope: "post" + }, + g53WorkPositionSub: { + title: "G53 subspindle working position", + description: "G53 working position for Secondary Spindle when active.", + type: "number", + value: 0, + scope: "post" + }, + useTailStock: { + title: "Use tail stock", + description: "Enable to use the tail stock.", + type: "boolean", + value: false, + scope: "post" + }, + useBarFeeder: { + title: "Use bar feeder", + description: "Enable to use the bar feeder.", + type: "boolean", + value: false, + scope: "post" + }, + gotChipConveyor: { + title: "Got chip conveyor", + description: "Specifies whether to use a chip conveyor.", + type: "boolean", + presentation: "yesno", + value: false, + scope: "post" + }, + useG112: { + title: "Use polar interpolation", + description: "Enables polar interpolation output.", + type: "boolean", + value: false, + scope: "post" + }, + usePolarCircular: { + title: "Use polar circular", + description: "Enables circular interpolation with polar output.", + type: "boolean", + group: 3, + value: false, + scope: "post" + }, + xAxisMinimum: { + title: "X-axis minimum limit", + description: "Defines the lower limit of X-axis travel as a radius value.", + type: "spatial", + range: [0, -99999], + group: 3, + value: 0, + scope: "post" + }, + useG61: { + title: "Use exact stop mode", + description: "Enables exact stop mode.", + type: "boolean", + value: false, + scope: "post" + }, + setting102: { + title: "Feed rate calculation diameter", + description: "Defines the part diameter in inches that the control uses to calculate feed rates.", + type: "spatial", + range: [0.1, 9999], + value: 1, + scope: "post" + }, + rapidRewinds: { + title: "Use G0 for rewinds", + description: "Uses G0 moves for rewinding of the C-axis.", + type: "boolean", + value: false, + scope: "post" + }, + useSSV: { + title: "Use SSV", + description: "Outputs M38/M39 to enable SSV for turning operations.", + type: "boolean", + value: false, + scope: "post" + }, + optimizeCAxisSelect: { + title: "Optimize C-axis selection", + description: "Optimizes the output of enable/disable C-axis codes.", + type: "boolean", + value: false, + scope: "post" + }, + gotSecondarySpindle: { + title: "Got secondary spindle", + description: "Specifies if the machine has a secondary spindle.", + type: "boolean", + value: false, + scope: "post" + }, + looping: { + title: "Use M97 looping", + description: "Output program for M97 looping.", + type: "boolean", + presentation: "yesno", + group: 5, + value: false, + scope: "post" + }, + numberOfRepeats: { + title: "Number of repeats", + description: "How many times to loop the program.", + type: "integer", + range: [0, 99999999], + group: 5, + value: 1, + scope: "post" + }, + useSimpleThread: { + title: "Use simple threading cycle", + description: "Enable to output G92 simple threading cycle, disable to output G76 standard threading cycle.", + type: "boolean", + value: true, + scope: "post" + }, + airCleanChuck: { + title: "Air clean chucks", + description: "Enable to use the air blast to clean out the chuck on part transfers and part ejection.", + type: "boolean", + value: true, + scope: "post" + }, + safeStartAllOperations: { + title: "Safe start all operations", + description: "Write optional blocks at the beginning of all operations that include all commands to start program.", + type: "boolean", + value: false, + scope: "post" + }, + useYAxisForDrilling: { + title: "Position in Y for axial drilling", + description: "Positions in Y for axial drilling options when it can instead of using the C-axis.", + type: "boolean", + value: false, + scope: "post" + }, + useG187: { + title: "Use G187", + description: "Specifies that smoothing using G187 should be used for milling operations.", + type: "boolean", + value: false, + scope: "post" + } +}; + +var permittedCommentChars = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,=_-"; + +var gFormat = createFormat({prefix:"G", decimals:0}); +var mFormat = createFormat({prefix:"M", decimals:0}); +var pFormat = createFormat({prefix:"P", decimals:0}); + +var spatialFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true}); +var xFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true, scale:2}); // diameter mode & IS SCALING POLAR COORDINATES +var yFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true}); +var zFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true}); +var rFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true}); // radius +var abcFormat = createFormat({decimals:3, forceDecimal:true, scale:DEG}); +var cFormat = createFormat({decimals:3, forceDecimal:true, scale:DEG}); +var feedFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true}); +var pitchFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true}); +var toolFormat = createFormat({decimals:0}); +var rpmFormat = createFormat({decimals:0}); +var secFormat = createFormat({decimals:3, forceDecimal:true}); // seconds - range 0.001-99999.999 +var milliFormat = createFormat({decimals:0}); // milliseconds // range 1-9999 +var taperFormat = createFormat({decimals:1, scale:DEG}); +var integerFormat = createFormat({decimals:0, forceDecimal:false, trim:true}); +var threadQFormat = createFormat({decimals:3, forceDecimal:false, trimLeadZero:true, scale:1000}); +var g76AFormat = createFormat({decimals:(unit == MM ? 3 : 4)}); + +var xOutput = createVariable({prefix:"X"}, xFormat); +var yOutput = createVariable({prefix:"Y"}, yFormat); +var zOutput = createVariable({prefix:"Z"}, zFormat); +var aOutput = createVariable({prefix:"A"}, abcFormat); +var bOutput = createVariable({prefix:"B"}, abcFormat); +var cOutput = createVariable({prefix:"C"}, cFormat); +var feedOutput = createVariable({prefix:"F"}, feedFormat); +var pitchOutput = createVariable({prefix:"F", force:true}, pitchFormat); +var sOutput = createVariable({prefix:"S", force:true}, rpmFormat); +var pOutput = createVariable({prefix:"P", force:true}, rpmFormat); + +// circular output +var iOutput = createReferenceVariable({prefix:"I", force:true}, spatialFormat); +var jOutput = createReferenceVariable({prefix:"J", force:true}, spatialFormat); +var kOutput = createReferenceVariable({prefix:"K", force:true}, spatialFormat); + +// cycle thread output +var g76IOutput = createVariable({prefix:"I", force:true}, zFormat); // no scaling +var g76KOutput = createVariable({prefix:"K", force:true}, zFormat); // no scaling +var g76DOutput = createVariable({prefix:"D", force:true}, zFormat); // no scaling +var g76AOutput = createVariable({prefix:"A", force:true}, g76AFormat); // no scaling +var g76QOutput = createVariable({prefix:"Q", force:true}, threadQFormat); +var g92IOutput = createVariable({prefix:"I"}, zFormat); // no scaling +var g92QOutput = createVariable({prefix:"Q"}, threadQFormat); + +var gMotionModal = createModal({}, gFormat); // modal group 1 // G0-G3, ... +var gPlaneModal = createModal({onchange:function () {gMotionModal.reset();}}, gFormat); // modal group 2 // G17-19 +var gFeedModeModal = createModal({}, gFormat); // modal group 5 // G98-99 +var gSpindleModeModal = createModal({}, gFormat); // modal group 5 // G96-97 +var gSynchronizedSpindleModal = createModal({}, gFormat); // G198/G199 +var gSpindleModal = createModal({}, gFormat); // G14/G15 SPINDLE MODE +var gUnitModal = createModal({}, gFormat); // modal group 6 // G20-21 +var gCycleModal = createModal({}, gFormat); // modal group 9 // G81, ... +var gPolarModal = createModal({}, gFormat); // G112, G113 +var ssvModal = createModal({}, mFormat); // M38, M39 +var cAxisEngageModal = createModal({}, mFormat); +var cAxisBrakeModal = createModal({}, mFormat); +var gExactStopModal = createModal({}, gFormat); // modal group for exact stop codes +var tailStockModal = createModal({}, mFormat); + +// fixed settings +var firstFeedParameter = 100; +var usePolarCircular = false; + +var WARNING_WORK_OFFSET = 0; +var WARNING_REPEAT_TAPPING = 1; + +// collected state +var sequenceNumber; +var currentWorkOffset; +var optionalSection = false; +var forceSpindleSpeed = false; +var activeMovements; // do not use by default +var currentFeedId; +var forcePolarMode; +var bestABCIndex = undefined; +var partCutoff = false; +var ejectRoutine = false; +var g100Mirroring = false; +var g14IsActive = false; +var xAxisMinimum; + +// used to convert blocks to optional for safeStartAllOperations, might get used outside of onSection +var skipBlock = false; +var operationNeedsSafeStart = false; + +var machineState = { + liveToolIsActive: undefined, + cAxisIsEngaged: undefined, + machiningDirection: undefined, + mainSpindleIsActive: undefined, + subSpindleIsActive: undefined, + mainSpindleBrakeIsActive: undefined, + subSpindleBrakeIsActive: undefined, + tailstockIsActive: undefined, + usePolarMode: undefined, + useXZCMode: undefined, + axialCenterDrilling: undefined, + tapping: undefined, + currentBAxisOrientationTurning: new Vector(0, 0, 0), + feedPerRevolution: undefined, + stockTransferIsActive: false +}; + +/** G/M codes setup */ +function getCode(code) { + switch (code) { + case "PART_CATCHER_ON": + return mFormat.format(36); + case "PART_CATCHER_OFF": + return mFormat.format(37); + case "TAILSTOCK_ON": + machineState.tailstockIsActive = true; + return mFormat.format(21); + case "TAILSTOCK_OFF": + machineState.tailstockIsActive = false; + return mFormat.format(22); + case "ENGAGE_C_AXIS": + if (currentSection.spindle == SPINDLE_PRIMARY) { + machineState.cAxisIsEngaged = true; + return cAxisEngageModal.format(154); + } else { + return ""; + } + case "DISENGAGE_C_AXIS": + if (currentSection.spindle == SPINDLE_PRIMARY) { + machineState.cAxisIsEngaged = false; + return cAxisEngageModal.format(155); + } else { + return ""; + } + case "POLAR_INTERPOLATION_ON": + return gPolarModal.format(112); + case "POLAR_INTERPOLATION_OFF": + return gPolarModal.format(113); + case "STOP_SPINDLE": + if (machineState.liveToolIsActive) { + machineState.liveToolIsActive = false; + return mFormat.format(135); + } else if (machineState.mainSpindleIsActive) { + machineState.mainSpindleIsActive = false; + return mFormat.format(5); + } else if (machineState.subSpindleIsActive) { + machineState.subSpindleIsActive = false; + return mFormat.format(g14IsActive ? 5 : 145); + } else { + return undefined; + } + case "START_LIVE_TOOL_CW": + machineState.liveToolIsActive = true; + return mFormat.format(133); + case "START_LIVE_TOOL_CCW": + machineState.liveToolIsActive = true; + return mFormat.format(134); + case "START_MAIN_SPINDLE_CW": + machineState.mainSpindleIsActive = true; + return mFormat.format(3); + case "START_MAIN_SPINDLE_CCW": + machineState.mainSpindleIsActive = true; + return mFormat.format(4); + case "START_SUB_SPINDLE_CW": + machineState.subSpindleIsActive = true; + return mFormat.format(g14IsActive ? 3 : 143); + case "START_SUB_SPINDLE_CCW": + machineState.subSpindleIsActive = true; + return mFormat.format(g14IsActive ? 4 : 144); + case "MAIN_SPINDLE_BRAKE_ON": + machineState.mainSpindleBrakeIsActive = true; + return cAxisBrakeModal.format(14); + case "MAIN_SPINDLE_BRAKE_OFF": + machineState.mainSpindleBrakeIsActive = false; + return cAxisBrakeModal.format(15); + case "SUB_SPINDLE_BRAKE_ON": + machineState.subSpindleBrakeIsActive = true; + return cAxisBrakeModal.format(g14IsActive ? 14 : 114); + case "SUB_SPINDLE_BRAKE_OFF": + machineState.subSpindleBrakeIsActive = false; + return cAxisBrakeModal.format(g14IsActive ? 15 : 115); + case "FEED_MODE_UNIT_REV": + machineState.feedPerRevolution = true; + return gFeedModeModal.format(99); + case "FEED_MODE_UNIT_MIN": + machineState.feedPerRevolution = false; + return gFeedModeModal.format(98); + case "CONSTANT_SURFACE_SPEED_ON": + return gSpindleModeModal.format(96); + case "CONSTANT_SURFACE_SPEED_OFF": + return gSpindleModeModal.format(97); + case "MAINSPINDLE_AIR_BLAST_ON": + return mFormat.format(12); + case "MAINSPINDLE_AIR_BLAST_OFF": + return mFormat.format(13); + case "SUBSPINDLE_AIR_BLAST_ON": + return mFormat.format(112); + case "SUBSPINDLE_AIR_BLAST_OFF": + return mFormat.format(113); + case "CLAMP_PRIMARY_CHUCK": + return mFormat.format(10); + case "UNCLAMP_PRIMARY_CHUCK": + return mFormat.format(11); + case "CLAMP_SECONDARY_CHUCK": + return mFormat.format(110); + case "UNCLAMP_SECONDARY_CHUCK": + return mFormat.format(111); + case "SPINDLE_SYNCHRONIZATION_ON": + machineState.spindleSynchronizationIsActive = true; + return gSynchronizedSpindleModal.format(199); + case "SPINDLE_SYNCHRONIZATION_OFF": + machineState.spindleSynchronizationIsActive = false; + return gSynchronizedSpindleModal.format(198); + case "START_CHIP_TRANSPORT": + return mFormat.format(31); + case "STOP_CHIP_TRANSPORT": + return mFormat.format(33); + case "OPEN_DOOR": + return mFormat.format(85); + case "CLOSE_DOOR": + return mFormat.format(86); + case "COOLANT_FLOOD_ON": + return mFormat.format(8); + case "COOLANT_FLOOD_OFF": + return mFormat.format(9); + case "COOLANT_AIR_ON": + return mFormat.format(83); + case "COOLANT_AIR_OFF": + return mFormat.format(84); + case "COOLANT_THROUGH_TOOL_ON": + return mFormat.format(88); + case "COOLANT_THROUGH_TOOL_OFF": + return mFormat.format(89); + case "COOLANT_OFF": + return mFormat.format(9); + default: + error(localize("Command " + code + " is not defined.")); + return 0; + } +} + +function isSpindleSpeedDifferent() { + if (isFirstSection()) { + return true; + } + if (getPreviousSection().getTool().clockwise != tool.clockwise) { + return true; + } + if (tool.getSpindleMode() == SPINDLE_CONSTANT_SURFACE_SPEED) { + if ((getPreviousSection().getTool().getSpindleMode() != SPINDLE_CONSTANT_SURFACE_SPEED) || + rpmFormat.areDifferent(getPreviousSection().getTool().surfaceSpeed, tool.surfaceSpeed)) { + return true; + } + } else { + if ((getPreviousSection().getTool().getSpindleMode() != SPINDLE_CONSTANT_SPINDLE_SPEED) || + rpmFormat.areDifferent(getPreviousSection().getTool().spindleRPM, spindleSpeed)) { + return true; + } + } + return false; +} + +function onSpindleSpeed(spindleSpeed) { + if ((sOutput.getCurrent() != Number.POSITIVE_INFINITY) && rpmFormat.areDifferent(spindleSpeed, sOutput.getCurrent())) { // avoid redundant output of spindle speed + startSpindle(false, getFramePosition(currentSection.getInitialPosition()), spindleSpeed); + } + if ((pOutput.getCurrent() != Number.POSITIVE_INFINITY) && rpmFormat.areDifferent(spindleSpeed, pOutput.getCurrent())) { // avoid redundant output of spindle speed + startSpindle(false, getFramePosition(currentSection.getInitialPosition()), spindleSpeed); + } +} + +function startSpindle(forceRPMMode, initialPosition, rpm) { + var _skipBlock = skipBlock; + var _spindleSpeed = spindleSpeed; + if (rpm !== undefined) { + _spindleSpeed = rpm; + } + + var useConstantSurfaceSpeed = currentSection.getTool().getSpindleMode() == SPINDLE_CONSTANT_SURFACE_SPEED; + var maxSpeed = (currentSection.spindle == SPINDLE_SECONDARY) ? getProperty("subMaximumSpindleSpeed") : getProperty("maximumSpindleSpeed"); + var maximumSpindleSpeed = (tool.maximumSpindleSpeed > 0) ? Math.min(tool.maximumSpindleSpeed, maxSpeed) : maxSpeed; + if (useConstantSurfaceSpeed && !forceRPMMode) { + skipBlock = _skipBlock; + writeBlock(gFormat.format(50), sOutput.format(maximumSpindleSpeed)); + } else if (!isFirstSection()) { // maximum spindle speed needs to be set when switching from SFM to RPM + var prevConstantSurfaceSpeed = getPreviousSection().getTool().getSpindleMode() == SPINDLE_CONSTANT_SURFACE_SPEED; + if (prevConstantSurfaceSpeed && !useConstantSurfaceSpeed) { + writeBlock(gFormat.format(50), sOutput.format(maxSpeed)); + } + } + + gSpindleModeModal.reset(); + skipBlock = _skipBlock; + if (useConstantSurfaceSpeed && !forceRPMMode) { + writeBlock(getCode("CONSTANT_SURFACE_SPEED_ON")); + } else { + writeBlock(getCode("CONSTANT_SURFACE_SPEED_OFF")); + } + + _spindleSpeed = useConstantSurfaceSpeed ? tool.surfaceSpeed * ((unit == MM) ? 1 / 1000.0 : 1 / 12.0) : _spindleSpeed; + if (useConstantSurfaceSpeed && forceRPMMode) { // RPM mode is forced until move to initial position + if (xFormat.getResultingValue(initialPosition.x) == 0) { + _spindleSpeed = maximumSpindleSpeed; + } else { + _spindleSpeed = Math.min((_spindleSpeed * ((unit == MM) ? 1000.0 : 12.0) / (Math.PI * Math.abs(initialPosition.x * 2))), maximumSpindleSpeed); + } + } + switch (currentSection.spindle) { + case SPINDLE_PRIMARY: // main spindle + if (machineState.isTurningOperation || machineState.axialCenterDrilling) { // turning main spindle + skipBlock = _skipBlock; + writeBlock( + sOutput.format(_spindleSpeed), + conditional(!machineState.tapping, tool.clockwise ? getCode("START_MAIN_SPINDLE_CW") : getCode("START_MAIN_SPINDLE_CCW")) + ); + } else { // milling main spindle + skipBlock = _skipBlock; + writeBlock( + (machineState.tapping ? sOutput.format(spindleSpeed) : pOutput.format(_spindleSpeed)), + conditional(!machineState.tapping, tool.clockwise ? getCode("START_LIVE_TOOL_CW") : getCode("START_LIVE_TOOL_CCW")) + ); + } + break; + case SPINDLE_SECONDARY: // sub spindle + if (!getProperty("gotSecondarySpindle")) { + error(localize("Secondary spindle is not available.")); + return; + } + if (machineState.isTurningOperation || machineState.axialCenterDrilling) { // turning sub spindle + gSpindleModeModal.reset(); + skipBlock = _skipBlock; + writeBlock( + sOutput.format(_spindleSpeed), + conditional(!machineState.tapping, tool.clockwise ? getCode("START_SUB_SPINDLE_CW") : getCode("START_SUB_SPINDLE_CCW")) + ); + } else { // milling sub spindle + skipBlock = _skipBlock; + writeBlock(pOutput.format(_spindleSpeed), tool.clockwise ? getCode("START_LIVE_TOOL_CW") : getCode("START_LIVE_TOOL_CCW")); + } + break; + } + + if (getProperty("useSSV")) { + if (machineState.isTurningOperation && hasParameter("operation-strategy") && getParameter("operation-strategy") != "turningThread") { + skipBlock = _skipBlock; + writeBlock(ssvModal.format(38)); + } + } +} + +/** Write retract in XY/Z. */ +function writeRetract(section, retractZ) { + var _skipBlock = skipBlock; + if (!isFirstSection()) { + if (gotYAxis) { + skipBlock = _skipBlock; + writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + yFormat.format(getProperty("g53HomePositionY"))); // retract + yOutput.reset(); + } + skipBlock = _skipBlock; + writeBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(getProperty("g53HomePositionX"))); // retract + xOutput.reset(); + if (retractZ) { + skipBlock = _skipBlock; + writeBlock(gFormat.format(53), gMotionModal.format(0), "Z" + zFormat.format((section.spindle == SPINDLE_SECONDARY) ? getProperty("g53HomePositionSubZ") : getProperty("g53HomePositionZ"))); // retract with regard to spindle + zOutput.reset(); + } + } +} + +/** Write WCS. */ +function writeWCS(section) { + var workOffset = section.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 code = workOffset - 6; + if (code > 99) { + error(localize("Work offset out of range.")); + return; + } + if (workOffset != currentWorkOffset) { + forceWorkPlane(); + writeBlock(gFormat.format(154), "P" + code); + currentWorkOffset = workOffset; + } + } else { + if (workOffset != currentWorkOffset) { + forceWorkPlane(); + writeBlock(gFormat.format(53 + workOffset)); // G54->G59 + currentWorkOffset = workOffset; + } + } + } +} + +/** Returns the modulus. */ +function getModulus(x, y) { + return Math.sqrt(x * x + y * y); +} + +/** + Returns the C rotation for the given X and Y coordinates. +*/ +function getC(x, y) { + var direction; + if (Vector.dot(machineConfiguration.getAxisU().getAxis(), new Vector(0, 0, 1)) != 0) { + direction = (machineConfiguration.getAxisU().getAxis().getCoordinate(2) >= 0) ? 1 : -1; // C-axis is the U-axis + } else { + direction = (machineConfiguration.getAxisV().getAxis().getCoordinate(2) >= 0) ? 1 : -1; // C-axis is the V-axis + } + + return Math.atan2(y, x) * direction; +} + +/** + Returns the C rotation for the given X and Y coordinates in the desired rotary direction. +*/ +function getCClosest(x, y, _c, clockwise) { + if (_c == Number.POSITIVE_INFINITY) { + _c = 0; // undefined + } + if (!xFormat.isSignificant(x) && !yFormat.isSignificant(y)) { // keep C if XY is on center + return _c; + } + var c = getC(x, y); + if (clockwise != undefined) { + if (clockwise) { + while (c < _c) { + c += Math.PI * 2; + } + } else { + while (c > _c) { + c -= Math.PI * 2; + } + } + } else { + min = _c - Math.PI; + max = _c + Math.PI; + while (c < min) { + c += Math.PI * 2; + } + while (c > max) { + c -= Math.PI * 2; + } + } + return c; +} + +function getCWithinRange(x, y, _c, clockwise) { + var c = getCClosest(x, y, _c, clockwise); + + var cyclicLimit; + var cyclic; + if (Vector.dot(machineConfiguration.getAxisU().getAxis(), new Vector(0, 0, 1)) != 0) { + // C-axis is the U-axis + cyclicLimit = machineConfiguration.getAxisU().getRange(); + cyclic = machineConfiguration.getAxisU().isCyclic(); + } else if (Vector.dot(machineConfiguration.getAxisV().getAxis(), new Vector(0, 0, 1)) != 0) { + // C-axis is the V-axis + cyclicLimit = machineConfiguration.getAxisV().getRange(); + cyclic = machineConfiguration.getAxisV().isCyclic(); + } else { + error(localize("Unsupported rotary axis direction.")); + return 0; + } + + // see if rewind is required + forceRewind = false; + if ((cFormat.getResultingValue(c) < abcFormat.getResultingValue(cyclicLimit[0])) || (cFormat.getResultingValue(c) > abcFormat.getResultingValue(cyclicLimit[1]))) { + if (!cyclic) { + forceRewind = true; + } + c = getCClosest(x, y, 0); // find closest C to 0 + if ((cFormat.getResultingValue(c) < abcFormat.getResultingValue(cyclicLimit[0])) || (cFormat.getResultingValue(c) > abcFormat.getResultingValue(cyclicLimit[1]))) { + var midRange = cyclicLimit[0] + (cyclicLimit[1] - cyclicLimit[0]) / 2; + c = getCClosest(x, y, midRange); // find closest C to midRange + } + if ((cFormat.getResultingValue(c) < abcFormat.getResultingValue(cyclicLimit[0])) || (cFormat.getResultingValue(c) > abcFormat.getResultingValue(cyclicLimit[1]))) { + error(localize("Unable to find C-axis position within the defined range.")); + return 0; + } + } + return c; +} + +/** + Returns the desired tolerance for the given section. +*/ +function getTolerance() { + var t = tolerance; + if (hasParameter("operation:tolerance")) { + if (t > 0) { + t = Math.min(t, getParameter("operation:tolerance")); + } else { + t = getParameter("operation:tolerance"); + } + } + return t; +} + +/** + Writes the specified block. +*/ +function writeBlock() { + var text = formatWords(arguments); + if (!text) { + skipBlock = false; + return; + } + if (getProperty("showSequenceNumbers")) { + if (sequenceNumber > 99999) { + sequenceNumber = getProperty("sequenceNumberStart"); + } + if (optionalSection || skipBlock) { + if (text) { + writeWords("/", "N" + sequenceNumber, text); + } + } else { + writeWords2("N" + sequenceNumber, arguments); + } + sequenceNumber += getProperty("sequenceNumberIncrement"); + } else { + if (optionalSection || skipBlock) { + writeWords2("/", arguments); + } else { + writeWords(arguments); + } + } + skipBlock = false; +} + +/** + Writes the specified optional block. +*/ +function writeOptionalBlock() { + if (getProperty("showSequenceNumbers")) { + var words = formatWords(arguments); + if (words) { + writeWords("/", "N" + sequenceNumber, words); + sequenceNumber += getProperty("sequenceNumberIncrement"); + } + } else { + writeWords2("/", arguments); + } +} + +function formatComment(text) { + return "(" + String(text).replace(/[()]/g, "") + ")"; +} + +/** + Output a comment. +*/ +function writeComment(text) { + writeln(formatComment(text)); +} + +function getB(abc, section) { + if (section.spindle == SPINDLE_PRIMARY) { + return abc.y; + } else { + return Math.PI - abc.y; + } +} + +var machineConfigurationMainSpindle; +var machineConfigurationSubSpindle; + +function onOpen() { + if (getProperty("useRadius")) { + maximumCircularSweep = toRad(90); // avoid potential center calculation errors for CNC + } + + if (getProperty("useG61")) { + gExactStopModal.format(64); + } + + xAxisMinimum = getProperty("xAxisMinimum"); + + if (true) { + var bAxisMain = createAxis({coordinate:1, table:false, axis:[0, -1, 0], range:[-0.001, 90.001], preference:0}); + var cAxisMain = createAxis({coordinate:2, table:true, axis:[0, 0, 1], cyclic:false, range:[-8280, 8280], preference:0, reset:1}); + + var bAxisSub = createAxis({coordinate:1, table:false, axis:[0, -1, 0], range:[-0.001, 180.001], preference:0}); + var cAxisSub = createAxis({coordinate:2, table:true, axis:[0, 0, 1], cyclic:false, range:[-8280, 8280], preference:0, reset:1}); + + machineConfigurationMainSpindle = gotBAxis ? new MachineConfiguration(bAxisMain, cAxisMain) : new MachineConfiguration(cAxisMain); + machineConfigurationSubSpindle = gotBAxis ? new MachineConfiguration(bAxisSub, cAxisSub) : new MachineConfiguration(cAxisSub); + } + + machineConfiguration = new MachineConfiguration(); // creates an empty configuration to be able to set eg vendor information + + machineConfiguration.setVendor("HAAS"); + machineConfiguration.setModel(description); + + if (!gotYAxis) { + yOutput.disable(); + } + aOutput.disable(); + if (!gotBAxis) { + bOutput.disable(); + } + + if (highFeedrate <= 0) { + error(localize("You must set 'highFeedrate' because axes are not synchronized for rapid traversal.")); + return; + } + + if (!getProperty("separateWordsWithSpace")) { + setWordSeparator(""); + } + + sequenceNumber = getProperty("sequenceNumberStart"); + writeln("%"); + + if (programName) { + var programId; + try { + programId = getAsInt(programName); + } catch (e) { + error(localize("Program name must be a number.")); + return; + } + if (!((programId >= 1) && (programId <= 99999))) { + error(localize("Program number is out of range.")); + return; + } + var oFormat = createFormat({width:5, zeropad:true, decimals:0}); + if (programComment) { + writeln("O" + oFormat.format(programId) + " (" + filterText(String(programComment).toUpperCase(), permittedCommentChars) + ")"); + } else { + writeln("O" + oFormat.format(programId)); + } + } else { + error(localize("Program name has not been specified.")); + return; + } + + 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 compensationOffset = tool.isTurningTool() ? tool.compensationOffset : tool.lengthOffset; + var comment = "T" + toolFormat.format(tool.number * 100 + compensationOffset % 100) + " " + + (tool.diameter != 0 ? "D=" + spatialFormat.format(tool.diameter) + " " : "") + + (tool.isTurningTool() ? localize("NR") + "=" + spatialFormat.format(tool.noseRadius) : localize("CR") + "=" + spatialFormat.format(tool.cornerRadius)) + + (tool.taperAngle > 0 && (tool.taperAngle < Math.PI) ? " " + localize("TAPER") + "=" + taperFormat.format(tool.taperAngle) + localize("deg") : "") + + (zRanges[tool.number] ? " - " + localize("ZMIN") + "=" + spatialFormat.format(zRanges[tool.number].getMinimum()) : "") + + " - " + localize(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 (spatialFormat.areDifferent(tooli.diameter, toolj.diameter) || + spatialFormat.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; + } + } + } + + // support program looping for bar work + if (getProperty("looping")) { + if (getProperty("numberOfRepeats") < 1) { + error(localize("numberOfRepeats must be greater than 0.")); + return; + } + if (sequenceNumber == 1) { + sequenceNumber++; + } + writeln(""); + writeln(""); + writeComment(localize("Local Looping")); + writeln(""); + writeBlock(mFormat.format(97), "P1", "L" + getProperty("numberOfRepeats")); + onCommand(COMMAND_OPEN_DOOR); + writeBlock(mFormat.format(30)); + writeln(""); + writeln(""); + writeln("N1 (START MAIN PROGRAM)"); + } + + // absolute coordinates and feed per min + writeBlock(getCode("FEED_MODE_UNIT_MIN"), gPlaneModal.format(18)); + + switch (unit) { + case IN: + writeBlock(gUnitModal.format(20)); + break; + case MM: + writeBlock(gUnitModal.format(21)); + break; + } + + onCommand(COMMAND_CLOSE_DOOR); + + // writeBlock("#" + (firstFeedParameter - 1) + "=" + ((currentSection.spindle == SPINDLE_SECONDARY) ? getProperty("g53HomePositionSubZ") : getProperty("g53HomePositionZ")), formatComment("g53HomePositionZ")); + + var usesPrimarySpindle = false; + var usesSecondarySpindle = false; + for (var i = 0; i < getNumberOfSections(); ++i) { + var section = getSection(i); + if (section.getType() != TYPE_TURNING) { + continue; + } + switch (section.spindle) { + case SPINDLE_PRIMARY: + usesPrimarySpindle = true; + break; + case SPINDLE_SECONDARY: + usesSecondarySpindle = true; + break; + } + } + + writeBlock(gFormat.format(50), sOutput.format(getSection(0).spindle == SPINDLE_PRIMARY ? getProperty("maximumSpindleSpeed") : getProperty("subMaximumSpindleSpeed"))); + sOutput.reset(); + + if (getProperty("gotChipConveyor")) { + onCommand(COMMAND_START_CHIP_TRANSPORT); + } + + if (gotYAxis) { + writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + yFormat.format(getProperty("g53HomePositionY"))); // retract + } + writeBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(getProperty("g53HomePositionX"))); // retract + writeBlock(gFormat.format(53), gMotionModal.format(0), "Z" + zFormat.format(getProperty("g53HomePositionZ"))); // retract + if (getProperty("gotSecondarySpindle")) { + var b = getSection(0).spindle == SPINDLE_PRIMARY ? 0 : getProperty("g53WorkPositionSub"); + writeBlock(gFormat.format(53), gMotionModal.format(0), "B" + spatialFormat.format(b)); // retract Sub Spindle if applicable + } + + // automatically eject part at end of program + if (getProperty("autoEject")) { + ejectRoutine = true; + } +/* + if (getProperty("useM97")) { + for (var i = 0; i < getNumberOfSections(); ++i) { + var section = getSection(i); + writeBlock(mFormat.format(97), pFormat.format(section.getId() + getProperty("sequenceNumberStart")), conditional(section.hasParameter("operation-comment"), "(" + section.getParameter("operation-comment") + ")")); + } + writeBlock(mFormat.format(30)); + if (getProperty("showSequenceNumbers") && getProperty("useM97")) { + error(localize("Properties 'showSequenceNumbers' and 'useM97' cannot be active together at the same time.")); + return; + } + } +*/ +} + +function onComment(message) { + writeComment(message); +} + +/** Force output of X, Y, and Z. */ +function forceXYZ() { + xOutput.reset(); + yOutput.reset(); + zOutput.reset(); +} + +/** Force output of A, B, and C. */ +function forceABC() { + aOutput.reset(); + bOutput.reset(); + cOutput.reset(); +} + +function forceFeed() { + currentFeedId = undefined; + previousDPMFeed = 0; + feedOutput.reset(); +} + +/** Force output of X, Y, Z, A, B, C, and F on next output. */ +function forceAny() { + forceXYZ(); + forceABC(); + forceFeed(); +} + +function writeG187() { + if ((hasParameter("operation-strategy") && (getParameter("operation-strategy") == "drill")) || !machineState.liveToolIsActive) { + writeBlock(gFormat.format(187)); // reset G187 setting to machine default + } else if (hasParameter("operation:tolerance")) { + var tolerance = Math.max(getParameter("operation:tolerance"), 0); + if (tolerance > 0) { + var stockToLeaveThreshold = toUnit(0.1, MM); + var stockToLeave = 0; + var verticalStockToLeave = 0; + if (hasParameter("operation:stockToLeave")) { + stockToLeave = spatialFormat.getResultingValue(getParameter("operation:stockToLeave")); + } + if (hasParameter("operation:verticalStockToLeave")) { + verticalStockToLeave = spatialFormat.getResultingValue(getParameter("operation:verticalStockToLeave")); + } + + var workMode; + if (((stockToLeave > stockToLeaveThreshold) && (verticalStockToLeave > stockToLeaveThreshold)) || + (hasParameter("operation:strategy") && getParameter("operation:strategy") == "face")) { + workMode = 1; // roughing + } else { + if ((stockToLeave > 0) || (verticalStockToLeave > 0)) { + workMode = 2; // default + } else { + workMode = 3; // fine + } + } + writeBlock(gFormat.format(187), "P" + workMode); // set tolerance mode + // writeBlock(gFormat.format(187), "P" + workMode, "E" + spatialFormat.format(tolerance)); // set tolerance mode + } else { + writeBlock(gFormat.format(187)); // reset G187 setting to machine default + } + } else { + writeBlock(gFormat.format(187)); // reset G187 setting to machine default + } +} + +function FeedContext(id, description, feed) { + this.id = id; + this.description = description; + this.feed = feed; +} + +function getFeed(f) { + if (activeMovements) { + var feedContext = activeMovements[movement]; + if (feedContext != undefined) { + if (!feedFormat.areDifferent(feedContext.feed, f)) { + if (feedContext.id == currentFeedId) { + return ""; // nothing has changed + } + forceFeed(); + currentFeedId = feedContext.id; + return "F#" + (firstFeedParameter + feedContext.id); + } + } + currentFeedId = undefined; // force Q feed next time + } + return feedOutput.format(f); // use feed value +} + +function initializeActiveFeeds() { + activeMovements = new Array(); + var movements = currentSection.getMovements(); + var feedPerRev = currentSection.feedMode == FEED_PER_REVOLUTION; + + var id = 0; + var activeFeeds = new Array(); + if (hasParameter("operation:tool_feedCutting")) { + if (movements & ((1 << MOVEMENT_CUTTING) | (1 << MOVEMENT_LINK_TRANSITION) | (1 << MOVEMENT_EXTENDED))) { + var feedContext = new FeedContext(id, localize("Cutting"), feedPerRev ? getParameter("operation:tool_feedCuttingRel") : getParameter("operation:tool_feedCutting")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_CUTTING] = feedContext; + activeMovements[MOVEMENT_LINK_TRANSITION] = feedContext; + activeMovements[MOVEMENT_EXTENDED] = feedContext; + } + ++id; + if (movements & (1 << MOVEMENT_PREDRILL)) { + feedContext = new FeedContext(id, localize("Predrilling"), feedPerRev ? getParameter("operation:tool_feedCuttingRel") : getParameter("operation:tool_feedCutting")); + activeMovements[MOVEMENT_PREDRILL] = feedContext; + activeFeeds.push(feedContext); + } + ++id; + } + + if (hasParameter("operation:finishFeedrate")) { + if (movements & (1 << MOVEMENT_FINISH_CUTTING)) { + var finishFeedrateRel; + if (hasParameter("operation:finishFeedrateRel")) { + finishFeedrateRel = getParameter("operation:finishFeedrateRel"); + } else if (hasParameter("operation:finishFeedratePerRevolution")) { + finishFeedrateRel = getParameter("operation:finishFeedratePerRevolution"); + } + var feedContext = new FeedContext(id, localize("Finish"), feedPerRev ? finishFeedrateRel : getParameter("operation:finishFeedrate")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_FINISH_CUTTING] = feedContext; + } + ++id; + } else if (hasParameter("operation:tool_feedCutting")) { + if (movements & (1 << MOVEMENT_FINISH_CUTTING)) { + var feedContext = new FeedContext(id, localize("Finish"), feedPerRev ? getParameter("operation:tool_feedCuttingRel") : getParameter("operation:tool_feedCutting")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_FINISH_CUTTING] = feedContext; + } + ++id; + } + + if (hasParameter("operation:tool_feedEntry")) { + if (movements & (1 << MOVEMENT_LEAD_IN)) { + var feedContext = new FeedContext(id, localize("Entry"), feedPerRev ? getParameter("operation:tool_feedEntryRel") : getParameter("operation:tool_feedEntry")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_LEAD_IN] = feedContext; + } + ++id; + } + + if (hasParameter("operation:tool_feedExit")) { + if (movements & (1 << MOVEMENT_LEAD_OUT)) { + var feedContext = new FeedContext(id, localize("Exit"), feedPerRev ? getParameter("operation:tool_feedExitRel") : getParameter("operation:tool_feedExit")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_LEAD_OUT] = feedContext; + } + ++id; + } + + if (hasParameter("operation:noEngagementFeedrate")) { + if (movements & (1 << MOVEMENT_LINK_DIRECT)) { + var feedContext = new FeedContext(id, localize("Direct"), feedPerRev ? getParameter("operation:noEngagementFeedrateRel") : getParameter("operation:noEngagementFeedrate")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_LINK_DIRECT] = feedContext; + } + ++id; + } else if (hasParameter("operation:tool_feedCutting") && + hasParameter("operation:tool_feedEntry") && + hasParameter("operation:tool_feedExit")) { + if (movements & (1 << MOVEMENT_LINK_DIRECT)) { + var feedContext = new FeedContext( + id, + localize("Direct"), + Math.max( + feedPerRev ? getParameter("operation:tool_feedCuttingRel") : getParameter("operation:tool_feedCutting"), + feedPerRev ? getParameter("operation:tool_feedEntryRel") : getParameter("operation:tool_feedEntry"), + feedPerRev ? getParameter("operation:tool_feedExitRel") : getParameter("operation:tool_feedExit") + ) + ); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_LINK_DIRECT] = feedContext; + } + ++id; + } + + if (hasParameter("operation:reducedFeedrate")) { + if (movements & (1 << MOVEMENT_REDUCED)) { + var feedContext = new FeedContext(id, localize("Reduced"), feedPerRev ? getParameter("operation:reducedFeedrateRel") : getParameter("operation:reducedFeedrate")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_REDUCED] = feedContext; + } + ++id; + } + + if (hasParameter("operation:tool_feedRamp")) { + if (movements & ((1 << MOVEMENT_RAMP) | (1 << MOVEMENT_RAMP_HELIX) | (1 << MOVEMENT_RAMP_PROFILE) | (1 << MOVEMENT_RAMP_ZIG_ZAG))) { + var feedContext = new FeedContext(id, localize("Ramping"), feedPerRev ? getParameter("operation:tool_feedRampRel") : getParameter("operation:tool_feedRamp")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_RAMP] = feedContext; + activeMovements[MOVEMENT_RAMP_HELIX] = feedContext; + activeMovements[MOVEMENT_RAMP_PROFILE] = feedContext; + activeMovements[MOVEMENT_RAMP_ZIG_ZAG] = feedContext; + } + ++id; + } + if (hasParameter("operation:tool_feedPlunge")) { + if (movements & (1 << MOVEMENT_PLUNGE)) { + var feedContext = new FeedContext(id, localize("Plunge"), feedPerRev ? getParameter("operation:tool_feedPlungeRel") : getParameter("operation:tool_feedPlunge")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_PLUNGE] = feedContext; + } + ++id; + } + if (true) { // high feed + if (movements & (1 << MOVEMENT_HIGH_FEED)) { + var feedContext = new FeedContext(id, localize("High Feed"), this.highFeedrate); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_HIGH_FEED] = feedContext; + } + ++id; + } + + for (var i = 0; i < activeFeeds.length; ++i) { + var feedContext = activeFeeds[i]; + writeBlock("#" + (firstFeedParameter + feedContext.id) + "=" + feedFormat.format(feedContext.feed), formatComment(feedContext.description)); + } +} + +var currentWorkPlaneABC = undefined; + +function forceWorkPlane() { + currentWorkPlaneABC = undefined; +} + +function setWorkPlane(abc) { + if (!machineConfiguration.isMultiAxisConfiguration()) { + return; // ignore + } + + var _skipBlock = false; + if (!((currentWorkPlaneABC == undefined) || + abcFormat.areDifferent(abc.x, currentWorkPlaneABC.x) || + abcFormat.areDifferent(abc.y, currentWorkPlaneABC.y) || + abcFormat.areDifferent(abc.z, currentWorkPlaneABC.z))) { + if (operationNeedsSafeStart) { + _skipBlock = true; + } else { + return; // no change + } + } + + skipBlock = _skipBlock; + onCommand(COMMAND_UNLOCK_MULTI_AXIS); + gMotionModal.reset(); + + skipBlock = _skipBlock; + writeBlock( + gMotionModal.format(0), + conditional(machineConfiguration.isMachineCoordinate(0), aOutput.format(abc.x)), + conditional(machineConfiguration.isMachineCoordinate(1), bOutput.format(getB(abc, currentSection))), + conditional(machineConfiguration.isMachineCoordinate(2), cOutput.format(abc.z)) + ); + + if (!currentSection.isMultiAxis() && !machineState.usePolarMode && !machineState.useXZCMode) { + skipBlock = _skipBlock; + onCommand(COMMAND_LOCK_MULTI_AXIS); + currentWorkPlaneABC = abc; + } else { + forceWorkPlane(); + } +} + +function getBestABCIndex(section) { + var fitFlag = false; + var index = undefined; + for (var i = 0; i < 6; ++i) { + fitFlag = doesToolpathFitInXYRange(getBestABC(section, i)); + if (fitFlag) { + index = i; + break; + } + } + return index; +} + +function getBestABC(section, which) { + var W = section.workPlane; + var abc = machineConfiguration.getABC(W); + if (which == undefined) { // turning, XZC, Polar modes + return abc; + } + if (Vector.dot(machineConfiguration.getAxisU().getAxis(), new Vector(0, 0, 1)) != 0) { + var axis = machineConfiguration.getAxisU(); // C-axis is the U-axis + } else { + var axis = machineConfiguration.getAxisV(); // C-axis is the V-axis + } + if (axis.isEnabled() && axis.isTable()) { + var ix = axis.getCoordinate(); + var rotAxis = axis.getAxis(); + if (isSameDirection(machineConfiguration.getDirection(abc), rotAxis) || + isSameDirection(machineConfiguration.getDirection(abc), Vector.product(rotAxis, -1))) { + var direction = isSameDirection(machineConfiguration.getDirection(abc), rotAxis) ? 1 : -1; + var box = section.getGlobalBoundingBox(); + switch (which) { + case 1: + x = box.lower.x + ((box.upper.x - box.lower.x) / 2); + y = box.lower.y + ((box.upper.y - box.lower.y) / 2); + break; + case 2: + x = box.lower.x; + y = box.lower.y; + break; + case 3: + x = box.upper.x; + y = box.lower.y; + break; + case 4: + x = box.upper.x; + y = box.upper.y; + break; + case 5: + x = box.lower.x; + y = box.upper.y; + break; + default: + var R = machineConfiguration.getRemainingOrientation(abc, W); + x = R.right.x; + y = R.right.y; + break; + } + abc.setCoordinate(ix, getCClosest(x, y, cOutput.getCurrent())); + } + } + // writeComment("Which = " + which + " Angle = " + abc.z) + return abc; +} + +var closestABC = false; // choose closest machine angles +var currentMachineABC; + +function getWorkPlaneMachineABC(section, workPlane) { + var W = workPlane; // map to global frame + + var abc; + if (machineState.isTurningOperation && gotBAxis) { + var both = machineConfiguration.getABCByDirectionBoth(workPlane.forward); + abc = both[0]; + if (both[0].z != 0) { + abc = both[1]; + } + } else { + abc = getBestABC(section, bestABCIndex); + 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 (machineState.isTurningOperation && gotBAxis) { // remapABC can change the B-axis orientation + if (abc.z != 0) { + error(localize("Could not calculate a B-axis turning angle within the range of the machine.")); + return abc; + } + } + + if (!machineConfiguration.isABCSupported(abc)) { + error( + localize("Work plane is not supported") + ":" + + conditional(machineConfiguration.isMachineCoordinate(0), " A" + abcFormat.format(abc.x)) + + conditional(machineConfiguration.isMachineCoordinate(1), " B" + abcFormat.format(abc.y)) + + conditional(machineConfiguration.isMachineCoordinate(2), " C" + abcFormat.format(abc.z)) + ); + } + + if (!machineState.isTurningOperation) { + 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 getBAxisOrientationTurning(section) { + var toolAngle = hasParameter("operation:tool_angle") ? getParameter("operation:tool_angle") : 0; + var toolOrientation = section.toolOrientation; + if (toolAngle && (toolOrientation != 0)) { + error(localize("You cannot use tool angle and tool orientation together in operation " + "\"" + (getParameter("operation-comment")) + "\"")); + } + + var angle = toRad(toolAngle) + toolOrientation; + + var axis = new Vector(0, 1, 0); + var mappedAngle = (currentSection.spindle == SPINDLE_PRIMARY ? (Math.PI / 2 - angle) : (Math.PI / 2 - angle)); + var mappedWorkplane = new Matrix(axis, mappedAngle); + var abc = getWorkPlaneMachineABC(section, mappedWorkplane); + + return abc; +} + +function setSpindleOrientationTurning(section) { + var J; // cutter orientation + var R; // cutting quadrant + var leftHandTool = (hasParameter("operation:tool_hand") && (getParameter("operation:tool_hand") == "L" || getParameter("operation:tool_holderType") == 0)); + if (hasParameter("operation:machineInside")) { + if (getParameter("operation:machineInside") == 0) { + R = currentSection.spindle == SPINDLE_PRIMARY ? 3 : 4; + } else { + R = currentSection.spindle == SPINDLE_PRIMARY ? 2 : 1; + } + } else { + if ((hasParameter("operation-strategy") && (getParameter("operation-strategy") == "turningFace")) || + (hasParameter("operation-strategy") && (getParameter("operation-strategy") == "turningPart"))) { + R = currentSection.spindle == SPINDLE_PRIMARY ? 3 : 4; + } else { + error(subst(localize("Failed to identify spindle orientation for operation \"%1\"."), getOperationComment())); + return; + } + } + if (leftHandTool) { + J = currentSection.spindle == (SPINDLE_PRIMARY ? 2 : 1); + } else { + J = currentSection.spindle == (SPINDLE_PRIMARY ? 1 : 2); + } + writeComment("Post processor is not customized, add code for cutter orientation and cutting quadrant here if needed."); +} + +var bAxisOrientationTurning = new Vector(0, 0, 0); + +function onSection() { + // Detect machine configuration + machineConfiguration = (currentSection.spindle == SPINDLE_PRIMARY) ? machineConfigurationMainSpindle : machineConfigurationSubSpindle; + if (!gotBAxis) { + if (getMachiningDirection(currentSection) == MACHINING_DIRECTION_AXIAL && !currentSection.isMultiAxis()) { + machineConfiguration.setSpindleAxis(new Vector(0, 0, 1)); + } else { + machineConfiguration.setSpindleAxis(new Vector(1, 0, 0)); + } + } else { + machineConfiguration.setSpindleAxis(new Vector(0, 0, 1)); // set the spindle axis depending on B0 orientation + } + + setMachineConfiguration(machineConfiguration); + currentSection.optimizeMachineAnglesByMachine(machineConfiguration, 1); // map tip mode + + var previousTapping = machineState.tapping; + machineState.tapping = hasParameter("operation:cycleType") && + ((getParameter("operation:cycleType") == "tapping") || + (getParameter("operation:cycleType") == "right-tapping") || + (getParameter("operation:cycleType") == "left-tapping") || + (getParameter("operation:cycleType") == "tapping-with-chip-breaking")); + + var forceToolAndRetract = optionalSection && !currentSection.isOptional(); + optionalSection = currentSection.isOptional(); + bestABCIndex = undefined; + + machineState.isTurningOperation = (currentSection.getType() == TYPE_TURNING); + if (machineState.isTurningOperation && gotBAxis) { + bAxisOrientationTurning = getBAxisOrientationTurning(currentSection); + } + partCutoff = hasParameter("operation-strategy") && (getParameter("operation-strategy") == "turningPart"); + var insertToolCall = forceToolAndRetract || isFirstSection() || + currentSection.getForceToolChange && currentSection.getForceToolChange() || + (tool.number != getPreviousSection().getTool().number) || + (tool.compensationOffset != getPreviousSection().getTool().compensationOffset) || + (tool.diameterOffset != getPreviousSection().getTool().diameterOffset) || + (tool.lengthOffset != getPreviousSection().getTool().lengthOffset); + insertToolCall = (machineState.stockTransferIsActive && partCutoff) ? false : insertToolCall; // tool is loaded during stock transfer op + + var retracted = false; // specifies that the tool has been retracted to the safe plane + var newSpindle = isFirstSection() || + (getPreviousSection().spindle != currentSection.spindle); + var newWorkOffset = isFirstSection() || + (getPreviousSection().workOffset != currentSection.workOffset); // work offset changes + var newWorkPlane = isFirstSection() || + !isSameDirection(getPreviousSection().getGlobalFinalToolAxis(), currentSection.getGlobalInitialToolAxis()) || + (machineState.isTurningOperation && + abcFormat.areDifferent(bAxisOrientationTurning.x, machineState.currentBAxisOrientationTurning.x) || + abcFormat.areDifferent(bAxisOrientationTurning.y, machineState.currentBAxisOrientationTurning.y) || + abcFormat.areDifferent(bAxisOrientationTurning.z, machineState.currentBAxisOrientationTurning.z)); + + operationNeedsSafeStart = getProperty("safeStartAllOperations") && !isFirstSection(); + + if (insertToolCall || newSpindle || newWorkOffset || newWorkPlane && + (!currentSection.isPatterned() && (!machineState.stockTransferIsActive && !partCutoff))) { + + // retract to safe plane + retracted = true; + if (!isFirstSection()) { + if (insertToolCall) { + onCommand(COMMAND_COOLANT_OFF); + } + writeRetract(currentSection, true); // retract in Z also + } + } + + var yAxisWasEnabled = !machineState.useXZCMode && !machineState.usePolarMode && machineState.liveToolIsActive; + updateMachiningMode(currentSection); // sets the needed machining mode to machineState (usePolarMode, useXZCMode, axialCenterDrilling) + + if (currentSection.getTool().isLiveTool) { + if (!isFirstSection() && + ((getPreviousSection().getTool().isLiveTool() != currentSection.getTool().isLiveTool()) || + (previousTapping && insertToolCall))) { + writeBlock(getCode("STOP_SPINDLE")); + } + } else { + writeBlock(getCode("STOP_SPINDLE")); + } + + /* + if (getProperty("useM97") && !isFirstSection()) { + writeBlock(mFormat.format(99)); + } +*/ + + if (getProperty("useSSV")) { + // ensure SSV is turned off + writeBlock(ssvModal.format(39)); + } + + writeln(""); + + /* + if (getProperty("useM97")) { + writeBlock("N" + spatialFormat.format(currentSection.getId() + getProperty("sequenceNumberStart"))); + } +*/ + + // Consider part cutoff as stockTransfer operation + if (!(machineState.stockTransferIsActive && partCutoff)) { + machineState.stockTransferIsActive = false; + } + + if (hasParameter("operation-comment")) { + var comment = getParameter("operation-comment"); + if (comment) { + writeComment(comment); + } + } + + if (!insertToolCall && operationNeedsSafeStart) { + skipBlock = true; + writeRetract(currentSection, true); // retract in Z also + } + + if (getProperty("showNotes") && hasParameter("notes")) { + var notes = getParameter("notes"); + if (notes) { + var lines = String(notes).split("\n"); + var r1 = new RegExp("^[\\s]+", "g"); + var r2 = new RegExp("[\\s]+$", "g"); + for (line in lines) { + var comment = lines[line].replace(r1, "").replace(r2, ""); + if (comment) { + writeComment(comment); + } + } + } + } + + if (insertToolCall || operationNeedsSafeStart) { + if (insertToolCall) { + forceWorkPlane(); + } + if (!getProperty("optimizeCAxisSelect")) { + cAxisEngageModal.reset(); + } + retracted = insertToolCall; + + if (!isFirstSection() && getProperty("optionalStop")) { + skipBlock = !insertToolCall; + onCommand(COMMAND_OPTIONAL_STOP); + } + + /** Handle multiple turrets. */ + if (gotMultiTurret) { + var activeTurret = tool.turret; + if (activeTurret == 0) { + warning(localize("Turret has not been specified. Using Turret 1 as default.")); + activeTurret = 1; // upper turret as default + } + switch (activeTurret) { + case 1: + // add specific handling for turret 1 + break; + case 2: + // add specific handling for turret 2, normally X-axis is reversed for the lower turret + //xFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true, scale:-1}); // inverted diameter mode + //xOutput = createVariable({prefix:"X"}, xFormat); + break; + default: + error(localize("Turret is not supported.")); + } + } + + if (tool.number > 99) { + warning(localize("Tool number exceeds maximum value.")); + } + + var compensationOffset = tool.isTurningTool() ? tool.compensationOffset : tool.lengthOffset; + if (compensationOffset > 99) { + error(localize("Compensation offset is out of range.")); + return; + } + + if (getProperty("gotSecondarySpindle")) { + switch (currentSection.spindle) { + case SPINDLE_PRIMARY: // main spindle + cFormat = createFormat({decimals:3, forceDecimal:true, scale:DEG}); + cOutput = createVariable({prefix:"C"}, cFormat); + skipBlock = !insertToolCall; + writeBlock(gSpindleModal.format(15)); + if (gotYAxis && g100Mirroring) { + writeBlock(gFormat.format(100), "Y0"); + g100Mirroring = false; + } + g14IsActive = false; + break; + case SPINDLE_SECONDARY: // sub spindle + cFormat = createFormat({decimals:3, forceDecimal:true, scale:-DEG}); + cOutput = createVariable({prefix:"M19 R"}, cFormat); // s/b M119 with G15 + skipBlock = !insertToolCall; + writeBlock(gSpindleModal.format(14)); + if (gotYAxis && !g100Mirroring) { + writeBlock(gFormat.format(101), "Y0"); + g100Mirroring = true; + } + g14IsActive = true; + break; + } + } + + skipBlock = !insertToolCall; + writeBlock("T" + toolFormat.format(tool.number * 100 + compensationOffset)); + if (tool.comment) { + writeComment(tool.comment); + } + + var showToolZMin = false; + if (showToolZMin && (currentSection.getType() == TYPE_MILLING)) { + if (is3D()) { + var numberOfSections = getNumberOfSections(); + var zRange = currentSection.getGlobalZRange(); + var number = tool.number; + for (var i = currentSection.getId() + 1; i < numberOfSections; ++i) { + var section = getSection(i); + if (section.getTool().number != number) { + break; + } + zRange.expandToRange(section.getGlobalZRange()); + } + writeComment(localize("ZMIN") + "=" + zRange.getMinimum()); + } + } + + /* + if (getProperty("preloadTool")) { + var nextTool = getNextTool(tool.number); + if (nextTool) { + var compensationOffset = nextTool.isTurningTool() ? nextTool.compensationOffset : nextTool.lengthOffset; + if (compensationOffset > 99) { + error(localize("Compensation offset is out of range.")); + return; + } + writeBlock("T" + toolFormat.format(nextTool.number * 100 + compensationOffset)); + } else { + // preload first tool + var section = getSection(0); + var firstTool = section.getTool().number; + if (tool.number != firstTool.number) { + var compensationOffset = firstTool.isTurningTool() ? firstTool.compensationOffset : firstTool.lengthOffset; + if (compensationOffset > 99) { + error(localize("Compensation offset is out of range.")); + return; + } + writeBlock("T" + toolFormat.format(firstTool.number * 100 + compensationOffset)); + } + } + } +*/ + } + + if (!machineState.stockTransferIsActive) { + if (machineState.isTurningOperation || machineState.axialCenterDrilling) { + skipBlock = !insertToolCall && (machineState.cAxisIsEngaged != undefined); + writeBlock(conditional(machineState.cAxisIsEngaged || (machineState.cAxisIsEngaged == undefined)), getCode("DISENGAGE_C_AXIS")); + } else { // milling + var engage = (currentSection.spindle == SPINDLE_PRIMARY) && (!machineState.cAxisIsEngaged || machineState.cAxisIsEngaged == undefined); + if (engage) { + var code = getCode("ENGAGE_C_AXIS"); + if (code) { + writeBlock(code); + writeBlock(gMotionModal.format(0), gFormat.format(28), "H" + abcFormat.format(0)); + } + } + } + } + + // command stop for manual tool change, useful for quick change live tools + if ((insertToolCall || operationNeedsSafeStart) && tool.manualToolChange) { + skipBlock = !insertToolCall; + onCommand(COMMAND_STOP); + writeBlock("(" + "MANUAL TOOL CHANGE TO T" + toolFormat.format(tool.number * 100 + compensationOffset) + ")"); + } + + if (newSpindle) { + // select spindle if required + } + + gFeedModeModal.reset(); + if ((currentSection.feedMode == FEED_PER_REVOLUTION) || machineState.tapping || machineState.axialCenterDrilling) { + writeBlock(getCode("FEED_MODE_UNIT_REV")); // unit/rev + } else { + writeBlock(getCode("FEED_MODE_UNIT_MIN")); // unit/min + } + + // Engage tailstock + if (getProperty("useTailStock")) { + if (machineState.axialCenterDrilling || (currentSection.spindle == SPINDLE_SECONDARY) || + (machineState.liveToolIsActive && (getMachiningDirection(currentSection) == MACHINING_DIRECTION_AXIAL))) { + if (currentSection.tailstock) { + warning(localize("Tail stock is not supported for secondary spindle or Z-axis milling.")); + } + if (machineState.tailstockIsActive) { + writeBlock(getCode("TAILSTOCK_OFF")); + } + } else { + writeBlock(currentSection.tailstock ? getCode("TAILSTOCK_ON") : getCode("TAILSTOCK_OFF")); + } + } + + // see page 138 in 96-8700an for stock transfer / G199/G198 + var spindleChange = forceSpindleSpeed || newSpindle || isSpindleSpeedDifferent() || (!machineState.liveToolIsActive && !machineState.mainSpindleIsActive && !machineState.subSpindleIsActive); + if (insertToolCall || operationNeedsSafeStart || + spindleChange || + isFirstSection()) { + if (machineState.isTurningOperation) { + if (spindleSpeed > 99999) { + warning(subst(localize("Spindle speed exceeds maximum value for operation \"%1\"."), getOperationComment())); + } + } else { + if (spindleSpeed > 6000) { + warning(subst(localize("Spindle speed exceeds maximum value for operation \"%1\"."), getOperationComment())); + } + } + skipBlock = !insertToolCall && !spindleChange; + startSpindle(true, getFramePosition(currentSection.getInitialPosition())); + } + + // wcs + if (insertToolCall) { // force work offset when changing tool + currentWorkOffset = undefined; + } + var workOffset = currentSection.workOffset; + writeWCS(currentSection); + + // set coolant after we have positioned at Z + setCoolant(tool.coolant); + + if (currentSection.partCatcher) { + engagePartCatcher(true); + } + + forceAny(); + gMotionModal.reset(); + + gPlaneModal.reset(); + writeBlock(gPlaneModal.format(getPlane())); + + var abc = new Vector(0, 0, 0); + if (machineConfiguration.isMultiAxisConfiguration()) { + if (machineState.isTurningOperation || machineState.axialCenterDrilling) { + if (gotBAxis) { + // TAG: handle B-axis support for turning operations here + writeBlock(gMotionModal.format(0), conditional(machineConfiguration.isMachineCoordinate(1), bOutput.format(getB(bAxisOrientationTurning, currentSection)))); + machineState.currentBAxisOrientationTurning = bAxisOrientationTurning; + //setSpindleOrientationTurning(); + } else { + setRotation(currentSection.workPlane); + } + } else { + if (currentSection.isMultiAxis()) { + forceWorkPlane(); + cancelTransformation(); + onCommand(COMMAND_UNLOCK_MULTI_AXIS); + abc = currentSection.getInitialToolAxisABC(); + } else { + if (machineState.useXZCMode) { + setRotation(currentSection.workPlane); // enables calculation of the C-axis by tool XY-position + abc = new Vector(0, 0, getCWithinRange(getFramePosition(currentSection.getInitialPosition()).x, getFramePosition(currentSection.getInitialPosition()).y, cOutput.getCurrent())); + } else { + abc = getWorkPlaneMachineABC(currentSection, 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 by the CNC machine.")); + return; + } + setRotation(remaining); + } + forceAny(); + if (abc !== undefined) { + if (!currentSection.isMultiAxis()) { + cOutput.format(abc.z); // make C current - we do not want to output here + previousABC.setZ(abc.z); + } + } + + if (machineState.cAxisIsEngaged) { // make sure C-axis in engaged + if (!machineState.usePolarMode && !machineState.useXZCMode && !currentSection.isMultiAxis()) { + onCommand(COMMAND_LOCK_MULTI_AXIS); + } else { + onCommand(COMMAND_UNLOCK_MULTI_AXIS); + } + } + + if (getProperty("useG187")) { + writeG187(); + } + + var initialPosition = getFramePosition(currentSection.getInitialPosition()); + /* + if (!retracted) { + // TAG: need to retract along X or Z + if (getCurrentPosition().z < initialPosition.z) { + writeBlock(gMotionModal.format(0), zOutput.format(initialPosition.z)); + } + } +*/ + if ((machineState.useXZCMode || machineState.usePolarMode) && yAxisWasEnabled) { + if (gotYAxis && yOutput.isEnabled()) { + writeBlock(gMotionModal.format(0), yOutput.format(0)); + } + } + if (machineState.usePolarMode) { + setPolarMode(true); // enable polar interpolation mode + } + gMotionModal.reset(); + + if (getProperty("useG61")) { + writeBlock(gExactStopModal.format(61)); + } + + if (insertToolCall || retracted || machineState.useXZCMode || (tool.getSpindleMode() == SPINDLE_CONSTANT_SURFACE_SPEED)) { + gMotionModal.reset(); + if (machineState.useXZCMode) { + writeBlock(gMotionModal.format(0), zOutput.format(initialPosition.z)); + writeBlock( + gMotionModal.format(0), + xOutput.format(getModulus(initialPosition.x, initialPosition.y)), + conditional(gotYAxis, yOutput.format(0)), + cOutput.format(getCWithinRange(initialPosition.x, initialPosition.y, cOutput.getCurrent())) + ); + previousABC.setZ(cOutput.getCurrent()); + } else { + writeBlock(gMotionModal.format(0), zOutput.format(initialPosition.z)); + writeBlock(gMotionModal.format(0), xOutput.format(initialPosition.x), yOutput.format(initialPosition.y)); + } + } + + // enable SFM spindle speed + if (tool.getSpindleMode() == SPINDLE_CONSTANT_SURFACE_SPEED) { + startSpindle(false); + } + + if (getProperty("useParametricFeed") && + hasParameter("operation-strategy") && + (getParameter("operation-strategy") != "drill") && // legacy + !(currentSection.hasAnyCycle && currentSection.hasAnyCycle()) && + !machineState.useXZCMode) { + if (!insertToolCall && + activeMovements && + (getCurrentSectionId() > 0) && + ((getPreviousSection().getPatternId() == currentSection.getPatternId()) && (currentSection.getPatternId() != 0))) { + // use the current feeds + } else { + initializeActiveFeeds(); + } + } else { + activeMovements = undefined; + } + + if (false) { // DEBUG + for (var key in machineState) { + writeComment(key + " : " + machineState[key]); + } + // writeComment((getMachineConfigurationAsText(machineConfiguration))); + } +} + +function getPlane() { + if (getMachiningDirection(currentSection) == MACHINING_DIRECTION_AXIAL) { // axial + if (machineState.useXZCMode || + (currentSection.hasParameter("operation-strategy") && (currentSection.getParameter("operation-strategy") == "drill")) || + machineState.isTurningOperation) { + return 18; + } else { + return 17; // G112 and XY milling only + } + } else if (getMachiningDirection(currentSection) == MACHINING_DIRECTION_RADIAL) { // radial + return 19; // YZ plane + } else { + error(subst(localize("Unsupported machining direction for operation " + "\"" + "%1" + "\"" + "."), getOperationComment())); + return undefined; + } +} + +/** Returns true if the toolpath fits within the machine XY limits for the given C orientation. */ +function doesToolpathFitInXYRange(abc) { + var xMin = xAxisMinimum * Math.abs(xFormat.getScale()); + var yMin = yAxisMinimum * Math.abs(yFormat.getScale()); + var yMax = yAxisMaximum * Math.abs(yFormat.getScale()); + var c = 0; + if (abc) { + c = abc.z; + } + if (Vector.dot(machineConfiguration.getAxisU().getAxis(), new Vector(0, 0, 1)) != 0) { + c *= (machineConfiguration.getAxisU().getAxis().getCoordinate(2) >= 0) ? 1 : -1; // C-axis is the U-axis + } else { + c *= (machineConfiguration.getAxisV().getAxis().getCoordinate(2) >= 0) ? 1 : -1; // C-axis is the V-axis + } + + var dx = new Vector(Math.cos(c), Math.sin(c), 0); + var dy = new Vector(Math.cos(c + Math.PI / 2), Math.sin(c + Math.PI / 2), 0); + + if (currentSection.getGlobalRange) { + var xRange = currentSection.getGlobalRange(dx); + var yRange = currentSection.getGlobalRange(dy); + + if (false) { // DEBUG + writeComment( + "toolpath X minimum= " + xFormat.format(xRange[0]) + ", " + "Limit= " + xMin + ", " + + "within range= " + (xFormat.getResultingValue(xRange[0]) >= xMin) + ); + writeComment( + "toolpath Y minimum= " + yFormat.getResultingValue(yRange[0]) + ", " + "Limit= " + yMin + ", " + + "within range= " + (yFormat.getResultingValue(yRange[0]) >= yMin) + ); + writeComment( + "toolpath Y maximum= " + (yFormat.getResultingValue(yRange[1]) + ", " + "Limit= " + yMax) + ", " + + "within range= " + (yFormat.getResultingValue(yRange[1]) <= yMax) + ); + writeln(""); + } + + if (getMachiningDirection(currentSection) == MACHINING_DIRECTION_RADIAL) { // G19 plane + if ((yFormat.getResultingValue(yRange[0]) >= yMin) && + (yFormat.getResultingValue(yRange[1]) <= yMax)) { + return true; // toolpath does fit in XY range + } else { + return false; // toolpath does not fit in XY range + } + } else { // G17 plane + if ((xFormat.getResultingValue(xRange[0]) >= xMin) && + (yFormat.getResultingValue(yRange[0]) >= yMin) && + (yFormat.getResultingValue(yRange[1]) <= yMax)) { + return true; // toolpath does fit in XY range + } else { + return false; // toolpath does not fit in XY range + } + } + } else { + if (revision < 40000) { + warning(localize("Please update to the latest release to allow XY linear interpolation instead of polar interpolation.")); + } + return false; // for older versions without the getGlobalRange() function + } +} + +var MACHINING_DIRECTION_AXIAL = 0; +var MACHINING_DIRECTION_RADIAL = 1; +var MACHINING_DIRECTION_INDEXING = 2; + +function getMachiningDirection(section) { + var forward = section.isMultiAxis() ? section.getGlobalInitialToolAxis() : section.workPlane.forward; + if (isSameDirection(forward, new Vector(0, 0, 1))) { + machineState.machiningDirection = MACHINING_DIRECTION_AXIAL; + return MACHINING_DIRECTION_AXIAL; + } else if (Vector.dot(forward, new Vector(0, 0, 1)) < 1e-7) { + machineState.machiningDirection = MACHINING_DIRECTION_RADIAL; + return MACHINING_DIRECTION_RADIAL; + } else { + machineState.machiningDirection = MACHINING_DIRECTION_INDEXING; + return MACHINING_DIRECTION_INDEXING; + } +} + +function updateMachiningMode(section) { + machineState.axialCenterDrilling = false; // reset + machineState.usePolarMode = false; // reset + machineState.useXZCMode = false; // reset + + if ((section.getType() == TYPE_MILLING) && !section.isMultiAxis()) { + if (getMachiningDirection(section) == MACHINING_DIRECTION_AXIAL) { + if (section.hasParameter("operation-strategy") && (section.getParameter("operation-strategy") == "drill")) { + // drilling axial + if ((section.getNumberOfCyclePoints() == 1) && + !xFormat.isSignificant(getGlobalPosition(section.getInitialPosition()).x) && + !yFormat.isSignificant(getGlobalPosition(section.getInitialPosition()).y) && + (spatialFormat.format(section.getFinalPosition().x) == 0) && + !doesCannedCycleIncludeYAxisMotion(section)) { // catch drill issue for old versions + // single hole on XY center + if (section.getTool().isLiveTool && section.getTool().isLiveTool()) { + // use live tool + } else { + // use main spindle for axialCenterDrilling + machineState.axialCenterDrilling = true; + } + } else { // several holes not on XY center + bestABCIndex = getBestABCIndex(section); + if (getProperty("useYAxisForDrilling") && (bestABCIndex != undefined) && !doesCannedCycleIncludeYAxisMotion(section)) { + // use XYZ-mode + } else { // use XZC mode + machineState.useXZCMode = true; + } + } + } else { // milling + bestABCIndex = getBestABCIndex(section); + if (bestABCIndex != undefined) { + if (forcePolarMode) { // polar mode is requested by user + if (currentSection.spindle == SPINDLE_SECONDARY) { + error(localize("Polar mode is not supported on the secondary spindle.")); + } + machineState.usePolarMode = true; + bestABCIndex = undefined; + } else { + // toolpath matches XY ranges, keep false + } + } else { + // toolpath does not match XY ranges, enable interpolation mode + if (getProperty("useG112") || forcePolarMode) { + if (currentSection.spindle == SPINDLE_SECONDARY) { + error(localize("Polar mode is not supported on the secondary spindle.")); + } + machineState.usePolarMode = true; + } else { + machineState.useXZCMode = true; + } + } + } + } else if (getMachiningDirection(section) == MACHINING_DIRECTION_RADIAL) { // G19 plane + if (!gotYAxis) { + if (!section.isMultiAxis() && (!doesToolpathFitInXYRange(machineConfiguration.getABC(section.workPlane)) || doesCannedCycleIncludeYAxisMotion(section))) { + error(subst(localize("Y-axis motion is not possible without a Y-axis for operation \"%1\"."), getOperationComment())); + return; + } + } else { + if (!doesToolpathFitInXYRange(machineConfiguration.getABC(section.workPlane))) { + error(subst(localize("Toolpath exceeds the maximum ranges for operation \"%1\"."), getOperationComment())); + return; + } + } + // C-coordinates come from setWorkPlane or is within a multi axis operation, we cannot use the C-axis for non wrapped toolpathes (only multiaxis works, all others have to be into XY range) + } else { + // useXZCMode & usePolarMode is only supported for axial machining, keep false + } + } else { + // turning or multi axis, keep false + } + + if (machineState.axialCenterDrilling) { + cOutput.disable(); + } else { + cOutput.enable(); + } + + var checksum = 0; + checksum += machineState.usePolarMode ? 1 : 0; + checksum += machineState.useXZCMode ? 1 : 0; + checksum += machineState.axialCenterDrilling ? 1 : 0; + validate(checksum <= 1, localize("Internal post processor error.")); +} + +function doesCannedCycleIncludeYAxisMotion(section) { + // these cycles have Y axis motions which are not detected by getGlobalRange() + var hasYMotion = false; + if (section.hasParameter("operation:strategy") && (section.getParameter("operation:strategy") == "drill")) { + switch (section.getParameter("operation:cycleType")) { + case "thread-milling": + case "bore-milling": + case "circular-pocket-milling": + hasYMotion = true; // toolpath includes Y-axis motion + break; + case "back-boring": + case "fine-boring": + var shift = getParameter("operation:boringShift"); + if (shift != spatialFormat.format(0)) { + hasYMotion = true; // toolpath includes Y-axis motion + } + break; + default: + hasYMotion = false; // all other cycles don´t have Y-axis motion + } + } + return hasYMotion; +} + +function getOperationComment() { + var operationComment = hasParameter("operation-comment") && getParameter("operation-comment"); + return operationComment; +} + +function setPolarMode(activate) { + if (activate) { + writeBlock(gMotionModal.format(0), cOutput.format(0)); // set C-axis to 0 to avoid G112 issues + writeBlock(getCode("POLAR_INTERPOLATION_ON")); // command for polar interpolation + writeBlock(gPlaneModal.format(getPlane())); + validate(gPlaneModal.getCurrent() == 17, localize("Internal post processor error.")); // make sure that G17 is active + xFormat.setScale(1); // radius mode + xOutput = createVariable({prefix:"X"}, xFormat); + yOutput.enable(); // required for G112 + } else { + writeBlock(getCode("POLAR_INTERPOLATION_OFF")); + xFormat.setScale(2); // diameter mode + xOutput = createVariable({prefix:"X"}, xFormat); + if (!gotYAxis) { + yOutput.disable(); + } + } +} + +function onDwell(seconds) { + if (seconds > 99999.999) { + warning(localize("Dwelling time is out of range.")); + } + milliseconds = clamp(1, seconds * 1000, 99999999); + writeBlock(gFormat.format(4), "P" + milliFormat.format(milliseconds)); +} + +var pendingRadiusCompensation = -1; + +function onRadiusCompensation() { + pendingRadiusCompensation = radiusCompensation; +} + +var resetFeed = false; + +function getHighfeedrate(radius) { + if (currentSection.feedMode == FEED_PER_REVOLUTION) { + if (toDeg(radius) <= 0) { + radius = toPreciseUnit(0.1, MM); + } + var rpm = spindleSpeed; // rev/min + if (currentSection.getTool().getSpindleMode() == SPINDLE_CONSTANT_SURFACE_SPEED) { + var O = 2 * Math.PI * radius; // in/rev + rpm = tool.surfaceSpeed / O; // in/min div in/rev => rev/min + } + return highFeedrate / rpm; // in/min div rev/min => in/rev + } + return highFeedrate; +} + +function onRapid(_x, _y, _z) { + // don't output starts for threading + if (threadNumber > 0) { + return; + } + if (machineState.useXZCMode) { + var start = getCurrentPosition(); + var dxy = getModulus(_x - start.x, _y - start.y); + if (true || (dxy < getTolerance())) { + var x = xOutput.format(getModulus(_x, _y)); + var c = cOutput.format(getCWithinRange(_x, _y, cOutput.getCurrent())); + var z = zOutput.format(_z); + if (pendingRadiusCompensation >= 0) { + error(localize("Radius compensation mode cannot be changed at rapid traversal.")); + return; + } + if (forceRewind) { + rewindTable(start, _z, cOutput.getCurrent(), highFeedrate, false); + } + if (currentSection.spindle == SPINDLE_SECONDARY) { + writeBlock(gMotionModal.format(0), c); + writeBlock(gMotionModal.format(0), x, z); + } else { + writeBlock(gMotionModal.format(0), x, c, z); + } + previousABC.setZ(cOutput.getCurrent()); + forceFeed(); + return; + } + + onExpandedLinear(_x, _y, _z, highFeedrate); + return; + } + + var x = xOutput.format(_x); + var y = yOutput.format(_y); + var z = zOutput.format(_z); + if (x || y || z) { + var useG1 = ((x ? 1 : 0) + (y ? 1 : 0) + (z ? 1 : 0)) > 1 && !isCannedCycle; + if (pendingRadiusCompensation >= 0) { + pendingRadiusCompensation = -1; + + if (useG1) { + switch (radiusCompensation) { + case RADIUS_COMPENSATION_LEFT: + writeBlock(gMotionModal.format(1), gFormat.format(41), x, y, z, getFeed(getHighfeedrate(_x))); + break; + case RADIUS_COMPENSATION_RIGHT: + writeBlock(gMotionModal.format(1), gFormat.format(42), x, y, z, getFeed(getHighfeedrate(_x))); + break; + default: + writeBlock(gMotionModal.format(1), gFormat.format(40), x, y, z, getFeed(getHighfeedrate(_x))); + } + } else { + switch (radiusCompensation) { + case RADIUS_COMPENSATION_LEFT: + writeBlock(gMotionModal.format(0), gFormat.format(41), x, y, z); + break; + case RADIUS_COMPENSATION_RIGHT: + writeBlock(gMotionModal.format(0), gFormat.format(42), x, y, z); + break; + default: + writeBlock(gMotionModal.format(0), gFormat.format(40), x, y, z); + } + } + } + if (false) { + // axes are not synchronized + writeBlock(gMotionModal.format(1), x, y, z, getFeed(getHighfeedrate(_x))); + resetFeed = false; + } else { + writeBlock(gMotionModal.format(0), x, y, z); + forceFeed(); + } + } +} + +/** Calculate the distance of a point to a line segment. */ +function pointLineDistance(startPt, endPt, testPt) { + var delta = Vector.diff(endPt, startPt); + distance = Math.abs(delta.y * testPt.x - delta.x * testPt.y + endPt.x * startPt.y - endPt.y * startPt.x) / + Math.sqrt(delta.y * delta.y + delta.x * delta.x); // distance from line to point + if (distance < 1e-4) { // make sure point is in line segment + var moveLength = Vector.diff(endPt, startPt).length; + var startLength = Vector.diff(startPt, testPt).length; + var endLength = Vector.diff(endPt, testPt).length; + if ((startLength > moveLength) || (endLength > moveLength)) { + distance = Math.min(startLength, endLength); + } + } + return distance; +} + +/** Refine segment for XC mapping. */ +function refineSegmentXC(startX, startC, endX, endC, maximumDistance) { + var rotary = machineConfiguration.getAxisU(); // C-axis + var startPt = rotary.getAxisRotation(startC).multiply(new Vector(startX, 0, 0)); + var endPt = rotary.getAxisRotation(endC).multiply(new Vector(endX, 0, 0)); + + var testX = startX + (endX - startX) / 2; // interpolate as the machine + var testC = startC + (endC - startC) / 2; + var testPt = rotary.getAxisRotation(testC).multiply(new Vector(testX, 0, 0)); + + var delta = Vector.diff(endPt, startPt); + var distf = pointLineDistance(startPt, endPt, testPt); + + if (distf > maximumDistance) { + return false; // out of tolerance + } else { + return true; + } +} + +function rewindTable(startXYZ, currentZ, rewindC, feed, retract) { + if (!cFormat.areDifferent(rewindC, cOutput.getCurrent())) { + error(localize("Rewind position not found.")); + return; + } + writeComment("Rewind of C-axis, make sure retracting is possible."); + onCommand(COMMAND_STOP); + if (retract) { + writeBlock(gMotionModal.format(1), zOutput.format(currentSection.getInitialPosition().z), getFeed(feed)); + } + writeBlock(getCode("DISENGAGE_C_AXIS")); + writeBlock(getCode("ENGAGE_C_AXIS")); + gMotionModal.reset(); + xOutput.reset(); + startSpindle(false); + if (retract) { + var x = getModulus(startXYZ.x, startXYZ.y); + if (getProperty("rapidRewinds")) { + writeBlock(gMotionModal.format(1), xOutput.format(x), getFeed(highFeedrate)); + writeBlock(gMotionModal.format(0), cOutput.format(rewindC)); + } else { + writeBlock(gMotionModal.format(1), xOutput.format(x), cOutput.format(rewindC), getFeed(highFeedrate)); + } + writeBlock(gMotionModal.format(1), zOutput.format(startXYZ.z), getFeed(feed)); + } + setCoolant(tool.coolant); + forceRewind = false; + writeComment("End of rewind"); +} + +function onLinear(_x, _y, _z, feed) { + // don't output starts for threading + if (threadNumber > 0) { + return; + } + if (machineState.useXZCMode) { + if (currentSection.spindle == SPINDLE_SECONDARY) { + if ((hasParameter("operation:strategy") && (getParameter("operation:strategy") == "drill") && !doesCannedCycleIncludeYAxisMotion(currentSection))) { + // allow drilling in XZC-mode + } else { + error(localize("XZC-mode is not supported on the secondary spindle.")); + } + } + if (pendingRadiusCompensation >= 0) { + error(subst(localize("Radius compensation is not supported for operation \"%1\". You have to use G112 mode for radius compensation."), getOperationComment())); + return; + } + if (maximumCircularSweep > toRad(179)) { + error(localize("Maximum circular sweep must be below 179 degrees.")); + return; + } + + var localTolerance = getTolerance() / 4; + + var startXYZ = getCurrentPosition(); + var startX = getModulus(startXYZ.x, startXYZ.y); + var startZ = startXYZ.z; + var startC = cOutput.getCurrent(); + + var endXYZ = new Vector(_x, _y, _z); + var endX = getModulus(endXYZ.x, endXYZ.y); + var endZ = endXYZ.z; + var endC = getCWithinRange(endXYZ.x, endXYZ.y, startC); + + var currentXYZ = endXYZ; var currentX = endX; var currentZ = endZ; var currentC = endC; + var centerXYZ = machineConfiguration.getAxisU().getOffset(); + + var refined = true; + var crossingRotary = false; + forceOptimized = false; // tool tip is provided to DPM calculations + while (refined) { // stop if we dont refine + // check if we cross center of rotary axis + var _start = new Vector(startXYZ.x, startXYZ.y, 0); + var _current = new Vector(currentXYZ.x, currentXYZ.y, 0); + var _center = new Vector(centerXYZ.x, centerXYZ.y, 0); + if ((xFormat.getResultingValue(pointLineDistance(_start, _current, _center)) == 0) && + (xFormat.getResultingValue(Vector.diff(_start, _center).length) != 0) && + (xFormat.getResultingValue(Vector.diff(_current, _center).length) != 0)) { + var ratio = Vector.diff(_center, _start).length / Vector.diff(_current, _start).length; + currentXYZ = centerXYZ; + currentXYZ.z = startZ + (endZ - startZ) * ratio; + currentX = getModulus(currentXYZ.x, currentXYZ.y); + currentZ = currentXYZ.z; + currentC = startC; + crossingRotary = true; + } else { // check if move is out of tolerance + refined = false; + while (!refineSegmentXC(startX, startC, currentX, currentC, localTolerance)) { // move is out of tolerance + refined = true; + currentXYZ = Vector.lerp(startXYZ, currentXYZ, 0.75); + currentX = getModulus(currentXYZ.x, currentXYZ.y); + currentZ = currentXYZ.z; + currentC = getCWithinRange(currentXYZ.x, currentXYZ.y, startC); + if (Vector.diff(startXYZ, currentXYZ).length < 1e-5) { // back to start point, output error + if (forceRewind) { + break; + } else { + warning(localize("Linear move cannot be mapped to rotary XZC motion.")); + break; + } + } + } + } + + currentC = getCWithinRange(currentXYZ.x, currentXYZ.y, startC); + if (forceRewind) { + var rewindC = getCClosest(startXYZ.x, startXYZ.y, currentC); + xOutput.reset(); // force X for repositioning + rewindTable(startXYZ, currentZ, rewindC, feed, true); + previousABC.setZ(rewindC); + } + var x = xOutput.format(currentX); + var c = cOutput.format(currentC); + var z = zOutput.format(currentZ); + var actualFeed = getMultiaxisFeed(currentXYZ.x, currentXYZ.y, currentXYZ.z, 0, 0, currentC, feed); + if (x || c || z) { + writeBlock(gMotionModal.format(1), x, c, z, getFeed(actualFeed.frn)); + } + setCurrentPosition(currentXYZ); + previousABC.setZ(currentC); + if (crossingRotary) { + writeBlock(gMotionModal.format(1), cOutput.format(endC), getFeed(feed)); // rotate at X0 with endC + previousABC.setZ(endC); + forceFeed(); + } + startX = currentX; startZ = currentZ; startC = crossingRotary ? endC : currentC; startXYZ = currentXYZ; // loop start point + currentX = endX; currentZ = endZ; currentC = endC; currentXYZ = endXYZ; // loop end point + crossingRotary = false; + } + forceOptimized = undefined; + return; + } + + if (isSpeedFeedSynchronizationActive()) { + resetFeed = true; + var threadPitch = getParameter("operation:threadPitch"); + var threadsPerInch = 1.0 / threadPitch; // per mm for metric + writeBlock(gMotionModal.format(32), xOutput.format(_x), yOutput.format(_y), zOutput.format(_z), pitchOutput.format(1 / threadsPerInch)); + return; + } + if (resetFeed) { + resetFeed = false; + forceFeed(); + } + var x = xOutput.format(_x); + var y = yOutput.format(_y); + var z = zOutput.format(_z); + var f = ((currentSection.feedMode != FEED_PER_REVOLUTION) && machineState.feedPerRevolution) ? feedOutput.format(feed / spindleSpeed) : getFeed(feed); + if (x || y || z) { + if (pendingRadiusCompensation >= 0) { + pendingRadiusCompensation = -1; + writeBlock(gPlaneModal.format(getPlane())); + if (getMachiningDirection(currentSection) == MACHINING_DIRECTION_INDEXING) { + error(localize("Tool orientation is not supported for radius compensation.")); + return; + } + switch (radiusCompensation) { + case RADIUS_COMPENSATION_LEFT: + writeBlock(gMotionModal.format(isSpeedFeedSynchronizationActive() ? 32 : 1), gFormat.format(41), x, y, z, f); + break; + case RADIUS_COMPENSATION_RIGHT: + writeBlock(gMotionModal.format(isSpeedFeedSynchronizationActive() ? 32 : 1), gFormat.format(42), x, y, z, f); + break; + default: + writeBlock(gMotionModal.format(isSpeedFeedSynchronizationActive() ? 32 : 1), gFormat.format(40), x, y, z, f); + } + } else { + writeBlock(gMotionModal.format(isSpeedFeedSynchronizationActive() ? 32 : 1), x, y, z, f); + } + } else if (f) { + if (getNextRecord().isMotion()) { // try not to output feed without motion + forceFeed(); // force feed on next line + } else { + writeBlock(gMotionModal.format(isSpeedFeedSynchronizationActive() ? 32 : 1), f); + } + } +} + +function onRapid5D(_x, _y, _z, _a, _b, _c) { + if (!currentSection.isOptimizedForMachine()) { + error(localize("Multi-axis motion is not supported for XZC mode.")); + return; + } + if (currentSection.spindle == SPINDLE_SECONDARY) { + error(localize("Multi-axis motion is not supported on the secondary spindle.")); + } + 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(getB(new Vector(_a, _b, _c), currentSection)); + var c = cOutput.format(_c); + if (true) { + // axes are not synchronized + writeBlock(gMotionModal.format(1), x, y, z, a, b, c, getFeed(highFeedrate)); + } else { + writeBlock(gMotionModal.format(0), x, y, z, a, b, c); + forceFeed(); + } + previousABC.setZ(_c); +} + +function onLinear5D(_x, _y, _z, _a, _b, _c, feed) { + if (!currentSection.isOptimizedForMachine()) { + error(localize("Multi-axis motion is not supported for XZC mode.")); + return; + } + if (currentSection.spindle == SPINDLE_SECONDARY) { + error(localize("Multi-axis motion is not supported on the secondary spindle.")); + } + 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(getB(new Vector(_a, _b, _c), currentSection)); + var c = cOutput.format(_c); + + var actualFeed = getMultiaxisFeed(_x, _y, _z, _a, _b, _c, feed); + var f = getFeed(actualFeed.frn); + + if (x || y || z || a || b || c) { + writeBlock(gMotionModal.format(1), x, y, z, a, b, c, f); + } else if (f) { + if (getNextRecord().isMotion()) { // try not to output feed without motion + forceFeed(); // force feed on next line + } else { + writeBlock(gMotionModal.format(1), f); + } + } + previousABC.setZ(_c); +} + +// Start of multi-axis feedrate logic +/***** Be sure to add 'useInverseTime' to post properties if necessary. *****/ +/***** 'inverseTimeOutput' should be defined if Inverse Time feedrates are supported. *****/ +/***** 'previousABC' can be added throughout to maintain previous rotary positions. Required for Mill/Turn machines. *****/ +/***** 'headOffset' should be defined when a head rotary axis is defined. *****/ +/***** The feedrate mode must be included in motion block output (linear, circular, etc.) for Inverse Time feedrate support. *****/ +var dpmBPW = 0.1; // ratio of rotary accuracy to linear accuracy for DPM calculations +var inverseTimeUnits = 1.0; // 1.0 = minutes, 60.0 = seconds +var maxInverseTime = 45000; // maximum value to output for Inverse Time feeds +var maxDPM = 99999; // maximum value to output for DPM feeds +var useInverseTimeFeed = false; // use DPM feeds +var previousDPMFeed = 0; // previously output DPM feed +var dpmFeedToler = 0.5; // tolerance to determine when the DPM feed has changed +var previousABC = new Vector(0, 0, 0); // previous ABC position if maintained in post, don't define if not used +var forceOptimized = undefined; // used to override optimized-for-angles points (XZC-mode) + +/** Calculate the multi-axis feedrate number. */ +function getMultiaxisFeed(_x, _y, _z, _a, _b, _c, feed) { + var f = {frn:0, fmode:0}; + if (feed <= 0) { + error(localize("Feedrate is less than or equal to 0.")); + return f; + } + + var length = getMoveLength(_x, _y, _z, _a, _b, _c); + + if (useInverseTimeFeed) { // inverse time + f.frn = getInverseTime(length.tool, feed); + f.fmode = 93; + feedOutput.reset(); + } else { // degrees per minute + f.frn = getFeedDPM(length, feed); + f.fmode = 94; + } + return f; +} + +/** Returns point optimization mode. */ +function getOptimizedMode() { + if (forceOptimized != undefined) { + return forceOptimized; + } + // return (currentSection.getOptimizedTCPMode() != 0); // TAG:doesn't return correct value + return true; // always return false for non-TCP based heads +} + +/** Calculate the DPM feedrate number. */ +function getFeedDPM(_moveLength, _feed) { + if ((_feed == 0) || (_moveLength.tool < 0.0001) || (toDeg(_moveLength.abcLength) < 0.0005)) { + previousDPMFeed = 0; + return _feed; + } + var moveTime = _moveLength.tool / _feed; + if (moveTime == 0) { + previousDPMFeed = 0; + return _feed; + } + + var dpmFeed; + var tcp = !getOptimizedMode() && (forceOptimized == undefined); // set to false for rotary heads + if (tcp) { // TCP mode is supported, output feed as FPM + dpmFeed = _feed; + } else if (false) { // standard DPM + dpmFeed = Math.min(toDeg(_moveLength.abcLength) / moveTime, maxDPM); + if (Math.abs(dpmFeed - previousDPMFeed) < dpmFeedToler) { + dpmFeed = previousDPMFeed; + } + } else if (false) { // combination FPM/DPM + var length = Math.sqrt(Math.pow(_moveLength.xyzLength, 2.0) + Math.pow((toDeg(_moveLength.abcLength) * dpmBPW), 2.0)); + dpmFeed = Math.min((length / moveTime), maxDPM); + if (Math.abs(dpmFeed - previousDPMFeed) < dpmFeedToler) { + dpmFeed = previousDPMFeed; + } + } else { // machine specific calculation + var feedRate = _feed / (_moveLength.radius.z / (toPreciseUnit(getProperty("setting102"), IN) / 2.0)); + feedRate = Math.min(feedRate, highFeedrate / 2); + dpmFeed = Math.min(feedRate, maxDPM); + if (Math.abs(dpmFeed - previousDPMFeed) < dpmFeedToler) { + dpmFeed = previousDPMFeed; + } + } + previousDPMFeed = dpmFeed; + return dpmFeed; +} + +/** Calculate the Inverse time feedrate number. */ +function getInverseTime(_length, _feed) { + var inverseTime; + if (_length < 1.e-6) { // tool doesn't move + if (typeof maxInverseTime === "number") { + inverseTime = maxInverseTime; + } else { + inverseTime = 999999; + } + } else { + inverseTime = _feed / _length / inverseTimeUnits; + if (typeof maxInverseTime === "number") { + if (inverseTime > maxInverseTime) { + inverseTime = maxInverseTime; + } + } + } + return inverseTime; +} + +/** Calculate radius for each rotary axis. */ +function getRotaryRadii(startTool, endTool, startABC, endABC) { + var radii = new Vector(0, 0, 0); + var startRadius; + var endRadius; + var axis = new Array(machineConfiguration.getAxisU(), machineConfiguration.getAxisV(), machineConfiguration.getAxisW()); + for (var i = 0; i < 3; ++i) { + if (axis[i].isEnabled()) { + var startRadius = getRotaryRadius(axis[i], startTool, startABC); + var endRadius = getRotaryRadius(axis[i], endTool, endABC); + radii.setCoordinate(axis[i].getCoordinate(), Math.max(startRadius, endRadius)); + } + } + return radii; +} + +/** Calculate the distance of the tool position to the center of a rotary axis. */ +function getRotaryRadius(axis, toolPosition, abc) { + if (!axis.isEnabled()) { + return 0; + } + + var direction = axis.getEffectiveAxis(); + var normal = direction.getNormalized(); + // calculate the rotary center based on head/table + var center; + var radius; + if (axis.isHead()) { + var pivot; + if (typeof headOffset === "number") { + pivot = headOffset; + } else { + pivot = tool.getBodyLength(); + } + if (axis.getCoordinate() == machineConfiguration.getAxisU().getCoordinate()) { // rider + center = Vector.sum(toolPosition, Vector.product(machineConfiguration.getDirection(abc), pivot)); + center = Vector.sum(center, axis.getOffset()); + radius = Vector.diff(toolPosition, center).length; + } else { // carrier + var angle = abc.getCoordinate(machineConfiguration.getAxisU().getCoordinate()); + radius = Math.abs(pivot * Math.sin(angle)); + radius += axis.getOffset().length; + } + } else { + center = axis.getOffset(); + var d1 = toolPosition.x - center.x; + var d2 = toolPosition.y - center.y; + var d3 = toolPosition.z - center.z; + var radius = Math.sqrt( + Math.pow((d1 * normal.y) - (d2 * normal.x), 2.0) + + Math.pow((d2 * normal.z) - (d3 * normal.y), 2.0) + + Math.pow((d3 * normal.x) - (d1 * normal.z), 2.0) + ); + } + return radius; +} + +/** Calculate the linear distance based on the rotation of a rotary axis. */ +function getRadialDistance(radius, startABC, endABC) { + // calculate length of radial move + var delta = Math.abs(endABC - startABC); + if (delta > Math.PI) { + delta = 2 * Math.PI - delta; + } + var radialLength = (2 * Math.PI * radius) * (delta / (2 * Math.PI)); + return radialLength; +} + +/** Calculate tooltip, XYZ, and rotary move lengths. */ +function getMoveLength(_x, _y, _z, _a, _b, _c) { + // get starting and ending positions + var moveLength = {}; + var startTool; + var endTool; + var startXYZ; + var endXYZ; + var startABC; + if (typeof previousABC !== "undefined") { + startABC = new Vector(previousABC.x, previousABC.y, previousABC.z); + } else { + startABC = getCurrentDirection(); + } + var endABC = new Vector(_a, _b, _c); + + if (!getOptimizedMode()) { // calculate XYZ from tool tip + startTool = getCurrentPosition(); + endTool = new Vector(_x, _y, _z); + startXYZ = startTool; + endXYZ = endTool; + + // adjust points for tables + if (!machineConfiguration.getTableABC(startABC).isZero() || !machineConfiguration.getTableABC(endABC).isZero()) { + startXYZ = machineConfiguration.getOrientation(machineConfiguration.getTableABC(startABC)).getTransposed().multiply(startXYZ); + endXYZ = machineConfiguration.getOrientation(machineConfiguration.getTableABC(endABC)).getTransposed().multiply(endXYZ); + } + + // adjust points for heads + if (machineConfiguration.getAxisU().isEnabled() && machineConfiguration.getAxisU().isHead()) { + if (typeof getOptimizedHeads === "function") { // use post processor function to adjust heads + startXYZ = getOptimizedHeads(startXYZ.x, startXYZ.y, startXYZ.z, startABC.x, startABC.y, startABC.z); + endXYZ = getOptimizedHeads(endXYZ.x, endXYZ.y, endXYZ.z, endABC.x, endABC.y, endABC.z); + } else { // guess at head adjustments + var startDisplacement = machineConfiguration.getDirection(startABC); + startDisplacement.multiply(headOffset); + var endDisplacement = machineConfiguration.getDirection(endABC); + endDisplacement.multiply(headOffset); + startXYZ = Vector.sum(startTool, startDisplacement); + endXYZ = Vector.sum(endTool, endDisplacement); + } + } + } else { // calculate tool tip from XYZ, heads are always programmed in TCP mode, so not handled here + startXYZ = getCurrentPosition(); + endXYZ = new Vector(_x, _y, _z); + startTool = machineConfiguration.getOrientation(machineConfiguration.getTableABC(startABC)).multiply(startXYZ); + endTool = machineConfiguration.getOrientation(machineConfiguration.getTableABC(endABC)).multiply(endXYZ); + } + + // calculate axes movements + moveLength.xyz = Vector.diff(endXYZ, startXYZ).abs; + moveLength.xyzLength = moveLength.xyz.length; + moveLength.abc = Vector.diff(endABC, startABC).abs; + for (var i = 0; i < 3; ++i) { + if (moveLength.abc.getCoordinate(i) > Math.PI) { + moveLength.abc.setCoordinate(i, 2 * Math.PI - moveLength.abc.getCoordinate(i)); + } + } + moveLength.abcLength = moveLength.abc.length; + + // calculate radii + moveLength.radius = getRotaryRadii(startTool, endTool, startABC, endABC); + + // calculate the radial portion of the tool tip movement + var radialLength = Math.sqrt( + Math.pow(getRadialDistance(moveLength.radius.x, startABC.x, endABC.x), 2.0) + + Math.pow(getRadialDistance(moveLength.radius.y, startABC.y, endABC.y), 2.0) + + Math.pow(getRadialDistance(moveLength.radius.z, startABC.z, endABC.z), 2.0) + ); + + // calculate the tool tip move length + // tool tip distance is the move distance based on a combination of linear and rotary axes movement + moveLength.tool = moveLength.xyzLength + radialLength; + + // debug + if (false) { + writeComment("DEBUG - tool = " + moveLength.tool); + writeComment("DEBUG - xyz = " + moveLength.xyz); + var temp = Vector.product(moveLength.abc, 180 / Math.PI); + writeComment("DEBUG - abc = " + temp); + writeComment("DEBUG - radius = " + moveLength.radius); + } + return moveLength; +} +// End of multi-axis feedrate logic + +function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { + var directionCode = clockwise ? 2 : 3; + var toler = (machineState.useXZCMode || machineState.usePolarMode) ? getTolerance() / 2 : getTolerance(); + if (machineState.useXZCMode) { + switch (getCircularPlane()) { + case PLANE_ZX: + if (!isSpiral()) { + var c = getCClosest(x, y, cOutput.getCurrent()); + if (!cFormat.areDifferent(c, cOutput.getCurrent())) { + validate(getCircularSweep() < Math.PI, localize("Circular sweep exceeds limit.")); + var start = getCurrentPosition(); + writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(getModulus(x, y)), cOutput.format(c), zOutput.format(z), iOutput.format(cx - start.x, 0), kOutput.format(cz - start.z, 0), getFeed(feed)); + previousABC.setZ(c); + return; + } + } + break; + case PLANE_XY: + var d2 = center.x * center.x + center.y * center.y; + if (d2 < 1e-6) { // center is on rotary axis + var c = getCWithinRange(x, y, cOutput.getCurrent(), !clockwise); + if (!forceRewind) { + var actualFeed = getMultiaxisFeed(x, y, z, 0, 0, c, feed); + writeBlock(gMotionModal.format(1), xOutput.format(getModulus(x, y)), cOutput.format(c), zOutput.format(z), getFeed(actualFeed.frn)); + previousABC.setZ(c); + return; + } + } + break; + } + + linearize(toler); + return; + } + + if (machineState.usePolarMode && !getProperty("usePolarCircular")) { + linearize(toler); + return; + } + + if (isSpeedFeedSynchronizationActive()) { + error(localize("Speed-feed synchronization is not supported for circular moves.")); + return; + } + + if (pendingRadiusCompensation >= 0) { + error(localize("Radius compensation cannot be activated/deactivated for a circular move.")); + return; + } + + var start = getCurrentPosition(); + + if (isFullCircle()) { + if (getProperty("useRadius") || isHelical()) { // radius mode does not support full arcs + linearize(toler); + return; + } + switch (getCircularPlane()) { + case PLANE_XY: + writeBlock(gPlaneModal.format(17), gMotionModal.format(directionCode), iOutput.format(cx - start.x, 0), jOutput.format(cy - start.y, 0), getFeed(feed)); + break; + case PLANE_ZX: + if (machineState.usePolarMode) { + linearize(tolerance); + return; + } + writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), iOutput.format(cx - start.x, 0), kOutput.format(cz - start.z, 0), getFeed(feed)); + break; + case PLANE_YZ: + if (machineState.usePolarMode) { + linearize(tolerance); + return; + } + writeBlock(gPlaneModal.format(19), gMotionModal.format(directionCode), jOutput.format(cy - start.y, 0), kOutput.format(cz - start.z, 0), getFeed(feed)); + break; + default: + linearize(toler); + } + } else if (!getProperty("useRadius")) { + if (isHelical() && ((getCircularSweep() < toRad(30)) || (getHelicalPitch() > 10))) { // avoid G112 issue + linearize(toler); + return; + } + switch (getCircularPlane()) { + case PLANE_XY: + if (!xFormat.isSignificant(start.x) && machineState.usePolarMode) { + linearize(toler); // avoid G112 issues + return; + } + writeBlock(gPlaneModal.format(17), gMotionModal.format(directionCode), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x, 0), jOutput.format(cy - start.y, 0), getFeed(feed)); + break; + case PLANE_ZX: + if (machineState.usePolarMode) { + linearize(tolerance); + return; + } + writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x, 0), kOutput.format(cz - start.z, 0), getFeed(feed)); + break; + case PLANE_YZ: + if (machineState.usePolarMode) { + linearize(tolerance); + return; + } + writeBlock(gPlaneModal.format(19), gMotionModal.format(directionCode), xOutput.format(x), yOutput.format(y), zOutput.format(z), jOutput.format(cy - start.y, 0), kOutput.format(cz - start.z, 0), getFeed(feed)); + break; + default: + linearize(toler); + } + } else { // use radius mode + if (isHelical() && ((getCircularSweep() < toRad(30)) || (getHelicalPitch() > 10))) { + linearize(toler); + return; + } + var r = getCircularRadius(); + if (toDeg(getCircularSweep()) > (180 + 1e-9)) { + r = -r; // allow up to <360 deg arcs + } + switch (getCircularPlane()) { + case PLANE_XY: + if (!xFormat.isSignificant(start.x) && machineState.usePolarMode) { + linearize(toler); // avoid G112 issues + return; + } + writeBlock(gPlaneModal.format(17), gMotionModal.format(directionCode), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed)); + break; + case PLANE_ZX: + if (machineState.usePolarMode) { + linearize(tolerance); + return; + } + writeBlock(gPlaneModal.format(18), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed)); + break; + case PLANE_YZ: + if (machineState.usePolarMode) { + linearize(tolerance); + return; + } + writeBlock(gPlaneModal.format(19), gMotionModal.format(directionCode), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed)); + break; + default: + linearize(toler); + } + } +} + +function onCycle() { + if ((typeof isSubSpindleCycle == "function") && isSubSpindleCycle(cycleType)) { + if (!getProperty("gotSecondarySpindle")) { + error(localize("Secondary spindle is not available.")); + return; + } + + writeln(""); + if (hasParameter("operation-comment")) { + var comment = getParameter("operation-comment"); + if (comment) { + writeComment(comment); + } + } + + if (!machineState.stockTransferIsActive) { + setCoolant(COOLANT_OFF); + writeRetract(currentSection, false); // no retract in Z + + // wcs required here + currentWorkOffset = undefined; + writeWCS(currentSection); + + // preload next cutting tool + preloadCutoffTool(); + } + + switch (cycleType) { + case "secondary-spindle-grab": + if (cycle.usePartCatcher) { + engagePartCatcher(true); + } + writeBlock(getCode("FEED_MODE_UNIT_MIN")); // mm/rev + if (cycle.stopSpindle) { // no spindle rotation + writeBlock(getCode("STOP_SPINDLE")); + writeBlock(mFormat.format(19)); + writeBlock(mFormat.format(119), "R" + abcFormat.format(cycle.spindleOrientation)); + } else { // spindle rotation + var transferCodes = getSpindleTransferCodes(); + writeBlock(getCode("CONSTANT_SURFACE_SPEED_OFF")); + writeBlock(sOutput.format(transferCodes.spindleRPM), transferCodes.spindleDirection ? getCode("START_MAIN_SPINDLE_CW") : getCode("START_MAIN_SPINDLE_CCW")); + writeBlock(pOutput.format(transferCodes.spindleRPM), transferCodes.spindleDirection ? getCode("START_SUB_SPINDLE_CCW") : getCode("START_SUB_SPINDLE_CW")); // inverted + writeBlock(getCode("SPINDLE_SYNCHRONIZATION_ON"), "R" + abcFormat.format(cycle.spindleOrientation), formatComment("SPINDLE SYNCHRONIZATION ON")); // Sync spindles + } + if (getProperty("airCleanChuck")) { + writeBlock(getCode("MAINSPINDLE_AIR_BLAST_ON"), formatComment("MAINSPINDLE AIR BLAST ON")); + writeBlock(getCode("SUBSPINDLE_AIR_BLAST_ON"), formatComment("SUBSPINDLE AIR BLAST ON")); + } + writeBlock( + getCode(currentSection.spindle == SPINDLE_PRIMARY ? "UNCLAMP_SECONDARY_CHUCK" : "UNCLAMP_PRIMARY_CHUCK"), + formatComment(currentSection.spindle == SPINDLE_PRIMARY ? "UNCLAMP SECONDARY CHUCK" : "UNCLAMP PRIMARY CHUCK") + ); + onDwell(cycle.dwell); + gMotionModal.reset(); + writeBlock(conditional(cycle.useMachineFrame, gFormat.format(53)), gMotionModal.format(0), "B" + spatialFormat.format(cycle.feedPosition)); + if (getProperty("airCleanChuck")) { + writeBlock(getCode("MAINSPINDLE_AIR_BLAST_OFF"), formatComment("MAINSPINDLE AIR BLAST OFF")); + writeBlock(getCode("SUBSPINDLE_AIR_BLAST_OFF"), formatComment("SUBSPINDLE AIR BLAST OFF")); + } + + onDwell(cycle.dwell); + writeBlock(conditional(cycle.useMachineFrame, gFormat.format(53)), gMotionModal.format(1), "B" + spatialFormat.format(cycle.chuckPosition), getFeed(cycle.feedrate)); + writeBlock( + getCode(currentSection.spindle == SPINDLE_PRIMARY ? "CLAMP_SECONDARY_CHUCK" : "CLAMP_PRIMARY_CHUCK"), + formatComment(currentSection.spindle == SPINDLE_PRIMARY ? "CLAMP SECONDARY CHUCK" : "CLAMP PRIMARY CHUCK") + ); + onDwell(cycle.dwell * 1.5); + machineState.stockTransferIsActive = true; + break; + case "secondary-spindle-return": + // determine if pull operation, spindle return, or both + var secondaryPull = false; + var secondaryHome = false; + + // pull part only (when offset!=0), Return secondary spindle to home (when offset=0) + var feedDis = 0; + var feedPosition = cycle.feedPosition; + if (cycle.useMachineFrame == 1) { + if (hasParameter("operation:feedPlaneHeight_direct")) { // Inventor + feedDis = getParameter("operation:feedPlaneHeight_direct"); + } else if (hasParameter("operation:feedPlaneHeightDirect")) { // HSMWorks + feedDis = getParameter("operation:feedPlaneHeightDirect"); + } + feedPosition = feedDis; + } else if (hasParameter("operation:feedPlaneHeight_offset")) { // Inventor + feedDis = getParameter("operation:feedPlaneHeight_offset"); + } else if (hasParameter("operation:feedPlaneHeightOffset")) { // HSMWorks + feedDis = getParameter("operation:feedPlaneHeightOffset"); + } + // Transfer part to secondary spindle + if (cycle.unclampMode != "keep-clamped") { + secondaryPull = feedDis != 0; + secondaryHome = true; + } else { + // pull part only (when offset!=0), Return secondary spindle to home (when offset=0) + secondaryPull = feedDis != 0; + secondaryHome = !secondaryPull; + } + + if (!machineState.stockTransferIsActive) { + writeBlock(getCode("FEED_MODE_UNIT_REV")); // mm/rev + if (cycle.stopSpindle) { // no spindle rotation + writeBlock(getCode("STOP_SPINDLE")); + } else { // spindle rotation + var transferCodes = getSpindleTransferCodes(); + writeBlock(getCode("CONSTANT_SURFACE_SPEED_OFF")); + writeBlock(sOutput.format(transferCodes.spindleRPM), transferCodes.spindleDirection ? getCode("START_MAIN_SPINDLE_CW") : getCode("START_MAIN_SPINDLE_CCW")); + writeBlock(pOutput.format(transferCodes.spindleRPM), transferCodes.spindleDirection ? getCode("START_SUB_SPINDLE_CCW") : getCode("START_SUB_SPINDLE_CW")); // inverted + writeBlock(getCode("SPINDLE_SYNCHRONIZATION_ON"), formatComment("SPINDLE SYNCHRONIZATION ON")); // Sync spindles + } + } + + if (secondaryPull) { + writeBlock(getCode("UNCLAMP_PRIMARY_CHUCK"), formatComment("UNCLAMP PRIMARY CHUCK")); + onDwell(cycle.dwell); + writeBlock(conditional(cycle.useMachineFrame, gFormat.format(53)), gMotionModal.format(1), "B" + spatialFormat.format(cycle.feedPosition), getFeed(cycle.feedrate)); + } + if (secondaryHome) { + setCoolant(COOLANT_OFF); + if (cycle.unclampMode == "unclamp-secondary") { // leave part in main spindle + writeBlock(getCode("CLAMP_PRIMARY_CHUCK"), formatComment("CLAMP PRIMARY CHUCK")); + onDwell(cycle.dwell * 1.5); + writeBlock(getCode("UNCLAMP_SECONDARY_CHUCK"), formatComment("UNCLAMP SECONDARY CHUCK")); + onDwell(cycle.dwell); + } else if (cycle.unclampMode == "unclamp-primary") { + if (!secondaryPull) { + writeBlock(getCode("UNCLAMP_PRIMARY_CHUCK"), formatComment("UNCLAMP PRIMARY CHUCK")); + onDwell(cycle.dwell); + } + } + writeBlock(gMotionModal.format(0), gFormat.format(53), "B" + spatialFormat.format(getProperty("g53WorkPositionSub"))); + + if (machineState.spindleSynchronizationIsActive) { // spindles are synchronized + if (cycle.unclampMode == "unclamp-secondary") { + writeBlock(getCode("CLAMP_SECONDARY_CHUCK"), formatComment("CLAMP SECONDARY CHUCK")); + } else if (cycle.unclampMode == "unclamp-primary") { + writeBlock(getCode("CLAMP_PRIMARY_CHUCK"), formatComment("CLAMP PRIMARY CHUCK")); + } + writeBlock(getCode("SPINDLE_SYNCHRONIZATION_OFF"), formatComment("SPINDLE SYNCHRONIZATION OFF")); // disable spindle sync + } + } else { + writeBlock(getCode("CLAMP_PRIMARY_CHUCK"), formatComment("CLAMP PRIMARY CHUCK")); + onDwell(cycle.dwell * 1.5); + } + machineState.stockTransferIsActive = true; + break; + } + } +} + +var saveShowSequenceNumbers = true; +var pathBlockNumber = {start: 0, end: 0}; +var isCannedCycle = false; + +function onCyclePath() { + saveShowSequenceNumbers = getProperty("showSequenceNumbers"); + isCannedCycle = true; + // buffer all paths and stop feeds being output + feedOutput.disable(); + setProperty("showSequenceNumbers", false); + redirectToBuffer(); + gMotionModal.reset(); + if ((hasParameter("operation:grooving") && getParameter("operation:grooving").toUpperCase() != "OFF")) { + xOutput.reset(); + zOutput.reset(); + } +} + +function onCyclePathEnd() { + setProperty("showSequenceNumbers", saveShowSequenceNumbers); // reset property to initial state + feedOutput.enable(); + var cyclePath = String(getRedirectionBuffer()).split(EOL); // get cycle path from buffer + closeRedirection(); + for (line in cyclePath) { // remove empty elements + if (cyclePath[line] == "") { + cyclePath.splice(line); + } + } + + var verticalPasses; + if (cycle.profileRoughingCycle == 0) { + verticalPasses = false; + } else if (cycle.profileRoughingCycle == 1) { + verticalPasses = true; + } else { + error(localize("Unsupported passes type.")); + return; + } + // output cycle data + switch (cycleType) { + case "turning-canned-rough": + writeBlock(gFormat.format(verticalPasses ? 72 : 71), + "P" + (getStartEndSequenceNumber(cyclePath, true)), + "Q" + (getStartEndSequenceNumber(cyclePath, false)), + "U" + xFormat.format(cycle.xStockToLeave), + "W" + spatialFormat.format(cycle.zStockToLeave), + "D" + spatialFormat.format(cycle.depthOfCut), + getFeed(cycle.cutfeedrate) + ); + break; + default: + error(localize("Unsupported turning canned cycle.")); + } + + for (var i = 0; i < cyclePath.length; ++i) { + if (i == 0 || i == (cyclePath.length - 1)) { // write sequence number on first and last line of the cycle path + setProperty("showSequenceNumbers", true); + if ((i == 0 && pathBlockNumber.start != sequenceNumber) || (i == (cyclePath.length - 1) && pathBlockNumber.end != sequenceNumber)) { + error(localize("Mismatch of start/end block number in turning canned cycle.")); + return; + } + } + writeBlock(cyclePath[i]); // output cycle path + setProperty("showSequenceNumbers", saveShowSequenceNumbers); // reset property to initial state + isCannedCycle = false; + } +} + +function getStartEndSequenceNumber(cyclePath, start) { + if (start) { + pathBlockNumber.start = sequenceNumber + conditional(saveShowSequenceNumbers, getProperty("sequenceNumberIncrement")); + return pathBlockNumber.start; + } else { + pathBlockNumber.end = sequenceNumber + getProperty("sequenceNumberIncrement") + conditional(saveShowSequenceNumbers, (cyclePath.length - 1) * getProperty("sequenceNumberIncrement")); + return pathBlockNumber.end; + } +} + +function getCommonCycle(x, y, z, r) { + // forceXYZ(); // force xyz on first drill hole of any cycle + if (machineState.useXZCMode) { + cOutput.reset(); + if (currentSection.spindle == SPINDLE_SECONDARY) { + onCommand(COMMAND_UNLOCK_MULTI_AXIS); + writeBlock(cOutput.format(getCWithinRange(x, y, cOutput.getCurrent()))); + onCommand(COMMAND_LOCK_MULTI_AXIS); + return [xOutput.format(getModulus(x, y)), zOutput.format(z), + (r !== undefined) ? ("R" + spatialFormat.format((gPlaneModal.getCurrent() == 19) ? r * 2 : r)) : ""]; + } else { + return [xOutput.format(getModulus(x, y)), cOutput.format(getCWithinRange(x, y, cOutput.getCurrent())), + zOutput.format(z), + (r !== undefined) ? ("R" + spatialFormat.format((gPlaneModal.getCurrent() == 19) ? r * 2 : r)) : ""]; + } + } else { + return [xOutput.format(x), yOutput.format(y), + zOutput.format(z), + (r !== undefined) ? ("R" + spatialFormat.format((gPlaneModal.getCurrent() == 19) ? r * 2 : r)) : ""]; + } +} + +function writeCycleClearance() { + if (true) { + switch (gPlaneModal.getCurrent()) { + case 18: + writeBlock(gMotionModal.format(0), zOutput.format(cycle.clearance)); + break; + case 19: + writeBlock(gMotionModal.format(0), xOutput.format(cycle.clearance)); + break; + default: + error(localize("Unsupported drilling orientation.")); + return; + } + } +} + +var threadNumber = 0; +var numberOfThreads = 1; +function onCyclePoint(x, y, z) { + + if (!getProperty("useCycles") || currentSection.isMultiAxis() || getMachiningDirection(currentSection) == MACHINING_DIRECTION_INDEXING) { + expandCyclePoint(x, y, z); + return; + } + writeBlock(gPlaneModal.format(getPlane())); + + var gCycleTapping; + switch (cycleType) { + case "tapping-with-chip-breaking": + case "right-tapping": + case "left-tapping": + case "tapping": + if (gPlaneModal.getCurrent() == 19) { // radial + if (tool.type == TOOL_TAP_LEFT_HAND) { + gCycleTapping = 196; + } else { + gCycleTapping = 195; + } + } else { // axial + if (tool.type == TOOL_TAP_LEFT_HAND) { + gCycleTapping = machineState.axialCenterDrilling ? 184 : 186; + } else { + gCycleTapping = machineState.axialCenterDrilling ? 84 : 95; + } + } + break; + } + + switch (cycleType) { + case "thread-turning": + // find number of threads and count which thread we are on + numberOfThreads = 1; + if ((hasParameter("operation:doMultipleThreads") && (getParameter("operation:doMultipleThreads") != 0))) { + numberOfThreads = getParameter("operation:numberOfThreads"); + } + if (isFirstCyclePoint()) { + // increment thread number for multiple threads + threadNumber += 1; + } + + var threadPhaseAngle = (360 / numberOfThreads) * (threadNumber - 1); + + if (getProperty("useSimpleThread")) { + var i = -cycle.incrementalX; // positive if taper goes down - delta radius + + // move to thread start for infeed angle other than 0, multiple threads and alternate infeed. + if (zFormat.areDifferent(zOutput.getCurrent(), zFormat.getResultingValue(z))) { + var zOut = zOutput.format(z - cycle.incrementalZ); + if (zOut) { + writeBlock(gMotionModal.format(0), zOut); + } + g92IOutput.reset(); + g92QOutput.reset(); + gCycleModal.reset(); + forceFeed(); + xOutput.reset(); + zOutput.reset(); + } + + writeBlock( + gCycleModal.format(92), + xOutput.format(x - cycle.incrementalX), + yOutput.format(y), + zOutput.format(z), + conditional(zFormat.isSignificant(i), g92IOutput.format(i)), + conditional(numberOfThreads > 1, g92QOutput.format(threadPhaseAngle)), + feedOutput.format(cycle.pitch) + ); + } else { + if (isLastCyclePoint()) { + // thread height and depth of cut + var threadHeight = getParameter("operation:threadDepth"); + var firstDepthOfCut = threadHeight - Math.abs(getCyclePoint(0).x - x); + var cuttingAngle = 59; // Angle is not stored with tool. toDeg(tool.getTaperAngle()); + if (hasParameter("operation:infeedAngle")) { + cuttingAngle = getParameter("operation:infeedAngle") * 2; + } + var i = -cycle.incrementalX; // positive if taper goes down - delta radius + gCycleModal.reset(); + + var threadInfeedMode = "constant"; + if (hasParameter("operation:infeedMode")) { + threadInfeedMode = getParameter("operation:infeedMode"); + } + + // Cutting Method: + // P1 = Constant Amount/1 Edge + // P2 = Constant Amount/Both Edges + // P3 = Constant Depth/One Edge + // P4 = Constant Depth/Both Edges >>>>>> not supported + + var threadCuttingMode = 3; + if (threadInfeedMode == "reduced") { + threadCuttingMode = 1; + } else if (threadInfeedMode == "constant") { + threadCuttingMode = 3; + } else if (threadInfeedMode == "alternate") { + threadCuttingMode = 2; + } else { + error(localize("Unsupported Infeed Mode.")); + return; + } + + // threading cycle + gCycleModal.reset(); + xOutput.reset(); + zOutput.reset(); + writeBlock( + gCycleModal.format(76), + xOutput.format(x - cycle.incrementalX), + zOutput.format(z), + conditional(zFormat.isSignificant(i), g76IOutput.format(i)), + g76KOutput.format(threadHeight), + g76DOutput.format(firstDepthOfCut), + g76AOutput.format(cuttingAngle), + "P" + integerFormat.format(threadCuttingMode), + conditional(numberOfThreads > 1, g76QOutput.format(threadPhaseAngle)), + pitchOutput.format(cycle.pitch) + ); + } + } + gMotionModal.reset(); + return; + } + if (true) { + if (gPlaneModal.getCurrent() == 17) { + error(localize("Drilling in G17 is not supported.")); + return; + } + // repositionToCycleClearance(cycle, x, y, z); + // return to initial Z which is clearance plane and set absolute mode + feedOutput.reset(); + + var F = (machineState.feedPerRevolution ? cycle.feedrate / spindleSpeed : cycle.feedrate); + var P = (cycle.dwell == 0) ? 0 : clamp(1, cycle.dwell * 1000, 99999999); // in milliseconds + + switch (cycleType) { + case "drilling": + forceXYZ(); + writeCycleClearance(); + writeBlock( + gCycleModal.format(gPlaneModal.getCurrent() == 19 ? 241 : 81), + getCommonCycle(x, y, z, cycle.retract), + feedOutput.format(F) + ); + break; + case "counter-boring": + writeCycleClearance(); + forceXYZ(); + if (P > 0) { + writeBlock( + gCycleModal.format(gPlaneModal.getCurrent() == 19 ? 242 : 82), + getCommonCycle(x, y, z, cycle.retract), + "P" + milliFormat.format(P), + feedOutput.format(F) + ); + } else { + writeBlock( + gCycleModal.format(gPlaneModal.getCurrent() == 19 ? 241 : 81), + getCommonCycle(x, y, z, cycle.retract), + feedOutput.format(F) + ); + } + break; + case "chip-breaking": + case "deep-drilling": + if (cycleType == "chip-breaking" && (cycle.accumulatedDepth < cycle.depth)) { + expandCyclePoint(x, y, z); + return; + } else { + writeCycleClearance(); + forceXYZ(); + writeBlock( + gCycleModal.format(gPlaneModal.getCurrent() == 19 ? 243 : 83), + getCommonCycle(x, y, z, cycle.retract), + "Q" + spatialFormat.format(cycle.incrementalDepth), // lathe prefers single Q peck value, IJK causes error + // "I" + spatialFormat.format(cycle.incrementalDepth), + // "J" + spatialFormat.format(cycle.incrementalDepthReduction), + // "K" + spatialFormat.format(cycle.minimumIncrementalDepth), + conditional(P > 0, "P" + milliFormat.format(P)), + feedOutput.format(F) + ); + } + break; + case "tapping": + writeCycleClearance(); + if (gPlaneModal.getCurrent() == 19) { + xOutput.reset(); + writeBlock(gMotionModal.format(0), zOutput.format(z), yOutput.format(y)); + writeBlock(gMotionModal.format(0), xOutput.format(cycle.retract)); + writeBlock( + gCycleModal.format(gCycleTapping), + getCommonCycle(x, y, z, undefined), + pitchOutput.format(F) + ); + } else { + forceXYZ(); + writeBlock( + gCycleModal.format(gCycleTapping), + getCommonCycle(x, y, z, cycle.retract), + pitchOutput.format(F) + ); + } + forceFeed(); + break; + case "left-tapping": + writeCycleClearance(); + xOutput.reset(); + if (gPlaneModal.getCurrent() == 19) { + writeBlock(gMotionModal.format(0), zOutput.format(z), yOutput.format(y)); + writeBlock(gMotionModal.format(0), xOutput.format(cycle.retract)); + } + writeBlock( + gCycleModal.format(gCycleTapping), + getCommonCycle(x, y, z, (gPlaneModal.getCurrent() == 19) ? undefined : cycle.retract), + pitchOutput.format(F) + ); + forceFeed(); + break; + case "right-tapping": + writeCycleClearance(); + xOutput.reset(); + if (gPlaneModal.getCurrent() == 19) { + writeBlock(gMotionModal.format(0), zOutput.format(z), yOutput.format(y)); + writeBlock(gMotionModal.format(0), xOutput.format(cycle.retract)); + } + writeBlock( + gCycleModal.format(gCycleTapping), + getCommonCycle(x, y, z, (gPlaneModal.getCurrent() == 19) ? undefined : cycle.retract), + pitchOutput.format(F) + ); + forceFeed(); + break; + case "tapping-with-chip-breaking": + writeCycleClearance(); + xOutput.reset(); + if (gPlaneModal.getCurrent() == 19) { + writeBlock(gMotionModal.format(0), zOutput.format(z), yOutput.format(y)); + writeBlock(gMotionModal.format(0), xOutput.format(cycle.retract)); + } + + // Parameter 57 bit 6, REPT RIG TAP, is set to 1 (On) + // On Mill software versions12.09 and above, REPT RIG TAP has been moved from the Parameters to Setting 133 + warningOnce(localize("For tapping with chip breaking make sure REPT RIG TAP (Setting 133) is enabled on your Haas."), WARNING_REPEAT_TAPPING); + + 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 + u = Math.max(u, cycle.bottom); + if (first) { + first = false; + writeBlock( + gCycleModal.format(gCycleTapping), + getCommonCycle((gPlaneModal.getCurrent() == 19) ? u : x, y, (gPlaneModal.getCurrent() == 19) ? z : u, (gPlaneModal.getCurrent() == 19) ? undefined : cycle.retract), + pitchOutput.format(F) + ); + } else { + writeBlock( + gCycleModal.format(gCycleTapping), + conditional(gPlaneModal.getCurrent() == 18, "Z" + spatialFormat.format(u)), + conditional(gPlaneModal.getCurrent() == 19, "X" + xFormat.format(u)), + pitchOutput.format(F) + ); + } + } + forceFeed(); + break; + case "fine-boring": + expandCyclePoint(x, y, z); + break; + case "reaming": + if (gPlaneModal.getCurrent() == 19) { + expandCyclePoint(x, y, z); + } else { + writeCycleClearance(); + forceXYZ(); + writeBlock( + gCycleModal.format(85), + getCommonCycle(x, y, z, cycle.retract), + feedOutput.format(F) + ); + } + break; + case "stop-boring": + if (P > 0) { + expandCyclePoint(x, y, z); + } else { + writeCycleClearance(); + forceXYZ(); + writeBlock( + gCycleModal.format((gPlaneModal.getCurrent() == 19) ? 246 : 86), + getCommonCycle(x, y, z, cycle.retract), + feedOutput.format(F) + ); + } + break; + case "boring": + if (P > 0) { + expandCyclePoint(x, y, z); + } else { + writeCycleClearance(); + forceXYZ(); + writeBlock( + gCycleModal.format((gPlaneModal.getCurrent() == 19) ? 245 : 85), + getCommonCycle(x, y, z, cycle.retract), + feedOutput.format(F) + ); + } + break; + default: + expandCyclePoint(x, y, z); + } + if (!cycleExpanded) { + writeBlock(gCycleModal.format(80)); + gMotionModal.reset(); + } + } else { + if (cycleExpanded) { + expandCyclePoint(x, y, z); + } else if (machineState.useXZCMode) { + var _x = xOutput.format(getModulus(x, y)); + var _c = cOutput.format(getCWithinRange(x, y, cOutput.getCurrent())); + if (!_x /*&& !_y*/ && !_c) { + xOutput.reset(); // at least one axis is required + _x = xOutput.format(getModulus(x, y)); + } + writeBlock(_x, _c); + } else { + var _x = xOutput.format(x); + var _y = yOutput.format(y); + var _z = zOutput.format(z); + if (!_x && !_y && !_z) { + switch (gPlaneModal.getCurrent()) { + case 18: // ZX + xOutput.reset(); // at least one axis is required + yOutput.reset(); // at least one axis is required + _x = xOutput.format(x); + _y = yOutput.format(y); + break; + case 19: // YZ + yOutput.reset(); // at least one axis is required + zOutput.reset(); // at least one axis is required + _y = yOutput.format(y); + _z = zOutput.format(z); + break; + } + } + writeBlock(_x, _y, _z); + } + } +} + +function onCycleEnd() { + if (!cycleExpanded && !machineState.stockTransferIsActive && !((typeof isSubSpindleCycle == "function") && isSubSpindleCycle(cycleType)) && + cycleType != "turning-canned-rough") { + switch (cycleType) { + case "thread-turning": + forceFeed(); + g92IOutput.reset(); + g92QOutput.reset(); + gCycleModal.reset(); + xOutput.reset(); + zOutput.reset(); + if (threadNumber == numberOfThreads) { + threadNumber = 0; + } + break; + default: + writeBlock(gCycleModal.format(80)); + gMotionModal.reset(); + } + } +} + +function onPassThrough(text) { + writeBlock(text); +} + +function onParameter(name, value) { + if (name == "action") { + if (String(value).toUpperCase() == "USEPOLARMODE") { + forcePolarMode = true; + } else if (String(value).toUpperCase() == "PARTEJECT") { + ejectRoutine = true; + } + } +} + +var currentCoolantMode = COOLANT_OFF; + +function setCoolant(coolant) { + var optionalCoolant = false; + if (coolant == currentCoolantMode) { + if (operationNeedsSafeStart) { + optionalCoolant = true; + } else { + return; // coolant is already active + } + } + + var m = undefined; + if (coolant == COOLANT_OFF) { + if (currentCoolantMode == COOLANT_THROUGH_TOOL) { + skipBlock = optionalCoolant; + writeBlock(getCode("COOLANT_THROUGH_TOOL_OFF")); + } else if (currentCoolantMode == COOLANT_AIR) { + skipBlock = optionalCoolant; + writeBlock(getCode("COOLANT_AIR_OFF")); + } else { + skipBlock = optionalCoolant; + writeBlock(getCode("COOLANT_OFF")); + } + currentCoolantMode = COOLANT_OFF; + return; + } + + switch (coolant) { + case COOLANT_FLOOD: + m = getCode("COOLANT_FLOOD_ON"); + break; + case COOLANT_THROUGH_TOOL: + m = getCode("COOLANT_THROUGH_TOOL_ON"); + break; + case COOLANT_AIR: + m = getCode("COOLANT_AIR_ON"); + break; + default: + onUnsupportedCoolant(coolant); + m = getCode("COOLANT_OFF"); + } + + if (m) { + skipBlock = optionalCoolant; + writeBlock(m); + currentCoolantMode = coolant; + } +} + +function onCommand(command) { + switch (command) { + case COMMAND_COOLANT_OFF: + setCoolant(COOLANT_OFF); + break; + case COMMAND_COOLANT_ON: + setCoolant(tool.coolant); + break; + case COMMAND_START_SPINDLE: + if (machineState.isTurningOperation || machineState.axialCenterDrilling) { + if (currentSection.spindle == SPINDLE_PRIMARY) { + writeBlock(tool.clockwise ? getCode("START_MAIN_SPINDLE_CW") : getCode("START_MAIN_SPINDLE_CCW")); + } else { + writeBlock(tool.clockwise ? getCode("START_SUB_SPINDLE_CW") : getCode("START_SUB_SPINDLE_CCW")); + } + } else { + writeBlock(tool.clockwise ? getCode("START_LIVE_TOOL_CW") : getCode("START_LIVE_TOOL_CCW")); + } + break; + case COMMAND_STOP_SPINDLE: + if (getProperty("useSSV")) { + writeBlock(ssvModal.format(39)); + } + writeBlock(getCode("STOP_SPINDLE")); + break; + case COMMAND_LOCK_MULTI_AXIS: + writeBlock(getCode((currentSection.spindle == SPINDLE_PRIMARY) ? "MAIN_SPINDLE_BRAKE_ON" : "SUB_SPINDLE_BRAKE_ON")); + break; + case COMMAND_UNLOCK_MULTI_AXIS: + writeBlock(getCode((currentSection.spindle == SPINDLE_PRIMARY) ? "MAIN_SPINDLE_BRAKE_OFF" : "SUB_SPINDLE_BRAKE_OFF")); + break; + case COMMAND_START_CHIP_TRANSPORT: + writeBlock(getCode("START_CHIP_TRANSPORT")); + break; + case COMMAND_STOP_CHIP_TRANSPORT: + writeBlock(getCode("STOP_CHIP_TRANSPORT")); + break; + case COMMAND_OPEN_DOOR: + if (gotDoorControl) { + writeBlock(getCode("OPEN_DOOR")); // optional + } + break; + case COMMAND_CLOSE_DOOR: + if (gotDoorControl) { + writeBlock(getCode("CLOSE_DOOR")); // optional + } + break; + case COMMAND_BREAK_CONTROL: + break; + case COMMAND_TOOL_MEASURE: + break; + case COMMAND_ACTIVATE_SPEED_FEED_SYNCHRONIZATION: + break; + case COMMAND_DEACTIVATE_SPEED_FEED_SYNCHRONIZATION: + break; + case COMMAND_STOP: + if (!skipBlock) { + forceSpindleSpeed = true; + currentCoolantMode = undefined; + } + writeBlock(mFormat.format(0)); + break; + case COMMAND_OPTIONAL_STOP: + if (!skipBlock) { + forceSpindleSpeed = true; + currentCoolantMode = undefined; + } + writeBlock(mFormat.format(1)); + break; + case COMMAND_END: + writeBlock(mFormat.format(2)); + break; + case COMMAND_ORIENTATE_SPINDLE: + if (machineState.isTurningOperation) { + if (currentSection.spindle == SPINDLE_PRIMARY) { + writeBlock(mFormat.format(19)); // use P or R to set angle (optional) + } else { + writeBlock(mFormat.format(g14IsActive ? 19 : 119)); + } + } else { + if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, 1))) { + writeBlock(mFormat.format(19)); // use P or R to set angle (optional) + } else if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, -1))) { + writeBlock(mFormat.format(g14IsActive ? 19 : 119)); + } else { + error(localize("Spindle orientation is not supported for live tooling.")); + return; + } + } + break; + // case COMMAND_CLAMP: // add support for clamping + // case COMMAND_UNCLAMP: // add support for clamping + default: + onUnsupportedCommand(command); + } +} + +/** Preload cutoff tool prior to spindle transfer/cutoff. */ +var prePositionCutoffTool = true; +function preloadCutoffTool() { + if (isLastSection()) { + return; + } + var numberOfSections = getNumberOfSections(); + for (var i = getNextSection().getId(); i < numberOfSections; ++i) { + var section = getSection(i); + if (section.getParameter("operation-strategy") == "turningSecondarySpindleReturn") { + continue; + } else if (section.getType() != TYPE_TURNING || section.spindle != SPINDLE_PRIMARY) { + break; + } else if (section.getParameter("operation-strategy") == "turningPart") { + var tool = section.getTool(); + var compensationOffset = tool.compensationOffset; + writeBlock("T" + toolFormat.format(tool.number * 100 + compensationOffset)); + if (prePositionCutoffTool) { + var initialPosition = getFramePosition(section.getInitialPosition()); + writeBlock(zOutput.format(initialPosition.z)); + } + break; + } + } + return; +} + +/** Get synchronization/transfer code based on part cutoff spindle direction. */ +function getSpindleTransferCodes() { + var transferCodes = {direction:0, spindleMode:SPINDLE_CONSTANT_SPINDLE_SPEED, surfaceSpeed:0, maximumSpindleSpeed:0}; + transferCodes.spindleDirection = isFirstSection() ? true : getPreviousSection().getTool().clockwise; // clockwise + transferCodes.spindleRPM = cycle.spindleSpeed; + if (isLastSection()) { + return transferCodes; + } + var numberOfSections = getNumberOfSections(); + for (var i = getNextSection().getId(); i < numberOfSections; ++i) { + var section = getSection(i); + if (section.getParameter("operation-strategy") == "turningSecondarySpindleReturn") { + continue; + } else if (section.getType() != TYPE_TURNING || section.spindle != SPINDLE_PRIMARY) { + break; + } else if (section.getType() == TYPE_TURNING) { + var tool = section.getTool(); + transferCodes.spindleMode = tool.getSpindleMode(); + transferCodes.surfaceSpeed = tool.surfaceSpeed; + transferCodes.maximumSpindleSpeed = tool.maximumSpindleSpeed; + transferCodes.spindleDirection = tool.clockwise; + break; + } + } + return transferCodes; +} + +function engagePartCatcher(engage) { + if (engage) { + // catch part here + writeBlock(getCode("PART_CATCHER_ON"), formatComment(localize("PART CATCHER ON"))); + } else { + onCommand(COMMAND_COOLANT_OFF); + if (gotYAxis) { + writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + yFormat.format(getProperty("g53HomePositionY"))); // retract + yOutput.reset(); + } + writeBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(getProperty("g53HomePositionX"))); // retract + writeBlock(gFormat.format(53), gMotionModal.format(0), "Z" + zFormat.format(currentSection.spindle == SPINDLE_SECONDARY ? getProperty("g53HomePositionSubZ") : getProperty("g53HomePositionZ"))); // retract + writeBlock(getCode("PART_CATCHER_OFF"), formatComment(localize("PART CATCHER OFF"))); + forceXYZ(); + } +} + +function ejectPart() { + writeln(""); + writeComment(localize("PART EJECT")); + + gMotionModal.reset(); + //writeBlock(gFormat.format(330)); // retract bar feeder + //goHome(); // Position all axes to home position + + if (gotYAxis) { + writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + yFormat.format(getProperty("g53HomePositionY"))); // retract + yOutput.reset(); + } + writeBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(getProperty("g53HomePositionX"))); // retract + writeBlock(gFormat.format(53), gMotionModal.format(0), "Z" + zFormat.format(currentSection.spindle == SPINDLE_SECONDARY ? getProperty("g53HomePositionSubZ") : getProperty("g53HomePositionZ"))); // retract + + onCommand(COMMAND_UNLOCK_MULTI_AXIS); + if (!getProperty("optimizeCAxisSelect")) { + cAxisEngageModal.reset(); + } + writeBlock( + getCode("FEED_MODE_UNIT_MIN"), + gPlaneModal.format(17), + getCode("DISENGAGE_C_AXIS") + ); + // setCoolant(COOLANT_THROUGH_TOOL); + gSpindleModeModal.reset(); + writeBlock( + getCode("CONSTANT_SURFACE_SPEED_OFF"), + sOutput.format(50), + getCode(currentSection.spindle == SPINDLE_SECONDARY ? "START_SUB_SPINDLE_CW" : "START_MAIN_SPINDLE_CW") + ); + // writeBlock(mFormat.format(getCode("INTERLOCK_BYPASS", getSpindle(true)))); + writeBlock(getCode("PART_CATCHER_ON")); + writeBlock(getCode(currentSection.spindle == SPINDLE_SECONDARY ? "UNCLAMP_SECONDARY_CHUCK" : "UNCLAMP_PRIMARY_CHUCK")); + onDwell(1.5); + // writeBlock(mFormat.format(getCode("CYCLE_PART_EJECTOR"))); + // onDwell(0.5); + writeBlock(getCode("PART_CATCHER_OFF")); + onDwell(1.1); + + // clean out chips + if (getProperty("airCleanChuck")) { + writeBlock(getCode(currentSection.spindle == SPINDLE_SECONDARY ? "SUBSPINDLE_AIR_BLAST_ON" : "MAINSPINDLE_AIR_BLAST_ON"), + formatComment("AIR BLAST ON")); + onDwell(2.5); + writeBlock(getCode(currentSection.spindle == SPINDLE_SECONDARY ? "SUBSPINDLE_AIR_BLAST_OFF" : "MAINSPINDLE_AIR_BLAST_OFF"), + formatComment("AIR BLAST OFF")); + } + writeBlock(getCode("STOP_SPINDLE")); + setCoolant(COOLANT_OFF); + writeComment(localize("END OF PART EJECT")); + writeln(""); +} + +function onSectionEnd() { + + if (currentSection.partCatcher) { + engagePartCatcher(false); + } + + if (machineState.usePolarMode) { + setPolarMode(false); // disable polar interpolation mode + } + + // cancel SFM mode to preserve spindle speed + if ((tool.getSpindleMode() == SPINDLE_CONSTANT_SURFACE_SPEED) && !machineState.stockTransferIsActive) { + startSpindle(true, getFramePosition(currentSection.getFinalPosition())); + } + + if (getProperty("useG61")) { + writeBlock(gExactStopModal.format(64)); + } + + if (((getCurrentSectionId() + 1) >= getNumberOfSections()) || + (tool.number != getNextSection().getTool().number)) { + onCommand(COMMAND_BREAK_CONTROL); + } + + if ((currentSection.getType() == TYPE_MILLING) && + (!hasNextSection() || (hasNextSection() && (getNextSection().getType() != TYPE_MILLING)))) { + // exit milling mode + if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, 1))) { + // +Z + } else { + writeBlock(getCode("STOP_SPINDLE")); + } + } + + if (machineState.cAxisIsEngaged && !getProperty("optimizeCAxisSelect")) { + writeBlock(getCode("DISENGAGE_C_AXIS")); // used for c-axis encoder reset + forceWorkPlane(); // needed since re-engage would result in undefined c-axis position + } + + forceAny(); + forcePolarMode = false; + partCutoff = false; +} + +function onClose() { + writeln(""); + + optionalSection = false; + + onCommand(COMMAND_COOLANT_OFF); + + if (getProperty("gotChipConveyor")) { + onCommand(COMMAND_STOP_CHIP_TRANSPORT); + } + + if (getNumberOfSections() > 0) { // Retracting Z first causes safezone overtravel error to keep from crashing into subspindle. Z should already be retracted to and end of section. + var section = getSection(getNumberOfSections() - 1); + if ((section.getType() != TYPE_TURNING) && isSameDirection(section.workPlane.forward, new Vector(0, 0, 1))) { + writeBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(getProperty("g53HomePositionX")), conditional(gotYAxis, "Y" + yFormat.format(getProperty("g53HomePositionY")))); // retract + xOutput.reset(); + yOutput.reset(); + writeBlock(gFormat.format(53), gMotionModal.format(0), "Z" + zFormat.format((currentSection.spindle == SPINDLE_SECONDARY) ? getProperty("g53HomePositionSubZ") : getProperty("g53HomePositionZ"))); // retract + zOutput.reset(); + writeBlock(getCode("STOP_SPINDLE")); + } else { + if (gotYAxis) { + writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + yFormat.format(getProperty("g53HomePositionY"))); // retract + } + writeBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(getProperty("g53HomePositionX"))); // retract + xOutput.reset(); + yOutput.reset(); + writeBlock(gFormat.format(53), gMotionModal.format(0), "Z" + zFormat.format(currentSection.spindle == SPINDLE_SECONDARY ? getProperty("g53HomePositionSubZ") : getProperty("g53HomePositionZ"))); // retract + zOutput.reset(); + writeBlock(getCode("STOP_SPINDLE")); + } + } + if (machineState.tailstockIsActive) { + writeBlock(getCode("TAILSTOCK_OFF")); + } + + gMotionModal.reset(); + if (!getProperty("optimizeCAxisSelect")) { + cAxisEngageModal.reset(); + } + writeBlock(getCode("DISENGAGE_C_AXIS")); + + if (ejectRoutine) { + ejectPart(); + } + + if (gotYAxis) { + writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + yFormat.format(getProperty("g53HomePositionY"))); + yOutput.reset(); + } + + if (getProperty("useBarFeeder")) { + writeln(""); + writeComment(localize("Bar feed")); + // feed bar here + // writeBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(getProperty("g53HomePositionX"))); + writeBlock(gFormat.format(105)); + } + + writeln(""); + onImpliedCommand(COMMAND_END); + onImpliedCommand(COMMAND_STOP_SPINDLE); + if (getProperty("looping")) { + writeBlock(mFormat.format(99)); + } else if (true /*!getProperty("useM97")*/) { + onCommand(COMMAND_OPEN_DOOR); + writeBlock(mFormat.format(getProperty("useBarFeeder") ? 99 : 30)); // stop program, spindle stop, coolant off + } else { + writeBlock(mFormat.format(99)); + } + writeln("%"); +} + +function setProperty(property, value) { + properties[property].current = value; +} +// <<<<< INCLUDED FROM ../common/haas lathe.cps + +properties.maximumSpindleSpeed.value = 4000; +properties.subMaximumSpindleSpeed.value = 4000; diff --git a/Haas_ST-20Y/haas st-20y.cps b/Haas_Lathes_BIDC/haas st-20y.cps similarity index 79% rename from Haas_ST-20Y/haas st-20y.cps rename to Haas_Lathes_BIDC/haas st-20y.cps index 1fa98d8..5b7ea3b 100644 --- a/Haas_ST-20Y/haas st-20y.cps +++ b/Haas_Lathes_BIDC/haas st-20y.cps @@ -1,11 +1,11 @@ /** - Copyright (C) 2012-2019 by Autodesk, Inc. + Copyright (C) 2012-2021 by Autodesk, Inc. All rights reserved. HAAS Lathe post processor configuration. - $Revision: 42650 50adfb6cb80e478bb4605cdfcfd268829708e272 $ - $Date: 2020-02-13 07:31:21 $ + $Revision: 43295 06360a6b2ff0d13b975cf2a27b03d8a4d3760ca5 $ + $Date: 2021-05-27 22:34:05 $ FORKID {14D60AD3-4366-49dc-939C-4DB5EA48FF68} */ @@ -15,7 +15,6 @@ description = "HAAS ST-20Y"; var gotYAxis = true; var yAxisMinimum = toPreciseUnit(gotYAxis ? -50.8 : 0, MM); // specifies the minimum range for the Y-axis var yAxisMaximum = toPreciseUnit(gotYAxis ? 50.8 : 0, MM); // specifies the maximum range for the Y-axis -var xAxisMinimum = toPreciseUnit(0, MM); // specifies the maximum range for the X-axis (RADIUS MODE VALUE) var gotBAxis = false; // B-axis always requires customization to match the machine specific functions for doing rotations var gotMultiTurret = false; // specifies if the machine has several turrets @@ -37,9 +36,9 @@ if (!description) { } vendor = "Haas Automation"; vendorUrl = "https://www.haascnc.com"; -legal = "Copyright (C) 2012-2020 by Autodesk, Inc."; +legal = "Copyright (C) 2012-2021 by Autodesk, Inc."; certificationLevel = 2; -minimumRevision = 40783; +minimumRevision = 45702; if (!longDescription) { longDescription = subst("Preconfigured %1 post with support for mill-turn. You can force G112 mode for a specific operation by using Manual NC Action with keyword 'usepolarmode'.", description); @@ -64,80 +63,294 @@ highFeedrate = (unit == IN) ? 470 : 12000; // user-defined properties properties = { - writeMachine: false, // write machine - writeTools: false, // writes the tools - writeVersion: false, // include version info - // preloadTool: false, // preloads next tool on tool change if any - showSequenceNumbers: false, // show sequence numbers - sequenceNumberStart: 10, // first sequence number - sequenceNumberIncrement: 1, // 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. - maximumSpindleSpeed: 2400, // specifies the maximum spindle speed - useParametricFeed: false, // specifies that feed should be output using Q values - showNotes: false, // specifies that operation notes should be output. - useCycles: true, // specifies that drilling cycles should be used. - autoEject: false, // specifies if the part should be automatically ejected at end of program - g53HomePositionX: 0, // home position for X-axis - g53HomePositionY: 0, // home position for Y-axis - g53HomePositionZ: 0, // home position for Z-axis - g53HomePositionSubZ: 0, // home Position for Z when the operation uses the Secondary Spindle - g53WorkPositionSub: 0, // home position for secondary spindle - useTailStock: false, // specifies to use the tailstock or not - useBarFeeder: false, // specifies to use the bar feeder - gotChipConveyor: false, // specifies to use a chip conveyor Y/N - useG112: false, // specifies if the machine has XY polar interpolation (G112) capabilities - useG61: false, // exact stop mode - // useM97: false, - setting102: 1.0, // diameter used by control to calculate feed rates (INCH value) - rapidRewinds: false, // rewinds the C-axis using G0 - useSSV: false, // outputs M38/39 to enable SSV in turning operations - optimizeCAxisSelect: false, // optimize output of enable/disable C-axis codes - gotSecondarySpindle: false, // specifies if the machine has a secondary spindle - looping: false, //output program for M97 looping - numberOfRepeats: 1, //how many times to loop program - useSimpleThread: true, // outputs a G92 threading cycle, false outputs a G76 (standard) threading cycle - airCleanChuck: true, // air clean chucks on transfer and eject - safeStartAllOperations: false // write optional blocks at the beginning of all operations that include all commands to start program -}; - -// user-defined property definitions -propertyDefinitions = { - writeMachine: {title:"Write machine", description:"Output the machine settings in the header of the code.", group:0, type:"boolean"}, - writeTools: {title:"Write tool list", description:"Output a tool list in the header of the code.", group:0, type:"boolean"}, - writeVersion: {title:"Write version", description:"Write the version number in the header of the code.", group:0, type:"boolean"}, - showSequenceNumbers: {title:"Use sequence numbers", description:"Use sequence numbers for each block of outputted code.", group:1, type:"boolean"}, - sequenceNumberStart: {title:"Start sequence number", description:"The number at which to start the sequence numbers.", group:1, type:"integer"}, - sequenceNumberIncrement: {title:"Sequence number increment", description:"The amount by which the sequence number is incremented by in each block.", group:1, type:"integer"}, - optionalStop: {title:"Optional stop", description:"Outputs optional stop code during when necessary in the code.", type:"boolean"}, - separateWordsWithSpace: {title:"Separate words with space", description:"Adds spaces between words if 'yes' is selected.", type:"boolean"}, - useRadius: {title:"Radius arcs", description:"If yes is selected, arcs are outputted using radius values rather than IJK.", type:"boolean"}, - maximumSpindleSpeed: {title:"Max spindle speed", description:"Defines the maximum spindle speed allowed by your machines.", type:"integer", range:[0, 999999999]}, - useParametricFeed: {title:"Parametric feed", description:"Specifies the feed value that should be output using a Q value.", type:"boolean"}, - showNotes: {title:"Show notes", description:"Writes operation notes as comments in the outputted code.", type:"boolean"}, - useCycles: {title:"Use cycles", description:"Specifies if canned drilling cycles should be used.", type:"boolean"}, - autoEject: {title:"Auto eject", description:"Specifies whether the part should automatically eject at the end of a program.", type:"boolean"}, - g53HomePositionX: {title:"G53 home position X", description:"G53 X-axis home position.", type:"number"}, - g53HomePositionY: {title:"G53 home position Y", description:"G53 Y-axis home position.", type:"number"}, - g53HomePositionZ: {title:"G53 home position Z", description:"G53 Z-axis home position.", type:"number"}, - g53HomePositionSubZ: {title:"G53 home position subspindle Z", description:"G53 Z-axis home position when Secondary Spindle is active.", type:"number"}, - g53WorkPositionSub: {title:"G53 subspindle working position", description:"G53 working position for Secondary Spindle when active.", type:"number"}, - useTailStock: {title:"Use tail stock", description:"Enable to use the tail stock.", type:"boolean"}, - useBarFeeder: {title:"Use bar feeder", description:"Enable to use the bar feeder.", type:"boolean"}, - gotChipConveyor: {title:"Got chip conveyor", description:"Specifies whether to use a chip conveyor.", type:"boolean", presentation:"yesno"}, - useG112: {title:"Use polar interpolation", description:"Enables polar interpolation output.", type:"boolean"}, - useG61: {title:"Use exact stop mode", description:"Enables exact stop mode.", type:"boolean"}, - setting102: {title: "Feed rate calculation diameter", description: "Defines the part diameter in inches that the control uses to calculate feed rates.", type: "spatial", range: [0.1, 9999.0]}, - rapidRewinds: {title: "Use G0 for rewinds", description: "Uses G0 moves for rewinding of the C-axis.", type: "boolean"}, - useSSV: {title: "Use SSV", description:"Outputs M38/M39 to enable SSV for turning operations.", type:"boolean"}, - optimizeCAxisSelect: {title:"Optimize C-axis selection", description:"Optimizes the output of enable/disable C-axis codes.", type:"boolean"}, - gotSecondarySpindle: {title:"Got secondary spindle", description:"Specifies if the machine has a secondary spindle.", type:"boolean"}, - looping: {title:"Use M97 looping", description:"Output program for M97 looping.", type:"boolean", presentation:"yesno", group:5}, - numberOfRepeats: {title:"Number of repeats", description:"How many times to loop the program.", type:"integer", range:[0, 99999999], group:5}, - useSimpleThread: {title:"Use simple threading cycle", description:"Enable to output G92 simple threading cycle, disable to output G76 standard threading cycle.", type:"boolean"}, - airCleanChuck: {title:"Air clean chucks", description:"Enable to use the air blast to clean out the chuck on part transfers and part ejection.", type:"boolean"}, - safeStartAllOperations: {title:"Safe start all operations", description:"Write optional blocks at the beginning of all operations that include all commands to start program.", type:"boolean"} + writeMachine: { + title: "Write machine", + description: "Output the machine settings in the header of the code.", + group: 0, + type: "boolean", + value: false, + scope: "post" + }, + writeTools: { + title: "Write tool list", + description: "Output a tool list in the header of the code.", + group: 0, + type: "boolean", + value: false, + scope: "post" + }, + writeVersion: { + title: "Write version", + description: "Write the version number in the header of the code.", + group: 0, + type: "boolean", + value: false, + scope: "post" + }, + showSequenceNumbers: { + title: "Use sequence numbers", + description: "Use sequence numbers for each block of outputted code.", + group: 1, + type: "boolean", + value: false, + scope: "post" + }, + sequenceNumberStart: { + title: "Start sequence number", + description: "The number at which to start the sequence numbers.", + group: 1, + 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: 1, + type: "integer", + value: 1, + scope: "post" + }, + optionalStop: { + title: "Optional stop", + description: "Outputs optional stop code during when necessary in the code.", + type: "boolean", + value: true, + scope: "post" + }, + separateWordsWithSpace: { + title: "Separate words with space", + description: "Adds spaces between words if 'yes' is selected.", + type: "boolean", + value: true, + scope: "post" + }, + useRadius: { + title: "Radius arcs", + description: "If yes is selected, arcs are outputted using radius values rather than IJK.", + type: "boolean", + value: false, + scope: "post" + }, + maximumSpindleSpeed: { + title: "Max spindle speed", + description: "Defines the maximum spindle speed allowed on the main spindle.", + group: 4, + type: "integer", + range: [0, 999999999] + }, + subMaximumSpindleSpeed: { + title: "Max spindle speed for subspindle", + description: "Defines the maximum spindle speed allowed on the subspindle.", + group: 4, + type: "integer", + range: [0, 999999999] + }, + useParametricFeed: { + title: "Parametric feed", + description: "Specifies the feed value that should be output using a Q value.", + type: "boolean", + value: false, + scope: "post" + }, + showNotes: { + title: "Show notes", + description: "Writes operation notes as comments in the outputted code.", + type: "boolean", + value: false, + scope: "post" + }, + useCycles: { + title: "Use cycles", + description: "Specifies if canned drilling cycles should be used.", + type: "boolean", + value: true, + scope: "post" + }, + autoEject: { + title: "Auto eject", + description: "Specifies whether the part should automatically eject at the end of a program.", + type: "boolean", + value: false, + scope: "post" + }, + g53HomePositionX: { + title: "G53 home position X", + description: "G53 X-axis home position.", + type: "number", + value: 0, + scope: "post" + }, + g53HomePositionY: { + title: "G53 home position Y", + description: "G53 Y-axis home position.", + type: "number", + value: 0, + scope: "post" + }, + g53HomePositionZ: { + title: "G53 home position Z", + description: "G53 Z-axis home position.", + type: "number", + value: 0, + scope: "post" + }, + g53HomePositionSubZ: { + title: "G53 home position subspindle Z", + description: "G53 Z-axis home position when Secondary Spindle is active.", + type: "number", + value: 0, + scope: "post" + }, + g53WorkPositionSub: { + title: "G53 subspindle working position", + description: "G53 working position for Secondary Spindle when active.", + type: "number", + value: 0, + scope: "post" + }, + useTailStock: { + title: "Use tail stock", + description: "Enable to use the tail stock.", + type: "boolean", + value: false, + scope: "post" + }, + useBarFeeder: { + title: "Use bar feeder", + description: "Enable to use the bar feeder.", + type: "boolean", + value: false, + scope: "post" + }, + gotChipConveyor: { + title: "Got chip conveyor", + description: "Specifies whether to use a chip conveyor.", + type: "boolean", + presentation: "yesno", + value: false, + scope: "post" + }, + useG112: { + title: "Use polar interpolation", + description: "Enables polar interpolation output.", + type: "boolean", + value: false, + scope: "post" + }, + usePolarCircular: { + title: "Use polar circular", + description: "Enables circular interpolation with polar output.", + type: "boolean", + group: 3, + value: false, + scope: "post" + }, + xAxisMinimum: { + title: "X-axis minimum limit", + description: "Defines the lower limit of X-axis travel as a radius value.", + type: "spatial", + range: [0, -99999], + group: 3, + value: 0, + scope: "post" + }, + useG61: { + title: "Use exact stop mode", + description: "Enables exact stop mode.", + type: "boolean", + value: false, + scope: "post" + }, + setting102: { + title: "Feed rate calculation diameter", + description: "Defines the part diameter in inches that the control uses to calculate feed rates.", + type: "spatial", + range: [0.1, 9999], + value: 1, + scope: "post" + }, + rapidRewinds: { + title: "Use G0 for rewinds", + description: "Uses G0 moves for rewinding of the C-axis.", + type: "boolean", + value: false, + scope: "post" + }, + useSSV: { + title: "Use SSV", + description: "Outputs M38/M39 to enable SSV for turning operations.", + type: "boolean", + value: false, + scope: "post" + }, + optimizeCAxisSelect: { + title: "Optimize C-axis selection", + description: "Optimizes the output of enable/disable C-axis codes.", + type: "boolean", + value: false, + scope: "post" + }, + gotSecondarySpindle: { + title: "Got secondary spindle", + description: "Specifies if the machine has a secondary spindle.", + type: "boolean", + value: false, + scope: "post" + }, + looping: { + title: "Use M97 looping", + description: "Output program for M97 looping.", + type: "boolean", + presentation: "yesno", + group: 5, + value: false, + scope: "post" + }, + numberOfRepeats: { + title: "Number of repeats", + description: "How many times to loop the program.", + type: "integer", + range: [0, 99999999], + group: 5, + value: 1, + scope: "post" + }, + useSimpleThread: { + title: "Use simple threading cycle", + description: "Enable to output G92 simple threading cycle, disable to output G76 standard threading cycle.", + type: "boolean", + value: true, + scope: "post" + }, + airCleanChuck: { + title: "Air clean chucks", + description: "Enable to use the air blast to clean out the chuck on part transfers and part ejection.", + type: "boolean", + value: true, + scope: "post" + }, + safeStartAllOperations: { + title: "Safe start all operations", + description: "Write optional blocks at the beginning of all operations that include all commands to start program.", + type: "boolean", + value: false, + scope: "post" + }, + useYAxisForDrilling: { + title: "Position in Y for axial drilling", + description: "Positions in Y for axial drilling options when it can instead of using the C-axis.", + type: "boolean", + value: false, + scope: "post" + }, + useG187: { + title: "Use G187", + description: "Specifies that smoothing using G187 should be used for milling operations.", + type: "boolean", + value: false, + scope: "post" + } }; var permittedCommentChars = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,=_-"; @@ -160,6 +373,9 @@ var rpmFormat = createFormat({decimals:0}); var secFormat = createFormat({decimals:3, forceDecimal:true}); // seconds - range 0.001-99999.999 var milliFormat = createFormat({decimals:0}); // milliseconds // range 1-9999 var taperFormat = createFormat({decimals:1, scale:DEG}); +var integerFormat = createFormat({decimals:0, forceDecimal:false, trim:true}); +var threadQFormat = createFormat({decimals:3, forceDecimal:false, trimLeadZero:true, scale:1000}); +var g76AFormat = createFormat({decimals:(unit == MM ? 3 : 4)}); var xOutput = createVariable({prefix:"X"}, xFormat); var yOutput = createVariable({prefix:"Y"}, yFormat); @@ -181,7 +397,10 @@ var kOutput = createReferenceVariable({prefix:"K", force:true}, spatialFormat); var g76IOutput = createVariable({prefix:"I", force:true}, zFormat); // no scaling var g76KOutput = createVariable({prefix:"K", force:true}, zFormat); // no scaling var g76DOutput = createVariable({prefix:"D", force:true}, zFormat); // no scaling -var g76AOutput = createVariable({prefix:"A", force:true}, zFormat); // no scaling +var g76AOutput = createVariable({prefix:"A", force:true}, g76AFormat); // no scaling +var g76QOutput = createVariable({prefix:"Q", force:true}, threadQFormat); +var g92IOutput = createVariable({prefix:"I"}, zFormat); // no scaling +var g92QOutput = createVariable({prefix:"Q"}, threadQFormat); var gMotionModal = createModal({}, gFormat); // modal group 1 // G0-G3, ... var gPlaneModal = createModal({onchange:function () {gMotionModal.reset();}}, gFormat); // modal group 2 // G17-19 @@ -216,6 +435,9 @@ var forcePolarMode; var bestABCIndex = undefined; var partCutoff = false; var ejectRoutine = false; +var g100Mirroring = false; +var g14IsActive = false; +var xAxisMinimum; // used to convert blocks to optional for safeStartAllOperations, might get used outside of onSection var skipBlock = false; @@ -253,11 +475,19 @@ function getCode(code) { machineState.tailstockIsActive = false; return mFormat.format(22); case "ENGAGE_C_AXIS": - machineState.cAxisIsEngaged = true; - return cAxisEngageModal.format(154); + if (currentSection.spindle == SPINDLE_PRIMARY) { + machineState.cAxisIsEngaged = true; + return cAxisEngageModal.format(154); + } else { + return ""; + } case "DISENGAGE_C_AXIS": - machineState.cAxisIsEngaged = false; - return cAxisEngageModal.format(155); + if (currentSection.spindle == SPINDLE_PRIMARY) { + machineState.cAxisIsEngaged = false; + return cAxisEngageModal.format(155); + } else { + return ""; + } case "POLAR_INTERPOLATION_ON": return gPolarModal.format(112); case "POLAR_INTERPOLATION_OFF": @@ -271,7 +501,7 @@ function getCode(code) { return mFormat.format(5); } else if (machineState.subSpindleIsActive) { machineState.subSpindleIsActive = false; - return mFormat.format(145); + return mFormat.format(g14IsActive ? 5 : 145); } else { return undefined; } @@ -289,10 +519,10 @@ function getCode(code) { return mFormat.format(4); case "START_SUB_SPINDLE_CW": machineState.subSpindleIsActive = true; - return mFormat.format(143); + return mFormat.format(g14IsActive ? 3 : 143); case "START_SUB_SPINDLE_CCW": machineState.subSpindleIsActive = true; - return mFormat.format(144); + return mFormat.format(g14IsActive ? 4 : 144); case "MAIN_SPINDLE_BRAKE_ON": machineState.mainSpindleBrakeIsActive = true; return cAxisBrakeModal.format(14); @@ -301,10 +531,10 @@ function getCode(code) { return cAxisBrakeModal.format(15); case "SUB_SPINDLE_BRAKE_ON": machineState.subSpindleBrakeIsActive = true; - return cAxisBrakeModal.format(114); + return cAxisBrakeModal.format(g14IsActive ? 14 : 114); case "SUB_SPINDLE_BRAKE_OFF": machineState.subSpindleBrakeIsActive = false; - return cAxisBrakeModal.format(115); + return cAxisBrakeModal.format(g14IsActive ? 15 : 115); case "FEED_MODE_UNIT_REV": machineState.feedPerRevolution = true; return gFeedModeModal.format(99); @@ -403,10 +633,16 @@ function startSpindle(forceRPMMode, initialPosition, rpm) { } var useConstantSurfaceSpeed = currentSection.getTool().getSpindleMode() == SPINDLE_CONSTANT_SURFACE_SPEED; - var maximumSpindleSpeed = (tool.maximumSpindleSpeed > 0) ? Math.min(tool.maximumSpindleSpeed, properties.maximumSpindleSpeed) : properties.maximumSpindleSpeed; + var maxSpeed = (currentSection.spindle == SPINDLE_SECONDARY) ? getProperty("subMaximumSpindleSpeed") : getProperty("maximumSpindleSpeed"); + var maximumSpindleSpeed = (tool.maximumSpindleSpeed > 0) ? Math.min(tool.maximumSpindleSpeed, maxSpeed) : maxSpeed; if (useConstantSurfaceSpeed && !forceRPMMode) { skipBlock = _skipBlock; writeBlock(gFormat.format(50), sOutput.format(maximumSpindleSpeed)); + } else if (!isFirstSection()) { // maximum spindle speed needs to be set when switching from SFM to RPM + var prevConstantSurfaceSpeed = getPreviousSection().getTool().getSpindleMode() == SPINDLE_CONSTANT_SURFACE_SPEED; + if (prevConstantSurfaceSpeed && !useConstantSurfaceSpeed) { + writeBlock(gFormat.format(50), sOutput.format(maxSpeed)); + } } gSpindleModeModal.reset(); @@ -442,12 +678,11 @@ function startSpindle(forceRPMMode, initialPosition, rpm) { } break; case SPINDLE_SECONDARY: // sub spindle - if (!properties.gotSecondarySpindle) { + if (!getProperty("gotSecondarySpindle")) { error(localize("Secondary spindle is not available.")); return; } if (machineState.isTurningOperation || machineState.axialCenterDrilling) { // turning sub spindle - // use could also swap spindles using G14/G15 gSpindleModeModal.reset(); skipBlock = _skipBlock; writeBlock( @@ -461,7 +696,7 @@ function startSpindle(forceRPMMode, initialPosition, rpm) { break; } - if (properties.useSSV) { + if (getProperty("useSSV")) { if (machineState.isTurningOperation && hasParameter("operation-strategy") && getParameter("operation-strategy") != "turningThread") { skipBlock = _skipBlock; writeBlock(ssvModal.format(38)); @@ -475,15 +710,15 @@ function writeRetract(section, retractZ) { if (!isFirstSection()) { if (gotYAxis) { skipBlock = _skipBlock; - writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + yFormat.format(properties.g53HomePositionY)); // retract + writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + yFormat.format(getProperty("g53HomePositionY"))); // retract yOutput.reset(); } skipBlock = _skipBlock; - writeBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(properties.g53HomePositionX)); // retract + writeBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(getProperty("g53HomePositionX"))); // retract xOutput.reset(); if (retractZ) { skipBlock = _skipBlock; - writeBlock(gFormat.format(53), gMotionModal.format(0), "Z" + zFormat.format((section.spindle == SPINDLE_SECONDARY) ? properties.g53HomePositionSubZ : properties.g53HomePositionZ)); // retract with regard to spindle + writeBlock(gFormat.format(53), gMotionModal.format(0), "Z" + zFormat.format((section.spindle == SPINDLE_SECONDARY) ? getProperty("g53HomePositionSubZ") : getProperty("g53HomePositionZ"))); // retract with regard to spindle zOutput.reset(); } } @@ -591,16 +826,16 @@ function getCWithinRange(x, y, _c, clockwise) { // see if rewind is required forceRewind = false; - if ((cFormat.getResultingValue(c) < cFormat.getResultingValue(cyclicLimit[0])) || (cFormat.getResultingValue(c) > cFormat.getResultingValue(cyclicLimit[1]))) { + if ((cFormat.getResultingValue(c) < abcFormat.getResultingValue(cyclicLimit[0])) || (cFormat.getResultingValue(c) > abcFormat.getResultingValue(cyclicLimit[1]))) { if (!cyclic) { forceRewind = true; } c = getCClosest(x, y, 0); // find closest C to 0 - if ((cFormat.getResultingValue(c) < cFormat.getResultingValue(cyclicLimit[0])) || (cFormat.getResultingValue(c) > cFormat.getResultingValue(cyclicLimit[1]))) { + if ((cFormat.getResultingValue(c) < abcFormat.getResultingValue(cyclicLimit[0])) || (cFormat.getResultingValue(c) > abcFormat.getResultingValue(cyclicLimit[1]))) { var midRange = cyclicLimit[0] + (cyclicLimit[1] - cyclicLimit[0]) / 2; c = getCClosest(x, y, midRange); // find closest C to midRange } - if ((cFormat.getResultingValue(c) < cFormat.getResultingValue(cyclicLimit[0])) || (cFormat.getResultingValue(c) > cFormat.getResultingValue(cyclicLimit[1]))) { + if ((cFormat.getResultingValue(c) < abcFormat.getResultingValue(cyclicLimit[0])) || (cFormat.getResultingValue(c) > abcFormat.getResultingValue(cyclicLimit[1]))) { error(localize("Unable to find C-axis position within the defined range.")); return 0; } @@ -632,9 +867,9 @@ function writeBlock() { skipBlock = false; return; } - if (properties.showSequenceNumbers) { + if (getProperty("showSequenceNumbers")) { if (sequenceNumber > 99999) { - sequenceNumber = properties.sequenceNumberStart; + sequenceNumber = getProperty("sequenceNumberStart"); } if (optionalSection || skipBlock) { if (text) { @@ -643,7 +878,7 @@ function writeBlock() { } else { writeWords2("N" + sequenceNumber, arguments); } - sequenceNumber += properties.sequenceNumberIncrement; + sequenceNumber += getProperty("sequenceNumberIncrement"); } else { if (optionalSection || skipBlock) { writeWords2("/", arguments); @@ -658,11 +893,11 @@ function writeBlock() { Writes the specified optional block. */ function writeOptionalBlock() { - if (properties.showSequenceNumbers) { + if (getProperty("showSequenceNumbers")) { var words = formatWords(arguments); if (words) { writeWords("/", "N" + sequenceNumber, words); - sequenceNumber += properties.sequenceNumberIncrement; + sequenceNumber += getProperty("sequenceNumberIncrement"); } } else { writeWords2("/", arguments); @@ -692,20 +927,22 @@ var machineConfigurationMainSpindle; var machineConfigurationSubSpindle; function onOpen() { - if (properties.useRadius) { + if (getProperty("useRadius")) { maximumCircularSweep = toRad(90); // avoid potential center calculation errors for CNC } - if (properties.useG61) { + if (getProperty("useG61")) { gExactStopModal.format(64); } + xAxisMinimum = getProperty("xAxisMinimum"); + if (true) { var bAxisMain = createAxis({coordinate:1, table:false, axis:[0, -1, 0], range:[-0.001, 90.001], preference:0}); - var cAxisMain = createAxis({coordinate:2, table:true, axis:[0, 0, 1], cyclic:false, range:[-8280, 8280], preference:0}); + var cAxisMain = createAxis({coordinate:2, table:true, axis:[0, 0, 1], cyclic:false, range:[-8280, 8280], preference:0, reset:1}); var bAxisSub = createAxis({coordinate:1, table:false, axis:[0, -1, 0], range:[-0.001, 180.001], preference:0}); - var cAxisSub = createAxis({coordinate:2, table:true, axis:[0, 0, 1], cyclic:false, range:[-8280, 8280], preference:0}); + var cAxisSub = createAxis({coordinate:2, table:true, axis:[0, 0, 1], cyclic:false, range:[-8280, 8280], preference:0, reset:1}); machineConfigurationMainSpindle = gotBAxis ? new MachineConfiguration(bAxisMain, cAxisMain) : new MachineConfiguration(cAxisMain); machineConfigurationSubSpindle = gotBAxis ? new MachineConfiguration(bAxisSub, cAxisSub) : new MachineConfiguration(cAxisSub); @@ -729,11 +966,11 @@ function onOpen() { return; } - if (!properties.separateWordsWithSpace) { + if (!getProperty("separateWordsWithSpace")) { setWordSeparator(""); } - sequenceNumber = properties.sequenceNumberStart; + sequenceNumber = getProperty("sequenceNumberStart"); writeln("%"); if (programName) { @@ -759,7 +996,7 @@ function onOpen() { return; } - if (properties.writeVersion) { + if (getProperty("writeVersion")) { if ((typeof getHeaderVersion == "function") && getHeaderVersion()) { writeComment(localize("post version") + ": " + getHeaderVersion()); } @@ -773,7 +1010,7 @@ function onOpen() { var model = machineConfiguration.getModel(); var description = machineConfiguration.getDescription(); - if (properties.writeMachine && (vendor || model || description)) { + if (getProperty("writeMachine") && (vendor || model || description)) { writeComment(localize("Machine")); if (vendor) { writeComment(" " + localize("vendor") + ": " + vendor); @@ -787,7 +1024,7 @@ function onOpen() { } // dump tool information - if (properties.writeTools) { + if (getProperty("writeTools")) { var zRanges = {}; if (is3D()) { var numberOfSections = getNumberOfSections(); @@ -856,8 +1093,8 @@ function onOpen() { } // support program looping for bar work - if (properties.looping) { - if (properties.numberOfRepeats < 1) { + if (getProperty("looping")) { + if (getProperty("numberOfRepeats") < 1) { error(localize("numberOfRepeats must be greater than 0.")); return; } @@ -868,7 +1105,8 @@ function onOpen() { writeln(""); writeComment(localize("Local Looping")); writeln(""); - writeBlock(mFormat.format(97), "P1", "L" + properties.numberOfRepeats); + writeBlock(mFormat.format(97), "P1", "L" + getProperty("numberOfRepeats")); + onCommand(COMMAND_OPEN_DOOR); writeBlock(mFormat.format(30)); writeln(""); writeln(""); @@ -887,7 +1125,9 @@ function onOpen() { break; } - // writeBlock("#" + (firstFeedParameter - 1) + "=" + ((currentSection.spindle == SPINDLE_SECONDARY) ? properties.g53HomePositionSubZ : properties.g53HomePositionZ), formatComment("g53HomePositionZ")); + onCommand(COMMAND_CLOSE_DOOR); + + // writeBlock("#" + (firstFeedParameter - 1) + "=" + ((currentSection.spindle == SPINDLE_SECONDARY) ? getProperty("g53HomePositionSubZ") : getProperty("g53HomePositionZ")), formatComment("g53HomePositionZ")); var usesPrimarySpindle = false; var usesSecondarySpindle = false; @@ -906,34 +1146,35 @@ function onOpen() { } } - writeBlock(gFormat.format(50), sOutput.format(properties.maximumSpindleSpeed)); + writeBlock(gFormat.format(50), sOutput.format(getSection(0).spindle == SPINDLE_PRIMARY ? getProperty("maximumSpindleSpeed") : getProperty("subMaximumSpindleSpeed"))); sOutput.reset(); - if (properties.gotChipConveyor) { + if (getProperty("gotChipConveyor")) { onCommand(COMMAND_START_CHIP_TRANSPORT); } if (gotYAxis) { - writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + yFormat.format(properties.g53HomePositionY)); // retract + writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + yFormat.format(getProperty("g53HomePositionY"))); // retract } - writeBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(properties.g53HomePositionX)); // retract - if (properties.gotSecondarySpindle) { - writeBlock(gFormat.format(53), gMotionModal.format(0), "B" + abcFormat.format(0)); // retract Sub Spindle if applicable + writeBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(getProperty("g53HomePositionX"))); // retract + writeBlock(gFormat.format(53), gMotionModal.format(0), "Z" + zFormat.format(getProperty("g53HomePositionZ"))); // retract + if (getProperty("gotSecondarySpindle")) { + var b = getSection(0).spindle == SPINDLE_PRIMARY ? 0 : getProperty("g53WorkPositionSub"); + writeBlock(gFormat.format(53), gMotionModal.format(0), "B" + spatialFormat.format(b)); // retract Sub Spindle if applicable } - writeBlock(gFormat.format(53), gMotionModal.format(0), "Z" + zFormat.format(properties.g53HomePositionZ)); // retract // automatically eject part at end of program - if (properties.autoEject) { + if (getProperty("autoEject")) { ejectRoutine = true; } /* - if (properties.useM97) { + if (getProperty("useM97")) { for (var i = 0; i < getNumberOfSections(); ++i) { var section = getSection(i); - writeBlock(mFormat.format(97), pFormat.format(section.getId() + properties.sequenceNumberStart), conditional(section.hasParameter("operation-comment"), "(" + section.getParameter("operation-comment") + ")")); + writeBlock(mFormat.format(97), pFormat.format(section.getId() + getProperty("sequenceNumberStart")), conditional(section.hasParameter("operation-comment"), "(" + section.getParameter("operation-comment") + ")")); } writeBlock(mFormat.format(30)); - if (properties.showSequenceNumbers && properties.useM97) { + if (getProperty("showSequenceNumbers") && getProperty("useM97")) { error(localize("Properties 'showSequenceNumbers' and 'useM97' cannot be active together at the same time.")); return; } @@ -972,6 +1213,43 @@ function forceAny() { forceFeed(); } +function writeG187() { + if ((hasParameter("operation-strategy") && (getParameter("operation-strategy") == "drill")) || !machineState.liveToolIsActive) { + writeBlock(gFormat.format(187)); // reset G187 setting to machine default + } else if (hasParameter("operation:tolerance")) { + var tolerance = Math.max(getParameter("operation:tolerance"), 0); + if (tolerance > 0) { + var stockToLeaveThreshold = toUnit(0.1, MM); + var stockToLeave = 0; + var verticalStockToLeave = 0; + if (hasParameter("operation:stockToLeave")) { + stockToLeave = spatialFormat.getResultingValue(getParameter("operation:stockToLeave")); + } + if (hasParameter("operation:verticalStockToLeave")) { + verticalStockToLeave = spatialFormat.getResultingValue(getParameter("operation:verticalStockToLeave")); + } + + var workMode; + if (((stockToLeave > stockToLeaveThreshold) && (verticalStockToLeave > stockToLeaveThreshold)) || + (hasParameter("operation:strategy") && getParameter("operation:strategy") == "face")) { + workMode = 1; // roughing + } else { + if ((stockToLeave > 0) || (verticalStockToLeave > 0)) { + workMode = 2; // default + } else { + workMode = 3; // fine + } + } + writeBlock(gFormat.format(187), "P" + workMode); // set tolerance mode + // writeBlock(gFormat.format(187), "P" + workMode, "E" + spatialFormat.format(tolerance)); // set tolerance mode + } else { + writeBlock(gFormat.format(187)); // reset G187 setting to machine default + } + } else { + writeBlock(gFormat.format(187)); // reset G187 setting to machine default + } +} + function FeedContext(id, description, feed) { this.id = id; this.description = description; @@ -1159,9 +1437,9 @@ function setWorkPlane(abc) { skipBlock = _skipBlock; writeBlock( gMotionModal.format(0), - conditional(machineConfiguration.isMachineCoordinate(0), "A" + abcFormat.format(abc.x)), - conditional(machineConfiguration.isMachineCoordinate(1), "B" + abcFormat.format(getB(abc, currentSection))), - conditional(machineConfiguration.isMachineCoordinate(2), "C" + abcFormat.format(abc.z)) + conditional(machineConfiguration.isMachineCoordinate(0), aOutput.format(abc.x)), + conditional(machineConfiguration.isMachineCoordinate(1), bOutput.format(getB(abc, currentSection))), + conditional(machineConfiguration.isMachineCoordinate(2), cOutput.format(abc.z)) ); if (!currentSection.isMultiAxis() && !machineState.usePolarMode && !machineState.useXZCMode) { @@ -1173,6 +1451,19 @@ function setWorkPlane(abc) { } } +function getBestABCIndex(section) { + var fitFlag = false; + var index = undefined; + for (var i = 0; i < 6; ++i) { + fitFlag = doesToolpathFitInXYRange(getBestABC(section, i)); + if (fitFlag) { + index = i; + break; + } + } + return index; +} + function getBestABC(section, which) { var W = section.workPlane; var abc = machineConfiguration.getABC(W); @@ -1396,7 +1687,7 @@ function onSection() { abcFormat.areDifferent(bAxisOrientationTurning.y, machineState.currentBAxisOrientationTurning.y) || abcFormat.areDifferent(bAxisOrientationTurning.z, machineState.currentBAxisOrientationTurning.z)); - operationNeedsSafeStart = properties.safeStartAllOperations && !isFirstSection(); + operationNeedsSafeStart = getProperty("safeStartAllOperations") && !isFirstSection(); if (insertToolCall || newSpindle || newWorkOffset || newWorkPlane && (!currentSection.isPatterned() && (!machineState.stockTransferIsActive && !partCutoff))) { @@ -1425,12 +1716,12 @@ function onSection() { } /* - if (properties.useM97 && !isFirstSection()) { + if (getProperty("useM97") && !isFirstSection()) { writeBlock(mFormat.format(99)); } */ - if (properties.useSSV) { + if (getProperty("useSSV")) { // ensure SSV is turned off writeBlock(ssvModal.format(39)); } @@ -1438,8 +1729,8 @@ function onSection() { writeln(""); /* - if (properties.useM97) { - writeBlock("N" + spatialFormat.format(currentSection.getId() + properties.sequenceNumberStart)); + if (getProperty("useM97")) { + writeBlock("N" + spatialFormat.format(currentSection.getId() + getProperty("sequenceNumberStart"))); } */ @@ -1460,7 +1751,7 @@ function onSection() { writeRetract(currentSection, true); // retract in Z also } - if (properties.showNotes && hasParameter("notes")) { + if (getProperty("showNotes") && hasParameter("notes")) { var notes = getParameter("notes"); if (notes) { var lines = String(notes).split("\n"); @@ -1479,12 +1770,12 @@ function onSection() { if (insertToolCall) { forceWorkPlane(); } - if (!properties.optimizeCAxisSelect) { + if (!getProperty("optimizeCAxisSelect")) { cAxisEngageModal.reset(); } retracted = insertToolCall; - if (!isFirstSection() && properties.optionalStop) { + if (!isFirstSection() && getProperty("optionalStop")) { skipBlock = !insertToolCall; onCommand(COMMAND_OPTIONAL_STOP); } @@ -1520,15 +1811,29 @@ function onSection() { return; } - if (properties.gotSecondarySpindle) { + if (getProperty("gotSecondarySpindle")) { switch (currentSection.spindle) { case SPINDLE_PRIMARY: // main spindle + cFormat = createFormat({decimals:3, forceDecimal:true, scale:DEG}); + cOutput = createVariable({prefix:"C"}, cFormat); skipBlock = !insertToolCall; writeBlock(gSpindleModal.format(15)); + if (gotYAxis && g100Mirroring) { + writeBlock(gFormat.format(100), "Y0"); + g100Mirroring = false; + } + g14IsActive = false; break; case SPINDLE_SECONDARY: // sub spindle + cFormat = createFormat({decimals:3, forceDecimal:true, scale:-DEG}); + cOutput = createVariable({prefix:"M19 R"}, cFormat); // s/b M119 with G15 skipBlock = !insertToolCall; writeBlock(gSpindleModal.format(14)); + if (gotYAxis && !g100Mirroring) { + writeBlock(gFormat.format(101), "Y0"); + g100Mirroring = true; + } + g14IsActive = true; break; } } @@ -1557,7 +1862,7 @@ function onSection() { } /* - if (properties.preloadTool) { + if (getProperty("preloadTool")) { var nextTool = getNextTool(tool.number); if (nextTool) { var compensationOffset = nextTool.isTurningTool() ? nextTool.compensationOffset : nextTool.lengthOffset; @@ -1586,9 +1891,16 @@ function onSection() { if (!machineState.stockTransferIsActive) { if (machineState.isTurningOperation || machineState.axialCenterDrilling) { skipBlock = !insertToolCall && (machineState.cAxisIsEngaged != undefined); - writeBlock(conditional(machineState.cAxisIsEngaged || machineState.cAxisIsEngaged == undefined), getCode("DISENGAGE_C_AXIS")); + writeBlock(conditional(machineState.cAxisIsEngaged || (machineState.cAxisIsEngaged == undefined)), getCode("DISENGAGE_C_AXIS")); } else { // milling - writeBlock(conditional(!machineState.cAxisIsEngaged || machineState.cAxisIsEngaged == undefined), getCode("ENGAGE_C_AXIS")); + var engage = (currentSection.spindle == SPINDLE_PRIMARY) && (!machineState.cAxisIsEngaged || machineState.cAxisIsEngaged == undefined); + if (engage) { + var code = getCode("ENGAGE_C_AXIS"); + if (code) { + writeBlock(code); + writeBlock(gMotionModal.format(0), gFormat.format(28), "H" + abcFormat.format(0)); + } + } } } @@ -1611,7 +1923,7 @@ function onSection() { } // Engage tailstock - if (properties.useTailStock) { + if (getProperty("useTailStock")) { if (machineState.axialCenterDrilling || (currentSection.spindle == SPINDLE_SECONDARY) || (machineState.liveToolIsActive && (getMachiningDirection(currentSection) == MACHINING_DIRECTION_AXIAL))) { if (currentSection.tailstock) { @@ -1627,22 +1939,20 @@ function onSection() { // see page 138 in 96-8700an for stock transfer / G199/G198 var spindleChange = forceSpindleSpeed || newSpindle || isSpindleSpeedDifferent() || (!machineState.liveToolIsActive && !machineState.mainSpindleIsActive && !machineState.subSpindleIsActive); - if (!machineState.stockTransferIsActive) { - if (insertToolCall || operationNeedsSafeStart || + if (insertToolCall || operationNeedsSafeStart || spindleChange || isFirstSection()) { - if (machineState.isTurningOperation) { - if (spindleSpeed > 99999) { - warning(subst(localize("Spindle speed exceeds maximum value for operation \"%1\"."), getOperationComment())); - } - } else { - if (spindleSpeed > 6000) { - warning(subst(localize("Spindle speed exceeds maximum value for operation \"%1\"."), getOperationComment())); - } + if (machineState.isTurningOperation) { + if (spindleSpeed > 99999) { + warning(subst(localize("Spindle speed exceeds maximum value for operation \"%1\"."), getOperationComment())); + } + } else { + if (spindleSpeed > 6000) { + warning(subst(localize("Spindle speed exceeds maximum value for operation \"%1\"."), getOperationComment())); } - skipBlock = !insertToolCall && !spindleChange; - startSpindle(true, getFramePosition(currentSection.getInitialPosition())); } + skipBlock = !insertToolCall && !spindleChange; + startSpindle(true, getFramePosition(currentSection.getInitialPosition())); } // wcs @@ -1716,6 +2026,10 @@ function onSection() { } } + if (getProperty("useG187")) { + writeG187(); + } + var initialPosition = getFramePosition(currentSection.getInitialPosition()); /* if (!retracted) { @@ -1735,7 +2049,7 @@ function onSection() { } gMotionModal.reset(); - if (properties.useG61) { + if (getProperty("useG61")) { writeBlock(gExactStopModal.format(61)); } @@ -1761,7 +2075,7 @@ function onSection() { startSpindle(false); } - if (properties.useParametricFeed && + if (getProperty("useParametricFeed") && hasParameter("operation-strategy") && (getParameter("operation-strategy") != "drill") && // legacy !(currentSection.hasAnyCycle && currentSection.hasAnyCycle()) && @@ -1805,10 +2119,18 @@ function getPlane() { /** Returns true if the toolpath fits within the machine XY limits for the given C orientation. */ function doesToolpathFitInXYRange(abc) { + var xMin = xAxisMinimum * Math.abs(xFormat.getScale()); + var yMin = yAxisMinimum * Math.abs(yFormat.getScale()); + var yMax = yAxisMaximum * Math.abs(yFormat.getScale()); var c = 0; if (abc) { c = abc.z; } + if (Vector.dot(machineConfiguration.getAxisU().getAxis(), new Vector(0, 0, 1)) != 0) { + c *= (machineConfiguration.getAxisU().getAxis().getCoordinate(2) >= 0) ? 1 : -1; // C-axis is the U-axis + } else { + c *= (machineConfiguration.getAxisV().getAxis().getCoordinate(2) >= 0) ? 1 : -1; // C-axis is the V-axis + } var dx = new Vector(Math.cos(c), Math.sin(c), 0); var dy = new Vector(Math.cos(c + Math.PI / 2), Math.sin(c + Math.PI / 2), 0); @@ -1818,25 +2140,32 @@ function doesToolpathFitInXYRange(abc) { var yRange = currentSection.getGlobalRange(dy); if (false) { // DEBUG - writeComment("toolpath X min: " + xFormat.format(xRange[0]) + ", " + "Limit " + xFormat.format(xAxisMinimum)); - writeComment("X-min within range: " + (xFormat.getResultingValue(xRange[0]) >= xFormat.getResultingValue(xAxisMinimum))); - writeComment("toolpath Y min: " + spatialFormat.getResultingValue(yRange[0]) + ", " + "Limit " + yAxisMinimum); - writeComment("Y-min within range: " + (spatialFormat.getResultingValue(yRange[0]) >= yAxisMinimum)); - writeComment("toolpath Y max: " + (spatialFormat.getResultingValue(yRange[1]) + ", " + "Limit " + yAxisMaximum)); - writeComment("Y-max within range: " + (spatialFormat.getResultingValue(yRange[1]) <= yAxisMaximum)); + writeComment( + "toolpath X minimum= " + xFormat.format(xRange[0]) + ", " + "Limit= " + xMin + ", " + + "within range= " + (xFormat.getResultingValue(xRange[0]) >= xMin) + ); + writeComment( + "toolpath Y minimum= " + yFormat.getResultingValue(yRange[0]) + ", " + "Limit= " + yMin + ", " + + "within range= " + (yFormat.getResultingValue(yRange[0]) >= yMin) + ); + writeComment( + "toolpath Y maximum= " + (yFormat.getResultingValue(yRange[1]) + ", " + "Limit= " + yMax) + ", " + + "within range= " + (yFormat.getResultingValue(yRange[1]) <= yMax) + ); + writeln(""); } if (getMachiningDirection(currentSection) == MACHINING_DIRECTION_RADIAL) { // G19 plane - if ((spatialFormat.getResultingValue(yRange[0]) >= yAxisMinimum) && - (spatialFormat.getResultingValue(yRange[1]) <= yAxisMaximum)) { + if ((yFormat.getResultingValue(yRange[0]) >= yMin) && + (yFormat.getResultingValue(yRange[1]) <= yMax)) { return true; // toolpath does fit in XY range } else { return false; // toolpath does not fit in XY range } } else { // G17 plane - if ((xFormat.getResultingValue(xRange[0]) >= xFormat.getResultingValue(xAxisMinimum)) && - (spatialFormat.getResultingValue(yRange[0]) >= yAxisMinimum) && - (spatialFormat.getResultingValue(yRange[1]) <= yAxisMaximum)) { + if ((xFormat.getResultingValue(xRange[0]) >= xMin) && + (yFormat.getResultingValue(yRange[0]) >= yMin) && + (yFormat.getResultingValue(yRange[1]) <= yMax)) { return true; // toolpath does fit in XY range } else { return false; // toolpath does not fit in XY range @@ -1881,7 +2210,7 @@ function updateMachiningMode(section) { !xFormat.isSignificant(getGlobalPosition(section.getInitialPosition()).x) && !yFormat.isSignificant(getGlobalPosition(section.getInitialPosition()).y) && (spatialFormat.format(section.getFinalPosition().x) == 0) && - !doesCannedCycleIncludeYAxisMotion()) { // catch drill issue for old versions + !doesCannedCycleIncludeYAxisMotion(section)) { // catch drill issue for old versions // single hole on XY center if (section.getTool().isLiveTool && section.getTool().isLiveTool()) { // use live tool @@ -1889,22 +2218,21 @@ function updateMachiningMode(section) { // use main spindle for axialCenterDrilling machineState.axialCenterDrilling = true; } - } else { - // several holes not on XY center, use live tool in XZCMode - machineState.useXZCMode = true; - } - } else { // milling - fitFlag = false; - bestABCIndex = undefined; - for (var i = 0; i < 6; ++i) { - fitFlag = doesToolpathFitInXYRange(getBestABC(section, i)); - if (fitFlag) { - bestABCIndex = i; - break; + } else { // several holes not on XY center + bestABCIndex = getBestABCIndex(section); + if (getProperty("useYAxisForDrilling") && (bestABCIndex != undefined) && !doesCannedCycleIncludeYAxisMotion(section)) { + // use XYZ-mode + } else { // use XZC mode + machineState.useXZCMode = true; } } - if (fitFlag) { + } else { // milling + bestABCIndex = getBestABCIndex(section); + if (bestABCIndex != undefined) { if (forcePolarMode) { // polar mode is requested by user + if (currentSection.spindle == SPINDLE_SECONDARY) { + error(localize("Polar mode is not supported on the secondary spindle.")); + } machineState.usePolarMode = true; bestABCIndex = undefined; } else { @@ -1912,7 +2240,10 @@ function updateMachiningMode(section) { } } else { // toolpath does not match XY ranges, enable interpolation mode - if (properties.useG112 || forcePolarMode) { + if (getProperty("useG112") || forcePolarMode) { + if (currentSection.spindle == SPINDLE_SECONDARY) { + error(localize("Polar mode is not supported on the secondary spindle.")); + } machineState.usePolarMode = true; } else { machineState.useXZCMode = true; @@ -1921,7 +2252,7 @@ function updateMachiningMode(section) { } } else if (getMachiningDirection(section) == MACHINING_DIRECTION_RADIAL) { // G19 plane if (!gotYAxis) { - if (!section.isMultiAxis() && !doesToolpathFitInXYRange(machineConfiguration.getABC(section.workPlane)) && doesCannedCycleIncludeYAxisMotion()) { + if (!section.isMultiAxis() && (!doesToolpathFitInXYRange(machineConfiguration.getABC(section.workPlane)) || doesCannedCycleIncludeYAxisMotion(section))) { error(subst(localize("Y-axis motion is not possible without a Y-axis for operation \"%1\"."), getOperationComment())); return; } @@ -1952,11 +2283,11 @@ function updateMachiningMode(section) { validate(checksum <= 1, localize("Internal post processor error.")); } -function doesCannedCycleIncludeYAxisMotion() { +function doesCannedCycleIncludeYAxisMotion(section) { // these cycles have Y axis motions which are not detected by getGlobalRange() var hasYMotion = false; - if (hasParameter("operation:strategy") && (getParameter("operation:strategy") == "drill")) { - switch (getParameter("operation:cycleType")) { + if (section.hasParameter("operation:strategy") && (section.getParameter("operation:strategy") == "drill")) { + switch (section.getParameter("operation:cycleType")) { case "thread-milling": case "bore-milling": case "circular-pocket-milling": @@ -1972,8 +2303,6 @@ function doesCannedCycleIncludeYAxisMotion() { default: hasYMotion = false; // all other cycles don´t have Y-axis motion } - } else { - hasYMotion = true; } return hasYMotion; } @@ -2034,6 +2363,10 @@ function getHighfeedrate(radius) { } function onRapid(_x, _y, _z) { + // don't output starts for threading + if (threadNumber > 0) { + return; + } if (machineState.useXZCMode) { var start = getCurrentPosition(); var dxy = getModulus(_x - start.x, _y - start.y); @@ -2048,7 +2381,12 @@ function onRapid(_x, _y, _z) { if (forceRewind) { rewindTable(start, _z, cOutput.getCurrent(), highFeedrate, false); } - writeBlock(gMotionModal.format(0), x, c, z); + if (currentSection.spindle == SPINDLE_SECONDARY) { + writeBlock(gMotionModal.format(0), c); + writeBlock(gMotionModal.format(0), x, z); + } else { + writeBlock(gMotionModal.format(0), x, c, z); + } previousABC.setZ(cOutput.getCurrent()); forceFeed(); return; @@ -2065,6 +2403,7 @@ function onRapid(_x, _y, _z) { var useG1 = ((x ? 1 : 0) + (y ? 1 : 0) + (z ? 1 : 0)) > 1 && !isCannedCycle; if (pendingRadiusCompensation >= 0) { pendingRadiusCompensation = -1; + if (useG1) { switch (radiusCompensation) { case RADIUS_COMPENSATION_LEFT: @@ -2153,7 +2492,7 @@ function rewindTable(startXYZ, currentZ, rewindC, feed, retract) { startSpindle(false); if (retract) { var x = getModulus(startXYZ.x, startXYZ.y); - if (properties.rapidRewinds) { + if (getProperty("rapidRewinds")) { writeBlock(gMotionModal.format(1), xOutput.format(x), getFeed(highFeedrate)); writeBlock(gMotionModal.format(0), cOutput.format(rewindC)); } else { @@ -2167,7 +2506,18 @@ function rewindTable(startXYZ, currentZ, rewindC, feed, retract) { } function onLinear(_x, _y, _z, feed) { + // don't output starts for threading + if (threadNumber > 0) { + return; + } if (machineState.useXZCMode) { + if (currentSection.spindle == SPINDLE_SECONDARY) { + if ((hasParameter("operation:strategy") && (getParameter("operation:strategy") == "drill") && !doesCannedCycleIncludeYAxisMotion(currentSection))) { + // allow drilling in XZC-mode + } else { + error(localize("XZC-mode is not supported on the secondary spindle.")); + } + } if (pendingRadiusCompensation >= 0) { error(subst(localize("Radius compensation is not supported for operation \"%1\". You have to use G112 mode for radius compensation."), getOperationComment())); return; @@ -2308,6 +2658,9 @@ function onRapid5D(_x, _y, _z, _a, _b, _c) { error(localize("Multi-axis motion is not supported for XZC mode.")); return; } + if (currentSection.spindle == SPINDLE_SECONDARY) { + error(localize("Multi-axis motion is not supported on the secondary spindle.")); + } if (pendingRadiusCompensation >= 0) { error(localize("Radius compensation mode cannot be changed at rapid traversal.")); return; @@ -2333,6 +2686,9 @@ function onLinear5D(_x, _y, _z, _a, _b, _c, feed) { error(localize("Multi-axis motion is not supported for XZC mode.")); return; } + if (currentSection.spindle == SPINDLE_SECONDARY) { + error(localize("Multi-axis motion is not supported on the secondary spindle.")); + } if (pendingRadiusCompensation >= 0) { error(localize("Radius compensation cannot be activated/deactivated for 5-axis move.")); return; @@ -2433,7 +2789,7 @@ function getFeedDPM(_moveLength, _feed) { dpmFeed = previousDPMFeed; } } else { // machine specific calculation - var feedRate = _feed / (_moveLength.radius.z / (toPreciseUnit(properties.setting102, IN) / 2.0)); + var feedRate = _feed / (_moveLength.radius.z / (toPreciseUnit(getProperty("setting102"), IN) / 2.0)); feedRate = Math.min(feedRate, highFeedrate / 2); dpmFeed = Math.min(feedRate, maxDPM); if (Math.abs(dpmFeed - previousDPMFeed) < dpmFeedToler) { @@ -2619,6 +2975,7 @@ function getMoveLength(_x, _y, _z, _a, _b, _c) { // End of multi-axis feedrate logic function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { + var directionCode = clockwise ? 2 : 3; var toler = (machineState.useXZCMode || machineState.usePolarMode) ? getTolerance() / 2 : getTolerance(); if (machineState.useXZCMode) { switch (getCircularPlane()) { @@ -2652,7 +3009,7 @@ function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { return; } - if (machineState.usePolarMode && !usePolarCircular) { + if (machineState.usePolarMode && !getProperty("usePolarCircular")) { linearize(toler); return; } @@ -2670,13 +3027,13 @@ function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { var start = getCurrentPosition(); if (isFullCircle()) { - if (properties.useRadius || isHelical()) { // radius mode does not support full arcs + if (getProperty("useRadius") || isHelical()) { // radius mode does not support full arcs linearize(toler); return; } switch (getCircularPlane()) { case PLANE_XY: - writeBlock(gPlaneModal.format(17), gMotionModal.format(clockwise ? 2 : 3), iOutput.format(cx - start.x, 0), jOutput.format(cy - start.y, 0), getFeed(feed)); + writeBlock(gPlaneModal.format(17), gMotionModal.format(directionCode), iOutput.format(cx - start.x, 0), jOutput.format(cy - start.y, 0), getFeed(feed)); break; case PLANE_ZX: if (machineState.usePolarMode) { @@ -2690,12 +3047,12 @@ function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { linearize(tolerance); return; } - writeBlock(gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), jOutput.format(cy - start.y, 0), kOutput.format(cz - start.z, 0), getFeed(feed)); + writeBlock(gPlaneModal.format(19), gMotionModal.format(directionCode), jOutput.format(cy - start.y, 0), kOutput.format(cz - start.z, 0), getFeed(feed)); break; default: linearize(toler); } - } else if (!properties.useRadius) { + } else if (!getProperty("useRadius")) { if (isHelical() && ((getCircularSweep() < toRad(30)) || (getHelicalPitch() > 10))) { // avoid G112 issue linearize(toler); return; @@ -2706,7 +3063,7 @@ function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { linearize(toler); // avoid G112 issues return; } - writeBlock(gPlaneModal.format(17), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x, 0), jOutput.format(cy - start.y, 0), getFeed(feed)); + writeBlock(gPlaneModal.format(17), gMotionModal.format(directionCode), xOutput.format(x), yOutput.format(y), zOutput.format(z), iOutput.format(cx - start.x, 0), jOutput.format(cy - start.y, 0), getFeed(feed)); break; case PLANE_ZX: if (machineState.usePolarMode) { @@ -2720,7 +3077,7 @@ function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { linearize(tolerance); return; } - writeBlock(gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), jOutput.format(cy - start.y, 0), kOutput.format(cz - start.z, 0), getFeed(feed)); + writeBlock(gPlaneModal.format(19), gMotionModal.format(directionCode), xOutput.format(x), yOutput.format(y), zOutput.format(z), jOutput.format(cy - start.y, 0), kOutput.format(cz - start.z, 0), getFeed(feed)); break; default: linearize(toler); @@ -2740,7 +3097,7 @@ function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { linearize(toler); // avoid G112 issues return; } - writeBlock(gPlaneModal.format(17), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed)); + writeBlock(gPlaneModal.format(17), gMotionModal.format(directionCode), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed)); break; case PLANE_ZX: if (machineState.usePolarMode) { @@ -2754,7 +3111,7 @@ function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { linearize(tolerance); return; } - writeBlock(gPlaneModal.format(19), gMotionModal.format(clockwise ? 2 : 3), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed)); + writeBlock(gPlaneModal.format(19), gMotionModal.format(directionCode), xOutput.format(x), yOutput.format(y), zOutput.format(z), "R" + rFormat.format(r), getFeed(feed)); break; default: linearize(toler); @@ -2764,7 +3121,7 @@ function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { function onCycle() { if ((typeof isSubSpindleCycle == "function") && isSubSpindleCycle(cycleType)) { - if (!properties.gotSecondarySpindle) { + if (!getProperty("gotSecondarySpindle")) { error(localize("Secondary spindle is not available.")); return; } @@ -2797,12 +3154,16 @@ function onCycle() { writeBlock(getCode("FEED_MODE_UNIT_MIN")); // mm/rev if (cycle.stopSpindle) { // no spindle rotation writeBlock(getCode("STOP_SPINDLE")); + writeBlock(mFormat.format(19)); + writeBlock(mFormat.format(119), "R" + abcFormat.format(cycle.spindleOrientation)); } else { // spindle rotation - writeBlock(sOutput.format(cycle.spindleSpeed), tool.clockwise ? getCode("START_MAIN_SPINDLE_CW") : getCode("START_MAIN_SPINDLE_CCW")); - writeBlock(pOutput.format(cycle.spindleSpeed), tool.clockwise ? getCode("START_SUB_SPINDLE_CCW") : getCode("START_SUB_SPINDLE_CW")); // inverted + var transferCodes = getSpindleTransferCodes(); + writeBlock(getCode("CONSTANT_SURFACE_SPEED_OFF")); + writeBlock(sOutput.format(transferCodes.spindleRPM), transferCodes.spindleDirection ? getCode("START_MAIN_SPINDLE_CW") : getCode("START_MAIN_SPINDLE_CCW")); + writeBlock(pOutput.format(transferCodes.spindleRPM), transferCodes.spindleDirection ? getCode("START_SUB_SPINDLE_CCW") : getCode("START_SUB_SPINDLE_CW")); // inverted + writeBlock(getCode("SPINDLE_SYNCHRONIZATION_ON"), "R" + abcFormat.format(cycle.spindleOrientation), formatComment("SPINDLE SYNCHRONIZATION ON")); // Sync spindles } - writeBlock(getCode("SPINDLE_SYNCHRONIZATION_ON"), "R" + abcFormat.format(cycle.spindleOrientation), formatComment("SPINDLE SYNCHRONIZATION ON")); // Sync spindles - if (properties.airCleanChuck) { + if (getProperty("airCleanChuck")) { writeBlock(getCode("MAINSPINDLE_AIR_BLAST_ON"), formatComment("MAINSPINDLE AIR BLAST ON")); writeBlock(getCode("SUBSPINDLE_AIR_BLAST_ON"), formatComment("SUBSPINDLE AIR BLAST ON")); } @@ -2813,7 +3174,7 @@ function onCycle() { onDwell(cycle.dwell); gMotionModal.reset(); writeBlock(conditional(cycle.useMachineFrame, gFormat.format(53)), gMotionModal.format(0), "B" + spatialFormat.format(cycle.feedPosition)); - if (properties.airCleanChuck) { + if (getProperty("airCleanChuck")) { writeBlock(getCode("MAINSPINDLE_AIR_BLAST_OFF"), formatComment("MAINSPINDLE AIR BLAST OFF")); writeBlock(getCode("SUBSPINDLE_AIR_BLAST_OFF"), formatComment("SUBSPINDLE AIR BLAST OFF")); } @@ -2824,7 +3185,7 @@ function onCycle() { getCode(currentSection.spindle == SPINDLE_PRIMARY ? "CLAMP_SECONDARY_CHUCK" : "CLAMP_PRIMARY_CHUCK"), formatComment(currentSection.spindle == SPINDLE_PRIMARY ? "CLAMP SECONDARY CHUCK" : "CLAMP PRIMARY CHUCK") ); - onDwell(cycle.dwell); + onDwell(cycle.dwell * 1.5); machineState.stockTransferIsActive = true; break; case "secondary-spindle-return": @@ -2862,10 +3223,12 @@ function onCycle() { if (cycle.stopSpindle) { // no spindle rotation writeBlock(getCode("STOP_SPINDLE")); } else { // spindle rotation - writeBlock(sOutput.format(cycle.spindleSpeed), tool.clockwise ? getCode("START_MAIN_SPINDLE_CW") : getCode("START_MAIN_SPINDLE_CCW")); - writeBlock(pOutput.format(cycle.spindleSpeed), tool.clockwise ? getCode("START_SUB_SPINDLE_CCW") : getCode("START_SUB_SPINDLE_CW")); // inverted + var transferCodes = getSpindleTransferCodes(); + writeBlock(getCode("CONSTANT_SURFACE_SPEED_OFF")); + writeBlock(sOutput.format(transferCodes.spindleRPM), transferCodes.spindleDirection ? getCode("START_MAIN_SPINDLE_CW") : getCode("START_MAIN_SPINDLE_CCW")); + writeBlock(pOutput.format(transferCodes.spindleRPM), transferCodes.spindleDirection ? getCode("START_SUB_SPINDLE_CCW") : getCode("START_SUB_SPINDLE_CW")); // inverted + writeBlock(getCode("SPINDLE_SYNCHRONIZATION_ON"), formatComment("SPINDLE SYNCHRONIZATION ON")); // Sync spindles } - writeBlock(getCode("SPINDLE_SYNCHRONIZATION_ON"), formatComment("SPINDLE SYNCHRONIZATION ON")); // Sync spindles } if (secondaryPull) { @@ -2877,7 +3240,7 @@ function onCycle() { setCoolant(COOLANT_OFF); if (cycle.unclampMode == "unclamp-secondary") { // leave part in main spindle writeBlock(getCode("CLAMP_PRIMARY_CHUCK"), formatComment("CLAMP PRIMARY CHUCK")); - onDwell(cycle.dwell); + onDwell(cycle.dwell * 1.5); writeBlock(getCode("UNCLAMP_SECONDARY_CHUCK"), formatComment("UNCLAMP SECONDARY CHUCK")); onDwell(cycle.dwell); } else if (cycle.unclampMode == "unclamp-primary") { @@ -2886,13 +3249,19 @@ function onCycle() { onDwell(cycle.dwell); } } - writeBlock(gMotionModal.format(0), gFormat.format(53), "B" + spatialFormat.format(properties.g53WorkPositionSub)); + writeBlock(gMotionModal.format(0), gFormat.format(53), "B" + spatialFormat.format(getProperty("g53WorkPositionSub"))); + if (machineState.spindleSynchronizationIsActive) { // spindles are synchronized + if (cycle.unclampMode == "unclamp-secondary") { + writeBlock(getCode("CLAMP_SECONDARY_CHUCK"), formatComment("CLAMP SECONDARY CHUCK")); + } else if (cycle.unclampMode == "unclamp-primary") { + writeBlock(getCode("CLAMP_PRIMARY_CHUCK"), formatComment("CLAMP PRIMARY CHUCK")); + } writeBlock(getCode("SPINDLE_SYNCHRONIZATION_OFF"), formatComment("SPINDLE SYNCHRONIZATION OFF")); // disable spindle sync } } else { writeBlock(getCode("CLAMP_PRIMARY_CHUCK"), formatComment("CLAMP PRIMARY CHUCK")); - onDwell(cycle.dwell); + onDwell(cycle.dwell * 1.5); } machineState.stockTransferIsActive = true; break; @@ -2901,16 +3270,15 @@ function onCycle() { } var saveShowSequenceNumbers = true; -var xyzFormat = createFormat({decimals:(unit == MM ? 4 : 5), forceDecimal:true}); var pathBlockNumber = {start: 0, end: 0}; var isCannedCycle = false; function onCyclePath() { - saveShowSequenceNumbers = properties.showSequenceNumbers; + saveShowSequenceNumbers = getProperty("showSequenceNumbers"); isCannedCycle = true; // buffer all paths and stop feeds being output feedOutput.disable(); - properties.showSequenceNumbers = false; + setProperty("showSequenceNumbers", false); redirectToBuffer(); gMotionModal.reset(); if ((hasParameter("operation:grooving") && getParameter("operation:grooving").toUpperCase() != "OFF")) { @@ -2920,7 +3288,7 @@ function onCyclePath() { } function onCyclePathEnd() { - properties.showSequenceNumbers = saveShowSequenceNumbers; // reset property to initial state + setProperty("showSequenceNumbers", saveShowSequenceNumbers); // reset property to initial state feedOutput.enable(); var cyclePath = String(getRedirectionBuffer()).split(EOL); // get cycle path from buffer closeRedirection(); @@ -2946,8 +3314,8 @@ function onCyclePathEnd() { "P" + (getStartEndSequenceNumber(cyclePath, true)), "Q" + (getStartEndSequenceNumber(cyclePath, false)), "U" + xFormat.format(cycle.xStockToLeave), - "W" + xyzFormat.format(cycle.zStockToLeave), - "D" + xyzFormat.format(cycle.depthOfCut), + "W" + spatialFormat.format(cycle.zStockToLeave), + "D" + spatialFormat.format(cycle.depthOfCut), getFeed(cycle.cutfeedrate) ); break; @@ -2957,24 +3325,24 @@ function onCyclePathEnd() { for (var i = 0; i < cyclePath.length; ++i) { if (i == 0 || i == (cyclePath.length - 1)) { // write sequence number on first and last line of the cycle path - properties.showSequenceNumbers = true; + setProperty("showSequenceNumbers", true); if ((i == 0 && pathBlockNumber.start != sequenceNumber) || (i == (cyclePath.length - 1) && pathBlockNumber.end != sequenceNumber)) { error(localize("Mismatch of start/end block number in turning canned cycle.")); return; } } writeBlock(cyclePath[i]); // output cycle path - properties.showSequenceNumbers = saveShowSequenceNumbers; // reset property to initial state + setProperty("showSequenceNumbers", saveShowSequenceNumbers); // reset property to initial state isCannedCycle = false; } } function getStartEndSequenceNumber(cyclePath, start) { if (start) { - pathBlockNumber.start = sequenceNumber + conditional(saveShowSequenceNumbers, properties.sequenceNumberIncrement); + pathBlockNumber.start = sequenceNumber + conditional(saveShowSequenceNumbers, getProperty("sequenceNumberIncrement")); return pathBlockNumber.start; } else { - pathBlockNumber.end = sequenceNumber + properties.sequenceNumberIncrement + conditional(saveShowSequenceNumbers, (cyclePath.length - 1) * properties.sequenceNumberIncrement); + pathBlockNumber.end = sequenceNumber + getProperty("sequenceNumberIncrement") + conditional(saveShowSequenceNumbers, (cyclePath.length - 1) * getProperty("sequenceNumberIncrement")); return pathBlockNumber.end; } } @@ -2983,9 +3351,17 @@ function getCommonCycle(x, y, z, r) { // forceXYZ(); // force xyz on first drill hole of any cycle if (machineState.useXZCMode) { cOutput.reset(); - return [xOutput.format(getModulus(x, y)), cOutput.format(getCWithinRange(x, y, cOutput.getCurrent())), - zOutput.format(z), - (r !== undefined) ? ("R" + spatialFormat.format((gPlaneModal.getCurrent() == 19) ? r * 2 : r)) : ""]; + if (currentSection.spindle == SPINDLE_SECONDARY) { + onCommand(COMMAND_UNLOCK_MULTI_AXIS); + writeBlock(cOutput.format(getCWithinRange(x, y, cOutput.getCurrent()))); + onCommand(COMMAND_LOCK_MULTI_AXIS); + return [xOutput.format(getModulus(x, y)), zOutput.format(z), + (r !== undefined) ? ("R" + spatialFormat.format((gPlaneModal.getCurrent() == 19) ? r * 2 : r)) : ""]; + } else { + return [xOutput.format(getModulus(x, y)), cOutput.format(getCWithinRange(x, y, cOutput.getCurrent())), + zOutput.format(z), + (r !== undefined) ? ("R" + spatialFormat.format((gPlaneModal.getCurrent() == 19) ? r * 2 : r)) : ""]; + } } else { return [xOutput.format(x), yOutput.format(y), zOutput.format(z), @@ -3009,30 +3385,11 @@ function writeCycleClearance() { } } -var threadStart; -var threadEnd; -function moveToThreadStart(x, y, z) { - var cuttingAngle = 0; - if (hasParameter("operation:infeedAngle")) { - cuttingAngle = getParameter("operation:infeedAngle"); - } - if (cuttingAngle != 0) { - var zz; - if (isFirstCyclePoint()) { - threadStart = getCurrentPosition(); - threadEnd = new Vector(x, y, z); - } else { - var zz = threadStart.z - (Math.abs(threadEnd.x - x) * Math.tan(toRad(cuttingAngle))); - writeBlock(gMotionModal.format(0), zOutput.format(zz)); - threadStart.setZ(zz); - threadEnd = new Vector(x, y, z); - } - } -} - +var threadNumber = 0; +var numberOfThreads = 1; function onCyclePoint(x, y, z) { - if (!properties.useCycles || currentSection.isMultiAxis() || getMachiningDirection(currentSection) == MACHINING_DIRECTION_INDEXING) { + if (!getProperty("useCycles") || currentSection.isMultiAxis() || getMachiningDirection(currentSection) == MACHINING_DIRECTION_INDEXING) { expandCyclePoint(x, y, z); return; } @@ -3062,49 +3419,98 @@ function onCyclePoint(x, y, z) { switch (cycleType) { case "thread-turning": - if (properties.useSimpleThread || - (hasParameter("operation:doMultipleThreads") && (getParameter("operation:doMultipleThreads") != 0)) || - (hasParameter("operation:infeedMode") && (getParameter("operation:infeedMode") != "constant"))) { + // find number of threads and count which thread we are on + numberOfThreads = 1; + if ((hasParameter("operation:doMultipleThreads") && (getParameter("operation:doMultipleThreads") != 0))) { + numberOfThreads = getParameter("operation:numberOfThreads"); + } + if (isFirstCyclePoint()) { + // increment thread number for multiple threads + threadNumber += 1; + } + + var threadPhaseAngle = (360 / numberOfThreads) * (threadNumber - 1); + + if (getProperty("useSimpleThread")) { var i = -cycle.incrementalX; // positive if taper goes down - delta radius - moveToThreadStart(x, y, z); - xOutput.reset(); - zOutput.reset(); + + // move to thread start for infeed angle other than 0, multiple threads and alternate infeed. + if (zFormat.areDifferent(zOutput.getCurrent(), zFormat.getResultingValue(z))) { + var zOut = zOutput.format(z - cycle.incrementalZ); + if (zOut) { + writeBlock(gMotionModal.format(0), zOut); + } + g92IOutput.reset(); + g92QOutput.reset(); + gCycleModal.reset(); + forceFeed(); + xOutput.reset(); + zOutput.reset(); + } + writeBlock( - gMotionModal.format(92), + gCycleModal.format(92), xOutput.format(x - cycle.incrementalX), yOutput.format(y), zOutput.format(z), - conditional(zFormat.isSignificant(i), g76IOutput.format(i)), - pitchOutput.format(cycle.pitch) + conditional(zFormat.isSignificant(i), g92IOutput.format(i)), + conditional(numberOfThreads > 1, g92QOutput.format(threadPhaseAngle)), + feedOutput.format(cycle.pitch) ); } else { if (isLastCyclePoint()) { // thread height and depth of cut var threadHeight = getParameter("operation:threadDepth"); - var firstDepthOfCut = threadHeight / getParameter("operation:numberOfStepdowns"); - var repeatPass = hasParameter("operation:nullPass") ? getParameter("operation:nullPass") : 0; + var firstDepthOfCut = threadHeight - Math.abs(getCyclePoint(0).x - x); var cuttingAngle = 59; // Angle is not stored with tool. toDeg(tool.getTaperAngle()); if (hasParameter("operation:infeedAngle")) { cuttingAngle = getParameter("operation:infeedAngle") * 2; } var i = -cycle.incrementalX; // positive if taper goes down - delta radius gCycleModal.reset(); - + + var threadInfeedMode = "constant"; + if (hasParameter("operation:infeedMode")) { + threadInfeedMode = getParameter("operation:infeedMode"); + } + + // Cutting Method: + // P1 = Constant Amount/1 Edge + // P2 = Constant Amount/Both Edges + // P3 = Constant Depth/One Edge + // P4 = Constant Depth/Both Edges >>>>>> not supported + + var threadCuttingMode = 3; + if (threadInfeedMode == "reduced") { + threadCuttingMode = 1; + } else if (threadInfeedMode == "constant") { + threadCuttingMode = 3; + } else if (threadInfeedMode == "alternate") { + threadCuttingMode = 2; + } else { + error(localize("Unsupported Infeed Mode.")); + return; + } + // threading cycle + gCycleModal.reset(); + xOutput.reset(); + zOutput.reset(); writeBlock( gCycleModal.format(76), xOutput.format(x - cycle.incrementalX), zOutput.format(z), + conditional(zFormat.isSignificant(i), g76IOutput.format(i)), g76KOutput.format(threadHeight), g76DOutput.format(firstDepthOfCut), g76AOutput.format(cuttingAngle), - // "P2" // P1 = Single edge-cutting constant, P2 = Double edge-cutting constant, P3 = Single-depth constant, P4 = Double-depth constant + "P" + integerFormat.format(threadCuttingMode), + conditional(numberOfThreads > 1, g76QOutput.format(threadPhaseAngle)), pitchOutput.format(cycle.pitch) ); } } gMotionModal.reset(); - forceFeed(); return; } if (true) { @@ -3344,13 +3750,19 @@ function onCyclePoint(x, y, z) { } function onCycleEnd() { - if (!cycleExpanded && !machineState.stockTransferIsActive && (typeof isSubSpindleCycle == "function") && isSubSpindleCycle(cycleType)) { + if (!cycleExpanded && !machineState.stockTransferIsActive && !((typeof isSubSpindleCycle == "function") && isSubSpindleCycle(cycleType)) && + cycleType != "turning-canned-rough") { switch (cycleType) { case "thread-turning": forceFeed(); + g92IOutput.reset(); + g92QOutput.reset(); + gCycleModal.reset(); xOutput.reset(); zOutput.reset(); - g76IOutput.reset(); + if (threadNumber == numberOfThreads) { + threadNumber = 0; + } break; default: writeBlock(gCycleModal.format(80)); @@ -3443,7 +3855,7 @@ function onCommand(command) { } break; case COMMAND_STOP_SPINDLE: - if (properties.useSSV) { + if (getProperty("useSSV")) { writeBlock(ssvModal.format(39)); } writeBlock(getCode("STOP_SPINDLE")); @@ -3500,13 +3912,13 @@ function onCommand(command) { if (currentSection.spindle == SPINDLE_PRIMARY) { writeBlock(mFormat.format(19)); // use P or R to set angle (optional) } else { - writeBlock(mFormat.format(119)); + writeBlock(mFormat.format(g14IsActive ? 19 : 119)); } } else { if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, 1))) { writeBlock(mFormat.format(19)); // use P or R to set angle (optional) } else if (isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, -1))) { - writeBlock(mFormat.format(119)); + writeBlock(mFormat.format(g14IsActive ? 19 : 119)); } else { error(localize("Spindle orientation is not supported for live tooling.")); return; @@ -3547,6 +3959,33 @@ function preloadCutoffTool() { return; } +/** Get synchronization/transfer code based on part cutoff spindle direction. */ +function getSpindleTransferCodes() { + var transferCodes = {direction:0, spindleMode:SPINDLE_CONSTANT_SPINDLE_SPEED, surfaceSpeed:0, maximumSpindleSpeed:0}; + transferCodes.spindleDirection = isFirstSection() ? true : getPreviousSection().getTool().clockwise; // clockwise + transferCodes.spindleRPM = cycle.spindleSpeed; + if (isLastSection()) { + return transferCodes; + } + var numberOfSections = getNumberOfSections(); + for (var i = getNextSection().getId(); i < numberOfSections; ++i) { + var section = getSection(i); + if (section.getParameter("operation-strategy") == "turningSecondarySpindleReturn") { + continue; + } else if (section.getType() != TYPE_TURNING || section.spindle != SPINDLE_PRIMARY) { + break; + } else if (section.getType() == TYPE_TURNING) { + var tool = section.getTool(); + transferCodes.spindleMode = tool.getSpindleMode(); + transferCodes.surfaceSpeed = tool.surfaceSpeed; + transferCodes.maximumSpindleSpeed = tool.maximumSpindleSpeed; + transferCodes.spindleDirection = tool.clockwise; + break; + } + } + return transferCodes; +} + function engagePartCatcher(engage) { if (engage) { // catch part here @@ -3554,11 +3993,11 @@ function engagePartCatcher(engage) { } else { onCommand(COMMAND_COOLANT_OFF); if (gotYAxis) { - writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + yFormat.format(properties.g53HomePositionY)); // retract + writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + yFormat.format(getProperty("g53HomePositionY"))); // retract yOutput.reset(); } - writeBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(properties.g53HomePositionX)); // retract - writeBlock(gFormat.format(53), gMotionModal.format(0), "Z" + zFormat.format(currentSection.spindle == SPINDLE_SECONDARY ? properties.g53HomePositionSubZ : properties.g53HomePositionZ)); // retract + writeBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(getProperty("g53HomePositionX"))); // retract + writeBlock(gFormat.format(53), gMotionModal.format(0), "Z" + zFormat.format(currentSection.spindle == SPINDLE_SECONDARY ? getProperty("g53HomePositionSubZ") : getProperty("g53HomePositionZ"))); // retract writeBlock(getCode("PART_CATCHER_OFF"), formatComment(localize("PART CATCHER OFF"))); forceXYZ(); } @@ -3573,14 +4012,14 @@ function ejectPart() { //goHome(); // Position all axes to home position if (gotYAxis) { - writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + yFormat.format(properties.g53HomePositionY)); // retract + writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + yFormat.format(getProperty("g53HomePositionY"))); // retract yOutput.reset(); } - writeBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(properties.g53HomePositionX)); // retract - writeBlock(gFormat.format(53), gMotionModal.format(0), "Z" + zFormat.format(currentSection.spindle == SPINDLE_SECONDARY ? properties.g53HomePositionSubZ : properties.g53HomePositionZ)); // retract + writeBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(getProperty("g53HomePositionX"))); // retract + writeBlock(gFormat.format(53), gMotionModal.format(0), "Z" + zFormat.format(currentSection.spindle == SPINDLE_SECONDARY ? getProperty("g53HomePositionSubZ") : getProperty("g53HomePositionZ"))); // retract onCommand(COMMAND_UNLOCK_MULTI_AXIS); - if (!properties.optimizeCaxisSelect) { + if (!getProperty("optimizeCAxisSelect")) { cAxisEngageModal.reset(); } writeBlock( @@ -3605,7 +4044,7 @@ function ejectPart() { onDwell(1.1); // clean out chips - if (properties.airCleanChuck) { + if (getProperty("airCleanChuck")) { writeBlock(getCode(currentSection.spindle == SPINDLE_SECONDARY ? "SUBSPINDLE_AIR_BLAST_ON" : "MAINSPINDLE_AIR_BLAST_ON"), formatComment("AIR BLAST ON")); onDwell(2.5); @@ -3633,7 +4072,7 @@ function onSectionEnd() { startSpindle(true, getFramePosition(currentSection.getFinalPosition())); } - if (properties.useG61) { + if (getProperty("useG61")) { writeBlock(gExactStopModal.format(64)); } @@ -3652,7 +4091,7 @@ function onSectionEnd() { } } - if (machineState.cAxisIsEngaged && !properties.optimizeCAxisSelect) { + if (machineState.cAxisIsEngaged && !getProperty("optimizeCAxisSelect")) { writeBlock(getCode("DISENGAGE_C_AXIS")); // used for c-axis encoder reset forceWorkPlane(); // needed since re-engage would result in undefined c-axis position } @@ -3669,27 +4108,27 @@ function onClose() { onCommand(COMMAND_COOLANT_OFF); - if (properties.gotChipConveyor) { + if (getProperty("gotChipConveyor")) { onCommand(COMMAND_STOP_CHIP_TRANSPORT); } if (getNumberOfSections() > 0) { // Retracting Z first causes safezone overtravel error to keep from crashing into subspindle. Z should already be retracted to and end of section. var section = getSection(getNumberOfSections() - 1); if ((section.getType() != TYPE_TURNING) && isSameDirection(section.workPlane.forward, new Vector(0, 0, 1))) { - writeBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(properties.g53HomePositionX), conditional(gotYAxis, "Y" + yFormat.format(properties.g53HomePositionY))); // retract + writeBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(getProperty("g53HomePositionX")), conditional(gotYAxis, "Y" + yFormat.format(getProperty("g53HomePositionY")))); // retract xOutput.reset(); yOutput.reset(); - writeBlock(gFormat.format(53), gMotionModal.format(0), "Z" + zFormat.format((currentSection.spindle == SPINDLE_SECONDARY) ? properties.g53HomePositionSubZ : properties.g53HomePositionZ)); // retract + writeBlock(gFormat.format(53), gMotionModal.format(0), "Z" + zFormat.format((currentSection.spindle == SPINDLE_SECONDARY) ? getProperty("g53HomePositionSubZ") : getProperty("g53HomePositionZ"))); // retract zOutput.reset(); writeBlock(getCode("STOP_SPINDLE")); } else { if (gotYAxis) { - writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + yFormat.format(properties.g53HomePositionY)); // retract + writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + yFormat.format(getProperty("g53HomePositionY"))); // retract } - writeBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(properties.g53HomePositionX)); // retract + writeBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(getProperty("g53HomePositionX"))); // retract xOutput.reset(); yOutput.reset(); - writeBlock(gFormat.format(53), gMotionModal.format(0), "Z" + zFormat.format(currentSection.spindle == SPINDLE_SECONDARY ? properties.g53HomePositionSubZ : properties.g53HomePositionZ)); // retract + writeBlock(gFormat.format(53), gMotionModal.format(0), "Z" + zFormat.format(currentSection.spindle == SPINDLE_SECONDARY ? getProperty("g53HomePositionSubZ") : getProperty("g53HomePositionZ"))); // retract zOutput.reset(); writeBlock(getCode("STOP_SPINDLE")); } @@ -3699,7 +4138,7 @@ function onClose() { } gMotionModal.reset(); - if (!properties.optimizeCAxisSelect) { + if (!getProperty("optimizeCAxisSelect")) { cAxisEngageModal.reset(); } writeBlock(getCode("DISENGAGE_C_AXIS")); @@ -3709,30 +4148,36 @@ function onClose() { } if (gotYAxis) { - writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + yFormat.format(properties.g53HomePositionY)); + writeBlock(gFormat.format(53), gMotionModal.format(0), "Y" + yFormat.format(getProperty("g53HomePositionY"))); yOutput.reset(); } - if (properties.useBarFeeder) { + if (getProperty("useBarFeeder")) { writeln(""); writeComment(localize("Bar feed")); // feed bar here - // writeBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(properties.g53HomePositionX)); + // writeBlock(gFormat.format(53), gMotionModal.format(0), "X" + xFormat.format(getProperty("g53HomePositionX"))); writeBlock(gFormat.format(105)); } writeln(""); onImpliedCommand(COMMAND_END); onImpliedCommand(COMMAND_STOP_SPINDLE); - if (properties.looping) { + if (getProperty("looping")) { writeBlock(mFormat.format(99)); - } else if (true /*!properties.useM97*/) { - writeBlock(mFormat.format(properties.useBarFeeder ? 99 : 30)); // stop program, spindle stop, coolant off + } else if (true /*!getProperty("useM97")*/) { + onCommand(COMMAND_OPEN_DOOR); + writeBlock(mFormat.format(getProperty("useBarFeeder") ? 99 : 30)); // stop program, spindle stop, coolant off } else { writeBlock(mFormat.format(99)); } writeln("%"); } + +function setProperty(property, value) { + properties[property].current = value; +} // <<<<< INCLUDED FROM ../common/haas lathe.cps -properties.maximumSpindleSpeed = 4000; +properties.maximumSpindleSpeed.value = 4000; +properties.subMaximumSpindleSpeed.value = 4000; diff --git a/Haas_Turning/haas turning.cps b/Haas_Lathes_BIDC/haas turning.cps similarity index 100% rename from Haas_Turning/haas turning.cps rename to Haas_Lathes_BIDC/haas turning.cps diff --git a/Haas_Next_Generation/Bechtel DT.cps b/Haas_Mills_BIDC/Bechtel DT.cps similarity index 100% rename from Haas_Next_Generation/Bechtel DT.cps rename to Haas_Mills_BIDC/Bechtel DT.cps diff --git a/Haas_Next_Generation/Bechtel VF2.cps b/Haas_Mills_BIDC/Bechtel VF2.cps similarity index 100% rename from Haas_Next_Generation/Bechtel VF2.cps rename to Haas_Mills_BIDC/Bechtel VF2.cps diff --git a/Haas_Mills_BIDC/Bechtel VF2HP.cps b/Haas_Mills_BIDC/Bechtel VF2HP.cps new file mode 100644 index 0000000..9177a03 --- /dev/null +++ b/Haas_Mills_BIDC/Bechtel VF2HP.cps @@ -0,0 +1,3812 @@ +/** + Copyright (C) 2012-2021 by Autodesk, Inc. + All rights reserved. + + HAAS post processor configuration. + + $Revision: 43348 37c695f19b2eab4d5737a29df773b981b83fa8d4 $ + $Date: 2021-07-12 15:10:04 $ + + FORKID {DBD402DA-DE90-4634-A6A3-0AE5CC97DEC7} + + Modified by BIDC of Purdue University + Authors: Gavin Williams (will1742@purdue.edu) +*/ + +//////////////////////////////////////////////////////////////////////////////////////////////// +// MANUAL NC COMMANDS +// +// The following ACTION commands are supported by this post. +// +// CYCLE_REVERSAL - Reverses the spindle in a drilling cycle +// USEPOLARMODE - Enables polar interpolation for the following operation. +// VFD_HIGH - Uses high pressure flood coolant if machine has VFD +// VFD_LOW - Uses low pressure flood coolant if machine has VFD +// VFD_NORMAL - Uses normal pressure flood coolant if machine has VFD +// +//////////////////////////////////////////////////////////////////////////////////////////////// + +description = "HAAS - Next Generation Control"; +vendor = "Haas Automation"; +vendorUrl = "https://www.haascnc.com"; +legal = "Copyright (C) 2012-2021 by Autodesk, Inc."; +certificationLevel = 2; +minimumRevision = 45702; + +longDescription = "Generic post for the HAAS Next Generation control. The post includes support for multi-axis indexing and simultaneous machining. The post utilizes the dynamic work offset feature so you can place your work piece as desired without having to repost your NC programs." + EOL + +"You can specify following pre-configured machines by using the property 'Machine model':" + EOL + +"UMC-500" + EOL + "UMC-750" + EOL + "UMC-1000" + EOL + "UMC-1600-H"; + +extension = "nc"; +programNameIsInteger = true; +setCodePage("ascii"); +keywords = "MODEL_IMAGE PREVIEW_IMAGE"; + +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(355); +allowHelicalMoves = true; +allowedCircularPlanes = undefined; // allow any circular motion +allowSpiralMoves = true; +highFeedrate = (unit == IN) ? 650 : 5000; + +// user-defined properties +properties = {/* + machineModel: { + title: "Machine model", + description: "Specifies the pre-configured machine model.", + type: "enum", + group: 0, + values: [ + {title: "None", id: "none"}, + {title: "UMC-500", id: "umc-500"}, + {title: "UMC-750", id: "umc-750"}, + {title: "UMC-1000", id: "umc-1000"}, + {title: "UMC-1600-H", id: "umc-1600"} + ], + value: "none", + scope: "post" + },*/ + hasAAxis: { + title: "Has A-axis rotary", + description: "Enable if the machine has an A-axis table/trunnion. Check the table direction on the machine and use the (Reversed) selection if the table is moving in the opposite direction.", + type: "enum", + group: 1, + values: [ + {title: "No", id: "false"}, + {title: "Yes", id: "true"}, + {title: "Reversed", id: "reversed"} + ], + value: "false", + scope: "post" + }, + hasBAxis: { + title: "Has B-axis rotary", + description: "Enable if the machine has a B-axis table/trunnion. Check the table direction on the machine and use the (Reversed) selection if the table is moving in the opposite direction.", + type: "enum", + group: 1, + values: [ + {title: "No", id: "false"}, + {title: "Yes", id: "true"}, + {title: "Reversed", id: "reversed"} + ], + value: "false", + scope: "post" + }, + hasCAxis: { + title: "Has C-axis rotary", + description: "Enable if the machine has a C-axis table. Specifies a trunnion setup if an A-axis or B-axis is defined. Check the table direction on the machine and use the (Reversed) selection if the table is moving in the opposite direction.", + type: "enum", + group: 1, + values: [ + {title: "No", id: "false"}, + {title: "Yes", id: "true"}, + {title: "Reversed", id: "reversed"} + ], + value: "false", + scope: "post" + },/* + useDPMFeeds: { + title: "Rotary moves use DPM feeds", + description: "Enable to output DPM feeds, disable for Inverse Time feeds with rotary axes moves.", + group: 1, + type: "boolean", + value: false, + scope: "post" + },*/ + useTCPC: { + title: "Use TCPC programming", + description: "The control supports Tool Center Point Control programming.", + group: 1, + type: "boolean", + value: true, + scope: "post" + },/* + useDWO: { + title: "Use DWO", + description: "Specifies that the Dynamic Work Offset feature (G254/G255) should be used.", + group: 1, + type: "boolean", + value: true, + scope: "post" + }, + preloadTool: { + title: "Preload tool", + description: "Preloads the next tool at a tool change (if any).", + group: 2, + type: "boolean", + value: true, + scope: "post" + }, + chipTransport: { + title: "Use chip transport", + description: "Enable to turn on chip transport at start of program.", + group: 2, + type: "boolean", + value: true, + scope: "post" + }, + optionalStop: { + title: "Optional stop", + description: "Specifies that optional stops M1 should be output at tool changes.", + group: 2, + type: "boolean", + value: true, + scope: "post" + }, + separateWordsWithSpace: { + title: "Separate words with space", + description: "Adds spaces between words if 'yes' is selected.", + group: 2, + type: "boolean", + value: true, + scope: "post" + }, + useRadius: { + title: "Radius arcs", + description: "If yes is selected, arcs are output using radius values rather than IJK.", + group: 2, + type: "boolean", + value: false, + scope: "post" + }, + useParametricFeed: { + title: "Parametric feed", + description: "Parametric feed values based on movement type are output.", + group: 2, + type: "boolean", + value: true, + scope: "post" + }, + useG0: { + title: "Use G0", + description: "Specifies that G0s should be used for rapid moves when moving along a single axis.", + group: 2, + type: "boolean", + value: true, + scope: "post" + }, + safePositionMethod: { + title: "Safe Retracts", + description: "Select your desired retract option. 'Clearance Height' retracts to the operation clearance height.", + type: "enum", + values: [ + {title: "G28", id: "G28"}, + {title: "G53", id: "G53"}, + {title: "Clearance Height", id: "clearanceHeight"} + ], + value: "G53", + scope: "post" + }, + useG187: { + title: "Use G187", + description: "Specifies that smoothing using G187 should be used.", + group: 2, + type: "boolean", + value: false, + scope: "post" + }, + homePositionCenter: { + title: "Home position center", + description: "Enable to center the part along X at the end of program for easy access. Requires a CNC with a moving table.", + group: 2, + type: "boolean", + value: false, + scope: "post" + }, + optionallyCycleToolsAtStart: { + title: "Optionally cycle tools at start", + description: "Cycle through each tool used at the beginning of the program when block delete is turned off.", + group: 2, + type: "boolean", + value: false, + scope: "post" + }, + measureToolsAtStart: { + title: "Optionally measure tools at start", + description: "Measure each tool used at the beginning of the program when block delete is turned off.", + group: 2, + type: "boolean", + value: false, + scope: "post" + }, + forceHomeOnIndexing: { + title: "Force XY home position on indexing", + description: "Move XY to their home positions on multi-axis indexing.", + group: 2, + type: "boolean", + value: true, + scope: "post" + }, + toolBreakageTolerance: { + title: "Tool breakage tolerance", + description: "Specifies the tolerance for which tool break detection will raise an alarm.", + group: 2, + type: "spatial", + value: 0.1, + scope: "post" + }, + safeStartAllOperations: { + title: "Safe start all operations", + description: "Write optional blocks at the beginning of all operations that include all commands to start program.", + group: 2, + type: "boolean", + value: true, + scope: "post" + }, + fastToolChange: { + title: "Fast tool change", + description: "Skip spindle off, coolant off, and Z retract to make tool change quicker.", + group: 2, + type: "boolean", + value: false, + scope: "post" + }, + useG95forTapping: { + title: "Use G95 for tapping", + description: "use IPR/MPR instead of IPM/MPM for tapping", + group: 2, + type: "boolean", + value: false, + scope: "post" + }, + safeRetractDistance: { + title: "Safe retract distance", + description: "Specifies the distance to add to retract distance when rewinding rotary axes.", + group: 2, + type: "spatial", + value: 0, + scope: "post" + },*/ + useSubroutines: { + title: "Use subroutines", + description: "Select your desired subroutine option. 'All Operations' creates subroutines per each operation, 'Cycles' creates subroutines for cycle operations on same holes, and 'Patterns' creates subroutines for patterned operations.", + type: "enum", + values: [ + {title: "No", id: "none"}, + {title: "All Operations", id: "allOperations"}, + {title: "Cycles", id: "cycles"}, + {title: "Patterns", id: "patterns"} + ], + group: 3, + value: "none", + scope: "post" + },/* + writeMachine: { + title: "Write machine", + description: "Output the machine settings in the header of the code.", + group: 4, + type: "boolean", + value: false, + scope: "post" + }, + writeTools: { + title: "Write tool list", + description: "Output a tool list in the header of the code.", + group: 4, + type: "boolean", + value: true, + scope: "post" + }, + writeVersion: { + title: "Write version", + description: "Write the version number in the header of the code.", + group: 4, + type: "boolean", + value: false, + scope: "post" + }, + showSequenceNumbers: { + title: "Use sequence numbers", + description: "Use sequence numbers for each block of outputted code.", + group: 4, + type: "boolean", + value: true, + scope: "post" + }, + sequenceNumberStart: { + title: "Start sequence number", + description: "The number at which to start the sequence numbers.", + group: 4, + 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: 4, + type: "integer", + value: 5, + scope: "post" + }, + sequenceNumberOnlyOnToolChange: { + title: "Block number only on tool change", + description: "Specifies that block numbers should only be output at tool changes.", + group: 4, + type: "boolean", + value: false, + scope: "post" + }, + showNotes: { + title: "Show notes", + description: "Enable to output notes for operations.", + group: 4, + type: "boolean", + value: true, + scope: "post" + }, + useM130PartImages: { + title: "Include M130 part images", + description: "Enable to include M130 part images with the NC file.", + group: 4, + type: "boolean", + value: false, + scope: "post" + }, + useM130ToolImages: { + title: "Include M130 tool images", + description: "Enable to include M130 tool images with the NC file.", + group: 4, + type: "boolean", + value: false, + scope: "post" + }, + coolantPressure: { + title: "Coolant pressure", + description: "Select the coolant pressure if equipped with a Variable Frequency Drive. Select 'Default' if this option is not installed.", + type: "enum", + group: 2, + values: [ + {title: "Default", id: ""}, + {title: "Low", id: "P0"}, + {title: "Normal", id: "P1"}, + {title: "High", id: "P2"} + ], + value: "", + scope: "post" + }, + singleResultsFile: { + title: "Create single results file", + description: "Set to false if you want to store the measurement results for each probe / inspection toolpath in a separate file", + group: 0, + type: "boolean", + value: true, + scope: "post" + }*/ + toolsToLoad: { + title: "Tools to load and probe", + description: "List or provide a range of tools to probe e.g. 1, 2, 3 or 1-5. Leaving this empty will probe all tools", + group: 4, + type: "string", + value: "", + scope: "post" + }, + toolHeightValidation: { + title: "Tool Length Validation", + description: "Length validation. By turning this off, you accept responsibility for any resulting crashes.", + group: 99, + type: "boolean", + value: true, + scope: "post" + }, + pencilWCSValidation: { + title: "WCS Validation", + description: "WCS validation. By turning this off, you accept responsibility for any resulting crashes.", + group: 99, + type: "boolean", + value: true, + scope: "post" + }, + measureToolsAtStart: { + title: "Tool Probing", + description: "Tool Probing. By turning this off, you accept responsibility for any resulting crashes.", + group: 99, + type: "boolean", + value: true, + scope: "post" + } +}; + +staticProperties = { + machineModel: "none", + safePositionMethod: "G53", + useDPMFeeds: false, + useTCPC: true, + useDWO: true, + safeStartAllOperations: true, + preloadTool: true, + chipTransport: false, + optionalStop: true, + separateWordsWithSpace: true, + useRadius: false, + useParametricFeed: true, + useG0: true, + useG187: false, + homePositionCenter: false, + optionallyCycleToolsAtStart: false, + measureToolsAtStart: true, + forceHomeOnIndexing: true, + toolBreakageTolerance: 0.1, + fastToolChange: false, + useG95forTapping: true, + safeRetractDistance: 0, + //useSubroutines: "allOperations", + writeMachine: false, + writeTools: true, + writeVersion: false, + showSequenceNumbers: true, + sequenceNumberStart: 10, + sequenceNumberIncrement: 5, + sequenceNumberOnlyOnToolChange: false, + showNotes: true, + useM130PartImages: false, + useM130ToolImages: false, + coolantPressure: "", + singleResultsFile: true, + useP9995: true, + postVersion: "VF2G7A21" + }; + + const HAAS_DRILL = 1; + const HAAS_TAP = 2; + const HAAS_SHELL = 3; + const HAAS_END_MILL = 4; + const HAAS_CENTER = 5; + const HAAS_BALL_NOSE = 6; + const HAAS_PROBE = 7; + + const NO_PROBING = 0; + const LEN_ROT = 1; + const LEN_NON_ROT = 2; + const LEN_DIA_ROT = 3; + + const DEFAULT_HAAS_K_FACTOR = 0.05; + const NULL_HAAS_K_FACTOR = 0; + + const CLEARANCE_HEIGHT = 1; + const LENGTH_TOLERANCE = .25; + const DIAM_TOLERANCE = .01; + + // VF4 specific + const MAX_TOOL_LENGTH = 11; + const MAX_TOOL_DIAM = 5; + const X_TRAVEL_LIMIT = 30; + const Y_TRAVEL_LIMIT = 15; + +var singleLineCoolant = false; // specifies to output multiple coolant codes in one line rather than in separate lines +// samples: +// {id: COOLANT_THROUGH_TOOL, on: 88, off: 89} +// {id: COOLANT_THROUGH_TOOL, on: [8, 88], off: [9, 89]} +var coolants = [ + {id: COOLANT_FLOOD, on: 8}, + {id: COOLANT_MIST}, + {id: COOLANT_THROUGH_TOOL, on: 88, off: 89}, + {id: COOLANT_AIR, on: 83, off: 84}, + {id: COOLANT_AIR_THROUGH_TOOL, on: 73, off: 74}, + {id: COOLANT_SUCTION}, + {id: COOLANT_FLOOD_MIST}, + {id: COOLANT_FLOOD_THROUGH_TOOL, on: [88, 8], off: [89, 9]}, + {id: COOLANT_OFF, off: 9} +]; + +var notes = { + o1: ["-", 7000], + C3: ["C", 7849], + Cs3: ["C#", 8315], + D3: ["D", 8810], + Ds3: ["D#", 9334], + E3: ["E", 9889], + F3: ["F", 10477], + Fs3: ["F#", 11100], + G3: ["G", 11760], + Gs3: ["G#", 12459], + A3: ["A", 13200], + As3: ["A#", 13985], + B3: ["B", 14816], + C4: ["C", 15698], + Cs4: ["C#", 16631], + D4: ["D", 17620], + Ds4: ["D#", 18668], + E4: ["E", 19778] +} + +// old machines only support 4 digits +var oFormat = createFormat({width:5, zeropad:true, decimals:0}); +var nFormat = createFormat({decimals:0}); + +var gFormat = createFormat({prefix:"G", decimals:0}); +var mFormat = createFormat({prefix:"M", decimals:0}); +var hFormat = createFormat({prefix:"H", decimals:0}); +var dFormat = createFormat({prefix:"D", decimals:0}); +var probeWCSFormat = createFormat({decimals:2, forceDecimal:true}); +var macroFormat = createFormat({prefix:"#", 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 pitchFormat = createFormat({decimals:(unit == MM ? 3 : 4), forceDecimal:true}); +var toolFormat = createFormat({decimals:0}); +var rpmFormat = createFormat({decimals:0}); +var secFormat = createFormat({decimals:3, forceDecimal:true}); // seconds - range 0.001-1000 +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({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 pitchOutput = createVariable({prefix:"F", 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({}, 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({}, gFormat); // modal group 9 // G81, ... +var gRetractModal = createModal({force:true}, gFormat); // modal group 10 // G98-99 +var gRotationModal = createModal({ + onchange: function () { + if (probeVariables.probeAngleMethod == "G68") { + probeVariables.outputRotationCodes = true; + } + } +}, gFormat); // modal group 16 // G68-G69 + +// fixed settings +var firstFeedParameter = 100; // the first variable to use with parametric feed +var forceResetWorkPlane = false; // enable to force reset of machine ABC on new orientation +var minimumCyclePoints = 5; // minimum number of points in cycle operation to consider for subprogram +var useDwoForPositioning = true; // specifies to use the DWO feature for XY positioning for multi-axis operations + +var WARNING_WORK_OFFSET = 0; + +var allowIndexingWCSProbing = false; // specifies that probe WCS with tool orientation is supported +var probeVariables = { + outputRotationCodes: false, // defines if it is required to output rotation codes + probeAngleMethod: "OFF", // OFF, AXIS_ROT, G68, G54.4 + compensationXY: undefined, + rotationalAxis: -1 +}; + +var SUB_UNKNOWN = 0; +var SUB_PATTERN = 1; +var SUB_CYCLE = 2; + +// collected state +var sequenceNumber; +var currentWorkOffset; +var coolantPressure; +var optionalSection = false; +var forceSpindleSpeed = false; +var forceCoolant = false; +var activeMovements; // do not use by default +var currentFeedId; +var maximumCircularRadiiDifference = toPreciseUnit(0.005, MM); +var maximumLineLength = 80; // the maximum number of charaters allowed in a line +var subprograms = []; +var currentPattern = -1; +var firstPattern = false; +var currentSubprogram; +var lastSubprogram; +var initialSubprogramNumber = 90000; +var definedPatterns = new Array(); +var incrementalMode = false; +var saveShowSequenceNumbers; +var cycleSubprogramIsActive = false; +var patternIsActive = false; +var lastOperationComment = ""; +var incrementalSubprogram; +var retracted = false; // specifies that the tool has been retracted to the safe plane +var hasA = false; +var hasB = false; +var hasC = false; +var measureTool = false; +var cycleReverse = false; +var probeMultipleFeatures = true; +var maximumSpindleRPM = 15000; +var homePositionCenter = false; + +// used to convert blocks to optional for safeStartAllOperations, might get used outside of onSection +var operationNeedsSafeStart = false; + + +var songStart = false; +var lastNote; +// TODO check last note +function playNote(note, seconds) { + if (songStart == false) { + writeBlock(sOutput.format(note[1]), mFormat.format(4), formatComment(note[0])); + writeBlock(gFormat.format(4), "P" + seconds.toFixed(2)); + lastNote = note[1]; + songStart = true; + return; + } + if (note[1] == lastNote) { + writeBlock(sOutput.format(8000), gFormat.format(4), "P.1"); + } + writeBlock(sOutput.format(note[1]), formatComment(note[0])); + writeBlock(gFormat.format(4), "P" + seconds.toFixed(2)); + lastNote = note[1]; +} + +var macroNumber = 500; +function takeInput(prompt, options) { + + // Cycle through macro variables, reset at end of general purpose vars + if (macroNumber > 549) macroNumber = 500; + + // init macro var to 0 + setMacro(macroNumber, 0, "Initialize macro variable"); + + // disply prompt and save response + writeBlock(mFormat.format(109), "P" + nFormat.format(macroNumber), formatComment(prompt)); + sequenceNumber -= staticProperties.sequenceNumberIncrement; + var gotoRef = sequenceNumber; + + // wait for input + writeln("IF[#" + macroNumber + " EQ 0.] GOTO" + nFormat.format(gotoRef) + " " + formatComment("NULL")); + + // print if's and goto's + var gotoMap = {}; + var gotoInc = 1; + options.forEach(function (element) { + writeWords("IF[#" + macroNumber + " EQ " + element.charCodeAt(0) + ".] GOTO" + nFormat.format(sequenceNumber + gotoInc), formatComment(element)); + gotoMap[element] = (sequenceNumber + gotoInc); + gotoInc += 1; + }); + + var incNum = staticProperties.sequenceNumberIncrement; + // adjust sequence number if needed + for (i = incNum; i < gotoInc; i+=incNum) { + sequenceNumber += staticProperties.sequenceNumberIncrement; + } + + // return to input until valid option is entered + writeWords("GOTO" + nFormat.format(gotoRef), formatComment("INVALID INPUT")); + + // increase var number, iterate sequence number + macroNumber += 1; + sequenceNumber += staticProperties.sequenceNumberIncrement; + return gotoMap; +} + +function keyPress(note, lNum, retNum) { + writeWords("N" + lNum + " " + sOutput.format(note[1]), formatComment(note[0])); + writeWords("GOTO" + nFormat.format(retNum)); + +} + +var macroNumber = 500; +function writeKeyboard(natural){ + if (macroNumber > 549) macroNumber = 500; + setMacro(macroNumber, 0, "Initialize macro variable"); + // disply prompt and save response + writeBlock(mFormat.format(109), "P" + nFormat.format(macroNumber), formatComment("C3 Keyboard")); + sequenceNumber -= staticProperties.sequenceNumberIncrement; + var gotoRef = sequenceNumber; + writeln("IF[#" + macroNumber + " EQ 0.] GOTO" + nFormat.format(gotoRef) + " " + formatComment("NULL")); + // print if's and goto's + var gotoMap = {}; + var gotoInc = 1; + if (natural) { + ['C', 'D', 'E', 'F', 'G', 'A', 'B', 'S', 'O'].forEach(function (element) { + writeWords("IF[#" + macroNumber + " EQ " + element.charCodeAt(0) + ".] GOTO" + nFormat.format(sequenceNumber + gotoInc), formatComment(element)); + gotoMap[element] = (sequenceNumber + gotoInc); + gotoInc += 1; + }); + } else { + ['C', 'D', 'F', 'G', 'A', 'N', 'O'].forEach(function (element) { + writeWords("IF[#" + macroNumber + " EQ " + element.charCodeAt(0) + ".] GOTO" + nFormat.format(sequenceNumber + gotoInc), formatComment(element)); + gotoMap[element] = (sequenceNumber + gotoInc); + gotoInc += 1; + }); + } + + var incNum = staticProperties.sequenceNumberIncrement; + // adjust sequence number if needed + for (i = incNum; i < gotoInc; i+=incNum) { + sequenceNumber += staticProperties.sequenceNumberIncrement; + } + + writeWords("GOTO" + nFormat.format(gotoRef), formatComment("INVALID INPUT")); + + if (natural) { + keyPress(notes.C3, gotoMap['C'], gotoRef); + keyPress(notes.D3, gotoMap['D'], gotoRef); + keyPress(notes.E3, gotoMap['E'], gotoRef); + keyPress(notes.F3, gotoMap['F'], gotoRef); + keyPress(notes.G3, gotoMap['G'], gotoRef); + keyPress(notes.A3, gotoMap['A'], gotoRef); + keyPress(notes.B3, gotoMap['B'], gotoRef); + keyPress(notes.o1, gotoMap['O'], gotoRef); + writeWords("N" + gotoMap['S'] +" GOTO" + nFormat.format(gotoRef + 10), formatComment("#")); + } else { + keyPress(notes.Cs3, gotoMap['C'], gotoRef); + keyPress(notes.Ds3, gotoMap['D'], gotoRef); + keyPress(notes.Fs3, gotoMap['F'], gotoRef); + keyPress(notes.Gs3, gotoMap['G'], gotoRef); + keyPress(notes.As3, gotoMap['A'], gotoRef); + keyPress(notes.o1, gotoMap['O'], gotoRef); + writeWords("N" + gotoMap['N'] +" GOTO" + nFormat.format(gotoRef - 10), formatComment("n")); + } + // increase var number, iterate sequence number + macroNumber += 1; + sequenceNumber += staticProperties.sequenceNumberIncrement; + return gotoRef; +} + +function playSong() { + playNote(notes.E3, 1.5); + playNote(notes.Fs3, .5); + playNote(notes.G3, 1); + playNote(notes.E3, 1); + playNote(notes.D3, 1); + playNote(notes.G3, 1); + playNote(notes.B3, 1); + playNote(notes.D3, 1); + playNote(notes.E3, 1.5); + playNote(notes.B3, .5); + playNote(notes.A3, 1.5); + playNote(notes.G3, .5); + playNote(notes.G3, 2.5); +} +/** + Writes the specified block. +*/ +var skipBlock = false; +function writeBlock() { + var text = formatWords(arguments); + if (!text) { + return; + } + var maximumSequenceNumber = ((getProperty("useSubroutines") == "allOperations") || (getProperty("useSubroutines") == "patterns") || + (getProperty("useSubroutines") == "cycles")) ? initialSubprogramNumber : 99999; + if (staticProperties.showSequenceNumbers) { + if (sequenceNumber >= maximumSequenceNumber) { + sequenceNumber = staticProperties.sequenceNumberStart; + } + if (optionalSection || skipBlock) { + if (text) { + writeWords("/", "N" + sequenceNumber, text); + } + } else { + writeWords2("N" + sequenceNumber, arguments); + } + sequenceNumber += staticProperties.sequenceNumberIncrement; + } else { + if (optionalSection || skipBlock) { + writeWords2("/", arguments); + } else { + writeWords(arguments); + } + } + skipBlock = false; +} + +/** + Writes the specified block - used for tool changes only. +*/ +function writeToolBlock() { + var show = staticProperties.showSequenceNumbers; + staticProperties.showSequenceNumbers = (show || staticProperties.sequenceNumberOnlyOnToolChange); + writeBlock(arguments); + staticProperties.showSequenceNumbers = show; +} + +/** + Writes the specified optional block. +*/ +function writeOptionalBlock() { + skipBlock = true; + writeBlock(arguments); +} + +function formatComment(text) { + return "(" + String(text).replace(/[()]/g, "") + ")"; +} + +/** + Output a comment. +*/ +function writeComment(text) { + writeln(formatComment(text.substr(0, maximumLineLength - 2))); +} + +/** + Returns the matching HAAS tool type for the tool. +*/ +function getHaasToolType(toolType) { + switch (toolType) { + case TOOL_DRILL: + case TOOL_REAMER: + return 1; // drill + case TOOL_TAP_RIGHT_HAND: + case TOOL_TAP_LEFT_HAND: + return 2; // tap + case TOOL_MILLING_FACE: + case TOOL_MILLING_SLOT: + case TOOL_BORING_BAR: + return 3; // shell mill + case TOOL_MILLING_END_FLAT: + case TOOL_MILLING_END_BULLNOSE: + case TOOL_MILLING_TAPERED: + case TOOL_MILLING_DOVETAIL: + return 4; // end mill + case TOOL_DRILL_SPOT: + case TOOL_MILLING_CHAMFER: + case TOOL_DRILL_CENTER: + case TOOL_COUNTER_SINK: + case TOOL_COUNTER_BORE: + case TOOL_MILLING_THREAD: + case TOOL_MILLING_FORM: + return 5; // center drill + case TOOL_MILLING_END_BALL: + case TOOL_MILLING_LOLLIPOP: + return 6; // ball nose + case TOOL_PROBE: + return 7; // probe + default: + error(localize("Invalid HAAS tool type.")); + return -1; + } +} + +function getHaasProbingType(toolType, use9023) { + switch (getHaasToolType(toolType)) { + case 3: + case 4: + return (use9023 ? 23 : 1); // rotate + case 1: + case 2: + case 5: + case 6: + case 7: + return (use9023 ? 12 : 2); // non rotate + case 0: + return (use9023 ? 13 : 3); // rotate length and dia + default: + error(localize("Invalid HAAS tool type.")); + return -1; + } +} + + +// Added new probe mapping - see documentation +// will1742 | Gavin Williams +function getHaasToolTypeBIDC(toolType) { + switch (toolType) { + case TOOL_DRILL: + case TOOL_REAMER: + return HAAS_DRILL; // drill + case TOOL_TAP_RIGHT_HAND: + case TOOL_TAP_LEFT_HAND: + return HAAS_TAP; // tap + case TOOL_MILLING_FACE: + case TOOL_MILLING_SLOT: + case TOOL_BORING_BAR: + return HAAS_SHELL; // shell mill + case TOOL_MILLING_END_FLAT: + case TOOL_MILLING_END_BULLNOSE: + case TOOL_MILLING_TAPERED: + case TOOL_MILLING_DOVETAIL: + case TOOL_MILLING_THREAD: + return HAAS_END_MILL; // end mill + case TOOL_DRILL_SPOT: + case TOOL_MILLING_CHAMFER: + case TOOL_DRILL_CENTER: + case TOOL_COUNTER_SINK: + case TOOL_COUNTER_BORE: + case TOOL_MILLING_FORM: + return HAAS_CENTER; // center drill + case TOOL_MILLING_END_BALL: + case TOOL_MILLING_LOLLIPOP: + case TOOL_MILLING_RADIUS: + return HAAS_BALL_NOSE; // ball nose + case TOOL_PROBE: + return HAAS_PROBE; // probe + default: + error(localize("Invalid HAAS tool type.")); + return -1; + } +} + +// 06/25/21 | Gavin Williams | will1742 +// 002 Probing +function formatCNumber(probeType, use9023){ + if (use9023) { + if (probeType == LEN_NON_ROT || probeType == LEN_DIA_ROT){ + return probeType + 10; + } + return 23; + } + return probeType; +} + +function getHaasProbingTypeBIDC(tool, use9023) { + switch (getHaasToolTypeBIDC(tool.type)) { + case HAAS_PROBE: + return formatCNumber(NO_PROBING, use9023); + case HAAS_TAP: + case HAAS_DRILL: + return formatCNumber(LEN_NON_ROT, use9023); + case HAAS_CENTER: + if (tool.type == TOOL_MILLING_FORM) { + return formatCNumber(NO_PROBING, use9023); + } + return formatCNumber(LEN_NON_ROT, use9023); + case HAAS_END_MILL: + return formatCNumber((tool.type == TOOL_MILLING_TAPERED ? LEN_ROT : LEN_DIA_ROT), use9023); + case HAAS_BALL_NOSE: + return formatCNumber((tool.type == TOOL_MILLING_RADIUS ? LEN_ROT : LEN_DIA_ROT), use9023); + case HAAS_SHELL: + if ((tool.type == TOOL_MILLING_FACE) && (tool.taperAngle !=0)) { + return formatCNumber(LEN_ROT, use9023); + } + return formatCNumber(LEN_DIA_ROT, use9023); + default: + return -1; + } +} + +function getHaasKFactorBIDC(tool) { + switch (getHaasToolTypeBIDC(tool.type)) { + case HAAS_SHELL: + case HAAS_END_MILL: + if (tool.type == TOOL_BORING_BAR || tool.type == TOOL_MILLING_END_FLAT) { + return DEFAULT_HAAS_K_FACTOR; + } + if (tool.type == TOOL_MILLING_FACE && tool.taperAngle != 0) { + return NULL_HAAS_K_FACTOR; + } + if (tool.type == TOOL_MILLING_THREAD) { + return DEFAULT_HAAS_K_FACTOR + tool.getThreadPitch(); + } + return DEFAULT_HAAS_K_FACTOR + tool.cornerRadius; + case HAAS_BALL_NOSE: + if (tool.type == TOOL_MILLING_RADIUS) { + return NULL_HAAS_K_FACTOR; + } + return DEFAULT_HAAS_K_FACTOR + (tool.diameter/2); + case HAAS_CENTER: + case HAAS_PROBE: + case HAAS_DRILL: + case HAAS_TAP: + + return NULL_HAAS_K_FACTOR; + default: + return -1; + } +} + +function writeToolCycleBlock(tool) { + writeOptionalBlock("T" + toolFormat.format(tool.number), mFormat.format(6)); // get tool + writeOptionalBlock(mFormat.format(0)); // wait for operator +} + +function prepareForToolCheck() { + onCommand(COMMAND_STOP_SPINDLE); + onCommand(COMMAND_COOLANT_OFF); + + // cancel TCP so that tool doesn't follow tables + if (currentSection.isMultiAxis() && tcpIsSupported) { + disableLengthCompensation(false, "TCPC OFF"); + } + if ((currentSection.isMultiAxis() && getCurrentDirection().length != 0) || + (currentMachineABC != undefined && currentMachineABC.length != 0)) { + setWorkPlane(new Vector(0, 0, 0)); + forceWorkPlane(); + } +} + +function writeToolMeasureBlock(tool, preMeasure) { + // var writeFunction = measureTool ? writeBlock : writeOptionalBlock; + var writeFunction = writeBlock; + var comment = measureTool ? formatComment("MEASURE TOOL") : ""; + if (!preMeasure) { + prepareForToolCheck(); + } + if (!staticProperties.useP9995) { // use Macro P9023 to measure tools + var probingType = getHaasProbingTypeBIDC(tool.type, true); + writeFunction( + gFormat.format(65), + "P9023", + "A" + probingType + ".", + "T" + toolFormat.format(tool.number), + conditional((probingType != 12), "H" + xyzFormat.format(tool.bodyLength + tool.holderLength)), + conditional((probingType != 12), "D" + xyzFormat.format(tool.diameter)), + comment + ); + } else { // use Macro P9995 to measure tools + // writeFunction("T" + toolFormat.format(tool.number), mFormat.format(6)); // get tool + setMacro(1600 + tool.number, tool.numberOfFlutes, "Number of Flutes"); + var probeType = getHaasProbingTypeBIDC(tool, false); + writeFunction( + gFormat.format(65), + "P9995", + "A0.", + "B" + getHaasToolTypeBIDC(tool.type) + ".", + "C" + probeType + ".", + "T" + toolFormat.format(tool.number), + "E" + xyzFormat.format(tool.bodyLength + tool.holderLength), + "D" + xyzFormat.format(tool.diameter), + "K" + xyzFormat.format(getHaasKFactorBIDC(tool)), + "I0.", + comment + ); // probe tool + writeWords("IF [[#" + (2000 + tool.number) + " GT " + + (tool.bodyLength + tool.holderLength + LENGTH_TOLERANCE).toFixed(2) + "] OR [#" + + (2000 + tool.number) + " LT " + + (tool.bodyLength + tool.holderLength - LENGTH_TOLERANCE).toFixed(2) + "]] THEN #3000 = 1 (Tool length out of tolerance)"); + + if (probeType == 3) { + writeWords("IF [[#" + (2000 + tool.number) + " GT " + + (tool.diameter + DIAM_TOLERANCE).toFixed(2) + "] OR [#" + + (2000 + tool.number) + " LT " + + (tool.diameter - DIAM_TOLERANCE).toFixed(2) + "]] THEN #3000 = 1 (Tool diameter out of tolerance)"); + } + } + measureTool = false; +} + +// 6/28/21 | Gavin Williams | will1742 +// 002 Improved Probing +// sets specified macro number with value +function setMacro(macro, value, comment) { + writeWords("#" + macro + "=" + value, "(" + comment + ")"); +} + +function defineMachineModel() { + var useTCPC = getProperty("useTCPC"); + switch (staticProperties.machineModel) { + case "umc-500": + var axis1 = createAxis({coordinate:1, table:true, axis:[0, 1, 0], range:[-35, 120], preference:1, tcp:useTCPC}); + var axis2 = createAxis({coordinate:2, table:true, axis:[0, 0, 1], cyclic:true, preference:0, reset:1, tcp:useTCPC}); + machineConfiguration = new MachineConfiguration(axis1, axis2); + machineConfiguration.setHomePositionX(toPreciseUnit(-23.96, IN)); + machineConfiguration.setHomePositionY(toPreciseUnit(-3.37, IN)); + machineConfiguration.setRetractPlane(toPreciseUnit(0, IN)); + maximumSpindleRPM = 8100; + break; + case "umc-750": + var axis1 = createAxis({coordinate:1, table:true, axis:[0, 1, 0], range:[-35, 120], preference:1, tcp:useTCPC}); + var axis2 = createAxis({coordinate:2, table:true, axis:[0, 0, 1], cyclic:true, preference:0, reset:1, tcp:useTCPC}); + machineConfiguration = new MachineConfiguration(axis1, axis2); + machineConfiguration.setHomePositionX(toPreciseUnit(-29.0, IN)); + machineConfiguration.setHomePositionY(toPreciseUnit(-8, IN)); + machineConfiguration.setRetractPlane(toPreciseUnit(2.5, IN)); + maximumSpindleRPM = 8100; + break; + case "umc-1000": + var axis1 = createAxis({coordinate:1, table:true, axis:[0, 1, 0], range:[-35, 120], preference:1, tcp:useTCPC}); + var axis2 = createAxis({coordinate:2, table:true, axis:[0, 0, 1], cyclic:true, preference:0, reset:1, tcp:useTCPC}); + machineConfiguration = new MachineConfiguration(axis1, axis2); + machineConfiguration.setHomePositionX(toPreciseUnit(-40.07, IN)); + machineConfiguration.setHomePositionY(toPreciseUnit(-10.76, IN)); + machineConfiguration.setRetractPlane(toPreciseUnit(0, IN)); + maximumSpindleRPM = 8100; + break; + case "umc-1600": + var axis1 = createAxis({coordinate:1, table:true, axis:[0, 1, 0], range:[-120, 120], preference:1, tcp:useTCPC}); + var axis2 = createAxis({coordinate:2, table:true, axis:[0, 0, 1], cyclic:true, preference:0, reset:1, tcp:useTCPC}); + machineConfiguration = new MachineConfiguration(axis1, axis2); + machineConfiguration.setHomePositionX(toPreciseUnit(0, IN)); + machineConfiguration.setHomePositionY(toPreciseUnit(0, IN)); + machineConfiguration.setRetractPlane(toPreciseUnit(0, IN)); + maximumSpindleRPM = 7500; + break; + } + machineConfiguration.setModel(staticProperties.machineModel.toUpperCase()); + machineConfiguration.setVendor("Haas Automation"); + + setMachineConfiguration(machineConfiguration); + if (receivedMachineConfiguration) { + warning(localize("The provided CAM machine configuration is overwritten by the postprocessor.")); + receivedMachineConfiguration = false; // CAM provided machine configuration is overwritten + } +} + +// Start of machine configuration logic +var compensateToolLength = false; // add the tool length to the pivot distance for nonTCP rotary heads +var virtualTooltip = false; // translate the pivot point to the virtual tool tip for nonTCP rotary heads +// internal variables, do not change +var receivedMachineConfiguration; +var tcpIsSupported; + +function activateMachine() { + // determine if TCP is supported by the machine + tcpIsSupported = false; + var axes = [machineConfiguration.getAxisU(), machineConfiguration.getAxisV(), machineConfiguration.getAxisW()]; + for (var i in axes) { + if (axes[i].isEnabled() && axes[i].isTCPEnabled()) { + tcpIsSupported = true; + break; + } + } + + // 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.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(); + } + + if (!machineConfiguration.isMultiAxisConfiguration()) { + return; // don't need to modify any settings for 3-axis machines + } + + // retract/reconfigure + safeRetractDistance = staticProperties.safeRetractDistance != undefined ? staticProperties.safeRetractDistance : + (typeof safeRetractDistance == "number" ? safeRetractDistance : 0); + if (machineConfiguration.performRewinds() || (typeof performRewinds == "undefined" ? false : performRewinds)) { + machineConfiguration.enableMachineRewinds(); // enables the rewind/reconfigure logic + if (typeof stockExpansion != "undefined") { + machineConfiguration.setRewindStockExpansion(stockExpansion); + if (!receivedMachineConfiguration) { + setMachineConfiguration(machineConfiguration); + } + } + } + + if (machineConfiguration.isHeadConfiguration()) { + compensateToolLength = typeof compensateToolLength == "undefined" ? false : compensateToolLength; + virtualTooltip = typeof virtualTooltip == "undefined" ? false : virtualTooltip; + machineConfiguration.setVirtualTooltip(virtualTooltip); + } + setFeedrateMode(); + + if (machineConfiguration.isHeadConfiguration() && compensateToolLength) { + for (var i = 0; i < getNumberOfSections(); ++i) { + var section = getSection(i); + if (section.isMultiAxis()) { + machineConfiguration.setToolLength(section.getTool().getBodyLength()); // define the tool length for head adjustments + section.optimizeMachineAnglesByMachine(machineConfiguration, tcpIsSupported ? 0 : 1); + } + } + } else { + optimizeMachineAngles2(tcpIsSupported ? 0 : 1); + } +} + +function setFeedrateMode(reset) { + if ((tcpIsSupported && !reset) || !machineConfiguration.isMultiAxisConfiguration()) { + return; + } + machineConfiguration.setMultiAxisFeedrate( + tcpIsSupported ? FEED_FPM : staticProperties.useDPMFeeds ? FEED_DPM : FEED_INVERSE_TIME, + 9999.99, // maximum output value for inverse time feed rates + INVERSE_MINUTES, // can be INVERSE_SECONDS or DPM_COMBINATION for DPM feeds + 0.5, // tolerance to determine when the DPM feed has changed + 1.0 // ratio of rotary accuracy to linear accuracy for DPM calculations + ); + if (!receivedMachineConfiguration || (revision < 45765)) { + setMachineConfiguration(machineConfiguration); + } +} + +function defineMachine() { + hasA = getProperty("hasAAxis") != "false"; + hasB = getProperty("hasBAxis") != "false"; + hasC = getProperty("hasCAxis") != "false"; + + if (hasA && hasB && hasC) { + error(localize("Only two rotary axes can be active at the same time.")); + return; + } else if ((hasA || hasB || hasC) && staticProperties.machineModel != "none") { + error(localize("You can only select either a machine model or use the ABC axis properties.")); + return; + } else if (((hasA || hasB || hasC) || staticProperties.machineModel != "none") && (receivedMachineConfiguration && machineConfiguration.isMultiAxisConfiguration())) { + error(localize("You can only select either a machine in the CAM setup or use the properties to define your kinematics.")); + return; + } + if (staticProperties.machineModel == "none") { + if (hasA || hasB || hasC) { // configure machine + var aAxis; + var bAxis; + var cAxis; + var useTCPC = getProperty("useTCPC"); + if (hasA) { // A Axis - For horizontal machines and trunnions + var dir = getProperty("hasAAxis") == "reversed" ? -1 : 1; + if (hasC || hasB) { + var aMin = (dir == 1) ? -120 - 0.0001 : -30 - 0.0001; + var aMax = (dir == 1) ? 30 + 0.0001 : 120 + 0.0001; + aAxis = createAxis({coordinate:0, table:true, axis:[dir, 0, 0], range:[aMin, aMax], preference:dir, reset:(hasB ? 0 : 1), tcp:useTCPC}); + } else { + aAxis = createAxis({coordinate:0, table:true, axis:[dir, 0, 0], cyclic:true, tcp:useTCPC}); + } + } + + if (hasB) { // B Axis - For horizontal machines and trunnions + var dir = getProperty("hasBAxis") == "reversed" ? -1 : 1; + if (hasC) { + var bMin = (dir == 1) ? -120 - 0.0001 : -30 - 0.0001; + var bMax = (dir == 1) ? 30 + 0.0001 : 120 + 0.0001; + bAxis = createAxis({coordinate:1, table:true, axis:[0, dir, 0], range:[bMin, bMax], preference:-dir, reset:1, tcp:useTCPC}); + } else if (hasA) { + bAxis = createAxis({coordinate:1, table:true, axis:[0, 0, dir], cyclic:true, tcp:useTCPC}); + } else { + bAxis = createAxis({coordinate:1, table:true, axis:[0, dir, 0], cyclic:true, tcp:useTCPC}); + } + } + + if (hasC) { // C Axis - For trunnions only + var dir = getProperty("hasCAxis") == "reversed" ? -1 : 1; + cAxis = createAxis({coordinate:2, table:true, axis:[0, 0, dir], cyclic:true, reset:1, tcp:useTCPC}); + } + + if (hasA && hasC) { // AC trunnion + machineConfiguration = new MachineConfiguration(aAxis, cAxis); + } else if (hasB && hasC) { // BC trunnion + machineConfiguration = new MachineConfiguration(bAxis, cAxis); + } else if (hasA && hasB) { // AB trunnion + machineConfiguration = new MachineConfiguration(aAxis, bAxis); + } else if (hasA) { // A rotary + machineConfiguration = new MachineConfiguration(aAxis); + } else if (hasB) { // B rotary - horizontal machine only + machineConfiguration = new MachineConfiguration(bAxis); + } else if (hasC) { // C rotary + machineConfiguration = new MachineConfiguration(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 + } + } + } else { + defineMachineModel(); + } + /* home positions */ + // machineConfiguration.setHomePositionX(toPreciseUnit(0, IN)); + // machineConfiguration.setHomePositionY(toPreciseUnit(0, IN)); + // machineConfiguration.setRetractPlane(toPreciseUnit(0, IN)); +} +// End of machine configuration logic + +function onOpen() { + receivedMachineConfiguration = (typeof machineConfiguration.isReceived == "function") ? machineConfiguration.isReceived() : + ((machineConfiguration.getDescription() != "") || machineConfiguration.isMultiAxisConfiguration()); + if (typeof defineMachine == "function") { + defineMachine(); // hardcoded machine configuration + } + activateMachine(); // enable the machine optimizations and settings + + if (staticProperties.useDPMFeeds) { + gFeedModeModal.format(94); + } + if (staticProperties.useRadius) { + maximumCircularSweep = toRad(90); // avoid potential center calculation errors for CNC + } + if (staticProperties.sequenceNumberOnlyOnToolChange) { + staticProperties.showSequenceNumbers = false; + } + if (!staticProperties.useDWO) { + useDWOForPositioning = false; + } + + gRotationModal.format(69); // Default to G69 Rotation Off + + if (highFeedrate <= 0) { + error(localize("You must set 'highFeedrate' because axes are not synchronized for rapid traversal.")); + return; + } + + if (!staticProperties.separateWordsWithSpace) { + setWordSeparator(""); + } + saveShowSequenceNumbers = staticProperties.showSequenceNumbers; + sequenceNumber = staticProperties.sequenceNumberStart; + writeln("%"); + + if (programName) { + var programId; + try { + programId = getAsInt(programName); + } catch (e) { + error(localize("Program name must be a number.")); + return; + } + if (!((programId >= 1) && (programId <= 99999))) { + error(localize("Program number is out of range.")); + return; + } + writeln( + "O" + oFormat.format(programId) + + conditional(programComment, " " + formatComment(programComment.substr(0, maximumLineLength - 2 - ("O" + oFormat.format(programId)).length - 1))) + ); + lastSubprogram = (initialSubprogramNumber - 1); + } else { + error(localize("Program name has not been specified.")); + return; + } + + writeComment("Career Account Username: " + getGlobalParameter("username")); + writeComment("Filename: " + getGlobalParameter("document-path")); + writeComment("Date: " + getGlobalParameter("generated-at")); + writeComment("Post Version: " + staticProperties.postVersion); + + if (staticProperties.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 (staticProperties.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 (staticProperties.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 (staticProperties.useM130PartImages) { + var toolRenderer = createToolRenderer(); + if (toolRenderer) { + toolRenderer.setBackgroundColor(new Color(1, 1, 1)); + toolRenderer.setFluteColor(new Color(40.0 / 255, 40.0 / 255, 40.0 / 255)); + toolRenderer.setShoulderColor(new Color(80.0 / 255, 80.0 / 255, 80.0 / 255)); + toolRenderer.setShaftColor(new Color(80.0 / 255, 80.0 / 255, 80.0 / 255)); + toolRenderer.setHolderColor(new Color(40.0 / 255, 40.0 / 255, 40.0 / 255)); + if (i % 2 == 0) { + toolRenderer.setBackgroundColor(new Color(1, 1, 1)); + } else { + toolRenderer.setBackgroundColor(new Color(240 / 255.0, 240 / 255.0, 240 / 255.0)); + } + var path = "tool" + tool.number + ".png"; + var width = 400; + var height = 532; + toolRenderer.exportAs(path, "image/png", tool, width, height); + } + } + } + } + } + + writeln(""); + writeRetract(Z); + writeBlock(sOutput.format(notes.o1[1]), mFormat.format(4), formatComment("Init Spindle")); + writeKeyboard(true); + writeKeyboard(false); + playSong(); + +} + +function onComment(message) { + writeComment(message); +} + +/** Force output of X, Y, and Z. */ +function forceXYZ() { + xOutput.reset(); + yOutput.reset(); + zOutput.reset(); +} + +/** Force output of A, B, and C. */ +function forceABC() { + aOutput.reset(); + bOutput.reset(); + cOutput.reset(); +} + +function forceFeed() { + currentFeedId = undefined; + feedOutput.reset(); +} + +/** Force output of X, Y, Z, A, B, C, and F on next output. */ +function forceAny() { + forceXYZ(); + forceABC(); + forceFeed(); +} + +var lengthCompensationActive = false; +/** Disables length compensation if currently active or if forced. */ +function disableLengthCompensation(force, message) { + if (lengthCompensationActive || force) { + writeBlock(gFormat.format(49), conditional(message, formatComment(message))); + lengthCompensationActive = false; + } +} + +function writeG187() { + if (hasParameter("operation-strategy") && (getParameter("operation-strategy") == "drill")) { + writeBlock(gFormat.format(187)); // reset G187 setting to machine default + } else if (hasParameter("operation:tolerance")) { + var tolerance = Math.max(getParameter("operation:tolerance"), 0); + if (tolerance > 0) { + var stockToLeaveThreshold = toUnit(0.1, MM); + var stockToLeave = 0; + var verticalStockToLeave = 0; + if (hasParameter("operation:stockToLeave")) { + stockToLeave = xyzFormat.getResultingValue(getParameter("operation:stockToLeave")); + } + if (hasParameter("operation:verticalStockToLeave")) { + verticalStockToLeave = xyzFormat.getResultingValue(getParameter("operation:verticalStockToLeave")); + } + + var workMode; + if (((stockToLeave > stockToLeaveThreshold) && (verticalStockToLeave > stockToLeaveThreshold)) || + (hasParameter("operation:strategy") && getParameter("operation:strategy") == "face")) { + workMode = 1; // roughing + } else { + if ((stockToLeave > 0) || (verticalStockToLeave > 0)) { + workMode = 2; // default + } else { + workMode = 3; // fine + } + } + writeBlock(gFormat.format(187), "P" + workMode); // set tolerance mode + // writeBlock(gFormat.format(187), "P" + workMode, "E" + xyzFormat.format(tolerance)); // set tolerance mode + } else { + writeBlock(gFormat.format(187)); // reset G187 setting to machine default + } + } else { + writeBlock(gFormat.format(187)); // reset G187 setting to machine default + } +} + +function FeedContext(id, description, feed) { + this.id = id; + this.description = description; + this.feed = feed; +} + +function getFeed(f) { + if (activeMovements) { + var feedContext = activeMovements[movement]; + if (feedContext != undefined) { + if (!feedFormat.areDifferent(feedContext.feed, f)) { + if (feedContext.id == currentFeedId) { + return ""; // nothing has changed + } + forceFeed(); + currentFeedId = feedContext.id; + return "F#" + (firstFeedParameter + feedContext.id); + } + } + currentFeedId = undefined; // force Q feed next time + } + return feedOutput.format(f); // use feed value +} + +function initializeActiveFeeds() { + activeMovements = new Array(); + var movements = currentSection.getMovements(); + + var id = 0; + var activeFeeds = new Array(); + if (hasParameter("operation:tool_feedCutting")) { + if (movements & ((1 << MOVEMENT_CUTTING) | (1 << MOVEMENT_LINK_TRANSITION) | (1 << MOVEMENT_EXTENDED))) { + var feedContext = new FeedContext(id, localize("Cutting"), getParameter("operation:tool_feedCutting")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_CUTTING] = feedContext; + activeMovements[MOVEMENT_LINK_TRANSITION] = feedContext; + activeMovements[MOVEMENT_EXTENDED] = feedContext; + } + ++id; + if (movements & (1 << MOVEMENT_PREDRILL)) { + feedContext = new FeedContext(id, localize("Predrilling"), getParameter("operation:tool_feedCutting")); + activeMovements[MOVEMENT_PREDRILL] = feedContext; + activeFeeds.push(feedContext); + } + ++id; + } + + if (hasParameter("operation:finishFeedrate")) { + if (movements & (1 << MOVEMENT_FINISH_CUTTING)) { + var feedContext = new FeedContext(id, localize("Finish"), getParameter("operation:finishFeedrate")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_FINISH_CUTTING] = feedContext; + } + ++id; + } else if (hasParameter("operation:tool_feedCutting")) { + if (movements & (1 << MOVEMENT_FINISH_CUTTING)) { + var feedContext = new FeedContext(id, localize("Finish"), getParameter("operation:tool_feedCutting")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_FINISH_CUTTING] = feedContext; + } + ++id; + } + + if (hasParameter("operation:tool_feedEntry")) { + if (movements & (1 << MOVEMENT_LEAD_IN)) { + var feedContext = new FeedContext(id, localize("Entry"), getParameter("operation:tool_feedEntry")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_LEAD_IN] = feedContext; + } + ++id; + } + + if (hasParameter("operation:tool_feedExit")) { + if (movements & (1 << MOVEMENT_LEAD_OUT)) { + var feedContext = new FeedContext(id, localize("Exit"), getParameter("operation:tool_feedExit")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_LEAD_OUT] = feedContext; + } + ++id; + } + + if (hasParameter("operation:noEngagementFeedrate")) { + if (movements & (1 << MOVEMENT_LINK_DIRECT)) { + var feedContext = new FeedContext(id, localize("Direct"), getParameter("operation:noEngagementFeedrate")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_LINK_DIRECT] = feedContext; + } + ++id; + } else if (hasParameter("operation:tool_feedCutting") && + hasParameter("operation:tool_feedEntry") && + hasParameter("operation:tool_feedExit")) { + if (movements & (1 << MOVEMENT_LINK_DIRECT)) { + var feedContext = new FeedContext(id, localize("Direct"), Math.max(getParameter("operation:tool_feedCutting"), getParameter("operation:tool_feedEntry"), getParameter("operation:tool_feedExit"))); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_LINK_DIRECT] = feedContext; + } + ++id; + } + + if (hasParameter("operation:reducedFeedrate")) { + if (movements & (1 << MOVEMENT_REDUCED)) { + var feedContext = new FeedContext(id, localize("Reduced"), getParameter("operation:reducedFeedrate")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_REDUCED] = feedContext; + } + ++id; + } + + if (hasParameter("operation:tool_feedRamp")) { + if (movements & ((1 << MOVEMENT_RAMP) | (1 << MOVEMENT_RAMP_HELIX) | (1 << MOVEMENT_RAMP_PROFILE) | (1 << MOVEMENT_RAMP_ZIG_ZAG))) { + var feedContext = new FeedContext(id, localize("Ramping"), getParameter("operation:tool_feedRamp")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_RAMP] = feedContext; + activeMovements[MOVEMENT_RAMP_HELIX] = feedContext; + activeMovements[MOVEMENT_RAMP_PROFILE] = feedContext; + activeMovements[MOVEMENT_RAMP_ZIG_ZAG] = feedContext; + } + ++id; + } + if (hasParameter("operation:tool_feedPlunge")) { + if (movements & (1 << MOVEMENT_PLUNGE)) { + var feedContext = new FeedContext(id, localize("Plunge"), getParameter("operation:tool_feedPlunge")); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_PLUNGE] = feedContext; + } + ++id; + } + if (true) { // high feed + if ((movements & (1 << MOVEMENT_HIGH_FEED)) || (highFeedMapping != HIGH_FEED_NO_MAPPING)) { + var feed; + if (hasParameter("operation:highFeedrateMode") && getParameter("operation:highFeedrateMode") != "disabled") { + feed = getParameter("operation:highFeedrate"); + } else { + feed = this.highFeedrate; + } + var feedContext = new FeedContext(id, localize("High Feed"), feed); + activeFeeds.push(feedContext); + activeMovements[MOVEMENT_HIGH_FEED] = feedContext; + activeMovements[MOVEMENT_RAPID] = feedContext; + } + ++id; + } + + for (var i = 0; i < activeFeeds.length; ++i) { + var feedContext = activeFeeds[i]; + writeBlock("#" + (firstFeedParameter + feedContext.id) + "=" + feedFormat.format(feedContext.feed), formatComment(feedContext.description)); + } +} + +var currentWorkPlaneABC = undefined; +var activeG254 = false; + +function forceWorkPlane() { + currentWorkPlaneABC = undefined; +} + +function defineWorkPlane(_section, _setWorkPlane) { + var abc = new Vector(0, 0, 0); + if (machineConfiguration.isMultiAxisConfiguration()) { // use 5-axis indexing for multi-axis mode + // set working plane after datum shift + + if (_section.isMultiAxis()) { + cancelTransformation(); + abc = _section.getInitialToolAxisABC(); + if (_setWorkPlane) { + if (activeG254) { + writeBlock(gFormat.format(255)); // cancel DWO + activeG254 = false; + } + if (!retracted) { + moveToSafeRetractPosition(); + } + forceWorkPlane(); + onCommand(COMMAND_UNLOCK_MULTI_AXIS); + gMotionModal.reset(); + 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)) + ); + } + } else { + abc = getWorkPlaneMachineABC(_section.workPlane, _setWorkPlane); + if (_setWorkPlane) { + 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 abc; + } + setRotation(remaining); + } + return abc; +} + +function setWorkPlane(abc) { + if (!machineConfiguration.isMultiAxisConfiguration()) { + return; // ignore + } + + var _skipBlock = false; + if (!((currentWorkPlaneABC == undefined) || + abcFormat.areDifferent(abc.x, currentWorkPlaneABC.x) || + abcFormat.areDifferent(abc.y, currentWorkPlaneABC.y) || + abcFormat.areDifferent(abc.z, currentWorkPlaneABC.z))) { + if (operationNeedsSafeStart) { + _skipBlock = true; + } else { + return; // no change + } + } + skipBlock = _skipBlock; + onCommand(COMMAND_UNLOCK_MULTI_AXIS); + + if (!retracted) { + skipBlock = _skipBlock; + moveToSafeRetractPosition(false); + } + + if (activeG254) { + skipBlock = _skipBlock; + activeG254 = false; + writeBlock(gFormat.format(255)); // cancel DWO + } + + gMotionModal.reset(); + skipBlock = _skipBlock; + 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)) + ); + + skipBlock = _skipBlock; + onCommand(COMMAND_LOCK_MULTI_AXIS); + + if (staticProperties.useDWO && + (abcFormat.isSignificant(abc.x % (Math.PI * 2)) || abcFormat.isSignificant(abc.y % (Math.PI * 2)) || abcFormat.isSignificant(abc.z % (Math.PI * 2)))) { + skipBlock = _skipBlock; + activeG254 = true; + writeBlock(gFormat.format(254)); // enable DWO + } + + setCurrentABC(abc); // required for machine simulation + currentWorkPlaneABC = abc; +} + +var closestABC = true; // choose closest machine angles +var currentMachineABC = new Vector(0, 0, 0); + +function getPreferenceWeight(_abc) { + var axis = new Array(machineConfiguration.getAxisU(), machineConfiguration.getAxisV(), machineConfiguration.getAxisW()); + var abc = new Array(_abc.x, _abc.y, _abc.z); + var preference = 0; + for (var i = 0; i < 3; ++i) { + if (axis[i].isEnabled()) { + preference += ((abcFormat.getResultingValue(abc[axis[i].getCoordinate()]) * axis[i].getPreference()) < 0) ? -1 : 1; + } + } + return preference; +} + +function remapToABC(currentABC, previousABC) { + var both = machineConfiguration.getABCByDirectionBoth(machineConfiguration.getDirection(currentABC)); + var abc1 = machineConfiguration.remapToABC(both[0], previousABC); + abc1 = machineConfiguration.remapABC(abc1); + var abc2 = machineConfiguration.remapToABC(both[1], previousABC); + abc2 = machineConfiguration.remapABC(abc2); + + // choose angles based on preference + var preference1 = getPreferenceWeight(abc1); + var preference2 = getPreferenceWeight(abc2); + if (preference1 > preference2) { + return abc1; + } else if (preference2 > preference1) { + return abc2; + } + + // choose angles based on closest solution + if (Vector.diff(abc1, previousABC).length < Vector.diff(abc2, previousABC).length) { + return abc1; + } else { + return abc2; + } +} + +function getWorkPlaneMachineABC(workPlane, _setWorkPlane) { + var W = workPlane; // map to global frame + + var abc = machineConfiguration.getABC(W); + if (closestABC) { + if (currentMachineABC) { + abc = remapToABC(abc, currentMachineABC); + } else { + abc = machineConfiguration.getPreferredABC(abc); + } + } else { + abc = machineConfiguration.getPreferredABC(abc); + } + + try { + abc = machineConfiguration.remapABC(abc); + if (_setWorkPlane) { + currentMachineABC = abc; + } + } catch (e) { + error( + localize("Machine angles not supported") + ":" + + conditional(machineConfiguration.isMachineCoordinate(0), " A" + abcFormat.format(abc.x)) + + conditional(machineConfiguration.isMachineCoordinate(1), " B" + abcFormat.format(abc.y)) + + conditional(machineConfiguration.isMachineCoordinate(2), " C" + abcFormat.format(abc.z)) + ); + } + + var direction = machineConfiguration.getDirection(abc); + if (!isSameDirection(direction, W.forward)) { + error(localize("Orientation not supported.")); + } + + if (!machineConfiguration.isABCSupported(abc)) { + error( + localize("Work plane is not supported") + ":" + + conditional(machineConfiguration.isMachineCoordinate(0), " A" + abcFormat.format(abc.x)) + + conditional(machineConfiguration.isMachineCoordinate(1), " B" + abcFormat.format(abc.y)) + + conditional(machineConfiguration.isMachineCoordinate(2), " C" + abcFormat.format(abc.z)) + ); + } + + 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 printProbeResults() { + return currentSection.getParameter("printResults", 0) == 1; +} + +function onPassThrough(text) { + var commands = String(text).split(","); + for (text in commands) { + writeBlock(commands[text]); + } +} + +function onManualNC(command, value) { + switch (command) { + case COMMAND_ACTION: + if (String(value).toUpperCase() == "CYCLE_REVERSAL") { + cycleReverse = true; + } else if (String(value).toUpperCase() == "VFD_LOW") { + coolantPressure = "P0"; + } else if (String(value).toUpperCase() == "VFD_NORMAL") { + coolantPressure = "P1"; + } else if (String(value).toUpperCase() == "VFD_HIGH") { + coolantPressure = "P2"; + } else if (String(value).toUpperCase() == "USEPOLARMODE") { + usePolarMode = true; + } + break; + default: + expandManualNC(command, value); + } +} + +var probeOutputWorkOffset = 1; +var stockTopZ = -1; +var stockUpperX; +var stockLowerX; +var stockUpperY; +var stockLowerY; + +function onParameter(name, value) { + if (name == "probe-output-work-offset") { + probeOutputWorkOffset = (value > 0) ? value : 1; + } + + // Added 6/15/21 | Gavin Williams | will1742 + // Issue 001 Input and Validation + if (name == "stock-upper-z") { + stockTopZ = value; + } + if (name == "stock-upper-x") { + stockUpperX = value; + } + if (name == "stock-lower-x") { + stockLowerX = value; + } + if (name == "stock-upper-y") { + stockUpperY = value; + } + if (name == "stock-lower-y") { + stockLowerY = value; + } +} + +var seenPatternIds = {}; + +function previewImage() { + var permittedExtensions = ["JPG", "MP4", "MOV", "PNG", "JPEG"]; + var patternId = currentSection.getPatternId(); + var show = false; + if (!seenPatternIds[patternId]) { + show = true; + seenPatternIds[patternId] = true; + } + var images = []; + if (show) { + if (FileSystem.isFile(FileSystem.getCombinedPath(FileSystem.getFolderPath(getOutputPath()), modelImagePath))) { + images.push(modelImagePath); + } + if (hasParameter("autodeskcam:preview-name") && FileSystem.isFile(FileSystem.getCombinedPath(FileSystem.getFolderPath(getOutputPath()), getParameter("autodeskcam:preview-name")))) { + images.push(getParameter("autodeskcam:preview-name")); + } + + for (var i = 0; i < images.length; ++i) { + var fileExtension = images[i].slice(images[i].lastIndexOf(".") + 1, images[i].length).toUpperCase(); + var permittedExtension = false; + for (var j = 0; j < permittedExtensions.length; ++j) { + if (fileExtension == permittedExtensions[j]) { + permittedExtension = true; + break; // found + } + } + if (!permittedExtension) { + warning(localize("The image file format " + "\"" + fileExtension + "\"" + " is not supported on HAAS controls.")); + } + + if (!staticProperties.useM130PartImages || !permittedExtension) { + FileSystem.remove(FileSystem.getCombinedPath(FileSystem.getFolderPath(getOutputPath()), images[i])); // remove + images.splice([i], 1); // remove from array + } + } + if (images.length > 0) { + writeBlock(mFormat.format(130), "(" + images[images.length - 1] + ")"); + } + } +} + +/** Returns true if the spatial vectors are significantly different. */ +function areSpatialVectorsDifferent(_vector1, _vector2) { + return (xyzFormat.getResultingValue(_vector1.x) != xyzFormat.getResultingValue(_vector2.x)) || + (xyzFormat.getResultingValue(_vector1.y) != xyzFormat.getResultingValue(_vector2.y)) || + (xyzFormat.getResultingValue(_vector1.z) != xyzFormat.getResultingValue(_vector2.z)); +} + +/** Returns true if the spatial boxes are a pure translation. */ +function areSpatialBoxesTranslated(_box1, _box2) { + return !areSpatialVectorsDifferent(Vector.diff(_box1[1], _box1[0]), Vector.diff(_box2[1], _box2[0])) && + !areSpatialVectorsDifferent(Vector.diff(_box2[0], _box1[0]), Vector.diff(_box2[1], _box1[1])); +} + +/** Returns true if the spatial boxes are same. */ +function areSpatialBoxesSame(_box1, _box2) { + return !areSpatialVectorsDifferent(_box1[0], _box2[0]) && !areSpatialVectorsDifferent(_box1[1], _box2[1]); +} + +function subprogramDefine(_initialPosition, _abc, _retracted, _zIsOutput) { + // convert patterns into subprograms + var usePattern = false; + patternIsActive = false; + if (currentSection.isPatterned && currentSection.isPatterned() && (getProperty("useSubroutines") == "patterns")) { + currentPattern = currentSection.getPatternId(); + firstPattern = true; + for (var i = 0; i < definedPatterns.length; ++i) { + if ((definedPatterns[i].patternType == SUB_PATTERN) && (currentPattern == definedPatterns[i].patternId)) { + currentSubprogram = definedPatterns[i].subProgram; + usePattern = definedPatterns[i].validPattern; + firstPattern = false; + break; + } + } + + if (firstPattern) { + // determine if this is a valid pattern for creating a subprogram + usePattern = subprogramIsValid(currentSection, currentPattern, SUB_PATTERN); + if (usePattern) { + currentSubprogram = ++lastSubprogram; + } + definedPatterns.push({ + patternType: SUB_PATTERN, + patternId: currentPattern, + subProgram: currentSubprogram, + validPattern: usePattern, + initialPosition: _initialPosition, + finalPosition: _initialPosition + }); + } + + if (usePattern) { + // make sure Z-position is output prior to subprogram call + if (!_retracted && !_zIsOutput) { + writeBlock(gMotionModal.format(0), zOutput.format(_initialPosition.z)); + } + + // call subprogram + writeBlock(mFormat.format(97), "P" + nFormat.format(currentSubprogram)); + patternIsActive = true; + + if (firstPattern) { + subprogramStart(_initialPosition, _abc, incrementalSubprogram); + } else { + skipRemainingSection(); + setCurrentPosition(getFramePosition(currentSection.getFinalPosition())); + } + } + } + + // Output cycle operation as subprogram + if (!usePattern && (getProperty("useSubroutines") == "cycles") && currentSection.doesStrictCycle && + (currentSection.getNumberOfCycles() == 1) && currentSection.getNumberOfCyclePoints() >= minimumCyclePoints) { + var finalPosition = getFramePosition(currentSection.getFinalPosition()); + currentPattern = currentSection.getNumberOfCyclePoints(); + firstPattern = true; + for (var i = 0; i < definedPatterns.length; ++i) { + if ((definedPatterns[i].patternType == SUB_CYCLE) && (currentPattern == definedPatterns[i].patternId) && + !areSpatialVectorsDifferent(_initialPosition, definedPatterns[i].initialPosition) && + !areSpatialVectorsDifferent(finalPosition, definedPatterns[i].finalPosition)) { + currentSubprogram = definedPatterns[i].subProgram; + usePattern = definedPatterns[i].validPattern; + firstPattern = false; + break; + } + } + + if (firstPattern) { + // determine if this is a valid pattern for creating a subprogram + usePattern = subprogramIsValid(currentSection, currentPattern, SUB_CYCLE); + if (usePattern) { + currentSubprogram = ++lastSubprogram; + } + definedPatterns.push({ + patternType: SUB_CYCLE, + patternId: currentPattern, + subProgram: currentSubprogram, + validPattern: usePattern, + initialPosition: _initialPosition, + finalPosition: finalPosition + }); + } + cycleSubprogramIsActive = usePattern; + } + + // Output each operation as a subprogram + if (!usePattern && (getProperty("useSubroutines") == "allOperations")) { + currentSubprogram = ++lastSubprogram; + writeBlock(mFormat.format(97), "P" + nFormat.format(currentSubprogram)); + firstPattern = true; + subprogramStart(_initialPosition, _abc, false); + } +} + +function subprogramStart(_initialPosition, _abc, _incremental) { + redirectToBuffer(); + var comment = ""; + if (hasParameter("operation-comment")) { + comment = getParameter("operation-comment"); + } + writeln( + "N" + nFormat.format(currentSubprogram) + + conditional(comment, formatComment(comment.substr(0, maximumLineLength - 2 - 6 - 1))) + ); + staticProperties.showSequenceNumbers = false; + if (_incremental) { + setIncrementalMode(_initialPosition, _abc); + } + gPlaneModal.reset(); + gMotionModal.reset(); +} + +function subprogramEnd() { + if (firstPattern) { + writeBlock(mFormat.format(99)); + writeln(""); + subprograms += getRedirectionBuffer(); + } + forceAny(); + firstPattern = false; + staticProperties.showSequenceNumbers = saveShowSequenceNumbers; + closeRedirection(); +} + +function subprogramIsValid(_section, _patternId, _patternType) { + var sectionId = _section.getId(); + var numberOfSections = getNumberOfSections(); + var validSubprogram = _patternType != SUB_CYCLE; + + var masterPosition = new Array(); + masterPosition[0] = getFramePosition(_section.getInitialPosition()); + masterPosition[1] = getFramePosition(_section.getFinalPosition()); + var tempBox = _section.getBoundingBox(); + var masterBox = new Array(); + masterBox[0] = getFramePosition(tempBox[0]); + masterBox[1] = getFramePosition(tempBox[1]); + + var rotation = getRotation(); + var translation = getTranslation(); + incrementalSubprogram = undefined; + + for (var i = 0; i < numberOfSections; ++i) { + var section = getSection(i); + if (section.getId() != sectionId) { + defineWorkPlane(section, false); + // check for valid pattern + if (_patternType == SUB_PATTERN) { + if (section.getPatternId() == _patternId) { + var patternPosition = new Array(); + patternPosition[0] = getFramePosition(section.getInitialPosition()); + patternPosition[1] = getFramePosition(section.getFinalPosition()); + tempBox = section.getBoundingBox(); + var patternBox = new Array(); + patternBox[0] = getFramePosition(tempBox[0]); + patternBox[1] = getFramePosition(tempBox[1]); + + if (areSpatialBoxesSame(masterPosition, patternPosition) && areSpatialBoxesSame(masterBox, patternBox) && !section.isMultiAxis()) { + incrementalSubprogram = incrementalSubprogram ? incrementalSubprogram : false; + } else if (!areSpatialBoxesTranslated(masterPosition, patternPosition) || !areSpatialBoxesTranslated(masterBox, patternBox)) { + validSubprogram = false; + break; + } else { + incrementalSubprogram = true; + } + } + + // check for valid cycle operation + } else if (_patternType == SUB_CYCLE) { + if ((section.getNumberOfCyclePoints() == _patternId) && (section.getNumberOfCycles() == 1)) { + var patternInitial = getFramePosition(section.getInitialPosition()); + var patternFinal = getFramePosition(section.getFinalPosition()); + if (!areSpatialVectorsDifferent(patternInitial, masterPosition[0]) && !areSpatialVectorsDifferent(patternFinal, masterPosition[1])) { + validSubprogram = true; + break; + } + } + } + } + } + setRotation(rotation); + setTranslation(translation); + return (validSubprogram); +} + +function setAxisMode(_format, _output, _prefix, _value, _incr) { + var i = _output.isEnabled(); + if (_output == zOutput) { + _output = _incr ? createIncrementalVariable({onchange: function() {retracted = false;}, prefix: _prefix}, _format) : createVariable({onchange: function() {retracted = false;}, prefix: _prefix}, _format); + } else { + _output = _incr ? createIncrementalVariable({prefix: _prefix}, _format) : createVariable({prefix: _prefix}, _format); + } + _output.format(_value); + _output.format(_value); + i = i ? _output.enable() : _output.disable(); + return _output; +} + +function setIncrementalMode(xyz, abc) { + xOutput = setAxisMode(xyzFormat, xOutput, "X", xyz.x, true); + yOutput = setAxisMode(xyzFormat, yOutput, "Y", xyz.y, true); + zOutput = setAxisMode(xyzFormat, zOutput, "Z", xyz.z, true); + aOutput = setAxisMode(abcFormat, aOutput, "A", abc.x, true); + bOutput = setAxisMode(abcFormat, bOutput, "B", abc.y, true); + cOutput = setAxisMode(abcFormat, cOutput, "C", abc.z, true); + gAbsIncModal.reset(); + writeBlock(gAbsIncModal.format(91)); + incrementalMode = true; +} + +function setAbsoluteMode(xyz, abc) { + if (incrementalMode) { + xOutput = setAxisMode(xyzFormat, xOutput, "X", xyz.x, false); + yOutput = setAxisMode(xyzFormat, yOutput, "Y", xyz.y, false); + zOutput = setAxisMode(xyzFormat, zOutput, "Z", xyz.z, false); + aOutput = setAxisMode(abcFormat, aOutput, "A", abc.x, false); + bOutput = setAxisMode(abcFormat, bOutput, "B", abc.y, false); + cOutput = setAxisMode(abcFormat, cOutput, "C", abc.z, false); + gAbsIncModal.reset(); + writeBlock(gAbsIncModal.format(90)); + incrementalMode = false; + } +} + +function onSection() { + +} + +// Added 6/14/21 | Gavin Williams | will1742 +// Issue 001 Input and Validation +// Displays a file: MP4, MOV, PNG, JPEG. 1920x1080 +// Input: Absolute path to file +function displayMedia(file) { + writeBlock(mFormat.format(130), formatComment("Net Share/Media/" + file)); +} + +// Added 6/14/21 | Gavin Williams | will1742 +// Issue 001 Input and Validation +// Takes input from the user +// Input: string prompt, will be displayed to users +// char array options, capital letters accepted as input +// int opSeqNum, optional arg to init prompt at specific value +// Output: 2D dict {Letter, Coorresponding GOTO} +// EX: [Y, 56][N, 57] +var macroNumber = 500; +function takeInput(prompt, options) { + + // Cycle through macro variables, reset at end of general purpose vars + if (macroNumber > 549) macroNumber = 500; + + // init macro var to 0 + setMacro(macroNumber, 0, "Initialize macro variable"); + + // disply prompt and save response + writeBlock(mFormat.format(109), "P" + nFormat.format(macroNumber), formatComment(prompt)); + sequenceNumber -= staticProperties.sequenceNumberIncrement; + var gotoRef = sequenceNumber; + + // wait for input + writeln("IF[#" + macroNumber + " EQ 0.] GOTO" + nFormat.format(gotoRef) + " " + formatComment("NULL")); + + // print if's and goto's + var gotoMap = {}; + var gotoInc = 1; + options.forEach(function (element) { + writeWords("IF[#" + macroNumber + " EQ " + element.charCodeAt(0) + ".] GOTO" + nFormat.format(sequenceNumber + gotoInc), formatComment(element)); + gotoMap[element] = (sequenceNumber + gotoInc); + gotoInc += 1; + }); + + var incNum = staticProperties.sequenceNumberIncrement; + // adjust sequence number if needed + for (i = incNum; i < gotoInc; i+=incNum) { + sequenceNumber += staticProperties.sequenceNumberIncrement; + } + + // return to input until valid option is entered + writeWords("GOTO" + nFormat.format(gotoRef), formatComment("INVALID INPUT")); + + // increase var number, iterate sequence number + macroNumber += 1; + sequenceNumber += staticProperties.sequenceNumberIncrement; + return gotoMap; +} + +function onDwell(seconds) { + if (seconds > 99999.999) { + warning(localize("Dwelling time is out of range.")); + } + seconds = clamp(0.001, seconds, 99999.999); + writeBlock(gFeedModeModal.format(94), gFormat.format(4), "P" + milliFormat.format(seconds * 1000)); +} + +function onSpindleSpeed(spindleSpeed) { + writeBlock(sOutput.format(spindleSpeed)); +} + +function onCycle() { + writeBlock(gPlaneModal.format(17)); +} + +function getCommonCycle(x, y, z, r, c) { + forceXYZ(); + if (usePolarMode) { + var polarPosition = getPolarPosition(x, y, z); + return [xOutput.format(polarPosition.first.x), yOutput.format(polarPosition.first.y), + zOutput.format(polarPosition.first.z), + aOutput.format(polarPosition.second.x), + bOutput.format(polarPosition.second.y), + cOutput.format(polarPosition.second.z), + "R" + xyzFormat.format(r)]; + } else { + if (incrementalMode) { + zOutput.format(c); + return [xOutput.format(x), yOutput.format(y), + "Z" + xyzFormat.format(z - r), + "R" + xyzFormat.format(r - c)]; + } else { + return [xOutput.format(x), yOutput.format(y), + zOutput.format(z), + "R" + xyzFormat.format(r)]; + } + } +} + +function setCyclePosition(_position) { + switch (gPlaneModal.getCurrent()) { + case 17: // XY + zOutput.format(_position); + break; + case 18: // ZX + yOutput.format(_position); + break; + case 19: // YZ + xOutput.format(_position); + break; + } +} + +/** Convert approach to sign. */ +function approach(value) { + validate((value == "positive") || (value == "negative"), "Invalid approach."); + return (value == "positive") ? 1 : -1; +} + +function setProbeAngleMethod() { + probeVariables.probeAngleMethod = (machineConfiguration.getNumberOfAxes() < 5 || is3D()) ? (getProperty("useG54x4") ? "G54.4" : "G68") : "UNSUPPORTED"; + var axes = [machineConfiguration.getAxisU(), machineConfiguration.getAxisV(), machineConfiguration.getAxisW()]; + for (var i = 0; i < axes.length; ++i) { + if (axes[i].isEnabled() && isSameDirection((axes[i].getAxis()).getAbsolute(), new Vector(0, 0, 1)) && axes[i].isTable()) { + probeVariables.probeAngleMethod = "AXIS_ROT"; + probeVariables.rotationalAxis = axes[i].getCoordinate(); + break; + } + } + probeVariables.outputRotationCodes = true; +} + +/** Output rotation offset based on angular probing cycle. */ +function setProbeAngle() { + if (probeVariables.outputRotationCodes) { + validate(probeOutputWorkOffset <= 6, "Angular Probing only supports work offsets 1-6."); + if (probeVariables.probeAngleMethod == "G68" && (Vector.diff(currentSection.getGlobalInitialToolAxis(), new Vector(0, 0, 1)).length > 1e-4)) { + error(localize("You cannot use multi axis toolpaths while G68 Rotation is in effect.")); + } + var validateWorkOffset = false; + switch (probeVariables.probeAngleMethod) { + case "G54.4": + var param = 26000 + (probeOutputWorkOffset * 10); + writeBlock("#" + param + "=#135"); + writeBlock("#" + (param + 1) + "=#136"); + writeBlock("#" + (param + 5) + "=#144"); + writeBlock(gFormat.format(54.4), "P" + probeOutputWorkOffset); + break; + case "G68": + gRotationModal.reset(); + gAbsIncModal.reset(); + writeBlock(gRotationModal.format(68), gAbsIncModal.format(90), probeVariables.compensationXY, "R[#194]"); + validateWorkOffset = true; + break; + case "AXIS_ROT": + var param = 5200 + probeOutputWorkOffset * 20 + probeVariables.rotationalAxis + 4; + writeBlock("#" + param + " = " + "[#" + param + " + #194]"); + forceWorkPlane(); // force workplane to rotate ABC in order to apply rotation offsets + currentWorkOffset = undefined; // force WCS output to make use of updated parameters + validateWorkOffset = true; + break; + default: + error(localize("Angular Probing is not supported for this machine configuration.")); + return; + } + if (validateWorkOffset) { + for (var i = currentSection.getId(); i < getNumberOfSections(); ++i) { + if (getSection(i).workOffset != currentSection.workOffset) { + error(localize("WCS offset cannot change while using angle rotation compensation.")); + return; + } + } + } + probeVariables.outputRotationCodes = false; + } +} + +function protectedProbeMove(_cycle, x, y, z) { + var _x = xOutput.format(x); + var _y = yOutput.format(y); + var _z = zOutput.format(z); + if (_z && z >= getCurrentPosition().z) { + writeBlock(gFormat.format(65), "P" + 9810, _z, getFeed(cycle.feedrate)); // protected positioning move + } + if (_x || _y) { + writeBlock(gFormat.format(65), "P" + 9810, _x, _y, getFeed(highFeedrate)); // protected positioning move + } + if (_z && z < getCurrentPosition().z) { + writeBlock(gFormat.format(65), "P" + 9810, _z, getFeed(cycle.feedrate)); // protected positioning move + } +} + +function cancelG68Rotation(force) { + if (force) { + gRotationModal.reset(); + } + writeBlock(gRotationModal.format(69)); +} + +function onCyclePoint(x, y, z) { + if (isInspectionOperation() && (typeof inspectionCycleInspect == "function")) { + inspectionCycleInspect(cycle, x, y, z); + return; + } + if (!isSameDirection(getRotation().forward, new Vector(0, 0, 1))) { + expandCyclePoint(x, y, z); + return; + } + if (isProbeOperation()) { + if (!isSameDirection(currentSection.workPlane.forward, new Vector(0, 0, 1))) { + if (!allowIndexingWCSProbing && currentSection.strategy == "probe") { + error(localize("Updating WCS / work offset using probing is only supported by the CNC in the WCS frame.")); + return; + } else if (staticProperties.useDWO) { + error(localize("Your machine does not support the selected probing operation with DWO enabled.")); + return; + } + } + if (printProbeResults()) { + writeProbingToolpathInformation(z - cycle.depth + tool.diameter / 2); + inspectionWriteCADTransform(); + inspectionWriteWorkplaneTransform(); + if (typeof inspectionWriteVariables == "function") { + inspectionVariables.pointNumber += 1; + } + } + protectedProbeMove(cycle, x, y, z); + } + + var forceCycle = false; + switch (cycleType) { + case "tapping-with-chip-breaking": + case "left-tapping-with-chip-breaking": + case "right-tapping-with-chip-breaking": + forceCycle = true; + if (!isFirstCyclePoint()) { + writeBlock(gCycleModal.format(80)); + gMotionModal.reset(); + } + } + if (forceCycle || isFirstCyclePoint() || isProbeOperation()) { + if (!isProbeOperation()) { + // return to initial Z which is clearance plane and set absolute mode + repositionToCycleClearance(cycle, x, y, z); + } + + var F = cycle.feedrate; + var P = !cycle.dwell ? 0 : clamp(1, cycle.dwell * 1000, 99999999); // in milliseconds + + switch (cycleType) { + case "drilling": + writeBlock( + gRetractModal.format(98), gCycleModal.format(81), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + conditional(cycleReverse, "E2000"), feedOutput.format(F) + ); + break; + case "counter-boring": + if (P > 0) { + writeBlock( + gRetractModal.format(98), gCycleModal.format(82), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), // not optional + conditional(cycleReverse, "E2000"), feedOutput.format(F) + ); + } else { + writeBlock( + gRetractModal.format(98), gCycleModal.format(81), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + conditional(cycleReverse, "E2000"), feedOutput.format(F) + ); + } + break; + case "chip-breaking": + if ((cycle.accumulatedDepth < cycle.depth) && (cycle.incrementalDepthReduction > 0)) { + expandCyclePoint(x, y, z); + } else if (cycle.accumulatedDepth < cycle.depth) { + writeBlock( + gRetractModal.format(98), gCycleModal.format(73), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + ("Q" + xyzFormat.format(cycle.incrementalDepth)), + ("K" + xyzFormat.format(cycle.accumulatedDepth)), + conditional(P > 0, "P" + milliFormat.format(P)), // optional + conditional(cycleReverse, "E2000"), feedOutput.format(F) + ); + } else { + writeBlock( + gRetractModal.format(98), gCycleModal.format(73), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + (((cycle.incrementalDepthReduction > 0) ? "I" : "Q") + xyzFormat.format(cycle.incrementalDepth)), + conditional(cycle.incrementalDepthReduction > 0, "J" + xyzFormat.format(cycle.incrementalDepthReduction)), + conditional(cycle.incrementalDepthReduction > 0, "K" + xyzFormat.format(cycle.minimumIncrementalDepth)), + conditional(P > 0, "P" + milliFormat.format(P)), // optional + conditional(cycleReverse, "E2000"), feedOutput.format(F) + ); + } + break; + case "deep-drilling": + writeBlock( + gRetractModal.format(98), gCycleModal.format(83), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + (((cycle.incrementalDepthReduction > 0) ? "I" : "Q") + xyzFormat.format(cycle.incrementalDepth)), + conditional(cycle.incrementalDepthReduction > 0, "J" + xyzFormat.format(cycle.incrementalDepthReduction)), + conditional(cycle.incrementalDepthReduction > 0, "K" + xyzFormat.format(cycle.minimumIncrementalDepth)), + conditional(P > 0, "P" + milliFormat.format(P)), // optional + conditional(cycleReverse, "E2000"), feedOutput.format(F) + ); + break; + case "tapping": + var tappingFPM = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); + F = (staticProperties.useG95forTapping ? tool.getThreadPitch() : tappingFPM); + if (staticProperties.useG95forTapping) { + writeBlock(gFeedModeModal.format(95)); + } + writeBlock( + gRetractModal.format(98), gCycleModal.format((tool.type == TOOL_TAP_LEFT_HAND) ? 74 : 84), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + conditional(cycleReverse, "E2000"), pitchOutput.format(F) + ); + forceFeed(); + break; + case "left-tapping": + var tappingFPM = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); + F = (staticProperties.useG95forTapping ? tool.getThreadPitch() : tappingFPM); + if (staticProperties.useG95forTapping) { + writeBlock(gFeedModeModal.format(95)); + } + writeBlock( + gRetractModal.format(98), gCycleModal.format(74), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + conditional(cycleReverse, "E2000"), pitchOutput.format(F) + ); + forceFeed(); + break; + case "right-tapping": + var tappingFPM = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); + F = (staticProperties.useG95forTapping ? tool.getThreadPitch() : tappingFPM); + if (staticProperties.useG95forTapping) { + writeBlock(gFeedModeModal.format(95)); + } + writeBlock( + gRetractModal.format(98), gCycleModal.format(84), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + conditional(cycleReverse, "E2000"), pitchOutput.format(F) + ); + forceFeed(); + break; + case "tapping-with-chip-breaking": + case "left-tapping-with-chip-breaking": + case "right-tapping-with-chip-breaking": + var tappingFPM = tool.getThreadPitch() * rpmFormat.getResultingValue(spindleSpeed); + F = (staticProperties.useG95forTapping ? tool.getThreadPitch() : tappingFPM); + if (staticProperties.useG95forTapping) { + writeBlock(gFeedModeModal.format(95)); + } + // Parameter 57 bit 6, REPT RIG TAP, is set to 1 (On) + // On Mill software versions12.09 and above, REPT RIG TAP has been moved from the Parameters to Setting 133 + 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; + writeBlock( + gRetractModal.format(99), 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), + conditional(cycleReverse, "E2000"), pitchOutput.format(F) + ); + } else { + var position; + var depth; + switch (gPlaneModal.getCurrent()) { + case 17: + xOutput.reset(); + position = xOutput.format(x); + depth = "Z" + xyzFormat.format(u); + break; + case 18: + zOutput.reset(); + position = zOutput.format(z); + depth = "Y" + xyzFormat.format(u); + break; + case 19: + yOutput.reset(); + position = yOutput.format(y); + depth = "X" + xyzFormat.format(u); + break; + } + writeBlock(conditional(u <= cycle.bottom, gRetractModal.format(98)), position, depth); + } + } + forceFeed(); + break; + case "fine-boring": + writeBlock( + gRetractModal.format(98), gCycleModal.format(76), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), // not optional + "Q" + xyzFormat.format(cycle.shift), + conditional(cycleReverse, "E2000"), feedOutput.format(F) + ); + forceSpindleSpeed = true; + break; + case "back-boring": + if (P > 0) { + expandCyclePoint(x, y, z); + } else { + var dx = (gPlaneModal.getCurrent() == 19) ? cycle.backBoreDistance : 0; + var dy = (gPlaneModal.getCurrent() == 18) ? cycle.backBoreDistance : 0; + var dz = (gPlaneModal.getCurrent() == 17) ? cycle.backBoreDistance : 0; + writeBlock( + gRetractModal.format(98), gCycleModal.format(77), + getCommonCycle(x - dx, y - dy, z - dz, cycle.bottom, cycle.clearance), + "Q" + xyzFormat.format(cycle.shift), + conditional(cycleReverse, "E2000"), feedOutput.format(F) + ); + forceSpindleSpeed = true; + } + break; + case "reaming": + writeBlock( + gRetractModal.format(98), gCycleModal.format(85), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + conditional(cycleReverse, "E2000"), feedOutput.format(F) + ); + break; + case "stop-boring": + if (P > 0) { + expandCyclePoint(x, y, z); + } else { + writeBlock( + gRetractModal.format(98), gCycleModal.format(86), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + conditional(cycleReverse, "E2000"), feedOutput.format(F) + ); + forceSpindleSpeed = true; + } + break; + case "manual-boring": + writeBlock( + gRetractModal.format(98), gCycleModal.format(88), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), // not optional + conditional(cycleReverse, "E2000"), feedOutput.format(F) + ); + break; + case "boring": + writeBlock( + gRetractModal.format(98), gCycleModal.format(89), + getCommonCycle(x, y, z, cycle.retract, cycle.clearance), + "P" + milliFormat.format(P), // not optional + conditional(cycleReverse, "E2000"), feedOutput.format(F) + ); + break; + + case "probing-x": + protectedProbeMove(cycle, x, y, z - cycle.depth); + writeBlock( + gFormat.format(65), "P" + 9811, + "X" + xyzFormat.format(x + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)), + "Q" + xyzFormat.format(cycle.probeOvertravel), + getProbingArguments(cycle, true) + ); + break; + case "probing-y": + protectedProbeMove(cycle, x, y, z - cycle.depth); + writeBlock( + gFormat.format(65), "P" + 9811, + "Y" + xyzFormat.format(y + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)), + "Q" + xyzFormat.format(cycle.probeOvertravel), + getProbingArguments(cycle, true) + ); + break; + case "probing-z": + protectedProbeMove(cycle, x, y, Math.min(z - cycle.depth + cycle.probeClearance, cycle.retract)); + writeBlock( + gFormat.format(65), "P" + 9811, + "Z" + xyzFormat.format(z - cycle.depth), + "Q" + xyzFormat.format(cycle.probeOvertravel), + getProbingArguments(cycle, true) + ); + break; + case "probing-x-wall": + protectedProbeMove(cycle, x, y, z); + writeBlock( + gFormat.format(65), "P" + 9812, + "X" + xyzFormat.format(cycle.width1), + zOutput.format(z - cycle.depth), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(cycle.probeClearance), + getProbingArguments(cycle, true) + ); + break; + case "probing-y-wall": + protectedProbeMove(cycle, x, y, z); + writeBlock( + gFormat.format(65), "P" + 9812, + "Y" + xyzFormat.format(cycle.width1), + zOutput.format(z - cycle.depth), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(cycle.probeClearance), + getProbingArguments(cycle, true) + ); + break; + case "probing-x-channel": + protectedProbeMove(cycle, x, y, z - cycle.depth); + writeBlock( + gFormat.format(65), "P" + 9812, + "X" + xyzFormat.format(cycle.width1), + "Q" + xyzFormat.format(cycle.probeOvertravel), + // not required "R" + xyzFormat.format(cycle.probeClearance), + getProbingArguments(cycle, true) + ); + break; + case "probing-x-channel-with-island": + protectedProbeMove(cycle, x, y, z); + writeBlock( + gFormat.format(65), "P" + 9812, + "X" + xyzFormat.format(cycle.width1), + zOutput.format(z - cycle.depth), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(-cycle.probeClearance), + getProbingArguments(cycle, true) + ); + break; + case "probing-y-channel": + protectedProbeMove(cycle, x, y, z - cycle.depth); + writeBlock( + gFormat.format(65), "P" + 9812, + "Y" + xyzFormat.format(cycle.width1), + "Q" + xyzFormat.format(cycle.probeOvertravel), + // not required "R" + xyzFormat.format(cycle.probeClearance), + getProbingArguments(cycle, true) + ); + break; + case "probing-y-channel-with-island": + protectedProbeMove(cycle, x, y, z); + writeBlock( + gFormat.format(65), "P" + 9812, + "Y" + xyzFormat.format(cycle.width1), + zOutput.format(z - cycle.depth), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(-cycle.probeClearance), + getProbingArguments(cycle, true) + ); + break; + case "probing-xy-circular-boss": + protectedProbeMove(cycle, x, y, z); + writeBlock( + gFormat.format(65), "P" + 9814, + "D" + xyzFormat.format(cycle.width1), + "Z" + xyzFormat.format(z - cycle.depth), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(cycle.probeClearance), + getProbingArguments(cycle, true) + ); + break; + case "probing-xy-circular-partial-boss": + protectedProbeMove(cycle, x, y, z); + writeBlock( + gFormat.format(65), "P" + 9823, + "A" + xyzFormat.format(cycle.partialCircleAngleA), + "B" + xyzFormat.format(cycle.partialCircleAngleB), + "C" + xyzFormat.format(cycle.partialCircleAngleC), + "D" + xyzFormat.format(cycle.width1), + "Z" + xyzFormat.format(z - cycle.depth), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(cycle.probeClearance), + getProbingArguments(cycle, true) + ); + break; + case "probing-xy-circular-hole": + protectedProbeMove(cycle, x, y, z - cycle.depth); + writeBlock( + gFormat.format(65), "P" + 9814, + "D" + xyzFormat.format(cycle.width1), + "Q" + xyzFormat.format(cycle.probeOvertravel), + // not required "R" + xyzFormat.format(cycle.probeClearance), + getProbingArguments(cycle, true) + ); + break; + case "probing-xy-circular-partial-hole": + protectedProbeMove(cycle, x, y, z - cycle.depth); + writeBlock( + gFormat.format(65), "P" + 9823, + "A" + xyzFormat.format(cycle.partialCircleAngleA), + "B" + xyzFormat.format(cycle.partialCircleAngleB), + "C" + xyzFormat.format(cycle.partialCircleAngleC), + "D" + xyzFormat.format(cycle.width1), + "Q" + xyzFormat.format(cycle.probeOvertravel), + getProbingArguments(cycle, true) + ); + break; + case "probing-xy-circular-hole-with-island": + protectedProbeMove(cycle, x, y, z); + writeBlock( + gFormat.format(65), "P" + 9814, + "Z" + xyzFormat.format(z - cycle.depth), + "D" + xyzFormat.format(cycle.width1), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(-cycle.probeClearance), + getProbingArguments(cycle, true) + ); + break; + case "probing-xy-circular-partial-hole-with-island": + protectedProbeMove(cycle, x, y, z); + writeBlock( + gFormat.format(65), "P" + 9823, + "Z" + xyzFormat.format(z - cycle.depth), + "A" + xyzFormat.format(cycle.partialCircleAngleA), + "B" + xyzFormat.format(cycle.partialCircleAngleB), + "C" + xyzFormat.format(cycle.partialCircleAngleC), + "D" + xyzFormat.format(cycle.width1), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(-cycle.probeClearance), + getProbingArguments(cycle, true) + ); + break; + case "probing-xy-rectangular-hole": + protectedProbeMove(cycle, x, y, z - cycle.depth); + writeBlock( + gFormat.format(65), "P" + 9812, + "X" + xyzFormat.format(cycle.width1), + "Q" + xyzFormat.format(cycle.probeOvertravel), + // not required "R" + xyzFormat.format(-cycle.probeClearance), + getProbingArguments(cycle, true) + ); + writeBlock( + gFormat.format(65), "P" + 9812, + "Y" + xyzFormat.format(cycle.width2), + "Q" + xyzFormat.format(cycle.probeOvertravel), + // not required "R" + xyzFormat.format(-cycle.probeClearance), + getProbingArguments(cycle, true) + ); + break; + case "probing-xy-rectangular-boss": + protectedProbeMove(cycle, x, y, z); + writeBlock( + gFormat.format(65), "P" + 9812, + "Z" + xyzFormat.format(z - cycle.depth), + "X" + xyzFormat.format(cycle.width1), + "R" + xyzFormat.format(cycle.probeClearance), + "Q" + xyzFormat.format(cycle.probeOvertravel), + getProbingArguments(cycle, true) + ); + writeBlock( + gFormat.format(65), "P" + 9812, + "Z" + xyzFormat.format(z - cycle.depth), + "Y" + xyzFormat.format(cycle.width2), + "R" + xyzFormat.format(cycle.probeClearance), + "Q" + xyzFormat.format(cycle.probeOvertravel), + getProbingArguments(cycle, true) + ); + break; + case "probing-xy-rectangular-hole-with-island": + protectedProbeMove(cycle, x, y, z); + writeBlock( + gFormat.format(65), "P" + 9812, + "Z" + xyzFormat.format(z - cycle.depth), + "X" + xyzFormat.format(cycle.width1), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(-cycle.probeClearance), + getProbingArguments(cycle, true) + ); + writeBlock( + gFormat.format(65), "P" + 9812, + "Z" + xyzFormat.format(z - cycle.depth), + "Y" + xyzFormat.format(cycle.width2), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(-cycle.probeClearance), + getProbingArguments(cycle, true) + ); + break; + case "probing-xy-inner-corner": + var cornerX = x + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2); + var cornerY = y + approach(cycle.approach2) * (cycle.probeClearance + tool.diameter / 2); + var cornerI = 0; + var cornerJ = 0; + if (cycle.probeSpacing !== undefined) { + cornerI = cycle.probeSpacing; + cornerJ = cycle.probeSpacing; + } + if ((cornerI != 0) && (cornerJ != 0)) { + if (currentSection.strategy == "probe") { + setProbeAngleMethod(); + probeVariables.compensationXY = "X[#185] Y[#186]"; + } + } + protectedProbeMove(cycle, x, y, z - cycle.depth); + writeBlock( + gFormat.format(65), "P" + 9815, xOutput.format(cornerX), yOutput.format(cornerY), + conditional(cornerI != 0, "I" + xyzFormat.format(cornerI)), + conditional(cornerJ != 0, "J" + xyzFormat.format(cornerJ)), + "Q" + xyzFormat.format(cycle.probeOvertravel), + getProbingArguments(cycle, true) + ); + break; + case "probing-xy-outer-corner": + var cornerX = x + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2); + var cornerY = y + approach(cycle.approach2) * (cycle.probeClearance + tool.diameter / 2); + var cornerI = 0; + var cornerJ = 0; + if (cycle.probeSpacing !== undefined) { + cornerI = cycle.probeSpacing; + cornerJ = cycle.probeSpacing; + } + if ((cornerI != 0) && (cornerJ != 0)) { + if (currentSection.strategy == "probe") { + setProbeAngleMethod(); + probeVariables.compensationXY = "X[#185] Y[#186]"; + } + } + protectedProbeMove(cycle, x, y, z - cycle.depth); + writeBlock( + gFormat.format(65), "P" + 9816, xOutput.format(cornerX), yOutput.format(cornerY), + conditional(cornerI != 0, "I" + xyzFormat.format(cornerI)), + conditional(cornerJ != 0, "J" + xyzFormat.format(cornerJ)), + "Q" + xyzFormat.format(cycle.probeOvertravel), + getProbingArguments(cycle, true) + ); + break; + case "probing-x-plane-angle": + protectedProbeMove(cycle, x, y, z - cycle.depth); + writeBlock( + gFormat.format(65), "P" + 9843, + "X" + xyzFormat.format(x + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)), + "D" + xyzFormat.format(cycle.probeSpacing), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "A" + xyzFormat.format(cycle.nominalAngle != undefined ? cycle.nominalAngle : 90), + getProbingArguments(cycle, false) + ); + if (currentSection.strategy == "probe") { + setProbeAngleMethod(); + probeVariables.compensationXY = "X" + xyzFormat.format(0) + " Y" + xyzFormat.format(0); + } + break; + case "probing-y-plane-angle": + protectedProbeMove(cycle, x, y, z - cycle.depth); + writeBlock( + gFormat.format(65), "P" + 9843, + "Y" + xyzFormat.format(y + approach(cycle.approach1) * (cycle.probeClearance + tool.diameter / 2)), + "D" + xyzFormat.format(cycle.probeSpacing), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "A" + xyzFormat.format(cycle.nominalAngle != undefined ? cycle.nominalAngle : 0), + getProbingArguments(cycle, false) + ); + if (currentSection.strategy == "probe") { + setProbeAngleMethod(); + probeVariables.compensationXY = "X" + xyzFormat.format(0) + " Y" + xyzFormat.format(0); + } + break; + case "probing-xy-pcd-hole": + protectedProbeMove(cycle, x, y, z); + writeBlock( + gFormat.format(65), "P" + 9819, + "A" + xyzFormat.format(cycle.pcdStartingAngle), + "B" + xyzFormat.format(cycle.numberOfSubfeatures), + "C" + xyzFormat.format(cycle.widthPCD), + "D" + xyzFormat.format(cycle.widthFeature), + "K" + xyzFormat.format(z - cycle.depth), + "Q" + xyzFormat.format(cycle.probeOvertravel), + getProbingArguments(cycle, false) + ); + if (cycle.updateToolWear) { + error(localize("Action -Update Tool Wear- is not supported with this cycle")); + return; + } + break; + case "probing-xy-pcd-boss": + protectedProbeMove(cycle, x, y, z); + writeBlock( + gFormat.format(65), "P" + 9819, + "A" + xyzFormat.format(cycle.pcdStartingAngle), + "B" + xyzFormat.format(cycle.numberOfSubfeatures), + "C" + xyzFormat.format(cycle.widthPCD), + "D" + xyzFormat.format(cycle.widthFeature), + "Z" + xyzFormat.format(z - cycle.depth), + "Q" + xyzFormat.format(cycle.probeOvertravel), + "R" + xyzFormat.format(cycle.probeClearance), + getProbingArguments(cycle, false) + ); + if (cycle.updateToolWear) { + error(localize("Action -Update Tool Wear- is not supported with this cycle")); + return; + } + break; + default: + expandCyclePoint(x, y, z); + } + + // place cycle operation in subprogram + if (cycleSubprogramIsActive) { + if (forceCycle || cycleExpanded || isProbeOperation()) { + cycleSubprogramIsActive = false; + } else { + // call subprogram + writeBlock(mFormat.format(97), "P" + nFormat.format(currentSubprogram)); + subprogramStart(new Vector(x, y, z), new Vector(0, 0, 0), false); + } + } + if (incrementalMode) { // set current position to clearance height + setCyclePosition(cycle.clearance); + } + + // 2nd through nth cycle point + } else { + if (cycleExpanded) { + expandCyclePoint(x, y, z); + } else { + if (usePolarMode) { + var polarPosition = getPolarPosition(x, y, z); + writeBlock(xOutput.format(polarPosition.first.x), yOutput.format(polarPosition.first.y), zOutput.format(polarPosition.first.z), + aOutput.format(polarPosition.second.x), bOutput.format(polarPosition.second.y), cOutput.format(polarPosition.second.z)); + return; + } + var _x; + var _y; + var _z; + if (!xyzFormat.areDifferent(x, xOutput.getCurrent()) && + !xyzFormat.areDifferent(y, yOutput.getCurrent()) && + !xyzFormat.areDifferent(z, zOutput.getCurrent())) { + switch (gPlaneModal.getCurrent()) { + case 17: // XY + xOutput.reset(); // at least one axis is required + break; + case 18: // ZX + zOutput.reset(); // at least one axis is required + break; + case 19: // YZ + yOutput.reset(); // at least one axis is required + break; + } + } + if (incrementalMode) { // set current position to retract height + setCyclePosition(cycle.retract); + } + writeBlock(xOutput.format(x), yOutput.format(y), zOutput.format(z)); + if (incrementalMode) { // set current position to clearance height + setCyclePosition(cycle.clearance); + } + } + } +} + +function getProbingArguments(cycle, updateWCS) { + var outputWCSCode = updateWCS && currentSection.strategy == "probe"; + if (outputWCSCode) { + validate(probeOutputWorkOffset <= 99, "Work offset is out of range."); + var nextWorkOffset = hasNextSection() ? getNextSection().workOffset == 0 ? 1 : getNextSection().workOffset : -1; + if (probeOutputWorkOffset == nextWorkOffset) { + currentWorkOffset = undefined; + } + } + return [ + (cycle.angleAskewAction == "stop-message" ? "B" + xyzFormat.format(cycle.toleranceAngle ? cycle.toleranceAngle : 0) : undefined), + ((cycle.updateToolWear && cycle.toolWearErrorCorrection < 100) ? "F" + xyzFormat.format(cycle.toolWearErrorCorrection ? cycle.toolWearErrorCorrection / 100 : 100) : undefined), + (cycle.wrongSizeAction == "stop-message" ? "H" + xyzFormat.format(cycle.toleranceSize ? cycle.toleranceSize : 0) : undefined), + (cycle.outOfPositionAction == "stop-message" ? "M" + xyzFormat.format(cycle.tolerancePosition ? cycle.tolerancePosition : 0) : undefined), + ((cycle.updateToolWear && cycleType == "probing-z") ? "T" + xyzFormat.format(cycle.toolLengthOffset) : undefined), + ((cycle.updateToolWear && cycleType !== "probing-z") ? "T" + xyzFormat.format(cycle.toolDiameterOffset) : undefined), + (cycle.updateToolWear ? "V" + xyzFormat.format(cycle.toolWearUpdateThreshold ? cycle.toolWearUpdateThreshold : 0) : undefined), + (cycle.printResults ? "W" + xyzFormat.format(1 + cycle.incrementComponent) : undefined), // 1 for advance feature, 2 for reset feature count and advance component number. first reported result in a program should use W2. + conditional(outputWCSCode, "S" + probeWCSFormat.format(probeOutputWorkOffset > 6 ? (0.01 * (probeOutputWorkOffset - 6) + 154) : probeOutputWorkOffset)) + ]; +} + +function onCycleEnd() { + if (isProbeOperation()) { + zOutput.reset(); + gMotionModal.reset(); + writeBlock(gFormat.format(65), "P" + 9810, zOutput.format(cycle.retract)); // protected retract move + } else { + if (cycleSubprogramIsActive) { + subprogramEnd(); + cycleSubprogramIsActive = false; + } + if (!cycleExpanded) { + writeBlock(gCycleModal.format(80), conditional(staticProperties.useG95forTapping, gFeedModeModal.format(94))); + gMotionModal.reset(); + } + } +} + +var pendingRadiusCompensation = -1; + +function onRadiusCompensation() { + pendingRadiusCompensation = radiusCompensation; +} + +function onRapid(_x, _y, _z) { + +} + +function onLinear(_x, _y, _z, feed) { + +} + +var forceG0 = false; +function onRapid5D(_x, _y, _z, _a, _b, _c) { + +} + +function onLinear5D(_x, _y, _z, _a, _b, _c, feed, feedMode) { + +} + +function moveToSafeRetractPosition(isRetracted) { + var _skipBlock = skipBlock; + if (!isRetracted) { + writeRetract(Z); + } + if (staticProperties.forceHomeOnIndexing) { + skipBlock = _skipBlock; + writeRetract(X, Y); + } +} + +// Start of onRewindMachine logic +var performRewinds = false; // only use this setting with hardcoded machine configurations, set to true to enable the rewind/reconfigure logic +var stockExpansion = new Vector(toPreciseUnit(0.1, IN), toPreciseUnit(0.1, IN), toPreciseUnit(0.1, IN)); // expand stock XYZ values +safeRetractDistance = (unit == IN) ? 1 : 25; // additional distance to retract out of stock +safeRetractFeed = (unit == IN) ? 20 : 500; // retract feed rate +safePlungeFeed = (unit == IN) ? 10 : 250; // plunge feed rate + +/** Allow user to override the onRewind logic. */ +function onRewindMachineEntry(_a, _b, _c) { + return false; +} + +/** Retract to safe position before indexing rotaries. */ +function onMoveToSafeRetractPosition() { + // cancel TCP so that tool doesn't follow rotaries + if (currentSection.isMultiAxis() && tcpIsSupported) { + disableLengthCompensation(false, "TCPC OFF"); + } + moveToSafeRetractPosition(false); +} + +/** 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(); + forceG0 = true; + 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) { + // reinstate TCP + if (tcpIsSupported) { + writeBlock(gMotionModal.format(0), gFormat.format(234), hFormat.format(tool.lengthOffset), formatComment("TCPC ON")); + forceFeed(); + lengthCompensationActive = true; + } + + // 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 + +// Start of polar interpolation +var usePolarMode = false; // enables polar interpolation for a single operation +var polarDirection = new Vector(1, 0, 0); // vector to maintain tool at while in polar interpolation +var saveTcpIsSupported = undefined; +function setPolarMode(section, mode) { + if (!mode) { // turn off polar mode if required + if (usePolarMode) { + var currentPosition = getCurrentPosition(); + var polarPosition = getPolarPosition(currentPosition.x, currentPosition.y, currentPosition.z); + currentMachineABC = new Vector(polarPosition.second.x, polarPosition.second.y, polarPosition.second.z); + deactivatePolarMode(); + tcpIsSupported = saveTcpIsSupported; + setFeedrateMode(true); + usePolarMode = false; + } + return; + } + + var direction = polarDirection; + + // determine the rotary axis to use for polar interpolation + var axis = undefined; + if (machineConfiguration.getAxisV().isEnabled()) { + if (Vector.dot(machineConfiguration.getAxisV().getAxis(), section.workPlane.getForward()) != 0) { + axis = machineConfiguration.getAxisV(); + } + } + if (axis == undefined && machineConfiguration.getAxisU().isEnabled()) { + if (Vector.dot(machineConfiguration.getAxisU().getAxis(), section.workPlane.getForward()) != 0) { + axis = machineConfiguration.getAxisU(); + } + } + if (axis == undefined) { + error(localize("Polar interpolation requires an active rotary axis be defined in direction of workplane normal.")); + } + + // calculate directional vector from initial position + if (direction == undefined) { + error(localize("Polar interpolation initiated without a directional vector.")); + return; + } else if (direction.isZero()) { + var initialPosition = getFramePosition(section.getInitialPosition()); + direction = Vector.diff(initialPosition, axis.getOffset()).getNormalized(); + } + + // put vector in plane of rotary axis + var temp = Vector.cross(direction, axis.getAxis()).getNormalized(); + direction = Vector.cross(axis.getAxis(), temp).getNormalized(); + + // activate polar interpolation + saveTcpIsSupported = tcpIsSupported; + tcpIsSupported = false; // temporary disable tcp support for polar mode + setFeedrateMode(); + activatePolarMode(tolerance / 2, 0, direction); +} +// End of polar interpolation + +function onCircular(clockwise, cx, cy, cz, x, y, z, feed) { + +} + +var currentCoolantMode = COOLANT_OFF; +var coolantOff = undefined; +var isOptionalCoolant = false; + +function setCoolant(coolant) { + var coolantCodes = getCoolantCodes(coolant); + forceSingleLine = false; + if ((coolantCodes != undefined) && (coolant == COOLANT_FLOOD)) { + if (coolantPressure != "") { + forceSingleLine = true; + coolantCodes.push(coolantPressure); + } + } + if (Array.isArray(coolantCodes)) { + if (singleLineCoolant || forceSingleLine) { + skipBlock = isOptionalCoolant; + writeBlock(coolantCodes.join(getWordSeparator())); + } else { + for (var c in coolantCodes) { + skipBlock = isOptionalCoolant; + writeBlock(coolantCodes[c]); + } + } + return undefined; + } + return coolantCodes; +} + +var isSpecialCoolantActive = false; + +function getCoolantCodes(coolant) { + isOptionalCoolant = false; + var multipleCoolantBlocks = new Array(); // create a formatted array to be passed into the outputted line + if (!coolants) { + error(localize("Coolants have not been defined.")); + } + if (isProbeOperation()) { // avoid coolant output for probing + coolant = COOLANT_OFF; + } + if (coolant == currentCoolantMode) { + if (operationNeedsSafeStart && coolant != COOLANT_OFF && !isSpecialCoolantActive) { + //isOptionalCoolant = true; + } else if (!forceCoolant || coolant == COOLANT_OFF) { + return undefined; // coolant is already active + } + } + if ((coolant != COOLANT_OFF) && (currentCoolantMode != COOLANT_OFF) && !isOptionalCoolant && !forceCoolant) { + if (Array.isArray(coolantOff)) { + for (var i in coolantOff) { + multipleCoolantBlocks.push(mFormat.format(coolantOff[i])); + } + } else { + multipleCoolantBlocks.push(mFormat.format(coolantOff)); + } + } + forceCoolant = false; + + if (isSpecialCoolantActive) { + forceSpindleSpeed = true; + } + var m; + var coolantCodes = {}; + for (var c in coolants) { // find required coolant codes into the coolants array + if (coolants[c].id == coolant) { + isSpecialCoolantActive = (coolants[c].id == COOLANT_THROUGH_TOOL) || (coolants[c].id == COOLANT_FLOOD_THROUGH_TOOL) || (coolants[c].id == COOLANT_AIR_THROUGH_TOOL); + coolantCodes.on = coolants[c].on; + if (coolants[c].off != undefined) { + coolantCodes.off = coolants[c].off; + break; + } else { + for (var i in coolants) { + if (coolants[i].id == COOLANT_OFF) { + coolantCodes.off = coolants[i].off; + break; + } + } + } + } + } + if (coolant == COOLANT_OFF) { + m = !coolantOff ? coolantCodes.off : coolantOff; // use the default coolant off command when an 'off' value is not specified + } else { + coolantOff = coolantCodes.off; + m = coolantCodes.on; + } + + if (!m) { + onUnsupportedCoolant(coolant); + m = 9; + } else { + if (Array.isArray(m)) { + for (var i in m) { + multipleCoolantBlocks.push(mFormat.format(m[i])); + } + } else { + multipleCoolantBlocks.push(mFormat.format(m)); + } + currentCoolantMode = coolant; + return multipleCoolantBlocks; // return the single formatted coolant value + } + return undefined; +} + +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 +}; + +function onCommand(command) { + switch (command) { + case COMMAND_STOP: + writeBlock(mFormat.format(0)); + forceSpindleSpeed = true; + forceCoolant = true; + return; + case COMMAND_OPTIONAL_STOP: + writeBlock(mFormat.format(1)); + forceSpindleSpeed = true; + forceCoolant = true; + return; + case COMMAND_COOLANT_ON: + setCoolant(COOLANT_FLOOD); + return; + case COMMAND_COOLANT_OFF: + setCoolant(COOLANT_OFF); + return; + case COMMAND_START_SPINDLE: + onCommand(tool.clockwise ? COMMAND_SPINDLE_CLOCKWISE : COMMAND_SPINDLE_COUNTERCLOCKWISE); + return; + case COMMAND_LOCK_MULTI_AXIS: + if (machineConfiguration.isMultiAxisConfiguration() && (machineConfiguration.getNumberOfAxes() >= 4)) { + var _skipBlock = skipBlock; + writeBlock(mFormat.format(10)); // lock 4th-axis motion + if (machineConfiguration.getNumberOfAxes() == 5) { + skipBlock = _skipBlock; + writeBlock(mFormat.format(12)); // lock 5th-axis motion + } + } + return; + case COMMAND_UNLOCK_MULTI_AXIS: + if (machineConfiguration.isMultiAxisConfiguration() && (machineConfiguration.getNumberOfAxes() >= 4)) { + var _skipBlock = skipBlock; + writeBlock(mFormat.format(11)); // unlock 4th-axis motion + if (machineConfiguration.getNumberOfAxes() == 5) { + skipBlock = _skipBlock; + writeBlock(mFormat.format(13)); // unlock 5th-axis motion + } + } + return; + case COMMAND_BREAK_CONTROL: + if (!toolChecked) { // avoid duplicate COMMAND_BREAK_CONTROL + prepareForToolCheck(); + writeBlock( + gFormat.format(65), + "P" + 9853, + "T" + toolFormat.format(tool.number), + "B" + xyzFormat.format(0), + "H" + xyzFormat.format(staticProperties.toolBreakageTolerance) + ); + toolChecked = true; + lengthCompensationActive = false; // macro 9853 cancels tool length compensation + } + return; + case COMMAND_TOOL_MEASURE: + measureTool = true; + return; + case COMMAND_START_CHIP_TRANSPORT: + writeBlock(mFormat.format(31)); + return; + case COMMAND_STOP_CHIP_TRANSPORT: + writeBlock(mFormat.format(33)); + return; + case COMMAND_PROBE_ON: + return; + case COMMAND_PROBE_OFF: + return; + } + + var stringId = getCommandStringId(command); + var mcode = mapCommand[stringId]; + if (mcode != undefined) { + writeBlock(mFormat.format(mcode)); + } else { + onUnsupportedCommand(command); + } +} + +var toolChecked = false; // specifies that the tool has been checked with the probe + +function onSectionEnd() { + if (isInspectionOperation() && !isLastSection()) { + writeBlock(gFormat.format(103), "P0", formatComment("LOOKAHEAD ON")); + } + if (!isLastSection() && (getNextSection().getTool().coolant != tool.coolant)) { + setCoolant(COOLANT_OFF); + } + if ((((getCurrentSectionId() + 1) >= getNumberOfSections()) || + (tool.number != getNextSection().getTool().number)) && + tool.breakControl) { + onCommand(COMMAND_BREAK_CONTROL); + } else { + toolChecked = false; + } + + if (true) { + if (isRedirecting()) { + if (firstPattern) { + var finalPosition = getFramePosition(currentSection.getFinalPosition()); + var abc; + if (currentSection.isMultiAxis() && machineConfiguration.isMultiAxisConfiguration()) { + abc = currentSection.getFinalToolAxisABC(); + } else { + abc = currentWorkPlaneABC; + } + if (abc == undefined) { + abc = new Vector(0, 0, 0); + } + setAbsoluteMode(finalPosition, abc); + subprogramEnd(); + } + } + } + forceAny(); + + if (currentSection.isMultiAxis()) { + writeBlock(gFeedModeModal.format(94)); // inverse time feed off + if (currentSection.isOptimizedForMachine()) { + // the code below gets the machine angles from previous operation. closestABC must also be set to true + currentMachineABC = currentSection.getFinalToolAxisABC(); + } + if (tcpIsSupported) { + disableLengthCompensation(false, "TCPC OFF"); + } + } + + if (isProbeOperation()) { + writeBlock(gFormat.format(65), "P" + 9833); // spin the probe off + if (probeVariables.probeAngleMethod != "G68") { + setProbeAngle(); // output probe angle rotations if required + } + } + + // reset for next section + operationNeedsSafeStart = false; + coolantPressure = staticProperties.coolantPressure; + cycleReverse = false; + + setPolarMode(currentSection, false); +} + +/** 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 = staticProperties.safePositionMethod; + if (method == "clearanceHeight") { + if (!is3D()) { + error(localize("Retract option 'Clearance Height' is not supported for multi-axis machining.")); + } else { + return; + } + } + validate(arguments.length != 0, "No axis specified for writeRetract()."); + + for (i in arguments) { + retractAxes[arguments[i]] = true; + } + if ((retractAxes[0] || retractAxes[1]) && !retracted && !skipBlock) { // 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[0] || retractAxes[1]) { + method = "G53"; + } + cancelG68Rotation(); // G68 has to be canceled for retracts + + // 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 { + if (homePositionCenter && + hasParameter("part-upper-x") && hasParameter("part-lower-x")) { + _xHome = (getParameter("part-upper-x") + getParameter("part-lower-x")) / 2; + } 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: + // special conditions + if (homePositionCenter) { // output X in standard block by itself if centering + writeBlock(gMotionModal.format(0), "X" + xyzFormat.format(_xHome)); + xOutput.reset(); + break; + } + 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 = !skipBlock; + break; + default: + error(localize("Unsupported axis specified for writeRetract().")); + return; + } + } + if (words.length > 0) { + switch (method) { + case "G28": + gMotionModal.reset(); + gAbsIncModal.reset(); + writeBlock(gFormat.format(28), gAbsIncModal.format(91), words); + writeBlock(gAbsIncModal.format(90)); + break; + case "G53": + gMotionModal.reset(); + writeBlock(gAbsIncModal.format(90), gFormat.format(53), gMotionModal.format(0), words); + break; + default: + error(localize("Unsupported safe position method.")); + return; + } + } +} + +var isDPRNTopen = false; +function inspectionCreateResultsFileHeader() { + if (isDPRNTopen) { + if (!staticProperties.singleResultsFile) { + writeln("DPRNT[END]"); + writeBlock("PCLOS"); + isDPRNTopen = false; + } + } + + if (isProbeOperation() && !printProbeResults()) { + return; // if print results is not desired by probe/ probeWCS + } + + if (!isDPRNTopen) { + writeBlock("PCLOS"); + writeBlock("POPEN"); + // check for existence of none alphanumeric characters but not spaces + var resFile; + if (staticProperties.singleResultsFile) { + resFile = getParameter("job-description") + "-RESULTS"; + } else { + resFile = getParameter("operation-comment") + "-RESULTS"; + } + resFile = resFile.replace(/:/g, "-"); + resFile = resFile.replace(/[^a-zA-Z0-9 -]/g, ""); + resFile = resFile.replace(/\s/g, "-"); + writeln("DPRNT[START]"); + writeln("DPRNT[RESULTSFILE*" + resFile + "]"); + if (hasGlobalParameter("document-id")) { + writeln("DPRNT[DOCUMENTID*" + getGlobalParameter("document-id") + "]"); + } + if (hasGlobalParameter("model-version")) { + writeln("DPRNT[MODELVERSION*" + getGlobalParameter("model-version") + "]"); + } + } + if (isProbeOperation() && printProbeResults()) { + isDPRNTopen = true; + } +} + +function getPointNumber() { + if (typeof inspectionWriteVariables == "function") { + return (inspectionVariables.pointNumber); + } else { + return ("#172[60]"); + } +} + +function inspectionWriteCADTransform() { + var cadOrigin = currentSection.getModelOrigin(); + var cadWorkPlane = currentSection.getModelPlane().getTransposed(); + var cadEuler = cadWorkPlane.getEuler2(EULER_XYZ_S); + writeln( + "DPRNT[G331" + + "*N" + getPointNumber() + + "*A" + abcFormat.format(cadEuler.x) + + "*B" + abcFormat.format(cadEuler.y) + + "*C" + abcFormat.format(cadEuler.z) + + "*X" + xyzFormat.format(-cadOrigin.x) + + "*Y" + xyzFormat.format(-cadOrigin.y) + + "*Z" + xyzFormat.format(-cadOrigin.z) + + "]" + ); +} + +function inspectionWriteWorkplaneTransform() { + var orientation = (machineConfiguration.isMultiAxisConfiguration() && currentMachineABC != undefined) ? machineConfiguration.getOrientation(currentMachineABC) : currentSection.workPlane; + var abc = orientation.getEuler2(EULER_XYZ_S); + writeln("DPRNT[G330" + + "*N" + getPointNumber() + + "*A" + abcFormat.format(abc.x) + + "*B" + abcFormat.format(abc.y) + + "*C" + abcFormat.format(abc.z) + + "*X0*Y0*Z0*I0*R0]" + ); +} + +function writeProbingToolpathInformation(cycleDepth) { + writeln("DPRNT[TOOLPATHID*" + getParameter("autodeskcam:operation-id") + "]"); + if (isInspectionOperation()) { + writeln("DPRNT[TOOLPATH*" + getParameter("operation-comment") + "]"); + } else { + writeln("DPRNT[CYCLEDEPTH*" + xyzFormat.format(cycleDepth) + "]"); + } +} + +function onClose() { + + + if (isDPRNTopen) { + writeln("DPRNT[END]"); + writeBlock("PCLOS"); + isDPRNTopen = false; + if (typeof inspectionProcessSectionEnd == "function") { + inspectionProcessSectionEnd(); + } + } + cancelG68Rotation(); + writeln(""); + + optionalSection = false; + + onCommand(COMMAND_STOP_SPINDLE); + writeBlock(mFormat.format(131)); + + writeln(""); + + writeRetract(Z) + // retract + if (!staticProperties.homePositionCenter || currentMachineABC.length != 0) { + writeRetract(X, Y); + } + + if (activeG254) { + writeBlock(gFormat.format(255)); // cancel DWO + activeG254 = false; + } + + // MAY NEED CHANGE HOMING ORDER TO ROTARY THEN LINEAR FOR NON-UMC MACHINES + + // Unwind Rotary table at end + if (machineConfiguration.isMultiAxisConfiguration()) { + onCommand(COMMAND_UNLOCK_MULTI_AXIS); + if (machineConfiguration.isMachineCoordinate(2)) { + writeBlock(gFormat.format(28), gAbsIncModal.format(91), "C" + abcFormat.format(0)); + writeBlock(gAbsIncModal.format(90)); + } else if (machineConfiguration.isMachineCoordinate(1)) { + writeBlock(gFormat.format(28), gAbsIncModal.format(91), "B" + abcFormat.format(0)); + writeBlock(gAbsIncModal.format(90)); + } else if (machineConfiguration.isMachineCoordinate(0)) { + writeBlock(gFormat.format(28), gAbsIncModal.format(91), "A" + abcFormat.format(0)); + writeBlock(gAbsIncModal.format(90)); + } + gMotionModal.reset(); + writeBlock( + gMotionModal.format(0), + conditional(machineConfiguration.isMachineCoordinate(0), "A" + abcFormat.format(0)), + conditional(machineConfiguration.isMachineCoordinate(1), "B" + abcFormat.format(0)), + conditional(machineConfiguration.isMachineCoordinate(2), "C" + abcFormat.format(0)) + ); + } + if (staticProperties.homePositionCenter) { + homePositionCenter = staticProperties.homePositionCenter; + writeRetract(X, Y); + } + + onImpliedCommand(COMMAND_END); + onImpliedCommand(COMMAND_STOP_SPINDLE); + + if (staticProperties.useM130PartImages || staticProperties.useM130ToolImages) { + writeBlock(mFormat.format(131)); + } + writeBlock(mFormat.format(30)); // stop program, spindle stop, coolant off + if (subprograms.length > 0) { + writeln(""); + write(subprograms); + } + writeln(""); + writeln("%"); +} + +/* +keywords += (keywords ? " MODEL_IMAGE" : "MODEL_IMAGE"); + +function onTerminate() { + var outputPath = getOutputPath(); + var programFilename = FileSystem.getFilename(outputPath); + var programSize = FileSystem.getFileSize(outputPath); + var postPath = findFile("setup-sheet-excel-2007.cps"); + var intermediatePath = getIntermediatePath(); + var a = "--property unit " + ((unit == IN) ? "0" : "1"); // use 0 for inch and 1 for mm + if (programName) { + a += " --property programName \"'" + programName + "'\""; + } + if (programComment) { + a += " --property programComment \"'" + programComment + "'\""; + } + a += " --property programFilename \"'" + programFilename + "'\""; + a += " --property programSize \"" + programSize + "\""; + a += " --noeditor --log temp.log \"" + postPath + "\" \"" + intermediatePath + "\" \"" + FileSystem.replaceExtension(outputPath, "xlsx") + "\""; + execute(getPostProcessorPath(), a, false, ""); + executeNoWait("excel", "\"" + FileSystem.replaceExtension(outputPath, "xlsx") + "\"", false, ""); +} +*/ + +function setProperty(property, value) { + properties[property].current = value; +} diff --git a/Haas_Next_Generation/Bechtel VF4.cps b/Haas_Mills_BIDC/Bechtel VF4.cps similarity index 99% rename from Haas_Next_Generation/Bechtel VF4.cps rename to Haas_Mills_BIDC/Bechtel VF4.cps index bf5e246..e041d89 100644 --- a/Haas_Next_Generation/Bechtel VF4.cps +++ b/Haas_Mills_BIDC/Bechtel VF4.cps @@ -82,7 +82,7 @@ properties = {/* {title: "Yes", id: "true"}, {title: "Reversed", id: "reversed"} ], - value: "false", + value: "reversed", scope: "post" }, hasBAxis: { @@ -108,7 +108,7 @@ properties = {/* {title: "Yes", id: "true"}, {title: "Reversed", id: "reversed"} ], - value: "false", + value: "true", scope: "post" },/* throughSpindle: { @@ -459,7 +459,7 @@ staticProperties = { homePositionCenter: false, optionallyCycleToolsAtStart: false, measureToolsAtStart: true, - forceHomeOnIndexing: true, + forceHomeOnIndexing: false, toolBreakageTolerance: 0.1, fastToolChange: false, useG95forTapping: true, @@ -2311,6 +2311,11 @@ function onSection() { writeBlock("T" + toolFormat.format(19), mFormat.format(6)); //Changes Tool writeBlock(gFormat.format(55), gFormat.format(0), forceX.format(stockMidX), forceY.format(stockMidY)); + if (getProperty("hasAAxis") != "false" && getProperty("hasCAxis") != "false") { + writeBlock(gFormat.format(0), aOutput.format(0), cOutput.format(0)); + } else if (getProperty("hasAAxis") != "false") { + writeBlock(gFormat.format(0), aOutput.format(0)); + } displayMedia("xyWCSCheck.jpg"); writeBlock(mFormat.format(0), formatComment("Open door")); /* diff --git a/Haas_Next_Generation/README.txt b/Haas_Mills_BIDC/README.txt similarity index 100% rename from Haas_Next_Generation/README.txt rename to Haas_Mills_BIDC/README.txt diff --git a/Haas_Next_Generation/haas vf2 deprecated.cps b/Haas_Mills_BIDC/haas vf2 deprecated.cps similarity index 100% rename from Haas_Next_Generation/haas vf2 deprecated.cps rename to Haas_Mills_BIDC/haas vf2 deprecated.cps