⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gps.txt

📁 C++GPS程序
💻 TXT
📖 第 1 页 / 共 2 页
字号:
需要什么样的GPS应用程序才能满足商业级的要求呢,像安装在车里的导航器一样?而且,GPS数据是怎么被解释,从而应用于实际工作中的呢?在这两部分里,我将和大家一起探讨这两个问题,并且给你编写商业级GPS应用程序必要的技巧,让专业的GPS设备能够更好的为你所用。

一句重要的语句

第一部分将探讨描述GPS原始数据的工作。实际上这个工作已经被国家舰船电子协会(下面简称NMEA,www.nmea.org)给简化了许多,该网站介 绍了一个正广泛应用于GPS主流设备的工业标准。为了给广大的开发人员一个良好的开端,我选择使用的一些VS.NET的源代码来自我的“GPS.NET Global Position SDK”组件。(为了简短这些代码,我去掉了诸如多线程和错误处理的部分。)

NMEA数据通过一个“逗号分隔的语句”来传递,这个语句包含的信息都基于语句的第一个单词。这里有五十种以上类型的语句,不过真正的一个描述仅仅需要处理少量的采集数据。最终常用的NMEA语句是“推荐最小”语句,它以“$GPRMC.”开头。这里有个一例子:

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

这条语句基本上包含了GPS应用程序所需的全部数据:纬度、经度、速度、方向、卫星时间、状态以及磁场变量。

第一步就是要写一个方法来解释NMEA数据,这个方法需要完成两件事:将每条语句分解为独立的单词,和检查首单词是否有效。清单 1-1 就是这个描述类的开始部分。

清单 1-1:一个NMEA描述的核心功能是将NMEA语句分解成单个的单词。

'**  Listing 1-1.  The core of an NMEA interpreter
'*******************************************************
Public Class NmeaInterpreter
  ' 处理来自GPS接收器的信息
  Public Function Parse(ByVal sentence As String) As Boolean
    ' 将语句分解为单词
    Dim Words() As String = GetWords(sentence)
    ' 通过匹配首单词来决定下一步的工作
    Select Case Words(0)
      Case "$GPRMC"      ' 一条“推荐最小”的语句被找到!
        ' 标示这条语句为可用
        Return True
      Case Else
        ' 标示这条语句为不可用
        Return False
    End Select
  End Function
  ' 将语句分解为单词
  Public Function GetWords(ByVal sentence As String) As String()
    Return sentence.Split(","c)
  End Function
End Class

接下来一步就是要分析提取出来的信息了,让我们从纬度和经度开始吧。纬度和经度存储格式为“DDD°MM’SS.S,”,其中D表示时(也可以叫 “度”),M表示分,S表示秒。坐标可以简单表示为“DD°MM.M’”或者直接就表示为“DD°.”语句中第四个单词(“3939.7,”)以度和分的 形式表示当前的纬度为39°39.7’。头两个字符(39)表示度,余下的部分(39.7)表示分。经度和纬度是相同的结构,从这个语句来看要注意,头三 个字符表示经度的度(105°06.6’)。第五和第七个单词标示“半球”,其中“N”代表“北半球”,“W”代表“西经”。半球信息放在数字部分后面组 成完整的测量信息。

我还发现NMEA描述在事件驱动下使工作更容易完成。这是因为并不是按照特定的顺序来获取数据。一个事件驱动类为一应用程序给出了它

最具灵活性和响应性的 描述。因此,我也将使用事件来设计描述,从而获取信息。PositionReceived是第一个事件,它将记录当前获得的纬度和经度。清单 1-2 扩展这个描述器,来报告当前位置。

清单 1-2:这个描述器可以报告当前的纬度和经度。

