rintcore 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.ruby-version +1 -0
- data/CONTRIBUTING.md +10 -6
- data/README.md +24 -4
- data/bin/rintcore +5 -0
- data/lib/rint_core/cli.rb +87 -0
- data/lib/rint_core/driver.rb +22 -0
- data/lib/rint_core/driver/operating_system.rb +30 -0
- data/lib/rint_core/driver/operations.rb +209 -0
- data/lib/rint_core/driver/parsing.rb +39 -0
- data/lib/rint_core/driver/queueing.rb +73 -0
- data/lib/rint_core/driver/state.rb +71 -0
- data/lib/rint_core/g_code.rb +3 -2
- data/lib/rint_core/g_code/codes.rb +2 -2
- data/lib/rint_core/g_code/line.rb +83 -0
- data/lib/rint_core/g_code/object.rb +173 -0
- data/lib/rint_core/printer.rb +59 -0
- data/lib/rint_core/version.rb +1 -1
- data/rintcore.gemspec +3 -1
- metadata +53 -28
- data/lib/rint_core/printer_driver.rb +0 -312
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'rint_core/g_code/codes'
|
2
|
+
require 'active_support/core_ext/object/blank'
|
3
|
+
|
4
|
+
module RintCore
|
5
|
+
module Driver
|
6
|
+
module Queueing
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def initialize_queueing
|
11
|
+
@main_queue = []
|
12
|
+
@priority_queue = []
|
13
|
+
@queue_index = 0
|
14
|
+
@line_number = 0
|
15
|
+
@resend_from = -1
|
16
|
+
@machine_history = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def advance_queue
|
20
|
+
return false unless online? && printing?
|
21
|
+
until clear_to_send? do
|
22
|
+
sleep(config.sleep_time)
|
23
|
+
end
|
24
|
+
not_clear_to_send!
|
25
|
+
return true if resend_line
|
26
|
+
return true if run_priority_queue
|
27
|
+
if run_main_queue
|
28
|
+
return true
|
29
|
+
else
|
30
|
+
not_printing!
|
31
|
+
unless paused?
|
32
|
+
@queue_index = 0
|
33
|
+
@line_number = 0
|
34
|
+
send!(RintCore::GCode::Codes::SET_LINE_NUM, -1, true)
|
35
|
+
end
|
36
|
+
return true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def resend_line
|
41
|
+
if @resend_from == @line_number
|
42
|
+
@resend_from = -1
|
43
|
+
return nil
|
44
|
+
elsif @resend_from < @line_number && @resend_from > -1
|
45
|
+
send!(@machine_history[@resend_from], @resend_from, false)
|
46
|
+
@resend_from += 1
|
47
|
+
return true
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def run_priority_queue
|
52
|
+
unless @priority_queue.blank?
|
53
|
+
send!(@priority_queue.shift)
|
54
|
+
# clear_to_send!
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def run_main_queue
|
59
|
+
if !paused? && @queue_index < @main_queue.length
|
60
|
+
current_line = @main_queue[@queue_index]
|
61
|
+
current_line = current_line.to_s unless current_line.class == String
|
62
|
+
unless current_line.blank?
|
63
|
+
send!(current_line, @line_number, true)
|
64
|
+
@line_number += 1
|
65
|
+
end
|
66
|
+
@queue_index += 1
|
67
|
+
return true
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'rint_core/g_code/codes'
|
2
|
+
require 'active_support/core_ext/object/blank'
|
3
|
+
|
4
|
+
module RintCore
|
5
|
+
module Driver
|
6
|
+
module State
|
7
|
+
|
8
|
+
def can_print?
|
9
|
+
connected? && online? && !printing?
|
10
|
+
end
|
11
|
+
|
12
|
+
def connected?
|
13
|
+
@connection.present?
|
14
|
+
end
|
15
|
+
|
16
|
+
def clear_to_send?
|
17
|
+
@clear && online?
|
18
|
+
end
|
19
|
+
|
20
|
+
def listen_can_continue?
|
21
|
+
!@stop_listening && connected?
|
22
|
+
end
|
23
|
+
|
24
|
+
def online?
|
25
|
+
connected? && @online
|
26
|
+
end
|
27
|
+
|
28
|
+
def paused?
|
29
|
+
@paused
|
30
|
+
end
|
31
|
+
|
32
|
+
def printing?
|
33
|
+
@printing
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def initialize_state
|
39
|
+
@clear = false
|
40
|
+
@online = false
|
41
|
+
@printing = false
|
42
|
+
@paused = false
|
43
|
+
@stop_listening = false
|
44
|
+
end
|
45
|
+
|
46
|
+
def clear_to_send!
|
47
|
+
@clear = true
|
48
|
+
end
|
49
|
+
|
50
|
+
def not_clear_to_send!
|
51
|
+
@clear = false
|
52
|
+
end
|
53
|
+
|
54
|
+
def online!
|
55
|
+
@online = true
|
56
|
+
end
|
57
|
+
|
58
|
+
def offline!
|
59
|
+
@online = false
|
60
|
+
end
|
61
|
+
|
62
|
+
def printing!
|
63
|
+
@printing = true
|
64
|
+
end
|
65
|
+
|
66
|
+
def not_printing!
|
67
|
+
@printing = false
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/rint_core/g_code.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
module RintCore
|
2
2
|
module GCode
|
3
|
-
|
3
|
+
module Codes
|
4
4
|
RAPID_MOVE = 'G0'
|
5
5
|
CONTROLLED_MOVE = 'G1'
|
6
6
|
DWELL = 'G4'
|
7
7
|
HEAD_OFFSET = 'G10'
|
8
8
|
USE_INCHES = 'G20'
|
9
|
-
|
9
|
+
USE_MILLIMETRES = 'G21'
|
10
10
|
HOME = 'G28'
|
11
11
|
ABS_POSITIONING = 'G90'
|
12
12
|
REL_POSITIONING = 'G91'
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'rint_core/g_code/codes'
|
2
|
+
require 'active_support/core_ext/object/blank'
|
3
|
+
|
4
|
+
module RintCore
|
5
|
+
module GCode
|
6
|
+
class Line
|
7
|
+
include RintCore::GCode::Codes
|
8
|
+
|
9
|
+
attr_accessor :imperial, :relative, :f
|
10
|
+
attr_reader :raw
|
11
|
+
attr_writer :x, :y, :z, :e
|
12
|
+
|
13
|
+
def initialize(line)
|
14
|
+
@coordinates = ['X','Y','Z','E','F']
|
15
|
+
@number_pattern = /[-]?\d+[.]?\d*/
|
16
|
+
@raw = line.upcase.strip
|
17
|
+
@raw = @raw.split(COMMENT_SYMBOL).first.strip if line.include?(COMMENT_SYMBOL)
|
18
|
+
|
19
|
+
parse_coordinates
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_mm(number)
|
23
|
+
number *= 25.4 if number.present? && @imperial
|
24
|
+
number
|
25
|
+
end
|
26
|
+
|
27
|
+
def x
|
28
|
+
to_mm @x
|
29
|
+
end
|
30
|
+
|
31
|
+
def y
|
32
|
+
to_mm @y
|
33
|
+
end
|
34
|
+
|
35
|
+
def z
|
36
|
+
to_mm @z
|
37
|
+
end
|
38
|
+
|
39
|
+
def e
|
40
|
+
to_mm @e
|
41
|
+
end
|
42
|
+
|
43
|
+
def command
|
44
|
+
if @raw.present?
|
45
|
+
@raw.split(' ').first
|
46
|
+
else
|
47
|
+
''
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def get_float(axis)
|
52
|
+
@raw.split(axis).last.scan(@number_pattern).first.to_f
|
53
|
+
end
|
54
|
+
|
55
|
+
def parse_coordinates
|
56
|
+
@coordinates.each do |axis|
|
57
|
+
send(axis.downcase+'=', get_float(axis)) if @raw.include?(axis)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def is_move?
|
62
|
+
@raw.start_with?(RAPID_MOVE) || @raw.start_with?(CONTROLLED_MOVE)
|
63
|
+
end
|
64
|
+
|
65
|
+
def travel_move?
|
66
|
+
is_move? && !@e.present?
|
67
|
+
end
|
68
|
+
|
69
|
+
def extrusion_move?
|
70
|
+
is_move? && @e.present? && @e > 0
|
71
|
+
end
|
72
|
+
|
73
|
+
def full_home?
|
74
|
+
command == HOME && @x.blank? && @y.blank? && @z.blank?
|
75
|
+
end
|
76
|
+
|
77
|
+
def to_s
|
78
|
+
@raw
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
require 'rint_core/g_code/codes'
|
2
|
+
require 'rint_core/g_code/line'
|
3
|
+
require 'active_support/core_ext/object/blank'
|
4
|
+
|
5
|
+
module RintCore
|
6
|
+
module GCode
|
7
|
+
class Object
|
8
|
+
include RintCore::GCode::Codes
|
9
|
+
|
10
|
+
attr_accessor :raw_data, :layers
|
11
|
+
attr_reader :lines, :x_min, :x_max, :y_min, :y_max, :z_min, :z_max,
|
12
|
+
:filament_used, :x_travel, :y_travel, :z_travel, :e_travel,
|
13
|
+
:width, :depth, :height
|
14
|
+
|
15
|
+
def initialize(data = nil)
|
16
|
+
if data.class == String && self.class.is_file?(data)
|
17
|
+
data = self.class.get_file(data)
|
18
|
+
end
|
19
|
+
return false if data.blank? || data.class != Array
|
20
|
+
@raw_data = data
|
21
|
+
@imperial = false
|
22
|
+
@relative = false
|
23
|
+
@lines = []
|
24
|
+
data.each do |line|
|
25
|
+
line = RintCore::GCode::Line.new(line)
|
26
|
+
@lines << line if line.raw.present?
|
27
|
+
end
|
28
|
+
process
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.is_file?(file)
|
32
|
+
file.present? && File.exist?(file) && File.file?(file)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.get_file(file)
|
36
|
+
IO.readlines(file)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def process
|
42
|
+
set_variables
|
43
|
+
|
44
|
+
@lines.each do |line|
|
45
|
+
case line.command
|
46
|
+
when USE_INCHES
|
47
|
+
@imperial = true
|
48
|
+
when USE_MILLIMETRES
|
49
|
+
@imperial = false
|
50
|
+
when ABS_POSITIONING
|
51
|
+
@relative = false
|
52
|
+
when REL_POSITIONING
|
53
|
+
@relative = true
|
54
|
+
when SET_POSITION
|
55
|
+
set_positions(line)
|
56
|
+
when HOME
|
57
|
+
home_axes(line)
|
58
|
+
when RAPID_MOVE
|
59
|
+
movement_line(line)
|
60
|
+
when CONTROLLED_MOVE
|
61
|
+
count_layers(line)
|
62
|
+
movement_line(line)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
@width = @x_max - @x_min
|
67
|
+
@depth = @y_max - @y_min
|
68
|
+
@height = @z_max - @z_min
|
69
|
+
end
|
70
|
+
|
71
|
+
def count_layers(line)
|
72
|
+
if line.z.present? && line.z > @current_z
|
73
|
+
@layers += 1
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def movement_line(line)
|
78
|
+
line.imperial = @imperial
|
79
|
+
line.relative = @relative
|
80
|
+
measure_travel(line)
|
81
|
+
set_current_position(line)
|
82
|
+
set_limits(line)
|
83
|
+
end
|
84
|
+
|
85
|
+
def measure_travel(line)
|
86
|
+
if line.relative
|
87
|
+
@x_travel += line.x.abs if line.x.present?
|
88
|
+
@y_travel += line.y.abs if line.y.present?
|
89
|
+
@z_travel += line.z.abs if line.z.present?
|
90
|
+
else
|
91
|
+
@x_travel += (@current_x - line.x).abs if line.x.present?
|
92
|
+
@y_travel += (@current_y - line.y).abs if line.y.present?
|
93
|
+
@z_travel += (@current_z - line.z).abs if line.z.present?
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def home_axes(line)
|
98
|
+
if line.x.present? || line.full_home?
|
99
|
+
@x_travel += @current_x
|
100
|
+
@current_x = 0
|
101
|
+
end
|
102
|
+
if line.y.present? || line.full_home?
|
103
|
+
@y_travel += @current_y
|
104
|
+
@current_y = 0
|
105
|
+
end
|
106
|
+
if line.z.present? || line.full_home?
|
107
|
+
@z_travel += @current_z
|
108
|
+
@current_z = 0
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def set_positions(line)
|
113
|
+
@current_x = line.x if line.x.present?
|
114
|
+
@current_y = line.y if line.y.present?
|
115
|
+
@current_z = line.z if line.z.present?
|
116
|
+
if line.e.present?
|
117
|
+
@filament_used += @current_e
|
118
|
+
@current_e = line.e
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def set_current_position(line)
|
123
|
+
if line.relative
|
124
|
+
@current_x += line.x if line.x.present?
|
125
|
+
@current_y += line.y if line.y.present?
|
126
|
+
@current_z += line.z if line.z.present?
|
127
|
+
@current_e += line.e if line.e.present?
|
128
|
+
else
|
129
|
+
@current_x = line.x if line.x.present?
|
130
|
+
@current_y = line.y if line.y.present?
|
131
|
+
@current_z = line.z if line.z.present?
|
132
|
+
@current_e = line.e if line.e.present?
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def set_limits(line)
|
137
|
+
if line.extrusion_move?
|
138
|
+
if line.x.present? && !line.x.zero?
|
139
|
+
@x_min = @current_x if @current_x < @x_min
|
140
|
+
@x_max = @current_x if @current_x > @x_max
|
141
|
+
end
|
142
|
+
if line.y.present? && !line.y.zero?
|
143
|
+
@y_min = @current_y if @current_y < @y_min
|
144
|
+
@y_max = @current_y if @current_y > @y_max
|
145
|
+
end
|
146
|
+
end
|
147
|
+
if line.z.present?
|
148
|
+
@z_min = @current_z if @current_z < @z_min
|
149
|
+
@z_max = @current_z if @current_z > @z_max
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def set_variables
|
154
|
+
@x_travel = 0
|
155
|
+
@y_travel = 0
|
156
|
+
@z_travel = 0
|
157
|
+
@current_x = 0
|
158
|
+
@current_y = 0
|
159
|
+
@current_z = 0
|
160
|
+
@current_e = 0
|
161
|
+
@x_min = 999999999
|
162
|
+
@y_min = 999999999
|
163
|
+
@z_min = 0
|
164
|
+
@x_max = -999999999
|
165
|
+
@y_max = -999999999
|
166
|
+
@z_max = -999999999
|
167
|
+
@filament_used = 0
|
168
|
+
@layers = 0
|
169
|
+
end
|
170
|
+
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'rint_core/driver'
|
2
|
+
require 'active_support/configurable'
|
3
|
+
|
4
|
+
module RintCore
|
5
|
+
class Printer
|
6
|
+
include RintCore::Driver
|
7
|
+
include ActiveSupport::Configurable
|
8
|
+
|
9
|
+
# Callbacks are typically given a string argument, usually the current line
|
10
|
+
config_accessor :port, :baud, :callbacks, :error_response, :debug_response,
|
11
|
+
:online_response, :good_response, :temperature_response,
|
12
|
+
:resend_response, :encoding, :sleep_time, :wait_period,
|
13
|
+
:read_timeout, :long_sleep
|
14
|
+
|
15
|
+
self.port = "/dev/ttyACM0"
|
16
|
+
self.baud = 115200
|
17
|
+
self.callbacks = {}
|
18
|
+
self.error_response = 'Error'
|
19
|
+
self.debug_response = 'DEBUG_'
|
20
|
+
self.online_response = ['start','Grbl']
|
21
|
+
self.good_response = ['ok']
|
22
|
+
self.temperature_response = 'T:'
|
23
|
+
self.resend_response = ['rs','resend']
|
24
|
+
self.encoding = 'us-ascii'
|
25
|
+
self.sleep_time = 0.001
|
26
|
+
self.wait_period = 0
|
27
|
+
self.read_timeout = 0
|
28
|
+
self.long_sleep = 0.25
|
29
|
+
|
30
|
+
attr_reader :last_line_received, :main_queue, :queue_index, :resend_from, :machine_history, :full_history
|
31
|
+
|
32
|
+
def initialize(auto_connect = false)
|
33
|
+
initialize_driver
|
34
|
+
connect! if auto_connect
|
35
|
+
end
|
36
|
+
|
37
|
+
def time_from_start
|
38
|
+
@start_time ||= Time.now
|
39
|
+
secs = Time.now - @start_time
|
40
|
+
[[60, :seconds], [60, :minutes], [24, :hours], [1000, :days]].map{ |count, name|
|
41
|
+
if secs > 0
|
42
|
+
secs, n = secs.divmod(count)
|
43
|
+
"#{n.to_i} #{name}"
|
44
|
+
end
|
45
|
+
}.compact.reverse.join(' ')
|
46
|
+
end
|
47
|
+
|
48
|
+
class << self
|
49
|
+
def baud_rates
|
50
|
+
[2400, 9600, 19200, 38400, 57600, 115200, 250000]
|
51
|
+
end
|
52
|
+
|
53
|
+
def is_port?(port)
|
54
|
+
port.present? && File.exist?(port) && File.new(port).isatty
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|