Python / PySerial / Arduino Reading serial data and later writing this exact serial data to the txt file

老子叫甜甜 提交于 2021-02-11 16:19:52

问题


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.


回答1:


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


来源:https://stackoverflow.com/questions/61987312/python-pyserial-arduino-reading-serial-data-and-later-writing-this-exact-ser

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!