'******************************************************* 
'*************  清单 1-2. 从语句中提取信息  *************
'*******************************************************
Public Class NmeaInterpreter
  ' 当前位置变化时,记录新位置
  Public Event PositionReceived(ByVal latitude As String, _
                                ByVal longitude As String)
  ' 处理GPS接收器的信息
  Public Function Parse(ByVal sentence As String) As Boolean
    ' 通过匹配首单词来决定下一步的工作
    Select Case GetWords(sentence)(0)
      Case "$GPRMC"      ' 一条“推荐最小”的语句被找到!
        Return ParseGPRMC(sentence)
      Case Else
        ' 标示这条语句为不可用
        Return False
    End Select
  End Function
  ' 将语句分解为单词
  Public Function GetWords(ByVal sentence As String) As String()
    Return sentence.Split(","c)
  End Function
  ' 描述 $GPRMC 消息
  Public Function ParseGPRMC(ByVal sentence As String) As Boolean
    ' 将语句分解为单词
    Dim Words() As String = GetWords(sentence)
    ' 我们是否有足够的数据来描述当前位置?
    If Words(3) <> "" And Words(4) <> "" And Words(5) <> "" And _
      Words(6) <> "" Then
      ' 是,则提取纬度和经度
      Dim Latitude As String = Words(3).Substring(0, 2) & "°" ' 获取度
      Latitude = Latitude & Words(3).Substring(2) & """"      ' 获取分
      Latitude = Latitude & Words(4)    ' 获取半球
      Dim Longitude As String = Words(5).Substring(0, 3) & "°" ' 获取度
      Longitude = Longitude & Words(5).Substring(3) & """"    ' 获取分
      Longitude = Longitude & Words(6)    ' 获取半球
      ' 将该变化通知应用程序
      RaiseEvent PositionReceived(Latitude, Longitude)
    End If
    ' 表示该语句可用
    Return True
  End Function
End Class

当然,我们肯定注意到了当没有接受到任何信息时,有些GPS设
备将报告空值。因此,在解意描述前先判断每个单词是一个很不错的想法。如果你需要打度的符号(°),那么按Alt健并且用数字键盘输入“0176”就OK了。

检验和(Checksum)就是采用XOR的方法来计算美元符($)和星号(*)之间的字节。这个检验和是用来与语句的检验和比较的。如果检验和不匹配, 语句将被弃用。这个做法是很有效的,因为GPS设备每隔很短的时间就返回一批相同的信息。利用检验和的比较能力,描述就可以剔除每一无效的语句。清单 1-3 扩展描述器类来完成这个功能。

清单 1-3:这个描述器可以检测错误并且仅仅解意释放错误NMEA数据

'**  清单 1-3. 检测并处理NMEA错误
'*******************************
Public Class NmeaInterpreter
  ' 当前位置变化时,记录新位置
  Public Event PositionReceived(ByVal latitude As String, _
                                ByVal longitude As String)
  ' 处理GPS接收器的信息
  Public Function Parse(ByVal sentence As String) As Boolean
    ' 如果检验和不能和我们计算的检验和匹配,那么丢弃它
    If Not IsValid(sentence) Then Return False
    ' 通过匹配首单词来决定下一步的工作
    Select Case GetWords(sentence)(0)
      Case "$GPRMC"      ' 一条“推荐最小”的语句被找到!
        Return ParseGPRMC(sentence)
      Case Else
        ' 标示这条语句为不可用
        Return False
    End Select
  End Function
  ' 将语句分解为单词
  Public Function GetWords(ByVal sentence As String) As String()
    Return sentence.Split(","c)
  End Function
  ' 描述 $GPRMC 消息
  Public Function ParseGPRMC(ByVal sentence As String) As Boolean
    ' 将语句分解为单词
    Dim Words() As String = GetWords(sentence)
    ' 我们是否有足够的数据来描述当前位置?
    If Words(3) <> "" And Words(4) <> "" And Words(5) <> "" And _
      Words(6) <> "" Then
      ' 是,则提取纬度和经度
      Dim Latitude As String = Words(3).Substring(0, 2) & "°" ' 获取度
      Latitude = Latitude & Words(3).Substring(2) & """"      ' 获取分
      Latitude = Latitude & Words(4)    ' 获取半球
      Dim Longitude As String = Words(5).Substring(0, 3) & "°" ' 获取度
      Longitude = Longitude & Words(5).Substring(3) & """"    ' 获取分
      Longitude = Longitude & Words(6)    ' 获取半球

 ' 将该变化通知应用程序
      RaiseEvent PositionReceived(Latitude, Longitude)
    End If
    ' 表示该语句可用
    Return True
  End Function
  ' 如果检验和匹配,则返回TRUE
  Public Function IsValid(ByVal sentence As String) As Boolean
    ' 星号计算后比较字符
    Return sentence.Substring(sentence.IndexOf("*") + 1) = GetChecksum(sentence)
  End Function
  ' 计算语句的检验和
  Public Function GetChecksum(ByVal sentence As String) As String
    ' 通过循环获得检验和
    Dim Character As Char
    Dim Checksum As Integer
    For Each Character In sentence
      Select Case Character
        Case "$"c
          ' 忽略美元符号
        Case "*"c
          ' 遇到星号则停止计算
          Exit For
        Case Else
          ' 是否为检验和的第一个值?
          If Checksum = 0 Then
            ' 是。将该值赋给检验和
            Checksum = Convert.ToByte(Character)
          Else
            ' 否。采用XOR算法和当前检验和值计算,并将结构赋给检验和
            Checksum = Checksum Xor Convert.ToByte(Character)
          End If
      End Select
    Next
    ' 返回一个十六进制的检验和
    Return Checksum.ToString("X2")
  End Function
