簡體   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