hybridgroup-argus 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 43c7894a41a1033f29b7da584853f6652165ed9c
4
- data.tar.gz: 1d8496bc4cb2f4139d62b1e63ddbde9389f9be46
3
+ metadata.gz: 4aa5b03362c2310d0fc0ab4890c0663fecb0f6e1
4
+ data.tar.gz: 66d8edfbc9992de265a7de09b09a2c34b59be643
5
5
  SHA512:
6
- metadata.gz: 3ad023f7f146c1dcd8457734fdeb532f3462439bf24fb1da9872732c05c27d505be576bdd88e0204e5ffac9cdc154e237bda84278fadce24db96d8f4f48496a1
7
- data.tar.gz: f162db2640775556506541e8ca6485a337b55d354bd2edd3705be92120d899830839a19492be7344c764497c94c54a3a03c35e8076927612f346cdfad5aa95a2
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
@@ -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 reset_watchdog
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
@@ -22,7 +22,7 @@ module Argus
22
22
  end
23
23
 
24
24
  def format_string
25
- @format_string ||= "x4"
25
+ @format_string ||= (defined?(initial_format) ? initial_format : "")
26
26
  end
27
27
 
28
28
  def allot(n=1)
@@ -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 emergency
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 = true
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
- @at_commander.config("general:navdata_demo", "TRUE")
130
+ config("general:navdata_demo", "TRUE")
113
131
  end
114
132
 
115
133
  def front_camera
116
- @at_commander.config("video:video_channel", "2")
134
+ config("video:video_channel", "2")
117
135
  end
118
136
 
119
137
  def bottom_camera
120
- @at_commander.config("video:video_channel", "1")
138
+ config("video:video_channel", "1")
121
139
  end
122
140
 
123
141
  def reset_watchdog
124
- @at_commander.reset_watchdog
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, :enable_nav_monitor
7
+ attr_reader :controller, :nav
8
8
 
9
9
  def initialize(opts={})
10
- @host = opts[:remote_host] || '192.168.1.1'
11
- @port = opts[:post] || '5556'
12
- @socket = opts[:socket] || UDPSocket.new
13
- @sender = opts[:sender] || Argus::UdpSender.new(socket: @socket, remote_host: @host, port: @port)
14
- @at = Argus::ATCommander.new(@sender)
15
- @controller = Argus::Controller.new(@at)
16
-
17
- @enable_nav_monitor = false
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
- @enable_nav_monitor = enable_nav_monitor
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 if enable_nav_monitor
37
+ @nav.stop
40
38
 
41
39
  @at.join
42
- @nav.join if enable_nav_monitor
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 emergency
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
@@ -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
@@ -24,6 +24,12 @@ module Argus
24
24
  option = options[tag] || NavOptionUnknown
25
25
  option.new(raw_data)
26
26
  end
27
+
28
+ # Skip the tag and size fields, We've already handled them in the
29
+ # base class.
30
+ def self.initial_format
31
+ "x4"
32
+ end
27
33
  end
28
34
 
29
35
  end
@@ -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[:socket] || UDPSocket
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
- nav_data = NavData.new(data)
54
+ NavData.new(data)
55
55
  else
56
56
  nil
57
57
  end
@@ -0,0 +1,13 @@
1
+ module Argus
2
+
3
+ class NullNavMonitor
4
+ UsageError = Class.new(StandardError)
5
+ def callback(*)
6
+ fail UsageError, "Callbacks are not supported when the NavMonitor is disabled."
7
+ end
8
+ def method_missing(*)
9
+ # Noop
10
+ end
11
+ end
12
+
13
+ end
@@ -1,7 +1,7 @@
1
1
  module Argus
2
2
  class UdpSender
3
3
  def initialize(opts={})
4
- @udp_socket = opts.fetch(:socket)
4
+ @udp_socket = opts[:socket] || UDPSocket.new
5
5
  @host = opts.fetch(:remote_host)
6
6
  @port = opts.fetch(:port, 5556)
7
7
  end
data/lib/argus/version.rb CHANGED
@@ -2,7 +2,7 @@ module Argus
2
2
  module Version # :nodoc: all
3
3
  NUMBERS = [
4
4
  MAJOR = 0,
5
- MINOR = 4,
5
+ MINOR = 5,
6
6
  BUILD = 0,
7
7
  ]
8
8
  end
