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 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: