Pārlūkot izejas kodu

unfinished laser engraver page. not public yet.

Thomas Buck 1 gadu atpakaļ
vecāks
revīzija
27572fab47

+ 426
- 0
input/projects/laser-engraver.md Parādīt failu

@@ -0,0 +1,426 @@
1
+title: Laser Engraver
2
+description: Marlin based CNC laser engraver with 3D printed parts
3
+x-parent: projects
4
+git: https://git.xythobuz.de/thomas/marlin/src/branch/laser-engraver
5
+x-date: 2022-11-11
6
+comments: true
7
+---
8
+
9
+After dabbling in 3D printing for a couple of years now, I now had to level-up my Makers toolkit.
10
+The next logical step, in my opinion, is laser engraving / laser cutting.
11
+I have to admit, I was initially a bit scared, and still have some respect for the potential hazards posed by the strong and focussed laser beam.
12
+So I decided to go slow and start with a low powered diode laser.
13
+
14
+⚠️ Be sure to always use proper laser safety goggles when working with such machines! ⚠️
15
+
16
+## Hardware
17
+
18
+I know I say this in a lot of articles here, probably in an attempt to justify my hoarding of electronic parts. 😳
19
+But this was even better than most of my previous projects, in the sense that I didn't have to buy any parts at all, except for the 2500mW 450nm laser diode, which I got used from my colleague [Philipp](https://www.phschoen.de/) for just 13€.
20
+The rails I bought many years ago and never used.
21
+The steppers, mainboard, display, fans and cables came from my now disassembled [CTC i3](ctc-i3.html).
22
+Everything else came out of my parts bin.
23
+
24
+### Mechanics
25
+
26
+The mechanism is based on the ["Cantilever Laser Engraver" by Meatball](https://www.printables.com/model/213526-cantilever-laser-engraver).
27
+This in turn is based on the ["Cantilever Laser Engraver" by GeoDave](https://www.thingiverse.com/thing:4605853).
28
+It uses 2020 aluminium extrusions with V-slot wheels for the X and Y axis.
29
+
30
+I really like this simple design that does not require a lot of parts.
31
+It has some problems with twisting of the Y-rail due to the weight hanging from the cantilever arm, but this can easily be solved by supporting the free-hanging side of the X-rail.
32
+Otherwise the length of the axes can be customized freely.
33
+
34
+<!--%
35
+lightgallery([
36
+    [ "img/laser_frame.jpg", "Frame of laser engraver, made of 2020 rails" ],
37
+])
38
+%-->
39
+
40
+I had to do some modifications to the design files provided by Meatball.
41
+
42
+The "Y-Axis Gantry Upper" has enlargened the holes for two of the four wheels, to be able to fit eccentric nuts that provide the required tensioning on the wheels.
43
+The "Y-Axis Gantry Lower" however has normal sized holes.
44
+So when using these parts, the two wheels are not actually moved perpendicular towards the extrusion, but are instead angled sideways.
45
+To avoid this problem I made the two holes in the lower bigger as well and used four instead of two eccentric nuts.
46
+I also slightly increased the distance between the two sets of wheels on the Y-axis, because it was very hard to fit the rail, even with the eccentric nuts as loose as possible.
47
+
48
+I also designed custom endstop mounts using M2.5 heat-melt inserts, as well as a support wheel for the free-hanging side of the cantilever arm.
49
+
50
+The OpenSCAD and STL files for these parts [can be found on my Printables profile](https://www.printables.com/model/314945-cantilever-laser-engraver-fixes).
51
+
52
+### Electronics
53
+
54
+TODO intro
55
+
56
+<!--%
57
+lightgallery([
58
+    [ "img/laser_gt2560.jpg", "GT2560 mainboard of laser engraver" ],
59
+])
60
+%-->
61
+
62
+To connect the laser diode TTL input, a PWM capable pin from the microcontroller is required.
63
+To find one, we need to take a look at the schematics for the GT2560 mainboard, which can be found in the [Geeetech Forums](https://www.geeetech.com/forum/viewtopic.php?f=13&t=19092&start=10).
64
+
65
+<!--%
66
+lightgallery([
67
+    [ "img/GT2560_1.png", "First page of GT2560 schematics" ],
68
+    [ "img/GT2560_2.png", "Second page of GT2560 schematics" ],
69
+])
70
+%-->
71
+
72
+I decided to use `PL4`, the `DIR` pin of one of the now unused stepper drivers.
73
+To connect to it I prepared a little piece of perfboard, to be placed in the slots like a stepstick, with an additional pull-up resistor to the 5V logic voltage present on the same header.
74
+To find the pin number for the Marlin configuration, we can take a look at the [Arduino Mega pin mappings](https://docs.arduino.cc/hacking/hardware/PinMapping2560), which show `PL4` to be Arduino pin `45`.
75
+
76
+<!--%
77
+lightgallery([
78
+    [ "img/laser_ttl_pwm.jpg", "TTL PWM input of laser, with pull-up resistor" ],
79
+])
80
+%-->
81
+
82
+I'm not only connecting the laser TTL input to the mainboard, I'm also switching the 12V supply as well, by using the MOSFET originally intended for the hotend heater.
83
+This brought a little problem however.
84
+Both connectors of the laser PCB have a ground connection.
85
+And the ground connection is also the one that's switched, when connecting the laser to the power supply.
86
+So even when the MOSFET was turned off the laser still had a ground connection and was powered through the ground pin of the TTL connector, so it could never fully turn off.
87
+So if you do the same, make sure to only connect one of the two ground pins!
88
+
89
+TODO display
90
+
91
+## Software
92
+
93
+### MCU Firmware
94
+
95
+TODO marlin configuration
96
+
97
+Apparently I seem to be the first person that tries to run an Ultimaker Controller 2004 LCD without a Z-Axis.
98
+I had to add a couple of `#ifdef Z_AXIS` in `src/lcd/HD44780/marlinui_HD44780.cpp`.
99
+
100
+You can see all the modifications to the configuration I initially made to get the machine running [in this commit](https://git.xythobuz.de/thomas/marlin/commit/41cd87398d539f41c2ebe54b5f675c6c8b5ce04b).
101
+My current Marlin configuration for the laser engraver can be found [on my Gitea instance](https://git.xythobuz.de/thomas/marlin/src/branch/laser-engraver).
102
+
103
+### Host Software
104
+
105
+Besides the microcontroller firmware, we also need some host software to prepare the G-Code from whatever kind of input file we start out with.
106
+There are two basic approaches for generating paths for the laser engraver.
107
+One is "rasterization", where a bitmap image is turned into commands line-by-line, enabling and disabling the laser at different parts of each line.
108
+This will draw an image similar to how a CRT TV works, which is useful eg. for engraving logos.
109
+
110
+The other variant is "vectorization", where either a bitmap is converted to a vector path, or we start out with a vector file format, like svg.
111
+The laser can then follow the outline and optionally also fill between the outlines in some kind of pattern.
112
+This can then be used to cut shapes from objects.
113
+
114
+At this point I should also mention [Lightburn](https://lightburnsoftware.com/).
115
+This software is used both for the Laser cutters at [Toolbox Bodensee](https://toolbox-bodensee.de/), as well as by my neighbour, who uses it with an [Ortur Laser Master 2](https://ortur.net/products/laser-master-2-pro).
116
+So I had some contact with it, and I have to admit, it works well and has a lot of functionality.
117
+But it is commercial paid software, not under any free software license, so [it is not an option for me](https://www.gnu.org/proprietary/proprietary.html).
118
+
119
+Below I will try to document all different free software packages I tried for laser engraving.
120
+
121
+#### LaserGRBL
122
+
123
+The first solution I found out about is [LaserGRBL](https://lasergrbl.com/).
124
+It is a Windows-only program, but at least it is open-source / free software.
125
+As the name implies however, it is intended for use with the [GRBL firmware](https://github.com/gnea/grbl).
126
+This firmware only runs on Atmega328p MCUs, so I can not use it.
127
+
128
+The G-Code flavor of GRBL is considerably different compared to Marlin, but I was able to get it to work mostly.
129
+
130
+For rasterization of bitmap images, GRBL produces G-Code with the laser power levels put inline with the movement commands.
131
+
132
+<pre class="sh_gcode">
133
+G0 X25 Y10 S0
134
+G1 X26.5 S150
135
+G0 X28.25 Y10.25 S0
136
+G1 X23 S150
137
+</pre>
138
+
139
+Without further modifications, this only moves the toolhead, while keeping the laser off at all times, because Marlin by default does not process the power-level parts of the G-Code lines.
140
+To get this to work, the "continuous inline power mode" has to be enabled by putting `M3 I` in the G-Code header setting of LaserGRBL.
141
+
142
+<!--%
143
+lightgallery([
144
+    [ "img/lasergrbl_settings.png", "LaserGRBL G-Code settings" ],
145
+])
146
+%-->
147
+
148
+Here are the results of my first attempts of engraving a rasterized image into a piece of scrap wood.
149
+The rocket used 6 lines/mm, with default speed and a PWM range of 0-255.
150
+The smirkey used 4 lines/mm, with default speed and a PWM range of 0-150.
151
+
152
+<!--%
153
+lightgallery([
154
+    [ "img/laser_raster_result.jpg", "My first cuts of some rasterized images" ],
155
+])
156
+%-->
157
+
158
+When trying to engrave vectorized paths, like the outline of an image, LaserGRBL produces different output, however.
159
+The power levels are now put on their own lines, but without any G-Code command, as usual shorthand used by GRBL.
160
+
161
+<pre class="sh_gcode">
162
+S0
163
+G0 X14.382 Y14.618
164
+S150
165
+G1 X14.618 Y14.382
166
+S0
167
+G0 X14.618 Y14.618
168
+S150
169
+G1 X14.457 Y14.457
170
+</pre>
171
+
172
+Using a simple Python script, we can convert to the same format as used for rasterization.
173
+It simply reads the input file into the output file, skipping every line starting with an uppercase letter 'S', instead appending that to the next line.
174
+
175
+I also noticed the speed set in LaserGRBL did not properly apply in Marlin.
176
+This is because, in vector mode, it puts a single "Fxxx" line at the beginning.
177
+Even though Marlin can interpret this in our configuration, there is no G1 mode set before, so Marlin does not know where to apply the speed.
178
+So I am also handling this case in the script as well.
179
+For raster input, LaserGRBL only puts the speed in a single G0 move at the beginning.
180
+So the speed does not apply to the G1 moves afterwards.
181
+This case is not handled yet.
182
+
183
+<pre class="sh_python">
184
+#!/usr/bin/env python
185
+
186
+import sys
187
+
188
+if len(sys.argv) < 3:
189
+    print("Usage:")
190
+    print("    " + sys.argv[0] + " input.nc output.gcode")
191
+    sys.exit(1)
192
+
193
+in_file = sys.argv[1]
194
+out_file = sys.argv[2]
195
+
196
+power = ""
197
+speed = ""
198
+
199
+with open(in_file, 'r') as fi, open(out_file, 'w') as fo:
200
+    for line in fi:
201
+        if line.startswith("S"):
202
+            power = " " + line.rstrip()
203
+        elif line.startswith("F"):
204
+            speed = " " + line.rstrip()
205
+        else:
206
+            s = line.rstrip()
207
+            if line.startswith("G1"):
208
+                s += power
209
+                s += speed
210
+            elif line.startswith("G0"):
211
+                s += power
212
+                if (power != " S0") and (power != ""):
213
+                    print("Warning: G0 move with power not zero!" + power)
214
+            s += "\n"
215
+            fo.write(s)
216
+</pre>
217
+
218
+Here is my first attempt of cutting a vector outline of an image out of a piece of paper.
219
+I used Marlins default speed and a PWM setting of 150 out of 255.
220
+
221
+<!--%
222
+lightgallery([
223
+    [ "img/laser_vector_result.jpg", "My first cut of a vector outline" ],
224
+])
225
+%-->
226
+
227
+For these tests I have simply used LaserGRBL to produce a G-Code file, which I have then transferred to an SD card for direct use in the engraver.
228
+LaserGRBL also can directly connect to the machine via the serial port.
229
+This has worked for me for a bit, but even though you can set the G-Code flavor to Marlin in the LaserGRBL settings, it does not really work properly.
230
+You can jog the toolhead but homing is not possible.
231
+I also had to reduce the polling frequency in the LaserGRBL settings to 'Quiet' and disable Soft-Reset to get it to work inside the VirtualBox VM I use to run the program.
232
+
233
+Apparently it is also possible to [run LaserGRBL in Wine](https://github.com/arkypita/LaserGRBL/issues/5#issuecomment-873564055) / [with PlayOnLinux](https://github.com/arkypita/LaserGRBL/raw/master/POL_LaserGRBL_setup.sh), but on my Arch system I was not able to get either of these running, due to problems with the required Winetricks.
234
+
235
+Also, for all the above tests with LaserGRBL I have imported raster bitmap images and either rastered them, or vectorized them within LaserGRBLs UI.
236
+With bitmaps it is possible to position the resulting G-Code paths with an offset from the zero position of the machine.
237
+This is not possible when using LaserGRBL to import SVG vector paths.
238
+With them, the output will always start at coordinates `(0, 0)`.
239
+You will then have to set the proper offset on the machine itself.
240
+
241
+#### Inkscape
242
+
243
+Inkscape includes the [G-Code Tools Plugin from the russian-language CNC-Club forums](https://www.cnc-club.ru/forum/viewtopic.php?t=35).
244
+Unfortunately I was not able to find much up-to-date english-language documentation for this.
245
+It is also relatively complicated and unintuitive.
246
+
247
+TODO
248
+
249
+I was able to get it to generate G-Code from a path, but not with any laser power instructions yet.
250
+
251
+#### FreeCAD
252
+
253
+FreeCAD has the [Path Workbench](https://wiki.freecadweb.org/Path_Workbench), which can be used to create G-Code instructions for all kinds of CNC machines.
254
+It is not really complete and fool-proof yet, unfortunately.
255
+And it is also not designed for pure 2D machines, like laser engravers, by default.
256
+
257
+TODO
258
+
259
+I have not yet tested that.
260
+
261
+#### Generating G-Code
262
+
263
+I also did some experimentation with programatically generating G-Code myself, using a simple Python script.
264
+It's drawing a grid for reference on the base plate of the machine, including numerical position indicators.
265
+
266
+<pre class="sh_python">
267
+#!/usr/bin/env python
268
+
269
+filename = "grid.gcode"
270
+w = 200
271
+h = 280
272
+d = 10
273
+pwr = 100
274
+speed_g0 = 3000
275
+speed_g1 = 1000
276
+
277
+digits = [
278
+    [
279
+        # 0
280
+        (0.0, 0.0),
281
+        (0.0, 1.0),
282
+        (1.0, 1.0),
283
+        (1.0, 0.0),
284
+        (0.0, 0.0)
285
+    ], [
286
+        # 1
287
+        (0.5, 0.0),
288
+        (0.5, 1.0)
289
+    ], [
290
+        # 2
291
+        (0.0, 1.0),
292
+        (1.0, 1.0),
293
+        (1.0, 0.5),
294
+        (0.0, 0.5),
295
+        (0.0, 0.0),
296
+        (1.0, 0.0),
297
+    ], [
298
+        # 3
299
+        (0.0, 1.0),
300
+        (1.0, 1.0),
301
+        (1.0, 0.5),
302
+        (0.0, 0.5),
303
+        (1.0, 0.5),
304
+        (1.0, 0.0),
305
+        (0.0, 0.0),
306
+    ], [
307
+        # 4
308
+        (0.0, 1.0),
309
+        (0.0, 0.5),
310
+        (1.0, 0.5),
311
+        (1.0, 1.0),
312
+        (1.0, 0.0),
313
+    ], [
314
+        # 5
315
+        (1.0, 1.0),
316
+        (0.0, 1.0),
317
+        (0.0, 0.5),
318
+        (1.0, 0.5),
319
+        (1.0, 0.0),
320
+        (0.0, 0.0),
321
+    ], [
322
+        # 6
323
+        (1.0, 1.0),
324
+        (0.0, 1.0),
325
+        (0.0, 0.0),
326
+        (1.0, 0.0),
327
+        (1.0, 0.5),
328
+        (0.0, 0.5),
329
+    ], [
330
+        # 7
331
+        (0.0, 1.0),
332
+        (1.0, 1.0),
333
+        (1.0, 0.0),
334
+    ], [
335
+        # 8
336
+        (1.0, 0.5),
337
+        (1.0, 1.0),
338
+        (0.0, 1.0),
339
+        (0.0, 0.5),
340
+        (1.0, 0.5),
341
+        (1.0, 0.0),
342
+        (0.0, 0.0),
343
+        (0.0, 0.5),
344
+    ], [
345
+        # 9
346
+        (1.0, 0.5),
347
+        (1.0, 1.0),
348
+        (0.0, 1.0),
349
+        (0.0, 0.5),
350
+        (1.0, 0.5),
351
+        (1.0, 0.0),
352
+        (0.0, 0.0),
353
+    ]
354
+]
355
+
356
+font_w = 1.5
357
+font_h = 3.0
358
+font_d = 0.5
359
+
360
+def draw_digit(f, i, sx, sy, ox, oy):
361
+    dig = digits[i]
362
+    n = 0
363
+    for p in dig:
364
+        x, y = p
365
+        s = ""
366
+
367
+        if n == 0:
368
+            s += "G0 S0 F" + str(speed_g0)
369
+        else:
370
+            s += "G1 S" + str(pwr) + " F" + str(speed_g1)
371
+
372
+        s += " X" + str(ox + sx * x)
373
+        s += " Y" + str(oy + sy * y)
374
+
375
+        print(s)
376
+        f.write(s + "\n")
377
+        n += 1
378
+
379
+    return s
380
+
381
+with open(filename, 'w') as f:
382
+    def write(s):
383
+        print(s)
384
+        f.write(s + "\n")
385
+
386
+    # header
387
+    write("G90")
388
+    write("M3 I")
389
+    write("M3 S0")
390
+
391
+    # first line is not having the power applied
392
+    # so just draw it twice
393
+    # TODO why?
394
+    write("G0 X0 Y0 S0 F" + str(speed_g0))
395
+    write("G1 X0 Y" + str(h) + " S" + str(pwr) + " F" + str(speed_g1))
396
+
397
+    # vertical lines
398
+    for x in range(0, w + d, d):
399
+        write("G0 X" + str(x) + " Y0 S0 F" + str(speed_g0))
400
+        write("G1 X" + str(x) + " Y" + str(h) + " S" + str(pwr) + " F" + str(speed_g1))
401
+
402
+    # horizontal lines
403
+    for y in range(0, h + d, d):
404
+        write("G0 X0 Y" + str(y) + " S0 F" + str(speed_g0))
405
+        write("G1 X" + str(w) + " Y" + str(y) + " S" + str(pwr) + " F" + str(speed_g1))
406
+
407
+    for x in range(0, w, d):
408
+        n = int(x / 1)
409
+        if n >= 10:
410
+            draw_digit(f, int(n / 10), font_w, font_h, font_d + x, font_d)
411
+            draw_digit(f, int(n % 10), font_w, font_h, 2 * font_d + font_w + x, font_d)
412
+        else:
413
+            draw_digit(f, n, font_w, font_h, font_d + x, font_d)
414
+
415
+    for y in range(d, h, d):
416
+        n = int(y / 1)
417
+        if n >= 10:
418
+            draw_digit(f, int(n / 10), font_w, font_h, font_d, font_d + y)
419
+            draw_digit(f, int(n % 10), font_w, font_h, 2 * font_d + font_w, font_d + y)
420
+        else:
421
+            draw_digit(f, n, font_w, font_h, font_d, font_d + y)
422
+
423
+    # footer
424
+    write("M5")
425
+    write("G0 X0 Y0 F" + str(speed_g0))
426
+</pre>

Binārs
static/img/GT2560_1.png Parādīt failu


Binārs
static/img/GT2560_1_small.png Parādīt failu


Binārs
static/img/GT2560_2.png Parādīt failu


Binārs
static/img/GT2560_2_small.png Parādīt failu


Binārs
static/img/laser_frame.jpg Parādīt failu


Binārs
static/img/laser_frame_small.jpg Parādīt failu


Binārs
static/img/laser_gt2560.jpg Parādīt failu


Binārs
static/img/laser_gt2560_small.jpg Parādīt failu


Binārs
static/img/laser_mechanics.jpg Parādīt failu


Binārs
static/img/laser_raster_result.jpg Parādīt failu


Binārs
static/img/laser_raster_result_small.jpg Parādīt failu


Binārs
static/img/laser_ttl_pwm.jpg Parādīt failu


Binārs
static/img/laser_ttl_pwm_small.jpg Parādīt failu


Binārs
static/img/laser_vector_result.jpg Parādīt failu


Binārs
static/img/laser_vector_result_small.jpg Parādīt failu


Binārs
static/img/lasergrbl_settings.png Parādīt failu


Binārs
static/img/lasergrbl_settings_small.png Parādīt failu


Notiek ielāde…
Atcelt
Saglabāt