artoo 0.4.1 → 0.5.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 +4 -4
- data/Gemfile +10 -5
- data/Gemfile.lock +33 -11
- data/api/assets/javascripts/artoo/controllers/robot.js.coffee +6 -2
- data/api/assets/stylesheets/core.scss +6 -0
- data/api/public/core.css +1539 -1531
- data/api/public/core.js +11 -0
- data/api/public/partials/robot-detail.html +16 -2
- data/artoo.gemspec +3 -2
- data/bin/sphero_linux_bind.sh +25 -0
- data/examples/ardrone_wiiclassic.rb +18 -22
- data/examples/conway_sphero.procfile +7 -0
- data/examples/conway_sphero.rb +8 -5
- data/examples/sphero_messages.rb +1 -10
- data/lib/artoo/api.rb +3 -3
- data/lib/artoo/drivers/ardrone.rb +2 -0
- data/lib/artoo/drivers/button.rb +15 -2
- data/lib/artoo/drivers/led.rb +1 -1
- data/lib/artoo/drivers/sphero.rb +32 -0
- data/lib/artoo/drivers/wiidriver.rb +19 -9
- data/lib/artoo/version.rb +1 -1
- data/test/connection_test.rb +1 -1
- data/test/delegator_test.rb +1 -1
- data/test/robot_test.rb +1 -1
- data/test/test_helper.rb +0 -1
- metadata +23 -6
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="
|
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
|
-
|
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', '~>
|
29
|
-
s.add_development_dependency '
|
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
|
-
|
10
|
-
|
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
|
-
|
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],
|
38
|
+
drone.forward(validate_pitch(pair[:y], OFFSETS[:ly]))
|
32
39
|
elsif pair[:y] < 0
|
33
|
-
drone.backward(validate_pitch(pair[:y],
|
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],
|
46
|
+
drone.right(validate_pitch(pair[:x], OFFSETS[:lx]))
|
40
47
|
elsif pair[:x] < 0
|
41
|
-
drone.left(validate_pitch(pair[:x],
|
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],
|
57
|
+
drone.up(validate_pitch(pair[:y], OFFSETS[:ry]))
|
51
58
|
elsif pair[:y] < 0
|
52
|
-
drone.down(validate_pitch(pair[:y],
|
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],
|
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],
|
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
|
data/examples/conway_sphero.rb
CHANGED
@@ -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
|
-
|
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
|
data/examples/sphero_messages.rb
CHANGED
@@ -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 "
|
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
|
-
#
|
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
|
-
|
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
|
data/lib/artoo/drivers/button.rb
CHANGED
@@ -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
|
data/lib/artoo/drivers/led.rb
CHANGED
data/lib/artoo/drivers/sphero.rb
CHANGED
@@ -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
|
-
|
26
|
+
|
32
27
|
connection.read_and_process
|
28
|
+
handle_events
|
33
29
|
end
|
34
30
|
|
35
31
|
super
|
36
32
|
rescue Exception => e
|
37
|
-
|
38
|
-
|
39
|
-
|
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
data/test/connection_test.rb
CHANGED
@@ -12,7 +12,7 @@ describe Artoo::Connection do
|
|
12
12
|
|
13
13
|
it 'Artoo::Connection#connect' do
|
14
14
|
@connection.connect
|
15
|
-
@connection.adaptor.
|
15
|
+
@connection.adaptor.class.must_equal Artoo::Adaptors::Loopback
|
16
16
|
end
|
17
17
|
|
18
18
|
it 'Artoo::Connection#disconnect' do
|