@@ -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(/AT\*REF=\d+,0.*AT\*PCMD=\d+,0,0,0,0,0/) }
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(/AT\*REF=\d+,512.*AT\*PCMD=\d+,0,0,0,0,0/) }
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(/AT\*REF=\d+,0.*AT\*PCMD=\d+,1,2,3,4,5/) }
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
- context "navigating commands" do
18
+ describe "controller commands" do
19
19
  Invariant { result.should == controller }
20
20
 
21
- context "when taking off" do
22
- When(:result) { controller.take_off }
23
- Then { at.should have_received(:ref).with(ref_bits(9)) }
24
- end
25
-
26
- context "when landing" do
27
- When(:result) { controller.land }
28
- Then { at.should have_received(:ref).with(ref_bits).twice }
29
- end
30
-
31
- context "when emergency" do
32
- Given { controller.take_off }
33
- When(:result) { controller.emergency }
34
- Then { at.should have_received(:ref).with(ref_bits(8)) }
35
- end
36
-
37
- context "when taking off after an emergency" do
38
- Given { controller.emergency }
39
- When(:result) { controller.take_off }
40
- Then { at.should have_received(:ref).with(ref_bits(9)) }
41
- end
42
-
43
- context "when hovering" do
44
- When(:result) { controller.hover }
45
- Then { at.should have_received(:pcmd).with("0,0,0,0,0") }
46
- end
47
-
48
- context "when moving forward" do
49
- When(:result) { controller.forward(0.80) }
50
- Then { at.should have_received(:pcmd).with("1,0,-1085485875,0,0") }
51
- end
52
-
53
- context "when moving backward" do
54
- When(:result) { controller.backward(0.80) }
55
- Then { at.should have_received(:pcmd).with("1,0,1061997773,0,0") }
56
- end
57
-
58
- context "when moving to the left" do
59
- When(:result) { controller.left(0.80) }
60
- Then { at.should have_received(:pcmd).with("1,-1085485875,0,0,0") }
61
- end
62
-
63
- context "when moving to the right" do
64
- When(:result) { controller.right(0.80) }
65
- Then { at.should have_received(:pcmd).with("1,1061997773,0,0,0") }
66
- end
67
-
68
- context "when moving up" do
69
- When(:result) { controller.up(0.80) }
70
- Then { at.should have_received(:pcmd).with("1,0,0,1061997773,0") }
71
- end
72
-
73
- context "when moving down" do
74
- When(:result) { controller.down(0.80) }
75
- Then { at.should have_received(:pcmd).with("1,0,0,-1085485875,0") }
76
- end
77
-
78
- context "when turning left" do
79
- When(:result) { controller.turn_left(0.80) }
80
- Then { at.should have_received(:pcmd).with("1,0,0,0,-1085485875") }
81
- end
82
-
83
- context "when turning right" do
84
- When(:result) { controller.turn_right(0.80) }
85
- Then { at.should have_received(:pcmd).with("1,0,0,0,1061997773") }
86
- end
87
-
88
- context "when executing several directions" do
89
- When(:result) {
90
- controller.forward(1.0).left(0.5).up(0.2).turn_left(0.8)
91
- }
92
- Then { at.should have_received(:pcmd).with("1,-1090519040,-1082130432,1045220557,-1085485875") }
93
- end
94
- end
95
-
96
- describe "led command" do
97
- Invariant { result.should == controller }
98
-
99
- context "when setting with numeric sequence" do
100
- When(:result) { controller.led(3, 2.0, 4) }
101
- Then {
102
- at.should have_received(:config)
103
- .with("leds:leds_anim", "3,1073741824,4")
104
- }
105
- end
106
-
107
- context "when setting with symbolic sequence" do
108
- When(:result) { controller.led(:blink_orange, 2.0, 4) }
109
- Then {
110
- at.should have_received(:config)
111
- .with("leds:leds_anim", "3,1073741824,4")
112
- }
113
- end
114
- end
115
-
116
- describe "enabled detection command" do
117
- Invariant { result.should == controller }
118
-
119
- context "when setting all parameters" do
120
- Given(:enemy) { 2 }
121
- Given(:type) { 11 }
122
- Given(:select) { 33 }
123
-
124
- When(:result) { controller.enable_detection(enemy, type, select) }
125
-
126
- Then { at.should have_received(:config).with("detect:enemy_colors", enemy.to_s) }
127
- Then { at.should have_received(:config).with("detect:detect_type", type.to_s) }
128
- Then { at.should have_received(:config).with("detect:detections_select_h", select.to_s) }
129
- end
130
-
131
- context "when setting with only enemy" do
132
- Given(:enemy) { 2 }
133
- Given(:type) { 10 }
134
- Given(:select) { 32 }
135
-
136
- When(:result) { controller.enable_detection(enemy) }
137
-
138
- Then { at.should have_received(:config).with("detect:enemy_colors", enemy.to_s) }
139
- Then { at.should have_received(:config).with("detect:detect_type", type.to_s) }
140
- Then { at.should have_received(:config).with("detect:detections_select_h", select.to_s) }
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
 
@@ -1,24 +1,53 @@
1
1
  require 'spec_helper'
2
+ require 'argus'
2
3
 
3
- module Argus
4
- describe Drone do
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
- Given(:socket) { flexmock("Socket", send: nil).should_ignore_missing }
7
- Given(:drone) { Drone.new(socket: socket) }
15
+ Then { drone.commander == commander }
8
16
 
9
- describe "default navigation monitor enabled" do
10
- Then { drone.enable_nav_monitor == false }
11
- end
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
- describe "default navigation monitor enabled when started" do
14
- When { drone.start }
15
- Then { drone.enable_nav_monitor == true }
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
- describe "navigation monitor can be disabled when started" do
19
- When { drone.start(false) }
20
- Then { drone.enable_nav_monitor == false }
21
- end
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
@@ -12,6 +12,7 @@ module Argus
12
12
 
13
13
  Then { nav_data.sequence_number == 173064 }
14
14
  Then { nav_data.vision_flag == 0 }
15
+ Then { nav_data.raw == raw_nav_bytes }
15
16
 
16
17
  describe "sequence number" do
17
18
  Given(:seq_num) { 1234 }
@@ -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 == 0 }
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 }
@@ -56,6 +56,7 @@ module Argus
56
56
  Then { d0.y == 20 }
57
57
  Then { d0.width == 30 }
58
58
  Then { d0.height == 40 }
59
+ Then { d0.distance == 50 }
59
60
  Then { d0.orientation_angle == 60.0 }
60
61
  Then { d0.camera_source == 70 }
61
62
  end
@@ -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, socket: flexmock(new: socket)) }
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(:socket) { UDPSocket.new }
7
- Given(:sender) { Argus::UdpSender.new(socket: socket, remote_host: 'localhost', port: port) }
8
- Given!(:server) {
9
- server = UDPSocket.new
10
- server.bind(nil, port)
11
- Thread.new {
12
- @data, _ = server.recvfrom(1000)
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
- When {
16
- sender.send_packet("HI")
17
- server.join
18
- }
19
- Then { @data.should == "HI" }
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
@@ -21,6 +21,6 @@ module Argus
21
21
  Then { video_data_envelope.payload_size == 2048 }
22
22
  end
23
23
 
24
- pending "TODO: handle invalid envelope"
24
+ # TODO: handle invalid envelope
25
25
  end
26
26
  end
@@ -11,8 +11,7 @@ module Argus
11
11
  Then {video_data.envelope.signature == "PaVE"}
12
12
  end
13
13
 
14
- pending "TODO: handle invalid envelope"
15
- pending "TODO: handle valid envelope but invalid frame"
16
-
14
+ # TODO: handle invalid envelope
15
+ # TODO: handle valid envelope but invalid frame
17
16
  end
18
17
  end
@@ -12,5 +12,10 @@ module Argus
12
12
  Then { udp_socket.should have_received(:close) }
13
13
  end
14
14
 
15
+ describe "receiving data" do
16
+ Given { streamer.start(udp_socket) }
17
+ When(:result) { streamer.receive_data }
18
+ Then { result.is_a?(VideoData) }
19
+ end
15
20
  end
16
21
  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
@@ -9,6 +9,10 @@ module Bytes
9
9
  [n].pack("V").unpack("C*")
10
10
  end
11
11
 
12
+ def float32(f)
13
+ [f].pack("e").unpack("C*")
14
+ end
15
+
12
16
  def make_nav_data(*options)
13
17
  result = options.flatten
14
18
  add_checksum(result)
@@ -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.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-08-20 00:00:00.000000000 Z
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: