hybridgroup-argus 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Jim Weirich
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,27 @@
1
+ # Argus -- Parrot AR Drone Ruby API
2
+
3
+ ## Current Status
4
+
5
+ * Experimental
6
+ * Subject to change
7
+ * Use at your own risk
8
+ * May cause cancer
9
+
10
+ ## Example
11
+
12
+ <pre>
13
+ require 'argus'
14
+
15
+ drone = Argus::Drone.new
16
+ drone.start
17
+
18
+ drone.take_off
19
+ sleep 5
20
+ drone.turn_right(1.0)
21
+ sleep 5
22
+ drone.turn_left(1.0)
23
+ sleep 5
24
+ drone.hover.land
25
+ sleep 5
26
+ drone.stop
27
+ </pre>
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby"
2
+
3
+ require 'rake/clean'
4
+
5
+ task :default => :specs
6
+
7
+ task :specs do
8
+ sh "rspec spec"
9
+ end
@@ -0,0 +1,76 @@
1
+ require 'thread'
2
+
3
+ module Argus
4
+ class ATCommander
5
+ def initialize(sender)
6
+ @sender = sender
7
+ @seq = 0
8
+ @ref_data = "0"
9
+ @pcmd_data = "0,0,0,0,0"
10
+ @buffer = ""
11
+ @thread = nil
12
+ @interval = 0.020
13
+ @mutex = Mutex.new
14
+ end
15
+
16
+ def start
17
+ @running = true
18
+ @thread = Thread.new do
19
+ while @running
20
+ tick
21
+ sleep @interval
22
+ end
23
+ end
24
+ end
25
+
26
+ def tick
27
+ @mutex.synchronize do
28
+ packet do
29
+ command("REF", @ref_data)
30
+ command("PCMD", @pcmd_data)
31
+ end
32
+ end
33
+ end
34
+
35
+ def stop
36
+ @running = false
37
+ end
38
+
39
+ def join
40
+ @thread.join if @thread
41
+ end
42
+
43
+ def interval=(new_interval)
44
+ @mutex.synchronize do @interval = new_interval end
45
+ end
46
+
47
+ def ref(data)
48
+ @mutex.synchronize do @ref_data = data end
49
+ end
50
+
51
+ def pcmd(data)
52
+ @mutex.synchronize do @pcmd_data = data end
53
+ end
54
+
55
+ def config(key, value)
56
+ @buffer << "AT*CONFIG=605,\"#{key}\",\"#{value}\"\r"
57
+ end
58
+
59
+ private
60
+
61
+ def packet
62
+ yield self
63
+ flush
64
+ end
65
+
66
+ def flush
67
+ @sender.send_packet(@buffer)
68
+ @buffer = ""
69
+ end
70
+
71
+ def command(name, args)
72
+ @seq += 1
73
+ @buffer << "AT*#{name}=#{@seq},#{args}\r"
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,130 @@
1
+ module Argus
2
+ class Controller
3
+
4
+ def initialize(at_commander)
5
+ @at_commander = at_commander
6
+
7
+ @emergency = false
8
+ land
9
+ hover
10
+ end
11
+
12
+ def take_off
13
+ @flying = true
14
+ @emergency = false
15
+ update_ref
16
+ end
17
+
18
+ def land
19
+ @flying = false
20
+ update_ref
21
+ end
22
+
23
+ def emergency
24
+ @flying = false
25
+ @emergency = true
26
+ update_ref
27
+ end
28
+
29
+ def hover
30
+ @moving = false
31
+ @roll = 0.0
32
+ @pitch = 0.0
33
+ @gaz = 0.0
34
+ @yaw = 0.0
35
+ update_pcmd
36
+ end
37
+
38
+ def forward(amount)
39
+ @moving = true
40
+ @pitch = -amount
41
+ update_pcmd
42
+ end
43
+
44
+ def backward(amount)
45
+ @moving = true
46
+ @pitch = amount
47
+ update_pcmd
48
+ end
49
+
50
+ def left(amount)
51
+ @moving = true
52
+ @roll = -amount
53
+ update_pcmd
54
+ end
55
+
56
+ def right(amount)
57
+ @moving = true
58
+ @roll = amount
59
+ update_pcmd
60
+ end
61
+
62
+ def up(amount)
63
+ @moving = true
64
+ @gaz = amount
65
+ update_pcmd
66
+ end
67
+
68
+ def down(amount)
69
+ @moving = true
70
+ @gaz = -amount
71
+ update_pcmd
72
+ end
73
+
74
+ def turn_left(amount)
75
+ @moving = true
76
+ @yaw = -amount
77
+ update_pcmd
78
+ end
79
+
80
+ def turn_right(amount)
81
+ @moving = true
82
+ @yaw = amount
83
+ update_pcmd
84
+ end
85
+
86
+ def front_camera
87
+ @at_commander.config("video:video_channel", "2")
88
+ end
89
+
90
+ def bottom_camera
91
+ @at_commander.config("video:video_channel", "1")
92
+ end
93
+
94
+ private
95
+
96
+ REF_BASE = [18, 20, 22, 24, 28].
97
+ inject(0) { |flag, bitnum| flag | (1 << bitnum) }
98
+ REF_FLY_BIT = (1 << 9)
99
+ REF_EMERGENCY_BIT = (1 << 8)
100
+
101
+ def update_ref
102
+ n = REF_BASE
103
+ n |= REF_FLY_BIT if @flying
104
+ n |= REF_EMERGENCY_BIT if @emergency
105
+ @at_commander.ref(n.to_s)
106
+ self
107
+ end
108
+
109
+ def update_pcmd
110
+ flags = 0
111
+ if @moving
112
+ flags = 1
113
+ iroll = encode_float(@roll)
114
+ ipitch = encode_float(@pitch)
115
+ igaz = encode_float(@gaz)
116
+ iyaw = encode_float(@yaw)
117
+ data = "#{flags},#{iroll},#{ipitch},#{igaz},#{iyaw}"
118
+ else
119
+ data = "0,0,0,0,0"
120
+ end
121
+ @at_commander.pcmd(data)
122
+ self
123
+ end
124
+
125
+ def encode_float(float)
126
+ [float].pack('g').unpack("l>").first
127
+ end
128
+
129
+ end
130
+ end
@@ -0,0 +1,36 @@
1
+ require 'socket'
2
+
3
+ module Argus
4
+ class Drone
5
+ def initialize(socket=nil, host='192.168.1.1', port='5556')
6
+ @socket = socket || UDPSocket.new
7
+ @sender = Argus::UdpSender.new(@socket, host, port)
8
+ @at = Argus::ATCommander.new(@sender)
9
+ @controller = Argus::Controller.new(@at)
10
+ end
11
+
12
+ def start
13
+ @at.start
14
+ end
15
+
16
+ def stop
17
+ @controller.land
18
+ @at.stop
19
+ @at.join
20
+ end
21
+
22
+ %w(
23
+ take_off land hover emergency
24
+ forward backward
25
+ left right
26
+ up down
27
+ turn_left turn_right
28
+ front_camera bottom_camera
29
+ ).each do |meth|
30
+ define_method(meth) { |*args|
31
+ @controller.send(meth, *args)
32
+ }
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,61 @@
1
+ module Argus
2
+ class NavData
3
+ attr_accessor :drone_state, :options, :vision_flag, :sequence_number
4
+ def initialize(data)
5
+ @data = data
6
+ parse_nav_data(@data)
7
+ end
8
+
9
+ private
10
+ def parse_nav_data(data)
11
+ state = data.unpack("V").first
12
+ @drone_state = {
13
+ :flying=>state[0], #/*!< FLY MASK : (0) ardrone is landed, (1) ardrone is flying */
14
+ :videoEnabled=>state[1], #/*!< VIDEO MASK : (0) video disable, (1) video enable */
15
+ :visionEnabled=>state[2], #/*!< VISION MASK : (0) vision disable, (1) vision enable */
16
+ :controlAlgorithm=>state[3], #/*!< CONTROL ALGO : (0) euler angles control, (1) angular speed control */
17
+ :altitudeControlAlgorithm=>state[4], #/*!< ALTITUDE CONTROL ALGO : (0) altitude control inactive (1) altitude control active */
18
+ :startButtonState=>state[5], #/*!< USER feedback : Start button state */
19
+ :controlCommandAck=>state[6], #/*!< Control command ACK : (0) None, (1) one received */
20
+ :cameraReady=>state[7], #/*!< CAMERA MASK : (0) camera not ready, (1) Camera ready */
21
+ :travellingEnabled=>state[8], #/*!< Travelling mask : (0) disable, (1) enable */
22
+ :usbReady=>state[9], #/*!< USB key : (0) usb key not ready, (1) usb key ready */
23
+ :navdataDemo=>state[10], #/*!< Navdata demo : (0) All navdata, (1) only navdata demo */
24
+ :navdataBootstrap=>state[11], #/*!< Navdata bootstrap : (0) options sent in all or demo mode, (1) no navdata options sent */
25
+ :motorProblem=>state[12], #/*!< Motors status : (0) Ok, (1) Motors problem */
26
+ :communicationLost=>state[13], #/*!< Communication Lost : (1) com problem, (0) Com is ok */
27
+ :softwareFault=>state[14], #/*!< Software fault detected - user should land as quick as possible (1) */
28
+ :lowBattery=>state[15], #/*!< VBat low : (1) too low, (0) Ok */
29
+ :userEmergencyLanding=>state[16], #/*!< User Emergency Landing : (1) User EL is ON, (0) User EL is OFF*/
30
+ :timerElapsed=>state[17], #/*!< Timer elapsed : (1) elapsed, (0) not elapsed */
31
+ :MagnometerNeedsCalibration=>state[18], #/*!< Magnetometer calibration state : (0) Ok, no calibration needed, (1) not ok, calibration needed */
32
+ :anglesOutOfRange=>state[19], #/*!< Angles : (0) Ok, (1) out of range */
33
+ :tooMuchWind=>state[20], #/*!< WIND MASK: (0) ok, (1) Too much wind */
34
+ :ultrasonicSensorDeaf=>state[21], #/*!< Ultrasonic sensor : (0) Ok, (1) deaf */
35
+ :cutoutDetected=>state[22], #/*!< Cutout system detection : (0) Not detected, (1) detected */
36
+ :picVersionNumberOk=>state[23], #/*!< PIC Version number OK : (0) a bad version number, (1) version number is OK */
37
+ :atCodecThreadOn=>state[24], #/*!< ATCodec thread ON : (0) thread OFF (1) thread ON */
38
+ :navdataThreadOn=>state[25], #/*!< Navdata thread ON : (0) thread OFF (1) thread ON */
39
+ :videoThreadOn=>state[26], #/*!< Video thread ON : (0) thread OFF (1) thread ON */
40
+ :acquisitionThreadOn=>state[27], #/*!< Acquisition thread ON : (0) thread OFF (1) thread ON */
41
+ :controlWatchdogDelay=>state[28], #/*!< CTRL watchdog : (1) delay in control execution (> 5ms), (0) control is well scheduled */
42
+ :adcWatchdogDelay=>state[29], #/*!< ADC Watchdog : (1) delay in uart2 dsr (> 5ms), (0) uart2 is good */
43
+ :comWatchdogProblem=>state[30], #/*!< Communication Watchdog : (1) com problem, (0) Com is ok */
44
+ :emergencyLanding=>state[31] #/*!< Emergency landing : (0) no emergency, (1) emergency */
45
+ }
46
+ data.slice!(0..3)
47
+ @sequence_number = data.unpack("V").first
48
+ data.slice!(0..3)
49
+ @vision_flag = data.unpack("V").first
50
+ @options = []
51
+ option1 = {}
52
+ data.slice!(0..3)
53
+ option1[:id] = data.unpack("v").first
54
+ data.slice!(0..1)
55
+ option1[:size] = data.unpack("v").first
56
+ data.slice!(0..1)
57
+ option1[:data] = data.unpack("V").first
58
+ @options.push(option1)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,18 @@
1
+ require 'socket'
2
+
3
+ module Argus
4
+ class NavStreamer
5
+ def initialize(socket=nil, host='192.168.1.1', port='5554')
6
+ @socket = socket || UDPSocket.new
7
+ @streamer = Argus::UdpNavStreamer.new(@socket, host, port)
8
+ end
9
+
10
+ def start
11
+ @streamer.start_stream
12
+ end
13
+
14
+ def receive_data
15
+ @streamer.receive_packet
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,39 @@
1
+ module Argus
2
+ class PaVEParser
3
+ def initialize(tcp_video_streamer)
4
+ @tcp_video_streamer = tcp_video_streamer
5
+ end
6
+
7
+ def get_frame
8
+ frame = {
9
+ :signature=>(@tcp_video_streamer.read(4)).unpack("A*").first,
10
+ :version=>(@tcp_video_streamer.read(1)).unpack("C").first,
11
+ :video_codec=>(@tcp_video_streamer.read(1)).unpack("C").first,
12
+ :header_size=>(@tcp_video_streamer.read(2)).unpack("v").first,
13
+ :payload_size=>(@tcp_video_streamer.read(4)).unpack("V").first,
14
+ :encoded_stream_width=>(@tcp_video_streamer.read(2)).unpack("v").first,
15
+ :encoded_stream_height=>(@tcp_video_streamer.read(2)).unpack("v").first,
16
+ :display_width=>(@tcp_video_streamer.read(2)).unpack("v").first,
17
+ :display_height=>(@tcp_video_streamer.read(2)).unpack("v").first,
18
+ :frame_number=>(@tcp_video_streamer.read(4)).unpack("V").first,
19
+ :timestamp=>(@tcp_video_streamer.read(4)).unpack("V").first,
20
+ :total_chunks=>(@tcp_video_streamer.read(1)).unpack("C").first,
21
+ :chunk_index=>(@tcp_video_streamer.read(1)).unpack("C").first,
22
+ :frame_type=>(@tcp_video_streamer.read(1)).unpack("C").first,
23
+ :control=>(@tcp_video_streamer.read(1)).unpack("C").first,
24
+ :stream_byte_position_lw=>(@tcp_video_streamer.read(4)).unpack("V").first,
25
+ :stream_byte_position_uw=>(@tcp_video_streamer.read(4)).unpack("V").first,
26
+ :stream_id=>(@tcp_video_streamer.read(2)).unpack("v").first,
27
+ :total_slices=>(@tcp_video_streamer.read(1)).unpack("C").first,
28
+ :slice_index=>(@tcp_video_streamer.read(1)).unpack("C").first,
29
+ :header1_size=>(@tcp_video_streamer.read(1)).unpack("C").first,
30
+ :header2_size=>(@tcp_video_streamer.read(1)).unpack("C").first,
31
+ :reserved[2]=>(@tcp_video_streamer.read(2)).unpack("H*").first,
32
+ :advertised_size=>(@tcp_video_streamer.read(4)).unpack("V").first,
33
+ :reserved[12]=>(@tcp_video_streamer.read(12)).unpack("H*").first
34
+ }
35
+ @tcp_video_streamer.read(4)
36
+ return @tcp_video_streamer.read(frame[:payload_size])
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,20 @@
1
+ require 'socket'
2
+ module Argus
3
+ class TcpVideoStreamer
4
+ def initialize(tcp_socket=nil, host='192.168.1.1', port=5555)
5
+ @tcp_socket = tcp_socket || TCPSocket.new(host, port)
6
+ @host = host
7
+ @port = port
8
+ end
9
+
10
+ def start_stream(udp_socket=nil)
11
+ sock = udp_socket || UDPSocket.new
12
+ sock.send("\x01\x00\x00\x00", 0, @host, @port)
13
+ sock.close
14
+ end
15
+
16
+ def read(n)
17
+ @tcp_socket.read(n)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,24 @@
1
+ module Argus
2
+ class UdpNavStreamer
3
+ def initialize(udp_socket, host='192.168.1.1', port=5554)
4
+ @udp_socket = udp_socket
5
+ @host = host
6
+ @port = port
7
+ @udp_socket.bind("0.0.0.0", port)
8
+ end
9
+
10
+ def start_stream
11
+ @udp_socket.send("\x01\x00\x00\x00", 0, @host, @port)
12
+ end
13
+
14
+ def receive_packet
15
+ data, from = @udp_socket.recvfrom(1024)
16
+ if data.unpack("V").first == "0x55667788".hex
17
+ data.slice!(0..3)
18
+ return NavData.new(data)
19
+ else
20
+ return "Not nav data!"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,13 @@
1
+ module Argus
2
+ class UdpSender
3
+ def initialize(udp_socket, host=nil, port=nil)
4
+ @udp_socket = udp_socket
5
+ @host = host || '192.168.1.1'
6
+ @port = port || 5556
7
+ end
8
+
9
+ def send_packet(data)
10
+ @udp_socket.send(data, 0, @host, @port)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ module Argus
2
+ module Version # :nodoc: all
3
+ NUMBERS = [
4
+ MAJOR = 0,
5
+ MINOR = 2,
6
+ BUILD = 0,
7
+ ]
8
+ end
9
+ VERSION = Version::NUMBERS.join('.')
10
+ end
data/lib/argus.rb ADDED
@@ -0,0 +1,9 @@
1
+ require 'argus/at_commander'
2
+ require 'argus/controller'
3
+ require 'argus/udp_sender'
4
+ require 'argus/udp_nav_streamer'
5
+ require 'argus/nav_data'
6
+ require 'argus/nav_streamer'
7
+ require 'argus/drone'
8
+ require 'argus/tcp_video_streamer'
9
+ require 'argus/pave_parser'
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe Argus::ATCommander do
4
+ Given(:sender) { flexmock(:on, Argus::UdpSender) }
5
+ Given(:cmdr) { Argus::ATCommander.new(sender) }
6
+
7
+ describe "#tick" do
8
+ When { cmdr.send(:tick) }
9
+
10
+ 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/) }
12
+ end
13
+
14
+ context "with a ref command" do
15
+ 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/) }
17
+ end
18
+
19
+ context "with a pcmd command" do
20
+ 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/) }
22
+ end
23
+ end
24
+
25
+ describe "increasing sequence numbers" do
26
+ Given(:seq_numbers) { [ ] }
27
+ Given {
28
+ sender.should_receive(:send_packet).and_return { |data|
29
+ data.scan(%r{=(\d+),}) { |seq|
30
+ seq_numbers << seq.first.to_i }
31
+ }
32
+ }
33
+ When { 2.times { cmdr.tick } }
34
+ Then { seq_numbers.should == [1, 2, 3, 4] }
35
+ end
36
+
37
+ describe "sending thread" do
38
+ Given {
39
+ @count = 0
40
+ sender.should_receive(:send_packet).and_return {
41
+ @count += 1
42
+ cmdr.stop if @count > 5
43
+ }
44
+ }
45
+ When {
46
+ cmdr.start
47
+ cmdr.join
48
+ }
49
+ Then { sender.should have_received(:send_packet) }
50
+ end
51
+
52
+
53
+
54
+ end
@@ -0,0 +1,95 @@
1
+ require 'spec_helper'
2
+
3
+ describe Argus::Controller do
4
+
5
+ REF_BASE = 0x11540000
6
+
7
+ def ref_bits(n=nil)
8
+ if n.nil?
9
+ REF_BASE.to_s
10
+ else
11
+ (REF_BASE | (1 << n)).to_s
12
+ end
13
+ end
14
+
15
+ Given(:at) { flexmock(:on, Argus::ATCommander) }
16
+ Given(:controller) { Argus::Controller.new(at) }
17
+
18
+ context "navigating commands" do
19
+ Invariant { result.should == controller }
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
+ end
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+ require 'socket'
3
+
4
+ describe Argus::UdpSender do
5
+ Given(:port) { 5500 }
6
+ Given(:socket) { UDPSocket.new }
7
+ Given(:sender) { Argus::UdpSender.new(socket, 'localhost', port) }
8
+ Given!(:server) {
9
+ server = UDPSocket.new
10
+ server.bind(nil, port)
11
+ Thread.new {
12
+ @data, _ = server.recvfrom(1000)
13
+ }
14
+ }
15
+ When {
16
+ sender.send_packet("HI")
17
+ server.join
18
+ }
19
+ Then { @data.should == "HI" }
20
+ end
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/ruby -wKU
2
+
3
+ require 'rspec/given'
4
+ require 'flexmock'
5
+
6
+ require 'argus'
7
+
8
+ RSpec.configure do |config|
9
+ config.mock_with :flexmock
10
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hybridgroup-argus
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jim Weirich
9
+ - Ron Evans
10
+ - Adrian Zankich
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+ date: 2013-02-23 00:00:00.000000000 Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: rspec-given
18
+ requirement: !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: '2.1'
24
+ type: :development
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ none: false
28
+ requirements:
29
+ - - ~>
30
+ - !ruby/object:Gem::Version
31
+ version: '2.1'
32
+ description: Argus is a Ruby interface to a Parrot AR Drone quadcopter.Argus is extremely
33
+ experimental at this point. Use at your own risk.
34
+ email:
35
+ - jim.weirich@gmail.com
36
+ - ron dot evans at gmail dot com
37
+ executables: []
38
+ extensions: []
39
+ extra_rdoc_files:
40
+ - README.md
41
+ - MIT-LICENSE
42
+ files:
43
+ - README.md
44
+ - Rakefile
45
+ - lib/argus.rb
46
+ - lib/argus/at_commander.rb
47
+ - lib/argus/controller.rb
48
+ - lib/argus/drone.rb
49
+ - lib/argus/nav_data.rb
50
+ - lib/argus/nav_streamer.rb
51
+ - lib/argus/pave_parser.rb
52
+ - lib/argus/tcp_video_streamer.rb
53
+ - lib/argus/udp_nav_streamer.rb
54
+ - lib/argus/udp_sender.rb
55
+ - lib/argus/version.rb
56
+ - spec/spec_helper.rb
57
+ - spec/argus/at_commander_spec.rb
58
+ - spec/argus/controller_spec.rb
59
+ - spec/argus/udp_sender_spec.rb
60
+ - MIT-LICENSE
61
+ homepage: http://github.com/hybridgroup/argus
62
+ licenses: []
63
+ post_install_message:
64
+ rdoc_options:
65
+ - --line-numbers
66
+ - --show-hash
67
+ - --main
68
+ - README.md
69
+ - --title
70
+ - Argus -- Parrot AR Drone Ruby API
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '1.9'
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '1.0'
85
+ requirements: []
86
+ rubyforge_project: n/a
87
+ rubygems_version: 1.8.23
88
+ signing_key:
89
+ specification_version: 3
90
+ summary: Ruby API for a Parrot AD Drone Quadcopter
91
+ test_files: []