【IT168技术】现在GPS应用必须足以在商业环境如汽车导航中使用,此外,该如何解释GPS数据的实际工作过程,在这三个部分组成的系列,我将介绍两个主题,在大多数行业工程有GPS设备的今天,增加你编写一个商业级GPS应用的技巧。
一个强大的语句
这系列中的第一部分的任务将探讨解析原始GPS数据。幸运的是,任务是简化国家海洋电子协会由于它采用了一种行业标准,现在使用绝大多数的GPS设备。为了给开发人员提供一个良好的开端,我选择使用一些Visual Studio。NET源代码来自我的“GPS.NET全球定位SDK的”组件。 (代码被剥离,如多线程和错误处理功能。)
NMEA数据发送以逗号分隔的“句子”,其中载有关于这句话的第一个字的信息。有超过50多种的句子,但翻译完成这项工作真只需要处理其中的一些。所有最常见的NMEA语句是一句是“Recommended Minimum”这一句,以“$GPRMC开头”。下面是一个例子:
代码:
这一个句子包含几乎所有的GPS应用程序需要:纬度,经度,速度,轴承,卫星获取的时间,固定的地位和磁性的变化。
解析器的核心
做NMEA翻译的第一步是写一个方法来做这两件事情:将每一句分离成单个字、审议第一个字,找出哪些信息是可以进一步提取。列表1-1显示了翻译类的开始。
代码片段:
2
3 '** Listing 1-1. The core of an NMEA interpreter
4
5 '*******************************************************
6
7 Public Class NmeaInterpreter
8 ' Processes information from the GPS receiver
9 Public Function Parse(ByVal sentence As String) As Boolean
10 ' Divide the sentence into words
11 Dim Words() As String = GetWords(sentence)
12 ' Look at the first word to decide where to go next
13 Select Case Words(0)
14 Case "$GPRMC" ' A "Recommended Minimum" sentence was found!
15 ' Indicate that the sentence was recognized
16 Return True
17 Case Else
18 ' Indicate that the sentence was not recognized
19 Return False
20 End Select
21 End Function
22 ' Divides a sentence into individual words
23 Public Function GetWords(ByVal sentence As String) As String()
24 Return sentence.Split(","c)
25 End Function
26 End Class
27
下一步是执行实际信息的提取,首先是经度和纬度。纬度和经度以“DDD°MM’SS.S”的形式存储,其中D代表小时(也称为“度”),M代表分钟,S代表秒。坐标可以在速记上显示,如“DD°MM.M’” 甚至是 “DD°”。这句话的第四个单词“3939.7”,显示了当前的纬度为小时和分钟(39 ° 39.7')。前两个字符(39)代表小时,这个词其余部分(39.7)代表分钟。经度和纬度有相同的结构方式,除了前三个字符代表小时(105 ° 06.6')。关键词5和7表明“半球”,其中“N”是指“北”,“W”是指“西”等。半球附加到数字的末尾部分,做一个完整的测量。我发现 NMEA解析器 正像是事件驱动一样更容易协作。这是因为数据的到达没有特定的顺序。事件驱动类给应用程序的解析器最大的灵活性和响应能力。因此,我将设计解析器用来报告信息使用事件。第一个事件,PositionReceived,将会被凸起 只要目前的经度和纬度被收到。列表1-2扩大解析器用以记录目前的情况。
代码片段:
2
3 '** Listing 1-2. Extracting information from a sentence
4
5 '*******************************************************
6
7 Public Class NmeaInterpreter
8 ' Raised when the current location has changed
9 Public Event PositionReceived(ByVal latitude As String, _
10 ByVal longitude As String)
11 ' Processes information from the GPS receiver
12 Public Function Parse(ByVal sentence As String) As Boolean
13 ' Look at the first word to decide where to go next
14 Select Case GetWords(sentence)(0)
15 Case "$GPRMC" ' A "Recommended Minimum" sentence was found!
16 Return ParseGPRMC(sentence)
17 Case Else
18 ' Indicate that the sentence was not recognized
19 Return False
20 End Select
21 End Function
22 ' Divides a sentence into individual words
23 Public Function GetWords(ByVal sentence As String) As String()
24 Return sentence.Split(","c)
25 End Function
26 ' Interprets a $GPRMC message
27 Public Function ParseGPRMC(ByVal sentence As String) As Boolean
28 ' Divide the sentence into words
29 Dim Words() As String = GetWords(sentence)
30 ' Do we have enough values to describe our location?
31 If Words(3) <> "" And Words(4) <> "" And Words(5) <> "" And _
32 Words(6) <> "" Then
33 ' Yes. Extract latitude and longitude
34 Dim Latitude As String = Words(3).Substring(0, 2) & "°" ' Append hours
35 Latitude = Latitude & Words(3).Substring(2) & """" ' Append minutes
36 Latitude = Latitude & Words(4) ' Append the hemisphere
37 Dim Longitude As String = Words(5).Substring(0, 3) & "°" ' Append hours
38 Longitude = Longitude & Words(5).Substring(3) & """" ' Append minutes
39 Longitude = Longitude & Words(6) ' Append the hemisphere
40 ' Notify the calling application of the change
41 RaiseEvent PositionReceived(Latitude, Longitude)
42 End If
43 ' Indicate that the sentence was recognized
44 Return True
45 End Function
46 End Class
47
这里值得注意的一个地方就是在没有获取到信息时,某些GPS设备将记录空值。因此,一个好主意就是在解析之前来测试每个单词的值。如果您需要输入度数符号(°),按住Alt键并键入数字键盘上的“0176”。
取出垃圾
校验和以美元符号和星号(但不包括)之间的XOR字节来计算。这个校验和然后与语句中的校验和进行比较。如果校验和不匹配,这句话通常被丢弃。这是正常的,因为这样做GPS设备往往每隔几秒钟重复相同的信息。有比较校验和的能力,解析器能够抛出任何带有无效的校验和的语句。列表1-3扩大解析器:
代码片段:
2
3 '** Listing 1-3. Detecting and handling NMEA errors
4
5 '*******************************************************
6
7 Public Class NmeaInterpreter
8 ' Raised when the current location has changed
9 Public Event PositionReceived(ByVal latitude As String, _
10 ByVal longitude As String)
11 ' Processes information from the GPS receiver
12 Public Function Parse(ByVal sentence As String) As Boolean
13 ' Discard the sentence if its checksum does not match our calculated
14 'checksum
15 If Not IsValid(sentence) Then Return False
16 ' Look at the first word to decide where to go next
17 Select Case GetWords(sentence)(0)
18 Case "$GPRMC" ' A "Recommended Minimum" sentence was found!
19 Return ParseGPRMC(sentence)
20 Case Else
21 ' Indicate that the sentence was not recognized
22 Return False
23 End Select
24 End Function
25 ' Divides a sentence into individual words
26 Public Function GetWords(ByVal sentence As String) As String()
27 Return sentence.Split(","c)
28 End Function
29 ' Interprets a $GPRMC message
30 Public Function ParseGPRMC(ByVal sentence As String) As Boolean
31 ' Divide the sentence into words
32 Dim Words() As String = GetWords(sentence)
33 ' Do we have enough values to describe our location?
34 If Words(3) <> "" And Words(4) <> "" And Words(5) <> "" And _
35 Words(6) <> "" Then
36 ' Yes. Extract latitude and longitude
37 Dim Latitude As String = Words(3).Substring(0, 2) & "°" ' Append hours
38 Latitude = Latitude & Words(3).Substring(2) & """" ' Append minutes
39 Latitude = Latitude & Words(4) ' Append the hemisphere
40 Dim Longitude As String = Words(5).Substring(0, 3) & "°" ' Append hours
41 Longitude = Longitude & Words(5).Substring(3) & """" ' Append minutes
42 Longitude = Longitude & Words(6) ' Append the hemisphere
43 ' Notify the calling application of the change
44 RaiseEvent PositionReceived(Latitude, Longitude)
45 End If
46 ' Indicate that the sentence was recognized
47 Return True
48 End Function
49 ' Returns True if a sentence's checksum matches the calculated checksum
50 Public Function IsValid(ByVal sentence As String) As Boolean
51 ' Compare the characters after the asterisk to the calculation
52 Return sentence.Substring(sentence.IndexOf("*") + 1) = GetChecksum(sentence)
53 End Function
54 ' Calculates the checksum for a sentence
55 Public Function GetChecksum(ByVal sentence As String) As String
56 ' Loop through all chars to get a checksum
57 Dim Character As Char
58 Dim Checksum As Integer
59 For Each Character In sentence
60 Select Case Character
61 Case "$"c
62 ' Ignore the dollar sign
63 Case "*"c
64 ' Stop processing before the asterisk
65 Exit For
66 Case Else
67 ' Is this the first value for the checksum?
68 If Checksum = 0 Then
69 ' Yes. Set the checksum to the value
70 Checksum = Convert.ToByte(Character)
71 Else
72 ' No. XOR the checksum with this character's value
73 Checksum = Checksum Xor Convert.ToByte(Character)
74 End If
75 End Select
76 Next
77 ' Return the checksum formatted as a two-character hexadecimal
78 Return Checksum.ToString("X2")
79 End Function
80 End Class
81
无线原子时
时间是GPS技术的基石,因为距离以光速来测量。每个GPS卫星载有4个原子钟,它用来测定几纳秒内的无线传输。一个有趣的特点是只需几行代码,这些原子钟可用于同步电脑毫秒级精确度的时钟。$GPRMC语句的第二字,“040302.663”,以压缩格式包含卫星导出的时间。前两个字符代表时,紧接着两个字符代表分钟,再接着两个代表秒,小数点后的一切代表毫秒。因此,时间是上午4:03:02.663。然而,卫星报告的时间为通用时间(GMT +0),所以时间必须适应当地的时区。列表1-4增加了对卫星导出时间的支持,并使用DateTime.ToLocalTime方法将卫星时间转换为本地时区。
代码片段:
2
3 '** Listing 1-4. Add support for satellite-derived time
4
5 '********************************************************
6
7 Public Class NmeaInterpreter
8 ' Raised when the current location has changed
9 Public Event PositionReceived(ByVal latitude As String, _
10 ByVal longitude As String)
11 Public Event DateTimeChanged(ByVal dateTime As DateTime)
12 ' Processes information from the GPS receiver
13 Public Function Parse(ByVal sentence As String) As Boolean
14 ' Discard the sentence if its checksum does not match our
15 ' calculated checksum
16 If Not IsValid(sentence) Then Return False
17 ' Look at the first word to decide where to go next
18 Select Case GetWords(sentence)(0)
19 Case "$GPRMC" ' A "Recommended Minimum" sentence was found!
20 Return ParseGPRMC(sentence)
21 Case Else
22 ' Indicate that the sentence was not recognized
23 Return False
24 End Select
25 End Function
26 ' Divides a sentence into individual words
27 Public Function GetWords(ByVal sentence As String) As String()
28 Return sentence.Split(","c)
29 End Function
30 ' Interprets a $GPRMC message
31 Public Function ParseGPRMC(ByVal sentence As String) As Boolean
32 ' Divide the sentence into words
33 Dim Words() As String = GetWords(sentence)
34 ' Do we have enough values to describe our location?
35 If Words(3) <> "" And Words(4) <> "" And Words(5) <> "" And _
36 Words(6) <> "" Then
37 ' Yes. Extract latitude and longitude
38 Dim Latitude As String = Words(3).Substring(0, 2) & "°" ' Append hours
39 Latitude = Latitude & Words(3).Substring(2) & """" ' Append minutes
40 Latitude = Latitude & Words(4) ' Append the hemisphere
41 Dim Longitude As String = Words(5).Substring(0, 3) & "°" ' Append hours
42 Longitude = Longitude & Words(5).Substring(3) & """" ' Append minutes
43 Longitude = Longitude & Words(6) ' Append the hemisphere
44 ' Notify the calling application of the change
45 RaiseEvent PositionReceived(Latitude, Longitude)
46 End If
47 ' Do we have enough values to parse satellite-derived time?
48 If Words(1) <> "" Then
49 ' Yes. Extract hours, minutes, seconds and milliseconds
50 Dim UtcHours As Integer = CType(Words(1).Substring(0, 2), Integer)
51 Dim UtcMinutes As Integer = CType(Words(1).Substring(2, 2), Integer)
52 Dim UtcSeconds As Integer = CType(Words(1).Substring(4, 2), Integer)
53 Dim UtcMilliseconds As Integer
54 ' Extract milliseconds if it is available
55 If Words(1).Length > 7 Then
56 UtcMilliseconds = CType(Single.Parse(Words(1).Substring(6), _
57 CultureInfo.InvariantCulture) * 1000, Integer)
58 End If
59 ' Now build a DateTime object with all values
60 Dim Today As DateTime = System.DateTime.Now.ToUniversalTime
61 Dim SatelliteTime As New System.DateTime(Today.Year, Today.Month, _
62 Today.Day, UtcHours, UtcMinutes, UtcSeconds, UtcMilliseconds)
63 ' Notify of the new time, adjusted to the local time zone
64 RaiseEvent DateTimeChanged(SatelliteTime.ToLocalTime)
65 End If
66 ' Indicate that the sentence was recognized
67 Return True
68 End Function
69 ' Returns True if a sentence's checksum matches the calculated checksum
70 Public Function IsValid(ByVal sentence As String) As Boolean
71 ' Compare the characters after the asterisk to the calculation
72 Return sentence.Substring(sentence.IndexOf("*") + 1) = _
73 GetChecksum(sentence)
74 End Function
75 ' Calculates the checksum for a sentence
76 Public Function GetChecksum(ByVal sentence As String) As String
77 ' Loop through all chars to get a checksum
78 Dim Character As Char
79 Dim Checksum As Integer
80 For Each Character In sentence
81 Select Case Character
82 Case "$"c
83 ' Ignore the dollar sign
84 Case "*"c
85 ' Stop processing before the asterisk
86 Exit For
87 Case Else
88 ' Is this the first value for the checksum?
89 If Checksum = 0 Then
90 ' Yes. Set the checksum to the value
91 Checksum = Convert.ToByte(Character)
92 Else
93 ' No. XOR the checksum with this character's value
94 Checksum = Checksum Xor Convert.ToByte(Character)
95 End If
96 End Select
97 Next
98 ' Return the checksum formatted as a two-character hexadecimal
99 Return Checksum.ToString("X2")
100 End Function
101 End Class
102
方向和速度提醒
GPS设备分析您的位置,随着时间的推移来计算速度和影响。在本文开头$ GPRMC语句也包括这些数据。速度在每个节点都是始终要记录的,轴承以“方位”来记录,从0 °到360 °顺时针其中0 °表示北, 90 °表示东等。因此在地平线上测量。要应用数学公式转换成英里每小时。全球定位系统的力量再一次证明了一行代码。表单1-5的数字,显示汽车是否超过时速限制。
代码片段:
2
3 '** Listing 1-5. Extracting speed and bearing
4
5 '*******************************************************
6
7 Public Class NmeaInterpreter
8 ' Raised when the current location has changed
9 Public Event PositionReceived(ByVal latitude As String, _
10 ByVal longitude As String)
11 Public Event DateTimeChanged(ByVal dateTime As DateTime)
12 Public Event BearingReceived(ByVal bearing As Double)
13 Public Event SpeedReceived(ByVal speed As Double)
14 Public Event SpeedLimitReached()
15 ' Processes information from the GPS receiver
16 Public Function Parse(ByVal sentence As String) As Boolean
17 ' Discard the sentence if its checksum does not match our calculated
18 ' checksum
19 If Not IsValid(sentence) Then Return False
20 ' Look at the first word to decide where to go next
21 Select Case GetWords(sentence)(0)
22 Case "$GPRMC" ' A "Recommended Minimum" sentence was found!
23 Return ParseGPRMC(sentence)
24 Case Else
25 ' Indicate that the sentence was not recognized
26 Return False
27 End Select
28 End Function
29 ' Divides a sentence into individual words
30 Public Function GetWords(ByVal sentence As String) As String()
31 Return sentence.Split(","c)
32 End Function
33 ' Interprets a $GPRMC message
34 Public Function ParseGPRMC(ByVal sentence As String) As Boolean
35 ' Divide the sentence into words
36 Dim Words() As String = GetWords(sentence)
37 ' Do we have enough values to describe our location?
38 If Words(3) <> "" And Words(4) <> "" And Words(5) <> "" And _
39 Words(6) <> "" Then
40 ' Yes. Extract latitude and longitude
41 Dim Latitude As String = Words(3).Substring(0, 2) & "°" ' Append hours
42 Latitude = Latitude & Words(3).Substring(2) & """" ' Append minutes
43 Latitude = Latitude & Words(4) ' Append the hemisphere
44 Dim Longitude As String = Words(5).Substring(0, 3) & "°" ' Append hours
45 Longitude = Longitude & Words(5).Substring(3) & """" ' Append minutes
46 Longitude = Longitude & Words(6) ' Append the hemisphere
47 ' Notify the calling application of the change
48 RaiseEvent PositionReceived(Latitude, Longitude)
49 End If
50 ' Do we have enough values to parse satellite-derived time?
51 If Words(1) <> "" Then
52 ' Yes. Extract hours, minutes, seconds and milliseconds
53 Dim UtcHours As Integer = CType(Words(1).Substring(0, 2), Integer)
54 Dim UtcMinutes As Integer = CType(Words(1).Substring(2, 2), Integer)
55 Dim UtcSeconds As Integer = CType(Words(1).Substring(4, 2), Integer)
56 Dim UtcMilliseconds As Integer
57 ' Extract milliseconds if it is available
58 If Words(1).Length > 7 Then UtcMilliseconds = _
59 CType(Single.Parse(Words(1).Substring(6), _
60 CultureInfo.InvariantCulture) * 1000, Integer)
61 ' Now build a DateTime object with all values
62 Dim Today As DateTime = System.DateTime.Now.ToUniversalTime
63 Dim SatelliteTime As New System.DateTime(Today.Year, Today.Month, _
64 Today.Day, UtcHours, UtcMinutes, UtcSeconds, UtcMilliseconds)
65 ' Notify of the new time, adjusted to the local time zone
66 RaiseEvent DateTimeChanged(SatelliteTime.ToLocalTime)
67 End If
68 ' Do we have enough information to extract the current speed?
69 If Words(7) <> "" Then
70 ' Yes. Convert it into MPH
71 Dim Speed As Double = CType(Words(7), Double) * 1.150779
72 ' If we're over 55MPH then trigger a speed alarm!
73 If Speed > 55 Then RaiseEvent SpeedLimitReached()
74 ' Notify of the new speed
75 RaiseEvent SpeedReceived(Speed)
76 End If
77 ' Do we have enough information to extract bearing?
78 If Words(8) <> "" Then
79 ' Indicate that the sentence was recognized
80 Dim Bearing As Double = CType(Words(8), Double)
81 RaiseEvent BearingReceived(Bearing)
82 End If
83 ' Indicate that the sentence was recognized
84 Return True
85 End Function
86 ' Returns True if a sentence's checksum matches the calculated checksum
87 Public Function IsValid(ByVal sentence As String) As Boolean
88 ' Compare the characters after the asterisk to the calculation
89 Return sentence.Substring(sentence.IndexOf("*") + 1) = _
90 GetChecksum(sentence)
91 End Function
92 ' Calculates the checksum for a sentence
93 Public Function GetChecksum(ByVal sentence As String) As String
94 ' Loop through all chars to get a checksum
95 Dim Character As Char
96 Dim Checksum As Integer
97 For Each Character In sentence
98 Select Case Character
99 Case "$"c
100 ' Ignore the dollar sign
101 Case "*"c
102 ' Stop processing before the asterisk
103 Exit For
104 Case Else
105 ' Is this the first value for the checksum?
106 If Checksum = 0 Then
107 ' Yes. Set the checksum to the value
108 Checksum = Convert.ToByte(Character)
109 Else
110 ' No. XOR the checksum with this character's value
111 Checksum = Checksum Xor Convert.ToByte(Character)
112 End If
113 End Select
114 Next
115 ' Return the checksum formatted as a two-character hexadecimal
116 Return Checksum.ToString("X2")
117 End Function
118 End Class
119
目前是否有 Fix
$ GPRMC语句包含一个值,显示“Fix”是否已经获得。当至少三颗卫星的信号强度足以与计算您的位置有关一个修复程序时,Fix将会获得。如果至少有四颗卫星都参与,高度也成为众所周知的。$ GPRMC语句的第三个字是两个字母中的一个:“A”为“积极”,其中获得一个Fix,或“V”为“无效”目前没有Fix存在。列表1-6包括代码审查这一字母和修复情况的报告。
代码片段:
2
3 '** Listing 1-6. Extracting satellite fix status
4
5 '*******************************************************
6
7 Public Class NmeaInterpreter
8
9 ' Raised when the current location has changed
10 Public Event PositionReceived(ByVal latitude As String, _
11 ByVal longitude As String)
12 Public Event DateTimeChanged(ByVal dateTime As DateTime)
13 Public Event BearingReceived(ByVal bearing As Double)
14 Public Event SpeedReceived(ByVal speed As Double)
15 Public Event SpeedLimitReached()
16 Public Event FixObtained()
17 Public Event FixLost()
18 ' Processes information from the GPS receiver
19 Public Function Parse(ByVal sentence As String) As Boolean
20 ' Discard the sentence if its checksum does not match our calculated
21 ' checksum
22 If Not IsValid(sentence) Then Return False
23 ' Look at the first word to decide where to go next
24 Select Case GetWords(sentence)(0)
25 Case "$GPRMC" ' A "Recommended Minimum" sentence was found!
26 Return ParseGPRMC(sentence)
27 Case Else
28 ' Indicate that the sentence was not recognized
29 Return False
30 End Select
31 End Function
32 ' Divides a sentence into individual words
33 Public Function GetWords(ByVal sentence As String) As String()
34 Return sentence.Split(","c)
35 End Function
36 ' Interprets a $GPRMC message
37 Public Function ParseGPRMC(ByVal sentence As String) As Boolean
38 ' Divide the sentence into words
39 Dim Words() As String = GetWords(sentence)
40 ' Do we have enough values to describe our location?
41 If Words(3) <> "" And Words(4) <> "" And Words(5) <> "" And _
42 Words(6) <> "" Then
43 ' Yes. Extract latitude and longitude
44 Dim Latitude As String = Words(3).Substring(0, 2) & "°" ' Append hours
45 Latitude = Latitude & Words(3).Substring(2) & """" ' Append minutes
46 Latitude = Latitude & Words(4) ' Append the hemisphere
47 Dim Longitude As String = Words(5).Substring(0, 3) & "°" ' Append hours
48 Longitude = Longitude & Words(5).Substring(3) & """" ' Append minutes
49 Longitude = Longitude & Words(6) ' Append the hemisphere
50 ' Notify the calling application of the change
51 RaiseEvent PositionReceived(Latitude, Longitude)
52 End If
53 ' Do we have enough values to parse satellite-derived time?
54 If Words(1) <> "" Then
55 ' Yes. Extract hours, minutes, seconds and milliseconds
56 Dim UtcHours As Integer = CType(Words(1).Substring(0, 2), Integer)
57 Dim UtcMinutes As Integer = CType(Words(1).Substring(2, 2), Integer)
58 Dim UtcSeconds As Integer = CType(Words(1).Substring(4, 2), Integer)
59 Dim UtcMilliseconds As Integer
60 ' Extract milliseconds if it is available
61 If Words(1).Length > 7 Then UtcMilliseconds = _
62 CType(Single.Parse(Words(1).Substring(6), _
63 CultureInfo.InvariantCulture) * 1000, Integer)
64 ' Now build a DateTime object with all values
65 Dim Today As DateTime = System.DateTime.Now.ToUniversalTime
66 Dim SatelliteTime As New System.DateTime(Today.Year, Today.Month, _
67 Today.Day, UtcHours, UtcMinutes, UtcSeconds, UtcMilliseconds)
68 ' Notify of the new time, adjusted to the local time zone
69 RaiseEvent DateTimeChanged(SatelliteTime.ToLocalTime)
70 End If
71 ' Do we have enough information to extract the current speed?
72 If Words(7) <> "" Then
73 ' Yes. Convert it into MPH
74 Dim Speed As Double = CType(Words(7), Double) * 1.150779
75 ' If we're over 55MPH then trigger a speed alarm!
76 If Speed > 55 Then RaiseEvent SpeedLimitReached()
77 ' Notify of the new speed
78 RaiseEvent SpeedReceived(Speed)
79 End If
80 ' Do we have enough information to extract bearing?
81 If Words(8) <> "" Then
82 ' Indicate that the sentence was recognized
83 Dim Bearing As Double = CType(Words(8), Double)
84 RaiseEvent BearingReceived(Bearing)
85 End If
86 ' Does the device currently have a satellite fix?
87 If Words(2) <> "" Then
88 Select Case Words(2)
89 Case "A"
90 RaiseEvent FixObtained()
91 Case "V"
92 RaiseEvent FixLost()
93 End Select
94 End If
95 ' Indicate that the sentence was recognized
96 Return True
97 End Function
98 ' Returns True if a sentence's checksum matches the calculated checksum
99 Public Function IsValid(ByVal sentence As String) As Boolean
100 ' Compare the characters after the asterisk to the calculation
101 Return sentence.Substring(sentence.IndexOf("*") + 1) = GetChecksum(sentence)
102 End Function
103 ' Calculates the checksum for a sentence
104 Public Function GetChecksum(ByVal sentence As String) As String
105 ' Loop through all chars to get a checksum
106 Dim Character As Char
107 Dim Checksum As Integer
108 For Each Character In sentence
109 Select Case Character
110 Case "$"c
111 ' Ignore the dollar sign
112 Case "*"c
113 ' Stop processing before the asterisk
114 Exit For
115 Case Else
116 ' Is this the first value for the checksum?
117 If Checksum = 0 Then
118 ' Yes. Set the checksum to the value
119 Checksum = Convert.ToByte(Character)
120 Else
121 ' No. XOR the checksum with this character's value
122 Checksum = Checksum Xor Convert.ToByte(Character)
123 End If
124 End Select
125 Next
126 ' Return the checksum formatted as a two-character hexadecimal
127 Return Checksum.ToString("X2")
128 End Function
129 End Class
130
正如你所看到的,一大堆的信息都装在NMEA一句话中。现在$ GPRMC语句已经被充分解析,解析器可以扩展以支持第二句:$ GPGSV。这句话描述了卫星配置的开销,实时。
实时卫星追踪
在确定如何精确读数,以及如何稳定的一个GPS的修补程序时,知道卫星的位置非常重要。全球定位系统的精度将会在系列的第2部分详细介绍,本节将侧重于判读卫星的位置和信号强度。有24颗卫星在轨道上运行。卫星在轨道的间距,以便在任何时间至少6颗卫星将被世界各地的用户用到。卫星不断运动,这是好事,因为它阻止很少或根本不会出现卫星可见的“世界上存在的盲点”。就像在寻找天上的星星,卫星的位置被描述为一个方位和海拔的组合。
如上所述,方位角测量了围绕地平线的方向。海拔测量值在一定程度从0 °至90 °,其中0 °表示地平线,90 °代表“顶峰”,直接开销。因此,如果设备说卫星的方位角为45 °,其海拔为45 °,卫星位于半山腰,从东北方向的地平线。除了位置,设备报告每个卫星的“伪随机码”(或PRC),这个数字用于唯一地标识从一个卫星到另一个卫星。以下是 $ GPGSV语句的例子:
代码片段:
每个句子包含多达4个卫星信息块,由4个字组成的。例如,第一块是“24,82,023,40”,第二块是“05,62,285,32”等。每个块的第一个字给出了卫星的PRC。第二个单词给出每颗卫星的高度,方位和所遵循的信号强度。如果这个卫星信息将被显示图形,它的样子会是如图1-1。
也许,这句话中最重要的数字是“信号噪声比”(或简称信噪比)。此数字表示卫星的无线电信号被接收的强烈程度。请记住,卫星传输相同强度的信号,但像树木和墙壁这样的东西可能掩盖一个信号。典型的信噪比值介于0和50,其中50是指一个很好的信号。 (信噪比可高达99,但我从来没有见过,即使在开阔的天空读数也是50。)在图1-1中,绿色的卫星表明一个强烈的信号,而黄色的卫星,标志着一个温和的信号(第2部分中,我将提供一种方法进行分类信号强度)。 #1卫星的信号是完全掩盖。列表1-7显示的是解析器在它扩大为用于读取卫星信息。
代码片段:
2
3 '** Listing 1-7. Extracting satellite information
4
5 '*******************************************************
6
7 Public Class NmeaInterpreter
8
9 ' Raised when the current location has changed
10
11 Public Event PositionReceived(ByVal latitude As String, _
12 ByVal longitude As String)
13 Public Event DateTimeChanged(ByVal dateTime As DateTime)
14 Public Event BearingReceived(ByVal bearing As Double)
15 Public Event SpeedReceived(ByVal speed As Double)
16 Public Event SpeedLimitReached()
17 Public Event FixObtained()
18 Public Event FixLost()
19 Public Event SatelliteReceived(ByVal pseudoRandomCode As Integer, _
20 ByVal azimuth As Integer, _
21 ByVal elevation As Integer, _
22 ByVal signalToNoiseRatio As Integer)
23 ' Processes information from the GPS receiver
24 Public Function Parse(ByVal sentence As String) As Boolean
25 ' Discard the sentence if its checksum does not match our calculated
26 ' checksum
27 If Not IsValid(sentence) Then Return False
28 ' Look at the first word to decide where to go next
29 Select Case GetWords(sentence)(0)
30 Case "$GPRMC" ' A "Recommended Minimum" sentence was found!
31 Return ParseGPRMC(sentence)
32 Case "$GPGSV" ' A "Satellites in View" message was found
33 Return ParseGPGSV(sentence)
34 Case Else
35 ' Indicate that the sentence was not recognized
36 Return False
37 End Select
38 End Function
39 ' Divides a sentence into individual words
40 Public Function GetWords(ByVal sentence As String) As String()
41 Return sentence.Split(","c)
42 End Function
43 ' Interprets a $GPRMC message
44 Public Function ParseGPRMC(ByVal sentence As String) As Boolean
45 ' Divide the sentence into words
46 Dim Words() As String = GetWords(sentence)
47 ' Do we have enough values to describe our location?
48 If Words(3) <> "" And Words(4) <> "" And Words(5) <> "" And _
49 Words(6) <> "" Then
50 ' Yes. Extract latitude and longitude
51 Dim Latitude As String = Words(3).Substring(0, 2) & "°" ' Append hours
52 Latitude = Latitude & Words(3).Substring(2) & """" ' Append minutes
53 Latitude = Latitude & Words(4) ' Append the hemisphere
54 Dim Longitude As String = Words(5).Substring(0, 3) & "°" ' Append hours
55 Longitude = Longitude & Words(5).Substring(3) & """" ' Append minutes
56 Longitude = Longitude & Words(6) ' Append the hemisphere
57 ' Notify the calling application of the change
58 RaiseEvent PositionReceived(Latitude, Longitude)
59 End If
60 ' Do we have enough values to parse satellite-derived time?
61 If Words(1) <> "" Then
62 ' Yes. Extract hours, minutes, seconds and milliseconds
63 Dim UtcHours As Integer = CType(Words(1).Substring(0, 2), Integer)
64 Dim UtcMinutes As Integer = CType(Words(1).Substring(2, 2), Integer)
65 Dim UtcSeconds As Integer = CType(Words(1).Substring(4, 2), Integer)
66 Dim UtcMilliseconds As Integer
67 ' Extract milliseconds if it is available
68 If Words(1).Length > 7 Then UtcMilliseconds = _
69 CType(Single.Parse(Words(1).Substring(6), _
70 CultureInfo.InvariantCulture) * 1000, Integer)
71 ' Now build a DateTime object with all values
72 Dim Today As DateTime = System.DateTime.Now.ToUniversalTime
73 Dim SatelliteTime As New System.DateTime(Today.Year, Today.Month, _
74 Today.Day, UtcHours, UtcMinutes, UtcSeconds, UtcMilliseconds)
75 ' Notify of the new time, adjusted to the local time zone
76 RaiseEvent DateTimeChanged(SatelliteTime.ToLocalTime)
77 End If
78 ' Do we have enough information to extract the current speed?
79 If Words(7) <> "" Then
80 ' Yes. Convert it into MPH
81 Dim Speed As Double = CType(Words(7), Double) * 1.150779
82 ' If we're over 55MPH then trigger a speed alarm!
83 If Speed > 55 Then RaiseEvent SpeedLimitReached()
84 ' Notify of the new speed
85 RaiseEvent SpeedReceived(Speed)
86 End If
87 ' Do we have enough information to extract bearing?
88 If Words(8) <> "" Then
89 ' Indicate that the sentence was recognized
90 Dim Bearing As Double = CType(Words(8), Double)
91 RaiseEvent BearingReceived(Bearing)
92 End If
93 ' Does the device currently have a satellite fix?
94 If Words(2) <> "" Then
95 Select Case Words(2)
96 Case "A"
97 RaiseEvent FixObtained()
98 Case "V"
99 RaiseEvent FixLost()
100 End Select
101 End If
102 ' Indicate that the sentence was recognized
103 Return True
104 End Function
105 ' Interprets a "Satellites in View" NMEA sentence
106 Public Function ParseGPGSV(ByVal sentence As String) As Boolean
107 Dim PseudoRandomCode As Integer
108 Dim Azimuth As Integer
109 Dim Elevation As Integer
110 Dim SignalToNoiseRatio As Integer
111 ' Divide the sentence into words
112 Dim Words() As String = GetWords(sentence)
113 ' Each sentence contains four blocks of satellite information.
114 ' Read each block and report each satellite's information
115 Dim Count As Integer
116 For Count = 1 To 4
117 ' Does the sentence have enough words to analyze?
118 If (Words.Length - 1) >= (Count * 4 + 3) Then
119 ' Yes. Proceed with analyzing the block. Does it contain any
120 ' information?
121 If Words(Count * 4) <> "" And Words(Count * 4 + 1) <> "" _
122 And Words(Count * 4 + 2) <> "" And Words(Count * 4 + 3) <> "" Then
123 ' Yes. Extract satellite information and report it
124 PseudoRandomCode = CType(Words(Count * 4), Integer)
125 Elevation = CType(Words(Count * 4 + 1), Integer)
126 Azimuth = CType(Words(Count * 4 + 2), Integer)
127 SignalToNoiseRatio = CType(Words(Count * 4 + 2), Integer)
128 ' Notify of this satellite's information
129 RaiseEvent SatelliteReceived(PseudoRandomCode, Azimuth, Elevation, _
130 SignalToNoiseRatio)
131 End If
132 End If
133 Next
134 ' Indicate that the sentence was recognized
135 Return True
136 End Function
137 ' Returns True if a sentence's checksum matches the calculated checksum
138 Public Function IsValid(ByVal sentence As String) As Boolean
139 ' Compare the characters after the asterisk to the calculation
140 Return sentence.Substring(sentence.IndexOf("*") + 1) = GetChecksum(sentence)
141 End Function
142 ' Calculates the checksum for a sentence
143 Public Function GetChecksum(ByVal sentence As String) As String
144 ' Loop through all chars to get a checksum
145 Dim Character As Char
146 Dim Checksum As Integer
147 For Each Character In sentence
148 Select Case Character
149 Case "$"c
150 ' Ignore the dollar sign
151 Case "*"c
152 ' Stop processing before the asterisk
153 Exit For
154 Case Else
155 ' Is this the first value for the checksum?
156 If Checksum = 0 Then
157 ' Yes. Set the checksum to the value
158 Checksum = Convert.ToByte(Character)
159 Else
160 ' No. XOR the checksum with this character's value
161 Checksum = Checksum Xor Convert.ToByte(Character)
162 End If
163 End Select
164 Next
165 ' Return the checksum formatted as a two-character hexadecimal
166 Return Checksum.ToString("X2")
167 End Function
168 End Class
169
一个世界级的解析器
国际读者可能已经发现了一个微妙的问题,这不是在上市初期处理-数字被在美国使用的数字格式报告!如比利时和瑞士使用不同的数字格式,需要调整解析器以便在所有的地方工作。幸运的是,NET框架,其中包括内置支持不同文化之间的转换数量,因此对解析器必要的改变很简单。在解析器中,唯一的分数值是速度,因此只有一处改动是必要的。NmeaCultureInfo变量代表NMEA语句内使用数字的文化。Double.Parse方法使用这个变量用于将速度转换成机器的地方文化。列表1-8显示了完整的解析器,现在可以在国际上用了。
代码片段:
2
3 '** Listing 1-8. Adding support for international cultures
4
5 '*************************************************************
6
7 Imports System.Globalization
8 Public Class NmeaInterpreter
9
10 ' Represents the EN-US culture, used for numbers in NMEA sentences
11 Private NmeaCultureInfo As New CultureInfo("en-US")
12 ' Used to convert knots into miles per hour
13 Private MPHPerKnot As Double = Double.Parse("1.150779", NmeaCultureInfo)
14 ' Raised when the current location has changed
15 Public Event PositionReceived(ByVal latitude As String,_
16 ByVal longitude As String)
17 Public Event DateTimeChanged(ByVal dateTime As DateTime)
18 Public Event BearingReceived(ByVal bearing As Double)
19 Public Event SpeedReceived(ByVal speed As Double)
20 Public Event SpeedLimitReached()
21 Public Event FixObtained()
22 Public Event FixLost()
23 Public Event SatelliteReceived(ByVal pseudoRandomCode As Integer, _
24 ByVal azimuth As Integer, _
25 ByVal elevation As Integer, _
26 ByVal signalToNoiseRatio As Integer)
27 ' Processes information from the GPS receiver
28 Public Function Parse(ByVal sentence As String) As Boolean
29 ' Discard the sentence if its checksum does not match our calculated
30 ' checksum
31 If Not IsValid(sentence) Then Return False
32 ' Look at the first word to decide where to go next
33 Select Case GetWords(sentence)(0)
34 Case "$GPRMC" ' A "Recommended Minimum" sentence was found!
35 Return ParseGPRMC(sentence)
36 Case "$GPGSV"
37 Return ParseGPGSV(sentence)
38 Case Else
39 ' Indicate that the sentence was not recognized
40 Return False
41 End Select
42 End Function
43 ' Divides a sentence into individual words
44 Public Function GetWords(ByVal sentence As String) As String()
45 Return sentence.Split(","c)
46 End Function
47 ' Interprets a $GPRMC message
48 Public Function ParseGPRMC(ByVal sentence As String) As Boolean
49 ' Divide the sentence into words
50 Dim Words() As String = GetWords(sentence)
51 ' Do we have enough values to describe our location?
52 If Words(3) <> "" And Words(4) <> "" _
53 And Words(5) <> "" And Words(6) <> "" Then
54 ' Yes. Extract latitude and longitude
55 Dim Latitude As String = Words(3).Substring(0, 2) & "°" ' Append hours
56 Latitude = Latitude & Words(3).Substring(2) & """" ' Append minutes
57 Latitude = Latitude & Words(4) ' Append the hemisphere
58 Dim Longitude As String = Words(5).Substring(0, 3) & "°" ' Append hours
59 Longitude = Longitude & Words(5).Substring(3) & """" ' Append minutes
60 Longitude = Longitude & Words(6) ' Append the hemisphere
61 ' Notify the calling application of the change
62 RaiseEvent PositionReceived(Latitude, Longitude)
63 End If
64 ' Do we have enough values to parse satellite-derived time?
65 If Words(1) <> "" Then
66 ' Yes. Extract hours, minutes, seconds and milliseconds
67 Dim UtcHours As Integer = CType(Words(1).Substring(0, 2), Integer)
68 Dim UtcMinutes As Integer = CType(Words(1).Substring(2, 2), Integer)
69 Dim UtcSeconds As Integer = CType(Words(1).Substring(4, 2), Integer)
70 Dim UtcMilliseconds As Integer
71 ' Extract milliseconds if it is available
72 If Words(1).Length > 7 Then
73 UtcMilliseconds = CType(Single.Parse(Words(1).Substring(6), _
74 CultureInfo.InvariantCulture) * 1000, Integer)
75 End If
76 ' Now build a DateTime object with all values
77 Dim Today As DateTime = System.DateTime.Now.ToUniversalTime
78 Dim SatelliteTime As New System.DateTime(Today.Year, Today.Month, _
79 Today.Day, UtcHours, UtcMinutes, UtcSeconds, UtcMilliseconds)
80 ' Notify of the new time, adjusted to the local time zone
81 RaiseEvent DateTimeChanged(SatelliteTime.ToLocalTime)
82 End If
83 ' Do we have enough information to extract the current speed?
84 If Words(7) <> "" Then
85 ' Yes. Parse the speed and convert it to MPH
86 Dim Speed As Double = Double.Parse(Words(7), NmeaCultureInfo) _
87 * MPHPerKnot
88 ' Notify of the new speed
89 RaiseEvent SpeedReceived(Speed)
90 ' Are we over the highway speed limit?
91 If Speed > 55 Then RaiseEvent SpeedLimitReached()
92 End If
93 ' Do we have enough information to extract bearing?
94 If Words(8) <> "" Then
95 ' Indicate that the sentence was recognized
96 Dim Bearing As Double = CType(Words(8), Double)
97 RaiseEvent BearingReceived(Bearing)
98 End If
99 ' Does the device currently have a satellite fix?
100 If Words(2) <> "" Then
101 Select Case Words(2)
102 Case "A"
103 RaiseEvent FixObtained()
104 Case "V"
105 RaiseEvent FixLost()
106 End Select
107 End If
108 ' Indicate that the sentence was recognized
109 Return True
110 End Function
111 ' Interprets a "Satellites in View" NMEA sentence
112 Public Function ParseGPGSV(ByVal sentence As String) As Boolean
113 Dim PseudoRandomCode As Integer
114 Dim Azimuth As Integer
115 Dim Elevation As Integer
116 Dim SignalToNoiseRatio As Integer
117 ' Divide the sentence into words
118 Dim Words() As String = GetWords(sentence)
119 ' Each sentence contains four blocks of satellite information.
120 ' Read each block
121 ' and report each satellite's information
122 Dim Count As Integer
123 For Count = 1 To 4
124 ' Does the sentence have enough words to analyze?
125 If (Words.Length - 1) >= (Count * 4 + 3) Then
126 ' Yes. Proceed with analyzing the block. Does it contain any information?
127 If Words(Count * 4) <> "" And Words(Count * 4 + 1) <> "" _
128 And Words(Count * 4 + 2) <> "" And Words(Count * 4 + 3) <> "" Then
129 ' Yes. Extract satellite information and report it
130 PseudoRandomCode = CType(Words(Count * 4), Integer)
131 Elevation = CType(Words(Count * 4 + 1), Integer)
132 Azimuth = CType(Words(Count * 4 + 2), Integer)
133 SignalToNoiseRatio = CType(Words(Count * 4 + 2), Integer)
134 ' Notify of this satellite's information
135 RaiseEvent SatelliteReceived(PseudoRandomCode, Azimuth, Elevation, _
136 SignalToNoiseRatio)
137 End If
138 End If
139 Next
140 ' Indicate that the sentence was recognized
141 Return True
142 End Function
143 ' Returns True if a sentence's checksum matches the calculated checksum
144 Public Function IsValid(ByVal sentence As String) As Boolean
145 ' Compare the characters after the asterisk to the calculation
146 Return sentence.Substring(sentence.IndexOf("*") + 1) = GetChecksum(sentence)
147 End Function
148 ' Calculates the checksum for a sentence
149 Public Function GetChecksum(ByVal sentence As String) As String
150 ' Loop through all chars to get a checksum
151 Dim Character As Char
152 Dim Checksum As Integer
153 For Each Character In sentence
154 Select Case Character
155 Case "$"c
156 ' Ignore the dollar sign
157 Case "*"c
158 ' Stop processing before the asterisk
159 Exit For
160 Case Else
161 ' Is this the first value for the checksum?
162 If Checksum = 0 Then
163 ' Yes. Set the checksum to the value
164 Checksum = Convert.ToByte(Character)
165 Else
166 ' No. XOR the checksum with this character's value
167 Checksum = Checksum Xor Convert.ToByte(Character)
168 End If
169 End Select
170 Next
171 ' Return the checksum formatted as a two-character hexadecimal
172 Return Checksum.ToString("X2")
173 End Function
174 End Class
175
最后的思考
您现在应该有一个很好的了解,即1个NMEA解析器是从语句中提取所有相关的字。您可以利用卫星有权决定您的位置,与您的计算机时钟同步,找到你的方向,查看你的速度,阴天时指向天空中的卫星。这种解析器也将使用.NET Compact Framework而没有任何修改。如果语句也存储在文件中,解析器可以用来播放整个客场之旅。这些都是伟大的功能,尤其是考虑到类的如此小的尺寸,但这种解析器是否准备好了驾驶您的汽车以及飞机?我还没有。还有一个重要议题就是在现实世界中使GPS应用变得更安全:精度。 GPS设备用来记录他们发现的任何信息,即使信息是不准确的。
事实上,关于当前的位置信息,误差可达半个足球场,即使设备上安装了最新的DGPS和WAAS校正技术!不幸的是,一些开发商并没有意识到这个问题。有一些第三方组件,不适合商业应用,需要加强最低水平的精度。在本系列的第2部分,我会详细解释精度执法,使解析器进一步适合于更专业高精密的应用!