mavlink-log 0.0.1 → 0.0.2

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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -0
  3. data/lib/mavlink/log.rb +5 -1
  4. data/lib/mavlink/log/entry.rb +34 -0
  5. data/lib/mavlink/log/file.rb +16 -41
  6. data/lib/mavlink/log/header.rb +20 -0
  7. data/lib/mavlink/log/message.rb +83 -0
  8. data/lib/mavlink/log/messages/attitude.rb +37 -0
  9. data/lib/mavlink/log/messages/factory.rb +37 -0
  10. data/lib/mavlink/log/messages/global_position_int.rb +47 -0
  11. data/lib/mavlink/log/messages/gps_raw_int.rb +51 -0
  12. data/lib/mavlink/log/messages/heart_beat.rb +31 -0
  13. data/lib/mavlink/log/messages/messages.rb +15 -0
  14. data/lib/mavlink/log/messages/mission_current.rb +11 -0
  15. data/lib/mavlink/log/messages/nav_controller_output.rb +39 -0
  16. data/lib/mavlink/log/messages/param_request_list.rb +15 -0
  17. data/lib/mavlink/log/messages/param_value.rb +27 -0
  18. data/lib/mavlink/log/messages/raw_imu.rb +43 -0
  19. data/lib/mavlink/log/messages/rc_channels_raw.rb +47 -0
  20. data/lib/mavlink/log/messages/request_data_stream.rb +27 -0
  21. data/lib/mavlink/log/messages/scaled_pressure.rb +19 -0
  22. data/lib/mavlink/log/messages/servo_output_raw.rb +43 -0
  23. data/lib/mavlink/log/messages/sys_status.rb +64 -0
  24. data/lib/mavlink/log/messages/vfr_hud.rb +37 -0
  25. data/lib/mavlink/log/version.rb +1 -1
  26. data/spec/file_spec.rb +11 -1
  27. data/spec/messages/attitude_spec.rb +34 -0
  28. data/spec/messages/global_position_int_spec.rb +38 -0
  29. data/spec/messages/gps_raw_int_spec.rb +40 -0
  30. data/spec/messages/heart_beat_spec.rb +32 -0
  31. data/spec/messages/param_value_spec.rb +30 -0
  32. data/spec/messages/raw_imu_spec.rb +40 -0
  33. data/spec/messages/rc_channels_raw_spec.rb +42 -0
  34. data/spec/messages/sys_status_spec.rb +46 -0
  35. data/spec/messages/vfr_hud_spec.rb +32 -0
  36. data/spec/spec_helper.rb +2 -0
  37. data/spec/support/shared_examples_for_message.rb +13 -0
  38. data/spec/support/shared_examples_for_timed_message_micro.rb +9 -0
  39. data/spec/support/shared_examples_for_timed_message_milli.rb +9 -0
  40. data/spec/sys_status_spec.rb +0 -0
  41. metadata +48 -3
  42. data/lib/mavlink/log/messages.rb +0 -138
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 51dc07848518c662316fb0655bcc8dc6f7bf584e
4
- data.tar.gz: 0f254b7f8f4621d34d4e1f78407fd5b1eb930d40
3
+ metadata.gz: 2aa7c3553fcad5fa98c61094e850ed0b23e9e28a
4
+ data.tar.gz: 95db6b58d4f7c4bf4af1ca0d5c97218dcf385d01
5
5
  SHA512:
6
- metadata.gz: 6321f5e5a88846fc4e5c9773972adb8a04dc7c66ee0604ea93277b1b61c572bb3750be827058da316904ba2ca722e61ed8e31ae26ad558b283079d73c23b52b9
7
- data.tar.gz: 885eabbb7e06f53342f55d810e9cd0d6bd142aa15102e31217bce0561619895488861d05e99c9466eb4c9d37c2b6e05500b9552bd5aff7d899bf094f4e3f83eb
6
+ metadata.gz: d2f934aed5b2e6c68f31cec773efe744ded1bf7d0b21497e3e3ddf57a236ad1bacccc86b16e8541a0146050716bd883e8ea14fba02651dcdeebb1fa7c5319896
7
+ data.tar.gz: dc241610e2b09e2dc5e32e1d90898ec026dd0986034a3326097d482ece1ebf1b6dd924865f676c5f5aea13be6e3b220b25f0e6b6a5a9583a58332c9ccafc55b5
data/README.md CHANGED
@@ -7,6 +7,7 @@ Information:
7
7
  * mavlink github: https://github.com/mavlink/mavlink
8
8
  * Spec: https://pixhawk.ethz.ch/mavlink
