hybridgroup-argus 0.4.0 → 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/README.md +4 -0
- data/lib/argus/ardrone_control_modes.rb +14 -0
- data/lib/argus/at_commander.rb +9 -5
- data/lib/argus/cfields.rb +1 -1
- data/lib/argus/controller.rb +30 -6
- data/lib/argus/drone.rb +18 -20
- data/lib/argus/flight_animation.rb +47 -0
- data/lib/argus/nav_monitor.rb +8 -4
- data/lib/argus/nav_option.rb +6 -0
- data/lib/argus/nav_streamer.rb +3 -3
- data/lib/argus/null_nav_monitor.rb +13 -0
- data/lib/argus/udp_sender.rb +1 -1
- data/lib/argus/version.rb +1 -1
- data/spec/argus/at_commander_spec.rb +35 -4
- data/spec/argus/cfields_spec.rb +39 -0
- data/spec/argus/controller_spec.rb +145 -121
- data/spec/argus/drone_spec.rb +44 -15
- data/spec/argus/flight_animation_spec.rb +21 -0
- data/spec/argus/nav_data_spec.rb +1 -0
- data/spec/argus/nav_monitor_spec.rb +65 -0
- data/spec/argus/nav_option_demo_spec.rb +2 -5
- data/spec/argus/nav_option_vision_detect_spec.rb +1 -0
- data/spec/argus/nav_streamer_spec.rb +6 -1
- data/spec/argus/null_nav_monitor_spec.rb +17 -0
- data/spec/argus/udp_sender_spec.rb +26 -13
- data/spec/argus/video_data_envelope_spec.rb +1 -1
- data/spec/argus/video_data_spec.rb +2 -3
- data/spec/argus/video_streamer_spec.rb +5 -0
- data/spec/spec_helper.rb +5 -1
- data/spec/support/bytes.rb +4 -0
- data/spec/support/capture_io.rb +32 -0
- metadata +12 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4aa5b03362c2310d0fc0ab4890c0663fecb0f6e1
|
4
|
+
data.tar.gz: 66d8edfbc9992de265a7de09b09a2c34b59be643
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 14733ed692c008b1ccedec0a1b5c868a12d1c2ab0d7e33494d02121953971798639520ab4622e0935acd980abfa5a9cb6f31d4c4d0aacd5d426b214b0350e7af
|
7
|
+
data.tar.gz: a3c84a2b7f381bc137781a8ef3df7dbb8453d39bd789aee6ba67a34d40f35ee054ca80fd40df512c314e2b02a4c5dc9aa2178c6683359bdbe2235237b35d4d7a
|
data/README.md
CHANGED
@@ -51,3 +51,7 @@ You can also use Argus by providing an externally created socket. For example, i
|
|
51
51
|
drone.stop
|
52
52
|
```
|
53
53
|
|
54
|
+
## Download the SDK
|
55
|
+
|
56
|
+
For additional reference, you can download the AR Drone Developer Guide (https://projects.ardrone.org/attachments/download/365/ARDrone_SDK_1_7_Developer_Guide.pdf) after signing up here (https://projects.ardrone.org/).
|
57
|
+
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Argus
|
2
|
+
module ArdroneControlModes
|
3
|
+
# ARDRONE_CONTROL_MODE values from the ardrone_api.h file.
|
4
|
+
|
5
|
+
CFG_GET_CONTROL_MODE = 4 # Send active configuration file
|
6
|
+
# to a client through the
|
7
|
+
# 'control' socket UDP 5559
|
8
|
+
|
9
|
+
ACK_CONTROL_MODE = 5 # Reset command mask in navdata
|
10
|
+
|
11
|
+
CUSTOM_CFG_GET_CONTROL_MODE = 6 # Requests the list of custom
|
12
|
+
# configuration IDs
|
13
|
+
end
|
14
|
+
end
|
data/lib/argus/at_commander.rb
CHANGED
@@ -3,6 +3,7 @@ require 'thread'
|
|
3
3
|
module Argus
|
4
4
|
class ATCommander
|
5
5
|
attr_reader :timestamps
|
6
|
+
attr_accessor :interval
|
6
7
|
|
7
8
|
def initialize(sender)
|
8
9
|
@sender = sender
|
@@ -44,10 +45,6 @@ module Argus
|
|
44
45
|
@thread.join if @thread
|
45
46
|
end
|
46
47
|
|
47
|
-
def interval=(new_interval)
|
48
|
-
@mutex.synchronize do @interval = new_interval end
|
49
|
-
end
|
50
|
-
|
51
48
|
def ref(data)
|
52
49
|
@mutex.synchronize do @ref_data = data end
|
53
50
|
end
|
@@ -62,11 +59,18 @@ module Argus
|
|
62
59
|
end
|
63
60
|
end
|
64
61
|
|
65
|
-
def
|
62
|
+
def comwdg
|
66
63
|
@mutex.synchronize do
|
67
64
|
command("COMWDG")
|
68
65
|
end
|
69
66
|
end
|
67
|
+
alias reset_watchdog comwdg # For backward compatibility
|
68
|
+
|
69
|
+
def ctrl(mode)
|
70
|
+
@mutex.synchronize do
|
71
|
+
command("CTRL", "#{mode},0")
|
72
|
+
end
|
73
|
+
end
|
70
74
|
|
71
75
|
private
|
72
76
|
|
data/lib/argus/cfields.rb
CHANGED
data/lib/argus/controller.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'argus/float_encoding'
|
2
|
+
require 'argus/ardrone_control_modes'
|
2
3
|
|
3
4
|
module Argus
|
4
5
|
class Controller
|
@@ -23,9 +24,15 @@ module Argus
|
|
23
24
|
update_ref
|
24
25
|
end
|
25
26
|
|
26
|
-
def
|
27
|
+
def enable_emergency(state=false)
|
28
|
+
@flying = true
|
29
|
+
@emergency = state
|
30
|
+
update_ref
|
31
|
+
end
|
32
|
+
|
33
|
+
def disable_emergency(state=true)
|
27
34
|
@flying = false
|
28
|
-
@emergency =
|
35
|
+
@emergency = state
|
29
36
|
update_ref
|
30
37
|
end
|
31
38
|
|
@@ -97,6 +104,16 @@ module Argus
|
|
97
104
|
self
|
98
105
|
end
|
99
106
|
|
107
|
+
def animate(selection, duration)
|
108
|
+
selection = FlightAnimation.lookup_value(selection)
|
109
|
+
value = [
|
110
|
+
selection,
|
111
|
+
duration
|
112
|
+
].join(',')
|
113
|
+
@at_commander.config("control:flight_anim",value)
|
114
|
+
self
|
115
|
+
end
|
116
|
+
|
100
117
|
def enable_detection(colors, type=10, select=32)
|
101
118
|
config("detect:enemy_colors",colors.to_s)
|
102
119
|
config("detect:detect_type", type.to_s)
|
@@ -106,22 +123,29 @@ module Argus
|
|
106
123
|
|
107
124
|
def config(key, value)
|
108
125
|
@at_commander.config(key, value)
|
126
|
+
self
|
109
127
|
end
|
110
128
|
|
111
129
|
def demo_mode
|
112
|
-
|
130
|
+
config("general:navdata_demo", "TRUE")
|
113
131
|
end
|
114
132
|
|
115
133
|
def front_camera
|
116
|
-
|
134
|
+
config("video:video_channel", "2")
|
117
135
|
end
|
118
136
|
|
119
137
|
def bottom_camera
|
120
|
-
|
138
|
+
config("video:video_channel", "1")
|
121
139
|
end
|
122
140
|
|
123
141
|
def reset_watchdog
|
124
|
-
@at_commander.
|
142
|
+
@at_commander.comwdg
|
143
|
+
self
|
144
|
+
end
|
145
|
+
|
146
|
+
def ack_control_mode
|
147
|
+
@at_commander.ctrl(ArdroneControlModes::ACK_CONTROL_MODE)
|
148
|
+
self
|
125
149
|
end
|
126
150
|
|
127
151
|
private
|
data/lib/argus/drone.rb
CHANGED
@@ -4,17 +4,21 @@ require 'argus/nav_monitor'
|
|
4
4
|
module Argus
|
5
5
|
|
6
6
|
class Drone
|
7
|
-
attr_reader :controller, :
|
7
|
+
attr_reader :controller, :nav
|
8
8
|
|
9
9
|
def initialize(opts={})
|
10
|
-
|
11
|
-
|
12
|
-
@
|
13
|
-
@
|
14
|
-
@
|
15
|
-
|
16
|
-
|
17
|
-
|
10
|
+
host = opts[:remote_host] || '192.168.1.1'
|
11
|
+
port = opts[:post] || '5556'
|
12
|
+
@sender = opts[:sender] || Argus::UdpSender.new(socket: opts[:socket], remote_host: host, port: port)
|
13
|
+
@at = opts[:commander] || Argus::ATCommander.new(@sender)
|
14
|
+
@controller = opts[:controller] || Argus::Controller.new(@at)
|
15
|
+
if opts[:nav_monitor]
|
16
|
+
@nav = opts[:nav_monitor]
|
17
|
+
elsif opts.fetch(:enable_nav_monitor, true)
|
18
|
+
@nav = NavMonitor.new(@controller, host)
|
19
|
+
else
|
20
|
+
@nav = NullNavMonitor.new
|
21
|
+
end
|
18
22
|
end
|
19
23
|
|
20
24
|
def commander
|
@@ -22,13 +26,7 @@ module Argus
|
|
22
26
|
end
|
23
27
|
|
24
28
|
def start(enable_nav_monitor=true)
|
25
|
-
@
|
26
|
-
|
27
|
-
if enable_nav_monitor
|
28
|
-
@nav = NavMonitor.new(@controller, @host)
|
29
|
-
@nav.start
|
30
|
-
end
|
31
|
-
|
29
|
+
@nav.start
|
32
30
|
@at.start
|
33
31
|
end
|
34
32
|
|
@@ -36,10 +34,10 @@ module Argus
|
|
36
34
|
@controller.land
|
37
35
|
|
38
36
|
@at.stop
|
39
|
-
@nav.stop
|
37
|
+
@nav.stop
|
40
38
|
|
41
39
|
@at.join
|
42
|
-
@nav.join
|
40
|
+
@nav.join
|
43
41
|
end
|
44
42
|
|
45
43
|
def nav_callback(*args, &block)
|
@@ -47,14 +45,14 @@ module Argus
|
|
47
45
|
end
|
48
46
|
|
49
47
|
%w(
|
50
|
-
take_off land hover
|
48
|
+
take_off land hover disable_emergency enable_emergency
|
51
49
|
forward backward
|
52
50
|
left right
|
53
51
|
up down
|
54
52
|
turn_left turn_right
|
55
53
|
front_camera bottom_camera
|
56
54
|
config
|
57
|
-
led
|
55
|
+
led animate
|
58
56
|
reset_watchdog
|
59
57
|
).each do |meth|
|
60
58
|
define_method(meth) { |*args|
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Argus
|
2
|
+
|
3
|
+
module FlightAnimation
|
4
|
+
NAMES = [
|
5
|
+
:phi_m30_deg,
|
6
|
+
:phi_30_deg,
|
7
|
+
:theta_m30_deg,
|
8
|
+
:theta_30_deg,
|
9
|
+
:theta_20_deg_yaw_200_deg,
|
10
|
+
:theta_20_deg_yaw_m_200_deg,
|
11
|
+
:turnaround,
|
12
|
+
:turnaround_go_down,
|
13
|
+
:yaw_shake,
|
14
|
+
:yaw_dance,
|
15
|
+
:phi_dance,
|
16
|
+
:theta_dance,
|
17
|
+
:vz_dance,
|
18
|
+
:wave,
|
19
|
+
:phi_theta_mixed,
|
20
|
+
:double_phi_theta_mixed,
|
21
|
+
:flip_ahead,
|
22
|
+
:flip_behind,
|
23
|
+
:flip_left,
|
24
|
+
:flip_right,
|
25
|
+
]
|
26
|
+
|
27
|
+
VALUES = {}
|
28
|
+
NAMES.each.with_index { |name, index| VALUES[name] = index }
|
29
|
+
|
30
|
+
def self.lookup_name(numeric_value)
|
31
|
+
NAMES[numeric_value]
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.lookup_value(symbolic_name)
|
35
|
+
case symbolic_name
|
36
|
+
when Symbol
|
37
|
+
VALUES[symbolic_name]
|
38
|
+
when Integer
|
39
|
+
symbolic_name
|
40
|
+
when /^\d+/
|
41
|
+
symbolic_name.to_i
|
42
|
+
when String
|
43
|
+
VALUES[symbolic_name.intern]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/argus/nav_monitor.rb
CHANGED
@@ -3,9 +3,9 @@ module Argus
|
|
3
3
|
class NavMonitor
|
4
4
|
attr_reader :streamer
|
5
5
|
|
6
|
-
def initialize(controller, remote_host)
|
6
|
+
def initialize(controller, remote_host, opts={})
|
7
7
|
@controller = controller
|
8
|
-
@streamer = NavStreamer.new(remote_host: remote_host)
|
8
|
+
@streamer = opts.fetch(:streamer) { NavStreamer.new(remote_host: remote_host) }
|
9
9
|
@callbacks = []
|
10
10
|
@mutex = Mutex.new
|
11
11
|
@nav_data = nil
|
@@ -28,6 +28,7 @@ module Argus
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def join
|
31
|
+
stop
|
31
32
|
@nav_thread.join
|
32
33
|
end
|
33
34
|
|
@@ -46,8 +47,6 @@ module Argus
|
|
46
47
|
@mutex.synchronize { @nav_options[tag] }
|
47
48
|
end
|
48
49
|
|
49
|
-
private
|
50
|
-
|
51
50
|
def update_nav_data(data)
|
52
51
|
@mutex.synchronize do
|
53
52
|
update_internal_nav_data(data)
|
@@ -60,11 +59,16 @@ module Argus
|
|
60
59
|
$stdout.flush
|
61
60
|
end
|
62
61
|
|
62
|
+
private
|
63
|
+
|
63
64
|
def update_internal_nav_data(data)
|
64
65
|
@nav_data = data
|
65
66
|
if @nav_data.bootstrap?
|
66
67
|
@controller.demo_mode
|
67
68
|
end
|
69
|
+
if @nav_data.control_command_ack?
|
70
|
+
@controller.ack_control_mode
|
71
|
+
end
|
68
72
|
data.options.each do |opt|
|
69
73
|
@nav_options[opt.tag] = opt if opt.tag < 100
|
70
74
|
end
|
data/lib/argus/nav_option.rb
CHANGED
data/lib/argus/nav_streamer.rb
CHANGED
@@ -25,8 +25,8 @@ module Argus
|
|
25
25
|
@remote_host = opts.fetch(:remote_host)
|
26
26
|
@local_host = opts[:local_host] || '0.0.0.0'
|
27
27
|
@port = opts[:port] || 5554
|
28
|
-
@socket_class = opts[:
|
29
|
-
start_timer
|
28
|
+
@socket_class = opts[:UDPSocket] || UDPSocket
|
29
|
+
start_timer unless opts[:disable_timer]
|
30
30
|
end
|
31
31
|
|
32
32
|
def start
|
@@ -51,7 +51,7 @@ module Argus
|
|
51
51
|
data, from = @socket.recvfrom(1024)
|
52
52
|
if data.unpack("V").first == 0x55667788
|
53
53
|
received_data
|
54
|
-
|
54
|
+
NavData.new(data)
|
55
55
|
else
|
56
56
|
nil
|
57
57
|
end
|
data/lib/argus/udp_sender.rb
CHANGED
data/lib/argus/version.rb
CHANGED
@@ -5,20 +5,48 @@ describe Argus::ATCommander do
|
|
5
5
|
Given(:cmdr) { Argus::ATCommander.new(sender) }
|
6
6
|
|
7
7
|
describe "#tick" do
|
8
|
+
Given(:expected_commands) {
|
9
|
+
[
|
10
|
+
"AT\\*REF=\\d+,0",
|
11
|
+
"AT\\*PCMD=\\d+,0,0,0,0,0",
|
12
|
+
]
|
13
|
+
}
|
14
|
+
Given(:command_pattern) { Regexp.new('\A' + expected_commands.map { |s| "#{s}\r" }.join + '\Z') }
|
15
|
+
|
8
16
|
When { cmdr.send(:tick) }
|
9
17
|
|
10
18
|
context "with no commands" do
|
11
|
-
Then { sender.should have_received(:send_packet).with(
|
19
|
+
Then { sender.should have_received(:send_packet).with(command_pattern) }
|
12
20
|
end
|
13
21
|
|
14
22
|
context "with a ref command" do
|
23
|
+
Given { expected_commands[0] = 'AT\*REF=\d+,512' }
|
15
24
|
Given { cmdr.ref("512") }
|
16
|
-
Then { sender.should have_received(:send_packet).with(
|
25
|
+
Then { sender.should have_received(:send_packet).with(command_pattern) }
|
17
26
|
end
|
18
27
|
|
19
28
|
context "with a pcmd command" do
|
29
|
+
Given { expected_commands[1] = 'AT\*PCMD=\d+,1,2,3,4,5' }
|
20
30
|
Given { cmdr.pcmd("1,2,3,4,5") }
|
21
|
-
Then { sender.should have_received(:send_packet).with(
|
31
|
+
Then { sender.should have_received(:send_packet).with(command_pattern) }
|
32
|
+
end
|
33
|
+
|
34
|
+
context "with a config command" do
|
35
|
+
Given { expected_commands.unshift('AT\*CONFIG=\d+,"general:navdata_demo","TRUE"') }
|
36
|
+
Given { cmdr.config("general:navdata_demo", "TRUE") }
|
37
|
+
Then { sender.should have_received(:send_packet).with(command_pattern) }
|
38
|
+
end
|
39
|
+
|
40
|
+
context "with a reset watchdog command" do
|
41
|
+
Given { expected_commands.unshift('AT\*COMWDG=\d+') }
|
42
|
+
Given { cmdr.comwdg }
|
43
|
+
Then { sender.should have_received(:send_packet).with(command_pattern) }
|
44
|
+
end
|
45
|
+
|
46
|
+
context "with a contrl command" do
|
47
|
+
Given { expected_commands.unshift('AT\*CTRL=\d+,4,0') }
|
48
|
+
Given { cmdr.ctrl(4) }
|
49
|
+
Then { sender.should have_received(:send_packet).with(command_pattern) }
|
22
50
|
end
|
23
51
|
end
|
24
52
|
|
@@ -49,6 +77,9 @@ describe Argus::ATCommander do
|
|
49
77
|
Then { sender.should have_received(:send_packet) }
|
50
78
|
end
|
51
79
|
|
52
|
-
|
80
|
+
describe "setting the interval" do
|
81
|
+
Given { cmdr.interval = 1.0 }
|
82
|
+
Then { cmdr.interval == 1.0 }
|
83
|
+
end
|
53
84
|
|
54
85
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module CFieldsSpec
|
4
|
+
describe Argus::CFields do
|
5
|
+
class Example < Argus::NavOption
|
6
|
+
include Argus::CFields
|
7
|
+
uint32_t :u32
|
8
|
+
uint16_t :u16
|
9
|
+
float32_t :f32
|
10
|
+
int32_t :i32
|
11
|
+
matrix33_t :m33
|
12
|
+
vector31_t :v31
|
13
|
+
|
14
|
+
def self.tag
|
15
|
+
14263
|
16
|
+
end
|
17
|
+
|
18
|
+
Argus::NavOption.register(self)
|
19
|
+
end
|
20
|
+
|
21
|
+
Given(:raw_data) {
|
22
|
+
[
|
23
|
+
Bytes.int16(Example.tag),
|
24
|
+
Bytes.int16(10),
|
25
|
+
Bytes.int32(1),
|
26
|
+
Bytes.int16(2),
|
27
|
+
Bytes.float32(3.4),
|
28
|
+
].flatten.pack("C*")
|
29
|
+
}
|
30
|
+
|
31
|
+
When(:data) { Example.new(raw_data) }
|
32
|
+
|
33
|
+
Then { data.size == 10 }
|
34
|
+
Then { data.tag == Example.tag }
|
35
|
+
Then { data.u32 == 1 }
|
36
|
+
Then { data.u16 == 2 }
|
37
|
+
Then { data.f32 == about(3.4).percent(1) }
|
38
|
+
end
|
39
|
+
end
|
@@ -15,129 +15,153 @@ describe Argus::Controller do
|
|
15
15
|
Given(:at) { flexmock(:on, Argus::ATCommander) }
|
16
16
|
Given(:controller) { Argus::Controller.new(at) }
|
17
17
|
|
18
|
-
|
18
|
+
describe "controller commands" do
|
19
19
|
Invariant { result.should == controller }
|
20
20
|
|
21
|
-
context "
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
end
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
21
|
+
context "navigating commands" do
|
22
|
+
context "when taking off" do
|
23
|
+
When(:result) { controller.take_off }
|
24
|
+
Then { at.should have_received(:ref).with(ref_bits(9)) }
|
25
|
+
end
|
26
|
+
|
27
|
+
context "when landing" do
|
28
|
+
When(:result) { controller.land }
|
29
|
+
Then { at.should have_received(:ref).with(ref_bits).twice }
|
30
|
+
end
|
31
|
+
|
32
|
+
context "when enable_emergency" do
|
33
|
+
Given { controller.enable_emergency }
|
34
|
+
When(:result) { controller.take_off }
|
35
|
+
Then { at.should have_received(:ref).with(ref_bits(9)) }
|
36
|
+
end
|
37
|
+
|
38
|
+
context "when taking off after a disable_emergency" do
|
39
|
+
Given { controller.disable_emergency }
|
40
|
+
When(:result) { controller.take_off }
|
41
|
+
Then { at.should have_received(:ref).with(ref_bits(8)) }
|
42
|
+
end
|
43
|
+
|
44
|
+
context "when hovering" do
|
45
|
+
When(:result) { controller.hover }
|
46
|
+
Then { at.should have_received(:pcmd).with("0,0,0,0,0") }
|
47
|
+
end
|
48
|
+
|
49
|
+
context "when moving forward" do
|
50
|
+
When(:result) { controller.forward(0.80) }
|
51
|
+
Then { at.should have_received(:pcmd).with("1,0,-1085485875,0,0") }
|
52
|
+
end
|
53
|
+
|
54
|
+
context "when moving backward" do
|
55
|
+
When(:result) { controller.backward(0.80) }
|
56
|
+
Then { at.should have_received(:pcmd).with("1,0,1061997773,0,0") }
|
57
|
+
end
|
58
|
+
|
59
|
+
context "when moving to the left" do
|
60
|
+
When(:result) { controller.left(0.80) }
|
61
|
+
Then { at.should have_received(:pcmd).with("1,-1085485875,0,0,0") }
|
62
|
+
end
|
63
|
+
|
64
|
+
context "when moving to the right" do
|
65
|
+
When(:result) { controller.right(0.80) }
|
66
|
+
Then { at.should have_received(:pcmd).with("1,1061997773,0,0,0") }
|
67
|
+
end
|
68
|
+
|
69
|
+
context "when moving up" do
|
70
|
+
When(:result) { controller.up(0.80) }
|
71
|
+
Then { at.should have_received(:pcmd).with("1,0,0,1061997773,0") }
|
72
|
+
end
|
73
|
+
|
74
|
+
context "when moving down" do
|
75
|
+
When(:result) { controller.down(0.80) }
|
76
|
+
Then { at.should have_received(:pcmd).with("1,0,0,-1085485875,0") }
|
77
|
+
end
|
78
|
+
|
79
|
+
context "when turning left" do
|
80
|
+
When(:result) { controller.turn_left(0.80) }
|
81
|
+
Then { at.should have_received(:pcmd).with("1,0,0,0,-1085485875") }
|
82
|
+
end
|
83
|
+
|
84
|
+
context "when turning right" do
|
85
|
+
When(:result) { controller.turn_right(0.80) }
|
86
|
+
Then { at.should have_received(:pcmd).with("1,0,0,0,1061997773") }
|
87
|
+
end
|
88
|
+
|
89
|
+
context "when executing several directions" do
|
90
|
+
When(:result) {
|
91
|
+
controller.forward(1.0).left(0.5).up(0.2).turn_left(0.8)
|
92
|
+
}
|
93
|
+
Then { at.should have_received(:pcmd).with("1,-1090519040,-1082130432,1045220557,-1085485875") }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe "config command" do
|
98
|
+
context "when setting with numeric sequence" do
|
99
|
+
When(:result) { controller.led(3, 2.0, 4) }
|
100
|
+
Then {
|
101
|
+
at.should have_received(:config)
|
102
|
+
.with("leds:leds_anim", "3,1073741824,4")
|
103
|
+
}
|
104
|
+
end
|
105
|
+
|
106
|
+
context "when setting with symbolic sequence" do
|
107
|
+
When(:result) { controller.led(:blink_orange, 2.0, 4) }
|
108
|
+
Then {
|
109
|
+
at.should have_received(:config)
|
110
|
+
.with("leds:leds_anim", "3,1073741824,4")
|
111
|
+
}
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "enabled detection command" do
|
116
|
+
context "when setting all parameters" do
|
117
|
+
Given(:enemy) { 2 }
|
118
|
+
Given(:type) { 11 }
|
119
|
+
Given(:select) { 33 }
|
120
|
+
|
121
|
+
When(:result) { controller.enable_detection(enemy, type, select) }
|
122
|
+
|
123
|
+
Then { at.should have_received(:config).with("detect:enemy_colors", enemy.to_s) }
|
124
|
+
Then { at.should have_received(:config).with("detect:detect_type", type.to_s) }
|
125
|
+
Then { at.should have_received(:config).with("detect:detections_select_h", select.to_s) }
|
126
|
+
end
|
127
|
+
|
128
|
+
context "when setting with only enemy" do
|
129
|
+
Given(:enemy) { 2 }
|
130
|
+
Given(:type) { 10 }
|
131
|
+
Given(:select) { 32 }
|
132
|
+
|
133
|
+
When(:result) { controller.enable_detection(enemy) }
|
134
|
+
|
135
|
+
Then { at.should have_received(:config).with("detect:enemy_colors", enemy.to_s) }
|
136
|
+
Then { at.should have_received(:config).with("detect:detect_type", type.to_s) }
|
137
|
+
Then { at.should have_received(:config).with("detect:detections_select_h", select.to_s) }
|
138
|
+
end
|
139
|
+
|
140
|
+
context "when doing demo mode" do
|
141
|
+
When(:result) { controller.demo_mode }
|
142
|
+
Then { at.should have_received(:config).with("general:navdata_demo", "TRUE") }
|
143
|
+
end
|
144
|
+
|
145
|
+
context "when selecting the forward camera" do
|
146
|
+
When(:result) { controller.front_camera }
|
147
|
+
Then { at.should have_received(:config).with("video:video_channel", "2") }
|
148
|
+
end
|
149
|
+
|
150
|
+
context "when selecting the bottom camera" do
|
151
|
+
When(:result) { controller.bottom_camera }
|
152
|
+
Then { at.should have_received(:config).with("video:video_channel", "1") }
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
describe "reset watchdog command" do
|
158
|
+
When(:result) { controller.reset_watchdog}
|
159
|
+
Then { at.should have_received(:comwdg).with() }
|
160
|
+
end
|
161
|
+
|
162
|
+
describe "ack control mode command" do
|
163
|
+
When(:result) { controller.ack_control_mode }
|
164
|
+
Then { at.should have_received(:ctrl).with(5) }
|
141
165
|
end
|
142
166
|
end
|
143
167
|
|
data/spec/argus/drone_spec.rb
CHANGED
@@ -1,24 +1,53 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'argus'
|
2
3
|
|
3
|
-
|
4
|
-
|
4
|
+
describe Argus::Drone do
|
5
|
+
Given(:controller) { flexmock("controller", :on, Argus::Controller) }
|
6
|
+
Given(:commander) { flexmock("commander", :on, Argus::ATCommander) }
|
7
|
+
Given(:nav_monitor) { flexmock("navmonitor", :on, Argus::NavMonitor) }
|
8
|
+
Given(:drone) {
|
9
|
+
Argus::Drone.new(
|
10
|
+
nav_monitor: nav_monitor,
|
11
|
+
commander: commander,
|
12
|
+
controller: controller)
|
13
|
+
}
|
5
14
|
|
6
|
-
|
7
|
-
Given(:drone) { Drone.new(socket: socket) }
|
15
|
+
Then { drone.commander == commander }
|
8
16
|
|
9
|
-
|
10
|
-
|
11
|
-
|
17
|
+
context "when starting the drone" do
|
18
|
+
When { drone.start }
|
19
|
+
Then { commander.should have_received(:start).once }
|
20
|
+
Then { nav_monitor.should have_received(:start).once }
|
12
21
|
|
13
|
-
|
14
|
-
When { drone.
|
15
|
-
Then {
|
22
|
+
context "and then stopped" do
|
23
|
+
When { drone.stop }
|
24
|
+
Then { controller.should have_received(:land).once }
|
25
|
+
Then { commander.should have_received(:stop).once }
|
26
|
+
Then { commander.should have_received(:join).once }
|
27
|
+
Then { nav_monitor.should have_received(:stop).once }
|
28
|
+
Then { nav_monitor.should have_received(:join).once }
|
16
29
|
end
|
30
|
+
end
|
17
31
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
32
|
+
describe "setting nav callbacks" do
|
33
|
+
When { drone.nav_callback(:a) }
|
34
|
+
Then { nav_monitor.should have_received(:callback).with(:a).once }
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "flight controls" do
|
38
|
+
When { drone.take_off }
|
39
|
+
Then { controller.should have_received(:take_off).once }
|
40
|
+
end
|
41
|
+
|
42
|
+
context "when created normally" do
|
43
|
+
Given { flexmock(Argus::NavMonitor).should_receive(:new => nil) }
|
44
|
+
When { Argus::Drone.new }
|
45
|
+
Then { Argus::NavMonitor.should have_received(:new).with(Argus::Controller, String).once }
|
22
46
|
end
|
23
|
-
end
|
24
47
|
|
48
|
+
context "when NavMonitor is disabled" do
|
49
|
+
Given { flexmock(Argus::NullNavMonitor).should_receive(:new => nil) }
|
50
|
+
When { Argus::Drone.new(enable_nav_monitor: false) }
|
51
|
+
Then { Argus::NullNavMonitor.should have_received(:new).with().once }
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Argus
|
4
|
+
|
5
|
+
describe FlightAnimation do
|
6
|
+
describe ".lookup_name" do
|
7
|
+
Then { FlightAnimation.lookup_name(3) == :theta_30_deg }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe ".lookup_value" do
|
11
|
+
Then { FlightAnimation.lookup_value(:flip_ahead) == 16 }
|
12
|
+
Then { FlightAnimation.lookup_value("flip_ahead") == 16 }
|
13
|
+
Then { FlightAnimation.lookup_value(16) == 16 }
|
14
|
+
Then { FlightAnimation.lookup_value("16") == 16 }
|
15
|
+
|
16
|
+
Then { FlightAnimation.lookup_value(:unknown) == nil }
|
17
|
+
Then { FlightAnimation.lookup_value("UNKNOWN") == nil }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
data/spec/argus/nav_data_spec.rb
CHANGED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'thread'
|
3
|
+
|
4
|
+
describe Argus::NavMonitor do
|
5
|
+
Given(:streamer) { flexmock("streamer", :on, Argus::NavStreamer) }
|
6
|
+
Given(:controller) { flexmock("controller", :on, Argus::Controller) }
|
7
|
+
Given(:nav) {
|
8
|
+
Argus::NavMonitor.new(controller, "localhost", streamer: streamer)
|
9
|
+
}
|
10
|
+
|
11
|
+
context "when the monitor is started" do
|
12
|
+
after do nav.join end
|
13
|
+
When { nav.start; Thread.pass }
|
14
|
+
Then { streamer.should have_received(:start).once }
|
15
|
+
end
|
16
|
+
|
17
|
+
context "when data is received" do
|
18
|
+
Given(:bootstrap) { false }
|
19
|
+
Given(:ack) { false }
|
20
|
+
Given(:nav_options) { [ ] }
|
21
|
+
Given(:nav_data) {
|
22
|
+
flexmock("NavData",
|
23
|
+
:bootstrap? => bootstrap,
|
24
|
+
:control_command_ack? => ack,
|
25
|
+
:options => nav_options)
|
26
|
+
}
|
27
|
+
|
28
|
+
When {
|
29
|
+
capture_io { nav.update_nav_data(nav_data) }
|
30
|
+
}
|
31
|
+
|
32
|
+
context "when typical data is received" do
|
33
|
+
Then { nav.data == nav_data }
|
34
|
+
Then { controller.should have_received(:demo_mode).never }
|
35
|
+
Then { controller.should have_received(:ack_control_mode).never }
|
36
|
+
end
|
37
|
+
|
38
|
+
context "when the bootstrap flag is set" do
|
39
|
+
Given(:bootstrap) { true }
|
40
|
+
Then { controller.should have_received(:demo_mode).once }
|
41
|
+
end
|
42
|
+
|
43
|
+
context "when the control command ack is set" do
|
44
|
+
Given(:ack) { true }
|
45
|
+
Then { controller.should have_received(:ack_control_mode).once }
|
46
|
+
end
|
47
|
+
|
48
|
+
context "with nav option sections" do
|
49
|
+
Given(:opt) { flexmock("option", tag: 0) }
|
50
|
+
Given(:nav_options) { [ opt ] }
|
51
|
+
Then { nav.data == nav_data }
|
52
|
+
Then { nav.option(0) == opt }
|
53
|
+
end
|
54
|
+
|
55
|
+
context "with a callback" do
|
56
|
+
Given { nav.callback { |data| @cb_data = data } }
|
57
|
+
Then { @cb_data == nav_data }
|
58
|
+
end
|
59
|
+
|
60
|
+
context "with a callback with errors" do
|
61
|
+
Given { nav.callback { |data| fail "OUCH" } }
|
62
|
+
Then { captured_out =~ /OUCH/ }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -3,10 +3,6 @@ require 'base64'
|
|
3
3
|
|
4
4
|
module Argus
|
5
5
|
describe NavOptionDemo do
|
6
|
-
def f(float)
|
7
|
-
FloatEncoding.encode_float(float)
|
8
|
-
end
|
9
|
-
|
10
6
|
# NOTE: This is a Base 64 encoded NavData packet recorded directly from the drone.
|
11
7
|
Given(:base64_data) {
|
12
8
|
"iHdmVdAEgA/5iwAAAAAAAAAAlAAAAAIAPAAAAADwREUAgCNFQFEiyAAAAABk" +
|
@@ -28,7 +24,8 @@ module Argus
|
|
28
24
|
When(:demo) { nav_data.options.first }
|
29
25
|
|
30
26
|
Then { ! demo.nil? }
|
31
|
-
Then { demo.tag ==
|
27
|
+
Then { demo.tag == Argus::NavTag::DEMO }
|
28
|
+
Then { demo.size == 148 }
|
32
29
|
|
33
30
|
Then { demo.ctrl_state == 0x20000 }
|
34
31
|
Then { demo.control_state_name == :default }
|
@@ -5,7 +5,7 @@ module Argus
|
|
5
5
|
Given(:remote_host) { '192.168.1.1' }
|
6
6
|
Given(:port) { 5554 }
|
7
7
|
Given(:socket) { flexmock("Socket", send: nil).should_ignore_missing }
|
8
|
-
Given(:streamer) { NavStreamer.new(remote_host: remote_host,
|
8
|
+
Given(:streamer) { NavStreamer.new(remote_host: remote_host, UDPSocket: flexmock(new: socket, disabled_timer: true)) }
|
9
9
|
|
10
10
|
context "after starting" do
|
11
11
|
Given { streamer.start }
|
@@ -23,6 +23,11 @@ module Argus
|
|
23
23
|
When(:nav_data) { streamer.receive_data }
|
24
24
|
Then { nav_data.nil? }
|
25
25
|
end
|
26
|
+
|
27
|
+
context "when receiving and extra start event" do
|
28
|
+
Given { streamer.start }
|
29
|
+
Then { socket.should have_received(:close) }
|
30
|
+
end
|
26
31
|
end
|
27
32
|
|
28
33
|
describe "State Transitions" do
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rspec/given'
|
2
|
+
require 'argus/null_nav_monitor'
|
3
|
+
|
4
|
+
describe Argus::NullNavMonitor do
|
5
|
+
Given(:nav) { Argus::NullNavMonitor.new }
|
6
|
+
|
7
|
+
context "when calling a regular method" do
|
8
|
+
When(:result) { nav.start }
|
9
|
+
Then { result.should_not have_raised }
|
10
|
+
end
|
11
|
+
|
12
|
+
context "when calling a regular method" do
|
13
|
+
When(:result) { nav.callback { } }
|
14
|
+
Then { result.should have_raised(Argus::NullNavMonitor::UsageError) }
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -3,18 +3,31 @@ require 'socket'
|
|
3
3
|
|
4
4
|
describe Argus::UdpSender do
|
5
5
|
Given(:port) { '5500' }
|
6
|
-
Given(:
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
6
|
+
Given(:host) { 'localhost' }
|
7
|
+
|
8
|
+
context "with real socket" do
|
9
|
+
Given(:socket) { UDPSocket.new }
|
10
|
+
Given(:sender) { Argus::UdpSender.new(remote_host: host, port: port) }
|
11
|
+
Given!(:server) {
|
12
|
+
server = UDPSocket.new
|
13
|
+
server.bind(nil, port)
|
14
|
+
Thread.new {
|
15
|
+
@data, _ = server.recvfrom(1000)
|
16
|
+
}
|
17
|
+
}
|
18
|
+
When {
|
19
|
+
sender.send_packet("HI")
|
20
|
+
server.join
|
13
21
|
}
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
22
|
+
Then { @data.should == "HI" }
|
23
|
+
end
|
24
|
+
|
25
|
+
context "with provided socket" do
|
26
|
+
Given(:socket) { flexmock(send: nil) }
|
27
|
+
Given(:sender) { Argus::UdpSender.new(socket: socket, remote_host: host, port: port) }
|
28
|
+
|
29
|
+
When { sender.send_packet("HI") }
|
30
|
+
|
31
|
+
Then { socket.should have_received(:send).with("HI", 0, host, port).once }
|
32
|
+
end
|
20
33
|
end
|
@@ -11,8 +11,7 @@ module Argus
|
|
11
11
|
Then {video_data.envelope.signature == "PaVE"}
|
12
12
|
end
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
14
|
+
# TODO: handle invalid envelope
|
15
|
+
# TODO: handle valid envelope but invalid frame
|
17
16
|
end
|
18
17
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
#!/usr/bin/ruby -wKU
|
2
|
+
require 'simplecov'
|
3
|
+
SimpleCov.start do
|
4
|
+
add_filter "spec/"
|
5
|
+
end
|
2
6
|
|
3
7
|
require 'rspec/given'
|
4
8
|
require 'flexmock'
|
5
|
-
|
6
9
|
require 'argus'
|
7
10
|
require 'support/bytes'
|
11
|
+
require 'support/capture_io'
|
8
12
|
|
9
13
|
RSpec.configure do |config|
|
10
14
|
config.mock_with :flexmock
|
data/spec/support/bytes.rb
CHANGED
@@ -0,0 +1,32 @@
|
|
1
|
+
module CaptureIO
|
2
|
+
def capture_io
|
3
|
+
old_out = $stdout
|
4
|
+
sio_out = StringIO.new
|
5
|
+
$stdout = sio_out
|
6
|
+
|
7
|
+
old_err = $stderr
|
8
|
+
sio_err = StringIO.new
|
9
|
+
$stderr = sio_err
|
10
|
+
|
11
|
+
yield
|
12
|
+
|
13
|
+
ensure
|
14
|
+
$stdout = old_out
|
15
|
+
$stderr = old_err
|
16
|
+
|
17
|
+
captured_out << sio_out.string
|
18
|
+
captured_err << sio_err.string
|
19
|
+
end
|
20
|
+
|
21
|
+
def captured_out
|
22
|
+
@captured_out ||= ""
|
23
|
+
end
|
24
|
+
|
25
|
+
def captured_err
|
26
|
+
@captured_err ||= ""
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
RSpec.configure do |config|
|
31
|
+
config.include CaptureIO
|
32
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hybridgroup-argus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jim Weirich
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2013-
|
13
|
+
date: 2013-10-17 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rspec-given
|
@@ -40,11 +40,13 @@ files:
|
|
40
40
|
- README.md
|
41
41
|
- Rakefile
|
42
42
|
- lib/argus.rb
|
43
|
+
- lib/argus/ardrone_control_modes.rb
|
43
44
|
- lib/argus/at_commander.rb
|
44
45
|
- lib/argus/cad_type.rb
|
45
46
|
- lib/argus/cfields.rb
|
46
47
|
- lib/argus/controller.rb
|
47
48
|
- lib/argus/drone.rb
|
49
|
+
- lib/argus/flight_animation.rb
|
48
50
|
- lib/argus/float_encoding.rb
|
49
51
|
- lib/argus/led_animation.rb
|
50
52
|
- lib/argus/nav_data.rb
|
@@ -56,6 +58,7 @@ files:
|
|
56
58
|
- lib/argus/nav_option_vision_detect.rb
|
57
59
|
- lib/argus/nav_streamer.rb
|
58
60
|
- lib/argus/nav_tag.rb
|
61
|
+
- lib/argus/null_nav_monitor.rb
|
59
62
|
- lib/argus/time_queue.rb
|
60
63
|
- lib/argus/udp_sender.rb
|
61
64
|
- lib/argus/version.rb
|
@@ -64,26 +67,32 @@ files:
|
|
64
67
|
- lib/argus/video_streamer.rb
|
65
68
|
- spec/spec_helper.rb
|
66
69
|
- spec/argus/at_commander_spec.rb
|
70
|
+
- spec/argus/cfields_spec.rb
|
67
71
|
- spec/argus/controller_spec.rb
|
68
72
|
- spec/argus/drone_spec.rb
|
73
|
+
- spec/argus/flight_animation_spec.rb
|
69
74
|
- spec/argus/float_encoding_spec.rb
|
70
75
|
- spec/argus/led_animation_spec.rb
|
71
76
|
- spec/argus/nav_data_spec.rb
|
77
|
+
- spec/argus/nav_monitor_spec.rb
|
72
78
|
- spec/argus/nav_option_checksum_spec.rb
|
73
79
|
- spec/argus/nav_option_demo_spec.rb
|
74
80
|
- spec/argus/nav_option_spec.rb
|
75
81
|
- spec/argus/nav_option_unknown_spec.rb
|
76
82
|
- spec/argus/nav_option_vision_detect_spec.rb
|
77
83
|
- spec/argus/nav_streamer_spec.rb
|
84
|
+
- spec/argus/null_nav_monitor_spec.rb
|
78
85
|
- spec/argus/time_queue_spec.rb
|
79
86
|
- spec/argus/udp_sender_spec.rb
|
80
87
|
- spec/argus/video_data_envelope_spec.rb
|
81
88
|
- spec/argus/video_data_spec.rb
|
82
89
|
- spec/argus/video_streamer_spec.rb
|
83
90
|
- spec/support/bytes.rb
|
91
|
+
- spec/support/capture_io.rb
|
84
92
|
- MIT-LICENSE
|
85
93
|
homepage: http://github.com/jimweirich/argus
|
86
|
-
licenses:
|
94
|
+
licenses:
|
95
|
+
- MIT-LICENSE
|
87
96
|
metadata: {}
|
88
97
|
post_install_message:
|
89
98
|
rdoc_options:
|