artoo 0.4.0 → 0.4.1
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/.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
@@ -3,7 +3,11 @@ require 'artoo/drivers/driver'
|
|
3
3
|
module Artoo
|
4
4
|
module Drivers
|
5
5
|
# Ardrone driver behaviors
|
6
|
+
# @see https://github.com/hybridgroup/argus/blob/master/lib/argus/drone.rb Argus::Drone docs for supported actions
|
6
7
|
class Ardrone < Driver
|
8
|
+
def start
|
9
|
+
connection.start(false) # send false, so Argus does not use NavMonitor
|
10
|
+
end
|
7
11
|
end
|
8
12
|
end
|
9
|
-
end
|
13
|
+
end
|
@@ -4,6 +4,8 @@ module Artoo
|
|
4
4
|
module Drivers
|
5
5
|
# Ardrone navigation driver behaviors
|
6
6
|
class ArdroneNavigation < Driver
|
7
|
+
|
8
|
+
# Starts driver and handle updates from device
|
7
9
|
def start_driver
|
8
10
|
every(interval) do
|
9
11
|
handle_update
|
@@ -12,10 +14,12 @@ module Artoo
|
|
12
14
|
super
|
13
15
|
end
|
14
16
|
|
17
|
+
# Receives data from navigation and publishes
|
18
|
+
# and event in update topic for it
|
15
19
|
def handle_update
|
16
20
|
navdata = connection.receive_data
|
17
21
|
publish(event_topic_name("update"), navdata)
|
18
22
|
end
|
19
23
|
end
|
20
24
|
end
|
21
|
-
end
|
25
|
+
end
|
@@ -4,6 +4,8 @@ module Artoo
|
|
4
4
|
module Drivers
|
5
5
|
# Ardrone video driver behaviors
|
6
6
|
class ArdroneVideo < Driver
|
7
|
+
|
8
|
+
# Starts drives and handles video frame
|
7
9
|
def start_driver
|
8
10
|
every(interval) do
|
9
11
|
handle_frame
|
@@ -12,11 +14,14 @@ module Artoo
|
|
12
14
|
super
|
13
15
|
end
|
14
16
|
|
17
|
+
# Retrieves frame from video connection
|
18
|
+
# and publishes data to update and frame
|
19
|
+
# event topics
|
15
20
|
def handle_frame(*params)
|
16
|
-
|
17
|
-
publish(event_topic_name("update"), "
|
18
|
-
publish(event_topic_name("frame"), frame)
|
21
|
+
video = connection.receive_data
|
22
|
+
publish(event_topic_name("update"), "video", video)
|
23
|
+
publish(event_topic_name("frame"), video.frame)
|
19
24
|
end
|
20
25
|
end
|
21
26
|
end
|
22
|
-
end
|
27
|
+
end
|
data/lib/artoo/drivers/button.rb
CHANGED
@@ -4,13 +4,18 @@ module Artoo
|
|
4
4
|
module Drivers
|
5
5
|
# Button driver behaviors for Firmata
|
6
6
|
class Button < Driver
|
7
|
+
COMMANDS = [:is_pressed?].freeze
|
8
|
+
|
7
9
|
DOWN = 1
|
8
10
|
UP = 0
|
9
11
|
|
12
|
+
# @return [Boolean] True if pressed
|
10
13
|
def is_pressed?
|
11
14
|
(@is_pressed ||= false) == true
|
12
15
|
end
|
13
16
|
|
17
|
+
# Sets values to read and write from button
|
18
|
+
# and starts driver
|
14
19
|
def start_driver
|
15
20
|
listener = ->(value) { update(value) }
|
16
21
|
connection.on("digital-read-#{pin}", listener)
|
@@ -24,6 +29,7 @@ module Artoo
|
|
24
29
|
super
|
25
30
|
end
|
26
31
|
|
32
|
+
# Publishes events according to the button feedback
|
27
33
|
def update(value)
|
28
34
|
if value == DOWN
|
29
35
|
@is_pressed = true
|
@@ -37,4 +43,4 @@ module Artoo
|
|
37
43
|
end
|
38
44
|
end
|
39
45
|
end
|
40
|
-
end
|
46
|
+
end
|
data/lib/artoo/drivers/driver.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Artoo
|
2
2
|
module Drivers
|
3
|
-
# The Driver class is the base class used to
|
4
|
-
# implement behavior for a specific kind of hardware devices. Examples
|
3
|
+
# The Driver class is the base class used to
|
4
|
+
# implement behavior for a specific kind of hardware devices. Examples
|
5
5
|
# would be an Arduino, a Sphero, or an ARDrone.
|
6
6
|
#
|
7
7
|
# Derive a class from this class, in order to implement behavior
|
@@ -9,33 +9,73 @@ module Artoo
|
|
9
9
|
class Driver
|
10
10
|
include Celluloid
|
11
11
|
include Celluloid::Notifications
|
12
|
-
|
12
|
+
|
13
13
|
attr_reader :parent
|
14
14
|
|
15
|
+
COMMANDS = [].freeze
|
16
|
+
|
17
|
+
# Create new driver
|
18
|
+
# @param [Hash] params
|
19
|
+
# @option params [Object] :parent
|
15
20
|
def initialize(params={})
|
16
21
|
@parent = params[:parent]
|
17
22
|
end
|
18
23
|
|
24
|
+
# @return [Connection] parent connection
|
19
25
|
def connection
|
20
26
|
parent.connection
|
21
27
|
end
|
22
28
|
|
29
|
+
# @return [String] parent pin
|
23
30
|
def pin
|
24
31
|
parent.pin
|
25
32
|
end
|
26
33
|
|
34
|
+
# @return [String] parent interval
|
27
35
|
def interval
|
28
36
|
parent.interval
|
29
37
|
end
|
30
38
|
|
39
|
+
# Generic driver start
|
31
40
|
def start_driver
|
32
41
|
Logger.info "Starting driver '#{self.class.name}'..."
|
33
42
|
end
|
34
43
|
|
44
|
+
# @return [String] parent topic name
|
35
45
|
def event_topic_name(event)
|
36
46
|
parent.event_topic_name(event)
|
37
47
|
end
|
38
48
|
|
49
|
+
# @return [Collection] commands
|
50
|
+
def commands
|
51
|
+
self.class.const_get('COMMANDS')
|
52
|
+
end
|
53
|
+
|
54
|
+
# Execute command
|
55
|
+
# @param [Symbol] method_name
|
56
|
+
# @param [Array] arguments
|
57
|
+
def command(method_name, *arguments)
|
58
|
+
known_command?(method_name)
|
59
|
+
if arguments.first
|
60
|
+
self.send(method_name, *arguments)
|
61
|
+
else
|
62
|
+
self.send(method_name)
|
63
|
+
end
|
64
|
+
rescue Exception => e
|
65
|
+
Logger.error e.message
|
66
|
+
Logger.error e.backtrace.inspect
|
67
|
+
return nil
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [Boolean] True if command exists
|
71
|
+
def known_command?(method_name)
|
72
|
+
return true if commands.include?(method_name.intern)
|
73
|
+
|
74
|
+
Logger.warn("Calling unknown command '#{method_name}'...")
|
75
|
+
return false
|
76
|
+
end
|
77
|
+
|
78
|
+
# Sends missing methods to connection
|
39
79
|
def method_missing(method_name, *arguments, &block)
|
40
80
|
connection.send(method_name, *arguments, &block)
|
41
81
|
rescue Exception => e
|
@@ -45,4 +85,4 @@ module Artoo
|
|
45
85
|
end
|
46
86
|
end
|
47
87
|
end
|
48
|
-
end
|
88
|
+
end
|
data/lib/artoo/drivers/led.rb
CHANGED
@@ -4,34 +4,45 @@ module Artoo
|
|
4
4
|
module Drivers
|
5
5
|
# The LED driver behaviors
|
6
6
|
class Led < Driver
|
7
|
+
|
8
|
+
COMMANDS = [:is_on?, :is_off?, :on, :off, :toggle, :brightness].freeze
|
9
|
+
|
10
|
+
# @return [Boolean] True if on
|
7
11
|
def is_on?
|
8
12
|
(@is_on ||= false) == true
|
9
13
|
end
|
10
14
|
|
15
|
+
# @return [Boolean] True if off
|
11
16
|
def is_off?
|
12
17
|
(@is_on ||= false) == false
|
13
18
|
end
|
14
19
|
|
20
|
+
# Sets led to on status
|
15
21
|
def on
|
16
22
|
@is_on = true
|
17
23
|
connection.set_pin_mode(pin, Firmata::Board::OUTPUT)
|
18
24
|
connection.digital_write(pin, Firmata::Board::HIGH)
|
19
25
|
end
|
20
26
|
|
27
|
+
# Sets led to off status
|
21
28
|
def off
|
22
29
|
@is_on = false
|
23
30
|
connection.set_pin_mode(pin, Firmata::Board::OUTPUT)
|
24
31
|
connection.digital_write(pin, Firmata::Board::LOW)
|
25
32
|
end
|
26
33
|
|
34
|
+
# Toggle status
|
35
|
+
# @example on > off, off > on
|
27
36
|
def toggle
|
28
37
|
is_off? ? on : off
|
29
38
|
end
|
30
39
|
|
40
|
+
# Change brightness level
|
41
|
+
# @param [Integer] level
|
31
42
|
def brightness(level=0)
|
32
43
|
connection.set_pin_mode(pin, Firmata::Board::PWM)
|
33
44
|
connection.analog_write(pin, level)
|
34
45
|
end
|
35
46
|
end
|
36
47
|
end
|
37
|
-
end
|
48
|
+
end
|
data/lib/artoo/drivers/motor.rb
CHANGED
@@ -4,8 +4,11 @@ module Artoo
|
|
4
4
|
module Drivers
|
5
5
|
# L293 or other H-bridge style motor driver behaviors for Firmata
|
6
6
|
class Motor < Driver
|
7
|
+
COMMANDS = [:forward, :backward, :stop, :speed, :current_speed].freeze
|
8
|
+
|
7
9
|
attr_reader :leg1_pin, :leg2_pin, :speed_pin, :current_speed
|
8
10
|
|
11
|
+
# Create new Motor
|
9
12
|
def initialize(params={})
|
10
13
|
super
|
11
14
|
|
@@ -16,6 +19,7 @@ module Artoo
|
|
16
19
|
@current_speed = 0
|
17
20
|
end
|
18
21
|
|
22
|
+
# Starts connection to read and process and driver
|
19
23
|
def start_driver
|
20
24
|
every(interval) do
|
21
25
|
connection.read_and_process
|
@@ -24,20 +28,27 @@ module Artoo
|
|
24
28
|
super
|
25
29
|
end
|
26
30
|
|
31
|
+
# Sets movement forward
|
32
|
+
# @param [Integer] s speed
|
27
33
|
def forward(s)
|
28
34
|
set_legs(Firmata::Board::LOW, Firmata::Board::HIGH)
|
29
35
|
speed(s)
|
30
36
|
end
|
31
37
|
|
38
|
+
# Sets movement backward
|
39
|
+
# @param [Integer] s speed
|
32
40
|
def backward(s)
|
33
41
|
set_legs(Firmata::Board::HIGH, Firmata::Board::LOW)
|
34
42
|
speed(s)
|
35
43
|
end
|
36
44
|
|
45
|
+
# Stops
|
37
46
|
def stop
|
38
47
|
speed(0)
|
39
48
|
end
|
40
49
|
|
50
|
+
# Set motor speed
|
51
|
+
# @param [Integer] s speed (must be an integer between 0-255)
|
41
52
|
def speed(s)
|
42
53
|
raise "Motor speed must be an integer between 0-255" unless (s.is_a?(Numeric) && s >= 0 && s <= 255)
|
43
54
|
@current_speed = s
|
@@ -55,4 +66,4 @@ module Artoo
|
|
55
66
|
end
|
56
67
|
end
|
57
68
|
end
|
58
|
-
end
|
69
|
+
end
|
data/lib/artoo/drivers/pinger.rb
CHANGED
@@ -4,6 +4,11 @@ module Artoo
|
|
4
4
|
module Drivers
|
5
5
|
# Pings itself
|
6
6
|
class Pinger < Driver
|
7
|
+
|
8
|
+
COMMANDS = [:ping].freeze
|
9
|
+
|
10
|
+
# Publishes events to update and alive event topics
|
11
|
+
# with incremental count
|
7
12
|
def start_driver
|
8
13
|
@count = 1
|
9
14
|
every(interval) do
|
@@ -14,6 +19,10 @@ module Artoo
|
|
14
19
|
|
15
20
|
super
|
16
21
|
end
|
22
|
+
|
23
|
+
def ping
|
24
|
+
"pong"
|
25
|
+
end
|
17
26
|
end
|
18
27
|
end
|
19
|
-
end
|
28
|
+
end
|
@@ -4,6 +4,11 @@ module Artoo
|
|
4
4
|
module Drivers
|
5
5
|
# Pings itself
|
6
6
|
class Pinger2 < Driver
|
7
|
+
|
8
|
+
COMMANDS = [:ping].freeze
|
9
|
+
|
10
|
+
# Publishes events to update and alive event topics
|
11
|
+
# with random number
|
7
12
|
def start_driver
|
8
13
|
every(interval) do
|
9
14
|
@count = rand(100000)
|
@@ -13,6 +18,10 @@ module Artoo
|
|
13
18
|
|
14
19
|
super
|
15
20
|
end
|
21
|
+
|
22
|
+
def ping
|
23
|
+
"pong"
|
24
|
+
end
|
16
25
|
end
|
17
26
|
end
|
18
|
-
end
|
27
|
+
end
|
data/lib/artoo/drivers/roomba.rb
CHANGED
@@ -4,12 +4,19 @@ module Artoo
|
|
4
4
|
module Drivers
|
5
5
|
# The Roomba driver behaviors
|
6
6
|
class Roomba < Driver
|
7
|
+
|
8
|
+
COMMANDS = [:start, :safe_mode, :full_mode, :forward, :stop, :fast_forward,
|
9
|
+
:backwards, :nudge_left, :nudge_right, :turn_left, :turn_right,
|
10
|
+
:turn_around, :drive, :play, :song, :beep].freeze
|
11
|
+
|
12
|
+
# Sets Direction constant values
|
7
13
|
module Direction
|
8
14
|
STRAIGHT = 32768
|
9
15
|
CLOCKWISE = 65535
|
10
16
|
COUNTERCLOCKWISE = 1
|
11
17
|
end
|
12
18
|
|
19
|
+
# Sets speed constant values
|
13
20
|
module Speed
|
14
21
|
MAX = 500
|
15
22
|
SLOW = 250
|
@@ -17,6 +24,7 @@ module Artoo
|
|
17
24
|
ZERO = 0
|
18
25
|
end
|
19
26
|
|
27
|
+
# Sets notes constant values
|
20
28
|
module Note
|
21
29
|
B = 95
|
22
30
|
D = 98
|
@@ -28,104 +36,144 @@ module Artoo
|
|
28
36
|
WHOLE = 114
|
29
37
|
end
|
30
38
|
|
39
|
+
# Sets mode constant values
|
31
40
|
module Mode
|
32
41
|
FULL = 132
|
33
42
|
SAFE = 131
|
34
43
|
START = 128
|
35
44
|
end
|
36
|
-
|
45
|
+
|
46
|
+
# Sets song constant values
|
37
47
|
module Song
|
38
48
|
SONG = 140
|
39
49
|
PLAY = 141
|
40
50
|
end
|
41
51
|
|
52
|
+
# Sends start mode
|
42
53
|
def start
|
43
54
|
send_bytes(Mode::START)
|
44
55
|
sleep 0.2
|
45
56
|
end
|
46
|
-
|
57
|
+
|
58
|
+
# Sends safe mode
|
47
59
|
def safe_mode
|
48
60
|
start
|
49
61
|
send_bytes(Mode::SAFE)
|
50
62
|
sleep 0.1
|
51
63
|
end
|
52
|
-
|
64
|
+
|
65
|
+
# Sends full mode
|
53
66
|
def full_mode
|
54
67
|
start
|
55
68
|
send_bytes(Mode::FULL)
|
56
69
|
sleep 0.1
|
57
70
|
end
|
58
|
-
|
71
|
+
|
72
|
+
# Move forward
|
73
|
+
# @param [Integer] seconds
|
74
|
+
# @param [Constant] velocity
|
75
|
+
# @see Speed
|
59
76
|
def forward(seconds, velocity = Speed::SLOW)
|
60
77
|
drive(velocity, Direction::STRAIGHT, seconds)
|
61
78
|
stop if seconds > 0
|
62
79
|
end
|
63
|
-
|
80
|
+
|
81
|
+
# Stop movement
|
64
82
|
def stop
|
65
83
|
drive(Speed::ZERO, Direction::STRAIGHT)
|
66
84
|
end
|
67
|
-
|
85
|
+
|
86
|
+
# Move forward with fast speed
|
87
|
+
# @param [Integer] seconds
|
68
88
|
def fast_forward(seconds)
|
69
89
|
drive(Speed::MAX, Direction::STRAIGHT, seconds)
|
70
90
|
stop if seconds > 0
|
71
91
|
end
|
72
|
-
|
92
|
+
|
93
|
+
# Move backward
|
94
|
+
# @param [Integer] seconds
|
73
95
|
def backwards(seconds)
|
74
96
|
drive(Speed::NEG, Direction::STRAIGHT, seconds)
|
75
97
|
stop if seconds > 0
|
76
98
|
end
|
77
|
-
|
99
|
+
|
100
|
+
# Nudge left
|
78
101
|
def nudge_left
|
79
102
|
turn_left(0.25)
|
80
103
|
end
|
81
|
-
|
104
|
+
|
105
|
+
# Turn left
|
106
|
+
# @param [Integer] seconds
|
82
107
|
def turn_left(seconds = 1)
|
83
108
|
drive(Speed::SLOW, Direction::COUNTERCLOCKWISE, seconds)
|
84
109
|
stop if seconds > 0
|
85
110
|
end
|
86
|
-
|
111
|
+
|
112
|
+
# Turn right
|
113
|
+
# @param [Integer] seconds
|
87
114
|
def turn_right(seconds = 1)
|
88
115
|
drive(Speed::SLOW, Direction::CLOCKWISE, seconds)
|
89
116
|
stop if seconds > 0
|
90
117
|
end
|
91
|
-
|
118
|
+
|
119
|
+
# Nudge right
|
92
120
|
def nudge_right
|
93
121
|
turn_right(0.25)
|
94
122
|
end
|
95
|
-
|
123
|
+
|
124
|
+
# Turn around
|
96
125
|
def turn_around
|
97
126
|
turn_left(1.6)
|
98
127
|
end
|
99
128
|
|
129
|
+
# Drive
|
130
|
+
# @param [Integer] v speed
|
131
|
+
# @param [Integer] r direction
|
132
|
+
# @param [Integer] s seconds (waiting time)
|
133
|
+
# @see Speed
|
134
|
+
# @see Direction
|
100
135
|
def drive(v, r, s = 0)
|
101
136
|
vH,vL = split_bytes(v)
|
102
137
|
rH,rL = split_bytes(r)
|
103
138
|
send_bytes([137, vH, vL, rH, rL])
|
104
139
|
sleep(s) if s > 0
|
105
140
|
end
|
106
|
-
|
141
|
+
|
142
|
+
# Split bytes (hex)
|
143
|
+
# @param [Integer] num
|
107
144
|
def split_bytes(num)
|
108
145
|
[num >> 8, num & 255]
|
109
146
|
end
|
110
|
-
|
147
|
+
|
148
|
+
# Play song
|
149
|
+
# @param [Integer] song_number
|
111
150
|
def play(song_number = 0)
|
112
151
|
send_bytes([Song::PLAY, song_number])
|
113
152
|
end
|
114
153
|
|
154
|
+
# Save song
|
155
|
+
# @param [Collection] notes
|
156
|
+
# @param [Integer] song_number
|
157
|
+
# @see Notes
|
115
158
|
def song(notes, song_number = 0)
|
116
159
|
note_group = notes.flatten.compact
|
117
160
|
l = note_group.length / 2
|
118
161
|
send_bytes([Song::SONG, song_number, l] + note_group)
|
119
162
|
end
|
120
|
-
|
163
|
+
|
164
|
+
# Play song
|
165
|
+
# @param [Collection] notes
|
166
|
+
# @param [Integer] song_number
|
167
|
+
# @see Notes
|
121
168
|
def play_song(notes, song_number = 0)
|
122
169
|
song(notes, song_number)
|
123
170
|
play(song_number)
|
124
171
|
end
|
125
172
|
|
173
|
+
# Beeps with a G note
|
126
174
|
def beep
|
127
175
|
play_song([Note::G, Note::WHOLE])
|
128
|
-
end
|
176
|
+
end
|
129
177
|
end
|
130
178
|
end
|
131
|
-
end
|
179
|
+
end
|