From a505e51617a62ed26bd62096d9faa62625cef1c0 Mon Sep 17 00:00:00 2001 From: ES-Alexander Date: Sun, 20 Feb 2022 18:45:42 +1100 Subject: [PATCH 1/5] ignore common unwanted files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d02b995 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.gcode +**__pycache__** From b6dd50373ebe2621b4628621da9fd483147d8df8 Mon Sep 17 00:00:00 2001 From: ES-Alexander Date: Sun, 20 Feb 2022 18:46:36 +1100 Subject: [PATCH 2/5] refactor spline functionality, improve performance --- bend_gcode.py | 69 +++++++++++---------------------------------------- spline.py | 55 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 55 deletions(-) create mode 100644 spline.py diff --git a/bend_gcode.py b/bend_gcode.py index 3139d3a..4394b24 100644 --- a/bend_gcode.py +++ b/bend_gcode.py @@ -5,10 +5,11 @@ @author: stefa """ +from spline import Spline import numpy as np import math -from scipy.interpolate import CubicSpline -import matplotlib.pyplot as plt +#from scipy.interpolate import CubicSpline +#import matplotlib.pyplot as plt import re from collections import namedtuple @@ -26,33 +27,18 @@ #2-point spline SPLINE_X = [125, 95] SPLINE_Z = [0, 140] +BEND_ANGLE = -30 # degrees, at the top point #4-point spline example #SPLINE_X = [150, 156,144,150] #SPLINE_Z = [0,30,60,90] - -SPLINE = CubicSpline(SPLINE_Z, SPLINE_X, bc_type=((1, 0), (1, -np.pi/6))) #define spline with BC-conditions -#SPLINE = CubicSpline(SPLINE_Z, SPLINE_X, bc_type=((1, 0), (1, -0.5235988))) #bent 30° - DISCRETIZATION_LENGTH = 0.01 #discretization length for the spline length lookup table ################# USER INPUT PARAMETERS END ######################### - -SplineLookupTable = [0.0] - -nx = np.arange(0,SPLINE_Z[-1],1) - -xs = np.arange(0,SPLINE_Z[-1],1) -fig, ax = plt.subplots(figsize=(6.5, 4)) -ax.plot(SPLINE_X, SPLINE_Z, 'o', label='data') -ax.plot(SPLINE(xs), xs, label="S") -ax.set_xlim(0, 200) -ax.set_ylim(0, 200) -plt.gca().set_aspect('equal', adjustable='box') -# ax.legend(loc='lower left', ncol=2) -plt.show() +spline = Spline(SPLINE_X, SPLINE_Z, DISCRETIZATION_LENGTH) +spline.plot() def getNormalPoint(currentPoint: Point2D, derivative: float, distance: float) -> Point2D: #claculates the normal of a point on the spline @@ -73,40 +59,12 @@ def writeLine(G, X, Y, Z, F = None, E = None): #write a line to the output file outputSting = outputSting + " F" + str(int(float(F))) outputFile.write(outputSting + "\n") -""" -# legacy - toooo slow! -def onSplineLength(Zheight) -> float: #calculates a new z height if the spline is followed - return Zheight #for debugging - discretizationLength = 0.01 #Steps taken to find the spline height - currentHeight = 0.00 - currentLength = 0.00 - while currentLength < Zheight: - currentLength += np.sqrt((SPLINE(currentHeight)-SPLINE(currentHeight+discretizationLength))**2 + discretizationLength**2) - currentHeight += discretizationLength - return currentHeight -""" - -def onSplineLength(Zheight) -> float: #calculates a new z height if the spline is followed - for i in range(len(SplineLookupTable)): - height = SplineLookupTable[i] - if height >= Zheight: - return i * DISCRETIZATION_LENGTH - print("Error! Spline not defined high enough!") - -def createSplineLookupTable(): - heightSteps = np.arange(DISCRETIZATION_LENGTH, SPLINE_Z[-1], DISCRETIZATION_LENGTH) - for i in range(len(heightSteps)): - height = heightSteps[i] - SplineLookupTable.append(SplineLookupTable[i] + np.sqrt((SPLINE(height)-SPLINE(height-DISCRETIZATION_LENGTH))**2 + DISCRETIZATION_LENGTH**2)) - - lastPosition = Point2D(0, 0) currentZ = 0.0 lastZ = 0.0 currentLayer = 0 relativeMode = False -createSplineLookupTable() with open(INPUT_FILE_NAME, "r") as gcodeFile, open(OUTPUT_FILE_NAME, "w+") as outputFile: for currentLine in gcodeFile: @@ -145,15 +103,16 @@ def createSplineLookupTable(): distToSpline = midpointX - SPLINE_X[0] #Correct the z-height if the spline gets followed - correctedZHeight = onSplineLength(currentZ) - - angleSplineThisLayer = np.arctan(SPLINE(correctedZHeight, 1)) #inclination angle this layer - - angleLastLayer = np.arctan(SPLINE(correctedZHeight - LAYER_HEIGHT, 1)) # inclination angle previous layer + correctedZHeight = spline.projected_length(currentZ)#onSplineLength(currentZ) + + angleSplineThisLayer = spline.inclination_angle(correctedZHeight) + #angleSplineThisLayer = np.arctan(SPLINE(correctedZHeight, 1)) #inclination angle this layer + angleLastLayer = spline.inclination_angle(correctedZHeight - LAYER_HEIGHT) + #angleLastLayer = np.arctan(SPLINE(correctedZHeight - LAYER_HEIGHT, 1)) # inclination angle previous layer heightDifference = np.sin(angleSplineThisLayer - angleLastLayer) * distToSpline * -1 # layer height difference - transformedGCode = getNormalPoint(Point2D(correctedZHeight, SPLINE(correctedZHeight)), SPLINE(correctedZHeight, 1), currentPosition.x - SPLINE_X[0]) + transformedGCode = getNormalPoint(Point2D(correctedZHeight, spline.x_at(correctedZHeight)), spline.x_at(correctedZHeight, 1), currentPosition.x - SPLINE_X[0]) #Check if a move is below Z = 0 if float(transformedGCode.x) <= 0.0: @@ -184,4 +143,4 @@ def createSplineLookupTable(): lastZ = currentZ else: outputFile.write(currentLine) -print("GCode bending finished!") \ No newline at end of file +print("GCode bending finished!") diff --git a/spline.py b/spline.py new file mode 100644 index 0000000..c9a97e9 --- /dev/null +++ b/spline.py @@ -0,0 +1,55 @@ +from scipy.interpolate import CubicSpline +from functools import lru_cache +import matplotlib.pyplot as plt +import numpy as np + +class Spline: + def __init__(self, X, Z, discretization_length=0.01, bend_angle=-30): + self.X, self.Z = X, Z + bc_type = ((1, 0), (1, np.radians(bend_angle))) + self.x_at = CubicSpline(self.Z, self.X, bc_type=bc_type) + self.discretization_length = discretization_length + + self._create_lookup_table() + # lines will often be at the same height as other lines + # -> may as well cache length computations so they can be reused + self.projected_length = lru_cache(maxsize=5)(self.projected_length) + + def _create_lookup_table(self): + # start with evenly spaced heights + # one extra length at the bottom simplifies later results + heights = np.arange(self.Z[0] - self.discretization_length, + self.Z[-1], self.discretization_length) + # determine actual height differences due to spline bending + x_values = self.x_at(heights) + height_deltas = np.sqrt(np.diff(x_values)**2 + + self.discretization_length**2) + # redetermine heights using the deltas + # set initial value to 0 + height_deltas[0] = 0 + self._lookup = height_deltas.cumsum() + + def projected_length(self, z): + """ Returns the length of height 'z' projected along the spline. """ + try: + # use the position of the first lookup match, assuming there is one + return (np.where(z <= self._lookup)[0][0] + * self.discretization_length) + except IndexError as e: # there wasn't one + raise IndexError(f"{z} mm outside defined spline range") from e + + def inclination_angle(self, z): + return np.arctan(self.x_at(z, 1)) + + def plot(self, spacing=1, printer_dims=(200, 200), + ax=None, figsize=(6.5, 4), show=True): + z_values = np.arange(self.Z[0], self.Z[-1], spacing) + x_values = self.x_at(z_values) + ax = ax or plt.subplots(figsize=figsize)[1] + ax.plot(self.X, self.Z, 'o', label='data') + ax.plot(x_values, z_values, label='S') + ax.set_xlim(0, printer_dims[0]) + ax.set_ylim(0, printer_dims[1]) + ax.set_aspect('equal', adjustable='box') + if show: + plt.show() From 7c2d91dc5aa4b33c4b8c7b469a14f1cfbb70b6f4 Mon Sep 17 00:00:00 2001 From: ES-Alexander Date: Sun, 20 Feb 2022 23:39:21 +1100 Subject: [PATCH 3/5] incorporate extra functionality, add caching --- spline.py | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/spline.py b/spline.py index c9a97e9..9150def 100644 --- a/spline.py +++ b/spline.py @@ -1,5 +1,5 @@ from scipy.interpolate import CubicSpline -from functools import lru_cache +from functools import lru_cache, wraps import matplotlib.pyplot as plt import numpy as np @@ -7,13 +7,15 @@ class Spline: def __init__(self, X, Z, discretization_length=0.01, bend_angle=-30): self.X, self.Z = X, Z bc_type = ((1, 0), (1, np.radians(bend_angle))) - self.x_at = CubicSpline(self.Z, self.X, bc_type=bc_type) + self._spline = CubicSpline(self.Z, self.X, bc_type=bc_type) self.discretization_length = discretization_length self._create_lookup_table() # lines will often be at the same height as other lines - # -> may as well cache length computations so they can be reused - self.projected_length = lru_cache(maxsize=5)(self.projected_length) + # -> may as well cache computations so they can be reused + self.x_at = lru_cache(maxsize=128)(self.x_at) + self.projected_length = lru_cache(maxsize=8)(self.projected_length) + self.inclination_angle = lru_cache(maxsize=32)(self.inclination_angle) def _create_lookup_table(self): # start with evenly spaced heights @@ -21,7 +23,7 @@ def _create_lookup_table(self): heights = np.arange(self.Z[0] - self.discretization_length, self.Z[-1], self.discretization_length) # determine actual height differences due to spline bending - x_values = self.x_at(heights) + x_values = self._spline(heights) height_deltas = np.sqrt(np.diff(x_values)**2 + self.discretization_length**2) # redetermine heights using the deltas @@ -38,13 +40,28 @@ def projected_length(self, z): except IndexError as e: # there wasn't one raise IndexError(f"{z} mm outside defined spline range") from e + @wraps(CubicSpline.__call__) + def x_at(self, *args, **kwargs): + return self._spline(*args, **kwargs) + def inclination_angle(self, z): return np.arctan(self.x_at(z, 1)) + def normal_point(self, x, z): + """ Calculates the normal of a point on the spline. """ + distance = x - self.X[0] + derivative = self.x_at(z, 1) + + angle = np.arctan(derivative) + np.pi / 2 + return ( + z + distance * np.cos(angle), + self.x_at(z) + distance * np.sin(angle) + ) + def plot(self, spacing=1, printer_dims=(200, 200), ax=None, figsize=(6.5, 4), show=True): z_values = np.arange(self.Z[0], self.Z[-1], spacing) - x_values = self.x_at(z_values) + x_values = self._spline(z_values) ax = ax or plt.subplots(figsize=figsize)[1] ax.plot(self.X, self.Z, 'o', label='data') ax.plot(x_values, z_values, label='S') @@ -52,4 +69,4 @@ def plot(self, spacing=1, printer_dims=(200, 200), ax.set_ylim(0, printer_dims[1]) ax.set_aspect('equal', adjustable='box') if show: - plt.show() + plt.pause(0.5) From f78bac007c3376161c5d66eaac93404620e70db7 Mon Sep 17 00:00:00 2001 From: ES-Alexander Date: Sun, 20 Feb 2022 23:39:55 +1100 Subject: [PATCH 4/5] refactor for clarity+performance, and add CLI --- bend_gcode.py | 208 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 124 insertions(+), 84 deletions(-) diff --git a/bend_gcode.py b/bend_gcode.py index 4394b24..adefed6 100644 --- a/bend_gcode.py +++ b/bend_gcode.py @@ -5,93 +5,91 @@ @author: stefa """ +from dataclasses import dataclass +from datetime import timedelta +from time import perf_counter +from typing import ClassVar from spline import Spline import numpy as np -import math -#from scipy.interpolate import CubicSpline -#import matplotlib.pyplot as plt import re -from collections import namedtuple -Point2D = namedtuple('Point2D', 'x y') -GCodeLine = namedtuple('GCodeLine', 'x y z e f') - -################# USER INPUT PARAMETERS ######################### - -INPUT_FILE_NAME = "pipe_mk2.gcode" -OUTPUT_FILE_NAME = "BENT_" + INPUT_FILE_NAME -LAYER_HEIGHT = 0.3 #Layer height of the sliced gcode -WARNING_ANGLE = 30 #Maximum Angle printable with your setup - -#2-point spline -SPLINE_X = [125, 95] -SPLINE_Z = [0, 140] -BEND_ANGLE = -30 # degrees, at the top point - -#4-point spline example -#SPLINE_X = [150, 156,144,150] -#SPLINE_Z = [0,30,60,90] - -DISCRETIZATION_LENGTH = 0.01 #discretization length for the spline length lookup table - -################# USER INPUT PARAMETERS END ######################### - -spline = Spline(SPLINE_X, SPLINE_Z, DISCRETIZATION_LENGTH) -spline.plot() - - -def getNormalPoint(currentPoint: Point2D, derivative: float, distance: float) -> Point2D: #claculates the normal of a point on the spline - angle = np.arctan(derivative) + math.pi /2 - return Point2D(currentPoint.x + distance * np.cos(angle), currentPoint.y + distance * np.sin(angle)) - -def parseGCode(currentLine: str) -> GCodeLine: #parse a G-Code line - thisLine = re.compile('(?i)^[gG][0-3](?:\s+x(?P-?[0-9.]{1,15})|\s+y(?P-?[0-9.]{1,15})|\s+z(?P-?[0-9.]{1,15})|\s+e(?P-?[0-9.]{1,15})|\s+f(?P-?[0-9.]{1,15}))*') - lineEntries = thisLine.match(currentLine) - if lineEntries: - return GCodeLine(lineEntries.group('x'), lineEntries.group('y'), lineEntries.group('z'), lineEntries.group('e'), lineEntries.group('f')) - -def writeLine(G, X, Y, Z, F = None, E = None): #write a line to the output file - outputSting = "G" + str(int(G)) + " X" + str(round(X,5)) + " Y" + str(round(Y,5)) + " Z" + str(round(Z,3)) - if E is not None: - outputSting = outputSting + " E" + str(round(float(E),5)) - if F is not None: - outputSting = outputSting + " F" + str(int(float(F))) - outputFile.write(outputSting + "\n") - - -lastPosition = Point2D(0, 0) -currentZ = 0.0 -lastZ = 0.0 -currentLayer = 0 -relativeMode = False - -with open(INPUT_FILE_NAME, "r") as gcodeFile, open(OUTPUT_FILE_NAME, "w+") as outputFile: - for currentLine in gcodeFile: +@dataclass +class Point2D: + x: float + y: float + +@dataclass +class GCodeLine: + x: float + y: float + z: float + e: float + f: int + + gcode_format: ClassVar[re.Pattern] = ( + re.compile('(?i)^[gG][0-3](?:\s' + '+x(?P-?[0-9.]{1,15})|\s' + '+y(?P-?[0-9.]{1,15})|\s' + '+z(?P-?[0-9.]{1,15})|\s' + '+e(?P-?[0-9.]{1,15})|\s' + '+f(?P-?[0-9.]{1,15}))*') + ) + + @classmethod + def from_gcode(cls, line: str): + line_entries = cls.gcode_format.match(line) + if line_entries: + return cls(*line_entries.groups()) + + +def main(in_file, out_file, spline, layer_height, warning_angle, + xy_precision=4, z_precision=3, e_precision=5): + + lastPosition = Point2D(0, 0) + currentZ = 0.0 + lastZ = 0.0 + currentLayer = 0 + relativeMode = False + + with open(in_file, "r") as gcodeFile, open(out_file, "w+") as outputFile: + def writeLine(G, X, Y, Z, E=None, F=None): + output = f'G{G} X{X:.{xy_precision}f} Y{Y:.{xy_precision}f} Z{Z:.{z_precision}f}' + if E is not None: + output += f" E{E:.{e_precision}f}" + if F is not None: + output += f" F{F}" + outputFile.write(output + '\n') + + print('Processing: (press CTRL+C to abort)') + start = perf_counter() + for index, currentLine in enumerate(gcodeFile): + if index % 1000 == 0: # track progress + print(f"[{timedelta(seconds=perf_counter()-start)}]: line {index}\r", end='') if currentLine[0] == ";": #if NOT a comment outputFile.write(currentLine) continue - if currentLine.find("G91 ") != -1: #filter relative commands + if currentLine.startswith("G91"): #filter relative commands relativeMode = True outputFile.write(currentLine) continue - if currentLine.find("G90 ") != -1: #set absolute mode + if currentLine.startswith("G90 "): #set absolute mode relativeMode = False outputFile.write(currentLine) continue if relativeMode: #if in relative mode don't do anything outputFile.write(currentLine) continue - currentLineCommands = parseGCode(currentLine) + currentLineCommands = GCodeLine.from_gcode(currentLine) if currentLineCommands is not None: #if current comannd is a valid gcode if currentLineCommands.z is not None: #if there is a z height in the command currentZ = float(currentLineCommands.z) - + if currentLineCommands.x is None or currentLineCommands.y is None: #if command does not contain x and y movement it#s probably not a print move if currentLineCommands.z is not None: #if there is only z movement (e.g. z-hop) - outputFile.write("G91\nG1 Z" + str(currentZ-lastZ)) + outputFile.write(f"G91\nG1 Z{currentZ - lastZ}") if currentLineCommands.f is not None: - outputFile.write(" F" + str(currentLineCommands.f)) + outputFile.write(f" F{currentLineCommands.f}") outputFile.write("\nG90\n") lastZ = currentZ continue @@ -100,47 +98,89 @@ def writeLine(G, X, Y, Z, F = None, E = None): #write a line to the output file currentPosition = Point2D(float(currentLineCommands.x), float(currentLineCommands.y)) midpointX = lastPosition.x + (currentPosition.x - lastPosition.x) / 2 #look for midpoint - distToSpline = midpointX - SPLINE_X[0] + distToSpline = midpointX - spline.X[0] #Correct the z-height if the spline gets followed - correctedZHeight = spline.projected_length(currentZ)#onSplineLength(currentZ) + correctedZHeight = spline.projected_length(currentZ) angleSplineThisLayer = spline.inclination_angle(correctedZHeight) - #angleSplineThisLayer = np.arctan(SPLINE(correctedZHeight, 1)) #inclination angle this layer - angleLastLayer = spline.inclination_angle(correctedZHeight - LAYER_HEIGHT) - #angleLastLayer = np.arctan(SPLINE(correctedZHeight - LAYER_HEIGHT, 1)) # inclination angle previous layer - + angleLastLayer = spline.inclination_angle(correctedZHeight - layer_height) heightDifference = np.sin(angleSplineThisLayer - angleLastLayer) * distToSpline * -1 # layer height difference - - transformedGCode = getNormalPoint(Point2D(correctedZHeight, spline.x_at(correctedZHeight)), spline.x_at(correctedZHeight, 1), currentPosition.x - SPLINE_X[0]) - + transformedGCode = Point2D(*spline.normal_point(currentPosition.x, correctedZHeight)) + #Check if a move is below Z = 0 if float(transformedGCode.x) <= 0.0: print("Warning! Movement below build platform. Check your spline!") #Detect unplausible moves if transformedGCode.x < 0 or np.abs(transformedGCode.x - currentZ) > 50: - print("Warning! Possibly unplausible move detected on height " + str(currentZ) + " mm!") + print(f"Warning! Possibly unplausible move detected on height {currentZ} mm!") outputFile.write(currentLine) - continue + continue #Check for self intersection - if (LAYER_HEIGHT + heightDifference) < 0: - print("ERROR! Self intersection on height " + str(currentZ) + " mm! Check your spline!") + if (layer_height + heightDifference) < 0: + print(f"ERROR! Self intersection on height {currentZ} mm! Check your spline!") #Check the angle of the printed layer and warn if it's above the machine limit - if angleSplineThisLayer > (WARNING_ANGLE * np.pi / 180.): - print("Warning! Spline angle is", (angleSplineThisLayer * 180. / np.pi), "at height ", str(currentZ), " mm! Check your spline!") + if angleSplineThisLayer > np.radians(warning_angle): + print(f"Warning! Spline angle is {np.degrees(angleSplineThisLayer)}, at height {currentZ} mm! Check your spline!") if currentLineCommands.e is not None: #if this is a line with extrusion """if float(currentLineCommands.e) < 0.0: print("Retraction")""" - extrusionAmount = float(currentLineCommands.e) * ((LAYER_HEIGHT + heightDifference)/LAYER_HEIGHT) - #outputFile.write(";was" + currentLineCommands.e + " is" + str(extrusionAmount) + " diff" + str(int(((LAYER_HEIGHT + heightDifference)/LAYER_HEIGHT)*100)) + "\n") + extrusionAmount = float(currentLineCommands.e) * ((layer_height + heightDifference)/layer_height) + #outputFile.write(";was" + currentLineCommands.e + " is" + str(extrusionAmount) + " diff" + str(int(((layer_height + heightDifference)/layer_height)*100)) + "\n") else: - extrusionAmount = None - writeLine(1,transformedGCode.y, currentPosition.y, transformedGCode.x, None, extrusionAmount) + extrusionAmount = None + writeLine(1,transformedGCode.y, currentPosition.y, transformedGCode.x, extrusionAmount, None) lastPosition = currentPosition lastZ = currentZ else: outputFile.write(currentLine) -print("GCode bending finished!") + + print("\nGCode bending finished!") + print(f"Processed {index} lines in {timedelta(seconds=perf_counter()-start)}") + +if __name__ == "__main__": + from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter + + parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter) + parser.add_argument("in_file", help="input file name (*.gcode)") + parser.add_argument("-o", "--out_file", help="output filename, default 'BENT_{in_file}'") + parser.add_argument("-x", "--x_values", default=(125, 95), nargs="*", type=float, + help=("x values that define the spline, space-separated (e.g. '125 50 33')." + " First should be in the center of your part.")) + parser.add_argument("-z", "--z_values", default=(0, 140), nargs="*", type=float, + help=("corresponding z values that define the spline, space-separated." + " First should be 0 (e.g. '0 80 140').")) + parser.add_argument("-l", "--layer_height", default=0.3, type=float, + help="layer height of the sliced gcode [mm].") + parser.add_argument("-a", "--warning_angle", default=30, type=float, + help="Maximum angle [degrees] printable with your setup") + parser.add_argument("-b", "--bend_angle", default=-30, type=float, + help="Angle [degrees] of the spline at the top point") + parser.add_argument("-d", "--discretization_length", default=0.01, type=float, + help="Discretization length for the spline length lookup table") + parser.add_argument("-s", "--skip_plot", action="store_true", + help="flag to skip plotting of the spline") + parser.add_argument("--xy_precision", type=int, default=4, + help="Decimals of precision to round x/y values to.") + parser.add_argument("--z_precision", type=int, default=3, + help="Decimals of precision to round z (height) values to.") + parser.add_argument("--e_precision", type=int, default=5, + help="Decimals of precision to round extrusion amounts to.") + parser.add_argument("--printer_dims", nargs=2, default=(200, 200), type=float, + help="printer width and height [mm], space-separated.") + + args = parser.parse_args() + + spline = Spline(args.x_values, args.z_values, args.discretization_length, + args.bend_angle) + if not args.skip_plot: + print("Press Q to close the plot and continue") + spline.plot(printer_dims=args.printer_dims) + + out_file = args.out_file or f"BENT_{args.in_file}" + + main(args.in_file, out_file, spline, args.layer_height, args.warning_angle, + args.xy_precision, args.z_precision, args.e_precision) From 5591b6da3368859f0f97bd0c1c1212544dff47f6 Mon Sep 17 00:00:00 2001 From: ES-Alexander Date: Mon, 21 Feb 2022 00:09:25 +1100 Subject: [PATCH 5/5] README: update to reflect CLI usage --- README.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d52eda6..ead05de 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,14 @@ # Usage - Place your part preferably in the middle of your print plate with known center X coordinates - Place the sliced GCode in the same directory as the Python script -- Set *INPUT_FILE_NAME* to your GCode file name -- Set *LAYER_HEIGHT* to your slicing layer height. Important, because you don't set it correctly you'll get under- or over extrusions -- Set *WARNING_ANGLE* to the maximum angle your system can print at due to clearances -- Define your spline with *SPLINE_X* and *SPLINE_Z*. This array can contain an arbitrary number of points. Make sure the first X-coordinate is in the center of your part. Make sure the last z coordinate is higher or equal the highest z-coordiante in your GCode. -- *SPLINE = CubicSpline(SPLINE_Z, SPLINE_X, bc_type=((1, 0), (1, -np.pi/6)))* defines the spline. You can alter the last pair of of *bc_type* (here *1,-np.pi/6*). This defines the final angle of your spline in RAD. \ No newline at end of file +- Run `bend_gcode.py` in your Terminal/Command Prompt + - Run `python3 bend_gcode.py --help` to see the available options (or `py bend_gcode.py --help`) + - Pass in your gcode file name as the first argument + - Set `-l` or `--layer_height` to your slicing layer height. + Important, because you don't set it correctly you'll get under- or over extrusions + - Set `-a` or `--warning_angle` to the maximum angle your system can print at due to clearances + - Define your spline with `-x`/`--x_values` and `-z`/`--z_values`, with at least two points. + - The first x-coordinate should be in the center of your part + - The first z-coordinate should be 0 (at the print bed) + - The last z-coordinate should be at or above the highest z-coordinate in your GCode + - `-b`/`--bend_angle` determines the angle of the spline at the last coordinate