技术开发 频道

WM平台上如何开发出自己的GPS导航

  【IT168技术】现在GPS应用必须足以在商业环境如汽车导航中使用,此外,该如何解释GPS数据的实际工作过程,在这三个部分组成的系列,我将介绍两个主题,在大多数行业工程有GPS设备的今天,增加你编写一个商业级GPS应用的技巧。

  一个强大的语句

  这系列中的第一部分的任务将探讨解析原始GPS数据。幸运的是,任务是简化国家海洋电子协会由于它采用了一种行业标准,现在使用绝大多数的GPS设备。为了给开发人员提供一个良好的开端,我选择使用一些Visual Studio。NET源代码来自我的“GPS.NET全球定位SDK的”组件。 (代码被剥离,如多线程和错误处理功能。)

  NMEA数据发送以逗号分隔的“句子”,其中载有关于这句话的第一个字的信息。有超过50多种的句子,但翻译完成这项工作真只需要处理其中的一些。所有最常见的NMEA语句是一句是“Recommended Minimum”这一句,以“$GPRMC开头”。下面是一个例子:

  代码:

1 $GPRMC,040302.663,A,3939.7,N,10506.6,W,0.27,358.86,200804,,*1A

  这一个句子包含几乎所有的GPS应用程序需要:纬度,经度,速度,轴承,卫星获取的时间,固定的地位和磁性的变化。

  解析器的核心

  做NMEA翻译的第一步是写一个方法来做这两件事情:将每一句分离成单个字、审议第一个字,找出哪些信息是可以进一步提取。列表1-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扩大解析器用以记录目前的情况。

  代码片段:

1 '*******************************************************
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扩大解析器:

  代码片段:

1 *******************************************************
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方法将卫星时间转换为本地时区。

  代码片段:

  1 ********************************************************
  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的数字,显示汽车是否超过时速限制。

  代码片段:

  1 '*******************************************************
  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包括代码审查这一字母和修复情况的报告。

  代码片段:

  1 *******************************************************
  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语句的例子:

  代码片段:

1 $GPGSV,3,1,10,24,82,023,40,05,62,285,32,01,62,123,00,17,59,229,28*70

  每个句子包含多达4个卫星信息块,由4个字组成的。例如,第一块是“24,82,023,40”,第二块是“05,62,285,32”等。每个块的第一个字给出了卫星的PRC。第二个单词给出每颗卫星的高度,方位和所遵循的信号强度。如果这个卫星信息将被显示图形,它的样子会是如图1-1。

  也许,这句话中最重要的数字是“信号噪声比”(或简称信噪比)。此数字表示卫星的无线电信号被接收的强烈程度。请记住,卫星传输相同强度的信号,但像树木和墙壁这样的东西可能掩盖一个信号。典型的信噪比值介于0和50,其中50是指一个很好的信号。 (信噪比可高达99,但我从来没有见过,即使在开阔的天空读数也是50。)在图1-1中,绿色的卫星表明一个强烈的信号,而黄色的卫星,标志着一个温和的信号(第2部分中,我将提供一种方法进行分类信号强度)。 #1卫星的信号是完全掩盖。列表1-7显示的是解析器在它扩大为用于读取卫星信息。

  代码片段:

  1 '*******************************************************
  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显示了完整的解析器,现在可以在国际上用了。

  代码片段:

  1 *************************************************************
  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部分,我会详细解释精度执法,使解析器进一步适合于更专业高精密的应用!

0
相关文章