Swapping over to dual motor

master^2
MitchellHansen 6 years ago
parent 9556d61613
commit fd5940d766

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="TestRunnerService">
<option name="PROJECT_TEST_RUNNER" value="Unittests" />
</component>
</module>

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6 (Trac3r)" project-jdk-type="Python SDK" />
</project>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/Trac3r.iml" filepath="$PROJECT_DIR$/.idea/Trac3r.iml" />
</modules>
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

@ -1,34 +1,26 @@
import cairo, os, math
# This renderer takes the generated GCODE and turns it into two images
# One is an SVG of the tool paths, the other a png image
class Renderer():
def __init__(self, settings):
self.settings = settings
self.svg_surface = cairo.SVGSurface("tmp/rendered-output-t.svg", self.settings.bed_actual_x, self.settings.bed_actual_y)
self.svg_surface = cairo.SVGSurface("tmp/rendered-output-t.svg", self.settings.canvas_x, self.settings.canvas_y)
self.svg_context = cairo.Context(self.svg_surface)
self.svg_context.scale(1, 1)
self.svg_context.set_line_width(0.1)
def clear_screen(self):
self.svg_context.rectangle(0, 0, self.settings.bed_actual_x, self.settings.bed_actual_y)
self.svg_context.rectangle(0, 0, self.settings.canvas_x, self.settings.canvas_y)
self.svg_context.set_source_rgba(1, 1, 1, 1.0)
self.svg_context.fill()
self.svg_context.set_source_rgba(0, 0, 0, 1.0)
self.svg_context.stroke()
self.svg_context.set_source_rgba(1, 0, 0, 1.0)
self.svg_context.line_to(self.settings.bed_min_x - self.settings.head_x_offset, self.settings.bed_min_y)
self.svg_context.line_to(self.settings.bed_max_x - self.settings.head_x_offset, self.settings.bed_min_y)
self.svg_context.line_to(self.settings.bed_max_x - self.settings.head_x_offset, self.settings.bed_max_y)
self.svg_context.line_to(self.settings.bed_min_x - self.settings.head_x_offset, self.settings.bed_max_y)
self.svg_context.line_to(self.settings.bed_min_x - self.settings.head_x_offset, self.settings.bed_min_y)
self.svg_context.stroke()
self.svg_context.set_source_rgba(0, 0, 0, 1.0)
# Render GCODE from the gcode-output.gcode output file that was generated in convert_gcode
def render_gcode(self):
@ -60,14 +52,16 @@ class Renderer():
y = float(operand[1:])
if y > largest_y: largest_y = y
if y < smallest_y: smallest_y = y
elif operand.startswith("Z{}".format(self.settings.touch_height + self.settings.raise_height)):
elif operand.startswith("Z{}".format(1)):
# signify a lift
if prev_x is not None and prev_y is not None and self.settings.lift_markers:
self.svg_context.arc(prev_x - self.settings.head_x_offset, prev_y, 0.5, 0, 2 * math.pi)
# draw a cirlce at the lift
self.svg_context.arc(prev_x, prev_y, 0.5, 0, 2 * math.pi)
self.svg_context.stroke()
# And draw the lift number
self.svg_context.set_source_rgba(1, 1, 1, 1.0)
self.svg_context.select_font_face("Purisa", cairo.FONT_SLANT_NORMAL,
cairo.FONT_WEIGHT_NORMAL)
@ -104,15 +98,6 @@ class Renderer():
if smallest_y < self.settings.bed_min_y:
print("Y_UNDERFLOW")
self.svg_context.set_source_rgba(0, 0, 1, 1.0)
self.svg_context.line_to(smallest_x - self.settings.head_x_offset, smallest_y)
self.svg_context.line_to(largest_x - self.settings.head_x_offset, smallest_y)
self.svg_context.line_to(largest_x - self.settings.head_x_offset, largest_y)
self.svg_context.line_to(smallest_x - self.settings.head_x_offset, largest_y)
self.svg_context.line_to(smallest_x - self.settings.head_x_offset, smallest_y)
self.svg_context.stroke()
self.svg_context.set_source_rgba(0, 0, 0, 1.0)
self.save_surfaces()
# self.init_surfaces()

