Commit e5819cfd authored by sumpfralle's avatar sumpfralle

added a GUI control for defining the "safety height" of the machine

changed the gcode exporter code to allow a specific definition of the safety height (instead of previous "max(safetyheight, homeheight, startz)")
moved "startz" offset (based on the configured measurement unit) from SimpleGCodeExporter to the Gui code to allow more control
slight beautification of the gcode exporter code (added spaces between operators and after commas - according to PEP 8)


git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@165 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent 282c6af4
...@@ -5,42 +5,40 @@ from gcode import gcode ...@@ -5,42 +5,40 @@ from gcode import gcode
class SimpleGCodeExporter: class SimpleGCodeExporter:
def __init__(self, filename, unit, x, y, z, feedrate, speed): def __init__(self, filename, unit, startx, starty, startz, feedrate, speed, safety_height=None):
self.file = file(filename,"w") self.file = file(filename,"w")
if unit == "mm": if unit == "mm":
self.file.write("G21\n") self.file.write("G21\n")
z += 7.0
else: else:
self.file.write("G20\n") self.file.write("G20\n")
z += 0.25 self.gcode = gcode(startx, starty, startz, safetyheight=safety_height)
self.gcode = gcode(x,y,z)
gc = self.gcode gc = self.gcode
self.file.write(gc.begin()+"\n") self.file.write(gc.begin() + "\n")
self.file.write("F"+str(feedrate)+"\n") self.file.write("F" + str(feedrate) + "\n")
self.file.write("S"+str(speed)+"\n") self.file.write("S" + str(speed) + "\n")
self.file.write(gc.safety()+"\n") self.file.write(gc.safety() + "\n")
def close(self): def close(self):
gc = self.gcode gc = self.gcode
self.file.write(gc.safety()+"\n") self.file.write(gc.safety() + "\n")
self.file.write(gc.end()+"\n") self.file.write(gc.end() + "\n")
self.file.close() self.file.close()
def AddPath(self, path): def AddPath(self, path):
gc = self.gcode gc = self.gcode
point = path.points[0] point = path.points[0]
self.file.write(gc.rapid(point.x,point.y,gc.safetyheight)+"\n") self.file.write(gc.rapid(point.x, point.y, gc.safetyheight) + "\n")
for point in path.points: for point in path.points:
self.file.write(gc.cut(point.x,point.y,point.z)+"\n") self.file.write(gc.cut(point.x, point.y, point.z) + "\n")
self.file.write(gc.rapid(point.x,point.y,gc.safetyheight)+"\n") self.file.write(gc.rapid(point.x, point.y, gc.safetyheight) + "\n")
def AddPathList(self, pathlist): def AddPathList(self, pathlist):
for path in pathlist: for path in pathlist:
self.AddPath(path) self.AddPath(path)
def ExportPathList(filename, pathlist, unit, x, y, z, feedrate, speed): def ExportPathList(filename, pathlist, unit, startx, starty, startz, feedrate, speed, safety_height=None):
exporter = SimpleGCodeExporter(filename, unit, x, y, z, feedrate, speed) exporter = SimpleGCodeExporter(filename, unit, startx, starty, startz, feedrate, speed, safety_height)
exporter.AddPathList(pathlist) exporter.AddPathList(pathlist)
exporter.close() exporter.close()
...@@ -16,17 +16,20 @@ class gcode: ...@@ -16,17 +16,20 @@ class gcode:
lastx = lasty = lastz = lasta = lastgcode = None lastx = lasty = lastz = lasta = lastgcode = None
lastfeed = None lastfeed = None
def __init__(self, startx, starty, startz, homeheight = 1.5, safetyheight = 0.04): def __init__(self, startx, starty, startz, homeheight=1.5, safetyheight=None):
self.startx = startx self.startx = startx
self.starty = starty self.starty = starty
self.startz = startz self.startz = startz
self.homeheight = max(startz,homeheight) if safetyheight is None:
self.safetyheight = self.lastz = max(self.homeheight,safetyheight) safetyheight = max(max(startz, homeheight), 0.04)
self.homeheight = max(startz, homeheight)
self.safetyheight = safetyheight
self.lastz = max(self.homeheight, safetyheight)
def begin(self): def begin(self):
return "G40 G49 G54 G80 G90\n" + \ return "G40 G49 G54 G80 G90\n" + \
"G04 P3 T1 M6\n" + \ "G04 P3 T1 M6\n" + \
"G00 X%.4f Y%.4f Z%.4f\n" % (self.startx, self.starty, self.startz) "G00 X%.4f Y%.4f Z%.4f\n" % (self.startx, self.starty, self.startz)
def end(self): def end(self):
return self.safety() + "\n" + "M2\n" return self.safety() + "\n" + "M2\n"
......
...@@ -337,7 +337,8 @@ class ProjectGui: ...@@ -337,7 +337,8 @@ class ProjectGui:
("ToolRadiusControl", "tool_radius"), ("ToolRadiusControl", "tool_radius"),
("TorusRadiusControl", "torus_radius"), ("TorusRadiusControl", "torus_radius"),
("FeedrateControl", "feedrate"), ("FeedrateControl", "feedrate"),
("SpeedControl", "speed")): ("SpeedControl", "speed"),
("SafetyHeightControl", "safety_height")):
obj = self.gui.get_object(objname) obj = self.gui.get_object(objname)
self.settings.add_item(key, obj.get_value, obj.set_value) self.settings.add_item(key, obj.get_value, obj.set_value)
# connect buttons with activities # connect buttons with activities
...@@ -638,6 +639,8 @@ class ProjectGui: ...@@ -638,6 +639,8 @@ class ProjectGui:
def load_model(self, model): def load_model(self, model):
self.model = model self.model = model
# place the "safe height" clearly above the model's peak
self.settings.set("safety_height", (2 * self.model.maxz - self.model.minz))
# do some initialization # do some initialization
self.append_to_queue(self.reset_bounds) self.append_to_queue(self.reset_bounds)
self.append_to_queue(self.toggle_3d_view, True) self.append_to_queue(self.toggle_3d_view, True)
...@@ -759,7 +762,9 @@ class ProjectGui: ...@@ -759,7 +762,9 @@ class ProjectGui:
self.option = pycam.PathProcessors.PathAccumulator(zigzag=True) self.option = pycam.PathProcessors.PathAccumulator(zigzag=True)
else: else:
self.option = None self.option = None
self.pathgenerator = pycam.PathGenerators.DropCutter(self.cutter, self.model, self.option, physics=self.physics); self.pathgenerator = pycam.PathGenerators.DropCutter(self.cutter,
self.model, self.option, physics=self.physics,
safety_height=self.settings.get("safety_height"))
dx = x_shift dx = x_shift
dy = y_shift dy = y_shift
if direction == "x": if direction == "x":
...@@ -780,7 +785,8 @@ class ProjectGui: ...@@ -780,7 +785,8 @@ class ProjectGui:
self.option = pycam.PathProcessors.ContourCutter() self.option = pycam.PathProcessors.ContourCutter()
else: else:
self.option = None self.option = None
self.pathgenerator = pycam.PathGenerators.PushCutter(self.cutter, self.model, self.option, physics=self.physics); self.pathgenerator = pycam.PathGenerators.PushCutter(self.cutter,
self.model, self.option, physics=self.physics)
if pathprocessor == "ContourCutter": if pathprocessor == "ContourCutter":
dx = x_shift dx = x_shift
else: else:
...@@ -869,11 +875,17 @@ class ProjectGui: ...@@ -869,11 +875,17 @@ class ProjectGui:
return return
try: try:
fi = open(filename, "w") fi = open(filename, "w")
# TODO: fix these hard-coded offsets
if self.settings.get("unit") == 'mm':
start_offset = 7.0
else:
start_offset = 0.25
exporter = pycam.Exporters.SimpleGCodeExporter.ExportPathList( exporter = pycam.Exporters.SimpleGCodeExporter.ExportPathList(
filename, self.toolpath, self.settings.get("unit"), filename, self.toolpath, self.settings.get("unit"),
minx, miny, maxz, minx, miny, maxz + start_offset,
self.gui.get_object("FeedrateControl").get_value(), self.gui.get_object("FeedrateControl").get_value(),
self.gui.get_object("SpeedControl").get_value()) self.gui.get_object("SpeedControl").get_value(),
safety_height=self.settings.get("safety_height"))
fi.close() fi.close()
if self.no_dialog: if self.no_dialog:
print "GCode file successfully written: %s" % str(filename) print "GCode file successfully written: %s" % str(filename)
......
...@@ -341,7 +341,14 @@ class SimpleGui(Tk.Frame): ...@@ -341,7 +341,14 @@ class SimpleGui(Tk.Frame):
maxy = float(self.settings.get("maxy"))+offset maxy = float(self.settings.get("maxy"))+offset
minz = float(self.settings.get("minz"))-offset minz = float(self.settings.get("minz"))-offset
maxz = float(self.settings.get("maxz"))+offset maxz = float(self.settings.get("maxz"))+offset
exporter = SimpleGCodeExporter.ExportPathList(filename, self.toolpath, self.settings.get("unit"), minx, miny, maxz, self.FeedRate.get(), self.Speed.get()) if self.settings.get("unit") == 'mm':
start_offset = 7.0
else:
start_offset = 0.25
exporter = SimpleGCodeExporter.ExportPathList(filename,
self.toolpath, self.settings.get("unit"),
minx, miny, maxz + start_offset,
self.FeedRate.get(), self.Speed.get())
def createWidgets(self): def createWidgets(self):
self.ogl = OpenglWidget(self, width=600, height=500, double=1) self.ogl = OpenglWidget(self, width=600, height=500, double=1)
......
...@@ -1212,6 +1212,7 @@ ...@@ -1212,6 +1212,7 @@
<property name="invisible_char">&#x2022;</property> <property name="invisible_char">&#x2022;</property>
<property name="adjustment">toolradius</property> <property name="adjustment">toolradius</property>
<property name="digits">3</property> <property name="digits">3</property>
<property name="numeric">True</property>
</object> </object>
<packing> <packing>
<property name="left_attach">1</property> <property name="left_attach">1</property>
...@@ -1227,6 +1228,7 @@ ...@@ -1227,6 +1228,7 @@
<property name="invisible_char">&#x2022;</property> <property name="invisible_char">&#x2022;</property>
<property name="adjustment">torusradius</property> <property name="adjustment">torusradius</property>
<property name="digits">3</property> <property name="digits">3</property>
<property name="numeric">True</property>
</object> </object>
<packing> <packing>
<property name="left_attach">1</property> <property name="left_attach">1</property>
...@@ -1299,6 +1301,7 @@ ...@@ -1299,6 +1301,7 @@
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="invisible_char">&#x2022;</property> <property name="invisible_char">&#x2022;</property>
<property name="adjustment">feedrate</property> <property name="adjustment">feedrate</property>
<property name="numeric">True</property>
</object> </object>
<packing> <packing>
<property name="left_attach">1</property> <property name="left_attach">1</property>
...@@ -1311,6 +1314,7 @@ ...@@ -1311,6 +1314,7 @@
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="invisible_char">&#x2022;</property> <property name="invisible_char">&#x2022;</property>
<property name="adjustment">speed</property> <property name="adjustment">speed</property>
<property name="numeric">True</property>
</object> </object>
<packing> <packing>
<property name="left_attach">1</property> <property name="left_attach">1</property>
...@@ -1660,7 +1664,7 @@ Only available for the Push Cutter.</property> ...@@ -1660,7 +1664,7 @@ Only available for the Push Cutter.</property>
<child> <child>
<object class="GtkTable" id="table7"> <object class="GtkTable" id="table7">
<property name="visible">True</property> <property name="visible">True</property>
<property name="n_rows">3</property> <property name="n_rows">4</property>
<property name="n_columns">2</property> <property name="n_columns">2</property>
<property name="column_spacing">2</property> <property name="column_spacing">2</property>
<property name="row_spacing">2</property> <property name="row_spacing">2</property>
...@@ -1671,6 +1675,8 @@ Only available for the Push Cutter.</property> ...@@ -1671,6 +1675,8 @@ Only available for the Push Cutter.</property>
<property name="label" translatable="yes">Overlap [%]:</property> <property name="label" translatable="yes">Overlap [%]:</property>
</object> </object>
<packing> <packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property> <property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property> <property name="y_options">GTK_FILL</property>
</packing> </packing>
...@@ -1681,10 +1687,13 @@ Only available for the Push Cutter.</property> ...@@ -1681,10 +1687,13 @@ Only available for the Push Cutter.</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="invisible_char">&#x2022;</property> <property name="invisible_char">&#x2022;</property>
<property name="adjustment">OverlapPercentValue</property> <property name="adjustment">OverlapPercentValue</property>
<property name="numeric">True</property>
</object> </object>
<packing> <packing>
<property name="left_attach">1</property> <property name="left_attach">1</property>
<property name="right_attach">2</property> <property name="right_attach">2</property>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property> <property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property> <property name="y_options">GTK_FILL</property>
</packing> </packing>
...@@ -1696,8 +1705,8 @@ Only available for the Push Cutter.</property> ...@@ -1696,8 +1705,8 @@ Only available for the Push Cutter.</property>
<property name="label" translatable="yes">Material Allowance:</property> <property name="label" translatable="yes">Material Allowance:</property>
</object> </object>
<packing> <packing>
<property name="top_attach">1</property> <property name="top_attach">2</property>
<property name="bottom_attach">2</property> <property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property> <property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property> <property name="y_options">GTK_FILL</property>
</packing> </packing>
...@@ -1712,12 +1721,13 @@ ODE support is currently required for this feature.</property> ...@@ -1712,12 +1721,13 @@ ODE support is currently required for this feature.</property>
<property name="invisible_char">&#x2022;</property> <property name="invisible_char">&#x2022;</property>
<property name="adjustment">MaterialAllowanceValue</property> <property name="adjustment">MaterialAllowanceValue</property>
<property name="digits">2</property> <property name="digits">2</property>
<property name="numeric">True</property>
</object> </object>
<packing> <packing>
<property name="left_attach">1</property> <property name="left_attach">1</property>
<property name="right_attach">2</property> <property name="right_attach">2</property>
<property name="top_attach">1</property> <property name="top_attach">2</property>
<property name="bottom_attach">2</property> <property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property> <property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property> <property name="y_options">GTK_FILL</property>
</packing> </packing>
...@@ -1730,12 +1740,13 @@ ODE support is currently required for this feature.</property> ...@@ -1730,12 +1740,13 @@ ODE support is currently required for this feature.</property>
<property name="invisible_char">&#x2022;</property> <property name="invisible_char">&#x2022;</property>
<property name="adjustment">MaxStepDownValue</property> <property name="adjustment">MaxStepDownValue</property>
<property name="digits">2</property> <property name="digits">2</property>
<property name="numeric">True</property>
</object> </object>
<packing> <packing>
<property name="left_attach">1</property> <property name="left_attach">1</property>
<property name="right_attach">2</property> <property name="right_attach">2</property>
<property name="top_attach">2</property> <property name="top_attach">3</property>
<property name="bottom_attach">3</property> <property name="bottom_attach">4</property>
<property name="x_options">GTK_FILL</property> <property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property> <property name="y_options">GTK_FILL</property>
</packing> </packing>
...@@ -1747,8 +1758,35 @@ ODE support is currently required for this feature.</property> ...@@ -1747,8 +1758,35 @@ ODE support is currently required for this feature.</property>
<property name="label" translatable="yes">Max. Step Down:</property> <property name="label" translatable="yes">Max. Step Down:</property>
</object> </object>
<packing> <packing>
<property name="top_attach">2</property> <property name="top_attach">3</property>
<property name="bottom_attach">3</property> <property name="bottom_attach">4</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="SafetyHeightLabel">
<property name="visible">True</property>
<property name="xalign">0</property>
<property name="label" translatable="yes">Safe Height:</property>
</object>
<packing>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="SafetyHeightControl">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">&#x2022;</property>
<property name="adjustment">SafetyHeightValue</property>
<property name="digits">1</property>
<property name="numeric">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="x_options">GTK_FILL</property> <property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property> <property name="y_options">GTK_FILL</property>
</packing> </packing>
...@@ -2328,4 +2366,11 @@ Install the "python-pyode" package to enable this feature.</property> ...@@ -2328,4 +2366,11 @@ Install the "python-pyode" package to enable this feature.</property>
<property name="page_increment">10</property> <property name="page_increment">10</property>
<property name="page_size">10</property> <property name="page_size">10</property>
</object> </object>
<object class="GtkAdjustment" id="SafetyHeightValue">
<property name="lower">-1000</property>
<property name="upper">1000</property>
<property name="step_increment">1</property>
<property name="page_increment">10</property>
<property name="page_size">10</property>
</object>
</interface> </interface>
...@@ -2,22 +2,21 @@ from pycam.PathProcessors import * ...@@ -2,22 +2,21 @@ from pycam.PathProcessors import *
from pycam.Geometry import * from pycam.Geometry import *
from pycam.Geometry.intersection import intersect_lines from pycam.Geometry.intersection import intersect_lines
import pycam.PathGenerators import pycam.PathGenerators
from pycam.Geometry.utils import INFINITE
import sys import sys
class DropCutter: class DropCutter:
def __init__(self, cutter, model, PathProcessor=None, physics=None): def __init__(self, cutter, model, PathProcessor=None, physics=None, safety_height=INFINITE):
self.cutter = cutter self.cutter = cutter
self.model = model self.model = model
self.processor = PathProcessor self.processor = PathProcessor
self.physics = physics self.physics = physics
self.safety_height = safety_height
# used for the non-ode code # used for the non-ode code
self._triangle_last = None self._triangle_last = None
self._cut_last = None self._cut_last = None
# put the toolpath clearly above the model, if the model exceeds the
# bounding box at certain positions
self._safe_height = self.model.maxz + 4 * (self.model.maxz - self.model.minz)
# remember if we already reported an invalid boundary # remember if we already reported an invalid boundary
self._boundary_warning_already_shown = False self._boundary_warning_already_shown = False
...@@ -123,7 +122,7 @@ class DropCutter: ...@@ -123,7 +122,7 @@ class DropCutter:
self.physics.set_drill_position((x.get(), y.get(), dim_height.start)) self.physics.set_drill_position((x.get(), y.get(), dim_height.start))
if self.physics.check_collision(): if self.physics.check_collision():
# the object fills the whole range of z0..z1 - we should issue a warning # the object fills the whole range of z0..z1 - we should issue a warning
next_point = Point(x.get(), y.get(), self._safe_height) next_point = Point(x.get(), y.get(), self.safety_height)
if not self._boundary_warning_already_shown: if not self._boundary_warning_already_shown:
print >>sys.stderr, "WARNING: DropCutter exceed the height" \ print >>sys.stderr, "WARNING: DropCutter exceed the height" \
+ " of the boundary box: using a safe height " \ + " of the boundary box: using a safe height " \
...@@ -149,7 +148,7 @@ class DropCutter: ...@@ -149,7 +148,7 @@ class DropCutter:
box_y_min = p.y - self.cutter.radius box_y_min = p.y - self.cutter.radius
box_y_max = p.y + self.cutter.radius box_y_max = p.y + self.cutter.radius
box_z_min = dim_height.end box_z_min = dim_height.end
box_z_max = self._safe_height box_z_max = self.safety_height
triangles = self.model.triangles(box_x_min, box_y_min, box_z_min, box_x_max, box_y_max, box_z_max) triangles = self.model.triangles(box_x_min, box_y_min, box_z_min, box_x_max, box_y_max, box_z_max)
for t in triangles: for t in triangles:
if t.normal().z < 0: continue; if t.normal().z < 0: continue;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment