无法通过串口解析GPS信息
Unable to parse GPS information via serial port
我使用了以下软件包:
- 从串口读取(
go get go.bug.st/serial
)
- 解析串口传入的消息(
go get adrianmo/go-nmea
)
主机: Windows 10
转版本: 转版本go1.14.4 windows/amd64
根据文档我写了一个简单的代码打开专用串口(COM4
)并从端口读取NMEA数据并尝试根据go-nmea
包解析数据
数据
来自 GPS 传感器的传入数据:
$GPRMC,135533.000,A,5306.6644,N,00851.3177,E,0.11,214.59,300620,,,A*6E
$GPRMC,135534.000,A,5306.6643,N,00851.3177,E,0.06,187.72,300620,,,A*68
$GPRMC,135535.000,A,5306.6643,N,00851.3177,E,0.22,341.68,300620,,,A*6C
$GPRMC,135536.000,A,5306.6644,N,00851.3176,E,0.20,324.35,300620,,,A*60
$GPRMC,135537.000,A,5306.6645,N,00851.3176,E,0.12,348.37,300620,,,A*69
代码片段
package main
import (
"fmt"
"log"
"github.com/adrianmo/go-nmea"
"go.bug.st/serial"
)
func main() {
mode := &serial.Mode{
BaudRate: 9600,
Parity: serial.NoParity,
DataBits: 8,
StopBits: serial.OneStopBit,
}
serPort, err := serial.Open("COM4", mode)
if err != nil {
log.Fatal(err)
}
defer serPort.Close()
buff := make([]byte, 1024)
for {
n, err := serPort.Read(buff)
if err != nil {
log.Fatal(err)
break
}
if n == 0 {
fmt.Println("\nEOF")
break
}
rawSentence := string(buff[:n])
fmt.Print(rawSentence)
s, err := nmea.Parse(rawSentence)
if err != nil {
log.Fatal(err)
}
if s.DataType() == nmea.TypeRMC {
m := s.(nmea.RMC)
fmt.Printf("Raw sentence: %v\n", m)
fmt.Printf("Time: %s\n", m.Time)
fmt.Printf("Validity: %s\n", m.Validity)
fmt.Printf("Latitude GPS: %s\n", nmea.FormatGPS(m.Latitude))
fmt.Printf("Latitude DMS: %s\n", nmea.FormatDMS(m.Latitude))
fmt.Printf("Longitude GPS: %s\n", nmea.FormatGPS(m.Longitude))
fmt.Printf("Longitude DMS: %s\n", nmea.FormatDMS(m.Longitude))
fmt.Printf("Speed: %f\n", m.Speed)
fmt.Printf("Course: %f\n", m.Course)
fmt.Printf("Date: %s\n", m.Date)
fmt.Printf("Variation: %f\n", m.Variation)
}
}
}
问题
如果我 运行 代码我得到以下错误:
2020/06/30 16:02:16 nmea: sentence does not start with a '$' or '!'
exit status 1
这很奇怪,因为如果我注释掉代码解析代码:
// s, err := nmea.Parse(rawSentence)
// if err != nil {
// log.Fatal(err)
// }
// if s.DataType() == nmea.TypeRMC {
// m := s.(nmea.RMC)
// fmt.Printf("Raw sentence: %v\n", m)
// fmt.Printf("Time: %s\n", m.Time)
// fmt.Printf("Validity: %s\n", m.Validity)
// fmt.Printf("Latitude GPS: %s\n", nmea.FormatGPS(m.Latitude))
// fmt.Printf("Latitude DMS: %s\n", nmea.FormatDMS(m.Latitude))
// fmt.Printf("Longitude GPS: %s\n", nmea.FormatGPS(m.Longitude))
// fmt.Printf("Longitude DMS: %s\n", nmea.FormatDMS(m.Longitude))
// fmt.Printf("Speed: %f\n", m.Speed)
// fmt.Printf("Course: %f\n", m.Course)
// fmt.Printf("Date: %s\n", m.Date)
// fmt.Printf("Variation: %f\n", m.Variation)
// }
串口打印GPS坐标,如上所述。
我哪里错了?我尝试通过在代码中执行以下操作来删除 new-line 和 carriage-return:
rawSentence := string(buff[:n])
rawSentence = string.ReplaceAll(rawSentence, "\r\n", "")
fmt.Print(rawSentence)
但我仍然得到同样的错误。
我能够找出问题所在。我首先检查我的字节是如何从以下代码中读取的:
n, err := serPort.Read(buff)
fmt.Printf("%d", n)
它依次给出值1
和73
、74
。假设 1
是设备本身发送的换行符,我发现这可能是代码无法捕获 $GPRMC
.
的原因
因此我修改了我的代码以检查读取的字节数是否总是大于 1 个字节
for {
n, err := serPort.Read(buff)
fmt.Printf("%v\n", n)
if err != nil {
log.Fatal(err)
break
}
// do not try to parse a single read byte
// instead parse the actual incoming string.
if n > 1 {
rawSentence := string(buff[:n])
fmt.Print(rawSentence)
s, err := nmea.Parse(rawSentence)
if err != nil {
log.Fatal(err)
}
if s.DataType() == nmea.TypeRMC {
m := s.(nmea.RMC)
fmt.Printf("Raw sentence: %v\n", m)
fmt.Printf("Time: %s\n", m.Time)
fmt.Printf("Validity: %s\n", m.Validity)
fmt.Printf("Latitude GPS: %s\n", nmea.FormatGPS(m.Latitude))
fmt.Printf("Latitude DMS: %s\n", nmea.FormatDMS(m.Latitude))
fmt.Printf("Longitude GPS: %s\n", nmea.FormatGPS(m.Longitude))
fmt.Printf("Longitude DMS: %s\n", nmea.FormatDMS(m.Longitude))
fmt.Printf("Speed: %f\n", m.Speed)
fmt.Printf("Course: %f\n", m.Course)
fmt.Printf("Date: %s\n", m.Date)
fmt.Printf("Variation: %f\n", m.Variation)
}
}
}
果然,代码现在可以运行了,导出的输出正是我所期望的:
$GPRMC,142312.000,A,5306.6774,N,00851.3114,E,0.04,14.48,300620,,,A*5A
Raw sentence: $GPRMC,142312.000,A,5306.6774,N,00851.3114,E,0.04,14.48,300620,,,A*5A
Time: 14:23:12.0000
Validity: A
Latitude GPS: 5306.6774
Latitude DMS: 53° 6' 40.644000"
Longitude GPS: 851.3114
Longitude DMS: 8° 51' 18.684000"
Speed: 0.040000
Course: 14.480000
Date: 30/06/20
Variation: 0.000000
我使用了以下软件包:
- 从串口读取(
go get go.bug.st/serial
) - 解析串口传入的消息(
go get adrianmo/go-nmea
)
主机: Windows 10
转版本: 转版本go1.14.4 windows/amd64
根据文档我写了一个简单的代码打开专用串口(COM4
)并从端口读取NMEA数据并尝试根据go-nmea
包解析数据
数据
来自 GPS 传感器的传入数据:
$GPRMC,135533.000,A,5306.6644,N,00851.3177,E,0.11,214.59,300620,,,A*6E
$GPRMC,135534.000,A,5306.6643,N,00851.3177,E,0.06,187.72,300620,,,A*68
$GPRMC,135535.000,A,5306.6643,N,00851.3177,E,0.22,341.68,300620,,,A*6C
$GPRMC,135536.000,A,5306.6644,N,00851.3176,E,0.20,324.35,300620,,,A*60
$GPRMC,135537.000,A,5306.6645,N,00851.3176,E,0.12,348.37,300620,,,A*69
代码片段
package main
import (
"fmt"
"log"
"github.com/adrianmo/go-nmea"
"go.bug.st/serial"
)
func main() {
mode := &serial.Mode{
BaudRate: 9600,
Parity: serial.NoParity,
DataBits: 8,
StopBits: serial.OneStopBit,
}
serPort, err := serial.Open("COM4", mode)
if err != nil {
log.Fatal(err)
}
defer serPort.Close()
buff := make([]byte, 1024)
for {
n, err := serPort.Read(buff)
if err != nil {
log.Fatal(err)
break
}
if n == 0 {
fmt.Println("\nEOF")
break
}
rawSentence := string(buff[:n])
fmt.Print(rawSentence)
s, err := nmea.Parse(rawSentence)
if err != nil {
log.Fatal(err)
}
if s.DataType() == nmea.TypeRMC {
m := s.(nmea.RMC)
fmt.Printf("Raw sentence: %v\n", m)
fmt.Printf("Time: %s\n", m.Time)
fmt.Printf("Validity: %s\n", m.Validity)
fmt.Printf("Latitude GPS: %s\n", nmea.FormatGPS(m.Latitude))
fmt.Printf("Latitude DMS: %s\n", nmea.FormatDMS(m.Latitude))
fmt.Printf("Longitude GPS: %s\n", nmea.FormatGPS(m.Longitude))
fmt.Printf("Longitude DMS: %s\n", nmea.FormatDMS(m.Longitude))
fmt.Printf("Speed: %f\n", m.Speed)
fmt.Printf("Course: %f\n", m.Course)
fmt.Printf("Date: %s\n", m.Date)
fmt.Printf("Variation: %f\n", m.Variation)
}
}
}
问题
如果我 运行 代码我得到以下错误:
2020/06/30 16:02:16 nmea: sentence does not start with a '$' or '!'
exit status 1
这很奇怪,因为如果我注释掉代码解析代码:
// s, err := nmea.Parse(rawSentence)
// if err != nil {
// log.Fatal(err)
// }
// if s.DataType() == nmea.TypeRMC {
// m := s.(nmea.RMC)
// fmt.Printf("Raw sentence: %v\n", m)
// fmt.Printf("Time: %s\n", m.Time)
// fmt.Printf("Validity: %s\n", m.Validity)
// fmt.Printf("Latitude GPS: %s\n", nmea.FormatGPS(m.Latitude))
// fmt.Printf("Latitude DMS: %s\n", nmea.FormatDMS(m.Latitude))
// fmt.Printf("Longitude GPS: %s\n", nmea.FormatGPS(m.Longitude))
// fmt.Printf("Longitude DMS: %s\n", nmea.FormatDMS(m.Longitude))
// fmt.Printf("Speed: %f\n", m.Speed)
// fmt.Printf("Course: %f\n", m.Course)
// fmt.Printf("Date: %s\n", m.Date)
// fmt.Printf("Variation: %f\n", m.Variation)
// }
串口打印GPS坐标,如上所述。
我哪里错了?我尝试通过在代码中执行以下操作来删除 new-line 和 carriage-return:
rawSentence := string(buff[:n])
rawSentence = string.ReplaceAll(rawSentence, "\r\n", "")
fmt.Print(rawSentence)
但我仍然得到同样的错误。
我能够找出问题所在。我首先检查我的字节是如何从以下代码中读取的:
n, err := serPort.Read(buff)
fmt.Printf("%d", n)
它依次给出值1
和73
、74
。假设 1
是设备本身发送的换行符,我发现这可能是代码无法捕获 $GPRMC
.
因此我修改了我的代码以检查读取的字节数是否总是大于 1 个字节
for {
n, err := serPort.Read(buff)
fmt.Printf("%v\n", n)
if err != nil {
log.Fatal(err)
break
}
// do not try to parse a single read byte
// instead parse the actual incoming string.
if n > 1 {
rawSentence := string(buff[:n])
fmt.Print(rawSentence)
s, err := nmea.Parse(rawSentence)
if err != nil {
log.Fatal(err)
}
if s.DataType() == nmea.TypeRMC {
m := s.(nmea.RMC)
fmt.Printf("Raw sentence: %v\n", m)
fmt.Printf("Time: %s\n", m.Time)
fmt.Printf("Validity: %s\n", m.Validity)
fmt.Printf("Latitude GPS: %s\n", nmea.FormatGPS(m.Latitude))
fmt.Printf("Latitude DMS: %s\n", nmea.FormatDMS(m.Latitude))
fmt.Printf("Longitude GPS: %s\n", nmea.FormatGPS(m.Longitude))
fmt.Printf("Longitude DMS: %s\n", nmea.FormatDMS(m.Longitude))
fmt.Printf("Speed: %f\n", m.Speed)
fmt.Printf("Course: %f\n", m.Course)
fmt.Printf("Date: %s\n", m.Date)
fmt.Printf("Variation: %f\n", m.Variation)
}
}
}
果然,代码现在可以运行了,导出的输出正是我所期望的:
$GPRMC,142312.000,A,5306.6774,N,00851.3114,E,0.04,14.48,300620,,,A*5A
Raw sentence: $GPRMC,142312.000,A,5306.6774,N,00851.3114,E,0.04,14.48,300620,,,A*5A
Time: 14:23:12.0000
Validity: A
Latitude GPS: 5306.6774
Latitude DMS: 53° 6' 40.644000"
Longitude GPS: 851.3114
Longitude DMS: 8° 51' 18.684000"
Speed: 0.040000
Course: 14.480000
Date: 30/06/20
Variation: 0.000000