farmbot-serial 0.0.9 → 0.1.0
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 +4 -4
- data/README.md +22 -1
- data/console.rb +55 -0
- data/lib/arduino.rb +7 -4
- data/lib/arduino/event_machine.rb +1 -1
- data/lib/arduino/outgoing_handler.rb +4 -0
- data/lib/arduino/status.rb +7 -13
- data/lib/gcode.rb +4 -3
- data/lib/gcode.yml +5 -0
- data/spec/fixtures/stub_logger.rb +5 -0
- data/spec/lib/arduino/status_spec.rb +40 -0
- data/spec/lib/gcode_spec.rb +5 -0
- data/spec/spec_helper.rb +7 -0
- metadata +7 -3
- data/example.rb +0 -50
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8656fb126d608b73102d0a77ac29d38e5fa60647
|
4
|
+
data.tar.gz: 67f35f21edc7b07e20894ef6e0f8768dd5d41751
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 99d37958fcc632fea80f2393becb10da870d94289045a6b22c75e2f1a23c820f07c227f8ac92086598e4f55172fa81d88380dbcb591725edb873f0bba81f2eb5
|
7
|
+
data.tar.gz: c30665c95c08c2bd69be3ef65adf51ea7869ff41b2d94a712c00fdc8f92e16970e951c67de05f0cb434fe7ca6cb3cc9eb7df91dcd521fa421c029bcb313941d6
|
data/README.md
CHANGED
@@ -2,13 +2,34 @@
|
|
2
2
|
|
3
3
|
A ruby gem for controlling Farmbot via serial line with EventMachine.
|
4
4
|
|
5
|
-
|
5
|
+
# Usage
|
6
|
+
|
7
|
+
## As an Interactive Console or Debugger
|
8
|
+
|
9
|
+
```
|
10
|
+
git clone https://github.com/FarmBot/farmbot-serial.git
|
11
|
+
cd farmbot-serial
|
12
|
+
ruby console.rb
|
13
|
+
|
14
|
+
```
|
15
|
+
|
16
|
+
From there, you can type commands, such as:
|
17
|
+
|
18
|
+
```
|
19
|
+
move_relative x: 100
|
20
|
+
```
|
21
|
+
|
22
|
+
All REPL commands will be executed within the context of `bot.commands`.
|
23
|
+
|
24
|
+
## As an Application
|
6
25
|
|
7
26
|
```
|
8
27
|
gem install farmbot-serial, '0.0.5'
|
28
|
+
|
9
29
|
```
|
10
30
|
|
11
31
|
```ruby
|
32
|
+
require 'eventmachine'
|
12
33
|
require 'farmbot-serial'
|
13
34
|
|
14
35
|
bot = FB::Arduino.new # Defaults to '/dev/ttyACM0', can be configured.
|
data/console.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require_relative 'lib/farmbot-serial'
|
2
|
+
require 'pry'
|
3
|
+
|
4
|
+
bot = FB::Arduino.new # Defaults to '/dev/ttyACM0', can be configured.
|
5
|
+
|
6
|
+
puts """
|
7
|
+
FARMBOT SERIAL SANDBOX. WELCOME!
|
8
|
+
================================
|
9
|
+
|
10
|
+
Example commands:
|
11
|
+
|
12
|
+
emergency_stop
|
13
|
+
move_relative x: 600, y: 100, z: 4
|
14
|
+
move_relative y: -600
|
15
|
+
home_x
|
16
|
+
home_y
|
17
|
+
home_z
|
18
|
+
home_all
|
19
|
+
read_parameter(8)
|
20
|
+
write_parameter('x', 0)
|
21
|
+
write_pin(pin: 8, value: 1, mode: 1)
|
22
|
+
read_status(8)
|
23
|
+
"""
|
24
|
+
print "> "
|
25
|
+
|
26
|
+
class KeyboardHandler < EM::Connection
|
27
|
+
include EM::Protocols::LineText2
|
28
|
+
|
29
|
+
attr_reader :bot
|
30
|
+
|
31
|
+
def initialize(bot)
|
32
|
+
@bot = bot
|
33
|
+
end
|
34
|
+
|
35
|
+
def receive_line(data)
|
36
|
+
puts (bot.commands.instance_eval(data) || "OK")
|
37
|
+
print "> "
|
38
|
+
rescue Exception => exc
|
39
|
+
exit(0) if data.start_with?('q')
|
40
|
+
puts "#{exc.message} : "
|
41
|
+
print "> "
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
EM.run do
|
46
|
+
FB::ArduinoEventMachine.connect(bot)
|
47
|
+
bot.onmessage do |gcode|
|
48
|
+
bot.log "NEW MESSAGE : #{gcode};" unless gcode.cmd.head == :R
|
49
|
+
end
|
50
|
+
bot.onchange { |diff| puts "STATUS CHANGE: #{diff};" }
|
51
|
+
bot.onclose { puts "bye!"; EM.stop } # Unplug the bot and see
|
52
|
+
# EventMachine::PeriodicTimer.new(7) { print '.'; bot.serial_port.puts "F31 P8" }
|
53
|
+
EM.open_keyboard(KeyboardHandler, bot)
|
54
|
+
end
|
55
|
+
|
data/lib/arduino.rb
CHANGED
@@ -8,6 +8,7 @@ require_relative 'arduino/status'
|
|
8
8
|
module FB
|
9
9
|
class Arduino
|
10
10
|
class EmergencyStop < StandardError; end # Not yet used.
|
11
|
+
Position = Struct.new(:x, :y, :z)
|
11
12
|
|
12
13
|
attr_accessor :serial_port, :logger, :commands, :inbound_queue, :status,
|
13
14
|
:inputs, :outbound_queue
|
@@ -23,7 +24,7 @@ module FB
|
|
23
24
|
@logger = logger
|
24
25
|
@commands = FB::OutgoingHandler.new(self)
|
25
26
|
@inputs = FB::IncomingHandler.new(self)
|
26
|
-
@status = FB::Status.new
|
27
|
+
@status = FB::Status.new
|
27
28
|
|
28
29
|
start_event_listeners
|
29
30
|
end
|
@@ -58,6 +59,10 @@ module FB
|
|
58
59
|
@onclose.call if @onclose
|
59
60
|
end
|
60
61
|
|
62
|
+
def current_position
|
63
|
+
Position.new(status[:X], status[:Y], status[:Z])
|
64
|
+
end
|
65
|
+
|
61
66
|
private
|
62
67
|
|
63
68
|
# Highest priority message when processing incoming Gcode. Use for system
|
@@ -69,13 +74,11 @@ module FB
|
|
69
74
|
def execute_command_next_tick
|
70
75
|
EM.next_tick do
|
71
76
|
if status.ready?
|
72
|
-
|
73
|
-
log "Sending queue after #{diff}s delay" if diff > 0
|
77
|
+
log "Exec after #{(Time.now - (@time || Time.now)).to_i}s wait"
|
74
78
|
serial_port.puts @outbound_queue.pop
|
75
79
|
@time = nil
|
76
80
|
else
|
77
81
|
@time ||= Time.now
|
78
|
-
serial_port.puts "F31 P8"
|
79
82
|
execute_command_next_tick
|
80
83
|
end
|
81
84
|
end
|
data/lib/arduino/status.rb
CHANGED
@@ -3,20 +3,20 @@ module FB
|
|
3
3
|
# Map of informational status and default values for status within Arduino.
|
4
4
|
DEFAULT_INFO = {X: 0, Y: 0, Z: 0, S: 10, Q: 0, T: 0, C: '', P: 0, V: 0,
|
5
5
|
W: 0, L: 0, E: 0, M: 0, XA: 0, XB: 0, YA: 0, YB: 0, ZA: 0,
|
6
|
-
ZB: 0,YR: 0, R: 0, BUSY:
|
6
|
+
ZB: 0,YR: 0, R: 0, BUSY: 1}
|
7
7
|
Info = Struct.new(*DEFAULT_INFO.keys)
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
def initialize(bot)
|
9
|
+
def initialize
|
12
10
|
@changes = EM::Channel.new
|
13
|
-
@
|
11
|
+
@info = Info.new(*DEFAULT_INFO.values)
|
14
12
|
end
|
15
13
|
|
16
14
|
def transaction(&blk)
|
17
15
|
old = @info.to_h
|
18
|
-
yield
|
19
|
-
|
16
|
+
yield(@info)
|
17
|
+
# Broadcast a diff between the old status and new status
|
18
|
+
diff = (@info.to_h.to_a - old.to_a).to_h
|
19
|
+
@changes << diff unless diff.empty?
|
20
20
|
end
|
21
21
|
|
22
22
|
def []=(register, value)
|
@@ -40,11 +40,5 @@ module FB
|
|
40
40
|
def ready?
|
41
41
|
self[:BUSY] == 0
|
42
42
|
end
|
43
|
-
|
44
|
-
def emit_updates(old)
|
45
|
-
# calculate a diff between the old status and new status
|
46
|
-
diff = (@info.to_h.to_a - old.to_a).to_h
|
47
|
-
@changes << diff unless diff.empty?
|
48
|
-
end
|
49
43
|
end
|
50
44
|
end
|
data/lib/gcode.rb
CHANGED
@@ -6,9 +6,9 @@ module FB
|
|
6
6
|
attr_accessor :cmd, :params, :str
|
7
7
|
|
8
8
|
def initialize(str)
|
9
|
-
@str
|
10
|
-
@params = str.split(' ').map{|line| GcodeToken.new(line)}
|
11
|
-
@cmd
|
9
|
+
@str = str
|
10
|
+
@params = str.split(' ').map { |line| GcodeToken.new(line) }
|
11
|
+
@cmd = @params.shift || 'NULL'
|
12
12
|
end
|
13
13
|
|
14
14
|
# Turns a string of many gcodes into an array of many gcodes. Used to parse
|
@@ -23,6 +23,7 @@ module FB
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def to_s
|
26
|
+
# self.to_s # => "A12 B23 C45"
|
26
27
|
[@cmd, *@params].map(&:to_s).join(" ")
|
27
28
|
end
|
28
29
|
|
data/lib/gcode.yml
CHANGED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe FB::IncomingHandler do
|
4
|
+
|
5
|
+
let(:status) { FB::Status.new }
|
6
|
+
|
7
|
+
it "capitalizes all incoming status keys" do
|
8
|
+
status[:bUsY] = 345345345
|
9
|
+
expect(status[:BUSY]).to eq(345345345)
|
10
|
+
expect(status[:bUsy]).to eq(345345345)
|
11
|
+
expect(status[:busy]).to eq(345345345)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "symbolizes all incoming status keys" do
|
15
|
+
status['busy'] = 878787
|
16
|
+
expect(status[:bUsy]).to eq(878787)
|
17
|
+
end
|
18
|
+
|
19
|
+
it "indicates BUSY status via #ready?()" do
|
20
|
+
status['busy'] = 1
|
21
|
+
expect(status.ready?).to be_falsey
|
22
|
+
status['busy'] = 0
|
23
|
+
expect(status.ready?).to be_truthy
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'broadcasts status changes' do
|
27
|
+
@diff = {}
|
28
|
+
|
29
|
+
within_event_loop do
|
30
|
+
status.onchange { |diff| @diff = diff }
|
31
|
+
status[:busy] = 1
|
32
|
+
status[:busy] = 0
|
33
|
+
status[:busy] = 1
|
34
|
+
end
|
35
|
+
|
36
|
+
expect(status[:busy]).to eq(1)
|
37
|
+
expect(@diff).to eq(:BUSY => 1)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
data/spec/lib/gcode_spec.rb
CHANGED
@@ -37,5 +37,10 @@ describe FB::Gcode do
|
|
37
37
|
expect(codes.last.cmd.head).to eq(:C)
|
38
38
|
expect(codes.first.params.first.tail).to eq(34)
|
39
39
|
end
|
40
|
+
|
41
|
+
it 'handles parameterless Gcode' do
|
42
|
+
expect(FB::Gcode.new(" ").name).to be(:unknown)
|
43
|
+
expect(FB::Gcode.new(" ").cmd).to eq("NULL")
|
44
|
+
end
|
40
45
|
end
|
41
46
|
|
data/spec/spec_helper.rb
CHANGED
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.0
|
4
|
+
version: 0.1.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-04-
|
12
|
+
date: 2015-04-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -120,7 +120,7 @@ files:
|
|
120
120
|
- ".rspec"
|
121
121
|
- README.md
|
122
122
|
- Rakefile
|
123
|
-
-
|
123
|
+
- console.rb
|
124
124
|
- lib/arduino.rb
|
125
125
|
- lib/arduino/event_machine.rb
|
126
126
|
- lib/arduino/incoming_handler.rb
|
@@ -130,7 +130,9 @@ files:
|
|
130
130
|
- lib/farmbot-serial.rb
|
131
131
|
- lib/gcode.rb
|
132
132
|
- lib/gcode.yml
|
133
|
+
- spec/fixtures/stub_logger.rb
|
133
134
|
- spec/fixtures/stub_serial_port.rb
|
135
|
+
- spec/lib/arduino/status_spec.rb
|
134
136
|
- spec/lib/arduino_spec.rb
|
135
137
|
- spec/lib/gcode_spec.rb
|
136
138
|
- spec/spec_helper.rb
|
@@ -159,7 +161,9 @@ signing_key:
|
|
159
161
|
specification_version: 4
|
160
162
|
summary: Serial library for Farmbot
|
161
163
|
test_files:
|
164
|
+
- spec/fixtures/stub_logger.rb
|
162
165
|
- spec/fixtures/stub_serial_port.rb
|
166
|
+
- spec/lib/arduino/status_spec.rb
|
163
167
|
- spec/lib/arduino_spec.rb
|
164
168
|
- spec/lib/gcode_spec.rb
|
165
169
|
- spec/spec_helper.rb
|
data/example.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
require_relative 'lib/farmbot-serial'
|
2
|
-
require 'pry'
|
3
|
-
|
4
|
-
bot = FB::Arduino.new # Defaults to '/dev/ttyACM0', can be configured.
|
5
|
-
|
6
|
-
puts """
|
7
|
-
FARMBOT SERIAL SANDBOX. WELCOME!
|
8
|
-
================================"""
|
9
|
-
$commands = {
|
10
|
-
"q" => "bot.commands.emergency_stop",
|
11
|
-
"w" => "bot.commands.move_relative(x: 600)",
|
12
|
-
"s" => "bot.commands.move_relative(x: -600)",
|
13
|
-
"e" => "bot.commands.home_x",
|
14
|
-
"r" => "bot.commands.home_y",
|
15
|
-
"t" => "bot.commands.home_z",
|
16
|
-
"y" => "bot.commands.home_all",
|
17
|
-
"u" => "bot.commands.read_parameter(8)",
|
18
|
-
"i" => "bot.commands.write_parameter('x', 0)",
|
19
|
-
"o" => "bot.commands.write_pin(pin: 8, value: 1, mode: 1)",
|
20
|
-
"p" => "bot.commands.read_status(8)",
|
21
|
-
}
|
22
|
-
|
23
|
-
$commands.each { |k, v| puts "#{k}: #{v}" }
|
24
|
-
|
25
|
-
class KeyboardHandler < EM::Connection
|
26
|
-
include EM::Protocols::LineText2
|
27
|
-
|
28
|
-
attr_reader :bot
|
29
|
-
|
30
|
-
def initialize(bot)
|
31
|
-
@bot = bot
|
32
|
-
end
|
33
|
-
|
34
|
-
def receive_line(data)
|
35
|
-
cmd = $commands[data] || ""
|
36
|
-
eval(cmd)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
puts "Starting now."
|
41
|
-
|
42
|
-
EM.run do
|
43
|
-
FB::ArduinoEventMachine.connect(bot)
|
44
|
-
bot.onmessage { |gcode| print "#{gcode.name}; " }
|
45
|
-
bot.onchange { |diff| print "#{diff}; " }
|
46
|
-
bot.onclose { puts "bye!"; EM.stop } # Unplug the bot and see
|
47
|
-
# EventMachine::PeriodicTimer.new(2) { bot.serial_port.puts "G82" }
|
48
|
-
EM.open_keyboard(KeyboardHandler, bot)
|
49
|
-
end
|
50
|
-
|