golang实现从串口读取GPS信息

来源:互联网 发布:中国社科院大学知乎 编辑:程序博客网 时间:2024/06/07 06:09

GPS模块的数据格式

对GPS模块的数据处理本质上还是串口通信程序设计,只是GPS模块的输出遵循固定的格式,通过字符串检索查找即可从模块发送的数据中找出需要的数据,常用的GPS模块大多采用NMEA-0183 协议。NMEA-0183 是美国国家海洋电子协会(National Marine Electronics Association)所指定的标准规格,这一标准制订所有航海电子仪器间的通讯标准,其中包含传输资料的格式以及传输资料的通讯协议。

以下是一组正常的GPS 数据

$GPGGA,082006.000,3852.9276,N,11527.4283,E,1,08,1.0,20.6,M,,,,0000*35

$GPRMC,082006.000,A,3852.9276,N,11527.4283,E,0.00,0.0,261009,,*38

$GPVTG,0.0,T,,M,0.00,N,0.0,K*50

下面分别对每组数据的含义进行分析。

GPS 固定数据输出语句($GPGGA),这是一帧GPS 定位的主要数据,也是使用最广的数据。为了便于理解,下面举例说明$GPGGA语句各部分的含义。

例:$GPGGA,082006.000,3852.9276,N,11527.4283,E,1,08,1.0,20.6,M,,,,0000*35

其标准格式为:

$GPGGA,(1),(2),(3),(4),(5),(6),(7),(8),(9),M,(10),M,(11),(12)*hh(CR)(LF)

各部分所对应的含义为:

(1) 定位UTC 时间:08 时20 分06 秒

(2) 纬度(格式ddmm.mmmm:即dd 度,mm.mmmm 分);

(3) N/S(北纬或南纬):北纬38 度52.9276 分;

(4) 经度(格式dddmm.mmmm:即ddd 度,mm.mmmm 分);

(5) E/W(东经或西经):东经115 度27.4283 分;

(6) 质量因子(0=没有定位,1=实时GPS,2=差分GPS):1=实时GPS;

(7) 可使用的卫星数(0~8):可使用的卫星数=08;

(8) 水平精度因子(1.0~99.9);水平精度因子=1.0;

(9) 天线高程(海平面,-9999.9~99999.9,单位:m);天线高程=20.6m);

(10) 大地椭球面相对海平面的高度(-999.9~9999.9,单位:m):无;

(11) 差分GPS 数据年龄,实时GPS 时无:无;

(12) 差分基准站号(0000~1023),实时GPS 时无:无;

*总和校验域;hh 总和校验数:35(CR)(LF)回车,换行。

GPRMC(建议使用最小GPS 数据格式)

$GPRMC,082006.000,A,3852.9276,N,11527.4283,E,0.00,0.0,261009,,*38

$GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11><CR><LF>

(1) 标准定位时间(UTC time)格式:时时分分秒秒.秒秒秒(hhmmss.sss)。

(2) 定位状态,A = 数据可用,V = 数据不可用。

(3) 纬度,格式:度度分分.分分分分(ddmm.mmmm)。

(4) 纬度区分,北半球(N)或南半球(S)。

(5) 经度,格式:度度分分.分分分分。

(6) 经度区分,东(E)半球或西(W)半球。

(7) 相对位移速度, 0.0 至1851.8 knots

(8) 相对位移方向,000.0 至359.9 度。实际值。

(9) 日期,格式:日日月月年年(ddmmyy)。

(10) 磁极变量,000.0 至180.0。

(11) 度数。

(12) Checksum.(检查位)

$GPVTG 地面速度信息

例:$GPVTG,0.0,T,,M,0.00,N,0.0,K*50

字段0:$GPVTG,语句ID,表明该语句为Track Made Good and Ground Speed(VTG)地

面速度信息

字段1:运动角度,000 - 359,(前导位数不足则补0)

字段2:T=真北参照系

字段3:运动角度,000 - 359,(前导位数不足则补0)

字段4:M=磁北参照系

字段5:水平运动速度(0.00)(前导位数不足则补0)

字段6:N=节,Knots

