Serial Comm. вопрос времени между Arduino и Pyserial

Это мой первый пост в Stack Exchange, поэтому, пожалуйста, простите любые ошибки форматирования.

Я провожу эксперимент с 7 полными датчиками: 5 термопар, 2 датчика влажности и 1 датчик давления. Я читаю их сигналы через аналоговые входные порты Arduino Mega. Я решил использовать Python для сохранения и компиляции данных в файле csv nice, поэтому я использую Pyserial.

Моя проблема в том, что я не могу пройти выше 1 выборки в секунду. Как вы можете видеть в моем коде, у меня есть 1 секунда задержки в Arduino и Python. Я провел успешные калибровочные тесты с помощью своих термопар, поэтому я знаю, что с такой скоростью Python и Arduino хорошо общаются. Все, что быстрее, чем 1 образец /секунда (т. Е. Меняю задержки на 0,5 или 0,25 секунды), возникает временная ошибка, и мои данные «вырезаны» и отправляются в нечетные куски вместо стандартного макета, который я запрограммировал.

Кроме того, я попытался увеличить скорость передачи в бодах с 9600 и что-то выше, которое отправит «Serial Comm» символы ASCII «мусора» (например, маленькие пустые блоки и нечетные символы). Я изменил скорость передачи в Arduino, Python и COM-порт в настройках менеджера устройств безрезультатно.

Мне бы очень хотелось увеличить частоту дискретизации, чтобы увеличить отношение сигнал /шум, и я считаю, что хорошей практикой является то, что метролог имеет более высокую частоту дискретизации, чем 1 самп /сек. Я посылаю ~ 1072 бит каждый раз, когда я пишу в Serial Comm (если я правильно подсчитал?), Поэтому у меня должно быть достаточно места для увеличения количества бит для отправки в секунду (примерно в 3 раза больше, чем я сейчас отправляю) .

В целом, мои две основные проблемы: если я увеличиваю скорость передачи в бодах, я получаю мусор в своем Serial Comm, и если я попытаюсь увеличить свою «частоту дискретизации», уменьшив задержки, появятся проблемы с синхронизацией и мои данные делятся ошибочно. Должен ли я использовать другую функцию, например Serial.flush ()?

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

// Data acquisition
// updated  March 30, 2017


//Note: This version is for TEMPERATURE, HUMIDITY and PRESSURE data         
acquisition ALONE. No motor/conveyor control.

//***GLOBAL VARIABLES***//

float lfactor = 125.0; 
float afactor = 1.15;

/////////////////////////

//Standard setup with analogReference to 5Volts. 

void setup() {

Serial.begin(9600);  
}

void loop() {


//******THERMOCOUPLES*******//

//get voltage reading
// [code]; TC # - Location

float tcv1 = analogRead(A4) * ( 5.0 / 1024.0 ); //TC 1 
float tcv2 = analogRead(A7) * ( 5.0 / 1024.0 ); //TC 2 
float tcv3 = analogRead(A8) * ( 5.0 / 1024.0 ); //TC 3 
float tcv4 = analogRead(A9) * ( 5.0 / 1024.0 ); //TC 4 
float tcv5 = analogRead(A10) * ( 5.0 / 1024.0 ); //TC 5

//convert to temperature using custom equation based on 5V reference
float tc1 = ( 188.7755 * tcv1 ) - 245.3959;  
float tc2 = ( 188.7755 * tcv2 ) - 245.3959;  
float tc3 = ( 188.7755 * tcv3 ) - 245.3959;  
float tc4 = ( 188.7755 * tcv4 ) - 245.3959;  
float tc5 = ( 188.7755 * tcv5 ) - 245.3959;    

//******HUMIDITY SENSORS********//

float hs1 = ((( analogRead(A13) * ( 5.0 / 1024.0) ) / 5.0 ) * 100.0 ); //HS 
1
float hs2 = ((( analogRead(A15) * ( 5.0 / 1024.0) ) / 5.0 ) * 100.0 ); //HS 
2

//******PRESSURE SENSORS********//

//obtain voltage signal from Sensirion sensor
float pvolt = analogRead(A0) * (4.995 / 1024.0); 

//convert to Pascals using equation from datasheet, including altitude 
compensation
//P = lfactor * (voltage[V] - .250 ) / 3.750

float pressure =  lfactor * ( pvolt - .250 ) / 3.750;  
float pascals = pressure * afactor; 

Serial.print("TC1");
Serial.print(":");
Serial.print(tc1);
Serial.print(";");

Serial.print("TC2");
Serial.print(":");
Serial.print(tc2);
Serial.print(";");

Serial.print("TC3");
Serial.print(":");
Serial.print(tc3);
Serial.print(";");

Serial.print("TC4");
Serial.print(":");
Serial.print(tc4);
Serial.print(";");

Serial.print("TC5");
Serial.print(":");
Serial.print(tc5);
Serial.print(";");    

Serial.print("RH 1");
Serial.print(":");
Serial.print(hs1);
Serial.print(";");  

Serial.print("RH 2");
Serial.print(":");
Serial.print(hs2);
Serial.print(";");

Serial.print("Pressure");
Serial.print(":");
Serial.print(pascals);
Serial.print(";");

Serial.println("");
delay(1000); 

  }

