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