Python/PySerial/Arduino读取串行数据,然后将此精确的串行数据写入txt文件 [英] Python / PySerial / Arduino Reading serial data and later writing this exact serial data to the txt file

查看:244
本文介绍了Python/PySerial/Arduino读取串行数据,然后将此精确的串行数据写入txt文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在此情况下发表了一篇新文章,因为在第一个案例中我被误解了...

我有一个从Arduino读取串行数据的代码,当在键盘上按下某些特定数字时,会将这些数字写入Arduino.此确切的代码在我运行时会完美运行,它读取串行数据,并且能够将数据写入Arduino.我使用线程和PySerial 库来实现这一目标.

来自Pynput导入键盘的

 导入线程导入序列导入系统ser =无类SerialReaderThread(threading.Thread):def运行(自己):全球服务ser = serial.Serial('COM3',波特率= 9600,超时= 5)而True:打印(ser.readline().decode('utf-8'))类KeyboardThread(threading.Thread):def运行(自己):def on_press(key):尝试:格式(key.char)如果key.char =="1":ser.write(b'1 \ r \ n')#串行写入-1elif key.char =="2":ser.write(b'2 \ r \ n')#串行写入-2elif key.char =="3":ser.write(b'3 \ r \ n')#串行写入-3elif key.char =="4":ser.write(b'4 \ r \ n')#串行写入-4elif key.char =="5":ser.write(b'5 \ r \ n')#串行写入-5elif key.char =="6":ser.write(b'6 \ r \ n')#串行写入-6elif key.char =="0":ser.write(b'0 \ r \ n')#串行写入-0除了AttributeError:格式(键)使用keyboard.Listener(on_press = on_press)作为侦听器:listener.join()监听器= keyboard.Listener(on_press = on_press)listener.start()serial_thread = SerialReaderThread()keyboard_thread = KeyboardThread()serial_thread.start()keyboard_thread.start()serial_thread.join()keyboard_thread.join() 

此后,我有一个想法,就是我也可以将要打印的串行数据完全写到Windows上的.txt文件中.因此,我创建了一个名为FileWriting的新线程,并决定只向其中写入 ser.readline().decode('utf-8') 不再工作了 ...这是我写的新修改的代码,用于写入.txt文件.

来自Pynput导入键盘的

 导入线程导入序列导入系统导入ioser =无类SerialReaderThread(threading.Thread):def运行(自己):全球服务ser = serial.Serial('COM3',波特率= 9600,超时= 5)而True:打印(ser.readline().decode('utf-8'))类FileWriting(threading.Thread):def运行(自己):而True:io.open("output.txt","a",encoding ="utf-8")为f:f.write(ser.readline().decode('utf-8'))类KeyboardThread(threading.Thread):def运行(自己):def on_press(key):尝试:格式(key.char)如果key.char =="1":ser.write(b'1 \ r \ n')#串行写入-1elif key.char =="2":ser.write(b'2 \ r \ n')#串行写入-2elif key.char =="3":ser.write(b'3 \ r \ n')#串行写入-3elif key.char =="4":ser.write(b'4 \ r \ n')#串行写入-4elif key.char =="5":ser.write(b'5 \ r \ n')#串行写入-5elif key.char =="6":ser.write(b'6 \ r \ n')#串行写入-6elif key.char =="0":ser.write(b'0 \ r \ n')#串行写入-0除了AttributeError:格式(键)使用keyboard.Listener(on_press = on_press)作为侦听器:listener.join()监听器= keyboard.Listener(on_press = on_press)listener.start()serial_thread = SerialReaderThread()keyboard_thread = KeyboardThread()file_thread = FileWriting()serial_thread.start()keyboard_thread.start()file_thread.start()serial_thread.join()keyboard_thread.join()file_thread.join() 

很明显,我只添加了一个名为file_thread的新线程,现在,当我运行串行数据的代码打印时,以及将数据写入Arduino都可以正常工作,但是,代码没有向Arduino写入任何内容.txt文件,并给我一个错误:

线程Thread-3中的

  Exception:追溯(最近一次通话):_bootstrap_inner中的文件"C:\ Python \ lib \ threading.py",第932行self.run()运行中的文件"C:\ Users \ ultra \ Desktop \ work \ menucode.py",第32行f.write(ser.readline().decode('utf-8'))AttributeError:"NoneType"对象没有属性"readline" 

如果有人在读取串行数据和写入文本文件时遇到Arduino的类似问题,或者有人知道如何解决此问题,请告诉我在这一点上我很绝望,一切都受到赞赏./strong>

解决方案

在文件顶部,您声明 ser = None .您收到的错误消息表明,在 FileWriting 线程尝试访问该对象之前,尚未将 ser 对象设置为 Serial 对象./p>

解决此问题的一种快速方法是

  ser = serial.Serial('COM3',波特率= 9600,超时= 5) 

在启动任何线程之前.

但是,由于您在不同的线程中有两个竞争的 ser.readline()调用,因此这可能会使程序的行为异常.这可能会导致每个线程捕获大约Arduino的输出数据的一半(取决于pyserial如何处理对同一资源的多个请求).为避免此问题,我建议让单个线程与 ser 对象一起使用,并让该线程使用 导入队列导入序列q = queue.Queue()ser = serial.Serial('COM3',波特率= 9600,超时= 5)类SerialReaderThread(threading.Thread):def运行(自己):而True:#从ser读取输出输出= ser.readline().decode('utf-8')打印(输出)#将输出添加到队列q.put(输出)类FileWriting(threading.Thread):def运行(自己):而True:输出= q.get()#这将一直等待,直到队列中有可用的项目为止使用open("output.txt","a +")为f:f.write(输出)f.write("\ n")#如果要用换行符分隔输出