Код Python:

from threading import Thread
import time
import serial
import os 
global datalist
global fileName

global motorspeed

motorspeed = 0 

def serInitialization():
    #activate the serial port, if possible
    try:
        ser = serial.Serial('COM9', 9600) #initialize the serial port
        print "Serial connection successful." 
        return ser
    except:
        print "Error: serial port cannot be initialized"
        while(1):
            voidholder = 1

def getDateTime():
  """Function grabs current time and date, then returns values in a 2-
 element list. """
   timeNow = time.strftime("%H:%M:%S")
   dateToday = time.strftime("%m/%d/%y")
  return [dateToday, timeNow]

def writetocsv(data):

    """ function writes datalist values to a csv file. If daily csv file 
exists already, 
    list values are simply appended to end of file. If it does not, function 
creates the file, 
    then appends values. 
    """

    global csv_success

    header = ["date", "time", " ", "TC1", " ", "TC2", " ", 
"TC3", " ", "TC4", " ", "TC5", " ", "HS1", " ", "HS2"," ", 
"PRESSURE", " ", "PRESSURE(alt)", "\n"]

    fileName = str(time.strftime("%m_%d_%y_")+ "log.csv")

    if os.path.exists(fileName):
        f = open(fileName, "a")

    else:
        f = open(fileName, "a+")

        for element in header:
            f.write(element + ",")
        f.write("\n")

    for element in data:
        if type(element)==str:
            f.write(element + ",")
        if type(element) == list:
            for i in element:
                f.write(i + ",")

    f.write("\n")
    f.close()
    csv_success = True

def mainprogram():

    data = []


    if ser.inWaiting():
        datetimeData = getDateTime()

        for i in datetimeData:
            data.append(i)

        val = ser.readline().strip('\n\r').split(';')
        print "Current readings: "
        for i in range(0,len(val)):
            sensorData = val[i].split(':')
            data.append(sensorData)

            print sensorData

        writetocsv(data)

        time.sleep(1) 


        print "\n" * 50

#Initializes the serial port with the arduino so now we can read what 
Arduino is sending us!
print "*******************************"
print "DATA ACQUISITION PROGRAM       "
print "*******************************"
print "Data files are saved under "
print "C:\\Users\\lpaw\\Downloads\\python workspace"
print "*******************************"


ser = serInitialization()

while True:

   mainprogram()

Скриншоты ошибок: Arduino Serial Comm и Python IDLE - данные перепутались

 Ошибка скорости передачи

2 голоса | спросил L. Paw 4 Maypm17 2017, 19:35:54

3 ответа


3

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

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

Но вы также, похоже, хотите записать данные организованным способом в виде наборов измерений. Для этого вам следует отклонить данные до тех пор, пока вы не увидите первый «TC1», а затем соберите строки, чтобы заполнить блок данных до тех пор, пока не будет распознано условие завершения и конца данных (в вашем случае пустая строка) и выпишите его на диск в временный файл. Вы также можете включить код, который отказывается от поврежденного блока, неписанного, если какой-либо из промежуточных заголовков чтения не соответствует ожиданиям, и возвращается к поиску следующего, надеюсь, чистого TC1, или отмечает его как ошибочное или что-то еще.

Чтобы использовать другую скорость передачи, вы должны применить соответствующую настройку как в Arduino, так и в конце python ссылки.

