artoo 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/api/public/core.js CHANGED
@@ -234,6 +234,17 @@ ngChange:rd,required:dc,ngRequired:dc,ngValue:ud}).directive(lb).directive(ec);a
234
234
  return device.console();
235
235
  });
236
236
  };
237
+ $scope.executeCommand = function(deviceId, command) {
238
+ var params, post_params;
239
+ params = $("#appendedDropdownButton").val();
240
+ post_params = {};
241
+ if (params !== "") {
242
+ post_params = "{\"params\": [" + params + "]}";
243
+ }
244
+ return $http.post('/robots/' + $scope.robot.name + "/devices/" + deviceId + "/commands/" + command, post_params).success(function(data) {
245
+ return true;
246
+ });
247
+ };
237
248
  $scope.driverHasOutput = function(driverId) {
238
249
  if ($.inArray(driverId, window.driversWithOutput) !== -1) {
239
250
  return true;
@@ -25,7 +25,7 @@
25
25
  <div class="span2">
26
26
  <b><span class="name">{{deviceDetail.name}}</span></b>
27
27
  </div>
28
- <div class="span10">
28
+ <div class="span5 pull-right">
29
29
  <b>
30
30
  <dl class="controls">
31
31
  <span ng-show='deviceDetail.pin'>
@@ -42,9 +42,23 @@
42
42
  </span>
43
43
  <span ng-show='deviceDetail.connection'>
44
44
  <dt><i class="icon-circle" ng-class="isConnected(deviceDetail.connection)"></i> </dt>
45
- <dd ng-show="deviceDetail.connection.name">{{deviceDetail.connection.name}}</dd>
45
+ <dd ng-show="deviceDetail.connection.name">{{deviceDetail.connection.name}}</dd>
46
46
  </span>
47
47
  </dl>
48
+ <div class="input-prepend">
49
+ <div class="commands btn-group" >
50
+ <a class="btn dropdown-toggle btn-mini" data-toggle="dropdown" href="#">
51
+ Commands
52
+ <span class="caret"></span>
53
+ </a>
54
+ <ul class="dropdown-menu">
55
+ <div ng-repeat="command in deviceDetail.commands">
56
+ <li><a ng-click="executeCommand(deviceDetail.name, command)">{{command }}</a></li>
57
+ </div>
58
+ </ul>
59
+ </div>
60
+ <input id="appendedDropdownButton" type="text">
61
+ </div>
48
62
  </b>
49
63
  </div>
50
64
  </div>
data/artoo.gemspec CHANGED
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
25
25
  s.add_runtime_dependency 'multi_json', '~> 1.6'
26
26
  s.add_runtime_dependency 'rake', '~> 10.0'
27
27
  s.add_runtime_dependency 'pry', '~> 0.9'
28
- s.add_development_dependency 'minitest', '~> 4.6'
29
- s.add_development_dependency 'mocha', '~> 0.13'
28
+ s.add_development_dependency 'minitest', '~> 5.0'
29
+ s.add_development_dependency 'minitest-happy'
30
+ s.add_development_dependency 'mocha', '~> 0.14.0.alpha'
30
31
  end
@@ -0,0 +1,25 @@
1
+ #!/bin/bash
2
+ #
3
+ # This will create a sphero connection bound to /dev/Sphero-XXX
4
+ #
5
+ # Requires sudo or ran as root
6
+ #
7
+ # $1 = unbound /dev/rfcommXX
8
+ # $2 = sphero hardware address from hcitool scan
9
+ # $3 = sphero three letter color code
10
+ #
11
+ # Optional parameter
12
+ # $4 = bluetooth radio hcix
13
+ #
14
+ # Example
15
+ #
16
+ # sudo ./sphero_linux_bind.sh 1 00:06:66:4A:43:23 PYG hci1
17
+ #
18
+ #
19
+ if [ -z "$4" ]; then
20
+ addr="hci0"
21
+ else
22
+ addr=$4
23
+ fi
24
+ rfcomm -i $addr bind /dev/rfcomm$1 $2 1
25
+ ln -s /dev/rfcomm$1 /dev/Sphero-$3
@@ -6,14 +6,21 @@ device :drone, :driver => :ardrone, :connection => :ardrone
6
6
  connection :arduino, :adaptor => :firmata, :port => "8023"
7
7
  device :classic, :driver => :wiiclassic, :connection => :arduino, :interval => 0.1
8
8
 
9
- work do
10
- init_settings
9
+ OFFSETS = {
10
+ :ry => 12.0,
11
+ :ly => 27.0,
12
+ :lx => 27.0,
13
+ :rt => 27.0,
14
+ :lt => 12.0
15
+ }
16
+ @toggle_camera = 0
11
17
 
18
+ work do
12
19
  on classic, :a_button => proc { drone.take_off }
13
20
  on classic, :b_button => proc { drone.hover }
14
21
  on classic, :x_button => proc { drone.land }
15
22
  on classic, :y_button => proc {
16
- if @toggle_camera == 0
23
+ unless @toggle_camera
17
24
  drone.bottom_camera
18
25
  @toggle_camera = 1
19
26
  else
@@ -28,17 +35,17 @@ work do
28
35
  on classic, :left_joystick => proc { |*value|
29
36
  pair = value[1]
30
37
  if pair[:y] > 0
31
- drone.forward(validate_pitch(pair[:y], @offsets[:ly]))
38
+ drone.forward(validate_pitch(pair[:y], OFFSETS[:ly]))
32
39
  elsif pair[:y] < 0
33
- drone.backward(validate_pitch(pair[:y], @offsets[:ly]))
40
+ drone.backward(validate_pitch(pair[:y], OFFSETS[:ly]))
34
41
  else
35
42
  drone.forward(0.0)
36
43
  end
37
44
 
38
45
  if pair[:x] > 0
39
- drone.right(validate_pitch(pair[:x], @offsets[:lx]))
46
+ drone.right(validate_pitch(pair[:x], OFFSETS[:lx]))
40
47
  elsif pair[:x] < 0
41
- drone.left(validate_pitch(pair[:x], @offsets[:lx]))
48
+ drone.left(validate_pitch(pair[:x], OFFSETS[:lx]))
42
49
  else
43
50
  drone.right(0.0)
44
51
  end
@@ -47,9 +54,9 @@ work do
47
54
  on classic, :right_joystick => proc { |*value|
48
55
  pair = value[1]
49
56
  if pair[:y] > 0
50
- drone.up(validate_pitch(pair[:y], @offsets[:ry]))
57
+ drone.up(validate_pitch(pair[:y], OFFSETS[:ry]))
51
58
  elsif pair[:y] < 0
52
- drone.down(validate_pitch(pair[:y], @offsets[:ry]))
59
+ drone.down(validate_pitch(pair[:y], OFFSETS[:ry]))
53
60
  else
54
61
  drone.up(0.0)
55
62
  end
@@ -57,7 +64,7 @@ work do
57
64
 
58
65
  on classic, :right_trigger => proc { |*value|
59
66
  if value[1] > 0
60
- drone.turn_right(validate_pitch(value[1], @offsets[:rt]))
67
+ drone.turn_right(validate_pitch(value[1], OFFSETS[:rt]))
61
68
  else
62
69
  drone.turn_right(0.0)
63
70
  end
@@ -65,22 +72,11 @@ work do
65
72
 
66
73
  on classic, :left_trigger => proc { |*value|
67
74
  if value[1] > 0
68
- drone.turn_left(validate_pitch(value[1], @offsets[:lt]))
75
+ drone.turn_left(validate_pitch(value[1], OFFSETS[:lt]))
69
76
  end
70
77
  }
71
78
  end
72
79
 
73
- def init_settings
74
- @toggle_camera = 0
75
- @offsets = {
76
- :ry => 12.0,
77
- :ly => 27.0,
78
- :lx => 27.0,
79
- :rt => 27.0,
80
- :lt => 12.0
81
- }
82
- end
83
-
84
80
  def validate_pitch(data, offset)
85
81
  value = data.abs / offset
86
82
  value >= 0.1 ? (value <= 1.0 ? value.round(2) : 1.0) : 0.0
@@ -0,0 +1,7 @@
1
+ Sphero-BWY: bash ../bin/sphero_linux_socat.sh 4560 Sphero-BWY
2
+ Sphero-GOB: bash ../bin/sphero_linux_socat.sh 4561 Sphero-GOB
3
+ Sphero-PGB: bash ../bin/sphero_linux_socat.sh 4562 Sphero-PGB
4
+ Sphero-PYG: bash ../bin/sphero_linux_socat.sh 4563 Sphero-PYG
5
+ Sphero-WRW: bash ../bin/sphero_linux_socat.sh 4564 Sphero-WRW
6
+ Sphero-WWW: bash ../bin/sphero_linux_socat.sh 4565 Sphero-WWW
7
+ Sphero-YBW: bash ../bin/sphero_linux_socat.sh 4566 Sphero-YBW
@@ -9,14 +9,18 @@ class ConwaySpheroRobot < Artoo::Robot
9
9
  work do
10
10
  birth
11
11
 
12
+ on sphero, :collision => proc { contact }
13
+
12
14
  every(3.seconds) { movement if alive? }
13
15
  every(10.seconds) { birthday if alive? }
14
16
  end
15
17
 
16
18
  def alive?; (@alive == true); end
19
+ def reset_contacts; @contacts = 0; end
20
+ def contact; @contacts += 1; end
17
21
 
18
22
  def birth
19
- sphero.detect_collisions
23
+ reset_contacts
20
24
  @age = 0
21
25
  life
22
26
  movement
@@ -37,12 +41,11 @@ class ConwaySpheroRobot < Artoo::Robot
37
41
 
38
42
  def birthday
39
43
  @age += 1
40
- contacts = sphero.collisions.size
41
- sphero.clear_collisions
42
44
 
43
- puts "Happy birthday, #{name}, you are #{@age} and had #{contacts} contacts."
45
+ puts "Happy birthday, #{name}, you are #{@age} and had #{@contacts} contacts."
44
46
  #return if @age <= 3
45
- death unless contacts >= 3 && contacts < 5
47
+ death unless @contacts >= 3 && @contacts < 5
48
+ reset_contacts
46
49
  end
47
50
 
48
51
  def movement
@@ -4,19 +4,10 @@ connection :sphero, :adaptor => :sphero, :port => '127.0.0.1:4560'
4
4
  device :sphero, :driver => :sphero
5
5
 
6
6
  work do
7
- puts "Configuring..."
8
- sphero.detect_collisions
7
+ on sphero, :collision => proc { puts "Collision!" }
9
8
 
10
9
  every(3.seconds) do
11
10
  puts "Rolling..."
12
11
  sphero.roll 90, rand(360)
13
- unless sphero.collisions.empty?
14
- puts "----------"
15
- sphero.collisions.each do |c|
16
- puts c
17
- end
18
- puts "=========="
19
- sphero.async_messages.clear
20
- end
21
12
  end
22
13
  end
data/lib/artoo/api.rb CHANGED
@@ -53,7 +53,7 @@ module Artoo
53
53
  MultiJson.dump(device(@params['robotid'], @params['deviceid']).commands)
54
54
  end
55
55
 
56
- # Retrieve robot command
56
+ # Execute robot command
57
57
  # @return [JSON] command
58
58
  post '/robots/:robotid/devices/:deviceid/commands/:commandid' do
59
59
  result = device(@params['robotid'], @params['deviceid']).command(@params['commandid'], command_params)
@@ -91,8 +91,8 @@ module Artoo
91
91
 
92
92
  def command_params
93
93
  data = MultiJson.load(@req.body, :symbolize_keys => true)
94
- if data
95
- data[:params]
94
+ if data && params = data[:params]
95
+ params.size == 1 ? params.first : params
96
96
  else
97
97
  nil
98
98
  end
@@ -5,6 +5,8 @@ module Artoo
5
5
  # Ardrone driver behaviors
6
6
  # @see https://github.com/hybridgroup/argus/blob/master/lib/argus/drone.rb Argus::Drone docs for supported actions
7
7
  class Ardrone < Driver
8
+ COMMANDS = [:start, :stop, :hover, :land, :take_off, :emergency, :front_camera, :bottom_camera, :up, :down, :left, :right, :forward, :backward, :turn_left, :turn_right].freeze
9
+
8
10
  def start
9
11
  connection.start(false) # send false, so Argus does not use NavMonitor
10
12
  end
@@ -17,18 +17,31 @@ module Artoo
17
17
  # Sets values to read and write from button
18
18
  # and starts driver
19
19
  def start_driver
20
- listener = ->(value) { update(value) }
21
- connection.on("digital-read-#{pin}", listener)
22
20
  connection.set_pin_mode(pin, Firmata::Board::INPUT)
23
21
  connection.toggle_pin_reporting(pin)
24
22
 
25
23
  every(interval) do
26
24
  connection.read_and_process
25
+ handle_events
27
26
  end
28
27
 
29
28
  super
30
29
  end
31
30
 
31
+ def handle_events
32
+ while i = find_event("digital-read-#{pin}") do
33
+ update(events.slice!(i).data.first)
34
+ end
35
+ end
36
+
37
+ def find_event(name)
38
+ events.index {|e| e.name == name}
39
+ end
40
+
41
+ def events
42
+ connection.async_events
43
+ end
44
+
32
45
  # Publishes events according to the button feedback
33
46
  def update(value)
34
47
  if value == DOWN
@@ -5,7 +5,7 @@ module Artoo
5
5
  # The LED driver behaviors
6
6
  class Led < Driver
7
7
 
8
- COMMANDS = [:is_on?, :is_off?, :on, :off, :toggle, :brightness].freeze
8
+ COMMANDS = [:on, :off, :toggle, :brightness].freeze
9
9
 
10
10
  # @return [Boolean] True if on
11
11
  def is_on?
@@ -14,6 +14,34 @@ module Artoo
14
14
  COMMANDS = [:detect_collisions, :clear_collisions, :collisions,
15
15
  :power_notifications, :sensor_data, :set_color, :color].freeze
16
16
 
17
+ # Starts drives and required connections
18
+ def start_driver
19
+ begin
20
+ detect_collisions
21
+
22
+ every(interval) do
23
+ handle_collision_events
24
+ end
25
+
26
+ super
27
+ rescue Exception => e
28
+ Logger.error "Error starting Sphero driver!"
29
+ Logger.error e.message
30
+ Logger.error e.backtrace.inspect
31
+ end
32
+ end
33
+
34
+ def handle_collision_events
35
+ while i = find_event(::Sphero::Response::CollisionDetected) do
36
+ update_collision(messages.slice!(i))
37
+ end
38
+ end
39
+
40
+ # Publish collision events
41
+ def update_collision(data)
42
+ publish(event_topic_name("collision"), data)
43
+ end
44
+
17
45
  # Detects collisions
18
46
  # @param [Hash] params
19
47
  def detect_collisions(params={})
@@ -61,6 +89,10 @@ module Artoo
61
89
 
62
90
  private
63
91
 
92
+ def find_event(response_klass)
93
+ messages.index {|m| m.is_a? response_klass}
94
+ end
95
+
64
96
  def matching_response_types(responses, respone_klass)
65
97
  responses.select { |m| m.is_a? respone_klass } if responses
66
98
  end
@@ -18,25 +18,21 @@ module Artoo
18
18
  # Starts drives and required connections
19
19
  def start_driver
20
20
  begin
21
- listener = ->(value) { update(value) }
22
- connection.on("i2c_reply", listener)
23
-
24
21
  connection.i2c_config(0)
25
22
  every(interval) do
26
23
  connection.i2c_write_request(address, 0x40, 0x00)
27
- p
28
24
  connection.i2c_write_request(address, 0x00, 0x00)
29
- p
30
25
  connection.i2c_read_request(address, 6)
31
- p
26
+
32
27
  connection.read_and_process
28
+ handle_events
33
29
  end
34
30
 
35
31
  super
36
32
  rescue Exception => e
37
- p "start driver"
38
- p e.message
39
- p e.backtrace.inspect
33
+ Logger.error "Error starting wii driver!"
34
+ Logger.error e.message
35
+ Logger.error e.backtrace.inspect
40
36
  end
41
37
  end
42
38
 
@@ -50,8 +46,22 @@ module Artoo
50
46
  @data = parse(value)
51
47
  end
52
48
 
49
+ def handle_events
50
+ while i = find_event("i2c_reply") do
51
+ update(events.slice!(i).data.first)
52
+ end
53
+ end
54
+
53
55
  protected
54
56
 
57
+ def find_event(name)
58
+ events.index {|e| e.name == name}
59
+ end
60
+
61
+ def events
62
+ connection.async_events
63
+ end
64
+
55
65
  def get_defaults
56
66
  {}
57
67
  end
data/lib/artoo/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Artoo
2
2
  unless const_defined?('VERSION')
3
- VERSION = "0.4.1"
3
+ VERSION = "0.5.0"
4
4
  end
5
5
  end
@@ -12,7 +12,7 @@ describe Artoo::Connection do
12
12
 
13
13
  it 'Artoo::Connection#connect' do
14
14
  @connection.connect
15
- @connection.adaptor.must_be_kind_of Artoo::Adaptors::Loopback
15
+ @connection.adaptor.class.must_equal Artoo::Adaptors::Loopback
16
16
  end
17
17
 
18
18
  it 'Artoo::Connection#disconnect' do
@@ -1,6 +1,6 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + "/test_helper")
2
2
 
3
- class DelegatorTest < MiniTest::Unit::TestCase
3
+ class DelegatorTest < Minitest::Test
4
4
  class Mirror
5
5
  attr_reader :last_call
6
6
  def method_missing(*a, &b)