farmbot-serial 0.0.9 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
|