End Class

时间是GPS技术的基础,因为距离通过光速来测量得到的。每个GPS卫星包含四个原子钟,它将在一段以十亿分之一秒为单位的时间内计量它的射线传播。一个 强大的特性是仅用很少的代码,这些原子钟可以和精确到毫秒的电脑钟同步。$GPRMC语句的第二个单词(040302.663)包含了卫星时间,这个时间 是用压缩格式表示的。头两个字符表示小时,接下来两个字符表示分钟,再下来两个字符表示秒,最后小数部分表示毫秒。因此,这个时间是4:03: 02.663 AM。然而,卫星报告的时间是国际时间(GMT+0),因此,这个时间必须被调整到区域的当地时间。清单 1-4 添加支持将卫星时间利用DateTime.ToLocalTime方法转换到当地时间的功能。

清单 1-4:这个类可以无线地即时将原子钟同步到你的电脑钟

'********************************************************
'**  Listing 1-4.  Add support for satellite-derived time
'********************************************************
Public Class 

NmeaInterpreter
  ' Raised when the current location has changed
  Public Event PositionReceived(ByVal latitude As String, _
                                ByVal longitude As String)
  Public Event DateTimeChanged(ByVal dateTime As DateTime)
  ' Processes information from the GPS receiver
  Public Function Parse(ByVal sentence As String) As Boolean
    ' Discard the sentence if its checksum does not match our    
    ' calculated checksum
    If Not IsValid(sentence) Then Return False
    ' Look at the first word to decide where to go next
    Select Case GetWords(sentence)(0)
      Case "$GPRMC"      ' A "Recommended Minimum" sentence was found!
        Return ParseGPRMC(sentence)
      Case Else
        ' Indicate that the sentence was not recognized
        Return False
    End Select
  End Function
  ' Divides a sentence into individual words
  Public Function GetWords(ByVal sentence As String) As String()
    Return sentence.Split(","c)
  End Function
  ' Interprets a $GPRMC message
  Public Function ParseGPRMC(ByVal sentence As String) As Boolean
    ' Divide the sentence into words
    Dim Words() As String = GetWords(sentence)
    ' Do we have enough values to describe our location?
    If Words(3) <> "" And Words(4) <> "" And Words(5) <> "" And _      
      Words(6) <> "" Then
      ' Yes. Extract latitude and longitude
      Dim Latitude As String = Words(3).Substring(0, 2) & "°" ' Append hours
      Latitude = Latitude & Words(3).Substring(2) & """"    ' Append minutes
      Latitude = Latitude & Words(4)    ' Append the hemisphere
      Dim Longitude As String = Words(5).Substring(0, 3) & "°" ' Append hours
      Longitude = Longitude & Words(5).Substring(3) & """"    ' Append minutes
      Longitude = Longitude & Words(6)    ' Append the hemisphere
      ' Notify the calling application of the change
      RaiseEvent PositionReceived(Latitude, Longitude)
    End If
    ' Do we have enough values

to parse satellite-derived time?
    If Words(1) <> "" Then
      ' Yes. Extract hours, minutes, seconds and milliseconds
      Dim UtcHours As Integer = CType(Words(1).Substring(0, 2), Integer)
      Dim UtcMinutes As Integer = CType(Words(1).Substring(2, 2), Integer)
      Dim UtcSeconds As Integer = CType(Words(1).Substring(4, 2), Integer)
      Dim UtcMilliseconds As Integer
      ' Extract milliseconds if it is available
      If Words(1).Length > 7 Then
          UtcMilliseconds = CType(Words(1).Substring(7), Integer)
      End If
      ' Now build a DateTime object with all values
      Dim Today As DateTime = System.DateTime.Now.ToUniversalTime
      Dim SatelliteTime As New System.DateTime(Today.Year, Today.Month, _
        Today.Day, UtcHours, UtcMinutes, UtcSeconds, UtcMilliseconds)
      ' Notify of the new time, adjusted to the local time zone

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -