Значения Arduino, Python, Serial и Unpacking: "ValueError: для распаковки нужно более 1 значения"

Это мой первый вопрос, и я относительно новичок в python, так что будьте добры со мной. Ваше руководство по этой проблеме будет с благодарностью!

У меня есть пульсоксиметр, который используется с конкретным экраном Arduino для получения 2 простых сигналов: частоты пульса и содержания насыщения кислородом. Смотрите код Arduino:

#include <PinChangeInt.h>
#include <eHealth.h>

int cont = 0;

void setup() {
  Serial.begin(115200);  
  eHealth.initPulsioximeter();

  //Attach the inttruptions for using the pulsioximeter.   
  PCintPort::attachInterrupt(6, readPulsioximeter, RISING);
}

void loop() {

  //BPM
  Serial.print(eHealth.getBPM());
  Serial.print(",");

  //SP02
  Serial.print(eHealth.getOxygenSaturation());  

  //NEW LINE
  Serial.print('\n');  
  delay(500);
}


//=========================================================================
void readPulsioximeter(){  

  cont ++;

  if (cont == 50) { //Get only of one 50 measures to reduce the latency
    eHealth.readPulsioximeter();  
    cont = 0;
  }
}

Таким образом, вывод в последовательный монитор, другими словами, когда вызывается pySerial readline(), разделенные запятыми строки выглядят так:

65,95
67,96
67,95
70,94

Просто, правда?

Что ж, я использую программу на python в сочетании с pySerial для чтения этих значений, назначения их вектору, печати их на графике в реальном времени и сохранения их в файле.csv.

Для справки, вот программа:

import serial
import time 
import matplotlib.pyplot as plt
import numpy as np
import sys
import os
import csv

#time load
timestr = time.strftime("%Y_%m_%d")

#spacer
spacer = "_"

#user inputs name
name = raw_input('Enter full name:  ')
file_name = name + spacer + timestr
file_name_str = file_name+'.csv'

#change directory
path = '/home/pi/Desktop/pulseox/data'
os.chdir(path)
text_file = open(file_name, "w")
full_path = path + "/" + file_name_str

#check
print full_path

#establish serial connection with ACM0
ser = serial.Serial('/dev/ttyACM0', 115200)

#establish vectors
thymeL = [ ]
bpmL = [ ]
sp02L = [ ]
array_data = thymeL, bpmL, sp02L


#declare time
thyme = 1

#establish plot values
#plt.axis([0,50,0,120])
plt.ion()
plt.title("Pulse [BPM] & SPo2 [%] v. Time [s]", fontsize = "16")
plt.xlabel("Time [s]", fontsize = "14")
plt.ylabel("Pulse (red) [BPM] & SPo2 (blue) [%]", fontsize = "14")

#print data to terminal, define time
while True:         
    data_in = ser.readline()
    bpm, sp02 = data_in.split(",")
    thyme = float(thyme)
    bpm = float(bpm)
    sp02 = float(sp02)
    print "Time [s]: %s" % (thyme)
    print "HR [BPM]: %s" % (bpm)
    print "SPO2 [%%]: %s" % (sp02)  
    print 

    thymeL.append(thyme)
    bpmL.append(bpm)
    sp02L.append(sp02)

    plt.scatter(thyme,bpm,color="red")
    plt.scatter(thyme,sp02,color="blue")
    plt.pause(0.1)
    time.sleep(0.05)

    thyme = thyme + 1

    with open(full_path, 'w') as f:
        writer = csv.writer(f)
        for t, b, s in zip(array_data[0], array_data[1], array_data[2]):
            writer.writerow([t, b, s])

25% времени все работает нормально. Но остальные 75% времени случайным образом программа выдаст следующую ошибку:

Traceback (most recent call last)L
    File "pulseox.py", line 74, in <module>
        bpm, sp02 = data_in.split(",")
ValueError: need more than 1 value to unpack

Поэтому игнорируйте остальную часть программы, за исключением следующих строк:

data_in = ser.readline()
spm,sp02 = data_in.split(",")

Если на самом деле последовательный монитор просто выводит 2 значения через запятую, такие как:

67, 95
71, 95

Тогда почему возникает ошибка распаковки, когда программе так просто распаковывают две переменные и присваивают их массивам? Это проблема, которая встречается в другой моей программе, и я хотел бы разобраться с ней! Любая помощь очень ценится!

1 ответ

Проблема в том, что код Python может читать из буфера, когда Arduino печатал только частично. Вы используете 4 отдельных отпечатка для Arduino и while True: data_in = ser.readline() в коде питона. Таким образом, может произойти следующее:

void loop() {

  //BPM
  Serial.print(eHealth.getBPM());
  Serial.print(",");

  // *** At this point the python code may read what has been written so far, i.e. it receives an invalid data set and thus the ValueError. ***

  //SP02
  Serial.print(eHealth.getOxygenSaturation());  

  //NEW LINE
  Serial.print('\n');  
  delay(500);
}

Вы должны сначала построить строку в форме x,y\n а затем распечатать эту строку, используя одну печать. Затем часть Python либо читает кортеж данных, либо не читает, но не читает неполные кортежи, что приводит к ошибке распаковки.

Так что-то вроде следующего сделало бы:

void loop() {

  char buffer[32];  // make sure buffer is large enough;
  sprintf(buffer, "%d,%d\n", eHealth.getBPM(), eHealth.getOxygenSaturation());
  Serial.print(buffer);
  delay(500);
}
Другие вопросы по тегам