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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/.yardopts +10 -0
  4. data/Gemfile +9 -0
  5. data/Gemfile.lock +10 -7
  6. data/README.md +2 -2
  7. data/api/assets/javascripts/artoo/controllers/robot.js.coffee +2 -1
  8. data/api/public/core.js +3 -1
  9. data/artoo.gemspec +0 -1
  10. data/lib/artoo/adaptors/adaptor.rb +27 -6
  11. data/lib/artoo/adaptors/ardrone.rb +10 -2
  12. data/lib/artoo/adaptors/ardrone_navigation.rb +9 -2
  13. data/lib/artoo/adaptors/ardrone_video.rb +13 -5
  14. data/lib/artoo/adaptors/firmata.rb +10 -2
  15. data/lib/artoo/adaptors/loopback.rb +2 -1
  16. data/lib/artoo/adaptors/roomba.rb +12 -4
  17. data/lib/artoo/adaptors/sphero.rb +15 -3
  18. data/lib/artoo/api.rb +48 -5
  19. data/lib/artoo/api_route_helpers.rb +22 -3
  20. data/lib/artoo/basic.rb +3 -7
  21. data/lib/artoo/connection.rb +25 -7
  22. data/lib/artoo/delegator.rb +6 -16
  23. data/lib/artoo/device.rb +39 -10
  24. data/lib/artoo/device_event_client.rb +6 -0
  25. data/lib/artoo/drivers/ardrone.rb +5 -1
  26. data/lib/artoo/drivers/ardrone_navigation.rb +5 -1
  27. data/lib/artoo/drivers/ardrone_video.rb +9 -4
  28. data/lib/artoo/drivers/button.rb +7 -1
  29. data/lib/artoo/drivers/driver.rb +44 -4
  30. data/lib/artoo/drivers/led.rb +12 -1
  31. data/lib/artoo/drivers/motor.rb +12 -1
  32. data/lib/artoo/drivers/pinger.rb +10 -1
  33. data/lib/artoo/drivers/pinger2.rb +10 -1
  34. data/lib/artoo/drivers/roomba.rb +65 -17
  35. data/lib/artoo/drivers/servo.rb +12 -2
  36. data/lib/artoo/drivers/sphero.rb +19 -5
  37. data/lib/artoo/drivers/wiichuck.rb +7 -1
  38. data/lib/artoo/drivers/wiiclassic.rb +14 -5
  39. data/lib/artoo/drivers/wiidriver.rb +4 -1
  40. data/lib/artoo/events.rb +11 -4
  41. data/lib/artoo/ext/actor.rb +1 -1
  42. data/lib/artoo/ext/timers.rb +1 -1
  43. data/lib/artoo/main.rb +2 -13
  44. data/lib/artoo/master.rb +20 -2
  45. data/lib/artoo/port.rb +8 -3
  46. data/lib/artoo/robot.rb +45 -17
  47. data/lib/artoo/utility.rb +53 -9
  48. data/lib/artoo/version.rb +1 -1
  49. data/test/drivers/driver_test.rb +15 -0
  50. data/test/drivers/led_test.rb +4 -0
  51. data/test/utility_test.rb +35 -18
  52. data/test/utility_test_cases.rb +56 -0
  53. 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
- frame = connection.video_parser.get_frame
17
- publish(event_topic_name("update"), "frame", frame)
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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