artoo 0.4.0 → 0.4.1

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