artoo 0.2.0 → 0.3.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ed97e1d66baccca21165b0960b2ed18212b2a1d4
4
- data.tar.gz: 77e070f5faa53a75532d5c73f87c2016d9e0f23a
3
+ metadata.gz: c7ec92eb682584d629792c9e30321ec075c44ccc
4
+ data.tar.gz: 469f3321dd5bf852382c66ecf475ad272d0913bd
5
5
  SHA512:
6
- metadata.gz: 6566a8f925b396b38e0641e64548f42787d0611852733077697efad840b972281cc0ac8d218801476593a590c52287802a6bdd8bb25758c19430eaa4c20c4e67
7
- data.tar.gz: 4107fcfa598cc71a9d3a5e11f26b1885336e0b5c64ae264fc13150162db6fe4055d54db3984007c46886a3c74306c92fc3dadb66392d1b41b820888b34662af0
6
+ metadata.gz: 34faae07ab1729b9ef5dc82549ccb6e140d6452db47dc8eb2c451b12a45b645f22a7e1c47f0ca9624b20ffdcb58c2224d9cc2802590adcad76268bb05b3f9739
7
+ data.tar.gz: 0b97958c5708ecd774c3de2aa1b2c0cdc3905573f5296781cb92d29622caeb2dea6baef8c78a2a17382ddf760ecfb2d36aaca412de69d133436a8360b705cf24
@@ -1,10 +1,11 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- artoo (0.2.0)
4
+ artoo (0.3.0)
5
5
  active_support (~> 3.0)
6
- celluloid-io (~> 0.12)
6
+ celluloid-io (~> 0.13)
7
7
  multi_json (~> 1.6)
8
+ pry (~> 0.9)
8
9
  rake (~> 10.0)
9
10
  reel (~> 0.3)
10
11
 
@@ -16,11 +17,10 @@ GEM
16
17
  activesupport (3.0.0)
17
18
  bootstrap-sass (2.2.2.0)
18
19
  sass (~> 3.2)
19
- celluloid (0.12.4)
20
- facter (>= 1.6.12)
20
+ celluloid (0.13.0)
21
21
  timers (>= 1.0.0)
22
- celluloid-io (0.12.1)
23
- celluloid (~> 0.12.0)
22
+ celluloid-io (0.13.1)
23
+ celluloid (>= 0.13.0)
24
24
  nio4r (>= 0.4.0)
25
25
  certified (0.1.1)
26
26
  chunky_png (1.2.7)
@@ -41,7 +41,6 @@ GEM
41
41
  eventmachine (1.0.0-java)
42
42
  execjs (1.4.0)
43
43
  multi_json (~> 1.0)
44
- facter (1.6.17)
45
44
  fssm (0.2.10)
46
45
  guard (1.6.2)
47
46
  listen (>= 0.6.0)
@@ -79,6 +78,7 @@ GEM
79
78
  metaclass (~> 0.0.1)
80
79
  multi_json (1.6.1)
81
80
  nio4r (0.4.3)
81
+ nio4r (0.4.3-java)
82
82
  pry (0.9.12)
83
83
  coderay (~> 1.0.5)
84
84
  method_source (~> 0.8)
@@ -89,7 +89,7 @@ GEM
89
89
  slop (~> 3.4)
90
90
  spoon (~> 0.0)
91
91
  rack (1.5.2)
92
- rake (10.0.3)
92
+ rake (10.0.4)
93
93
  reel (0.3.0)
94
94
  celluloid-io (>= 0.8.0)
95
95
  http (>= 0.2.0)
@@ -108,7 +108,7 @@ GEM
108
108
  thor (0.17.0)
109
109
  tilt (1.3.3)
110
110
  timers (1.1.0)
111
- websocket_parser (0.1.1)
111
+ websocket_parser (0.1.2)
112
112
  http
113
113
 
114
114
  PLATFORMS
