Browse Source

initial commit

Thomas Buck 1 year ago
commit
b344502ff1

+ 1
- 0
.gitignore View File

@@ -0,0 +1 @@
1
+*.pyc

+ 10
- 0
README.md View File

@@ -0,0 +1,10 @@
1
+# G-Code Tools
2
+
3
+A collection of Python scripts to convert / generate G-Code.
4
+For more background see [the page about my laser engraver](https://www.xythobuz.de/laser-engraver.html).
5
+
6
+The directory `generators` contains scripts that generate G-Code by themselves.
7
+
8
+The directory `tools` contains scripts that convert or otherwise work with G-Code.
9
+
10
+See the README.md in each directory for details.

+ 15
- 0
generators/README.md View File

@@ -0,0 +1,15 @@
1
+# Generators
2
+
3
+Scripts that generate G-Code by themselves.
4
+
5
+## square_gcode.py
6
+
7
+Very simple, just cuts out square shape.
8
+
9
+## grid_gcode.py
10
+
11
+Generates a centimeter grid with numerical graduations for engraving on a work surface.
12
+
13
+## cut_test_gcode.py
14
+
15
+Generates sheets of repeated shapes, cut with different parameters for each, to find optimal cutting speed and number of iterations for a new material.

+ 228
- 0
generators/cut_test_gcode.py View File

@@ -0,0 +1,228 @@
1
+#!/usr/bin/env python
2
+
3
+# general settings
4
+filename = "cut_test.gcode"
5
+pwr = 255
6
+pwr_num = 150
7
+speed_g0 = 3000
8
+speed_g1_num = 500
9
+
10
+# settings of single test shape
11
+width = 10
12
+height = 10
13
+dist = 2
14
+
15
+# range for tests
16
+iterations = [ 5, 10, 15, 20 ]
17
+speeds_g1 = [ 1000, 500, 200 ]
18
+
19
+def drawSquare(w, h, x, y, speed_g1):
20
+    write("G0 X" + str(x) + " Y" + str(y) + " S0 F" + str(speed_g0))
21
+    square = [
22
+        ( x + w, y ),
23
+        ( x + w, y + h ),
24
+        ( x, y + h ),
25
+        ( x, y ),
26
+    ]
27
+    for xp, yp in square:
28
+        write("G1 X" + str(xp) + " Y" + str(yp) + " S" + str(pwr) + " F" + str(speed_g1))
29
+
30
+def drawHeart(w, h, x, y, speed_g1):
31
+    heart = [
32
+        ( 0.0, 5.0 / 8.0 ),
33
+        ( 0.0, 6.0 / 8.0 ),
34
+        ( 0.1, 7.0 / 8.0 ),
35
+        ( 0.2, 8.0 / 8.0 ),
36
+        ( 0.3, 8.0 / 8.0 ),
37
+        ( 0.4, 7.0 / 8.0 ),
38
+        ( 0.5, 6.0 / 8.0 ),
39
+        ( 0.6, 7.0 / 8.0 ),
40
+        ( 0.7, 8.0 / 8.0 ),
41
+        ( 0.8, 8.0 / 8.0 ),
42
+        ( 0.9, 7.0 / 8.0 ),
43
+        ( 1.0, 6.0 / 8.0 ),
44
+        ( 1.0, 5.0 / 8.0 ),
45
+        ( 0.9, 4.0 / 8.0 ),
46
+        ( 0.8, 3.0 / 8.0 ),
47
+        ( 0.7, 2.0 / 8.0 ),
48
+        ( 0.6, 1.0 / 8.0 ),
49
+        ( 0.5, 0.0 / 8.0 ),
50
+        ( 0.4, 1.0 / 8.0 ),
51
+        ( 0.3, 2.0 / 8.0 ),
52
+        ( 0.2, 3.0 / 8.0 ),
53
+        ( 0.1, 4.0 / 8.0 ),
54
+        ( 0.0, 5.0 / 8.0 )
55
+    ]
56
+    write("G0 X" + str(x + heart[0][0] * w) + " Y" + str(y + heart[0][1] * h) + " S0 F" + str(speed_g0))
57
+    for xp, yp in heart:
58
+        write("G1 X" + str(x + xp * w) + " Y" + str(y + yp * h) + " S" + str(pwr) + " F" + str(speed_g1))
59
+
60
+def drawShape(w, h, x, y, speed_g1):
61
+    #drawSquare(w, h, x, y, speed_g1)
62
+    drawHeart(w, h, x, y, speed_g1)
63
+
64
+digits = [
65
+    [
66
+        # 0
67
+        (0.0, 0.0),
68
+        (0.0, 1.0),
69
+        (1.0, 1.0),
70
+        (1.0, 0.0),
71
+        (0.0, 0.0)
72
+    ], [
73
+        # 1
74
+        (0.5, 0.0),
75
+        (0.5, 1.0)
76
+    ], [
77
+        # 2
78
+        (0.0, 1.0),
79
+        (1.0, 1.0),
80
+        (1.0, 0.5),
81
+        (0.0, 0.5),
82
+        (0.0, 0.0),
83
+        (1.0, 0.0),
84
+    ], [
85
+        # 3
86
+        (0.0, 1.0),
87
+        (1.0, 1.0),
88
+        (1.0, 0.5),
89
+        (0.0, 0.5),
90
+        (1.0, 0.5),
91
+        (1.0, 0.0),
92
+        (0.0, 0.0),
93
+    ], [
94
+        # 4
95
+        (0.0, 1.0),
96
+        (0.0, 0.5),
97
+        (1.0, 0.5),
98
+        (1.0, 1.0),
99
+        (1.0, 0.0),
100
+    ], [
101
+        # 5
102
+        (1.0, 1.0),
103
+        (0.0, 1.0),
104
+        (0.0, 0.5),
105
+        (1.0, 0.5),
106
+        (1.0, 0.0),
107
+        (0.0, 0.0),
108
+    ], [
109
+        # 6
110
+        (1.0, 1.0),
111
+        (0.0, 1.0),
112
+        (0.0, 0.0),
113
+        (1.0, 0.0),
114
+        (1.0, 0.5),
115
+        (0.0, 0.5),
116
+    ], [
117
+        # 7
118
+        (0.0, 1.0),
119
+        (1.0, 1.0),
120
+        (1.0, 0.0),
121
+    ], [
122
+        # 8
123
+        (1.0, 0.5),
124
+        (1.0, 1.0),
125
+        (0.0, 1.0),
126
+        (0.0, 0.5),
127
+        (1.0, 0.5),
128
+        (1.0, 0.0),
129
+        (0.0, 0.0),
130
+        (0.0, 0.5),
131
+    ], [
132
+        # 9
133
+        (1.0, 0.5),
134
+        (1.0, 1.0),
135
+        (0.0, 1.0),
136
+        (0.0, 0.5),
137
+        (1.0, 0.5),
138
+        (1.0, 0.0),
139
+        (0.0, 0.0),
140
+    ]
141
+]
142
+
143
+font_w = 1.5
144
+font_h = 3.0
145
+font_d = 0.5
146
+
147
+def draw_digit(f, i, size_x, size_y, off_x, off_y):
148
+    dig = digits[i]
149
+    n = 0
150
+    for p in dig:
151
+        x, y = p
152
+        s = ""
153
+
154
+        if n == 0:
155
+            s += "G0 S0 F" + str(speed_g0)
156
+        else:
157
+            s += "G1 S" + str(pwr_num) + " F" + str(speed_g1_num)
158
+
159
+        s += " X" + str(off_x + size_x * x)
160
+        s += " Y" + str(off_y + size_y * y)
161
+
162
+        print(s)
163
+        f.write(s + "\n")
164
+        n += 1
165
+
166
+    return s
167
+
168
+def draw_number(f, n, x, y):
169
+    if n >= 1000:
170
+        draw_digit(f, int(n / 1000),       font_w, font_h, x,                         y)
171
+        draw_digit(f, int((n / 100)) % 10, font_w, font_h, x + font_d + font_w,       y)
172
+        draw_digit(f, int((n / 10) % 10),  font_w, font_h, x + 2 * (font_d + font_w), y)
173
+        draw_digit(f, int(n % 10),         font_w, font_h, x + 3 * (font_d + font_w), y)
174
+    elif n >= 100:
175
+        draw_digit(f, int(n / 100),       font_w, font_h, x,                         y)
176
+        draw_digit(f, int((n / 10) % 10), font_w, font_h, x + font_d + font_w,       y)
177
+        draw_digit(f, int(n % 10),        font_w, font_h, x + 2 * (font_d + font_w), y)
178
+    elif n >= 10:
179
+        draw_digit(f, int(n / 10), font_w, font_h, x,                   y)
180
+        draw_digit(f, int(n % 10), font_w, font_h, x + font_d + font_w, y)
181
+    else:
182
+        draw_digit(f, n, font_w, font_h, x, y)
183
+
184
+with open(filename, 'w') as f:
185
+    def write(s):
186
+        print(s)
187
+        f.write(s + "\n")
188
+
189
+    # header
190
+    write("G90")
191
+    write("G28")
192
+    write("G92 X0 Y-20")
193
+    write("M3 I")
194
+    write("M3 S0")
195
+    write("")
196
+
197
+    # first line is not having the power applied
198
+    # TODO
199
+    write("G0 X0 Y0 S0 F" + str(speed_g0))
200
+    write("G1 X1 Y0 S1 F" + str(speeds_g1[0]))
201
+    write("G0 X0 Y0 S0 F" + str(speed_g0))
202
+    write("G1 X0 Y1 S1 F" + str(speeds_g1[0]))
203
+    write("G0 X0 Y0 S0 F" + str(speed_g0))
204
+
205
+    max_num_str_len = 4
206
+    str_w = (max_num_str_len * font_w) + ((max_num_str_len - 1) * font_d)
207
+
208
+    write("; iterations")
209
+    for i in range(0, len(iterations)):
210
+        write("; " + str(iterations[i]))
211
+        draw_number(f, iterations[i], (width + str_w) / 2.0 + dist + i * (width + dist), 0)
212
+    write("")
213
+
214
+    write("; speeds")
215
+    for i in range(0, len(speeds_g1)):
216
+        write("; " + str(speeds_g1[i]))
217
+        draw_number(f, speeds_g1[i], 0, (height + font_h) / 2.0 + dist + i * (height + dist))
218
+
219
+    for i in range(0, len(speeds_g1)):
220
+        for j in range(0, len(iterations)):
221
+            write("; speed=" + str(speeds_g1[i]) + " n=" + str(iterations[j]))
222
+            for k in range(0, iterations[j]):
223
+                drawShape(width, height, str_w + dist + j * (width + dist), font_h + dist + i * (height + dist), speeds_g1[i])
224
+            write("")
225
+
226
+    # footer
227
+    write("M5")
228
+    write("G0 X0 Y0 F" + str(speed_g0))

+ 172
- 0
generators/grid_gcode.py View File

@@ -0,0 +1,172 @@
1
+#!/usr/bin/env python
2
+
3
+filename = "grid.gcode"
4
+w = 200
5
+h = 280
6
+d = 10
7
+pwr = 100
8
+speed_g0 = 3000
9
+speed_g1 = 1000
10
+
11
+digits = [
12
+    [
13
+        # 0
14
+        (0.0, 0.0),
15
+        (0.0, 1.0),
16
+        (1.0, 1.0),
17
+        (1.0, 0.0),
18
+        (0.0, 0.0)
19
+    ], [
20
+        # 1
21
+        (0.5, 0.0),
22
+        (0.5, 1.0)
23
+    ], [
24
+        # 2
25
+        (0.0, 1.0),
26
+        (1.0, 1.0),
27
+        (1.0, 0.5),
28
+        (0.0, 0.5),
29
+        (0.0, 0.0),
30
+        (1.0, 0.0),
31
+    ], [
32
+        # 3
33
+        (0.0, 1.0),
34
+        (1.0, 1.0),
35
+        (1.0, 0.5),
36
+        (0.0, 0.5),
37
+        (1.0, 0.5),
38
+        (1.0, 0.0),
39
+        (0.0, 0.0),
40
+    ], [
41
+        # 4
42
+        (0.0, 1.0),
43
+        (0.0, 0.5),
44
+        (1.0, 0.5),
45
+        (1.0, 1.0),
46
+        (1.0, 0.0),
47
+    ], [
48
+        # 5
49
+        (1.0, 1.0),
50
+        (0.0, 1.0),
51
+        (0.0, 0.5),
52
+        (1.0, 0.5),
53
+        (1.0, 0.0),
54
+        (0.0, 0.0),
55
+    ], [
56
+        # 6
57
+        (1.0, 1.0),
58
+        (0.0, 1.0),
59
+        (0.0, 0.0),
60
+        (1.0, 0.0),
61
+        (1.0, 0.5),
62
+        (0.0, 0.5),
63
+    ], [
64
+        # 7
65
+        (0.0, 1.0),
66
+        (1.0, 1.0),
67
+        (1.0, 0.0),
68
+    ], [
69
+        # 8
70
+        (1.0, 0.5),
71
+        (1.0, 1.0),
72
+        (0.0, 1.0),
73
+        (0.0, 0.5),
74
+        (1.0, 0.5),
75
+        (1.0, 0.0),
76
+        (0.0, 0.0),
77
+        (0.0, 0.5),
78
+    ], [
79
+        # 9
80
+        (1.0, 0.5),
81
+        (1.0, 1.0),
82
+        (0.0, 1.0),
83
+        (0.0, 0.5),
84
+        (1.0, 0.5),
85
+        (1.0, 0.0),
86
+        (0.0, 0.0),
87
+    ]
88
+]
89
+
90
+font_w = 1.5
91
+font_h = 3.0
92
+font_d = 0.5
93
+
94
+def draw_digit(f, i, sx, sy, ox, oy):
95
+    dig = digits[i]
96
+    n = 0
97
+    for p in dig:
98
+        x, y = p
99
+        s = ""
100
+
101
+        if n == 0:
102
+            s += "G0 S0 F" + str(speed_g0)
103
+        else:
104
+            s += "G1 S" + str(pwr) + " F" + str(speed_g1)
105
+
106
+        s += " X" + str(ox + sx * x)
107
+        s += " Y" + str(oy + sy * y)
108
+
109
+        print(s)
110
+        f.write(s + "\n")
111
+        n += 1
112
+
113
+    return s
114
+
115
+with open(filename, 'w') as f:
116
+    def write(s):
117
+        print(s)
118
+        f.write(s + "\n")
119
+
120
+    # header
121
+    write("G90")
122
+    write("G28")
123
+    write("G92 X0 Y-20")
124
+    write("M3 I")
125
+    write("M3 S0")
126
+    write("")
127
+
128
+    # first line is not having the power applied
129
+    # so just draw it twice
130
+    # TODO why?
131
+    write("G0 X0 Y0 S0 F" + str(speed_g0))
132
+    write("G1 X0 Y" + str(h) + " S" + str(pwr) + " F" + str(speed_g1))
133
+
134
+    # vertical lines
135
+    write("; vertical lines")
136
+    for x in range(0, w + d, d):
137
+        write("G0 X" + str(x) + " Y0 S0 F" + str(speed_g0))
138
+        write("G1 X" + str(x) + " Y" + str(h) + " S" + str(pwr) + " F" + str(speed_g1))
139
+    write("")
140
+
141
+    # horizontal lines
142
+    write("; horizontal lines")
143
+    for y in range(0, h + d, d):
144
+        write("G0 X0 Y" + str(y) + " S0 F" + str(speed_g0))
145
+        write("G1 X" + str(w) + " Y" + str(y) + " S" + str(pwr) + " F" + str(speed_g1))
146
+    write("")
147
+
148
+    # horizontal text
149
+    for x in range(0, w, d):
150
+        n = int(x / 10)
151
+        write("; number '" + str(n) + "' at x " + str(x))
152
+        if n >= 10:
153
+            draw_digit(f, int(n / 10), font_w, font_h, font_d + x, font_d)
154
+            draw_digit(f, int(n % 10), font_w, font_h, 2 * font_d + font_w + x, font_d)
155
+        else:
156
+            draw_digit(f, n, font_w, font_h, font_d + x, font_d)
157
+    write("")
158
+
159
+    # vertical text
160
+    for y in range(d, h, d):
161
+        n = int(y / 10)
162
+        write("; number '" + str(n) + "' at y " + str(y))
163
+        if n >= 10:
164
+            draw_digit(f, int(n / 10), font_w, font_h, font_d, font_d + y)
165
+            draw_digit(f, int(n % 10), font_w, font_h, 2 * font_d + font_w, font_d + y)
166
+        else:
167
+            draw_digit(f, n, font_w, font_h, font_d, font_d + y)
168
+    write("")
169
+
170
+    # footer
171
+    write("M5")
172
+    write("G0 X0 Y0 F" + str(speed_g0))

+ 48
- 0
generators/square_gcode.py View File

@@ -0,0 +1,48 @@
1
+#!/usr/bin/env python
2
+
3
+filename = "square.gcode"
4
+w = 10
5
+h = 10
6
+n = 20
7
+pwr = 255
8
+speed_g0 = 3000
9
+speed_g1 = 500
10
+
11
+with open(filename, 'w') as f:
12
+    def write(s):
13
+        print(s)
14
+        f.write(s + "\n")
15
+
16
+    # header
17
+    write("G90")
18
+    write("G28")
19
+    write("G92 X0 Y-20")
20
+    write("M3 I")
21
+    write("M3 S0")
22
+    write("")
23
+
24
+    square = [
25
+        ( 0, 0 ),
26
+        ( w, 0 ),
27
+        ( w, h ),
28
+        ( 0, h ),
29
+    ]
30
+
31
+    # first line is not having the power applied
32
+    # so just draw it twice
33
+    # TODO why?
34
+    write("G0 X0 Y0 S0 F" + str(speed_g0))
35
+    write("G1 X0 Y0 S" + str(pwr) + " F" + str(speed_g1))
36
+
37
+    for i in range(0, n):
38
+        for x, y in square:
39
+            write("G1 X" + str(x) + " Y" + str(y) + " S" + str(pwr) + " F" + str(speed_g1))
40
+        write("")
41
+
42
+    # finish last line
43
+    write("G1 X0 Y0 S" + str(pwr) + " F" + str(speed_g1))
44
+    write("")
45
+
46
+    # footer
47
+    write("M5")
48
+    write("G0 X0 Y0 F" + str(speed_g0))

+ 28
- 0
tools/README.md View File

@@ -0,0 +1,28 @@
1
+# Tools
2
+
3
+Scripts that convert or otherwise work with G-Code.
4
+
5
+## convert_lasergrbl.py
6
+
7
+Converts output from LaserGRBL to a format that can be understood by the Marlin firmware.
8
+
9
+## outline_gcode.py
10
+
11
+Takes all G1 move coordinates from a G-Code files to get the bounding box of the object, minimum and maximum coordinates in x and y axis.
12
+Then produces a whole lot of low-power moves along this bounding box.
13
+
14
+Useful to proplery place stock material on a laser cutting machine.
15
+
16
+## gcode_center_outline.py
17
+
18
+Combines the previous two scripts.
19
+First cleans up G-Code from LaserGRBL like in `convert_lasergrbl.py`.
20
+Also creates an outline as a separate file, like in `outline_gcode.py`.
21
+Both are then shifted as well to the center of my machine.
22
+
23
+Machine size is hardcoded in the script.
24
+
25
+## send_gcode.py
26
+
27
+Simple G-Code sender using pySerial to access serial port.
28
+For use with Marlin and possibly other RepRap compatible firmwares.

+ 69
- 0
tools/convert_lasergrbl.py View File

@@ -0,0 +1,69 @@
1
+#!/usr/bin/env python
2
+
3
+import sys
4
+
5
+def add_spaces(s):
6
+    prev = ' '
7
+    r = ""
8
+    for c in s:
9
+        if str(prev).isdigit() and str(c).isalpha():
10
+            r = r + " "
11
+        r = r + c
12
+        prev = c
13
+    return r
14
+
15
+def convert_gcode(fi, fo):
16
+    power = ""
17
+    speed = ""
18
+    mode_g0 = True
19
+
20
+    for line in fi:
21
+        if line.startswith("S"):
22
+            power = " " + line.rstrip()
23
+        elif line.startswith("F"):
24
+            speed = " " + line.rstrip()
25
+        elif line.startswith("M3 S0"):
26
+            fo.write(line)
27
+            fo.write("G0 X0 Y0 S0 F1000\n")
28
+            fo.write("G1 X1 Y0 S1 F1000\n")
29
+            fo.write("G0 X0 Y0 S0 F1000\n")
30
+            fo.write("G1 X0 Y1 S1 F1000\n")
31
+            fo.write("G0 X0 Y0 S0 F1000\n")
32
+        else:
33
+            s = add_spaces(line.rstrip())
34
+            if line.startswith("G1"):
35
+                mode_g0 = False
36
+                s += power
37
+                s += speed
38
+            elif line.startswith("G0"):
39
+                mode_g0 = True
40
+                s += power
41
+                if (power != " S0") and (power != ""):
42
+                    print("Warning: G0 move with power not zero!" + power)
43
+            elif line.startswith("X") or line.startswith("Y"):
44
+                if mode_g0:
45
+                    s = "G0 " + s
46
+                    s += power
47
+                    if (power != " S0") and (power != ""):
48
+                        print("Warning: G0 move with power not zero!" + power)
49
+                else:
50
+                    s = "G1 " + s
51
+                    s += power
52
+                    s += speed
53
+            s += "\n"
54
+            fo.write(s)
55
+
56
+def main():
57
+    if len(sys.argv) < 3:
58
+        print("Usage:")
59
+        print("    " + sys.argv[0] + " input.nc output.gcode")
60
+        sys.exit(1)
61
+
62
+    in_file = sys.argv[1]
63
+    out_file = sys.argv[2]
64
+
65
+    with open(in_file, 'r') as fi, open(out_file, 'w') as fo:
66
+        convert_gcode(fi, fo)
67
+
68
+if __name__ == '__main__':
69
+    main()

+ 92
- 0
tools/gcode_center_outline.py View File

@@ -0,0 +1,92 @@
1
+#!/usr/bin/env python
2
+
3
+import sys
4
+import os
5
+from outline_gcode import file_bounding_box, write_outline
6
+from convert_lasergrbl import convert_gcode
7
+
8
+machine_size = ( 208, 287 )
9
+
10
+def patch_offset(fi, fo, zp):
11
+    found_off = False
12
+    found_home = False
13
+    found_abs = False
14
+    for line in fi:
15
+        if line.startswith("G92"):
16
+            found_off = True
17
+        elif line.startswith("G28"):
18
+            found_home = True
19
+        elif line.startswith("G90"):
20
+            found_abs = True
21
+
22
+    fi.seek(0)
23
+
24
+    sx = "{:.3f}".format(zp[0])
25
+    sy = "{:.3f}".format(zp[1])
26
+
27
+    if found_off:
28
+        for line in fi:
29
+            if line.startswith("G92"):
30
+                fo.write("G92 X" + sx + " Y" + sy + "\n")
31
+            else:
32
+                fo.write(line)
33
+    elif found_home:
34
+        for line in fi:
35
+            fo.write(line)
36
+            if line.startswith("G28"):
37
+                fo.write("G92 X" + sx + " Y" + sy + "\n")
38
+    elif found_abs:
39
+        for line in fi:
40
+            fo.write(line)
41
+            if line.startswith("G90"):
42
+                fo.write("G92 X" + sx + " Y" + sy + "\n")
43
+    else:
44
+        fo.write("G92 X" + sx + " Y" + sy + "\n")
45
+        for line in fi:
46
+            fo.write(line)
47
+
48
+def main():
49
+    if len(sys.argv) < 2:
50
+        print("Usage:")
51
+        print("    " + sys.argv[0] + " input.nc")
52
+        sys.exit(1)
53
+
54
+    in_file = sys.argv[1]
55
+
56
+    out_tmp_file = os.path.splitext(in_file)[0] + '_tmp.gcode'
57
+    out_file = os.path.splitext(in_file)[0] + '.gcode'
58
+    outline_tmp_file = os.path.splitext(in_file)[0] + '_bb_tmp.gcode'
59
+    outline_file = os.path.splitext(in_file)[0] + '_bb.gcode'
60
+
61
+    for f in [ out_tmp_file, out_file, outline_tmp_file, outline_file ]:
62
+        if os.path.exists(f):
63
+            print("File exists: " + f)
64
+            sys.exit(1)
65
+
66
+    bb = ( None, None, None, None )
67
+    with open(in_file, 'r') as f:
68
+        bb = file_bounding_box(f)
69
+
70
+    x_min, x_max, y_min, y_max = bb
71
+
72
+    size = ( x_max - x_min, y_max - y_min )
73
+    off = ( -x_min + (machine_size[0] - size[0]) / 2.0, -y_min + (machine_size[1] - size[1]) / 2.0 )
74
+    zero_point = ( -off[0], -off[1] )
75
+
76
+    with open(in_file, 'r') as fi, open(out_tmp_file, 'w') as fo:
77
+        convert_gcode(fi, fo)
78
+
79
+    with open(out_tmp_file, 'r') as fi, open(out_file, 'w') as fo:
80
+        patch_offset(fi, fo, zero_point)
81
+
82
+    with open(outline_tmp_file, 'w') as f:
83
+        write_outline(f, bb)
84
+
85
+    with open(outline_tmp_file, 'r') as fi, open(outline_file, 'w') as fo:
86
+        patch_offset(fi, fo, zero_point)
87
+
88
+    os.remove(out_tmp_file)
89
+    os.remove(outline_tmp_file)
90
+
91
+if __name__ == '__main__':
92
+    main()

+ 102
- 0
tools/outline_gcode.py View File

@@ -0,0 +1,102 @@
1
+#!/usr/bin/env python
2
+
3
+import sys
4
+
5
+pwr = 1
6
+iterations = 100
7
+speed = 3000
8
+
9
+def file_bounding_box(f):
10
+    x_min = None
11
+    x_max = None
12
+    y_min = None
13
+    y_max = None
14
+    mode_g1 = False
15
+
16
+    for line in f:
17
+        if line.startswith("G1"):
18
+            mode_g1 = True
19
+        elif line.startswith("G0"):
20
+            mode_g1 = False
21
+
22
+        if mode_g1:
23
+            x_pos = line.find("X")
24
+            if x_pos > -1:
25
+                x_str = line[x_pos + 1:]
26
+                x_num = float(x_str.split()[0])
27
+                #print("found x: " + str(x_num))
28
+                if (x_min == None) or (x_num < x_min):
29
+                    x_min = x_num
30
+                if (x_max == None) or (x_num > x_max):
31
+                    x_max = x_num
32
+
33
+            y_pos = line.find("Y")
34
+            if y_pos > -1:
35
+                y_str = line[y_pos + 1:]
36
+                y_num = float(y_str.split()[0])
37
+                #print("found y: " + str(y_num))
38
+                if (y_min == None) or (y_num < y_min):
39
+                    y_min = y_num
40
+                if (y_max == None) or (y_num > y_max):
41
+                    y_max = y_num
42
+
43
+    return ( x_min, x_max, y_min, y_max )
44
+
45
+def write_outline(f, bb):
46
+    def write(s):
47
+        #print(s)
48
+        f.write(s + "\n")
49
+
50
+    x_min, x_max, y_min, y_max = bb
51
+
52
+    print("x_min: " + str(x_min))
53
+    print("x_max: " + str(x_max))
54
+    print("y_min: " + str(y_min))
55
+    print("y_max: " + str(y_max))
56
+
57
+    pos = [
58
+        ( x_min, y_min ),
59
+        ( x_max, y_min ),
60
+        ( x_max, y_max ),
61
+        ( x_min, y_max ),
62
+    ]
63
+
64
+    # header
65
+    write("G90")
66
+    write("G28")
67
+    write("G92 X0 Y-20")
68
+    write("M3 I")
69
+    write("M3 S0")
70
+
71
+    write("G0 X0 Y0 S0 F" + str(speed))
72
+    write("G1 X1 Y0 S1 F" + str(speed))
73
+    write("G0 X0 Y0 S0 F" + str(speed))
74
+    write("G1 X0 Y1 S1 F" + str(speed))
75
+    write("G0 X0 Y0 S0 F" + str(speed))
76
+
77
+    write("G0 X" + str(x_min) + " Y" + str(y_min) + " S0 F" + str(speed))
78
+
79
+    for i in range(0, iterations):
80
+        for x, y in pos:
81
+            write("G1 X" + str(x) + " Y" + str(y) + " S" + str(pwr) + " F" + str(speed))
82
+
83
+    write("M5")
84
+    write("G0 X" + str(x_min) + " Y" + str(y_min) + " S0 F" + str(speed))
85
+
86
+def main():
87
+    if len(sys.argv) < 3:
88
+        print("Usage:")
89
+        print("    " + sys.argv[0] + " input.nc output.gcode")
90
+        sys.exit(1)
91
+
92
+    in_file = sys.argv[1]
93
+    out_file = sys.argv[2]
94
+
95
+    with open(in_file, 'r') as f:
96
+        bb = file_bounding_box(f)
97
+
98
+    with open(out_file, 'w') as f:
99
+        write_outline(f, bb)
100
+
101
+if __name__ == '__main__':
102
+    main()

+ 125
- 0
tools/send_gcode.py View File

@@ -0,0 +1,125 @@
1
+#!/usr/bin/env python
2
+
3
+import sys
4
+import serial
5
+
6
+if len(sys.argv) < 3:
7
+    print("Usage:")
8
+    print("    " + sys.argv[0] + " /dev/serial/port input.gcode")
9
+    sys.exit(1)
10
+
11
+port_file = sys.argv[1]
12
+in_file = sys.argv[2]
13
+
14
+port = serial.Serial()
15
+port.port = port_file
16
+port.baudrate = 115200
17
+#port.timeout = 0.0
18
+
19
+max_cmd_buffer = 5
20
+counter = 0
21
+
22
+def connect_serial():
23
+    try:
24
+        port.open()
25
+        if port.is_open:
26
+            print("connected to: " + port_file)
27
+        else:
28
+            print("error connecting to " + port_file)
29
+            sys.exit(1)
30
+    except serial.serialutil.SerialException:
31
+        print("error connecting to " + port_file)
32
+        sys.exit(1)
33
+
34
+def wait_for_text(s):
35
+    while True:
36
+        response = port.read_until().decode().strip()
37
+        print("rx w: " + response)
38
+        if response.startswith(s):
39
+            break
40
+        elif response.startswith("Error"):
41
+            print(response)
42
+            print("CNC returned error. aborting.")
43
+            abort_print(False)
44
+            port.close()
45
+            sys.exit(1)
46
+
47
+def abort_print(wait_for_oks = True):
48
+    global counter
49
+
50
+    print("tx: M5")
51
+    port.write("M5\n".encode())
52
+    counter += 1
53
+
54
+    print("tx: G0 X0 Y0 F1000")
55
+    port.write("G0 X0 Y0 F1000\n".encode())
56
+    counter += 1
57
+
58
+    if wait_for_oks:
59
+        while counter > 0:
60
+            wait_for_text("ok")
61
+            counter -= 1
62
+
63
+def send_file(f):
64
+    global counter
65
+
66
+    for line in f:
67
+        if ";" in line:
68
+            line = line.split(";")[0]
69
+
70
+        line = line.strip()
71
+
72
+        if len(line) <= 0:
73
+            print("skipping empty line")
74
+            continue
75
+
76
+        print("tx: " + line)
77
+        tx = line.encode() + b'\n'
78
+        port.write(tx)
79
+
80
+        counter += 1
81
+        print("cnt=" + str(counter))
82
+
83
+        while counter >= max_cmd_buffer:
84
+            response = port.read_until().decode().strip()
85
+            #print("rx: " + response)
86
+            if response.startswith("ok"):
87
+                counter -= 1
88
+                print("cnt=" + str(counter))
89
+            elif response.startswith("Error"):
90
+                print(response)
91
+                print("CNC returned error. aborting.")
92
+                abort_print(False)
93
+                port.close()
94
+                sys.exit(1)
95
+
96
+def main():
97
+    connect_serial()
98
+
99
+    print("waiting for CNC to reset")
100
+    wait_for_text("start")
101
+
102
+    print("auto-homing after reset")
103
+    print("tx: G28")
104
+    port.write("G28\n".encode())
105
+    wait_for_text("ok")
106
+
107
+    try:
108
+        with open(in_file, 'r') as f:
109
+            send_file(f)
110
+
111
+        while counter > 0:
112
+            wait_for_text("ok")
113
+            counter -= 1
114
+
115
+        print("workaround. kill when done.")
116
+        while True:
117
+            pass
118
+    except KeyboardInterrupt:
119
+        print("user interrupt. aborting.")
120
+        abort_print(True)
121
+
122
+    port.close()
123
+
124
+if __name__ == '__main__':
125
+    main()

Loading…
Cancel
Save