Hallo,
ich habe etwas Probleme damit, Daten vom uC (Arduino UNO über USB-RS232)
mit Pyserial (mit Python3) zu lesen.
Daten sind 4 Temperaturwerte, Format:
"23.45,24.65,18.00,12.36\r\n"
Der Arduino sendet die Daten vernünftig, das habe ich im Terminal
überprüfen können.
Python-Code:
(Daten sollen eingelesen werden und werden dann mit APscheduler getaktet
in eine SQL Datenbank geschrieben)
1
import time
2
import serial
3
import pymysql.cursors
4
import pymysql
5
from apscheduler.schedulers.background import BackgroundScheduler
Eine beispielhafte Ausgabe:
b'25.50,25.00,27.00,24.44\r\n'
temp0: 25.50 temp1: 25.00 temp2: 27.00 temp3: 24.44
b'25.50,25.00,27.00,24.44\r\n'
temp0: 25.50 temp1: 25.00 temp2: 27.00 temp3: 24.44
b'25.50,25.00,27.00,24.44\r\n'
temp0: 25.50 temp1: 25.00 temp2: 27.00 temp3: 24.44
b'25.50,25.00,27.00,24.44\r\n'
temp0: 25.50 temp1: 25.00 temp2: 27.00 temp3: 24.44
b'25.50,25.00,27.00,24.44\r\n'
temp0: 25.50 temp1: 25.00 temp2: 27.00 temp3: 24.44
b'25.50,25\n'
serial data error!
b'25.50,24.50,26.69,24.12\r\n'
temp0: 25.50 temp1: 24.50 temp2: 26.69 temp3: 24.12
b'25.50,24.50,26.69,24.12\r\n'
temp0: 25.50 temp1: 24.50 temp2: 26.69 temp3: 24.12
b'2\r\n'
serial data error!
b'25.50,24.00,26.69,24.12\r\n'
temp0: 25.50 temp1: 24.00 temp2: 26.69 temp3: 24.12
b'25.50,24.50,26.69,24.12\r\n'
temp0: 25.50 temp1: 24.50 temp2: 26.69 temp3: 24.12
b'25.50,24.50,26.69,24.12\r\n'
temp0: 25.50 temp1: 24.50 temp2: 26.69 temp3: 24.12
b'25.50,24.50,26.69,24.12\r\n'
Ich denke, man kann das Problem ganz gut erkennen. Eine gute Lösung habe
ich noch nicht gefunden.
Ich habe schon versucht vor dem Lesevorgang mit ser.flushInput() den
Eingangspuffer zu leeren. Das hat die Fehlerrate aber eher
verschlechtert.
Danke im Vorraus.
Marvin
In welchen Intervallen werden die Daten gesendet? Könnte mir vorstellen,
dass der Buffer zwischendurch vollläuft. Benutzt du den Standard Windows
CDC Treiber oder einen von einem bestimmten Hersteller? Je nach Treiber
gibt es keinen zirkulären Buffer für die seriellen Daten, sondern er
läuft einfach voll, wenn du nicht schnell genug ausliest.
Hast du mal probiert, deine gettemp funktion in kürzeren Intervallen
aufzurufen? In 60 Sekunden können 60 x 25 = 1500 byte auflaufen, das
könnte auf einem embedded System schon die größe des buffers sein.
Versuch einfach mal testweise ein Intervall von 1 Sekunde.
Ich hab jetzt mal testweise den Scheduler auf eine Sekunde gestellt.
Bisher gab es damit noch keine Auffälligkeiten. Ich werde es so mal
etwas laufen lassen.
Jim M. schrieb:> Wieso wird da überhaupt der Scheduler verwendet? Die> ser.readline()> Funktion müsste doch von sich aus blockieren?
Ja, das tut sie, aber ich bekäme dann Messwerte im Takt von ETWA einer
Sekunde. Ich will die Daten aber im Takt von genau 60 Sekunden in eine
Datenbak schreiben.
Ich gehe mal davon aus, dass sich der Puffer an einer sinnvollen Stelle
leeren lässt, damit ich das Messintervall wieder vergrößern kann.
Marvin schrieb:> Ja, das tut sie, aber ich bekäme dann Messwerte im Takt von ETWA einer> Sekunde. Ich will die Daten aber im Takt von genau 60 Sekunden in eine> Datenbak schreiben.
So wie es jetzt ist, ist es aber unvorhersehbar, welchen Messwert du
kriegst. Du weißt nämlich nicht, wann den Puffer vollgelaufen ist bzw
wie alt der Messwert, den du liest, ist. Wenn du einen aktuellen Wert
alle 60 Sekunden willst musst du entweder die Werte in einer while
Schleife so lesen wie sie reinkommen und dann bei jeder Iteration prüfen
ob 60 Sekunden vergangen sind und dann den Wert in die DB schreiben.
Oder du schedulest alle 60 sekunden einen Flush des input buffers und
wartest dann auf die nächste line.
Felix U. schrieb:> Wenn du einen aktuellen Wert alle 60 Sekunden willst musst du entweder> die Werte in einer while Schleife so lesen wie sie reinkommen und dann> bei jeder Iteration prüfen ob 60 Sekunden vergangen sind und dann den> Wert in die DB schreiben.
Damit schreibst Du nur jeden 60sten Wert weg und 59 andere verwirfst Du.
Wenn man schon jede Sekunde einen Wert bekommt, aber nur jede Minute
einen Wert protokollieren will, würde ich die Messwerte immer für eine
Minute mitteln und dann den Mittelwert in die DB schreiben. Dann haben
die 60 erhaltenen Werte wenigstens einen Sinn.
Frank M. schrieb:> Damit schreibst Du nur jeden 60sten Wert weg und 59 andere verwirfst Du.
So scheint es vom Fragesteller ja gewollt zu sein, zumindest habe ich
das aus dem urpsrünglichem Code entnommen.
Felix U. schrieb:> So scheint es vom Fragesteller ja gewollt zu sein,
Mag ja sein, trotzdem sollte er die gesandten Daten nicht einfach
ignorieren, sonst greift er willkürlich jede Minute irgendwelche im
Empfangspuffer befindliche Daten ab.
Darf ich mal fragen, ob Du einen original Arduino Uno mit FTDI benutzt
oder einen CH340?
Letzterer macht mit mit Chinaclones vermehrt Probleme, da der
Linuxtreiber (auch auf dem Raspberry) nicht 100% kompatibel mit dem
Chipsatz ist.
Probiere einfach mal Dein Pythonskript auf einem MAC oder Windows PC
aus. Wenn Du dort Deine Daten korrekt eingelesen bekommst, dann hast Du
den Übeltäter. Dann hast Du die Wahl zwischen Treiber oder Arduino mit
FTDI
Grüße
Tony