mavlink-log 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -0
- data/lib/mavlink/log.rb +5 -1
- data/lib/mavlink/log/entry.rb +34 -0
- data/lib/mavlink/log/file.rb +16 -41
- data/lib/mavlink/log/header.rb +20 -0
- data/lib/mavlink/log/message.rb +83 -0
- data/lib/mavlink/log/messages/attitude.rb +37 -0
- data/lib/mavlink/log/messages/factory.rb +37 -0
- data/lib/mavlink/log/messages/global_position_int.rb +47 -0
- data/lib/mavlink/log/messages/gps_raw_int.rb +51 -0
- data/lib/mavlink/log/messages/heart_beat.rb +31 -0
- data/lib/mavlink/log/messages/messages.rb +15 -0
- data/lib/mavlink/log/messages/mission_current.rb +11 -0
- data/lib/mavlink/log/messages/nav_controller_output.rb +39 -0
- data/lib/mavlink/log/messages/param_request_list.rb +15 -0
- data/lib/mavlink/log/messages/param_value.rb +27 -0
- data/lib/mavlink/log/messages/raw_imu.rb +43 -0
- data/lib/mavlink/log/messages/rc_channels_raw.rb +47 -0
- data/lib/mavlink/log/messages/request_data_stream.rb +27 -0
- data/lib/mavlink/log/messages/scaled_pressure.rb +19 -0
- data/lib/mavlink/log/messages/servo_output_raw.rb +43 -0
- data/lib/mavlink/log/messages/sys_status.rb +64 -0
- data/lib/mavlink/log/messages/vfr_hud.rb +37 -0
- data/lib/mavlink/log/version.rb +1 -1
- data/spec/file_spec.rb +11 -1
- data/spec/messages/attitude_spec.rb +34 -0
- data/spec/messages/global_position_int_spec.rb +38 -0
- data/spec/messages/gps_raw_int_spec.rb +40 -0
- data/spec/messages/heart_beat_spec.rb +32 -0
- data/spec/messages/param_value_spec.rb +30 -0
- data/spec/messages/raw_imu_spec.rb +40 -0
- data/spec/messages/rc_channels_raw_spec.rb +42 -0
- data/spec/messages/sys_status_spec.rb +46 -0
- data/spec/messages/vfr_hud_spec.rb +32 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/support/shared_examples_for_message.rb +13 -0
- data/spec/support/shared_examples_for_timed_message_micro.rb +9 -0
- data/spec/support/shared_examples_for_timed_message_milli.rb +9 -0
- data/spec/sys_status_spec.rb +0 -0
- metadata +48 -3
- data/lib/mavlink/log/messages.rb +0 -138
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2aa7c3553fcad5fa98c61094e850ed0b23e9e28a
|
4
|
+
data.tar.gz: 95db6b58d4f7c4bf4af1ca0d5c97218dcf385d01
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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/
|
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
|
data/lib/mavlink/log/file.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
33
|
-
|
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
|
-
|
36
|
-
@entries << Entry.new(
|
37
|
-
@messages <<
|
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
|
-
|
41
|
-
|
42
|
-
|
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) /
|
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 /
|
54
|
+
Time.at(@entries.first.time / 1000000.0)
|
57
55
|
end
|
58
56
|
|
59
57
|
def ended_at
|
60
|
-
Time.at(@entries.last.time /
|
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
|