字段7:水平运动速度(0.00)(前导位数不足则补0)

字段8:K=公里/时,km/h

字段9:校验值

以环天BU353 路测USB GPS为例,该GPS模块的主要参数:http://jn.goepe.com/apollo/show_product1.php?id=2164028&uid=zhaogis

GPS模块的驱动安装

驱动程序可以去官网下载,下载地址:http://usglobalsat.com/s-24-support-drivers.aspx

备用下载地址:http://usglobalsat.com/s-172-bu-353-s4-support.aspx

GPS模块的应用程序设计

实现读取并解析GPS信息的代码如下:

package modelimport (//"fmt"//"infrastructure/log"//"io""math""strconv""strings""time""infrastructure/github.com/serial")type GpsInfo struct {Longitude       stringLatitude        stringLonDirection    stringLatDirection    stringLongitudeRadian float64LatitudeRadian  float64IsGpsNormal     bool}type ComObject struct {ComName  stringBaudrate int//Com         io.ReadWriteCloserCom         *serial.SerialPortIsComNormal boolCloseChan   chan bool}var (ComName = "COM3"ComObj  = &ComObject{ComName: ComName, Baudrate: 4800, IsComNormal: false, CloseChan: make(chan bool, 1)}GpsObj               = &GpsInfo{IsGpsNormal: false}BsGpsObj             = &GpsInfo{IsGpsNormal: true, LonDirection: "E", LongitudeRadian: 116.63, LatDirection: "N", LatitudeRadian: 40.32}UeBsDistance float64 = 0directionMap = map[string]string{"N": "北纬","S": "南纬","E": "东经","W": "西经",})func StartGpsModule() {ComObj.ComName = ComNameif true == ComObj.GetPortName() {ComName = ComObj.ComName}for {if true == ComObj.IsComNormal {<-ComObj.CloseChanComObj.IsComNormal = falseGpsObj.IsGpsNormal = falsecontinue}time.Sleep(time.Second * 5)if false == ComObj.GetPortName() {continue}err := ComObj.OpenCom()if nil != err {GpsObj.IsGpsNormal = falsecontinue} else {ComObj.IsComNormal = true}go ComObj.ReceiveFromCom()}}func (this *ComObject) GetPortName() bool {ports, err := serial.GetPortsList()if nil != err || 0 == len(ports) {return false}this.ComName = ports[0]return true//for _, port := range ports {//fmt.Printf("Found port: %v\n", port)//}}func (this *ComObject) OpenCom() (err error) {mode := &serial.Mode{BaudRate: 4800,DataBits: 8,Parity:   serial.PARITY_NONE,StopBits: serial.STOPBITS_ONE,}s, err := serial.OpenPort(this.ComName, mode)if nil != err {//log.Error("pkg: model, func: OpenCom, method: goserial.OpenPort, errInfo:", err)return}this.Com = sreturn nil}func (this *ComObject) Close() {this.Com.Close()this.CloseChan <- true}func (this *ComObject) ReceiveFromCom() {defer this.Close()buf := make([]byte, 512)for {time.Sleep(time.Second)n, err := this.Com.Read(buf[0:])if nil != err {//log.Error("pkg: model, func: ReceiveFromCom, method: this.Com.Read, errInfo:", err)return}parseGpsInfo(string(buf[:n]))//fmt.Println("parseRst:", GpsObj)}}func parseGpsInfo(gpsInfo string) {var parseSuccessfulFlag bool = falsestrLineSlice := strings.Split(gpsInfo, "\n")if 0 == len(strLineSlice) {GpsObj.IsGpsNormal = falsereturn}for _, oneLine := range strLineSlice {if 0 == len(oneLine) {continue}if '$' != oneLine[0] {continue}if !strings.Contains(oneLine, "*") {continue}if !strings.Contains(oneLine, "N") && !strings.Contains(oneLine, "S") {continue}if !strings.Contains(oneLine, "E") && !strings.Contains(oneLine, "W") {continue}if strings.Contains(oneLine, "GPGGA") {if false == parseLongitudeAndLatitudeFromGpgga(oneLine) {continue}parseSuccessfulFlag = truebreak}if strings.Contains(oneLine, "GPRMC") {if false == parseLongitudeAndLatitudeFromGprmc(oneLine) {continue}parseSuccessfulFlag = truebreak}}if true == parseSuccessfulFlag {GpsObj.IsGpsNormal = trueUeBsDistance = CalcDistByLongitudeLantitude(*GpsObj, *BsGpsObj)} else {GpsObj.IsGpsNormal = falseUeBsDistance = 0}}func parseLongitudeAndLatitudeFromGpgga(gpggaInfo string) bool {strSlice := strings.Split(gpggaInfo, ",")if 3 > len(strSlice[2]) || 4 > len(strSlice[4]) {return false}GpsObj.LatDirection = strSlice[3]GpsObj.LonDirection = strSlice[5]GpsObj.Latitude = directionMap[strSlice[3]] + strSlice[2][:2] + "度" + strSlice[2][2:] + "分"GpsObj.Longitude = directionMap[strSlice[5]] + strSlice[4][:3] + "度" + strSlice[4][3:] + "分"tmpIntPartLat, _ := strconv.ParseFloat(strSlice[2][:2], 32)tmpDecimalPartLat, _ := strconv.ParseFloat(strSlice[2][2:], 32)GpsObj.LatitudeRadian = tmpIntPartLat + tmpDecimalPartLat/60tmpIntPartLon, _ := strconv.ParseFloat(strSlice[4][:3], 32)tmpDecimalPartLon, _ := strconv.ParseFloat(strSlice[4][3:], 32)GpsObj.LongitudeRadian = tmpIntPartLon + tmpDecimalPartLon/60return true}func parseLongitudeAndLatitudeFromGprmc(gprmcInfo string) bool {strSlice := strings.Split(gprmcInfo, ",")if 3 > len(strSlice[3]) || 4 > len(strSlice[5]) {return false}GpsObj.LatDirection = strSlice[4]GpsObj.LonDirection = strSlice[6]GpsObj.Latitude = directionMap[strSlice[4]] + strSlice[3][:2] + "度" + strSlice[3][2:] + "分"GpsObj.Longitude = directionMap[strSlice[6]] + strSlice[5][:3] + "度" + strSlice[5][3:] + "分"tmpIntPartLat, _ := strconv.ParseFloat(strSlice[3][:2], 32)tmpDecimalPartLat, _ := strconv.ParseFloat(strSlice[3][2:], 32)GpsObj.LatitudeRadian = tmpIntPartLat + tmpDecimalPartLat/60tmpIntPartLon, _ := strconv.ParseFloat(strSlice[5][:3], 32)tmpDecimalPartLon, _ := strconv.ParseFloat(strSlice[5][3:], 32)GpsObj.LongitudeRadian = tmpIntPartLon + tmpDecimalPartLon/60return true}func CalcDistByLongitudeLantitude(gpsPointA, gpsPointB GpsInfo) (distance float64) {if false == gpsPointA.IsGpsNormal || false == gpsPointB.IsGpsNormal {return 0}lonA, latA := getFormatedLongitudeLantitude(gpsPointA)lonB, latB := getFormatedLongitudeLantitude(gpsPointB)c := math.Sin(latA*math.Pi/180)*math.Sin(latB*math.Pi/180)*math.Cos((lonA-lonB)*math.Pi/180) + math.Cos(latA*math.Pi/180)*math.Cos(latB*math.Pi/180)distance = 6371004 * math.Acos(c)return}func getFormatedLongitudeLantitude(gpsPoint GpsInfo) (lon, lat float64) {if "E" == gpsPoint.LonDirection {lon = gpsPoint.LongitudeRadian} else {lon = 0 - gpsPoint.LongitudeRadian}if "N" == gpsPoint.LatDirection {lat = 90 - gpsPoint.LatitudeRadian} else {lat = 90 + gpsPoint.LatitudeRadian}return}

可参考:http://studygolang.com/articles/302

golang实现对串口的操作的库:https://github.com/huin/goserial

0 0
原创粉丝点击