繁体   English   中英

如何使用 arduino 和 pyserial 从串口解码信息

[英]How to decode information from the serial port using arduino and pyserial

我想读取通过 Arduino 串口发送的信息。为此,我使用 pyserial,初始化端口,然后尝试读取信息。

这是 Arduino 代码

void setup() {
  Serial.begin(9600);
}

void loop() {
  Serial.println("1");
}

这是 python 代码

import serial
ComPort = "com3"
try:
    SerialComs = serial.Serial(ComPort, 9600)  # Intializes the Com port
except:
    pass

while True:
    for i in range(1):
        data = 0
        value = SerialComs.readline() 
        print(value)

我得到的 output 是这样的:

b'1\r\n'

为了只得到我想要的数字 1,我尝试了这个:

import serial
ComPort = "com3"
try:
    SerialComs = serial.Serial(ComPort, 9600)  # Intializes the Com port
except:
    pass

while True:
    for i in range(1):
        data = 0
        value = int(SerialComs.readline().decode('ascii'))
        print(value)

但我得到这个错误

UnicodeDecodeError:“ascii”编解码器无法解码 position 中的字节 0xb1 0:序号不在范围内(128)

我该怎么做才能只从串口获取号码?

快速的答案是将errors='ignore'添加到您的解码行。 例如

value = SerialComs.readline().decode(encoding='ascii', errors='ignore')

由于读取行中的 ASCII 字符无效,这将阻止代码退出并出现错误。

当您转换为 integer 时,这仍然会出错,因为字符串中会有无效内容,因此您需要检查您的内容是否为数字。 例如

readline_data0 = [b"\x00\x00\xf01\r\n",
                  b"1\r\n",
                  b"1\r\n",
                  b"1\r\n"]

for line in readline_data0:
    txt = "".join(
        [x for x in line.decode(encoding="ascii", errors="ignore") if x.isdigit()]
    )
    value = int(txt)
    print(value)

会给 output:

1
1
1
1

如果您不确定串行端口上输入的是什么,这可能很容易出错。

为缓解此问题,来自 Arduino 的更详细的消息将有助于确定哪些是预期数据。 例如,如果来自 Aruino 的消息基于逗号分隔值,它可能看起来像: Serial.println(",sensor1,1,");

如何从序列内容中轻松提取的示例:

readline_data1 = [b"\x00\x00\xf0,sensor1,1,\r\n",
                  b",sensor1,1,\r\n",
                  b",sensor1,1,\r\n",
                  b",sensor1,1,\r\n"]


def get_sensor_value(sensor_name, ascii_data):
    fields = ascii_data.split(',')
    sensor_loc = fields.index(sensor_name) + 1
    return int(fields[sensor_loc])


for line in readline_data1:
    txt = line.decode(encoding="ascii", errors="ignore")
    value = get_sensor_value('sensor1', txt)
    print(value)

其中给出了 output:

1
1
1
1

这还有一个好处,即它可以扩展为从多个传感器发送数据,因为这些值可以与特定传感器相关联。

readline_data1 = [b"\x00\x00\xf0,sensor1,1,\r\n",
                  b",sensor1,1,sensor3,3,\r\n",
                  b",sensor2,2,\r\n",
                  b",sensor1,1,\r\n"]


def get_sensor_value(sensor_name, ascii_data):
    fields = ascii_data.split(',')
    if sensor_name not in fields:
        return
    sensor_loc = fields.index(sensor_name) + 1
    return int(fields[sensor_loc])


for line in readline_data1:
    txt = line.decode(encoding="ascii", errors="ignore")
    for check_sensor in ['sensor1', 'sensor2', 'sensor3']:
        value = get_sensor_value(check_sensor, txt)
        if value:
            print(f"{check_sensor} = {value}")

其中给出了 output:

sensor1 = 1
sensor1 = 1
sensor3 = 3
sensor2 = 2
sensor1 = 1

如果所有行都是int ,那么您需要一些步骤:

value = SerialComs.readline()
value = value.decode()   # convert from bytes -> str
value = value.strip()    # remove line endings
value = int(value)       # convert str -> in
print(value)

一站式完成:

value = int(SerialComs.readline().decode().strip())
print(value)

如果您在将非 ascii 字节输入序列号 stream 时遇到问题,则必须将它们过滤掉:

value = bytes([v for v in SerialComs.readline() if v in range(1,127)])
value = int(value.decode().strip())
print(value)

Andrés,根据您对@quamrana 回答的评论,关于字节序列: b'\x00\x00\xf01\r\n' ,在我看来, \x00\x00\xf0是以某种方式产生的虚假字节进入串行数据 stream,可能是数据线上的噪声。

如果在 Arduino 上,您只运行了Serial.println("1"); 如你所说,那么由"1\r\n"表示的3个字节应该是通过串行数据stream发送的唯一字节。

我可能会检查是否有任何松动的电线/连接、接地问题,或者尝试使用不同的电缆。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM