rintcore 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|