9
9
  * Common message definitions: https://github.com/mavlink/mavlink/blob/master/message_definitions/v1.0/common.xml
10
+ * Packet Decoding: http://eastbay-rc.blogspot.com/2013/04/mavlink-protocol-notes-packet-decoding.html
10
11
 
11
12
  ## Installation
12
13
 
data/lib/mavlink/log.rb CHANGED
@@ -1,3 +1,7 @@
1
+ require "mavlink/log/entry"
1
2
  require "mavlink/log/file"
2
- require "mavlink/log/messages"
3
+ require "mavlink/log/header"
4
+ require "mavlink/log/message"
5
+ require "mavlink/log/messages/factory"
6
+ require "mavlink/log/messages/messages"
3
7
  require "mavlink/log/version"
@@ -0,0 +1,34 @@
1
+ module MAVLink
2
+ module Log
3
+
4
+ class Entry
5
+
6
+ attr_reader :time, :header, :payload, :crc
7
+
8
+ def initialize(raw_time, header, payload, raw_crc)
9
+ @time = to_time(raw_time)
10
+ @header = header
11
+ @payload = payload
12
+ @crc = to_crc(raw_crc)
13
+
14
+ if false && header.id==22
15
+ puts raw_time.unpack('H*')
16
+ puts payload.unpack("H*")
17
+ puts raw_crc.unpack('H*')
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def to_time(raw)
24
+ (raw[0..3].unpack('L>')[0] << 32) | raw[4..7].unpack('L>')[0]
25
+ end
26
+
27
+ def to_crc(raw)
28
+ raw.unpack('S>')[0]
29
+ end
30
+
31
+ end
32
+
33
+ end
34
+ end
@@ -3,15 +3,9 @@ require 'open-uri'
3
3
  module MAVLink
4
4
  module Log
5
5
 
6
- USEC_PER_SEC = 1000000.0
7
-
8
- Header = Struct.new(:magic, :length, :sequence, :system, :component, :id)
9
-
10
- Entry = Struct.new(:time, :header, :payload, :crc)
11
-
12
6
  class File
13
7
 
14
- attr_accessor :entries, :messages
8
+ attr_reader :entries, :messages
15
9
 
16
10
  # Determines if the file at the given URI is a MAVLink telemetry log file.
17
11
  #
@@ -29,17 +23,21 @@ module MAVLink
29
23
  raw_time = file.read(8)
30
24
  break if raw_time.nil?
31
25
 
32
- time = to_time(raw_time)
33
- header = to_header(file.read(6))
26
+ header = Header.new(file.read(6))
27
+ raise "Unexpected magic number (#{header.magic})" unless header.magic == 0xFE
28
+
34
29
  payload = file.read(header.length)
35
- crc = file.read(2).unpack('S>')[0]
36
- @entries << Entry.new(time, header, payload, crc)
37
- @messages << MessageFactory.build(@entries.last)
30
+ raw_crc = file.read(2)
31
+ @entries << Entry.new(raw_time, header, payload, raw_crc)
32
+ @messages << Messages::Factory.build(@entries.last)
38
33
  end
39
34
  end
40
- #@messages.each do |e|
41
- # puts e.inspect
42
- #end
35
+
36
+ if @entries.empty?
37
+ raise 'No entries found in file'
38
+ end
39
+
40
+ #puts @messages.inspect
43
41
  rescue => e
44
42
  raise ArgumentError, "File does not appear to be an MAVLink log (#{e})"
45
43
  end
@@ -49,38 +47,15 @@ module MAVLink
49
47
  # @return [Float] duration of the session, in seconds
50
48
  def duration
51
49
  return 0 if @entries.empty?
52
- (@entries.last.time - @entries.first.time) / USEC_PER_SEC
50
+ (@entries.last.time - @entries.first.time) / 1000000.0
53
51
  end
54
52
 
55
53
  def started_at
56
- Time.at(@entries.first.time / USEC_PER_SEC)
54
+ Time.at(@entries.first.time / 1000000.0)
57
55
  end
58
56
 
59
57
  def ended_at
60
- Time.at(@entries.last.time / USEC_PER_SEC)
61
- end
62
-
63
- # Determines if KML methods can be called for this file.
64
- #
65
- # @return [Boolean] true if KML can be generated for this file, false otherwise
66
- def to_kml?
67
- @entries.any? { |e| e.header.id == GlobalPositionInt::ID }
68
- end
69
-
70
- private
71
-
72
- def to_time(raw_time)
73
- (raw_time[0..3].unpack('L>')[0] << 32) | raw_time[4..7].unpack('L>')[0]
74
- end
75
-
76
- def to_header(raw_header)
77
- magic = raw_header[0].unpack('C')[0]
78
- length = raw_header[1].unpack('C')[0]
79
- sequence = raw_header[2].unpack('C')[0]
80
- system = raw_header[3].unpack('C')[0]
81
- component = raw_header[4].unpack('C')[0]
82
- id = raw_header[5].unpack('C')[0]
83
- Header.new(magic, length, sequence, system, component, id)
58
+ Time.at(@entries.last.time / 1000000.0)
84
59
  end