data/README.md CHANGED
@@ -71,7 +71,7 @@ SPHEROS.each {|p|
71
71
  SpheroRobot.work!(robots)
72
72
  ```
73
73
 
74
- Ruby versions supported: Ruby 2.0, 1.9.3, JRuby 1.7.2, and Rubinius 2.0
74
+ Ruby versions supported: Ruby 2.0, Ruby 1.9.3, JRuby 1.7.2, and Rubinius 2.0-rc1
75
75
 
76
76
 
77
77
  Artoo is conceptualy influenced by Sinatra (https://github.com/sinatra/sinatra) as well as borrowing some code from it.
@@ -100,6 +100,23 @@ end
100
100
 
101
101
  Once the robot or group is working, you can view the main API page at the host and port specified.
102
102
 
103
+ ## CLI:
104
+
105
+ Artoo includes Robi, a Command Line Interface (CLI) based on Pry (http://pryrepl.org/) to allow you to interactively control your robot.
106
+
107
+ ```
108
+ robi ./examples/hello.rb
109
+ I, [2013-03-16T18:14:22.281462 #61513] INFO -- : Registering connection 'loop'...
110
+ I, [2013-03-16T18:14:22.283027 #61513] INFO -- : Preparing work...
111
+ [1] pry(main)> start
112
+ I, [2013-03-16T18:14:23.836523 #61513] INFO -- : Initializing connection loop...
113
+ I, [2013-03-16T18:14:23.842265 #61513] INFO -- : Starting work...
114
+ I, [2013-03-16T18:14:23.842879 #61513] INFO -- : Connecting to 'loop' on port '#<Artoo::Port:0xe3c0>'...
115
+ [2] pry(main)> list
116
+ #<Artoo::MainRobot:0xe5e4>
117
+ [3] pry(main)> exit
118
+ ```
119
+
103
120
  ## Installing:
104
121
 
105
122
  ```ruby
data/Rakefile CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'bundler'
2
2
  Bundler::GemHelper.install_tasks
3
+ require 'pry'
3
4
 
4
5
  require 'rake/testtask'
5
6
 
@@ -9,3 +10,10 @@ Rake::TestTask.new do |t|
9
10
  end
10
11
 
11
12
  task :default => :test
13
+
14
+ desc "Start an interactive session with robot(s) loaded."
15
+ task :console, :file do |t, args|
16
+ robot_file = args[:file]
17
+ exec "bundle exec robi #{robot_file}"
18
+ end
19
+
@@ -19,11 +19,12 @@ Gem::Specification.new do |s|
19
19
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
20
  s.require_paths = ["lib"]
21
21
 
22
- s.add_runtime_dependency 'celluloid-io', '~> 0.12'
22
+ s.add_runtime_dependency 'celluloid-io', '~> 0.13'
23
23
  s.add_runtime_dependency 'reel', '~> 0.3'
24
24
  s.add_runtime_dependency 'multi_json', '~> 1.6'
25
25
  s.add_runtime_dependency 'active_support', '~> 3.0'
26
26
  s.add_runtime_dependency 'rake', '~> 10.0'
27
+ s.add_runtime_dependency 'pry', '~> 0.9'
27
28
  s.add_development_dependency 'minitest', '~> 4.6'
28
29
  s.add_development_dependency 'mocha', '~> 0.13'
29
30
  end
File without changes
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+ require 'pry'
3
+
4
+ Pry.config.prompt = proc { "robi> " }
5
+
6
+ command_set = Pry::CommandSet.new do
7
+ block_command "start", "Start all robots working" do
8
+ if defined?(Artoo::MainRobot)
9
+ output.puts "Starting main robot..."
10
+ Artoo::MainRobot.work! unless Artoo::MainRobot.is_running?
11
+ else
12
+ output.puts "Starting robots..."
13
+ end
14
+
15
+ Celluloid::Actor[:master].start_work
16
+ end
17
+
18
+ block_command "pause", "Pause all robots" do
19
+ output.puts "Pausing robots..."
20
+ Celluloid::Actor[:master].pause_work
21
+ end
22
+
23
+ block_command "continue", "Continue all robots" do
24
+ output.puts "Continuing robots..."
25
+ Celluloid::Actor[:master].continue_work
26
+ end
27
+
28
+ block_command "stop", "Stop all robots" do
29
+ output.puts "Not yet implemented..."
30
+ Celluloid::Actor[:master].stop_work
31
+ end
32
+
33
+ block_command "list", "List all robots" do
34
+ output.puts Celluloid::Actor[:master].robots
35
+ end
36
+ end
37
+
38
+ Pry::Commands.import command_set
39
+
40
+ ENV["ARTOO_CLI"] = 'true'
41
+ require ARGV[0]
42
+ Pry.start
@@ -66,8 +66,6 @@ work do
66
66
  on classic, :left_trigger => proc { |*value|
67
67
  if value[1] > 0
68
68
  drone.turn_left(validate_pitch(value[1], @offsets[:lt]))
69
- else
70
- drone.turn_left(0.0)
71
69
  end
72
70
  }
73
71
  end
@@ -1,6 +1,6 @@
1
1
  require 'artoo/robot'
2
2
 
3
- class SpheroRobot < Artoo::Robot
3
+ class ConwaySpheroRobot < Artoo::Robot
4
4
  connection :sphero, :adaptor => :sphero
5
5
  device :sphero, :driver => :sphero
6
6
 
@@ -59,9 +59,9 @@ SPHEROS = {"127.0.0.1:4560" => "/dev/tty.Sphero-BRG-RN-SPP",
59
59
  "127.0.0.1:4566" => "/dev/tty.Sphero-PYG-RN-SPP"}
60
60
  robots = []
61
61
  SPHEROS.each_key {|p|
62
- robots << SpheroRobot.new(:connections =>
62
+ robots << ConwaySpheroRobot.new(:connections =>
63
63
  {:sphero =>
64
64
  {:port => p}})
65
65
  }
66
66
 
67
- SpheroRobot.work!(robots)
67
+ ConwaySpheroRobot.work!(robots)
@@ -5,7 +5,7 @@ class HelloRobot < Artoo::Robot
5
5
 
6
6
  work do
7
7
  every(3.seconds) do
8
- puts "Hello from #{name}"
8
+ puts "Hello from #{name}"
9
9
  end
10
10
  after(10.seconds) do
11
11
  puts "#{name} is alive!" if name == 'Number 5'
@@ -19,4 +19,3 @@ robots = []
19
19
  end
20
20
 
21
21
  HelloRobot.work!(robots)
22
- sleep
@@ -1,6 +1,6 @@
1
1
  require 'artoo/robot'
2
2
 
3
- class SpheroRobot < Artoo::Robot
3
+ class DoubleSpheroRobot < Artoo::Robot
4
4
  connection :sphero, :adaptor => :sphero
5
5
  device :sphero, :driver => :sphero
6
6
 
@@ -18,9 +18,9 @@ SPHEROS = {"127.0.0.1:4560" => "/dev/tty.Sphero-BRG-RN-SPP",
18
18
  "127.0.0.1:4561" => "/dev/tty.Sphero-YBW-RN-SPP"}
19
19
  robots = []
20
20
  SPHEROS.each_key {|p|
21
- robots << SpheroRobot.new(:connections =>
21
+ robots << DoubleSpheroRobot.new(:connections =>
22
22
  {:sphero =>
23
23
  {:port => p}})
24
24
  }
25
25
 
26
- SpheroRobot.work!(robots)
26
+ DoubleSpheroRobot.work!(robots)
@@ -0,0 +1,26 @@
1
+ require 'artoo'
2
+
3
+ connection :arduino, :adaptor => :firmata, :port => "8023"
4
+ device :classic, :driver => :wiiclassic, :connection => :arduino, :interval => 0.1
5
+
6
+ work do
7
+ on classic, :a_button => proc { puts "a button pressed!" }
8
+ on classic, :b_button => proc { puts "b button pressed!" }
9
+ on classic, :x_button => proc { puts "x button pressed!" }
10
+ on classic, :y_button => proc { puts "y button pressed!" }
11
+ on classic, :home_button => proc { puts "home button pressed!" }
12
+ on classic, :start_button => proc { puts "start button pressed!" }
13
+ on classic, :select_button => proc { puts "select button pressed!" }
14
+ on classic, :left_joystick => proc { |*value|
15
+ puts "left joystick x: #{value[1][:x]}, y: #{value[1][:y]}" unless (value[1][:x] == 0 && value[1][:y] == 0)
16
+ }
17
+ on classic, :right_joystick => proc { |*value|
18
+ puts "right joystick x: #{value[1][:x]}, y: #{value[1][:y]}" unless (value[1][:x] == 0 && value[1][:y] == 0)
19
+ }
20
+ on classic, :right_trigger => proc { |*value|
21
+ puts "right trigger: #{value[1]}" unless (value[1]== 0)
22
+ }
23
+ on classic, :left_trigger => proc { |*value|
24
+ puts "left trigger: #{value[1]}" unless (value[1]== 0)
25
+ }
26
+ end
@@ -4,6 +4,7 @@ module Artoo
4
4
  module Adaptors
5
5
  # Connect to a ARDrone 2.0 (http://ardrone2.parrot.com/)
6
6
  class Ardrone < Adaptor
7
+ finalizer :finalize
7
8
  attr_reader :ardrone
8
9
 
9
10
  def finalize
@@ -4,7 +4,7 @@ module Artoo
4
4
  module Adaptors
5
5
  # Connect to a Roomba (http://www.irobot.com/en/us/robots/Educators/Create.aspx)
6
6
  class Roomba < Adaptor
7
-
7
+ finalizer :finalize
8
8
  attr_reader :sp
9
9
 
10
10
  def finalize
@@ -4,6 +4,7 @@ module Artoo
4
4
  module Adaptors
5
5
  # Connect to a Sphero (http://gosphero.com)
6
6
  class Sphero < Adaptor
7
+ finalizer :finalize
7
8
  RETRY_COUNT = 5
8
9
  attr_reader :sphero
9
10
 
@@ -17,32 +17,42 @@ module Artoo
17
17
  end
18
18
 
19
19
  get '/robots' do
20
- MultiJson.dump(Actor[:master].robots.collect {|r|r.to_hash})
20
+ MultiJson.dump(master.robots.collect {|r|r.to_hash})
21
21
  end
22
22
 
23
23
  get '/robots/:robotid' do
24
- Actor[:master].get_robot_by_name(@params['robotid']).as_json
24
+ master.get_robot(@params['robotid']).as_json
25
25
  end
26
26
 
27
27
  get '/robots/:robotid/devices' do
28
- MultiJson.dump(Actor[:master].get_robot_by_name(@params['robotid']).devices.each_value.collect {|d| d.to_hash})
28
+ MultiJson.dump(master.get_robot_devices(@params['robotid']).each_value.collect {|d| d.to_hash})
29
29
  end
30
30
 
31
31
  get '/robots/:robotid/devices/:deviceid' do
32
- Actor[:master].get_robot_by_name(@params['robotid']).devices[@params['deviceid'].intern].as_json
32
+ device(@params['robotid'], @params['deviceid']).as_json
33
33
  end
34
34
 
35
35
  get_ws '/robots/:robotid/devices/:deviceid/events' do
36
- DeviceEventClient.new(@req, Actor[:master].get_robot_by_name(@params['robotid']).devices[@params['deviceid'].intern].event_topic_name('update'))
36
+ DeviceEventClient.new(@req, device(@params['robotid'], @params['deviceid']).event_topic_name('update'))
37
37
  return nil
38
38
  end
39
39
 
40
40
  get '/robots/:robotid/connections' do
41
- MultiJson.dump(Actor[:master].get_robot_by_name(@params['robotid']).connections.each_value.collect {|c| c.to_hash})
41
+ MultiJson.dump(master.get_robot_connections(@params['robotid']).each_value.collect {|c| c.to_hash})
42
42
  end
43
43
 
44
44
  get '/robots/:robotid/connections/:connectionid' do
45
- Actor[:master].get_robot_by_name(@params['robotid']).connections[@params['connectionid'].intern].as_json
45
+ master.get_robot_connection(@params['robotid'], @params['connectionid']).as_json
46
+ end
47
+
48
+ protected
49
+
50
+ def master
51
+ Actor[:master]
52
+ end
53
+
54
+ def device(robot_id, device_id)
55
+ master.get_robot_device(robot_id, device_id)
46
56
  end
47
57
  end
48
58
  end
@@ -47,6 +47,14 @@ module Artoo
47
47
  MultiJson.dump(to_hash)
48
48
  end
49
49
 
50
+ def to_s
51
+ "#{self.class}:0x#{self.object_id}"
52
+ end
53
+
54
+ def inspect
55
+ "#<#{to_s}>"
56
+ end
57
+
50
58
  def method_missing(method_name, *arguments, &block)
51
59
  unless adaptor.connected?
52
60
  Logger.warn "Cannot call unconnected adaptor '#{name}', attempting to reconnect..."
@@ -51,6 +51,10 @@ module Artoo
51
51
  driver.send(method_name, *arguments, &block)
52
52
  end
53
53
 
54
+ def inspect
55
+ "#<Device @id=#{object_id}, @name='name', @driver='driver'>"
56
+ end
57
+
54
58
  private
55
59
 
56
60
  def require_driver(d)
@@ -1,60 +1,16 @@
1
- require 'artoo/drivers/driver'
1
+ require 'artoo/drivers/wiidriver'
2
2
 
3
3
  module Artoo
4
4
  module Drivers
5
5
  # Wiichuck driver behaviors for Firmata
6
- class Wiichuck < Driver
7
- attr_reader :joystick
8
-
9
- def address; 0x52; end
10
-
11
- INITIAL_DEFAULTS = {
12
- :sy_origin => nil,
13
- :sx_origin => nil
14
- }
15
-
16
- def initialize(params={})
17
- @joystick = INITIAL_DEFAULTS
18
- super
19
- end
20
-
21
- def start_driver
22
- begin
23
- listener = ->(value) { update(value) }
24
- connection.on("i2c_reply", listener)
25
-
26
- connection.i2c_config(0)
27
- every(interval) do
28
- connection.i2c_write_request(address, 0x40, 0x00)
29
- p
30
- connection.i2c_write_request(address, 0x00, 0x00)
31
- p
32
- connection.i2c_read_request(address, 6)
33
- p
34
- connection.read_and_process
35
- end
36
-
37
- super
38
- rescue Exception => e
39
- p "start driver"
40
- p e.message
41
- p e.backtrace.inspect
42
- end
43
-
44
- end
45
-
6
+ class Wiichuck < Wiidriver
46
7
  def update(value)
47
8
  begin
48
- if encrypted?(value)
49
- Logger.error "Encrypted bytes from wiichuck!"
50
- return
51
- end
9
+ super
52
10
 
53
- data = parse_wiichuck(value)
54
-
55
- adjust_origins(data)
56
- update_buttons(data)
57
- update_joystick(data)
11
+ adjust_origins
12
+ update_buttons
13
+ update_joystick
58
14
 
59
15
  rescue Exception => e
60
16
  Logger.error "wiichuck update exception!"
@@ -63,44 +19,35 @@ module Artoo
63
19
  end
64
20
  end
65
21
 
66
- def adjust_origins(data)
22
+ def adjust_origins
67
23
  set_joystick_default_value(:sy_origin, data[:sy])
68
24
  set_joystick_default_value(:sx_origin, data[:sx])
69
25
  end
70
26
 
71
- def set_joystick_default_value(joystick_axis, default_value)
72
- joystick[joystick_axis] = default_value if joystick[joystick_axis].nil?
73
- end
74
-
75
- def update_buttons(data)
27
+ def update_buttons
76
28
  publish(event_topic_name("c_button")) if data[:c] == true
77
29
  publish(event_topic_name("z_button")) if data[:z] == true
78
30
  end
79
31
 
80
- def update_joystick(data)
81
- publish(event_topic_name("joystick"), {:x => data[:sx] - @joystick[:sx_origin], :y => data[:sy] - @joystick[:sy_origin]})
32
+ def update_joystick
33
+ publish(event_topic_name("joystick"), {:x => calculate_joystick_value(:sx, :sx_origin), :y => calculate_joystick_value(:sy, :sy_origin)})
82
34
  end
83
35
 
84
36
  private
85
37
 
86
- def encrypted?(value)
87
- value[:data][0] == value[:data][1] && value[:data][2] == value[:data][3] && value[:data][4] == value[:data][5]
88
- end
89
-
90
- def decode( x )
91
- return ( x ^ 0x17 ) + 0x17
92
- end
93
-
94
- def get_value(value, index)
95
- decode(value[:data][index])
38
+ def get_defaults
39
+ {
40
+ :sy_origin => nil,
41
+ :sx_origin => nil
42
+ }
96
43
  end
97
44
 
98
- def parse_wiichuck(value)
45
+ def parse(value)
99
46
  return {
100
- :sx => get_value(value, 0),
101
- :sy => get_value(value, 1),
102
- :z => (get_value(value, 5) & 0x01 == 0 ? true : false ),
103
- :c => (get_value(value, 5) & 0x02 == 0 ? true : false )
47
+ :sx => decode_value(value, 0),
48
+ :sy => decode_value(value, 1),
49
+ :z => generate_bool(decode_value(value, 5) & 0x01),
50
+ :c => generate_bool(decode_value(value, 5) & 0x02)
104
51
  }
105
52
  end
106
53
  end
@@ -1,66 +1,18 @@
1
- require 'artoo/drivers/driver'
1
+ require 'artoo/drivers/wiidriver'
2
2
 
3
3
  module Artoo
4
4
  module Drivers
5
5
  # Wiiclassic driver behaviors for Firmata
6
- class Wiiclassic < Driver
7
- attr_reader :joystick
8
-
9
- def address; 0x52; end
10
-
11
- INITIAL_DEFAULTS = {
12
- :ry_origin => nil,
13
- :rx_origin => nil,
14
- :ly_origin => nil,
15
- :lx_origin => nil,
16
- :rt_origin => nil,
17
- :lt_origin => nil
18
- }
19
-
20
- def initialize(params={})
21
- @joystick = INITIAL_DEFAULTS
22
- super
23
- end
24
-
25
- def start_driver
26
- begin
27
- listener = ->(value) { update(value) }
28
- connection.on("i2c_reply", listener)
29
-
30
- connection.i2c_config(0)
31
- every(interval) do
32
- connection.i2c_write_request(address, 0x40, 0x00)
33
- p
34
- connection.i2c_write_request(address, 0x00, 0x00)
35
- p
36
- connection.i2c_read_request(address, 6)
37
- p
38
- connection.read_and_process
39
- end
40
-
41
- super
42
- rescue Exception => e
43
- p "start driver"
44
- p e.message
45
- p e.backtrace.inspect
46
- end
47
-
48
- end
49
-
6
+ class Wiiclassic < Wiidriver
50
7
  def update(value)
51
8
  begin
52
- if encrypted?(value)
53
- Logger.error "Encrypted bytes from wiiclassic!"
54
- return
55
- end
56
-
57
- data = parse_wiiclassic(value)
9
+ super
58
10
 
59
- adjust_origins(data)
60
- update_buttons(data)
61
- update_left_joystick(data)
62
- update_right_joystick(data)
63
- update_triggers(data)
11
+ adjust_origins
12
+ update_buttons
13
+ update_left_joystick
14
+ update_right_joystick
15
+ update_triggers
64
16
 
65
17
  rescue Exception => e
66
18
  Logger.error "wiiclassic update exception!"
@@ -69,7 +21,7 @@ module Artoo
69
21
  end
70
22
  end
71
23
 
72
- def adjust_origins(data)
24
+ def adjust_origins
73
25
  set_joystick_default_value(:ly_origin, data[:ly])
74
26
  set_joystick_default_value(:lx_origin, data[:lx])
75
27
  set_joystick_default_value(:ry_origin, data[:ry])
@@ -78,73 +30,100 @@ module Artoo
78
30
  set_joystick_default_value(:lt_origin, data[:lt])
79
31
  end
80
32
 
81
- def set_joystick_default_value(joystick_axis, default_value)
82
- joystick[joystick_axis] = default_value if joystick[joystick_axis].nil?
33
+ def update_buttons
34
+ update_button("a_button", :a)
35
+ update_button("b_button", :b)
36
+ update_button("x_button", :x)
37
+ update_button("y_button", :y)
38
+ update_button("home_button", :h)
39
+ update_button("start_button", :+)
40
+ update_button("select_button", :-)
41
+ end
42
+
43
+ def update_button(name, key)
44
+ publish(event_topic_name(name)) if data[key] == true
83
45
  end
84
46
 
85
- def update_buttons(data)
86
- publish(event_topic_name("a_button")) if data[:a] == true
87
- publish(event_topic_name("b_button")) if data[:b] == true
88
- publish(event_topic_name("x_button")) if data[:x] == true
89
- publish(event_topic_name("y_button")) if data[:y] == true
90
- publish(event_topic_name("home_button")) if data[:h] == true
91
- publish(event_topic_name("start_button")) if data[:+] == true
92
- publish(event_topic_name("select_button")) if data[:-] == true
47
+ def update_left_joystick
48
+ publish(event_topic_name("left_joystick"), {:x => calculate_joystick_value(:lx, :lx_origin), :y => calculate_joystick_value(:ly, :ly_origin)})
93
49
  end
94
50
 
95
- def update_left_joystick(data)
96
- publish(event_topic_name("left_joystick"), {:x => data[:lx] - @joystick[:lx_origin], :y => data[:ly] - @joystick[:ly_origin]})
51
+ def update_right_joystick
52
+ publish(event_topic_name("right_joystick"), {:x => calculate_joystick_value(:rx, :rx_origin), :y => calculate_joystick_value(:ry, :ry_origin)})
97
53
  end
98
54
 
99
- def update_right_joystick(data)
100
- publish(event_topic_name("right_joystick"), {:x => data[:rx] - @joystick[:rx_origin], :y => data[:ry] - @joystick[:ry_origin]})
55
+ def update_triggers
56
+ publish(event_topic_name("right_trigger"), calculate_joystick_value(:rt, :rt_origin))
57
+ publish(event_topic_name("left_trigger"), calculate_joystick_value(:lt, :lt_origin))
101
58
  end
102
59
 
103
- def update_triggers(data)
104
- publish(event_topic_name("right_trigger"), data[:rt] - @joystick[:rt_origin])
105
- publish(event_topic_name("left_trigger"), data[:lt] - @joystick[:lt_origin])
60
+ private
61
+
62
+ def get_defaults
63
+ {
64
+ :ry_origin => nil,
65
+ :rx_origin => nil,
66
+ :ly_origin => nil,
67
+ :lx_origin => nil,
68
+ :rt_origin => nil,
69
+ :lt_origin => nil
70
+ }
71
+ end
72
+
73
+ def parse(value)
74
+ return parse_joysticks(value).
75
+ merge(parse_buttons(value)).
76
+ merge(parse_triggers(value)).
77
+ merge(parse_dpad(value)).
78
+ merge(parse_zbuttons(value))
106
79
  end
107
80
 
108
- private
81
+ def parse_joysticks(value)
82
+ {
83
+ :lx => decode_value(value, 0) & 0x3f,
84
+ :ly => decode_value(value, 1) & 0x3f,
85
+ :rx => ((decode_value(value, 0) & 0xC0) >> 2) | ((decode_value(value, 1) & 0xC0) >> 4) | (decode_value(value, 2)[7]),
86
+ :ry => decode_value(value, 2) & 0x1f
87
+ }
88
+ end
109
89
 
110
- def encrypted?(value)
111
- value[:data][0] == value[:data][1] && value[:data][2] == value[:data][3] && value[:data][4] == value[:data][5]
90
+ def parse_buttons(value)
91
+ {
92
+ :a => get_bool_decoded_value(value, 5, 4),
93
+ :b => get_bool_decoded_value(value, 5, 6),
94
+ :x => get_bool_decoded_value(value, 5, 3),
95
+ :y => get_bool_decoded_value(value, 5, 5),
96
+ :+ => get_bool_decoded_value(value, 4, 2),
97
+ :- => get_bool_decoded_value(value, 4, 4),
98
+ :h => get_bool_decoded_value(value, 4, 3)
99
+ }
112
100
  end
113
101
 
114
- def decode( x )
115
- return ( x ^ 0x17 ) + 0x17
102
+ def parse_triggers(value)
103
+ {
104
+ :lt => ((decode_value(value, 2) & 0x60) >> 3) | ((decode_value(value, 3) & 0xC0) >> 6),
105
+ :rt => decode_value(value, 3) & 0x1f
106
+ }
116
107
  end
117
108
 
118
- def get_value(value, index)
119
- decode(value[:data][index])
109
+ def parse_dpad(value)
110
+ {
111
+ :d_up => get_bool_decoded_value(value, 5, 0),
112
+ :d_down => get_bool_decoded_value(value, 4, 6),
113
+ :d_left => get_bool_decoded_value(value, 5, 1),
114
+ :d_right => get_bool_decoded_value(value, 4, 7)
115
+ }
120
116
  end
121
117
 
122
- def parse_wiiclassic(value)
123
- return {
124
- :lx => get_value(value, 0) & 0x3f,
125
- :ly => get_value(value, 1) & 0x3f,
126
- :rx => ((get_value(value, 0) & 0xC0) >> 2) | ((get_value(value, 1) & 0xC0) >> 4) | (get_value(value, 2)[7]),
127
- :ry => get_value(value, 2) & 0x1f,
128
- :lt => ((get_value(value, 2) & 0x60) >> 3) | ((get_value(value, 3) & 0xC0) >> 6),
129
- :rt => get_value(value, 3) & 0x1f,
130
- :d_up => generate_bool(get_value(value, 5)[0]),
131
- :d_down => generate_bool(get_value(value, 4)[6]),
132
- :d_left => generate_bool(get_value(value, 5)[1]),
133
- :d_right => generate_bool(get_value(value, 4)[7]),
134
- :zr => generate_bool(get_value(value, 5)[2]),
135
- :zl => generate_bool(get_value(value, 5)[7]),
136
- :a => generate_bool(get_value(value, 5)[4]),
137
- :b => generate_bool(get_value(value, 5)[6]),
138
- :x => generate_bool(get_value(value, 5)[3]),
139
- :y => generate_bool(get_value(value, 5)[5]),
140
- :+ => generate_bool(get_value(value, 4)[2]),
141
- :- => generate_bool(get_value(value, 4)[4]),
142
- :h => generate_bool(get_value(value, 4)[3]),
118
+ def parse_zbuttons(value)
119
+ {
120
+ :zr => get_bool_decoded_value(value, 5, 2),
121
+ :zl => get_bool_decoded_value(value, 5, 7)
143
122
  }
144
123
  end
145
124
 
146
- def generate_bool(value)
147
- value == 0 ? true : false
125
+ def get_bool_decoded_value(value, offset1, offset2)
126
+ generate_bool(decode_value(value, offset1)[offset2])
148
127
  end
149
128
  end
150
129
  end
@@ -0,0 +1,89 @@
1
+ require 'artoo/drivers/driver'
2
+
3
+ module Artoo
4
+ module Drivers
5
+ # Wii-based controller shared driver behaviors for Firmata
6
+ class Wiidriver < Driver
7
+ attr_reader :joystick, :data
8
+
9
+ def address; 0x52; end
10
+
11
+ def initialize(params={})
12
+ @joystick = get_defaults
13
+ @data = {}
14
+ super
15
+ end
16
+
17
+ def start_driver
18
+ begin
19
+ listener = ->(value) { update(value) }
20
+ connection.on("i2c_reply", listener)
21
+
22
+ connection.i2c_config(0)
23
+ every(interval) do
24
+ connection.i2c_write_request(address, 0x40, 0x00)
25
+ p
26
+ connection.i2c_write_request(address, 0x00, 0x00)
27
+ p
28
+ connection.i2c_read_request(address, 6)
29
+ p
30
+ connection.read_and_process
31
+ end
32
+
33
+ super
34
+ rescue Exception => e
35
+ p "start driver"
36
+ p e.message
37
+ p e.backtrace.inspect
38
+ end
39
+ end
40
+
41
+ def update(value)
42
+ if encrypted?(value)
43
+ Logger.error "Encrypted bytes from wii device!"
44
+ raise "Encrypted bytes from wii device!"
45
+ end
46
+
47
+ @data = parse(value)
48
+ end
49
+
50
+ protected
51
+
52
+ def get_defaults
53
+ {}
54
+ end
55
+
56
+ def parse
57
+ {}
58
+ end
59
+
60
+ def set_joystick_default_value(joystick_axis, default_value)
61
+ joystick[joystick_axis] = default_value if joystick[joystick_axis].nil?
62
+ end
63
+
64
+ def calculate_joystick_value(axis, origin)
65
+ data[axis] - joystick[origin]
66
+ end
67
+
68
+ def encrypted?(value)
69
+ [[0, 1], [2, 3], [4, 5]].all? {|a| get_value(value, a[0]) == get_value(value, a[1]) }
70
+ end
71
+
72
+ def decode(x)
73
+ return ( x ^ 0x17 ) + 0x17
74
+ end
75
+
76
+ def decode_value(value, index)
77
+ decode(get_value(value, index))
78
+ end
79
+
80
+ def get_value(value, index)
81
+ value[:data][index]
82
+ end
83
+
84
+ def generate_bool(value)
85
+ value == 0 ? true : false
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,18 @@
1
+ # monkeypatches for Celluloid Actor class
2
+ module Celluloid
3
+ def timers
4
+ Actor.timers
5
+ end
6
+
7
+ class Actor
8
+ attr_accessor :timers
9
+
10
+ class << self
11
+ def timers
12
+ actor = Thread.current[:celluloid_actor]
13
+ raise NotActorError, "not in actor scope" unless actor
14
+ actor.timers
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,41 @@
1
+ # monkeypatches for Timers & Timer classes used by Celluloid
2
+ class Timers
3
+ def initialize
4
+ @timers = SortedSet.new
5
+ @paused_timers = SortedSet.new
6
+ end
7
+
8
+ def pause(timer = nil)
9
+ return pause_all if timer.nil?
10
+ raise TypeError, "not a Timers::Timer" unless timer.is_a? Timers::Timer
11
+ @timers.delete timer
12
+ @paused_timers.add timer
13
+ end
14
+
15
+ def pause_all
16
+ @timers.each {|timer| timer.pause}
17
+ end
18
+
19
+ def continue(timer = nil)
20
+ return continue_all if timer.nil?
21
+ raise TypeError, "not a Timers::Timer" unless timer.is_a? Timers::Timer
22
+ @paused_timers.delete timer
23
+ @timers.add timer
24
+ end
25
+
26
+ def continue_all
27
+ @paused_timers.each {|timer| timer.continue}
28
+ end
29
+
30
+ class Timer
31
+ # Pause this timer
32
+ def pause
33
+ @timers.pause self
34
+ end
35
+
36
+ # Continue this timer
37
+ def continue
38
+ @timers.continue self
39
+ end
40
+ end
41
+ end
@@ -9,8 +9,43 @@ module Artoo
9
9
  @robots = bots
10
10
  end
11
11
 
12
- def get_robot_by_name(name)
13
- robots.find_all {|r| r.name == name}.first
12
+ def robot(name)
13
+ robots.find {|r| r.name == name}
14
+ end
15
+
16
+ def robot_devices(name)
17
+ robot(name).devices
18
+ end
19
+
20
+ def robot_device(name, device_id)
21
+ robot_devices(name)[device_id.intern]
22
+ end
23
+
24
+ def robot_connections(name)
25
+ robot(name).connections
26
+ end
27
+
28
+ def robot_connection(robot_id, connection_id)
29
+ robot_connections(robot_id)[connection_id.intern]
30
+ end
31
+
32
+ def start_work
33
+ robots.each {|r| r.async.work} unless Artoo::Robot.is_running?
34
+ end
35
+
36
+ def pause_work
37
+ robots.each {|r|
38
+ Logger.info "pausing #{r.name}"
39
+ r.async.pause_work
40
+ }
41
+ end
42
+
43
+ def continue_work
44
+ robots.each {|r| r.async.continue_work}
45
+ end
46
+
47
+ def stop_work
48
+ #robots.each {|r| r.async.stop_work} unless !Artoo::Robot.is_running?
14
49
  end
15
50
  end
16
51
  end
@@ -1,5 +1,8 @@
1
+ require 'celluloid/autostart'
1
2
  require 'celluloid/io'
2
3
  require 'multi_json'
4
+ require 'artoo/ext/timers'
5
+ require 'artoo/ext/actor'
3
6
 
4
7
  require 'artoo/basic'
5
8
  require 'artoo/connection'
@@ -10,6 +13,7 @@ require 'artoo/master'
10
13
  require 'artoo/port'
11
14
  require 'artoo/utility'
12
15
 
16
+
13
17
  module Artoo
14
18
  # The most important class used by Artoo is Robot. This represents the primary
15
19
  # interface for interacting with a collection of physical computing capabilities.
@@ -29,7 +33,7 @@ module Artoo
29
33
  end
30
34
 
31
35
  class << self
32
- attr_accessor :device_types, :working_code,
36
+ attr_accessor :device_types, :working_code, :running,
33
37
  :use_api, :api_host, :api_port
34
38
 
35
39
  def connection_types
@@ -80,6 +84,18 @@ module Artoo
80
84
  # an array of existing instances
81
85
  # or, a new instance can be created
82
86
  def work!(robot=nil)
87
+ return if !test? && is_running?
88
+ prepare_robots(robot)
89
+
90
+ unless cli?
91
+ Celluloid::Actor[:api] = Api.new(self.api_host, self.api_port) if self.use_api
92
+ Celluloid::Actor[:master].start_work
93
+ self.running = true
94
+ sleep # sleep main thread, and let the work commence!
95
+ end
96
+ end
97
+
98
+ def prepare_robots(robot=nil)
83
99
  if robot.respond_to?(:work)
84
100
  robots = [robot]
85
101
  elsif robot.kind_of?(Array)
@@ -88,17 +104,21 @@ module Artoo
88
104
  robots = [self.new]
89
105
  end
90
106
 
91
- robots.each {|r| r.async.work}
92
-
93
107
  Celluloid::Actor[:master] = Master.new(robots)
94
- Celluloid::Actor[:api] = Api.new(self.api_host, self.api_port) if self.use_api
95
-
96
- sleep # sleep main thread, and let the work commence!
97
108
  end
98
109
 
99
110
  def test?
100
111
  ENV["ARTOO_TEST"] == 'true'
101
112
  end
113
+
114
+ def cli?
115
+ ENV["ARTOO_CLI"] == 'true'
116
+ end
117
+
118
+ def is_running?
119
+ self.running ||= false
120
+ self.running == true
121
+ end
102
122
  end
103
123
 
104
124
  def safe_name
@@ -121,12 +141,22 @@ module Artoo
121
141
  execute_working_code
122
142
  end
123
143
 
144
+ def pause_work
145
+ Logger.info "Pausing work..."
146
+ current_instance.timers.pause
147
+ end
148
+
149
+ def continue_work
150
+ Logger.info "Continuing work..."
151
+ current_instance.timers.continue
152
+ end
153
+
124
154
  def disconnect
125
155
  connections.each {|k, c| c.async.disconnect}
126
156
  end
127
157
 
128
158
  def default_connection
129
- connections[connections.keys.first]
159
+ connections.values.first
130
160
  end
131
161
 
132
162
  def connection_types
@@ -153,6 +183,10 @@ module Artoo
153
183
  MultiJson.dump(to_hash)
154
184
  end
155
185
 
186
+ def inspect
187
+ "#<Robot #{object_id}>"
188
+ end
189
+
156
190
  private
157
191
 
158
192
  def initialize_connections(params={})
@@ -1,5 +1,5 @@
1
1
  module Artoo
2
2
  unless const_defined?('VERSION')
3
- VERSION = "0.2.0"
3
+ VERSION = "0.3.0"
4
4
  end
5
5
  end
@@ -7,10 +7,5 @@ describe Artoo::Drivers::Wiiclassic do
7
7
  @driver = Artoo::Drivers::Wiiclassic.new(:parent => @device)
8
8
  end
9
9
 
10
- it 'must Artoo::Drivers::Wiiclassic#set_joystick_default_value' do
11
- val = "101"
12
- @driver.joystick[:test_axis] = nil
13
- @driver.set_joystick_default_value(:test_axis, val)
14
- @driver.joystick[:test_axis].must_equal val
15
- end
10
+ it 'must do things'
16
11
  end
@@ -0,0 +1,54 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../test_helper")
2
+ require 'artoo/drivers/wiidriver'
3
+
4
+ class Artoo::Drivers::Wiidriver
5
+ public :set_joystick_default_value, :calculate_joystick_value, :encrypted?,
6
+ :decode, :get_value, :generate_bool
7
+ end
8
+
9
+ describe Artoo::Drivers::Wiidriver do
10
+ before do
11
+ @device = mock('device')
12
+ @driver = Artoo::Drivers::Wiidriver.new(:parent => @device)
13
+ end
14
+
15
+ it 'Artoo::Drivers::Wiidriver#set_joystick_default_value' do
16
+ val = "101"
17
+ @driver.joystick[:test_axis] = nil
18
+ @driver.set_joystick_default_value(:test_axis, val)
19
+ @driver.joystick[:test_axis].must_equal val
20
+ end
21
+
22
+ it 'Artoo::Drivers::Wiidriver#calculate_joystick_value' do
23
+ @driver.data[:test_axis] = 8
24
+ @driver.joystick[:test_origin] = 5
25
+ @driver.calculate_joystick_value(:test_axis, :test_origin).must_equal 3
26
+ end
27
+
28
+ it 'Artoo::Drivers::Wiidriver#encrypted?' do
29
+ value = {:data => [0, 0, 0, 0, 0, 0]}
30
+ @driver.encrypted?(value).must_equal true
31
+ end
32
+
33
+ it 'Artoo::Drivers::Wiidriver#encrypted?' do
34
+ value = {:data => [1, 2, 3, 4, 5, 6]}
35
+ @driver.encrypted?(value).must_equal false
36
+ end
37
+
38
+ it 'Artoo::Drivers::Wiidriver#decode' do
39
+ @driver.decode(22).must_equal 24
40
+ @driver.decode(0).must_equal 46
41
+ @driver.decode(16).must_equal 30
42
+ end
43
+
44
+ it 'Artoo::Drivers::Wiidriver#get_value' do
45
+ value = {:data => [1, 2, 3, 4, 5, 6], :other_data => [10, 20, 30, 40, 50, 60]}
46
+ @driver.get_value(value, 1).must_equal 2
47
+ @driver.get_value(value, 5).must_equal 6
48
+ end
49
+
50
+ it 'Artoo::Drivers::Wiidriver#generate_bool' do
51
+ @driver.generate_bool(0).must_equal true
52
+ @driver.generate_bool(1).must_equal false
53
+ end
54
+ end
@@ -0,0 +1,45 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/test_helper")
2
+
3
+ class MockRobot
4
+ attr_reader :name
5
+
6
+ def initialize(name)
7
+ @name = name
8
+ end
9
+
10
+ def devices
11
+ ["#{name}-device1", "#{name}-device2", "#{name}-device3"]
12
+ end
13
+
14
+ def connections
15
+ ["#{name}-connection1", "#{name}-connection2", "#{name}-connection3"]
16
+ end
17
+ end
18
+
19
+ describe Artoo::Master do
20
+ before do
21
+ @robots = []
22
+
23
+ @robot1 = MockRobot.new("robot1")
24
+ @robot2 = MockRobot.new("robot2")
25
+ @robot3 = MockRobot.new("robot3")
26
+
27
+ @robots << @robot1
28
+ @robots << @robot2
29
+ @robots << @robot3
30
+
31
+ @master = Artoo::Master.new(@robots)
32
+ end
33
+
34
+ it 'Artoo::Master#robot' do
35
+ @master.robot("robot2").must_equal @robot2
36
+ end
37
+
38
+ it 'Artoo::Master#robot_devices' do
39
+ @master.robot_devices("robot2").first.must_equal "robot2-device1"
40
+ end
41
+
42
+ it 'Artoo::Master#robot_connections' do
43
+ @master.robot_connections("robot2").last.must_equal "robot2-connection3"
44
+ end
45
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: artoo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ron Evans
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2013-03-08 00:00:00.000000000 Z
15
+ date: 2013-04-09 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: celluloid-io
@@ -20,14 +20,14 @@ dependencies:
20
20
  requirements:
21
21
  - - ~>
22
22
  - !ruby/object:Gem::Version
23
- version: '0.12'
23
+ version: '0.13'
24
24
  type: :runtime
25
25
  prerelease: false
26
26
  version_requirements: !ruby/object:Gem::Requirement
27
27
  requirements:
28
28
  - - ~>
29
29
  - !ruby/object:Gem::Version
30
- version: '0.12'
30
+ version: '0.13'
31
31
  - !ruby/object:Gem::Dependency
32
32
  name: reel
33
33
  requirement: !ruby/object:Gem::Requirement
@@ -84,6 +84,20 @@ dependencies:
84
84
  - - ~>
85
85
  - !ruby/object:Gem::Version
86
86
  version: '10.0'
87
+ - !ruby/object:Gem::Dependency
88
+ name: pry
89
+ requirement: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: '0.9'
94
+ type: :runtime
95
+ prerelease: false
96
+ version_requirements: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ~>
99
+ - !ruby/object:Gem::Version
100
+ version: '0.9'
87
101
  - !ruby/object:Gem::Dependency
88
102
  name: minitest
89
103
  requirement: !ruby/object:Gem::Requirement
@@ -117,6 +131,7 @@ email:
117
131
  - artoo@hybridgroup.com
118
132
  executables:
119
133
  - retry.sh
134
+ - robi
120
135
  - sphero.sh
121
136
  extensions: []
122
137
  extra_rdoc_files: []
@@ -160,6 +175,7 @@ files:
160
175
  - api/public/partials/robot-index.html
161
176
  - artoo.gemspec
162
177
  - bin/retry.sh
178
+ - bin/robi
163
179
  - bin/sphero.sh
164
180
  - examples/ardrone.rb
165
181
  - examples/ardrone_nav.rb
@@ -186,6 +202,7 @@ files:
186
202
  - examples/sphero_multiple.rb
187
203
  - examples/sphero_wiichuck.rb
188
204
  - examples/wiichuck.rb
205
+ - examples/wiiclassic.rb
189
206
  - lib/artoo.rb
190
207
  - lib/artoo/adaptors/adaptor.rb
191
208
  - lib/artoo/adaptors/ardrone.rb
@@ -217,7 +234,10 @@ files:
217
234
  - lib/artoo/drivers/sphero.rb
218
235
  - lib/artoo/drivers/wiichuck.rb
219
236
  - lib/artoo/drivers/wiiclassic.rb
237
+ - lib/artoo/drivers/wiidriver.rb
220
238
  - lib/artoo/events.rb
239
+ - lib/artoo/ext/actor.rb
240
+ - lib/artoo/ext/timers.rb
221
241
  - lib/artoo/main.rb
222
242
  - lib/artoo/master.rb
223
243
  - lib/artoo/port.rb
@@ -244,6 +264,8 @@ files:
244
264
  - test/drivers/sphero_test.rb
245
265
  - test/drivers/wiichuck_test.rb
246
266
  - test/drivers/wiiclassic_test.rb
267
+ - test/drivers/wiidriver_test.rb
268
+ - test/master_test.rb
247
269
  - test/port_test.rb
248
270
  - test/robot_test.rb
249
271
  - test/test_helper.rb
@@ -267,32 +289,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
267
289
  version: '0'
268
290
  requirements: []
269
291
  rubyforge_project: artoo
270
- rubygems_version: 2.0.0
292
+ rubygems_version: 2.0.3
271
293
  signing_key:
272
294
  specification_version: 4
273
295
  summary: Ruby-based microframework for robotics
274
- test_files:
275
- - test/adaptors/adaptor_test.rb
276
- - test/adaptors/ardrone_test.rb
277
- - test/adaptors/firmata_test.rb
278
- - test/adaptors/loopback_test.rb
279
- - test/adaptors/sphero_test.rb
280
- - test/api_test.rb
281
- - test/artoo_test.rb
282
- - test/connection_test.rb
283
- - test/delegator_test.rb
284
- - test/device_test.rb
285
- - test/drivers/ardrone_navigation_test.rb
286
- - test/drivers/ardrone_test.rb
287
- - test/drivers/ardrone_video_test.rb
288
- - test/drivers/driver_test.rb
289
- - test/drivers/led_test.rb
290
- - test/drivers/motor_test.rb
291
- - test/drivers/servo_test.rb
292
- - test/drivers/sphero_test.rb
293
- - test/drivers/wiichuck_test.rb
294
- - test/drivers/wiiclassic_test.rb
295
- - test/port_test.rb
296
- - test/robot_test.rb
297
- - test/test_helper.rb
298
- - test/utility_test.rb
296
+ test_files: []