Как преобразовать python-to-arduino через последовательный код в python3-to-arduino поверх последовательного кода? - PullRequest
1 голос
/ 29 сентября 2019

Код ниже используется для работы в spyder для связи через последовательный порт с Arduino. В консольном окне spyder я увидел бы выводимые строки данных:

78.7,77.9,100,80

78.7,77.9,100,80

78,7, 77,9,100,80

78,7,77.9,100,80 ...

Данные получены от двух датчиков температуры, расходомера и заданной температуры термостата.

Я обновил свою систему Kubuntu 18.04 до всех вещей python3. Теперь код выполняется, но в окне консоли spyder3 не отображаются видимые символы, но прокручиваются пустые строки. Остальная часть моего кода на Python для анализа и построения этих данных не работает.

Я потратил весь день, пытаясь исправить это без удачи. Я предполагаю, что это простое исправление для кого-то с большим опытом, чем я.

Единственное различие между старым рабочим кодом и приведенным ниже кодом заключается в том, что в операторы print добавлены скобки для удаления ошибки синтаксиса.

python

""" This code was originally copied from:
Listen to serial, return most recent numeric values
Lots of help from here:
http://stackoverflow.com/questions/1093598/pyserial-how-to-read-last-line-sent-from-serial-device
"""

from threading import Thread

import time
import serial

last_received = ''
def receiving(ser):
    global last_received
    buffer = ''
    while True:
        buffer = buffer + ser.read(ser.inWaiting())
        if '\n' in buffer:
            lines = buffer.split('\n') # Guaranteed to have at least 2 entries
            last_received = lines[-2]
            #If the Arduino sends lots of empty lines, you'll lose the
            #last filled line, so you could make the above statement conditional
            #like so: if lines[-2]: last_received = lines[-2]
            buffer = lines[-1]


class SerialData(object):
    def __init__(self, init=50):
        try:
            self.ser = serial.Serial(
                port='/dev/ttyACM0',
                baudrate=9600,
                bytesize=serial.EIGHTBITS,
                parity=serial.PARITY_NONE,
                stopbits=serial.STOPBITS_ONE,
                timeout=0.1,
                xonxoff=0,
                rtscts=0,
                interCharTimeout=None
            )
        except serial.serialutil.SerialException:
            #no serial connection
            self.ser = None
        else:
            Thread(target=receiving, args=(self.ser,)).start()

    def next(self):
        if not self.ser:
            return '81.3,78.1,10.0,60.0,0' #100 #return anything so we can test when Arduino isn't connected
        #return a float value or try a few times until we get one
        for i in range(40):
            raw_line = last_received
            try:
               # return float(raw_line.strip())
                return str(raw_line.strip())
            except ValueError:
                print('bogus data',raw_line)
                time.sleep(.005)
        return 0.
    def __del__(self):
        if self.ser:
            self.ser.close()
    def write(self,val):
        self.ser.write(val)

if __name__=='__main__':
    s = SerialData()
    for i in range(500):
        time.sleep(.015)
        print( s.next())

Ответы [ 2 ]

1 голос
/ 30 сентября 2019

Одним из наиболее значительных отличий между Python 2.x и 3.x является способ кодирования текстовых строк. Для Python 3.x все является Unicode, по сравнению с ASCII для 2.x, поэтому вам просто нужно декодировать необработанные байты, которые вы читаете из последовательного порта:

buffer = buffer + ser.read(ser.inWaiting()).decode('utf-8')

РЕДАКТИРОВАТЬ: теперь у вас возникла другая проблема, связанная с исключением. Похоже, ваш порт открыт, чтобы быть уверенным, что вы можете изменить способ обработки исключения при создании экземпляра порта:

except serial.serialutil.SerialException as e: 
    print(e)
    self.ser = None

Как только вы узнаете об ошибке, вы сможете ее устранить. Вполне вероятно, что ваш порт не был должным образом закрыт в более ранней сессии.

0 голосов
/ 01 октября 2019

Бинго! Последнее предложение исправило программу, и графический интерфейс Python, который я написал для нее, работает с этими исправлениями.

python

from threading import Thread
import time
import serial

last_received = ''
def receiving(ser):
    global last_received
    buffer = ''
    while True:
        buffer = buffer + ser.read(ser.inWaiting()).decode('utf-8')
        if '\n' in buffer:
            lines = buffer.split('\n') # Guaranteed to have at least 2 entries
            last_received = lines[-2]
            #If the Arduino sends lots of empty lines, you'll lose the
            #last filled line, so you could make the above statement conditional
            #like so: if lines[-2]: last_received = lines[-2]
            buffer = lines[-1]


class SerialData(object):
    def __init__(self, init=50):
        try:
            self.ser = serial.Serial(
                port='/dev/ttyACM1',
                baudrate=9600,
                bytesize=serial.EIGHTBITS,
                parity=serial.PARITY_NONE,
                stopbits=serial.STOPBITS_ONE,
                timeout=0.1,
                xonxoff=0,
                rtscts=0,
                interCharTimeout=None
            )
        except serial.serialutil.SerialException as e: 
            print(e)
            #no serial connection
            self.ser = None
        else:
            Thread(target=receiving, args=(self.ser,)).start()

    def next(self):
       # if not self.ser:
       #     return '81.3,78.1,10.0,60.0,0' #100 #return anything so we can test when Arduino isn't connected
        #return a float value or try a few times until we get one
        for i in range(40):
            raw_line = last_received
            try:
               # return float(raw_line.strip())
                return str(raw_line.strip())
            except ValueError:
                print('bogus data',raw_line)
                time.sleep(.005)
        return 0.
    def __del__(self):
        if self.ser:
            self.ser.close()
    def write(self,val):
        self.ser.write(val)

if __name__=='__main__':
    s = SerialData()
    for i in range(500):
        time.sleep(.015)
        print (s.next())
...