farmbot-serial 0.6.2 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/arduino/incoming_handler.rb +9 -5
- data/lib/arduino/outgoing_handler.rb +53 -1
- data/lib/arduino/status.rb +19 -17
- data/lib/gcode.rb +4 -1
- data/lib/gcode.yml +2 -0
- data/lib/parameters.yml +25 -0
- data/serial-console.rb +45 -0
- data/spec/lib/arduino/incoming_handler_spec.rb +6 -4
- data/spec/lib/arduino/outgoing_handler_spec.rb +75 -0
- data/spec/lib/arduino/status_spec.rb +1 -1
- data/spec/lib/gcode_spec.rb +0 -5
- data/spec/spec_helper.rb +0 -16
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: caf76751695f80320148ccda60a2b7f5f90d99ce
|
4
|
+
data.tar.gz: df0cb1eed0147a30522799aa64f1ddedb599b773
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 18dffa6b60f61e21f179f770e61d92b75df8a249c7f35afc324a24341571b0b3f82bfcf369579e459315ae88117a71465ca7a8c305cc48701dc76d59ed4c943b
|
7
|
+
data.tar.gz: b77c02b6530fe4aa310149d8ce66591c353165708dbe85ebe194df89ee0e2dc7e8aae70a8c34cc5f39d2b0a93761a4600f37db3aa911f7072930bcf42af102e5
|
@@ -8,17 +8,21 @@ module FB
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def execute(gcode)
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
name = gcode.name
|
12
|
+
if respond_to?(name)
|
13
|
+
self.send(name, gcode)
|
14
|
+
else
|
15
|
+
bot.log "#{gcode.name} is a valid GCode, but no input handler method exists"
|
16
|
+
end
|
14
17
|
end
|
15
18
|
|
16
19
|
def unknown(gcode)
|
17
20
|
bot.log "Don't know how to parse incoming GCode: #{gcode}"
|
18
21
|
end
|
19
22
|
|
23
|
+
# Called when the Ardunio is reporting the status of a parameter.
|
20
24
|
def report_parameter_value(gcode)
|
21
|
-
bot.status.
|
25
|
+
bot.status.set(gcode.value_of(:P), gcode.value_of(:V))
|
22
26
|
end
|
23
27
|
|
24
28
|
def reporting_end_stops(gcode)
|
@@ -31,7 +35,7 @@ module FB
|
|
31
35
|
|
32
36
|
def report_status_value(gcode)
|
33
37
|
# TODO: Verfiy the accuracy of this code. CC: @timevww
|
34
|
-
bot.status.
|
38
|
+
bot.status.set(gcode.value_of(:P), gcode.value_of(:V))
|
35
39
|
end
|
36
40
|
|
37
41
|
def received(gcode)
|
@@ -65,13 +65,65 @@ module FB
|
|
65
65
|
|
66
66
|
def pin_write(pin:, value:, mode:)
|
67
67
|
write { "F41 P#{pin} V#{value} M#{mode}" }
|
68
|
-
bot.status.
|
68
|
+
bot.status.set(pin, value)
|
69
|
+
end
|
70
|
+
|
71
|
+
def set_max_speed(axis, value)
|
72
|
+
set_paramater_value(axis, value, 71, 72, 73)
|
73
|
+
end
|
74
|
+
|
75
|
+
def set_acceleration(axis, value)
|
76
|
+
set_paramater_value(axis, value, 41, 42, 43)
|
77
|
+
end
|
78
|
+
|
79
|
+
def set_timeout(axis, value)
|
80
|
+
set_paramater_value(axis, value, 11, 12, 13)
|
81
|
+
end
|
82
|
+
|
83
|
+
def set_steps_per_mm(axis, value)
|
84
|
+
raise "The Farmbot Arduino does not currently store a value for steps "\
|
85
|
+
"per mm. Keep track of this information at the application level"
|
86
|
+
end
|
87
|
+
|
88
|
+
def set_end_inversion(axis, value)
|
89
|
+
set_paramater_value(axis, bool_to_int(value), 21, 22, 23)
|
90
|
+
end
|
91
|
+
|
92
|
+
def set_motor_inversion(axis, value)
|
93
|
+
set_paramater_value(axis, bool_to_int(value), 31, 32, 33)
|
94
|
+
end
|
95
|
+
|
96
|
+
def set_negative_coordinates(axis, value)
|
97
|
+
raise "Not yet implemented. TODO: This method."
|
69
98
|
end
|
70
99
|
|
71
100
|
private
|
72
101
|
|
102
|
+
class InvalidAxisEntry < Exception; end
|
103
|
+
class BadBooleanValue < Exception; end
|
104
|
+
|
105
|
+
# The Arduino uses a different parameter number for each axis. Ex:
|
106
|
+
# MOVEMENT_TIMEOUT_X is 11 and MOVEMENT_TIMEOUT_Y is 12. To keep things dry,
|
107
|
+
# this method will lookup the correct paramater numer based on the axis
|
108
|
+
# provided and the three options available (if_x, if_y, if_z)
|
109
|
+
def set_paramater_value(axis, value, if_x, if_y, if_z)
|
110
|
+
param_num = { 'x' => if_x, 'y' => if_y, 'z' => if_z }[axis.to_s.downcase]
|
111
|
+
raise InvalidAxisEntry, "You entered an invalid axis" unless param_num
|
112
|
+
write { "F22 P#{param_num} V#{value.to_s}" }
|
113
|
+
end
|
114
|
+
|
73
115
|
def write(&blk)
|
74
116
|
bot.write(FB::Gcode.new(&blk))
|
75
117
|
end
|
118
|
+
|
119
|
+
def bool_to_int(value)
|
120
|
+
case value
|
121
|
+
when true, 'true', 1, '1' then 1
|
122
|
+
when false, 'false', 0, '0' then 0
|
123
|
+
else
|
124
|
+
raise BadBooleanValue, "Farmbot expected a boolean value in one of "\
|
125
|
+
"the following forms: [true, false, 1, 0]"
|
126
|
+
end
|
127
|
+
end
|
76
128
|
end
|
77
129
|
end
|
data/lib/arduino/status.rb
CHANGED
@@ -1,12 +1,11 @@
|
|
1
1
|
module FB
|
2
2
|
class Status
|
3
3
|
# Map of informational status and default values for status within Arduino.
|
4
|
-
DEFAULT_INFO = {X: 0, Y: 0, Z: 0, S: 10, BUSY: 1, LAST: 'none'
|
5
|
-
Info = Struct.new(*DEFAULT_INFO.keys)
|
4
|
+
DEFAULT_INFO = {X: 0, Y: 0, Z: 0, S: 10, BUSY: 1, LAST: 'none'}
|
6
5
|
|
7
6
|
def initialize
|
8
7
|
@changes = EM::Channel.new
|
9
|
-
@info =
|
8
|
+
@info = OpenStruct.new(DEFAULT_INFO)
|
10
9
|
end
|
11
10
|
|
12
11
|
def transaction(&blk)
|
@@ -18,14 +17,11 @@ module FB
|
|
18
17
|
end
|
19
18
|
|
20
19
|
def []=(register, value)
|
21
|
-
transaction
|
22
|
-
register = register.upcase.to_sym
|
23
|
-
@info[register] = value if @info.members.include?(register)
|
24
|
-
end
|
20
|
+
transaction { @info[register.to_s.upcase] = value }
|
25
21
|
end
|
26
22
|
|
27
23
|
def [](value)
|
28
|
-
@info[value.upcase.
|
24
|
+
@info[value.upcase.to_s]
|
29
25
|
end
|
30
26
|
|
31
27
|
def to_h
|
@@ -34,10 +30,7 @@ module FB
|
|
34
30
|
|
35
31
|
def gcode_update(gcode)
|
36
32
|
transaction do
|
37
|
-
gcode.params.each
|
38
|
-
setter = "#{p.head}="
|
39
|
-
@info.send(setter, p.tail) if @info.respond_to?(setter)
|
40
|
-
end
|
33
|
+
gcode.params.each { |p| @info[p.head] = p.tail }
|
41
34
|
end
|
42
35
|
end
|
43
36
|
|
@@ -49,13 +42,22 @@ module FB
|
|
49
42
|
self[:BUSY] == 0
|
50
43
|
end
|
51
44
|
|
52
|
-
def
|
53
|
-
@info[
|
45
|
+
def get(val)
|
46
|
+
@info[val.to_s.upcase] || :unknown
|
47
|
+
end
|
48
|
+
|
49
|
+
def set(key, val)
|
50
|
+
transaction do |info|
|
51
|
+
info[Gcode::PARAMETER_DICTIONARY.fetch(key, key.to_s)] = val
|
52
|
+
end
|
54
53
|
end
|
55
54
|
|
56
|
-
def
|
57
|
-
|
58
|
-
|
55
|
+
def pin(num)
|
56
|
+
case get(num)
|
57
|
+
when false, 0, :off then :off
|
58
|
+
when true, 1, :on then :on
|
59
|
+
else; :unknown
|
60
|
+
end
|
59
61
|
end
|
60
62
|
end
|
61
63
|
end
|
data/lib/gcode.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
module FB
|
3
3
|
class Gcode
|
4
|
-
GCODE_DICTIONARY
|
4
|
+
GCODE_DICTIONARY = YAML.load_file(File.join(File.dirname(__FILE__),
|
5
|
+
'gcode.yml'))
|
6
|
+
PARAMETER_DICTIONARY = YAML.load_file(File.join(File.dirname(__FILE__),
|
7
|
+
'parameters.yml'))
|
5
8
|
|
6
9
|
attr_accessor :cmd, :params, :block
|
7
10
|
|
data/lib/gcode.yml
CHANGED
data/lib/parameters.yml
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# Internally, the arduino uses a number code for each status. Those statuses are
|
2
|
+
# defined here.
|
3
|
+
---
|
4
|
+
0: :PARAM_VERSION
|
5
|
+
11: :MOVEMENT_TIMEOUT_X
|
6
|
+
12: :MOVEMENT_TIMEOUT_Y
|
7
|
+
13: :MOVEMENT_TIMEOUT_Z
|
8
|
+
21: :MOVEMENT_INVERT_ENDPOINTS_X
|
9
|
+
22: :MOVEMENT_INVERT_ENDPOINTS_Y
|
10
|
+
23: :MOVEMENT_INVERT_ENDPOINTS_Z
|
11
|
+
31: :MOVEMENT_INVERT_MOTOR_X
|
12
|
+
32: :MOVEMENT_INVERT_MOTOR_Y
|
13
|
+
33: :MOVEMENT_INVERT_MOTOR_Z
|
14
|
+
41: :MOVEMENT_STEPS_ACC_DEC_X
|
15
|
+
42: :MOVEMENT_STEPS_ACC_DEC_Y
|
16
|
+
43: :MOVEMENT_STEPS_ACC_DEC_Z
|
17
|
+
51: :MOVEMENT_HOME_UP_X
|
18
|
+
52: :MOVEMENT_HOME_UP_Y
|
19
|
+
53: :MOVEMENT_HOME_UP_Z
|
20
|
+
61: :MOVEMENT_MIN_SPD_X
|
21
|
+
62: :MOVEMENT_MIN_SPD_Y
|
22
|
+
63: :MOVEMENT_MIN_SPD_Z
|
23
|
+
71: :MOVEMENT_MAX_SPD_X
|
24
|
+
72: :MOVEMENT_MAX_SPD_Y
|
25
|
+
73: :MOVEMENT_MAX_SPD_Z
|
data/serial-console.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative 'lib/farmbot-serial'
|
2
|
+
require 'pry'
|
3
|
+
|
4
|
+
connection = FB::DefaultSerialPort.new('/dev/ttyUSB0')
|
5
|
+
|
6
|
+
puts """
|
7
|
+
THIS IS A SERIAL TERMINAL.
|
8
|
+
|
9
|
+
"""
|
10
|
+
|
11
|
+
print "> "
|
12
|
+
|
13
|
+
class KeyboardHandler < EM::Connection
|
14
|
+
include EM::Protocols::LineText2
|
15
|
+
|
16
|
+
attr_reader :connection
|
17
|
+
|
18
|
+
def initialize(connection)
|
19
|
+
@connection = connection
|
20
|
+
end
|
21
|
+
|
22
|
+
def receive_line(data)
|
23
|
+
connection.puts(data.chomp + "\r\n")
|
24
|
+
puts("Computer: #{data}")
|
25
|
+
end
|
26
|
+
|
27
|
+
def unbind
|
28
|
+
EM.stop
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class SerialHandler < EventMachine::Connection
|
33
|
+
def receive_data(data)
|
34
|
+
puts("Arduino: #{data}")
|
35
|
+
end
|
36
|
+
|
37
|
+
def unbind
|
38
|
+
EM.stop
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
EM.run do
|
43
|
+
EM.open_keyboard(KeyboardHandler, connection)
|
44
|
+
EM.attach(connection,)
|
45
|
+
end
|
@@ -5,16 +5,18 @@ describe FB::IncomingHandler do
|
|
5
5
|
let(:bot) { FakeArduino.new }
|
6
6
|
let(:handler) { FB::IncomingHandler.new(bot) }
|
7
7
|
|
8
|
+
it 'gets calibration data' do
|
9
|
+
gcode = FB::Gcode.new { "R21 P71 V7654" }
|
10
|
+
handler.execute(gcode)
|
11
|
+
expect(bot.status.to_h[:MOVEMENT_MAX_SPD_X]).to eq(7654)
|
12
|
+
end
|
13
|
+
|
8
14
|
it 'handles unknowns' do
|
9
15
|
handler.execute(FakeGcode.new('hello', 'abc'))
|
10
16
|
expectation = "hello is a valid GCode, but no input handler method exists"
|
11
17
|
expect(bot.logger.message).to eq(expectation)
|
12
18
|
end
|
13
19
|
|
14
|
-
# def report_parameter_value(gcode)
|
15
|
-
# bot.status.set_pin(gcode.value_of(:P), gcode.value_of(:V))
|
16
|
-
# end
|
17
|
-
|
18
20
|
it 'reports the value of a parameter' do
|
19
21
|
handler.report_parameter_value(FB::Gcode.new { "A1 P1 V0" })
|
20
22
|
expect(bot.status.pin(1)).to eq(:off)
|
@@ -73,4 +73,79 @@ describe FB::OutgoingHandler do
|
|
73
73
|
handler.pin_write(pin: 0, value: 1, mode: 3)
|
74
74
|
expect(bot.next_cmd.to_s).to eq("F41 P0 V1 M3")
|
75
75
|
end
|
76
|
+
|
77
|
+
it 'sets max speed' do
|
78
|
+
handler.set_max_speed(:x, 1000)
|
79
|
+
expect(bot.next_cmd.to_s).to eq("F22 P71 V1000")
|
80
|
+
handler.set_max_speed(:Y, 100)
|
81
|
+
expect(bot.next_cmd.to_s).to eq("F22 P72 V100")
|
82
|
+
handler.set_max_speed('z', 1)
|
83
|
+
expect(bot.next_cmd.to_s).to eq("F22 P73 V1")
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'sets acceleration' do
|
87
|
+
handler.set_acceleration(:x, 123)
|
88
|
+
expect(bot.next_cmd.to_s).to eq("F22 P41 V123")
|
89
|
+
handler.set_acceleration(:y, 123)
|
90
|
+
expect(bot.next_cmd.to_s).to eq("F22 P42 V123")
|
91
|
+
handler.set_acceleration(:z, 123)
|
92
|
+
expect(bot.next_cmd.to_s).to eq("F22 P43 V123")
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'sets a timeout' do
|
96
|
+
handler.set_timeout(:x, 223)
|
97
|
+
expect(bot.next_cmd.to_s).to eq("F22 P11 V223")
|
98
|
+
handler.set_timeout(:y, 223)
|
99
|
+
expect(bot.next_cmd.to_s).to eq("F22 P12 V223")
|
100
|
+
handler.set_timeout(:z, 223)
|
101
|
+
expect(bot.next_cmd.to_s).to eq("F22 P13 V223")
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'sets end stop inversion' do
|
105
|
+
handler.set_end_inversion(:x, true)
|
106
|
+
expect(bot.next_cmd.to_s).to eq("F22 P21 V1")
|
107
|
+
handler.set_end_inversion(:y, '0')
|
108
|
+
expect(bot.next_cmd.to_s).to eq("F22 P22 V0")
|
109
|
+
handler.set_end_inversion(:z, 1)
|
110
|
+
expect(bot.next_cmd.to_s).to eq("F22 P23 V1")
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'sets motor inversion' do
|
114
|
+
handler.set_motor_inversion(:x, false)
|
115
|
+
expect(bot.next_cmd.to_s).to eq("F22 P31 V0")
|
116
|
+
handler.set_motor_inversion(:y, '1')
|
117
|
+
expect(bot.next_cmd.to_s).to eq("F22 P32 V1")
|
118
|
+
handler.set_motor_inversion(:z, 0)
|
119
|
+
expect(bot.next_cmd.to_s).to eq("F22 P33 V0")
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'does NOT set negative coordinates' do
|
123
|
+
expect do
|
124
|
+
handler.set_negative_coordinates(:x, 99)
|
125
|
+
end.to raise_exception
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'does NOT set steps per mm (thats not the Arduinos job)' do
|
129
|
+
expect do
|
130
|
+
handler.set_steps_per_mm(:x, 99)
|
131
|
+
end.to raise_exception
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'sets end inversion' do
|
135
|
+
expect do
|
136
|
+
handler.set_steps_per_mm(:x, 99)
|
137
|
+
end.to raise_exception
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'raises exceptions when given invalid axis names' do
|
141
|
+
expect do
|
142
|
+
handler.set_max_speed('q', 1)
|
143
|
+
end.to raise_exception(FB::OutgoingHandler::InvalidAxisEntry)
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'handles bad inputs when inverting motors / steps' do
|
147
|
+
expect do
|
148
|
+
handler.set_motor_inversion(:x, 4)
|
149
|
+
end.to raise_exception(FB::OutgoingHandler::BadBooleanValue)
|
150
|
+
end
|
76
151
|
end
|
data/spec/lib/gcode_spec.rb
CHANGED
@@ -44,10 +44,5 @@ describe FB::Gcode do
|
|
44
44
|
expect(FB::Gcode.new{ " " }.cmd.head).to eq(null_token.head)
|
45
45
|
expect(FB::Gcode.new{ " " }.cmd.tail).to eq(null_token.tail)
|
46
46
|
end
|
47
|
-
|
48
|
-
it 'sets dyanmic parameters' do
|
49
|
-
random_gcode = FB::Gcode.new{ "Q#{Time.now.to_f.to_s[-2, 2]}" }
|
50
|
-
expect(random_gcode.cmd.tail).to_not eq(random_gcode.cmd.tail)
|
51
|
-
end
|
52
47
|
end
|
53
48
|
|
data/spec/spec_helper.rb
CHANGED
@@ -12,22 +12,6 @@ require_relative 'fakes/fake_logger'
|
|
12
12
|
require_relative 'fakes/fake_arduino'
|
13
13
|
require_relative 'fakes/fake_gcode'
|
14
14
|
|
15
|
-
require 'ruby-prof'
|
16
|
-
|
17
|
-
RSpec.configure do |config|
|
18
|
-
config.before(:suite) do
|
19
|
-
# Profile the code
|
20
|
-
RubyProf.start
|
21
|
-
end
|
22
|
-
|
23
|
-
config.after(:suite) do
|
24
|
-
result = RubyProf.stop
|
25
|
-
# Print a flat profile to text
|
26
|
-
printer = RubyProf::FlatPrinter.new(result)
|
27
|
-
printer.print(STDOUT)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
15
|
# This is used for testing things that require an event loop. Once run, you can
|
32
16
|
# observe / make assertions on side effects.
|
33
17
|
def within_event_loop(ticks_remaining = 1)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: farmbot-serial
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tim Evers
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-08-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -144,6 +144,8 @@ files:
|
|
144
144
|
- lib/farmbot-serial.rb
|
145
145
|
- lib/gcode.rb
|
146
146
|
- lib/gcode.yml
|
147
|
+
- lib/parameters.yml
|
148
|
+
- serial-console.rb
|
147
149
|
- spec/fakes/fake_arduino.rb
|
148
150
|
- spec/fakes/fake_gcode.rb
|
149
151
|
- spec/fakes/fake_logger.rb
|