Также обратите внимание, что, хотя серийный монитор Arduino действительно полезен для отладки, вы не должны открывать его при попытке собрать данные с помощью python - это либо вызовет ошибку в том, что одна программа будет запрещена , или две программы для борьбы с данными, и каждый из них получает неполные результаты.

Другим методом, который может быть простым и полезным, особенно во время разработки, является запись каждой полученной строки последовательных данных в текстовый файл с числовой меткой времени в начале каждой строки. Затем вы можете получить второй процесс, который читает этот файл, захватывает полные многострочные записи и записывает их, используя либо метку времени первого, либо последнего элемента записи. В частности, это позволяет получить промежуточный вид данных для понимания любых странностей. С помощью различных команд командной строки Unix вы можете даже запустить первую программу, сохраняя промежуточный формат и подавая вторую программу извлечения записей в реальном времени.

ответил Chris Stratton 4 Maypm17 2017, 23:25:14
0

В конце вашего цикла ()

вы обязательно должны использовать одиночный Serial.flush.
Serial.println("");
Serial.flush()
delay(100); 

Помните, что у вас ограниченный SRAM для хранения символов. Я бы посоветовал вам использовать встроенный последовательный монитор в среде Arduino с вышеуказанным изменением и увеличить скорость передачи в бодах. Не должно быть проблем с отправкой данных со скоростью 115 КБ.

Вы также должны рассмотреть возможность отправки сигнала от Python, чтобы получить правильную строку чтения (ACK /NAK), чтобы вы могли полностью удалить задержки (вам все равно нужен флеш).

ответил Jack Creasey 4 Maypm17 2017, 20:10:16
0

Имеет ли ваш код Python какой-либо способ определения start & конец набора данных?
Предполагает ли это, что при чтении фрагмента данных из последовательного порта первый байт всегда будет началом «Cond.temp», а последним байтом будет; в конце Пресса (alt)?
После прочтения фрагмента данных у вас есть чек, чтобы узнать, завершено ли это или вы должны подождать несколько десятков миллисекунд и вернуться к чтению еще?

Я предполагаю, что ответы на эти вопросы: Нет, Да и amp; Нет.

Ваш компьютер и ваш Arduino работают полностью асинхронно - никто не знает, что делает другой.
Когда ваш код на Python считывает фрагмент данных из последовательного порта (я делаю еще одно предположение здесь - что вы не читаете его побайтно), у вас нет способа узнать, что начало этого фрагмента действительно начало вашего набора данных.
Точно так же у вас также нет способа узнать, что конец этого фрагмента - это конец вашего набора данных - может быть, это всего лишь небольшая часть, или, может быть, вы получаете начало следующего набора, приклеенного к концу этого.

Если вы используете USB-последовательный адаптер, ваши данные, скорее всего, будут поступать в бит & которые вам нужно собрать - просто по характеру, как часто работают эти beasties, - они могут буферизировать некоторое количество последовательных байтов, прежде чем упаковывать их вместе в один пакет USB.

Вам нужно каким-то образом указать начало и /или конец ваших наборов данных. Даже что-то простое, как символ \ n новой строки в конце каждого из них может работать на вас.
Затем вам нужно прочитать и buffer данные, которые вы получаете , пока не узнаете, что достигли конца набора данных .
Итак, для примера \ n:
 - прочитайте некоторые материалы
 - добавить его в буфер
 - У вас есть \ n в любом месте буфера ?
 - да - вытащите этот раздел с начала буфера до \ n & обработать его
 - нет - вернитесь к началу и ждите больше вещей
 - после того, как вы вытащили из буфера некоторые вещи, чтобы обработать, не просто забыть остальное - это может быть начало вашего следующего набора данных!
 - переместите его в начало вашего буфера
 - промыть & повтор

Для вашей проблемы со скоростью передачи данных я не могу сказать многого наверняка. Мусор, который вы видите, типичен для ситуации с несогласованностью в бодах.
Убедитесь, что ваш конкретный Arduino поддерживает скорости передачи, которые вы пытаетесь использовать на любой тактовой частоте, с которой вы ее используете.
Убедитесь, что ваш USB-последовательный адаптер (если вы используете его) работает на этих скоростях (либо петлевые контакты 2 и 3, либо введите себе в терминал или получите другой, предпочтительно другой, и подключите их вместе с 3-проводным контакт 2-3, контакт 3-2, контакт 5-5).

ответил brhans 4 Maypm17 2017, 23:54:59

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132