I am making a new post regarding this case because I was misunderstood in the first one...

I have a code that reads the serial data from the Arduino and when some specific digits are pressed on the keyboard it writes these digits to the Arduino. This exact code works perfectly when I run it, it reads the serial data and I am able to write data to the Arduino. I use threading and PySerial library to achieve this.

from pynput import keyboard
import threading
import serial
import sys


ser = None

class SerialReaderThread(threading.Thread):


    def run(self):

        global ser

        ser = serial.Serial('COM3', baudrate = 9600, timeout = 5)

        while True:

            print(ser.readline().decode('utf-8'))


class KeyboardThread(threading.Thread):

    def run(self):

        def on_press(key):

            try:
                format(key.char)

                if key.char == "1":
                    ser.write(b'1\r\n') #serial write - 1

                elif key.char == "2":
                    ser.write(b'2\r\n') #serial write - 2

                elif key.char == "3":
                    ser.write(b'3\r\n') #serial write - 3

                elif key.char == "4":
                    ser.write(b'4\r\n') #serial write - 4

                elif key.char == "5":
                    ser.write(b'5\r\n') #serial write - 5    

                elif key.char == "6":
                    ser.write(b'6\r\n') #serial write - 6

                elif key.char == "0":
                    ser.write(b'0\r\n') #serial write - 0      
            except AttributeError:
                format(key)


        with keyboard.Listener(on_press=on_press) as listener:
            listener.join()

        listener = keyboard.Listener(on_press=on_press)
        listener.start()


serial_thread = SerialReaderThread()
keyboard_thread = KeyboardThread()

serial_thread.start()
keyboard_thread.start()

serial_thread.join()
keyboard_thread.join()

After this I got an idea that I could also write this serial data exactly what I was printing to the .txt file on windows. So I made a new thread called FileWriting and decided to just write ser.readline().decode('utf-8') to it, however it doesn't work anymore... This is the newly modified code which I wrote to write to the .txt file.

from pynput import keyboard
import threading
import serial
import sys
import io


ser = None

class SerialReaderThread(threading.Thread):


    def run(self):

        global ser

        ser = serial.Serial('COM3', baudrate = 9600, timeout = 5)

        while True:

            print(ser.readline().decode('utf-8'))



class FileWriting(threading.Thread):


   def run(self):

       while True:
             with io.open("output.txt", "a", encoding="utf-8") as f:
                    f.write(ser.readline().decode('utf-8'))



class KeyboardThread(threading.Thread):

    def run(self):

        def on_press(key):

            try:
                format(key.char)

                if key.char == "1":
                    ser.write(b'1\r\n') #serial write - 1

                elif key.char == "2":
                    ser.write(b'2\r\n') #serial write - 2

                elif key.char == "3":
                    ser.write(b'3\r\n') #serial write - 3

                elif key.char == "4":
                    ser.write(b'4\r\n') #serial write - 4

                elif key.char == "5":
                    ser.write(b'5\r\n') #serial write - 5    

                elif key.char == "6":
                    ser.write(b'6\r\n') #serial write - 6

                elif key.char == "0":
                    ser.write(b'0\r\n') #serial write - 0      
            except AttributeError:
                format(key)


        with keyboard.Listener(on_press=on_press) as listener:
            listener.join()

        listener = keyboard.Listener(on_press=on_press)
        listener.start()


serial_thread = SerialReaderThread()
keyboard_thread = KeyboardThread()
file_thread = FileWriting()

serial_thread.start()
keyboard_thread.start()
file_thread.start()

serial_thread.join()
keyboard_thread.join()
file_thread.join()

As it's clear I only added a new thread called file_thread, now as I run the code printing of the serial data works fine as well as the writing data to the Arduino, however, the code doesn't write anything to the .txt file and gives me an error:

Exception in thread Thread-3:
Traceback (most recent call last):
  File "C:\Python\lib\threading.py", line 932, in _bootstrap_inner
    self.run()
  File "C:\Users\ultra\Desktop\work\menucode.py", line 32, in run
    f.write(ser.readline().decode('utf-8'))
AttributeError: 'NoneType' object has no attribute 'readline'

If anybody had similar problems with Arduino while reading the serial data and writing to the text file, or if anybody knows how to fix this please let me know I am quite desperate at this point and everything is appreciated.

解决方案

At the top of your file, you declare ser = None. The error message you get indicate that the ser object has not yet been set to a Serial object before the FileWriting thread tries to access it.

A quick way to fix this issue is by doing

ser = serial.Serial('COM3', baudrate = 9600, timeout = 5)

before you start any of the threads.

However, that would probably make the program behave strangely, as you have two competing ser.readline() calls in different threads. This would probably result in roughly half of the Arduino's output data being captured by each of the threads (depending on how pyserial handles multiple requests for the same resource). To avoid this issue, I would recommend letting a single thread interface with the ser object, and having that thread pass data to other threads using a queue.

A simple example of how this data exchange could go:

import queue
import serial
q = queue.Queue()
ser = serial.Serial('COM3', baudrate = 9600, timeout = 5)

class SerialReaderThread(threading.Thread):
    def run(self):
        while True:
            # Read output from ser
            output = ser.readline().decode('utf-8')
            print(output)
            # Add output to queue
            q.put(output)

class FileWriting(threading.Thread):
   def run(self):
       while True:
             output = q.get()  # This will wait until an item is available in the queue
             with open("output.txt", "a+") as f:
                    f.write(output)
                    f.write("\n")  # If you want outputs separated by newlines

这篇关于Python/PySerial/Arduino读取串行数据,然后将此精确的串行数据写入txt文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