将 ser.readline() 编码为 UTF-8

问题描述 投票:0回答:2

我有一个 Neo 6M GPS 模块,我正在尝试从中打印坐标。目前它正在以字节形式打印 NMEA 句子,并在末尾添加

\r\n
。这是一个例子:

b'$GPGGA,161812.371,4042.759,N,07400.317,W,1,12,1.0,0.0,M,0.0,M,,*7B\r\n'

要将字符串解析为坐标,我需要去掉

\r
\n
b' '

为此,我正在尝试 .strip("b'rn\")。事实证明,您只能删除字符串,而不能删除字节。 为了克服字节和条带的不兼容,我尝试将字节解码为字符串,如下所示:

(ser.readline().decode("utf-8")).strip("b'rn\\")

这不会运行,我收到此错误:

Traceback (most recent call last):
  File "gps2.py", line 10, in <module>
    newdata = (ser.readline().decode("utf-8")).strip("b'rn\\")
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xfe in position 0: invalid start byte

下面是我的代码。有谁能够帮助我解码并剥离它,或者以另一种方式摆脱

\r
\n
b' '

import serial
import time
import string
import pynmea2

while True:
    port = "/dev/ttyAMA0"
    ser = serial.Serial(port,baudrate=9600,timeout=0.5)
    dataout = pynmea2.NMEAStreamReader()
    newdata = (ser.readline().decode("utf-8")).strip("b'rn\\")

    if newdata[0:6] == "$GPRMC":
        newmsg = pynmea2.parse(newdata)
        lat = newmsg.latitude
        lng = newmsg.longitude
        gps = ("Latitude = " + str(lat) + " and Longitude = " +str(lng))
        print(gps)
    elif newdata[0:6] == "$GPGLL":
        print("Found GPGLL record: " + newdata)
    else:
        print(newdata)
python gps byte nmea
2个回答
1
投票

注意: 当原始评论变得比评论更长时,我将其更改为答案,以回应OP对原始问题的放大。

你无法摆脱

b' '
。数据里没有。这是 Python 约定,表明您的数据是字节串而不是常规字符串。调用
decode()
会将字节串转换为字符串。另一方面,数据中的
\r\n
。它表明您的设备正在以回车/换行对终止字符串。这两个都算作空白。开头的字符0xfe
是字节顺序标记对
\xfe\xff
的第一部分,可以丢弃。所以你所需要的只是
ser.readline()[2:].decode("utf-8").strip()

至于您在问题中没有提到的不可解释的数据,仅在后续评论中提到:

无论是设备还是其文档,我只能推测您在所需数据前面得到的明显二进制数据。它当然不是我可以识别的任何类型的字符数据:它不是 UTF-8,也不是有效的 UTF-16,而且我的预感是它也不是东亚 MBCS。它不太可能是浮点数或整数,因为没有一个零字节,而二进制数字数据(和 UTF-32)往往有很多这样的字节。

但是,如果您想要的数据以像

$GPGGA,

 这样的已知常量开头,那么从获得的流中选择您想要的数据应该不会很困难。例如,假设您得到

b'i\x9a\xcab\x82\xbab\x8a\xb2b\x92\xc2b\x92\xca\x9ab\x8a\xa2R\xba\xc2jR":A\x1dMY\xb1\xcd\xb1\xc9\xb1\xc5\xc1\xb1\xc5\xe1\xb1\xd1\xd9\xb1\xc5\xd5\xdd\xb1\xc9\xc1\xb1\xc9\xd5\xb1\xc9\xd5\xb1\xc5\xc5\xd9\xb1\xc5\xd1\xb1\xc9\xd9\xb1\xd9\xc5\xb1\xc9\xe5\xc9\xb1\xc5\xd1\xb1\xc9\xdd\xb1\xc1\xc9\xb1\xc9\xd1\xdd\xb1\xc1\xd9\xa9\xdd\x195)\x91\x1dA\x1dMY\xb1\xcd\xb1\xcd\xb1\xc5\xc1\xb1\xc9\xe5\xb1\xd5\xd9\xb1\xc1\xd9\xcd\xb1\xc9\xd1\xb1\xcd\xc5\xb1\xd1\xe5\xb1\xc9\xc1\xe5\xb1\xc5\xd5\xa9\xdd\xcd5)\x91\x1dA\x1d11\xb1\xd5\xc5\xc9\xd5\xb9\xe5\xe5\xc1\xc5\xe1\xb19\xb1\xc1\xc1\xc1\xc9\xd5\xb9\xd5\xe1\xd1\xc1\xcd\xb1]\xb1\xc9\xc1\xc1\xdd\xcd\xd9\xb9\xc1\xc1\xb1\x05\xb1\x05\xa9\xdd\r5)\xff\xfe\xff$GPGGA,161812.371,4042.759,N,07400.317,W,1,12,1.0,0.0,M,0.0,M,,*7B\r\n'
(其中大部分是从您的 Pastebin 内容中复制的)并将其存储在 

dataout

 中。然后 
dataout.partition(b'$GPGGA,')[-1].decode().strip()
 将为您提供您期望的数字,无论 
$GPGGA,
 左侧是否存在无法解释的二进制数据。

站在你的立场上,我仍然想知道二进制数据是什么。我认为这更有可能是由串行数据传输的复杂性引起的,而不是设备中的任何缺陷造成的。我的猜测是,它是真实数据,但可能带有意外的数据位(

pySerial

 称为 
bytesize)、停止位或奇偶校验。您对 serial.Serial()
 的调用采用默认值:8 个数据位、无奇偶校验、1 个停止位。我不知道
serial
模块有多聪明,但它可能在看到一些数据后可以从错误的初始值中恢复。 25 年前,调制解调器可以通过查看(无可否认,是预先指定的)数据的前 2 个字节来做到这一点。


© www.soinside.com 2019 - 2024. All rights reserved.