artoo 0.4.0 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/.yardopts +10 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +10 -7
- data/README.md +2 -2
- data/api/assets/javascripts/artoo/controllers/robot.js.coffee +2 -1
- data/api/public/core.js +3 -1
- data/artoo.gemspec +0 -1
- data/lib/artoo/adaptors/adaptor.rb +27 -6
- data/lib/artoo/adaptors/ardrone.rb +10 -2
- data/lib/artoo/adaptors/ardrone_navigation.rb +9 -2
- data/lib/artoo/adaptors/ardrone_video.rb +13 -5
- data/lib/artoo/adaptors/firmata.rb +10 -2
- data/lib/artoo/adaptors/loopback.rb +2 -1
- data/lib/artoo/adaptors/roomba.rb +12 -4
- data/lib/artoo/adaptors/sphero.rb +15 -3
- data/lib/artoo/api.rb +48 -5
- data/lib/artoo/api_route_helpers.rb +22 -3
- data/lib/artoo/basic.rb +3 -7
- data/lib/artoo/connection.rb +25 -7
- data/lib/artoo/delegator.rb +6 -16
- data/lib/artoo/device.rb +39 -10
- data/lib/artoo/device_event_client.rb +6 -0
- data/lib/artoo/drivers/ardrone.rb +5 -1
- data/lib/artoo/drivers/ardrone_navigation.rb +5 -1
- data/lib/artoo/drivers/ardrone_video.rb +9 -4
- data/lib/artoo/drivers/button.rb +7 -1
- data/lib/artoo/drivers/driver.rb +44 -4
- data/lib/artoo/drivers/led.rb +12 -1
- data/lib/artoo/drivers/motor.rb +12 -1
- data/lib/artoo/drivers/pinger.rb +10 -1
- data/lib/artoo/drivers/pinger2.rb +10 -1
- data/lib/artoo/drivers/roomba.rb +65 -17
- data/lib/artoo/drivers/servo.rb +12 -2
- data/lib/artoo/drivers/sphero.rb +19 -5
- data/lib/artoo/drivers/wiichuck.rb +7 -1
- data/lib/artoo/drivers/wiiclassic.rb +14 -5
- data/lib/artoo/drivers/wiidriver.rb +4 -1
- data/lib/artoo/events.rb +11 -4
- data/lib/artoo/ext/actor.rb +1 -1
- data/lib/artoo/ext/timers.rb +1 -1
- data/lib/artoo/main.rb +2 -13
- data/lib/artoo/master.rb +20 -2
- data/lib/artoo/port.rb +8 -3
- data/lib/artoo/robot.rb +45 -17
- data/lib/artoo/utility.rb +53 -9
- data/lib/artoo/version.rb +1 -1
- data/test/drivers/driver_test.rb +15 -0
- data/test/drivers/led_test.rb +4 -0
- data/test/utility_test.rb +35 -18
- data/test/utility_test_cases.rb +56 -0
- metadata +5 -16
data/lib/artoo/drivers/servo.rb
CHANGED
@@ -4,14 +4,18 @@ module Artoo
|
|
4
4
|
module Drivers
|
5
5
|
# Servo behaviors for Firmata
|
6
6
|
class Servo < Driver
|
7
|
+
COMMANDS = [:move, :min, :center, :max].freeze
|
8
|
+
|
7
9
|
attr_reader :current_angle
|
8
10
|
|
11
|
+
# Create new Servo with angle=0
|
9
12
|
def initialize(params={})
|
10
13
|
super
|
11
14
|
|
12
15
|
@current_angle = 0
|
13
16
|
end
|
14
17
|
|
18
|
+
# Starts connection to read and process and driver
|
15
19
|
def start_driver
|
16
20
|
every(interval) do
|
17
21
|
connection.read_and_process
|
@@ -20,30 +24,36 @@ module Artoo
|
|
20
24
|
super
|
21
25
|
end
|
22
26
|
|
27
|
+
# Moves to specified angle
|
28
|
+
# @param [Integer] angle must be between 0-180
|
23
29
|
def move(angle)
|
24
30
|
raise "Servo angle must be an integer between 0-180" unless (angle.is_a?(Numeric) && angle >= 0 && angle <= 180)
|
25
|
-
|
31
|
+
|
26
32
|
@current_angle = angle
|
27
33
|
connection.set_pin_mode(pin, Firmata::Board::SERVO)
|
28
34
|
connection.analog_write(pin, angle_to_span(angle))
|
29
35
|
end
|
30
36
|
|
37
|
+
# Moves to min position
|
31
38
|
def min
|
32
39
|
move(0)
|
33
40
|
end
|
34
41
|
|
42
|
+
# Moves to center position
|
35
43
|
def center
|
36
44
|
move(90)
|
37
45
|
end
|
38
46
|
|
47
|
+
# Moves to max position
|
39
48
|
def max
|
40
49
|
move(180)
|
41
50
|
end
|
42
51
|
|
43
52
|
# converts an angle to a span between 0-255
|
53
|
+
# @param [Integer] angle
|
44
54
|
def angle_to_span(angle)
|
45
55
|
(angle * 255 / 180).to_i
|
46
56
|
end
|
47
57
|
end
|
48
58
|
end
|
49
|
-
end
|
59
|
+
end
|
data/lib/artoo/drivers/sphero.rb
CHANGED
@@ -4,36 +4,50 @@ module Artoo
|
|
4
4
|
module Drivers
|
5
5
|
# The Sphero driver behaviors
|
6
6
|
class Sphero < Driver
|
7
|
-
RED = [255, 0, 0]
|
8
|
-
GREEN = [0, 255, 0]
|
9
|
-
YELLOW = [255, 255, 0]
|
10
|
-
BLUE = [0, 0, 255]
|
11
|
-
WHITE = [255, 255, 255]
|
12
7
|
|
8
|
+
RED = [255, 0, 0]
|
9
|
+
GREEN = [0, 255, 0]
|
10
|
+
YELLOW = [255, 255, 0]
|
11
|
+
BLUE = [0, 0, 255]
|
12
|
+
WHITE = [255, 255, 255]
|
13
|
+
|
14
|
+
COMMANDS = [:detect_collisions, :clear_collisions, :collisions,
|
15
|
+
:power_notifications, :sensor_data, :set_color, :color].freeze
|
16
|
+
|
17
|
+
# Detects collisions
|
18
|
+
# @param [Hash] params
|
13
19
|
def detect_collisions(params={})
|
14
20
|
connection.configure_collision_detection 0x01, 0x20, 0x20, 0x20, 0x20, 0x50
|
15
21
|
end
|
16
22
|
|
23
|
+
# Clears collisions
|
17
24
|
def clear_collisions
|
18
25
|
messages.clear if responses = messages
|
19
26
|
end
|
20
27
|
|
28
|
+
# @return [CollisionDetected] collision
|
21
29
|
def collisions
|
22
30
|
matching_response_types messages, ::Sphero::Response::CollisionDetected
|
23
31
|
end
|
24
32
|
|
33
|
+
# @return [PowerNotification] power notification
|
25
34
|
def power_notifications
|
26
35
|
matching_response_types messages, ::Sphero::Response::PowerNotification
|
27
36
|
end
|
28
37
|
|
38
|
+
# @return [SensorData] sensor data
|
29
39
|
def sensor_data
|
30
40
|
matching_response_types messages, ::Sphero::Response::SensorData
|
31
41
|
end
|
32
42
|
|
43
|
+
# Set color
|
44
|
+
# @param [Collection] colors
|
33
45
|
def set_color(*colors)
|
34
46
|
connection.rgb(*color(*colors))
|
35
47
|
end
|
36
48
|
|
49
|
+
# Retrieves color
|
50
|
+
# @param [Collection] colors
|
37
51
|
def color(*colors)
|
38
52
|
case colors.first
|
39
53
|
when :red then RED
|
@@ -4,6 +4,9 @@ module Artoo
|
|
4
4
|
module Drivers
|
5
5
|
# Wiichuck driver behaviors for Firmata
|
6
6
|
class Wiichuck < Wiidriver
|
7
|
+
|
8
|
+
# Update button and joystick values
|
9
|
+
# @param [Object] value
|
7
10
|
def update(value)
|
8
11
|
begin
|
9
12
|
super
|
@@ -19,21 +22,24 @@ module Artoo
|
|
19
22
|
end
|
20
23
|
end
|
21
24
|
|
25
|
+
# Adjust x, y origin values
|
22
26
|
def adjust_origins
|
23
27
|
set_joystick_default_value(:sy_origin, data[:sy])
|
24
28
|
set_joystick_default_value(:sx_origin, data[:sx])
|
25
29
|
end
|
26
30
|
|
31
|
+
# Publishes events for c and z buttons
|
27
32
|
def update_buttons
|
28
33
|
publish(event_topic_name("c_button")) if data[:c] == true
|
29
34
|
publish(event_topic_name("z_button")) if data[:z] == true
|
30
35
|
end
|
31
36
|
|
37
|
+
# Publishes event for joystick
|
32
38
|
def update_joystick
|
33
39
|
publish(event_topic_name("joystick"), {:x => calculate_joystick_value(:sx, :sx_origin), :y => calculate_joystick_value(:sy, :sy_origin)})
|
34
40
|
end
|
35
41
|
|
36
|
-
private
|
42
|
+
private
|
37
43
|
|
38
44
|
def get_defaults
|
39
45
|
{
|
@@ -3,11 +3,14 @@ require 'artoo/drivers/wiidriver'
|
|
3
3
|
module Artoo
|
4
4
|
module Drivers
|
5
5
|
# Wiiclassic driver behaviors for Firmata
|
6
|
-
class Wiiclassic < Wiidriver
|
6
|
+
class Wiiclassic < Wiidriver
|
7
|
+
|
8
|
+
# Update buttons and joysticks values
|
9
|
+
# @param [Object] value
|
7
10
|
def update(value)
|
8
11
|
begin
|
9
12
|
super
|
10
|
-
|
13
|
+
|
11
14
|
adjust_origins
|
12
15
|
update_buttons
|
13
16
|
update_left_joystick
|
@@ -21,6 +24,7 @@ module Artoo
|
|
21
24
|
end
|
22
25
|
end
|
23
26
|
|
27
|
+
# Adjust all origins
|
24
28
|
def adjust_origins
|
25
29
|
set_joystick_default_value(:ly_origin, data[:ly])
|
26
30
|
set_joystick_default_value(:lx_origin, data[:lx])
|
@@ -30,6 +34,7 @@ module Artoo
|
|
30
34
|
set_joystick_default_value(:lt_origin, data[:lt])
|
31
35
|
end
|
32
36
|
|
37
|
+
# Update button values
|
33
38
|
def update_buttons
|
34
39
|
update_button("a_button", :a)
|
35
40
|
update_button("b_button", :b)
|
@@ -40,25 +45,29 @@ module Artoo
|
|
40
45
|
update_button("select_button", :-)
|
41
46
|
end
|
42
47
|
|
48
|
+
# Publish button event
|
43
49
|
def update_button(name, key)
|
44
50
|
publish(event_topic_name(name)) if data[key] == true
|
45
51
|
end
|
46
52
|
|
53
|
+
# Publish left joystick event
|
47
54
|
def update_left_joystick
|
48
55
|
publish(event_topic_name("left_joystick"), {:x => calculate_joystick_value(:lx, :lx_origin), :y => calculate_joystick_value(:ly, :ly_origin)})
|
49
56
|
end
|
50
57
|
|
58
|
+
# Publish right joystick event
|
51
59
|
def update_right_joystick
|
52
60
|
publish(event_topic_name("right_joystick"), {:x => calculate_joystick_value(:rx, :rx_origin), :y => calculate_joystick_value(:ry, :ry_origin)})
|
53
61
|
end
|
54
62
|
|
63
|
+
# Publish triggers events
|
55
64
|
def update_triggers
|
56
65
|
publish(event_topic_name("right_trigger"), calculate_joystick_value(:rt, :rt_origin))
|
57
66
|
publish(event_topic_name("left_trigger"), calculate_joystick_value(:lt, :lt_origin))
|
58
67
|
end
|
59
68
|
|
60
69
|
private
|
61
|
-
|
70
|
+
|
62
71
|
def get_defaults
|
63
72
|
{
|
64
73
|
:ry_origin => nil,
|
@@ -67,8 +76,8 @@ module Artoo
|
|
67
76
|
:lx_origin => nil,
|
68
77
|
:rt_origin => nil,
|
69
78
|
:lt_origin => nil
|
70
|
-
}
|
71
|
-
end
|
79
|
+
}
|
80
|
+
end
|
72
81
|
|
73
82
|
def parse(value)
|
74
83
|
return parse_joysticks(value).
|
@@ -8,12 +8,14 @@ module Artoo
|
|
8
8
|
|
9
9
|
def address; 0x52; end
|
10
10
|
|
11
|
+
# Create new Wiidriver
|
11
12
|
def initialize(params={})
|
12
13
|
@joystick = get_defaults
|
13
14
|
@data = {}
|
14
15
|
super
|
15
16
|
end
|
16
17
|
|
18
|
+
# Starts drives and required connections
|
17
19
|
def start_driver
|
18
20
|
begin
|
19
21
|
listener = ->(value) { update(value) }
|
@@ -38,6 +40,7 @@ module Artoo
|
|
38
40
|
end
|
39
41
|
end
|
40
42
|
|
43
|
+
# Get and update data
|
41
44
|
def update(value)
|
42
45
|
if encrypted?(value)
|
43
46
|
Logger.error "Encrypted bytes from wii device!"
|
@@ -47,7 +50,7 @@ module Artoo
|
|
47
50
|
@data = parse(value)
|
48
51
|
end
|
49
52
|
|
50
|
-
protected
|
53
|
+
protected
|
51
54
|
|
52
55
|
def get_defaults
|
53
56
|
{}
|
data/lib/artoo/events.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
module Artoo
|
2
|
+
# Class that handles events
|
2
3
|
module Events
|
4
|
+
|
3
5
|
# Subscribe to an event from a device
|
6
|
+
# @param [Device] device
|
7
|
+
# @param [Hash] events
|
4
8
|
def on(device, events={})
|
5
9
|
events.each do |k, v|
|
6
10
|
subscribe("#{safe_name}_#{device.name}_#{k}", create_proxy_method(k, v))
|
@@ -10,8 +14,10 @@ module Artoo
|
|
10
14
|
# Create an anonymous subscription method so we can wrap the
|
11
15
|
# subscription method fire into a valid method regardless
|
12
16
|
# of where it is defined
|
13
|
-
|
14
|
-
|
17
|
+
# @param [String] base_name
|
18
|
+
# @param [String] v
|
19
|
+
def create_proxy_method(base_name, v)
|
20
|
+
proxy_method_name(base_name).tap do |name|
|
15
21
|
self.class.send :define_method, name do |*args|
|
16
22
|
case v
|
17
23
|
when Symbol
|
@@ -24,9 +30,10 @@ module Artoo
|
|
24
30
|
end
|
25
31
|
|
26
32
|
# A simple loop to create a 'fake' anonymous method
|
27
|
-
|
33
|
+
# @return [Method] created method
|
34
|
+
def proxy_method_name(base_name)
|
28
35
|
begin
|
29
|
-
meth = "#{
|
36
|
+
meth = "#{base_name}_#{Random.rand(999)}"
|
30
37
|
end while respond_to?(meth)
|
31
38
|
meth
|
32
39
|
end
|
data/lib/artoo/ext/actor.rb
CHANGED
data/lib/artoo/ext/timers.rb
CHANGED
data/lib/artoo/main.rb
CHANGED
@@ -6,27 +6,16 @@ module Artoo
|
|
6
6
|
# DSL methods executed on main are delegated to this class like Sinatra
|
7
7
|
class MainRobot < Artoo::Robot
|
8
8
|
|
9
|
-
#
|
9
|
+
# We assume that the first file that requires 'artoo' is the
|
10
10
|
# app_file. all other path related options are calculated based
|
11
11
|
# on this path by default.
|
12
12
|
set :app_file, caller_files.first || $0
|
13
13
|
set :start_work, Proc.new { File.expand_path($0) == File.expand_path(app_file) }
|
14
|
-
|
15
|
-
# if run? && ARGV.any?
|
16
|
-
# require 'optparse'
|
17
|
-
# OptionParser.new { |op|
|
18
|
-
# op.on('-p port', 'set the port (default is 4567)') { |val| set :port, Integer(val) }
|
19
|
-
# op.on('-o addr', 'set the host (default is 0.0.0.0)') { |val| set :bind, val }
|
20
|
-
# op.on('-e env', 'set the environment (default is development)') { |val| set :environment, val.to_sym }
|
21
|
-
# op.on('-s server', 'specify rack server/handler (default is thin)') { |val| set :server, val }
|
22
|
-
# op.on('-x', 'turn on the mutex lock (default is off)') { set :lock, true }
|
23
|
-
# }.parse!(ARGV.dup)
|
24
|
-
# end
|
25
14
|
end
|
26
15
|
|
27
16
|
at_exit { MainRobot.work! if $!.nil? && MainRobot.start_work? }
|
28
17
|
end
|
29
18
|
|
30
|
-
# include would include the module in Object
|
19
|
+
# include would include the module in Object,
|
31
20
|
# extend only extends the `main` object
|
32
21
|
extend Artoo::Delegator
|
data/lib/artoo/master.rb
CHANGED
@@ -3,36 +3,52 @@ module Artoo
|
|
3
3
|
# of all the running robots
|
4
4
|
class Master
|
5
5
|
include Celluloid
|
6
|
-
|
6
|
+
attr_reader :robots
|
7
7
|
|
8
|
+
# Create new master
|
9
|
+
# @param [Collection] robots
|
8
10
|
def initialize(bots)
|
9
11
|
@robots = bots
|
10
12
|
end
|
11
13
|
|
14
|
+
# @param [String] name
|
15
|
+
# @return [Robot] robot
|
12
16
|
def robot(name)
|
13
17
|
robots.find {|r| r.name == name}
|
14
18
|
end
|
15
19
|
|
20
|
+
# @param [String] name
|
21
|
+
# @return [Collection] robot devices
|
16
22
|
def robot_devices(name)
|
17
23
|
robot(name).devices
|
18
24
|
end
|
19
25
|
|
26
|
+
# @param [String] name
|
27
|
+
# @param [String] device_id
|
28
|
+
# @return [Device] robot device
|
20
29
|
def robot_device(name, device_id)
|
21
30
|
robot_devices(name)[device_id.intern]
|
22
31
|
end
|
23
32
|
|
33
|
+
# @param [String] name
|
34
|
+
# @return [Collection] robot connections
|
24
35
|
def robot_connections(name)
|
25
36
|
robot(name).connections
|
26
37
|
end
|
27
38
|
|
39
|
+
# @param [String] robot_id
|
40
|
+
# @param [String] connection_id
|
41
|
+
# @return [Device] robot connection
|
28
42
|
def robot_connection(robot_id, connection_id)
|
29
43
|
robot_connections(robot_id)[connection_id.intern]
|
30
44
|
end
|
31
45
|
|
46
|
+
# Do asynchronous work for each robot
|
32
47
|
def start_work
|
33
48
|
robots.each {|r| r.async.work} unless Artoo::Robot.is_running?
|
34
49
|
end
|
35
50
|
|
51
|
+
# Pause work for each robot
|
36
52
|
def pause_work
|
37
53
|
robots.each {|r|
|
38
54
|
Logger.info "pausing #{r.name}"
|
@@ -40,12 +56,14 @@ module Artoo
|
|
40
56
|
}
|
41
57
|
end
|
42
58
|
|
59
|
+
# Continue work for each robot
|
43
60
|
def continue_work
|
44
61
|
robots.each {|r| r.async.continue_work}
|
45
62
|
end
|
46
63
|
|
64
|
+
# @deprecated
|
47
65
|
def stop_work
|
48
66
|
#robots.each {|r| r.async.stop_work} unless !Artoo::Robot.is_running?
|
49
67
|
end
|
50
68
|
end
|
51
|
-
end
|
69
|
+
end
|
data/lib/artoo/port.rb
CHANGED
@@ -1,28 +1,33 @@
|
|
1
1
|
module Artoo
|
2
|
-
# The Artoo::Port class represents port and/or host to be used to connect
|
2
|
+
# The Artoo::Port class represents port and/or host to be used to connect
|
3
3
|
# tp a specific individual hardware device.
|
4
4
|
class Port
|
5
5
|
attr_reader :port, :host
|
6
6
|
|
7
|
+
# Create new port
|
8
|
+
# @param [Object] data
|
7
9
|
def initialize(data)
|
8
10
|
@is_tcp, @is_serial = false
|
9
11
|
parse(data)
|
10
12
|
end
|
11
13
|
|
14
|
+
# @return [Boolean] True if serial port
|
12
15
|
def is_serial?
|
13
16
|
@is_serial == true
|
14
17
|
end
|
15
18
|
|
19
|
+
# @return [Boolean] True if tcp port
|
16
20
|
def is_tcp?
|
17
21
|
@is_tcp == true
|
18
22
|
end
|
19
23
|
|
24
|
+
# @return [String] port
|
20
25
|
def to_s
|
21
26
|
if is_serial?
|
22
27
|
port
|
23
28
|
else
|
24
29
|
"#{host}:#{port}"
|
25
|
-
end
|
30
|
+
end
|
26
31
|
end
|
27
32
|
|
28
33
|
private
|
@@ -48,4 +53,4 @@ module Artoo
|
|
48
53
|
end
|
49
54
|
end
|
50
55
|
end
|
51
|
-
end
|
56
|
+
end
|