85
60
 
86
61
  end
@@ -0,0 +1,20 @@
1
+ module MAVLink
2
+ module Log
3
+
4
+ class Header
5
+
6
+ attr_reader :magic, :length, :sequence, :system, :component, :id
7
+
8
+ def initialize(raw_header)
9
+ @magic = raw_header[0].unpack('C')[0]
10
+ @length = raw_header[1].unpack('C')[0]
11
+ @sequence = raw_header[2].unpack('C')[0]
12
+ @system = raw_header[3].unpack('C')[0]
13
+ @component = raw_header[4].unpack('C')[0]
14
+ @id = raw_header[5].unpack('C')[0]
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,83 @@
1
+ module MAVLink; module Log
2
+
3
+ class Message
4
+
5
+ def initialize(entry)
6
+ @entry = entry
7
+ end
8
+
9
+ def id
10
+ @entry.header.id
11
+ end
12
+
13
+ def crc
14
+ @entry.crc
15
+ end
16
+
17
+ protected
18
+
19
+ def float(range)
20
+ unpack(range, 'e')
21
+ end
22
+
23
+ def int8_t(range)
24
+ unpack(range, 'c')
25
+ end
26
+
27
+ def uint8_t(range)
28
+ unpack(range, 'C')
29
+ end
30
+
31
+ def int16_t(range)
32
+ unpack(range, 's<')
33
+ end
34
+
35
+ def uint16_t(range)
36
+ unpack(range, 'S<')
37
+ end
38
+
39
+ def int32_t(range)
40
+ unpack(range, 'l<')
41
+ end
42
+
43
+ def uint32_t(range)
44
+ unpack(range, 'L<')
45
+ end
46
+
47
+ def uint64_t(range)
48
+ unpack(range, 'Q<')
49
+ end
50
+
51
+ def string(range)
52
+ unpack(range, 'Z*')
53
+ end
54
+
55
+ private
56
+
57
+ def payload
58
+ @entry.payload
59
+ end
60
+
61
+ def unpack(range, format, index = 0)
62
+ payload[range].unpack(format)[index]
63
+ end
64
+
65
+ end
66
+
67
+ class TimedMessageMilli < Message
68
+
69
+ def time_boot_ms
70
+ @time_boot_ms ||= uint32_t(0..3)
71
+ end
72
+
73
+ end
74
+
75
+ class TimedMessageMicro < Message
76
+
77
+ def time_usec
78
+ @time_usec ||= uint64_t(0..7)
79
+ end
80
+
81
+ end
82
+
83
+ end; end
@@ -0,0 +1,37 @@
1
+ module MAVLink; module Log; module Messages
2
+
3
+ class Attitude < TimedMessageMilli
4
+
5
+ # radians (-pi..pi)
6
+ def roll
7
+ @roll ||= float(0..3)
8
+ end
9
+
10
+ # radians (-pi..pi)
11
+ def pitch
12
+ @pitch ||= float(4..7)
13
+ end
14
+
15
+ # radians (-pi..pi)
16
+ def yaw
17
+ @yaw ||= float(8..11)
18
+ end
19
+
20
+ # rad/s
21
+ def rollspeed
22
+ @rollspeed ||= float(12..15)
23
+ end
24
+
25
+ # rad/s
26
+ def pitchspeed
27
+ @pitchspeed ||= float(16..19)
28
+ end
29
+
30
+ # rad/s
31
+ def yawspeed
32
+ @yawspeed ||= float(20..23)
33
+ end
34
+
35
+ end
36
+
37
+ end; end; end
@@ -0,0 +1,37 @@
1
+ module MAVLink; module Log; module Messages
2
+
3
+ class Dummy
4
+ def initialize(entry)
5
+ #puts entry.header.inspect
6
+ end
7
+ end
8
+
9
+ class Factory
10
+
11
+ def self.build(entry)
12
+ case(entry.header.id)
13
+ when 0; HeartBeat.new(entry)
14
+ when 1; SysStatus.new(entry)
15
+ when 21; ParamRequestList.new(entry)
16
+ when 22; ParamValue.new(entry)
17
+ when 24; GpsRawInt.new(entry)
18
+ when 27; RawImu.new(entry)
19
+ when 29; ScaledPressure.new(entry)
20
+ when 30; Attitude.new(entry)
21
+ when 33; GlobalPositionInt.new(entry)
22
+ when 35; RcChannelsRaw.new(entry)
23
+ when 36; ServoOutputRaw.new(entry)
24
+ when 42; MissionCurrent.new(entry)
25
+ when 62; NavControllerOutput.new(entry)
26
+ when 66; RequestDataStream.new(entry)
27
+ when 74; VfrHud.new(entry)
28
+ when 150..240; Dummy.new(entry)
29
+ else
30
+ puts entry.header.inspect
31
+ nil
32
+ end
33
+ end
34
+
35
+ end
36
+
37
+ end; end; end
@@ -0,0 +1,47 @@
1
+ module MAVLink; module Log; module Messages
2
+
3
+ class GlobalPositionInt < TimedMessageMilli
4
+
5
+ # dec. degrees
6
+ def lat
7
+ @lat ||= (int32_t(4..7) / 10000000.0)
8
+ end
9
+
10
+ # dec. degrees
11
+ def lon
12
+ @lon ||= (int32_t(8..11) / 10000000.0)
13
+ end
14
+
15
+ # meters
16
+ def alt
17
+ @alt ||= (int32_t(12..15) / 1000.0)
18
+ end
19
+
20
+ # meters
21
+ def relative_alt
22
+ @relative_alt ||= (int32_t(16..19) / 1000.0)
23
+ end
24
+
25
+ # m/s
26
+ def vx
27
+ @vx ||= (int16_t(20..21) / 100.0)
28
+ end
29
+
30
+ # m/s
31
+ def vy
32
+ @vy ||= (int16_t(22..23) / 100.0)
33
+ end
34
+
35
+ # m/s
36
+ def vz
37
+ @vz ||= (int16_t(24..25) / 100.0)
38
+ end
39
+
40
+ # degrees (0.0..359.99) (0xFFFF if unknown)
41
+ def hdg
42
+ @hdg ||= (uint16_t(26..27) / 100.0)
43
+ end
44
+
45
+ end
46
+
47
+ end; end; end
@@ -0,0 +1,51 @@
1
+ module MAVLink; module Log; module Messages
2
+
3
+ class GpsRawInt < TimedMessageMicro
4
+
5
+ # WGS84 dec. degrees
6
+ def lat
7
+ @lat ||= (int32_t(8..11) / 10000000.0)
8
+ end
9
+
10
+ # WGS84 dec. degrees
11
+ def lon
12
+ @lon ||= (int32_t(12..15) / 10000000.0)
13
+ end
14
+
15
+ # meters
16
+ def alt
17
+ @alt ||= (int32_t(16..19) / 1000.0)
18
+ end
19
+
20
+ # meters
21
+ def eph
22
+ @eph ||= (uint16_t(20..21) / 100.0)
23
+ end
24
+
25
+ # meters
26
+ def epv
27
+ @epv ||= (uint16_t(22..23) / 100.0)
28
+ end
29
+
30
+ # m/s
31
+ def vel
32
+ @vel ||= (uint16_t(24..25) / 100.0)
33
+ end
34
+
35
+ # degrees 0..359.99
36
+ def cog
37
+ @cog ||= (uint16_t(26..27) / 100.0)
38
+ end
39
+
40
+ # 0-1: no fix, 2: 2D fix, 3: 3D fix
41
+ def fix_type
42
+ @fix_type ||= uint8_t(28)
43
+ end
44
+
45
+ def satellites_visible
46
+ @satellites_visible ||= uint8_t(29)
47
+ end
48
+
49
+ end
50
+
51
+ end; end; end
@@ -0,0 +1,31 @@
1
+ module MAVLink; module Log; module Messages
2
+
3
+ class HeartBeat < Message
4
+
5
+ def type
6
+ @type ||= uint8_t(0)
7
+ end
8
+
9
+ def autopilot
10
+ @autopilot ||= uint8_t(1)
11
+ end
12
+
13
+ def base_mode
14
+ @base_mode ||= uint8_t(2)
15
+ end
16
+
17
+ def custom_mode
18
+ @custom_mode ||= uint32_t(3..6)
19
+ end
20
+
21
+ def system_status
22
+ @system_status ||= uint8_t(7)
23
+ end
24
+
25
+ def mavlink_version
26
+ @mavlink_version ||= uint8_t(8)
27
+ end
28
+
29
+ end
30
+
31
+ end; end; end