Merge pull request #7127 from sliptonic/feature/chipbreak

[Path] Feature/chipbreak
This commit is contained in:
sliptonic
2022-07-16 12:02:38 -05:00
committed by GitHub
10 changed files with 223 additions and 124 deletions

View File

@@ -275,7 +275,7 @@ void PathSegmentWalker::walk(PathSegmentVisitor &cb, const Base::Vector3d &start
// relative mode
absolutecenter = false;
} else if ((name=="G81")||(name=="G82")||(name=="G83")||(name=="G84")||(name=="G85")||(name=="G86")||(name=="G89")){
} else if ((name=="G73")||(name=="G81")||(name=="G82")||(name=="G83")||(name=="G84")||(name=="G85")||(name=="G86")||(name=="G89")){
// drill,tap,bore
double r = 0;
if (cmd.has("R"))

View File

@@ -2,30 +2,31 @@
This is a documentation of all GCodes used by the FreeCAD Path Workbench
| Command | Description | Supported parameters |
| --- | --- | --- |
| G0, G00 | Rapid move | X,Y,Z,A,B,C |
| G1, G01 | Normal interpolated move | X,Y,Z,A,B,C |
| G2, G02 | Clockwise arc | X,Y,Z,A,B,C,I,J,K |
| G3, G03 | Counterclockwise arc | X,Y,Z,A,B,C,I,J,K |
| G40 | Turn off tool radius compensation | Radius compensation is done in FreeCAD |
| G41 | Tool radius compensation value | Radius compensation is done in FreeCAD |
| G42 | Tool radius compensation value | Radius compensation is done in FreeCAD |
| G43 | Tool length offset | |
| G44 | Tool length offset | |
| G53 | Machine coordinate system fixture | ??? |
| G54 | Scratchpad coordinate system fixture | ??? |
| G55 - G59.9 | Machine specific work offset fixtures relative to homing switches | ??? |
| G81 | Machine specific drill operation | X,Y,Z,R,Q |
| G82 | Machine specific drill operation | X,Y,Z,R,Q |
| G83 | Machine specific drill operation | X,Y,Z,R,Q |
| G90 | Absolute coordinates | |
| G91 | Relative coordinates | |
| G98 | Return to initial Z level in canned cycle | |
| G99 | Return to R level in canned cycle | |
| M0, M00 | Compulsory stop | |
| M1, M01 | Optional stop | |
| M3, M03 | Spindle on (clockwise rotation) | S\<rounds per minute\> |
| M4, M04 | Spindle on (counterclockwise rotation) | S\<rounds per minute\> |
| M6, M06 | Tool change | T\<tool number\> |
| (\<String\>) | comment | |
| Command | Description | Supported parameters |
| --- | --- | --- |
| G0, G00 | Rapid move | X,Y,Z,A,B,C |
| G1, G01 | Normal interpolated move | X,Y,Z,A,B,C |
| G2, G02 | Clockwise arc | X,Y,Z,A,B,C,I,J,K |
| G3, G03 | Counterclockwise arc | X,Y,Z,A,B,C,I,J,K |
| G40 | Turn off tool radius compensation | Radius compensation is done in FreeCAD |
| G41 | Tool radius compensation value | Radius compensation is done in FreeCAD |
| G42 | Tool radius compensation value | Radius compensation is done in FreeCAD |
| G43 | Tool length offset | |
| G44 | Tool length offset | |
| G53 | Machine coordinate system fixture | ??? |
| G54 | Scratchpad coordinate system fixture | ??? |
| G55 - G59.9 | Machine specific work offset fixtures relative to homing switches | ??? |
| G73 | Machine specific drill operation | X,Y,Z,R,Q |
| G81 | Machine specific drill operation | X,Y,Z,R,Q |
| G82 | Machine specific drill operation | X,Y,Z,R,Q |
| G83 | Machine specific drill operation | X,Y,Z,R,Q |
| G90 | Absolute coordinates | |
| G91 | Relative coordinates | |
| G98 | Return to initial Z level in canned cycle | |
| G99 | Return to R level in canned cycle | |
| M0, M00 | Compulsory stop | |
| M1, M01 | Optional stop | |
| M3, M03 | Spindle on (clockwise rotation) | S\<rounds per minute\> |
| M4, M04 | Spindle on (counterclockwise rotation) | S\<rounds per minute\> |
| M6, M06 | Tool change | T\<tool number\> |
| (\<String\>) | comment | |

View File

@@ -38,7 +38,27 @@ else:
PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule())
def generate(edge, dwelltime=0.0, peckdepth=0.0, repeat=1, retractheight=None):
def generate(edge, dwelltime=0.0, peckdepth=0.0, repeat=1, retractheight=None, chipBreak=False):
"""
Generates Gcode for drilling a single hole.
Takes as input an edge. It assumes the edge is trivial with just two vectors.
The edge must be aligned with the Z axes (Vector(0,0,1)) or it is an error.
The first vertex of the edge will be the startpoint
The second vertex of the edge will be the endpoint.
All other vertices are ignored.
additionally, you can pass in a dwelltime, peckdepth, and repeat value.
These will result in appropriate G81,G82, and G83 codes.
If chipBreak is True, the generator will produce G73 cycles instead of G83.
Chipbreaking cycles produce very small retracts to break the chip rather than
full retracts to clear chips from the hole.
http://linuxcnc.org/docs/html/gcode/g-code.html#gcode:g73
"""
startPoint = edge.Vertexes[0].Point
endPoint = edge.Vertexes[1].Point
@@ -49,6 +69,9 @@ def generate(edge, dwelltime=0.0, peckdepth=0.0, repeat=1, retractheight=None):
PathLog.debug(numpy.isclose(startPoint.sub(endPoint).y, 0, rtol=1e-05, atol=1e-06))
PathLog.debug(endPoint)
if dwelltime > 0.0 and peckdepth > 0.0:
raise ValueError("Peck and Dwell cannot be used together")
if repeat < 1:
raise ValueError("repeat must be 1 or greater")
@@ -79,6 +102,12 @@ def generate(edge, dwelltime=0.0, peckdepth=0.0, repeat=1, retractheight=None):
cmdParams["Z"] = endPoint.z
cmdParams["R"] = retractheight if retractheight is not None else startPoint.z
if repeat < 1:
raise ValueError("repeat must be 1 or greater")
if not type(repeat) is int:
raise ValueError("repeat value must be an integer")
if repeat > 1:
cmdParams["L"] = repeat
@@ -89,7 +118,7 @@ def generate(edge, dwelltime=0.0, peckdepth=0.0, repeat=1, retractheight=None):
else:
cmd = "G81"
else:
cmd = "G83"
cmd = "G73" if chipBreak else "G83"
cmdParams["Q"] = peckdepth
return [Path.Command(cmd, cmdParams)]

View File

@@ -61,101 +61,106 @@
</widget>
</item>
<item row="1" column="0">
<widget class="QWidget" name="widget">
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="1" colspan="2">
<widget class="QCheckBox" name="peckEnabled">
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="1" colspan="2">
<widget class="QCheckBox" name="peckEnabled">
<property name="text">
<string>Peck</string>
</property>
</widget>
</item>
<item row="7" column="4">
<widget class="QLabel" name="dwellTimelabel">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Time</string>
</property>
</widget>
</item>
<item row="8" column="4">
<widget class="QLabel" name="Offsetlabel">
<property name="text">
<string>Extend Depth</string>
</property>
</widget>
</item>
<item row="1" column="6">
<widget class="Gui::QuantitySpinBox" name="peckDepth">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="8" column="6">
<widget class="QComboBox" name="ExtraOffset">
<item>
<property name="text">
<string>Peck</string>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QLabel" name="peckDepthLabel">
<property name="enabled">
<bool>false</bool>
<string>None</string>
</property>
</item>
<item>
<property name="text">
<string>Depth</string>
</property>
</widget>
</item>
<item row="1" column="6">
<widget class="Gui::QuantitySpinBox" name="peckDepth">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QLabel" name="retractLabel">
<property name="enabled">
<bool>false</bool>
<string>Drill Tip</string>
</property>
</item>
<item>
<property name="text">
<string>Retract</string>
<string>2x Drill Tip</string>
</property>
</widget>
</item>
<item row="3" column="6">
<widget class="Gui::QuantitySpinBox" name="peckRetractHeight">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="5" column="1" rowspan="2" colspan="2">
<widget class="QCheckBox" name="dwellEnabled">
<property name="text">
<string>Dwell</string>
</property>
</widget>
</item>
<item row="6" column="4">
<widget class="QLabel" name="dwellTimelabel">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Time</string>
</property>
</widget>
</item>
<item row="6" column="6">
<widget class="Gui::QuantitySpinBox" name="dwellTime">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="7" column="4">
<widget class="QLabel" name="Offsetlabel">
<property name="text">
<string>Extend Depth</string>
</property>
</widget>
</item>
</item>
</widget>
</item>
<item row="7" column="6">
<widget class="QComboBox" name="ExtraOffset">
<item>
<property name="text">
<string>None</string>
</property>
</item>
<item>
<property name="text">
<string>Drill Tip</string>
</property>
</item>
<item>
<property name="text">
<string>2x Drill Tip</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
<widget class="Gui::QuantitySpinBox" name="dwellTime">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="6" column="1" rowspan="2" colspan="2">
<widget class="QCheckBox" name="dwellEnabled">
<property name="text">
<string>Dwell</string>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QLabel" name="peckDepthLabel">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Depth</string>
</property>
</widget>
</item>
<item row="4" column="4">
<widget class="QLabel" name="retractLabel">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Retract</string>
</property>
</widget>
</item>
<item row="4" column="6">
<widget class="Gui::QuantitySpinBox" name="peckRetractHeight">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="chipBreakEnabled">
<property name="text">
<string>Chip Break</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<spacer name="verticalSpacer">
@@ -175,7 +180,7 @@
<customwidgets>
<customwidget>
<class>Gui::QuantitySpinBox</class>
<extends>QDoubleSpinBox</extends>
<extends>QWidget</extends>
<header>Gui/QuantitySpinBox.h</header>
</customwidget>
</customwidgets>

