diff --git a/src/Mod/Path/CMakeLists.txt b/src/Mod/Path/CMakeLists.txt index 7ba19b451e..1c37306219 100644 --- a/src/Mod/Path/CMakeLists.txt +++ b/src/Mod/Path/CMakeLists.txt @@ -149,6 +149,7 @@ SET(Generator_SRCS Generators/drill_generator.py Generators/rotation_generator.py Generators/helix_generator.py + Generators/toolchange_generator.py ) SET(PathScripts_post_SRCS @@ -240,6 +241,7 @@ SET(PathTests_SRCS PathTests/TestPathPropertyBag.py PathTests/TestPathSetupSheet.py PathTests/TestPathStock.py + PathTests/TestPathToolChangeGenerator.py PathTests/TestPathThreadMilling.py PathTests/TestPathTool.py PathTests/TestPathToolBit.py diff --git a/src/Mod/Path/Generators/toolchange_generator.py b/src/Mod/Path/Generators/toolchange_generator.py new file mode 100644 index 0000000000..6fd9000a91 --- /dev/null +++ b/src/Mod/Path/Generators/toolchange_generator.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +# *************************************************************************** +# * Copyright (c) 2021 sliptonic * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + + +import PathScripts.PathLog as PathLog +import math +import Path +import FreeCAD +from enum import Enum + +__title__ = "Toolchange Path Generator" +__author__ = "sliptonic (Brad Collette)" +__url__ = "https://www.freecadweb.org" +__doc__ = "Generates the rotation toolpath" + + +if True: + PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) + PathLog.trackModule(PathLog.thisModule()) +else: + PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) + + +class SpindleDirection(Enum): + OFF = "OFF" + CW = "M3" + CCW = "M4" + + +def generate( + toolnumber, toollabel, spindlespeed=0, spindledirection=SpindleDirection.OFF +): + """ + Generates Gcode for a simple toolchange. + + """ + + PathLog.track( + f"toolnumber:{toolnumber} toollabel: {toollabel} spindlespeed:{spindlespeed} spindledirection: {spindledirection}" + ) + + if spindledirection is not SpindleDirection.OFF and spindlespeed == 0: + raise ValueError("Turning on spindle with zero speed is invalid") + + if spindlespeed < 0: + raise ValueError("Spindle speed must be a positive value") + + commands = [] + + commands.append(Path.Command(f"({toollabel})")) + commands.append(Path.Command("M6", {"T": int(toolnumber)})) + + if spindledirection is SpindleDirection.OFF: + return commands + else: + commands.append(Path.Command(spindledirection.value, {"S": spindlespeed})) + + return commands diff --git a/src/Mod/Path/PathScripts/PathToolController.py b/src/Mod/Path/PathScripts/PathToolController.py index 5704fcfb87..485a54bebc 100644 --- a/src/Mod/Path/PathScripts/PathToolController.py +++ b/src/Mod/Path/PathScripts/PathToolController.py @@ -28,6 +28,8 @@ import Path import PathScripts.PathLog as PathLog import PathScripts.PathPreferences as PathPreferences import PathScripts.PathToolBit as PathToolBit +from Generators import toolchange_generator as toolchange_generator +from Generators.toolchange_generator import SpindleDirection if False: @@ -259,27 +261,28 @@ class ToolController: def execute(self, obj): PathLog.track() - commands = "" - commands += "(" + obj.Label + ")" + "\n" - commands += "M6 T" + str(obj.ToolNumber) + "\n" + args = { + "toolnumber": obj.ToolNumber, + "toollabel": obj.Label, + "spindlespeed": obj.SpindleSpeed, + "spindledirection": SpindleDirection.OFF, + } - # If a toolbit is used, check to see if spindlepower is allowed. - # This is to prevent accidentally spinning the spindle with an - # unpowered tool like probe or dragknife - - allowSpindlePower = True - if not isinstance(obj.Tool, Path.Tool) and hasattr(obj.Tool, "SpindlePower"): - allowSpindlePower = obj.Tool.SpindlePower - - if allowSpindlePower: - PathLog.debug("selected tool preventing spindle power") - if obj.SpindleDir == "Forward": - commands += "M3 S" + str(obj.SpindleSpeed) + "\n" + if hasattr(obj.Tool, "SpindlePower"): + if not obj.Tool.SpindlePower: + args["spindledirection"] = SpindleDirection.OFF else: - commands += "M4 S" + str(obj.SpindleSpeed) + "\n" + if obj.SpindleDir == "Forward": + args["spindledirection"] = SpindleDirection.CW + else: + args["spindledirection"] = SpindleDirection.CCW + else: + if obj.SpindleDir == "Forward": + args["spindledirection"] = SpindleDirection.CW + else: + args["spindledirection"] = SpindleDirection.CCW - if commands == "": - commands += "(No commands processed)" + commands = toolchange_generator.generate(**args) path = Path.Path(commands) obj.Path = path diff --git a/src/Mod/Path/PathTests/TestPathToolChangeGenerator.py b/src/Mod/Path/PathTests/TestPathToolChangeGenerator.py new file mode 100644 index 0000000000..f9e61fd34e --- /dev/null +++ b/src/Mod/Path/PathTests/TestPathToolChangeGenerator.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +# *************************************************************************** +# * Copyright (c) 2021 sliptonic * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +import Path +import FreeCAD +import Generators.toolchange_generator as generator +from Generators.toolchange_generator import SpindleDirection + +import PathScripts.PathLog as PathLog +import PathTests.PathTestUtils as PathTestUtils +import numpy as np + +PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) +PathLog.trackModule(PathLog.thisModule()) + + +class TestPathToolChangeGenerator(PathTestUtils.PathTestBase): + def test00(self): + """Test Basic Tool Change Generator Return""" + + args = { + "toolnumber": 1, + "toollabel": "My Label", + "spindlespeed": 500, + "spindledirection": SpindleDirection.OFF, + } + + results = generator.generate(**args) + + # Get a label + self.assertTrue(len(results) == 2) + commentcommand = results[0] + self.assertTrue(isinstance(commentcommand, Path.Command)) + self.assertTrue(commentcommand.toGCode() == "(My Label)") + + # Get a tool command + toolcommand = results[1] + self.assertTrue(toolcommand.Name == "M6") + + # Turn on the spindle + args["spindledirection"] = SpindleDirection.CW + results = generator.generate(**args) + self.assertTrue(len(results) == 3) + + speedcommand = results[2] + self.assertTrue(speedcommand.Name == "M3") + self.assertTrue(speedcommand.Parameters["S"] == 500) + + # speed zero with spindle on + args["spindlespeed"] = 0 + self.assertRaises(ValueError, generator.generate, **args) + + # negative spindlespeed + args["spindlespeed"] = -10 + self.assertRaises(ValueError, generator.generate, **args) diff --git a/src/Mod/Path/TestPathApp.py b/src/Mod/Path/TestPathApp.py index df94f86591..dab2a245dc 100644 --- a/src/Mod/Path/TestPathApp.py +++ b/src/Mod/Path/TestPathApp.py @@ -46,6 +46,7 @@ from PathTests.TestPathStock import TestPathStock from PathTests.TestPathThreadMilling import TestPathThreadMilling from PathTests.TestPathTool import TestPathTool from PathTests.TestPathToolBit import TestPathToolBit +from PathTests.TestPathToolChangeGenerator import TestPathToolChangeGenerator from PathTests.TestPathToolController import TestPathToolController from PathTests.TestPathTooltable import TestPathTooltable from PathTests.TestPathUtil import TestPathUtil @@ -76,6 +77,7 @@ False if TestPathStock.__name__ else True False if TestPathThreadMilling.__name__ else True False if TestPathTool.__name__ else True False if TestPathToolBit.__name__ else True +False if TestPathToolChangeGenerator.__name__ else True False if TestPathToolController.__name__ else True False if TestPathTooltable.__name__ else True False if TestPathUtil.__name__ else True