@ -0,0 +1,50 @@
import subprocess, os, time
class ImageConverter:
class ConverterSettings:
def __init__(self):
# mkbitmap settings
self.highpass_filter = 0
self.blur = 0
# This function takes a file and runs it through mogrify, mkbitmap, and finally potrace.
# The flow of the intermediate files is
# input_file.extension : The input file
# input_file.bmp : The input file converted to bmp
# input_file-n.bmp : The bmp file after running through some filters
# input_file.svg : The output svg render
def convert_image(self, file_name, settings):
base_name = file_name.split(".")[0]
print("Converting input file [{}]".format(file_name))
print("Running mogrify...")
start = time.time()
subprocess.call(["mogrify", "-format", "bmp", "input-images/{}".format(file_name)])
print("Run took [{:.2f}] seconds".format(time.time() - start))
print("Running mkbitmap...")
start = time.time()
mkbitmap_args = ["mkbitmap", "input-images/{}.bmp".format(base_name),
"-o", "input-images/{}-n.pbm".format(base_name)]
if settings.highpass_filter > 0:
mkbitmap_args.append(["-f", settings.highpass_filter])
if settings.blur > 0:
mkbitmap_args.append(["-b", settings.blur])
subprocess.call(mkbitmap_args)
print("Run took [{:.2f}] seconds".format(time.time() - start))
print("Running potrace...")
start = time.time()
subprocess.call(["potrace",
# "-t", "0.1",
"-z", "white",
"-b", "svg",
"input-images/{}-n.pbm".format(base_name),
"--rotate", "0",
"-o", "tmp/conversion-output.svg",
])
print("Run took [{:.2f}] seconds\n".format(time.time() - start))

@ -22,14 +22,14 @@ class Svg2GcodeConverter:
G28 ; home all axes
G0 F{1} ; Set the feed rate
G1 Z{0} ; Move the pen to just above the paper
'''.format(self.settings.touch_height + self.settings.raise_height, self.settings.speed)
'''.format(1, self.settings.speed)
self.gcode_end = '''
G1 Z{0} F7000 ; Raise the pen high up so we can fit a cap onto it
M104 S0 ; Set the nozzle to 0
G28 X0 Y0 ; Home back to (0,0) for (x,y)
M84 ; Turn off the motors
'''.format(75)
'''.format(1)
# From an input svg file, convert the vector svg paths to gcode tool paths
def convert_gcode(self):
@ -70,8 +70,8 @@ class Svg2GcodeConverter:
max_x_dim = max(bounding_x_max, bounding_x_min)
max_y_dim = max(bounding_y_max, bounding_y_min)
scale_x = (self.settings.bed_max_x - self.settings.bed_min_x) / max_x_dim
scale_y = (self.settings.bed_max_y - self.settings.bed_min_y) / max_y_dim
scale_x = self.settings.canvas_x / max_x_dim
scale_y = self.settings.canvas_y / max_y_dim
scale = min(scale_x, scale_y)
print("Scaling to : {:.5f}\n".format(scale))
@ -91,11 +91,11 @@ class Svg2GcodeConverter:
start = part.start
end = part.end
start_x = start.real * scale + self.settings.offset_x
start_y = start.imag * scale + self.settings.offset_y
start_x = start.real * scale
start_y = start.imag * scale
end_x = end.real * scale + self.settings.offset_x
end_y = end.imag * scale + self.settings.offset_y
end_x = end.real * scale
end_y = end.imag * scale
# Check to see if the endpoint of the last cycle continues and whether we need to lift the pen or not
lift = True
@ -109,7 +109,7 @@ class Svg2GcodeConverter:
previous_y = end.imag
if lift:
gcode += "G1 Z{:.3f}\n".format(self.settings.raise_height + self.settings.touch_height)
gcode += "G1 Z{:.3f}\n".format(1)
else:
gcode += ";# NOT LIFTING [{}]\n".format(self.settings.lift_counter)
@ -128,16 +128,16 @@ class Svg2GcodeConverter:
evals.append(curve.evaluate(i))
gcode += "G1 X{:.3f} Y{:.3f}\n".format(start_x, start_y)
gcode += "G1 Z{:.3f} \n".format(self.settings.touch_height)
gcode += "G1 Z{:.3f} \n".format(0)
for i in evals:
x = i[0][0]
y = i[1][0]
gcode += "G1 X{:.3f} Y{:.3f}\n".format(x * scale + self.settings.offset_x, y * scale + self.settings.offset_y)
gcode += "G1 X{:.3f} Y{:.3f}\n".format(x * scale, y * scale)
if isinstance(part, Line):
gcode += "G1 X{:.3f} Y{:.3f}\n".format(start_x, start_y)
gcode += "G1 Z{:.3f} \n".format(self.settings.touch_height)
gcode += "G1 Z{:.3f} \n".format(0)
gcode += "G1 X{:.3f} Y{:.3f}\n".format(end_x, end_y)
gcode += self.gcode_end

@ -3,43 +3,43 @@ from tkinter import filedialog
from tkinter.ttk import Notebook
from PIL import Image, ImageTk
import subprocess, os, time
import os
from Renderer import Renderer
from GCodeRenderer import Renderer
from Svg2GcodeConverter import Svg2GcodeConverter
from ImageConverter import ImageConverter
class Settings:
def __init__(self):
# Height at which the pen touches and draws on the surface
self.touch_height = 12
# How far to raise the pen tip to raise it off the page
self.raise_height = 2
# The inherent offset from true 0 we have from the pen bracket
self.head_x_offset = 50
# XY movement speed
# ============ HARDCODED VALUES ===========
# Canvas size
self.canvas_x = 300
self.canvas_y = 300
# The position of the pulley centers in relation to the top left and right of the canvas
self.left_pulley_xy_offset = (-40, 40)
self.right_pulley_xy_offset = (40, 40)
# Diameter of the inner portion of the pulley in millimeters
self.pulley_diameter = 45
# Feed rates
self.speed = 1000
# Whether we render lift markers
self.lift_markers = False
# X and Y offsets to place the image on A11 paper
self.offset_x = 70 + self.head_x_offset
self.offset_y = 20
# ============ CALCULATED VALUES ===========
# Bed dimensions to fit A11 paper
self.bed_max_x = 300 - 70 + self.head_x_offset + 20 # 20 is to adjust for the misalignment of print bed
self.bed_min_x = self.offset_x
self.bed_max_y = 280
self.bed_min_y = 20
self.distance_between_centers = abs(self.left_pulley_xy_offset[0]) + self.canvas_x + self.right_pulley_xy_offset[0]
self.bed_actual_x = 300
self.bed_actual_y = 300
self.lift_counter = 0
# Main GUI class and program entry point
class Tracer(Tk):
def update_highpass_value(self, value):
@ -48,6 +48,7 @@ class Tracer(Tk):
def update_blur_value(self, value):
self.blur = value
def __init__(self):
super().__init__()
@ -58,15 +59,21 @@ class Tracer(Tk):
if not os.path.exists("tmp"):
os.makedirs("tmp")
# Settings for the printer are loaded, TODO: Customize for our dual motor printer
self.settings = Settings()
# Image filename which we are converting
self.filename = None
# GCODE -> SVG,PNG renderer
self.cairo_renderer = Renderer(self.settings)
# SVG -> GCODE converter
self.gcode_converter = Svg2GcodeConverter(self.settings)
self.highpass_filter = 0
self.blur = 0
# FILE -> SVG converter
self.image_converter = ImageConverter()
self.image_converter_settings = ImageConverter.ConverterSettings()
self.label = None
self.pix = None
@ -95,17 +102,18 @@ class Tracer(Tk):
self.lift_markers_checkbox.pack()
self.highpass_slider = Scale(self.rightframe, command=self.update_highpass_value, resolution=0.1, to=15)
self.highpass_slider.set(self.highpass_filter)
self.highpass_slider.set(self.image_converter_settings.highpass_filter)
self.highpass_slider.pack()
self.blur_slider = Scale(self.rightframe, command=self.update_blur_value, resolution=0.1, to=5)
self.blur_slider.set(self.blur)
self.blur_slider.set(self.image_converter_settings.blur)
self.blur_slider.pack()
# Start TK
self.mainloop()
def file_select_callback(self):
filepath = filedialog.askopenfilename(initialdir=".", title="Select file",
filetypes=(("jpeg files", "*.jpg"), ("all files", "*.*")))
@ -120,7 +128,7 @@ class Tracer(Tk):
self.render()
def render(self):
self.convert_image(self.filename)
self.image_converter.convert_image(self.filename)
self.gcode_converter.convert_gcode()
self.cairo_renderer.clear_screen()
@ -150,48 +158,7 @@ class Tracer(Tk):
self.label1.pack(expand=True, fill="both")
# This function takes a file and runs it through mogrify, mkbitmap, and finally potrace.
# The flow of the intermediate files is
# input_file.extension : The input file
# input_file.bmp : The input file converted to bmp
# input_file-n.bmp : The bmp file after running through some filters
# input_file.svg : The output svg render
def convert_image(self, file_name):
base_name = file_name.split(".")[0]
print("Converting input file [{}]".format(file_name))
print("Running mogrify...")
start = time.time()
subprocess.call(["mogrify", "-format", "bmp", "input-images/{}".format(file_name)])
print("Run took [{:.2f}] seconds".format(time.time() - start))
print("Running mkbitmap...")
start = time.time()
mkbitmap_args = ["mkbitmap", "input-images/{}.bmp".format(base_name),
"-o", "input-images/{}-n.pbm".format(base_name)]
if self.highpass_filter > 0:
mkbitmap_args.append(["-f", self.highpass_filter])
if self.blur > 0:
mkbitmap_args.append(["-b", self.blur])
subprocess.call(mkbitmap_args)
print("Run took [{:.2f}] seconds".format(time.time() - start))
print("Running potrace...")
start = time.time()
subprocess.call(["potrace",
#"-t", "0.1",
"-z", "white",
"-b", "svg",
"input-images/{}-n.pbm".format(base_name),
"--rotate", "0",
"-o", "tmp/conversion-output.svg",
])
print("Run took [{:.2f}] seconds\n".format(time.time() - start))
if __name__ == "__main__":

Loading…
Cancel
Save