printrun-src/printrun/laser.py

changeset 43
f7e9bd735ce1
parent 42
ea4c43494a19
equal deleted inserted replaced
42:ea4c43494a19 43:f7e9bd735ce1
1 """ 1 """
2 Lasercutter library 2 Lasercutter library
3 2015-2017 by NeoSoft, Malte Di Donato 3 2015-2019 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-2017 by NeoSoft - Malte Di Donato 21 ; 2015-2019 by NeoSoft - Malte Di Donato
22
23 G21 ; Metric
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
26 G90 ; absolute positioning
27 M201 X1000 Y1000 ; Set acceleration
28 M203 X1000 Y1000 ; Set max feedrate
29 M209 S0 ; disable firmware retraction, we dont want to burn holes...
30 ;M85 S0 ; Disable idle hold timeout (BUG!)
31 M84 ; enable motors
32
33 """
34
35 GCODE_FOOT = """
36 M400 ; Wait for all moves to finish
37 M5 ; Force laser off!
38 G0 X0 Y0 F%.4f ; Move back to origin
39 ; M501 ; undo all settings made
40 """ % (100*60)
41
42
43 GCODE_HEAD_MELZI = """
44 ; GCode generated by laser.py pronterface library (marlin code flavour)
45 ; 2015-2019 by NeoSoft - Malte Di Donato
22 46
23 G21 ; Metric 47 G21 ; Metric
24 ; We assume Z is in focus height and laser head is focus at bottom left of image! 48 ; 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 49 G92 X0 Y0 E0; set zero position - new origin
26 G90 ; absolute positioning 50 G90 ; absolute positioning
33 ;M85 S0 ; Disable idle hold timeout (BUG!) 57 ;M85 S0 ; Disable idle hold timeout (BUG!)
34 M84 ; enable motors 58 M84 ; enable motors
35 59
36 """ 60 """
37 61
38 GCODE_FOOT = """ 62 GCODE_FOOT_MELZI = """
39 M400 ; Wait for all moves to finish 63 M400 ; Wait for all moves to finish
40 M42 P28 S0 ; Force laser off! 64 M42 P28 S0 ; Force laser off!
41 ;M85 S30 ; re-enable idle hold timeout (BUG!) 65 ;M85 S30 ; re-enable idle hold timeout (BUG!)
42 G0 X0 Y0 F%.4f ; Move back to origin 66 G0 X0 Y0 F%.4f ; Move back to origin
43 M571 S0 E0 ; disable extruder firmware hack 67 M571 S0 E0 ; disable extruder firmware hack
53 self.lc_engrave_speed = 10 77 self.lc_engrave_speed = 10
54 # 30mm/sec works for wood (regulate the output power to something between 10-30%) 78 # 30mm/sec works for wood (regulate the output power to something between 10-30%)
55 # 30mm/sec for black anodized aluminum to get a light engraving @ 100% power 79 # 30mm/sec for black anodized aluminum to get a light engraving @ 100% power
56 # 10mm/sec for black anodized aluminum to get maximum possible engraving! @ 100% power 80 # 10mm/sec for black anodized aluminum to get maximum possible engraving! @ 100% power
57 self.lc_travel_speed = 120 81 self.lc_travel_speed = 120
82
83 # insert config option to enable the Melzi Marlin FW Hack (M571)
84 self.lc_melzi_hack = False
58 85
59 # BITMAP: 86 # BITMAP:
60 self.lc_bitmap_speed_factor = 1.0 87 self.lc_bitmap_speed_factor = 1.0
61 self.lc_dpi = 300 88 self.lc_dpi = 300
62 self.lc_grey_threshold = 0 89 self.lc_grey_threshold = 0
149 self.log("size: %d x %d pixels" % im.size) 176 self.log("size: %d x %d pixels" % im.size)
150 177
151 pix = im.load() 178 pix = im.load()
152 179
153 fo = open(filename + ".g", "w") 180 fo = open(filename + ".g", "w")
154 fo.write("; Filename: %s\n%s" % (filename, GCODE_HEAD)) 181 if self.settings.lc_melzi_hack:
182 fo.write("; Filename: %s\n%s" % (filename, GCODE_HEAD_MELZI))
183 else:
184 fo.write("; Filename: %s\n%s" % (filename, GCODE_HEAD))
155 185
156 fo.write(";Start engraving the raster image: %dx%d points @ %d DPI = %.0fx%.0f mm\n\n" % ( 186 fo.write(";Start engraving the raster image: %dx%d points @ %d DPI = %.0fx%.0f mm\n\n" % (
157 im.size[0], im.size[1], self.settings.lc_dpi, 187 im.size[0], im.size[1], self.settings.lc_dpi,
158 im.size[0] * self.MM_PIXEL, im.size[1] * self.MM_PIXEL) ) 188 im.size[0] * self.MM_PIXEL, im.size[1] * self.MM_PIXEL) )
159 189
235 fo.write("M400 ; X=%d printing row: direction %i\nG92 E0\n%s" % ( 265 fo.write("M400 ; X=%d printing row: direction %i\nG92 E0\n%s" % (
236 X, DIR, gcode_col)) 266 X, DIR, gcode_col))
237 if self.settings.lc_change_dir: 267 if self.settings.lc_change_dir:
238 DIR = DIR * (-1) # change y direction on every X 268 DIR = DIR * (-1) # change y direction on every X
239 269
240 fo.write(GCODE_FOOT) 270 if self.settings.lc_melzi_hack:
271 fo.write(GCODE_FOOT_MELZI)
272 else:
273 fo.write(GCODE_FOOT)
241 fo.close() 274 fo.close()
242 275
243 if self.pronterwindow: 276 if self.pronterwindow:
244 self.log("") 277 self.log("")
245 self.pronterwindow.load_gcode_async(filename + '.g') 278 self.pronterwindow.load_gcode_async(filename + '.g')
253 self.log("Converting HPGL plot for lasercut:") 286 self.log("Converting HPGL plot for lasercut:")
254 self.log("File: %s" % filename) 287 self.log("File: %s" % filename)
255 288
256 fi = open(filename, "r") 289 fi = open(filename, "r")
257 fo = open(filename + ".g", "w") 290 fo = open(filename + ".g", "w")
258 fo.write("; Filename: %s\n%s" % (filename, GCODE_HEAD)) 291 if self.settings.lc_melzi_hack:
292 fo.write("; Filename: %s\n%s" % (filename, GCODE_HEAD_MELZI))
293 else:
294 fo.write("; Filename: %s\n%s" % (filename, GCODE_HEAD))
259 295
260 G = "0" 296 G = "0"
261 LASER_STATE = 0 297 LASER_STATE = 0
262 last_coord = [0.0,0.0] 298 last_coord = [0.0,0.0]
263 last_cmd = "" 299 last_cmd = ""
301 print "Ignoring pen thickness" 337 print "Ignoring pen thickness"
302 else: 338 else:
303 print "UNKNOWN: %s" % action 339 print "UNKNOWN: %s" % action
304 last_cmd = cmd 340 last_cmd = cmd
305 341
306 fo.write(GCODE_FOOT) 342 if self.settings.lc_melzi_hack:
343 fo.write(GCODE_FOOT_MELZI)
344 else:
345 fo.write(GCODE_FOOT)
307 fi.close() 346 fi.close()
308 fo.close() 347 fo.close()
309 348
310 if self.pronterwindow: 349 if self.pronterwindow:
311 self.log("") 350 self.log("")
421 scale_y = bed_max_y / height 460 scale_y = bed_max_y / height
422 461
423 self.log("Scaling factor: %.2f, %.2f" % (scale_x,scale_y)) 462 self.log("Scaling factor: %.2f, %.2f" % (scale_x,scale_y))
424 463
425 fo = open(filename + ".g", "w") 464 fo = open(filename + ".g", "w")
426 fo.write("; Filename: %s\n%s" % (filename, GCODE_HEAD)) 465 if self.settings.lc_melzi_hack:
427 fo.write("M571 S0 E1 ; On SVG we control the laser by ourself\n") 466 fo.write("; Filename: %s\n%s" % (filename, GCODE_HEAD_MELZI))
467 fo.write("M571 S0 E1 ; On SVG we control the laser by ourself\n")
468 else:
469 fo.write("; Filename: %s\n%s" % (filename, GCODE_HEAD))
428 470
429 travel_speed = self.settings.lc_travel_speed * 60 471 travel_speed = self.settings.lc_travel_speed * 60
430 engrave_speed = self.settings.lc_engrave_speed * 60 * self.settings.lc_svg_speed_factor 472 engrave_speed = self.settings.lc_engrave_speed * 60 * self.settings.lc_svg_speed_factor
431 473
432 errors = 0 474 errors = 0
451 # ignore all stroke colors which are not #000000 493 # ignore all stroke colors which are not #000000
452 if style[1] != "#000000": 494 if style[1] != "#000000":
453 self.log("Ignoring shape %s (%i) by stroke color" % (tag_suffix, elemidx)) 495 self.log("Ignoring shape %s (%i) by stroke color" % (tag_suffix, elemidx))
454 skip = True 496 skip = True
455 break 497 break
498 # TODO: do a config option to enter the CUT color or something
456 if skip: 499 if skip:
457 continue 500 continue
458 501
459 self.log("Parsing shape: %s (%i)" % (tag_suffix, elemidx)) 502 self.log("Parsing shape: %s (%i)" % (tag_suffix, elemidx))
460 shape_class = getattr(shapes_pkg, tag_suffix) 503 shape_class = getattr(shapes_pkg, tag_suffix)
461 shape_obj = shape_class(elem) 504 shape_obj = shape_class(elem)
462 d = shape_obj.d_path() 505 d = shape_obj.d_path()
463 mat = shape_obj.transformation_matrix() 506 mat = shape_obj.transformation_matrix()
464 507
465 if d: 508 if d:
466 fo.write("M400 ; start %s\n" % (tag_suffix)) 509 if self.settings.lc_melzi_hack:
467 fo.write("G92 E0\n") 510 fo.write("M400 ; start %s\n" % (tag_suffix))
511 fo.write("G92 E0\n")
468 E = 0 512 E = 0
469 xo = 0 513 xo = 0
470 yo = 0 514 yo = 0
471 idxo = None 515 idxo = None
472 #p = point_generator(d, mat, smoothness) 516 #p = point_generator(d, mat, smoothness)
487 x = sp[0][0][0] + ofs_x 531 x = sp[0][0][0] + ofs_x
488 y = sp[0][0][1] + ofs_y 532 y = sp[0][0][1] + ofs_y
489 y = height - y # invert the bed 533 y = height - y # invert the bed
490 xs = scale_x * x 534 xs = scale_x * x
491 ys = scale_y * y 535 ys = scale_y * y
492 fo.write("M400 ; Wait for all moves to finish\n") 536 if self.settings.lc_melzi_hack:
493 fo.write("M42 P28 S0 ; Turn off laser\n") 537 fo.write("M400 ; Wait for all moves to finish\n")
494 fo.write("G0 X%0.4f Y%0.4f F%.4f ; Move to start of shape\n" % ( 538 fo.write("M42 P28 S0 ; Turn off laser\n")
495 xs, ys, travel_speed)) 539 fo.write("G0 X%0.4f Y%0.4f F%.4f ; Move to start of shape\n" % (
496 fo.write("M400 ; Wait for all moves to finish\n") 540 xs, ys, travel_speed))
497 fo.write("M42 P28 S255 ; Turn on laser\n") 541 fo.write("M400 ; Wait for all moves to finish\n")
542 fo.write("M42 P28 S255 ; Turn on laser\n")
543 else:
544 fo.write("M5 ; Turn off laser\n")
545 fo.write("G0 X%0.4f Y%0.4f F%.4f ; Move to start of shape\n" % (
546 xs, ys, travel_speed))
547 # todo: laser power as parameter?
548 fo.write("M3 S100 ; Turn on laser\n")
498 549
499 xo = xs 550 xo = xs
500 yo = ys 551 yo = ys
501 object_xs = xs 552 object_xs = xs
502 object_ys = ys 553 object_ys = ys
519 xo = xs 570 xo = xs
520 yo = ys 571 yo = ys
521 E = E + (e_distance) 572 E = E + (e_distance)
522 573
523 if xs >= 0 and xs <= bed_max_x+0.1 and ys >= 0 and ys <= bed_max_y+0.1: 574 if xs >= 0 and xs <= bed_max_x+0.1 and ys >= 0 and ys <= bed_max_y+0.1:
524 fo.write("G1 X%0.4f Y%0.4f E%.4f F%.4f\n" % ( 575 if self.settings.lc_melzi_hack:
525 xs, ys, E * E_FACTOR, engrave_speed)) 576 fo.write("G1 X%0.4f Y%0.4f E%.4f F%.4f\n" % (
577 xs, ys, E * E_FACTOR, engrave_speed))
578 else:
579 fo.write("G1 X%0.4f Y%0.4f F%.4f\n" % (
580 xs, ys, engrave_speed))
526 else: 581 else:
527 fo.write("G0 X%0.4f Y%0.4f F%.4f\n" % ( 582 if self.settings.lc_melzi_hack:
528 xs, ys, travel_speed)) 583 fo.write("G0 X%0.4f Y%0.4f F%.4f\n" % (
584 xs, ys, travel_speed))
585 else:
586 fo.write("M5 ; Turn off laser\n")
587 fo.write("G0 X%0.4f Y%0.4f F%.4f\n" % (
588 xs, ys, travel_speed))
589 # todo: laser power as parameter?
590 fo.write("M3 S100 ; Turn on laser\n")
529 errors += 1 591 errors += 1
530 if errors < 10: 592 if errors < 10:
531 self.log("Position outside print dimension: %d, %d" % (xs, ys)) 593 self.log("Position outside print dimension: %d, %d" % (xs, ys))
532 594
533 #print " Point: ", end_pt[0], end_pt[1], pen 595 #print " Point: ", end_pt[0], end_pt[1], pen
534 #self.log("Laser OFF at: " + repr(sp[-1][-1])) 596 #self.log("Laser OFF at: " + repr(sp[-1][-1]))
535 597
536 if shape_obj.xml_node.get('fill'): 598 #if shape_obj.xml_node.get('fill'):
599 if tag_suffix == "polygon":
537 # Close the polygon 600 # Close the polygon
538 e_distance = math.hypot(object_xs - xo, object_ys - yo) 601 if self.settings.lc_melzi_hack:
539 E = E + (e_distance) 602 e_distance = math.hypot(object_xs - xo, object_ys - yo)
540 fo.write("G1 X%0.4f Y%0.4f E%.4f F%.4f ; Close the object polygon\n" % ( 603 E = E + (e_distance)
541 object_xs, object_ys, E * E_FACTOR, engrave_speed)) 604 fo.write("G1 X%0.4f Y%0.4f E%.4f F%.4f ; Close the object polygon\n" % (
542 print "connecting filled path end to start" 605 object_xs, object_ys, E * E_FACTOR, engrave_speed))
543 606 else:
544 fo.write(GCODE_FOOT) 607 fo.write("G1 X%0.4f Y%0.4f F%.4f ; Close the object polygon\n" % (
608 object_xs, object_ys, engrave_speed))
609 print "connecting filled polygon path end to start"
610
611 if self.settings.lc_melzi_hack:
612 fo.write(GCODE_FOOT_MELZI)
613 else:
614 fo.write(GCODE_FOOT)
545 fo.close() 615 fo.close()
546 616
547 if errors > 0: 617 if errors > 0:
548 self.log("%i errors while generating gcode" % errors) 618 self.log("%i errors while generating gcode" % errors)
549 619

mercurial