Здравствуйте. С Arduino работаю недавно плата Mega 2560, пытаюсь организовать поток данных от датчиков на компьютер. На компе. Pycharm и GUI на PySide6. Плата подключена к com3, через монитор порта вижу нормальный поток информации о температуре и т.д. Но когда запускаю GUI и нажимаю кнопку подключить порт в самом начале информация идет по байтно (как в мониторе), но в какой-то момент происходит что-то, что переводит передачу в по битный режим. Подскажите, что происходит и как с этим бороться ? Благодарю.
Откуда же мы можем знать?
Ни вашего кода ардуино, ни программы на питоне никто из нас не видел
int speed = 120; // https://www.youtube.com/watch?v=f_rmcND-3jI
bool isLedOn = true;
float distance = 31.6;
float time = speed / distance;
char letterA = 'f';
String chanel = "SoftWareProjer";
int x;
int y = 40;
String name = "Ivan";
String surname = " Smirnov";
String summ_2 = name + surname;
char myStr1[20];
String shh = "привет"; // вопрос с передачей кирилици
void setup()
{
Serial.begin(9600);
while (!Serial) //https://www.youtube.com/watch?v=_RN_Bpze-Jo
{}
//Serial.println("HelloComputerHelloComputerHelloComputerHelloComputerHelloComputer");
//Serial.println(summ_2); // сбой потока данных в питоне произошел в мемент передачи в порт содерживого переменной summ_2
}
void loop() {
int size_bufer = Serial.available(); /* Принимаемые по последовательному порту байты попадают в буфер микроконтроллера,
откуда Ваша программа может их считать. Функция возвращает количество накопленных в буфере байт. */
Serial.println("HelloComputerHelloComputerHelloComputerHelloComputerHelloComputer");
count++;
x = y * 3;
y++;
//Serial.print("x- ");
//Serial.println(x);
//Serial.print("y- ");
//Serial.println(y);
//Serial.println(shh);
Serial.print("size_bufer- ");
Serial.println(size_bufer);
Serial.print("count- ");
Serial.println(count);
dtostrf(distance,2,1,myStr1);
Serial.println(myStr1);
delay(5000); ```
В Pithon код намного больше, не стал обрезать.
функция приема данных из буфера:
def read_bufer():
``` import sys
from PySide6.QtCore import QDate, QDateTime # загружаем необходимые для работы с виджетами методы
from PySide6.QtWidgets import QApplication, QMainWindow, QLCDNumber, QMessageBox, QSlider, QScrollBar, QLabel
from PySide6.QtSerialPort import QSerialPort, QSerialPortInfo
from PySide6.QtCore import QIODevice
from Monitor_Kuzya import Ui_MainWindow # читаем файл с эскизом GUI в формате .py. Импортируем класс Ui_MainWindow
class Arduino(QMainWindow):
def __init__(self):
super(Arduino,self).__init__() # задаем место расположения окна на экране компьютера (х, у, w, h)
self.setGeometry(10,100,619, 458) # w и h взяты из size_convert класс Ui_MainWindow размеры самого окна MainWindow.resize(422, 425)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.dateEdit.setDisplayFormat("yyyy.MM.dd") # устанавливаем формат даты в котором мы хотим ее выводить в окно dateEdit
self.ui.dateEdit.setDate(QDate.currentDate()) # в окно dateEdit передаем текущую дату с помощью метода QDate.currentDate()
self.ui.dateTimeEdit.setDisplayFormat("H: mm /// dd.MM.yyyy") # устанавливаем формат времени и даты в котором мы хотим ее выводить в окно dateTimeEdit
self.ui.dateTimeEdit.setDateTime(QDateTime.currentDateTime()) # в окно dateTimeEdit передаем текущую дату и время с помощью метода QDateTime.currentDateTime()
# *** --- РАБОТА С com ПОРТОМ ПК --- *** #
serial = QSerialPort() # создадим объект класса QSerialPort
serial.setBaudRate(9600) # зададим скорость обмена данными для этого объекта
portList = [] # список для хранения доступных портов ПК
ports = QSerialPortInfo.availablePorts() # функция возвращает object доступных портов в системе
for port in ports: # в цикле просматриваем объект
portList.append(port.portName()) # получаем список доступных портов
# portList.append(port.description()) # дает информацию по портам, что к ним подключено
print('Список доступных портов ПК', portList)
def open_com():
print("Кнопка OPEN нажата")
print("Имя Порта -", self.ui.comboBox.currentText()) # выбираем из списка в comboBoxе имя нужного нам порта
serial.setPortName(self.ui.comboBox.currentText()) # присваиваем serial имя выбранного порта
serial.setBaudRate(9600) # зададим скорость обмена данными для этого объекта
serial.open(QIODevice.ReadWrite) # открываем порт
def close_com():
serial.close() # закрываем порт
print("Порт: ", self.ui.comboBox.currentText(), "закрыт")
def serial_send(data): # передаем на Ar data - список int значений от датчиков
txs = "" # для подачи в буфер создадим пустую строку
for val in data: # пройдем циклом по списку data
txs += str(val) # текущее значение списка переведем в строковый вид и добавим к строке для буфера
txs += ',' # разделим элементы списка "," - требуется по нашему протоколу
txs = txs[:-1] # уберем из строки последнюю запятую
txs += ';' # добавим в конце строки терминатор ";"
# print(type(txs), txs) # вид и тип подготовленного к передаче в порт пакета <class 'str'> 1,84,71,96;
serial.write(txs.encode()) # отправим в порт подготовленную строку переведя ее в байтовый вид (encode())
def read_bufer(): # читаем поступившую с Ar через буфер com порта информацию
str_in_line = serial.readLine() # поступившая из буфера строка
print(str_in_line)
serial.readyRead.connect(read_bufer) # связывает сигнал readyRead() со слотом readData()
# Этот сигнал возникает, когда последовательный порт
# получает новые данные
# *** --- Ф У Н К Ц И И --- *** #
def ledControl(val_led):
# print(val_led) # контроль пришедшего сигнала
if val_led == 2: val_led = 1; # конвертация к цифровой единице (1 или 5В)
print(val_led) # контроль отправляемого на Ar сигнала
serial_send([0, val_led]) # передаем сигнал ledControl в функцию отправки пакета на Ar по ключу 0
def fanControl(val_fan):
# print(val_fan) # контроль пришедшего сигнала
if val_fan == 2: val_fan = 1; # конвертация к цифровой единице (1 или 5В)
print(val_fan) # контроль отправляемого на Ar сигнала
serial_send([3, val_fan]) # передаем сигнал fanControl в функцию отправки пакета на Ar по ключу 3
def lightControl(val_lig):
# print(val_lig) # контроль пришедшего сигнала
if val_lig == 2: val_lig = 1; # конвертация к цифровой единице (1 или 5В)
print(val_lig) # контроль отправляемого на Ar сигнала
serial_send([4, val_lig]) # передаем сигнал fanControl в функцию отправки пакета на Ar по ключу 4
def rgb_Control():
val_R = self.ui.r_slider.value() # читаем состояние R-slidera
val_G = self.ui.g_slider.value() # читаем состояние G-slidera
val_B = self.ui.b_slider.value() # читаем состояние B-slidera
print(val_R, val_G, val_B) # контроль состояния RGB-slidera
serial_send([1, val_R, val_G, val_B]) # передаем пакет в функцию отправки через порт на Ar
# *** --- РАБОТА С ТЕРМИНАЛОМ И АРДУИНО --- *** #
print(QDate.currentDate().toString('dd-MM-yyyy')) # выводим в widget currentDate текущую дату
self.ui.comboBox.addItems(portList) # передаем в comboBox список доступных портов
self.ui.pbt_open.clicked.connect(open_com) # нажатием кнопки "pbt_open" открываем порт arduino
self.ui.pbt_close.clicked.connect(close_com) # нажатием кнопки "pbt_close" закрываем порт arduino
self.ui.checkBox_LED.stateChanged.connect(ledControl) # устанавливаем флаг "checkBox_LED" включаем светодиод
self.ui.checkBox_FAN.stateChanged.connect(fanControl) # устанавливаем флаг "checkBox_FAN" включаем вентилятор
self.ui.checkBox_LIGHT.stateChanged.connect(lightControl) # устанавливаем флаг "checkBox_LIGHT" включаем свет
self.ui.r_slider.valueChanged.connect(rgb_Control) # читаем r_slider
self.ui.g_slider.valueChanged.connect(rgb_Control) # читаем g_slider
self.ui.b_slider.valueChanged.connect(rgb_Control) # читаем b_slider
temperatura_out = -26.2
temperatura_in = 15.4
vlagnost = 72
self.ui.tempBar.setValue(temperatura_in) # t_комната_n в виджет QProgressBar выводится значение float, в Qt Designer задаем пределы значений.
self.ui.temperatura_in.setValue(temperatura_out) # Т_Погода в виджет QProgressBar выводится значение float, в Qt Designer задаем пределы значений.
self.ui.temperatura_in_lcd.setDigitCount(5) # зададим количество цифр в виджете, используя метод setDigitCount(5). Количество цифр в виджете будет "3" + "знак" + "точка"
self.ui.temperatura_in_lcd.display(temperatura_out) # выводим температуру на улице на LCD дисплей
self.ui.label_vlagnost.setText(str(vlagnost)) # в виджет label выводится тип данных str
self.ui.Temperatura_label.setText(str(temperatura_in)) # в виджет label выводится тип данных str
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Arduino()
window.show()
sys.exit(app.exec()) ```
Если что делаю не так, извените я здесь первый день...
Код для Arduino сократил до минимума (ошибка не изменилась)
int speed = 120;
float distance = 32;
float time = speed / distance;
char myStr1[20];
void setup()
{
Serial.begin(9600);
while (!Serial) // задержка пока порт не откроется
{}
}
void loop() {
int size_bufer = Serial.available(); // Функция возвращает количество накопленных в буфере байт
Serial.println("HelloComputerHelloComputerHelloComputerHelloComputerHelloComputer");
count++;
Serial.print("size_bufer- ");
Serial.println(size_bufer);
Serial.print("count- ");
Serial.println(count);
//dtostrf(distance,2,1,myStr1);
dtostrf(time,2,1,myStr1);
Serial.println(myStr1);
delay(5000);
} ```
Да, еще. Подобный переход передачи с байтового на битовый, происходит в не зависимости от содержания передаваемой информации. В другом скетче я передаю температуру и тек же принимаемая информация меняет вид. См. скрин.
слушайте, о чем вы? О том что сначала “31” передавалось в одну строку, а потом каждая цифра - на своей строке?
Вы понимаете что такое байты, а что биты?
А если по делу - сложно искать ошибки, когда код и вывод в Сериал не соответвует друг другу.
Пожалуйста, выложите вывод именно от того кода, что вы показали.
Ну или наоборот - выложите код, от которого этот вывод.
и
в вашем случае (плата Mega 2560) совершено не нужные строки.
человек с ютуба тоже не очень осведомлен о назначении данных строк.
и да, ваш вывод в порт отличается от того что написано в коде.
плюс еще, где объявление переменной count ?
Убрал все лишнее из скетча
int count;
int speed = 120;
float distance = 32;
float time = speed / distance;
char myStr1[20];
void setup()
{
Serial.begin(9600);
}
void loop() {
int size_bufer = Serial.available(); // Функция возвращает количество накопленных в буфере байт
Serial.println("HelloComputerHelloComputerHelloComputerHelloComputerHelloComputer");
count++;
Serial.print("size_bufer- ");
Serial.println(size_bufer);
Serial.print("count- ");
Serial.println(count);
//dtostrf(distance,2,1,myStr1);
dtostrf(time,2,1,myStr1);
Serial.println(myStr1);
delay(5000);
} ```
В PyCharme ответ теперь соответствует коду в Arduino

Передача не всегда одинаковая после подключения порта. В этот раз картина другая , в первом цикле сообщение передано полностью.
Первая строка кода.
я не знаю питона, но сдается мне что
читает все что есть в буфере, а потом вы выводите это как одну строку
так вот, пока ваш скрипт очухывается в буфер успевает налететь что то, а после, как очухается, он просто печатает то что приходит по одному символу
вам надо накапливать строку до символов \r\n и только потом выводить ее
может я и не прав, мое предположение…
В вашем первом коде было такое:
serial.readyRead.connect(read_bufer) # связывает сигнал readyRead() со слотом readData()
# Этот сигнал возникает, когда последовательный порт
# получает новые данные
Если найти ман по функции readyRead(), там есть такое:
This signal is emitted once every time new data is available for reading from the device’s current read channel.
Я не нашел исходник, нужно бы еще покопаться, чтобы понять, что там на самом деле выполняется.
Зато я нашел похожую проблему с посимвольным выводом на stackoverflow. И там есть несколько решений, которые сводятся к написанию своей функции для буферизации данных и выводу по определенному ключу, например при получении кода переноса строки и/или возврата каретки. Я думаю, вы можете взять решение оттуда.
В 3 питоне (а про 2.7 мы давно забыли) ровно так и происходит и это видно по распечатке от “потерпевшего” - в ней не символ выводится одинокий а байтовый массив.
что по букаффке b впереди видно.
Так что убирать нахрен это вывод, или превращать его в правильный. Тут уж каждый сам пи…ец своего счастья.
Всем привет. Продолжу задавать вопросы и предоставлять информацию о том, что накопал, т.к. проблему не решил. Начну со ссылки на видео, где подобная схема работает. Ардуинка шлет данные, они попадают в порт в виде байтового массива (букаффке b) и далее с ними работают. Почему у меня так не происходит ?
Вторая ссылка на видео как у меня загружается скетч в Arduino, и что я получаю в мониторе порта.
Что смущает. Это выдача старой информации в мониторе, той которая была до очередного открытия порта, которое сопровождается перезагрузкой платы. И по моему разумению поток должен начинаться с вывода фразы из
setup()
{
Serial.println(“Its frosty today”); }
Получается, что этот блок остается в буфере:
count-3
3.8
Hello Computer
А этот начинает передаваться уже в потоке, начиная с фразы в setup() и с обновленным счетчиком.
Its frosty today
count-1
3.8
Hello Computer
count-2
3.8
Hello Computer
Почему я на это обращаю внимание? Ответ в полученной информации в Pithon. Там я тоже получаю в правильном виде только ту информацию, которая храниться в буфере. Как только начинается поток, она передается в виде байтового массива (правильно замечено в одном из ответов), но по одному символу. Сейчас сделаю видео и выложу.
В этом видео, как выводится в Python информация из Arduino через com порт.
Сначала мы видим нормальный вывод того, что осталось в буфере от “предыдущего” потока. Потом идет начало подачи текущего потока, пытается собирать символы в слова, и далее сваливается в передачу символов в виде “бит” массивов. Простите за несоответствующую лексику, просто не знаю как это безобразие назвать.
Я посмотрел вчерашние рекомендации по разбору всего этого программным способом, но мне кажется, что здесь проблема аппаратного свойства. Ведь работает у Aleksa. Я ему писал, но ответа не получил.
Я с Вами согласен, именно до появления символов \n.
Вот только как, и главное где это сделать. Ардуинка своим println(), уже эти символы добавляет в пакет к тексту ( char myStr2[18] = “Hello Computer”; ).
В мониторе порта мы видим правильный вывод. Три последовательные строки с соответствующей информацией.
А вот pithon ведет себя по разному хранящуюся в буфере информацию он воспринимает правильно, а вот в потоке не ждет этого (\n) символа и все печатает по битно… Как то так, остоется придумать как это исправить…