-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathqr2gcode.rb
195 lines (164 loc) · 5.36 KB
/
qr2gcode.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
#
# QR2GCODE
# A QR Code to CNC (GRBL/GCODE) converter and generator
# January 2018 // Roman Mittermayr // mittermayr.com
#
# Enjoyed this? Drop me a Satoshi if you like:
# 1CJPbRRRAuxJ1m3SuR3u6NAntzrc5EP5py
#
#
# Note for really, ridiculously good programmers:
# This code is kept simple to make it easy to get a quick
# overview and allow for changes easily, by anyone.
# It could of course be optimised, severely.
#
require 'rqrcode'
# Settings
x_home = 10 #mm
y_home = 10 #mm
spacing = 1 #mm
feed_rate = 600
z_depth = -0.3 #mm
z_hover = 5 #mm
z_safe = 20 #mm
EOL = "\r\n"
vertical_refining = true
add_border = true
$gcode = ""
def add(code)
$gcode += code + EOL
end
unless ARGV.count.eql? 1
puts "\r\nSyntax: ruby qr2gcode.rb <string>\r\n\r\n"
abort
end
data = ARGV.first
# TODO check for input validity
qr = RQRCode::QRCode.new(data, :level => :h)
#png = qr.as_png(file: "qrcode.png")
add("%")
add("(Header)")
add("(Generated by QR2GCode)")
add("(Header end.)")
add("G21") # units in mm
add("G00 G90 G80 G40 G49")
add("G1 Z#{z_safe} F#{feed_rate}")
x = 0
y = 0
is_drilling = false
# Create a clean QR matrix
matrix = []
qr.modules.each do |row|
r = []
row.each do |col|
r << col
end
matrix.unshift(r) # reverse columns (0 origin is top/left on computer, but bottom/left on machine)
end
row_length = matrix[0].length
# Start with the horizontal paths
matrix.each do |row|
row.each_with_index do |col, col_index|
# Check if the next is also active, this means we can
# leave the drill down, and carve a line
is_next_active = false
if col_index < (row_length-1)
next_item = row[col_index+1]
is_next_active = true if next_item
end
if col # active dot? Then drill!
_x = x_home + x
_y = y_home + y
# Part 1: Move to the place we want to drill
if is_drilling # Could be already drilling, don't go any lower then!!
add("G1 X#{_x} Y#{_y}")
else # Not drilling? Stay above ground while moving, until it's time to drill
add("G1 X#{_x} Y#{_y} Z#{z_hover}")
end
# Okay, we're positioned - if we're not yet drilling, drill now.
add("G1 Z#{z_depth} F#{feed_rate}") unless is_drilling
is_drilling = true # Now we're definitely drilling
unless is_next_active # If this was just a single dot, then lift the drill
add("G1 Z#{z_hover} F#{feed_rate}")
is_drilling = false
end
end
x += spacing
end
# End of line: Lift up here, if drilling
add("G1 Z#{z_hover} F#{feed_rate}") if is_drilling
is_drilling = false
y += spacing
x = 0
end
# "Vertically-focused" QR matrix
if vertical_refining
# All horizontal lines are done, let's transpose so we can go vertically now
matrix = matrix.transpose
# Return to start, then do the same but with vertifal refinements
add("G1 Z#{z_safe} F#{feed_rate}")
add("G00 X0 Y0")
x = 0
y = 0
is_drilling = false
matrix.each do |col|
col.each_with_index do |row_item,row_index|
# Only check whether or not we're part of a line if we are an active dot
part_of_line = false
is_next_active = false
if row_item # is active dot?
if row_index == 0 # First dot
# Only check if next dot is active
part_of_line = true if col[row_index+1]
is_next_active = true
elsif row_index == (row_length-1) # Last dot
# Only check if previous dot is active
part_of_line = true if col[row_index-1]
else # Middle dot
# Check if EITHER previous or next is active
part_of_line = true if col[row_index-1]
part_of_line = true if col[row_index+1]
is_next_active = true if col[row_index+1]
end
end
# If this is a 'single dot', then skip here
# We are only refining lines, no point in working on that dot again
if part_of_line
_x = x_home + x
_y = y_home + y
if is_drilling # drilling already, keep on carvin'
add("G1 X#{_x} Y#{_y}")
else # Not drilling, so stay above ground until we're there
add("G1 X#{_x} Y#{_y} Z#{z_hover}")
end
add("G1 Z#{z_depth} F#{feed_rate}") unless is_drilling
is_drilling = true # Now we're definitely drilling
unless is_next_active
add("G1 Z#{z_hover} F#{feed_rate}") # Lift up, if we're done drilling
is_drilling = false
end
end # part of a line?
y += spacing
end # end of column
# Lift up here, if drilling
add("G1 Z#{z_hover} F#{feed_rate}") if is_drilling
is_drilling = false
x += spacing # Move to next column
y = 0 # Start back at the top
end
end # of vertical_refining
if add_border
padding = 5
add("G1 X#{x_home-padding} Y#{y_home-padding} Z#{z_safe}")
add("G1 Z#{z_depth}")
add("G1 X#{x_home-padding} Y#{y_home+padding+(spacing*row_length)}")
add("G1 X#{x_home+padding+(spacing*row_length)} Y#{y_home+padding+(spacing*row_length)}")
add("G1 X#{x_home+padding+(spacing*row_length)} Y#{y_home-padding}")
add("G1 X#{x_home-padding} Y#{y_home-padding}")
add("G1 Z#{z_safe}")
end
add("G1 Z#{z_safe} F#{feed_rate}")
add("G00 X0 Y0")
add("M30")
add("%")
File.open("qrcode.ngc", "w") { |f| f.write($gcode) }