View File

@@ -295,7 +295,7 @@ class PathArray:
CmdMoveStraight = ["G1", "G01"]
CmdMoveCW = ["G2", "G02"]
CmdMoveCCW = ["G3", "G03"]
CmdDrill = ["G81", "G82", "G83"]
CmdDrill = ["G73", "G81", "G82", "G83"]
CmdMoveArc = CmdMoveCW + CmdMoveCCW
CmdMove = CmdMoveStraight + CmdMoveArc

View File

@@ -98,6 +98,15 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp):
PathOp.FeatureBaseGeometry | PathOp.FeatureLocations | PathOp.FeatureCoolant
)
def onDocumentRestored(self, obj):
if not hasattr(obj, "chipBreakEnabled"):
obj.addProperty(
"App::PropertyBool",
"chipBreakEnabled",
"Drill",
QT_TRANSLATE_NOOP("App::Property", "Use chipbreaking"),
)
def initCircularHoleOperation(self, obj):
"""initCircularHoleOperation(obj) ... add drilling specific properties to obj."""
obj.addProperty(
@@ -115,6 +124,12 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp):
"Drill",
QT_TRANSLATE_NOOP("App::Property", "Enable pecking"),
)
obj.addProperty(
"App::PropertyBool",
"chipBreakEnabled",
"Drill",
QT_TRANSLATE_NOOP("App::Property", "Use chipbreaking"),
)
obj.addProperty(
"App::PropertyFloat",
"DwellTime",
@@ -231,10 +246,16 @@ class ObjectDrilling(PathCircularHoleBase.ObjectOp):
dwelltime = obj.DwellTime if obj.DwellEnabled else 0.0
peckdepth = obj.PeckDepth.Value if obj.PeckEnabled else 0.0
repeat = 1 # technical debt: Add a repeat property for user control
chipBreak = (obj.chipBreakEnabled and obj.PeckEnabled)
try:
drillcommands = generator.generate(
edge, dwelltime, peckdepth, repeat, obj.RetractHeight.Value
edge,
dwelltime,
peckdepth,
repeat,
obj.RetractHeight.Value,
chipBreak=chipBreak
)
except ValueError as e: # any targets that fail the generator are ignored

View File

@@ -57,14 +57,17 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage):
self.dwellTimeSpinBox = PathGui.QuantitySpinBox(
self.form.dwellTime, obj, "DwellTime"
)
self.form.chipBreakEnabled.setEnabled(False)
def registerSignalHandlers(self, obj):
self.form.peckEnabled.toggled.connect(self.form.peckDepth.setEnabled)
self.form.peckEnabled.toggled.connect(self.form.dwellEnabled.setDisabled)
self.form.peckEnabled.toggled.connect(self.setChipBreakControl)
self.form.dwellEnabled.toggled.connect(self.form.dwellTime.setEnabled)
self.form.dwellEnabled.toggled.connect(self.form.dwellTimelabel.setEnabled)
self.form.dwellEnabled.toggled.connect(self.form.peckEnabled.setDisabled)
self.form.dwellEnabled.toggled.connect(self.setChipBreakControl)
self.form.peckRetractHeight.setEnabled(True)
self.form.retractLabel.setEnabled(True)
@@ -73,10 +76,17 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage):
self.form.dwellEnabled.setEnabled(False)
self.form.peckDepth.setEnabled(True)
self.form.peckDepthLabel.setEnabled(True)
self.form.chipBreakEnabled.setEnabled(True)
elif self.form.dwellEnabled.isChecked():
self.form.peckEnabled.setEnabled(False)
self.form.dwellTime.setEnabled(True)
self.form.dwellTimelabel.setEnabled(True)
self.form.chipBreakEnabled.setEnabled(False)
else:
self.form.chipBreakEnabled.setEnabled(False)
def setChipBreakControl(self):
self.form.chipBreakEnabled.setEnabled(self.form.peckEnabled.isChecked())
def getForm(self):
"""getForm() ... return UI"""
@@ -104,6 +114,8 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage):
obj.DwellEnabled = self.form.dwellEnabled.isChecked()
if obj.PeckEnabled != self.form.peckEnabled.isChecked():
obj.PeckEnabled = self.form.peckEnabled.isChecked()
if obj.chipBreakEnabled != self.form.chipBreakEnabled.isChecked():
obj.chipBreakEnabled = self.form.chipBreakEnabled.isChecked()
if obj.ExtraOffset != str(self.form.ExtraOffset.currentData()):
obj.ExtraOffset = str(self.form.ExtraOffset.currentData())
@@ -124,6 +136,12 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage):
self.form.peckEnabled.setCheckState(QtCore.Qt.Checked)
else:
self.form.peckEnabled.setCheckState(QtCore.Qt.Unchecked)
self.form.chipBreakEnabled.setEnabled(False)
if obj.chipBreakEnabled:
self.form.chipBreakEnabled.setCheckState(QtCore.Qt.Checked)
else:
self.form.chipBreakEnabled.setCheckState(QtCore.Qt.Unchecked)
self.selectInComboBox(obj.ExtraOffset, self.form.ExtraOffset)
@@ -139,6 +157,7 @@ class TaskPanelOpPage(PathCircularHoleBaseGui.TaskPanelOpPage):
signals.append(self.form.dwellTime.editingFinished)
signals.append(self.form.dwellEnabled.stateChanged)
signals.append(self.form.peckEnabled.stateChanged)
signals.append(self.form.chipBreakEnabled.stateChanged)
signals.append(self.form.toolController.currentIndexChanged)
signals.append(self.form.coolantController.currentIndexChanged)
signals.append(self.form.ExtraOffset.currentIndexChanged)

View File

@@ -87,7 +87,7 @@ CmdMoveRapid = ["G0", "G00"]
CmdMoveStraight = ["G1", "G01"]
CmdMoveCW = ["G2", "G02"]
CmdMoveCCW = ["G3", "G03"]
CmdMoveDrill = ["G81", "G82", "G83"]
CmdMoveDrill = ["G73", "G81", "G82", "G83"]
CmdMoveArc = CmdMoveCW + CmdMoveCCW
CmdMove = CmdMoveStraight + CmdMoveArc + CmdMoveDrill
CmdMoveAll = CmdMove + CmdMoveRapid

View File

@@ -290,7 +290,7 @@ class PathSimulation:
if cmd.Name in ["G80"]:
self.firstDrill = True
if cmd.Name in ["G81", "G82", "G83"]:
if cmd.Name in ["G73", "G81", "G82", "G83"]:
if self.firstDrill:
extendcommand = Path.Command("G0", {"Z": cmd.r})
self.curpos = self.RapidMove(extendcommand, self.curpos)
@@ -372,7 +372,7 @@ class PathSimulation:
) = self.voxSim.GetResultMesh()
if cmd.Name in ["G80"]:
self.firstDrill = True
if cmd.Name in ["G81", "G82", "G83"]:
if cmd.Name in ["G73", "G81", "G82", "G83"]:
extendcommands = []
if self.firstDrill:
extendcommands.append(Path.Command("G0", {"Z": cmd.r}))

View File

@@ -152,3 +152,27 @@ class TestPathDrillGenerator(PathTestUtils.PathTestBase):
self.assertRaises(ValueError, generator.generate, **args)
args = {"edge": e, "retractheight": "1"}
self.assertRaises(ValueError, generator.generate, **args)
def test50(self):
"""Test Error if dwell and peck"""
v1 = FreeCAD.Vector(0, 0, 10)
v2 = FreeCAD.Vector(0, 0, 0)
e = Part.makeLine(v1, v2)
# dwelltime should be a float
args = {"edge": e, "dwelltime": 1.0, "peckdepth": 1.0}
self.assertRaises(ValueError, generator.generate, **args)
def test60(self):
"""Test chipBreak"""
v1 = FreeCAD.Vector(0, 0, 10)
v2 = FreeCAD.Vector(0, 0, 0)
e = Part.makeLine(v1, v2)
args = {"edge": e, "peckdepth": 1.0, "chipBreak": True}
result = generator.generate(**args)
command = result[0]
self.assertTrue(command.Name == "G73")