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 = "" |
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 |