Merge pull request #7185 from LarryWoestman/post_refactor

Path:  Added G73 decomposition and more refactored tests
This commit is contained in:
sliptonic
2022-09-06 16:29:14 -05:00
committed by GitHub
8 changed files with 1574 additions and 1038 deletions

View File

@@ -34,6 +34,14 @@ import argparse
import os
import shlex
import FreeCAD
from FreeCAD import Units
# to distinguish python built-in open function from the one declared below
if open.__module__ in ["__builtin__", "io"]:
pythonopen = open
def add_flag_type_arguments(
argument_group,
@@ -64,6 +72,8 @@ def init_argument_defaults(argument_defaults):
argument_defaults["line-numbers"] = False
argument_defaults["metric_inches"] = True
argument_defaults["modal"] = False
argument_defaults["output_all_arguments"] = False
argument_defaults["output_visible_arguments"] = False
argument_defaults["show-editor"] = True
argument_defaults["tlo"] = True
argument_defaults["tool_change"] = True
@@ -81,6 +91,8 @@ def init_arguments_visible(arguments_visible):
arguments_visible["line-numbers"] = True
arguments_visible["metric_inches"] = True
arguments_visible["modal"] = True
arguments_visible["output_all_arguments"] = True
arguments_visible["output_visible_arguments"] = True
arguments_visible["postamble"] = True
arguments_visible["preamble"] = True
arguments_visible["precision"] = True
@@ -188,6 +200,24 @@ def init_shared_arguments(values, argument_defaults, arguments_visible):
"Output the G-command name even if it is the same as the previous line",
arguments_visible["modal"],
)
add_flag_type_arguments(
shared,
argument_defaults["output_all_arguments"],
"--output_all_arguments",
"--no-output_all_arguments",
"Output all of the available arguments",
"Don't output all of the available arguments",
arguments_visible["output_all_arguments"],
)
add_flag_type_arguments(
shared,
argument_defaults["output_visible_arguments"],
"--output_visible_arguments",
"--no-output_visible_arguments",
"Output all of the visible arguments",
"Don't output the visible arguments",
arguments_visible["output_visible_arguments"],
)
if arguments_visible["postamble"]:
help_message = (
'Set commands to be issued after the last command, default is "'
@@ -283,6 +313,11 @@ def init_shared_values(values):
# The starting axis precision is 3 digits after the decimal point.
#
values["AXIS_PRECISION"] = 3
#
# How far to move up (in millimeters) in the Z axis when chipbreaking with a G73 command.
#
values["CHIPBREAKING_AMOUNT"] = Units.Quantity(0.25, FreeCAD.Units.Length)
#
# If this is set to "", all spaces are removed from between commands and parameters.
#
@@ -319,7 +354,7 @@ def init_shared_values(values):
# If TRANSLATE_DRILL_CYCLES is True, these are the drill cycles
# that get translated to G0 and G1 commands.
#
values["DRILL_CYCLES_TO_TRANSLATE"] = ("G81", "G82", "G83")
values["DRILL_CYCLES_TO_TRANSLATE"] = ("G73", "G81", "G82", "G83")
#
# The default value of drill retractations (CURRENT_Z).
# The other possible value is G99.
@@ -352,10 +387,6 @@ def init_shared_values(values):
#
values["FINISH_LABEL"] = "Finish"
#
# The name of the machine the postprocessor is for
#
values["MACHINE_NAME"] = "unknown machine"
#
# The line number increment value
#
values["LINE_INCREMENT"] = 10
@@ -369,6 +400,10 @@ def init_shared_values(values):
#
values["LIST_TOOLS_IN_PREAMBLE"] = False
#
# The name of the machine the postprocessor is for
#
values["MACHINE_NAME"] = "unknown machine"
#
# If this value is true G-code commands are suppressed if they are
# the same as the previous line.
#
@@ -441,6 +476,9 @@ def init_shared_values(values):
# This list controls the order of parameters in a line during output.
#
values["PARAMETER_ORDER"] = [
"D",
"H",
"L",
"X",
"Y",
"Z",
@@ -453,13 +491,13 @@ def init_shared_values(values):
"I",
"J",
"K",
"R",
"P",
"E",
"Q",
"F",
"S",
"T",
"Q",
"R",
"L",
"P",
]
#
# Any commands in this value will be output as the last commands
@@ -557,10 +595,26 @@ def init_shared_values(values):
values["USE_TLO"] = True
def process_shared_arguments(values, parser, argstring):
def process_shared_arguments(values, parser, argstring, all_visible, filename):
"""Process the arguments to the postprocessor."""
try:
args = parser.parse_args(shlex.split(argstring))
if args.output_all_arguments:
argument_text = all_visible.format_help()
if not filename == "-":
gfile = pythonopen(filename, "w", newline=values["END_OF_LINE_CHARACTERS"])
gfile.write(argument_text)
gfile.close()
return (False, argument_text)
if args.output_visible_arguments:
argument_text = parser.format_help()
if not filename == "-":
gfile = pythonopen(filename, "w", newline=values["END_OF_LINE_CHARACTERS"])
gfile.write(argument_text)
gfile.close()
return (False, argument_text)
# Default to metric unless an argument overrides it
values["UNITS"] = "G21"
if args.metric:
values["UNITS"] = "G21"
if args.inches:
@@ -650,6 +704,81 @@ def process_shared_arguments(values, parser, argstring):
values["SPINDLE_WAIT"] = args.wait_for_spindle
except Exception:
return (False, None)
return (False, "")
return (True, args)
#
# LinuxCNC (and GRBL) G-Code Parameter/word Patterns
# __________________________________________________
#
# LinuxCNC words (called parameters in this code in many places) may be
# reordered in any way without changing the meaning of the line.
# However, the documentation shows the examples with the parameters/words
# in a certain order that people might be used to and want to see.
#
# axes one or more of "X Y Z A B C U V W", usually in that order
#
# default parameter order D H L axes I J K R P E Q F S T $
#
# G10 L P axes R I J Q
#
# G33.1 X Y Z K I $
#
# G53 G00|G01 or G00|G01 G53 X Y Z
#
# G73, G74, G81 to G86, G89 (X Y Z) or (U V W) R Q L P F K $
#
# G76 P Z I J R K Q H E L $
#
# M19 R Q P $
#
# M66 P|E L Q
#
# M98 P Q L
#
# N and O are associated with line numbers
#
#
#
# Tormach PathPilot (based on LinuxCNC, mostly) G-Code Patterns
# _____________________________________________________________
#
# (Just the exceptions to the LinuxCNC patterns shown above)
#
# G47 Z R X Y P Q D
#
#
# Mach4 G-Code Patterns
# _____________________
#
# (Just the exceptions to the LinuxCNC patterns shown above)
#
# G10 L1 P Z W D R X U Y V Q
#
# G30 P axes
#
# G41, G42 D|P X Y F
#
# G65, G66 P A B C
#
# G73, G74, G76, G81-9 X Y Z Q R I J P L F
#
# G84.2, G84.3 X Y Z R P L F J
#
#
#
# Centroid G-Code Patterns
# ________________________
#
# (Just the exceptions to the LinuxCNC patterns shown above)
#
# E1-E6 are equivalent to G54-G59
#
# G10 P D H R
#
# G65 P L arguments (arguments are A-Z excluding G, L, N, O, and P)
# G65 "program.cnc" L arguments
#
# G117, G118, G119 P X Y Z I J K P Q
#

View File

@@ -94,130 +94,125 @@ def drill_translate(values, outstring, cmd, params):
# get the other parameters
drill_feedrate = Units.Quantity(params["F"], FreeCAD.Units.Velocity)
if cmd == "G83":
if cmd in ("G73", "G83"):
drill_Step = Units.Quantity(params["Q"], FreeCAD.Units.Length)
a_bit = (
drill_Step * 0.05
) # NIST 3.5.16.4 G83 Cycle: "current hole bottom, backed off a bit."
# NIST 3.5.16.4 G83 Cycle: "current hole bottom, backed off a bit."
a_bit = drill_Step * 0.05
elif cmd == "G82":
drill_DwellTime = params["P"]
# wrap this block to ensure machine's values["MOTION_MODE"] is restored
# in case of error
try:
if values["MOTION_MODE"] == "G91":
trBuff += (
linenumber(values) + "G90\n"
) # force absolute coordinates during cycles
# wrap this block to ensure machine's values["MOTION_MODE"] is restored in case of error
# try:
if values["MOTION_MODE"] == "G91":
# force absolute coordinates during cycles
trBuff += linenumber(values) + "G90\n"
strG0_RETRACT_Z = (
"G0 Z"
+ format(
float(RETRACT_Z.getValueAs(values["UNIT_FORMAT"])),
axis_precision_string,
)
+ "\n"
strG0_RETRACT_Z = (
"G0 Z"
+ format(float(RETRACT_Z.getValueAs(values["UNIT_FORMAT"])), axis_precision_string)
+ "\n"
)
strF_Feedrate = (
" F"
+ format(
float(drill_feedrate.getValueAs(values["UNIT_SPEED_FORMAT"])), feed_precision_string
)
strF_Feedrate = (
" F"
+ format(
float(drill_feedrate.getValueAs(values["UNIT_SPEED_FORMAT"])),
feed_precision_string,
)
+ "\n"
)
# print(strF_Feedrate)
+ "\n"
)
# print(strF_Feedrate)
# preliminary movement(s)
if values["CURRENT_Z"] < RETRACT_Z:
trBuff += linenumber(values) + strG0_RETRACT_Z
# preliminary movement(s)
if values["CURRENT_Z"] < RETRACT_Z:
trBuff += linenumber(values) + strG0_RETRACT_Z
trBuff += (
linenumber(values)
+ "G0 X"
+ format(float(drill_X.getValueAs(values["UNIT_FORMAT"])), axis_precision_string)
+ " Y"
+ format(float(drill_Y.getValueAs(values["UNIT_FORMAT"])), axis_precision_string)
+ "\n"
)
if values["CURRENT_Z"] > RETRACT_Z:
# NIST GCODE 3.5.16.1 Preliminary and In-Between Motion says G0 to RETRACT_Z
# Here use G1 since retract height may be below surface !
trBuff += (
linenumber(values)
+ "G0 X"
+ format(
float(drill_X.getValueAs(values["UNIT_FORMAT"])), axis_precision_string
)
+ " Y"
+ format(
float(drill_Y.getValueAs(values["UNIT_FORMAT"])), axis_precision_string
)
+ "\n"
+ "G1 Z"
+ format(float(RETRACT_Z.getValueAs(values["UNIT_FORMAT"])), axis_precision_string)
+ strF_Feedrate
)
if values["CURRENT_Z"] > RETRACT_Z:
# NIST GCODE 3.5.16.1 Preliminary and In-Between Motion says G0 to RETRACT_Z
# Here use G1 since retract height may be below surface !
trBuff += (
linenumber(values)
+ "G1 Z"
+ format(
float(RETRACT_Z.getValueAs(values["UNIT_FORMAT"])),
axis_precision_string,
)
+ strF_Feedrate
)
last_Stop_Z = RETRACT_Z
last_Stop_Z = RETRACT_Z
# drill moves
if cmd in ("G81", "G82"):
trBuff += (
linenumber(values)
+ "G1 Z"
+ format(
float(drill_Z.getValueAs(values["UNIT_FORMAT"])),
axis_precision_string,
)
+ strF_Feedrate
)
# pause where applicable
if cmd == "G82":
trBuff += linenumber(values) + "G4 P" + str(drill_DwellTime) + "\n"
trBuff += linenumber(values) + strG0_RETRACT_Z
else: # 'G83'
if params["Q"] != 0:
while 1:
if last_Stop_Z != RETRACT_Z:
clearance_depth = (
last_Stop_Z + a_bit
) # rapid move to just short of last drilling depth
# drill moves
if cmd in ("G81", "G82"):
trBuff += (
linenumber(values)
+ "G1 Z"
+ format(float(drill_Z.getValueAs(values["UNIT_FORMAT"])), axis_precision_string)
+ strF_Feedrate
)
# pause where applicable
if cmd == "G82":
trBuff += linenumber(values) + "G4 P" + str(drill_DwellTime) + "\n"
trBuff += linenumber(values) + strG0_RETRACT_Z
else: # "G73" or "G83"
if params["Q"] != 0:
while 1:
if last_Stop_Z != RETRACT_Z:
# rapid move to just short of last drilling depth
clearance_depth = last_Stop_Z + a_bit
trBuff += (
linenumber(values)
+ "G0 Z"
+ format(
float(clearance_depth.getValueAs(values["UNIT_FORMAT"])),
axis_precision_string,
)
+ "\n"
)
next_Stop_Z = last_Stop_Z - drill_Step
if next_Stop_Z > drill_Z:
trBuff += (
linenumber(values)
+ "G1 Z"
+ format(
float(next_Stop_Z.getValueAs(values["UNIT_FORMAT"])),
axis_precision_string,
)
+ strF_Feedrate
)
if cmd == "G73":
# Rapid up "a small amount".
chip_breaker_height = next_Stop_Z + values["CHIPBREAKING_AMOUNT"]
trBuff += (
linenumber(values)
+ "G0 Z"
+ format(
float(
clearance_depth.getValueAs(values["UNIT_FORMAT"])
),
float(chip_breaker_height.getValueAs(values["UNIT_FORMAT"])),
axis_precision_string,
)
+ "\n"
)
next_Stop_Z = last_Stop_Z - drill_Step
if next_Stop_Z > drill_Z:
trBuff += (
linenumber(values)
+ "G1 Z"
+ format(
float(next_Stop_Z.getValueAs(values["UNIT_FORMAT"])),
axis_precision_string,
)
+ strF_Feedrate
)
else: # "G83"
# Rapid up to the retract height
trBuff += linenumber(values) + strG0_RETRACT_Z
last_Stop_Z = next_Stop_Z
else:
trBuff += (
linenumber(values)
+ "G1 Z"
+ format(
float(drill_Z.getValueAs(values["UNIT_FORMAT"])),
axis_precision_string,
)
+ strF_Feedrate
last_Stop_Z = next_Stop_Z
else:
trBuff += (
linenumber(values)
+ "G1 Z"
+ format(
float(drill_Z.getValueAs(values["UNIT_FORMAT"])),
axis_precision_string,
)
trBuff += linenumber(values) + strG0_RETRACT_Z
break
+ strF_Feedrate
)
trBuff += linenumber(values) + strG0_RETRACT_Z
break
except Exception:
pass
# except Exception:
# print("exception occurred")
# pass
if values["MOTION_MODE"] == "G91":
trBuff += linenumber(values) + "G91\n" # Restore if changed
@@ -365,12 +360,21 @@ def parse(values, pathobj):
)
else:
continue
elif param in ["H", "L", "T"]:
elif param in ("H", "L", "T"):
outstring.append(param + str(int(c.Parameters[param])))
elif param == "D":
if command in ["G41", "G42"]:
if command in ("G41", "G42"):
outstring.append(param + str(int(c.Parameters[param])))
elif command in ["G96", "G97"]:
elif command in ("G41.1", "G42.1"):
pos = Units.Quantity(c.Parameters[param], FreeCAD.Units.Length)
outstring.append(
param
+ format(
float(pos.getValueAs(values["UNIT_FORMAT"])),
axis_precision_string,
)
)
elif command in ("G96", "G97"):
outstring.append(
param
+ PostUtils.fmt(
@@ -379,25 +383,25 @@ def parse(values, pathobj):
"G21",
)
)
else: # anything else that is supported (G41.1?, G42.1?)
else: # anything else that is supported
outstring.append(param + str(float(c.Parameters[param])))
elif param == "P":
if command in ["G2", "G02", "G3", "G03", "G5.2", "G5.3", "G10"]:
if command in (
"G2",
"G02",
"G3",
"G03",
"G5.2",
"G5.3",
"G10",
"G54.1",
"G59",
):
outstring.append(param + str(int(c.Parameters[param])))
elif command in [
"G4",
"G04",
"G64",
"G76",
"G82",
"G86",
"G89",
]:
elif command in ("G4", "G04", "G76", "G82", "G86", "G89"):
outstring.append(param + str(float(c.Parameters[param])))
elif command in ["G5", "G05"]:
pos = Units.Quantity(
c.Parameters[param], FreeCAD.Units.Length
)
elif command in ("G5", "G05", "G64"):
pos = Units.Quantity(c.Parameters[param], FreeCAD.Units.Length)
outstring.append(
param
+ format(
@@ -407,6 +411,18 @@ def parse(values, pathobj):
)
else: # anything else that is supported
outstring.append(param + str(c.Parameters[param]))
elif param == "Q":
if command == "G10":
outstring.append(param + str(int(c.Parameters[param])))
elif command in ("G64", "G73", "G83"):
pos = Units.Quantity(c.Parameters[param], FreeCAD.Units.Length)
outstring.append(
param
+ format(
float(pos.getValueAs(values["UNIT_FORMAT"])),
axis_precision_string,
)
)
elif param == "S":
outstring.append(
param

View File

@@ -228,6 +228,14 @@ parser = init_arguments(values, argument_defaults, arguments_visible)
# The TOOLTIP_ARGS value is created from the help information about the arguments.
#
TOOLTIP_ARGS = parser.format_help()
#
# Create another parser just to get a list of all possible arguments
# that may be output using --output_all_arguments.
#
all_arguments_visible = {}
for k in iter(arguments_visible):
all_arguments_visible[k] = True
all_visible = init_arguments(values, argument_defaults, all_arguments_visible)
def export(objectslist, filename, argstring):
@@ -239,9 +247,11 @@ def export(objectslist, filename, argstring):
# print(parser.format_help())
(flag, args) = PostUtilsArguments.process_shared_arguments(values, parser, argstring)
(flag, args) = PostUtilsArguments.process_shared_arguments(
values, parser, argstring, all_visible, filename
)
if not flag:
return None
return args
#
# Process any additional arguments here
#

View File

@@ -195,6 +195,14 @@ parser = init_arguments(values, argument_defaults, arguments_visible)
# The TOOLTIP_ARGS value is created from the help information about the arguments.
#
TOOLTIP_ARGS = parser.format_help()
#
# Create another parser just to get a list of all possible arguments
# that may be output using --output_all_arguments.
#
all_arguments_visible = {}
for k in iter(arguments_visible):
all_arguments_visible[k] = True
all_visible = init_arguments(values, argument_defaults, all_arguments_visible)
def export(objectslist, filename, argstring):
@@ -206,9 +214,11 @@ def export(objectslist, filename, argstring):
# print(parser.format_help())
(flag, args) = PostUtilsArguments.process_shared_arguments(values, parser, argstring)
(flag, args) = PostUtilsArguments.process_shared_arguments(
values, parser, argstring, all_visible, filename
)
if not flag:
return None
return args
#
# Process any additional arguments here
#

View File

@@ -162,6 +162,14 @@ parser = init_arguments(values, argument_defaults, arguments_visible)
# The TOOLTIP_ARGS value is created from the help information about the arguments.
#
TOOLTIP_ARGS = parser.format_help()
#
# Create another parser just to get a list of all possible arguments
# that may be output using --output_all_arguments.
#
all_arguments_visible = {}
for k in iter(arguments_visible):
all_arguments_visible[k] = True
all_visible = init_arguments(values, argument_defaults, all_arguments_visible)
def export(objectslist, filename, argstring):
@@ -173,9 +181,11 @@ def export(objectslist, filename, argstring):
# print(parser.format_help())
(flag, args) = PostUtilsArguments.process_shared_arguments(values, parser, argstring)
(flag, args) = PostUtilsArguments.process_shared_arguments(
values, parser, argstring, all_visible, filename
)
if not flag:
return None
return args
#
# Process any additional arguments here
#

View File

@@ -169,6 +169,14 @@ parser = init_arguments(values, argument_defaults, arguments_visible)
# The TOOLTIP_ARGS value is created from the help information about the arguments.
#
TOOLTIP_ARGS = parser.format_help()
#
# Create another parser just to get a list of all possible arguments
# that may be output using --output_all_arguments.
#
all_arguments_visible = {}
for k in iter(arguments_visible):
all_arguments_visible[k] = True
all_visible = init_arguments(values, argument_defaults, all_arguments_visible)
def export(objectslist, filename, argstring):
@@ -180,9 +188,11 @@ def export(objectslist, filename, argstring):
# print(parser.format_help())
(flag, args) = PostUtilsArguments.process_shared_arguments(values, parser, argstring)
(flag, args) = PostUtilsArguments.process_shared_arguments(
values, parser, argstring, all_visible, filename
)
if not flag:
return None
return args
#
# Process any additional arguments here
#

View File

@@ -82,32 +82,6 @@ def init_values(values):
# which are then suppressed by default.
#
values["OUTPUT_TOOL_CHANGE"] = False
#
# Enable as many parameters as possible to be output by default
#
values["PARAMETER_ORDER"] = [
"X",
"Y",
"Z",
"A",
"B",
"C",
"U",
"V",
"W",
"I",
"J",
"K",
"F",
"S",
"T",
"Q",
"R",
"L",
"H",
"D",
"P",
]
values["POSTPROCESSOR_FILE_NAME"] = __name__
#
# Do not show the editor by default since we are testing.
@@ -189,20 +163,31 @@ parser = init_arguments(values, argument_defaults, arguments_visible)
# The TOOLTIP_ARGS value is created from the help information about the arguments.
#
TOOLTIP_ARGS = parser.format_help()
#
# Create another parser just to get a list of all possible arguments
# that may be output using --output_all_arguments.
#
all_arguments_visible = {}
for k in iter(arguments_visible):
all_arguments_visible[k] = True
all_visible = init_arguments(values, argument_defaults, all_arguments_visible)
def export(objectslist, filename, argstring):
"""Postprocess the objects in objectslist to filename."""
#
global all_visible
global parser
global UNITS
global values
# print(parser.format_help())
(flag, args) = PostUtilsArguments.process_shared_arguments(values, parser, argstring)
(flag, args) = PostUtilsArguments.process_shared_arguments(
values, parser, argstring, all_visible, filename
)
if not flag:
return None
return args
#
# Process any additional arguments here
#

File diff suppressed because it is too large Load Diff