printrun-src/printrun/laser.py

changeset 32
0abfa4642776
parent 28
23efe2c53872
child 33
eee51ca7cbe7
equal deleted inserted replaced
31:92035ebc4743 32:0abfa4642776
1 """ 1 """
2 Lasercutter library 2 Lasercutter library
3 2015-2016 by NeoSoft, Malte Di Donato 3 2015-2017 by NeoSoft, Malte Di Donato
4 Intended to use standalone or implemented in Pronterface/Printrun 4 Intended to use standalone or implemented in Pronterface/Printrun
5 """ 5 """
6 6
7 """ 7 """
8 LASERCUT SETTINGS 8 LASERCUT SETTINGS
16 16
17 17
18 # GENERAL HEADER AND FOOTER GCODE 18 # GENERAL HEADER AND FOOTER GCODE
19 GCODE_HEAD = """ 19 GCODE_HEAD = """
20 ; GCode generated by laser.py pronterface library (marlin code flavour) 20 ; GCode generated by laser.py pronterface library (marlin code flavour)
21 ; 2015/2016 by NeoSoft - Malte Bayer 21 ; 2015-2017 by NeoSoft - Malte Di Donato
22 22
23 G21 ; Metric 23 G21 ; Metric
24 ; We assume Z is in focus height and laser head is focus at bottom left of image! 24 ; We assume Z is in focus height and laser head is focus at bottom left of image!
25 G92 X0 Y0 E0; set zero position - new origin 25 G92 X0 Y0 E0; set zero position - new origin
26 G90 ; absolute positioning 26 G90 ; absolute positioning
28 M201 X1000 Y1000 E1000 ; Set acceleration 28 M201 X1000 Y1000 E1000 ; Set acceleration
29 M203 X1000 Y1000 Z4 E1000 ; Set max feedrate 29 M203 X1000 Y1000 Z4 E1000 ; Set max feedrate
30 M209 S0 ; disable firmware retraction, we dont want to burn holes... 30 M209 S0 ; disable firmware retraction, we dont want to burn holes...
31 M302 ; Allow cold extrudes - doesnt matter because we hack the extruder physically off with the M571 E mod 31 M302 ; Allow cold extrudes - doesnt matter because we hack the extruder physically off with the M571 E mod
32 M571 S1 E1 ; Activate Laser output on extrusion, but block real motor movement! 32 M571 S1 E1 ; Activate Laser output on extrusion, but block real motor movement!
33 M85 S0 ; Disable idle hold timeout
34 M84 ; enable motors
35
33 """ 36 """
34 37
35 GCODE_FOOT = """G0 X0 Y0 F%.4f 38 GCODE_FOOT = """
39 M42 P28 S0 ; Force laser off!
40 M85 S30 ; re-enable idle hold timeout
41 G0 X0 Y0 F%.4f ; Move back to origin
36 M400 ; Wait for all moves to finish 42 M400 ; Wait for all moves to finish
37 M571 S0 E0 43 M571 S0 E0 ; disable extruder firmware hack
38 M42 P28 S0 ; Force laser off!
39 M501 ; undo all settings made 44 M501 ; undo all settings made
40 """ % (100*60) 45 """ % (100*60)
41 46
42 47
43 class LasercutterSettings: 48 class LasercutterSettings:
293 def svg2gcode(self, filename): 298 def svg2gcode(self, filename):
294 # Imports for SVG 299 # Imports for SVG
295 import xml.etree.ElementTree as ET 300 import xml.etree.ElementTree as ET
296 from svg2gcode import shapes as shapes_pkg 301 from svg2gcode import shapes as shapes_pkg
297 from svg2gcode.shapes import point_generator 302 from svg2gcode.shapes import point_generator
303 from svg2gcode import simplepath, cspsubdiv, cubicsuperpath
298 304
299 self.log("Generating paths from SVG (outlines only)...") 305 self.log("Generating paths from SVG (outlines only)...")
300 svg_shapes = set(['rect', 'circle', 'ellipse', 'line', 'polyline', 'polygon', 'path']) 306 svg_shapes = set(['rect', 'circle', 'ellipse', 'line', 'polyline', 'polygon', 'path'])
301 tree = ET.parse(filename) 307 tree = ET.parse(filename)
302 root = tree.getroot() 308 root = tree.getroot()
373 379
374 self.log("Scaling factor: %.2f, %.2f" % (scale_x,scale_y)) 380 self.log("Scaling factor: %.2f, %.2f" % (scale_x,scale_y))
375 381
376 fo = open(filename + ".g", "w") 382 fo = open(filename + ".g", "w")
377 fo.write("; Filename: %s\n%s" % (filename, GCODE_HEAD)) 383 fo.write("; Filename: %s\n%s" % (filename, GCODE_HEAD))
384 fo.write("M571 S0 E1 ; On SVG we control the laser by ourself\n")
378 385
379 travel_speed = self.settings.lc_travel_speed * 60 386 travel_speed = self.settings.lc_travel_speed * 60
380 engrave_speed = self.settings.lc_engrave_speed * 60 * self.settings.lc_svg_speed_factor 387 engrave_speed = self.settings.lc_engrave_speed * 60 * self.settings.lc_svg_speed_factor
381 388
382 389
389 if tag_suffix in svg_shapes: 396 if tag_suffix in svg_shapes:
390 self.log("Parsing shape: %s" % tag_suffix) 397 self.log("Parsing shape: %s" % tag_suffix)
391 shape_class = getattr(shapes_pkg, tag_suffix) 398 shape_class = getattr(shapes_pkg, tag_suffix)
392 shape_obj = shape_class(elem) 399 shape_obj = shape_class(elem)
393 d = shape_obj.d_path() 400 d = shape_obj.d_path()
394 m = shape_obj.transformation_matrix() 401 mat = shape_obj.transformation_matrix()
395 402
396 if d: 403 if d:
397 fo.write("M400 ; start %s\n" % (tag_suffix)) 404 fo.write("M400 ; start %s\n" % (tag_suffix))
398 fo.write("G92 E0\n") 405 fo.write("G92 E0\n")
399 E = 0 406 E = 0
400 xo = 0 407 xo = 0
401 yo = 0 408 yo = 0
402 p = point_generator(d, m, smoothness) 409 idxo = None
403 start = True 410 #p = point_generator(d, mat, smoothness)
404 for x,y,pen in p: 411
405 x += ofs_x 412 simple_path = simplepath.parsePath(d)
406 y += ofs_y 413 if len(simple_path) == 0:
407 y = height - y # invert the bed 414 self.log("Path length zero!")
408 xs = scale_x * x 415 continue
409 ys = scale_y * y 416
410 if xo == xs and yo == ys: continue 417 p = cubicsuperpath.parsePath(d)
411 418
412 if not pen: start = True 419 if mat:
413 if xs >= 0 and xs <= bed_max_x+0.1 and ys >= 0 and ys <= bed_max_y+0.1: 420 simpletransform.applyTransformToPath(mat, p)
414 if start: 421
415 fo.write("G0 X%0.2f Y%0.2f F%.4f ; Move to start of shape\n" % ( 422 for sp in p:
416 xs, ys, travel_speed)) 423 cspsubdiv.subdiv( sp, smoothness)
417 start = False 424 self.log("Laser ON at: " + repr(sp[0][0]))
418 xo = xs 425 x = sp[0][0][0] + ofs_x
419 yo = ys 426 y = sp[0][0][1] + ofs_y
420 object_xs = xs 427 y = height - y # invert the bed
421 object_ys = ys 428 xs = scale_x * x
422 else: 429 ys = scale_y * y
423 e_distance = math.hypot(xs - xo, ys - yo) 430 fo.write("M400 ; Wait for all moves to finish\n")
424 xo = xs 431 fo.write("M42 P28 S0 ; Turn off laser\n")
425 yo = ys 432 fo.write("G0 X%0.4f Y%0.4f F%.4f ; Move to start of shape\n" % (
426 E = E + (e_distance) 433 xs, ys, travel_speed))
427 fo.write("G1 X%0.2f Y%0.2f E%.4f F%.4f\n" % ( 434 fo.write("M400 ; Wait for all moves to finish\n")
428 xs, ys, E * E_FACTOR, engrave_speed)) 435 fo.write("M42 P28 S255 ; Turn on laser\n")
429 else: 436
430 self.log("Position outside print dimension: %d, %d" % (xs, ys)) 437 xo = xs
438 yo = ys
439 object_xs = xs
440 object_ys = ys
441
442 for csp in sp:
443 ctrl_pt1 = csp[0]
444 ctrl_pt2 = csp[1]
445 end_pt = csp[2]
446
447 x = end_pt[0] + ofs_x
448 y = end_pt[1] + ofs_y
449
450 y = height - y # invert the bed
451 xs = round(scale_x * x, 4)
452 ys = round(scale_y * y, 4)
453 if xo == xs and yo == ys: continue
454
455 #self.log(" Point " + repr(end_pt))
456
457 if xs >= 0 and xs <= bed_max_x+0.1 and ys >= 0 and ys <= bed_max_y+0.1:
458 e_distance = math.hypot(xs - xo, ys - yo)
459 xo = xs
460 yo = ys
461 E = E + (e_distance)
462 fo.write("G1 X%0.4f Y%0.4f E%.4f F%.4f\n" % (
463 xs, ys, E * E_FACTOR, engrave_speed))
464
465 else:
466 self.log("Position outside print dimension: %d, %d" % (xs, ys))
467
468
469 #print " Point: ", end_pt[0], end_pt[1], pen
470 self.log("Laser OFF at: " + repr(sp[-1][-1]))
431 471
432 if shape_obj.xml_node.get('fill'): 472 if shape_obj.xml_node.get('fill'):
433 # Close the polygon 473 # Close the polygon
434 e_distance = math.hypot(object_xs - xo, object_ys - yo) 474 e_distance = math.hypot(object_xs - xo, object_ys - yo)
435 E = E + (e_distance) 475 E = E + (e_distance)
436 fo.write("G1 X%0.2f Y%0.2f E%.4f F%.4f ; Close the object polygon\n" % ( 476 fo.write("G1 X%0.4f Y%0.4f E%.4f F%.4f ; Close the object polygon\n" % (
437 object_xs, object_ys, E * E_FACTOR, engrave_speed)) 477 object_xs, object_ys, E * E_FACTOR, engrave_speed))
438 print "connecting filled path end to start" 478 print "connecting filled path end to start"
439 479
440 fo.write(GCODE_FOOT) 480 fo.write(GCODE_FOOT)
441 fo.close() 481 fo.close()

mercurial