Temperaturmesswerte über RS232 einlesen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Regret
User
Beiträge: 17
Registriert: Freitag 20. Mai 2016, 10:58

Also ich hab das nochmal mit "time.sleep()" probiert:

Code: Alles auswählen

while True:
		port.write('s\n')
		newline = port.readline()
		newline = newline[13:21]
		RefTemp.write('%s;%s;\n' % (newline, time.ctime()))
		print newline
		time.sleep(0.333)
Mit einer sleeptime von 0.333sek bekomm ich jetzt pro Sekunde ein Messwert (Ich hab es mal eine Minute lang laufen lassen).

Leider ist das Ergebniss weiterhin wie folgt:

Code: Alles auswählen

;Wed May 25 08:56:30 2016;
;Wed May 25 08:56:31 2016;
+021.894;Wed May 25 08:56:31 2016;
;Wed May 25 08:56:31 2016;
;Wed May 25 08:56:32 2016;
+021.894;Wed May 25 08:56:32 2016;
...
Da ich die weitere Auswertung mit "R" mache könnte ich natürlich auch einfach alle Zeilen die kein "+" am Anfang haben löschen lassen, aber mich fuchst es jetzt schon irgendwie das die Ausgabe nicht schon mit Python wie gewünscht aussieht. Also im Optimalfall:

Code: Alles auswählen

+021.894;Wed May 25 08:56:31 2016;
+021.894;Wed May 25 08:56:32 2016;
+021.894;Wed May 25 08:56:33 2016;
+021.894;Wed May 25 08:56:34 2016;
...
EDIT:

Code: Alles auswählen

RefTemp.write('%s %s \n' % (newline, time.ctime()))
Kann ich in der Zeile eigentlich nicht anpassen, dass die ; nicht auftauchen, bzw. ein Leerzeiche zwischen Temperatur und Datum ist? Und lässt sich time.ctime() auch abändern um den Zeitstempel viellleicht so aussehen zu lassen: 08:56:31 25.05.2016
Regret
User
Beiträge: 17
Registriert: Freitag 20. Mai 2016, 10:58

Also ich habs jetzt hinbekommen. Ist vielleicht gepfuscht und geht durchaus eleganter wenn man die ganzen Modules kennt aber so funktioniert es:

Code: Alles auswählen

import time
import serial

port = serial.Serial("/dev/ttyS0", 115200, timeout=1) #oeffnet den serial port S0

RefTemp = open("RefTemp.dat", "w")
RefTemp.close()
sleep = 1/3.
i = 0
x = 2


try:
	RefTemp = open("RefTemp.dat", "w")
	while True:
		port.write('s\n')
		time.sleep(sleep)
		localtime   = time.localtime()
		timeString  = time.strftime("%Y.%m.%d %H:%M:%S", localtime)
		newline = port.readline()
		newline = newline[13:21]
		if i == x:
			RefTemp.write('%s %s \n' % (newline, timeString))
			x = x+3
		print i, newline
		i = i+1
		
		
		
except KeyboardInterrupt:
	pass
	RefTemp.close()
Im Endeffekt hab ich die Schleifenanzahl die hochzählt mit "i" deklariert. "x" ist die Zeilennummer die ich will (ist ja in meinem Fall jede 3.).
Wenn jetzt die Schleife durchläuft vergleiche die if-Funktion i mit x und wenn die Schleifenanzahl i (und damit die aktuelle Zeilennummer) mit der gewünschten Zeilennummer x übereinstimmt schreibt er den Wert auf und addiert auf die gewünschte Zeilennummer eine 3, weil ich ja jede dritte Zeile will.

Das Ergebnis ist:

Code: Alles auswählen

+022.690 2016.05.25 14:23:38 
+022.689 2016.05.25 14:23:39 
+022.689 2016.05.25 14:23:40 
+022.689 2016.05.25 14:23:41 
+022.690 2016.05.25 14:23:42 
...
Falls noch jemand eine schönere Lösung hat wäre ich daran interessiert :)
BlackJack

@Regret: Hm, Du willst jede Sekunde einen Wert, Du wartest immer eine Drittelsekunde und bei jedem dritten lesen ist dann auch ein Wert tatsächlich vorhanden. Wäre es da nicht sinnvoller nur jede Sekunde einen Wert zu lesen und den dann halt auch *tatsächlich*?

Oder überhaupt nicht mit `sleep()` warten sondern den Timeout deutlich über eine Sekunde setzen, damit `readline()` entsprechend auf die Zeile wartet, die von der Gegenseite ja offensichtlich nur einmal in der Sekunde gesendet wird.
Regret
User
Beiträge: 17
Registriert: Freitag 20. Mai 2016, 10:58

@BlackJack: Im endeffekt hast du recht, das drittel Sekunde war allerdings noch aus einem Versuch und da hat es kein unterschied gemacht ob ich garkein Sleep nutze oder 1/3 Sekunde. Ich geh mal davon aus, das dass Messgerät daher sowieso nur einmal die Sekunde antwortet. Ich hab das Gerät leider grad nicht mehr da aber die Kalibrierung ist für Dienstag geplant. Dann werd ich das nochmal testen und ein Feedback geben.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@Regret: Das Messgerät antwortet nach Deinen bisherigen Posts öfter als nur einmal pro Sekunde, scheint aber nach einer Abfrage den nächsten Messwert erst mit einer Latenz von 1 Sekunde liefern zu können.

Die Messroutine könnte man auch wie folgt schreiben, in der Annahme, dass nach 'port.write' die Daten sofort geliefert werden, es anschließend aber ca. 1 sec. braucht, um den nächsten Messwert bereitzustellen (ungetestet):

Code: Alles auswählen

with open("RefTemp.dat", "w") as out:
    while True:
        port.write('s\n')
        data = port.readline()
        temperature = data[13:21]
        if temperature:
            time_stamp = time.strftime("%Y.%m.%d %H:%M:%S", time.localtime())
            out.write('%s %s \n' % (temperature, time_stamp))
            print(temperature)
            time.sleep(1)
Eventuell muss das 'time.sleep()' noch etwas angepasst werden, damit auch jede Sekunde erfasst, und nicht gelegentlich eine übersprungen wird.
BlackJack

@kbr: Wie kommst Du darauf dass das Messgerät öfter als jede Sekunde etwas sendet? Auf dem `Serial()`-Objekt ist ein Timeout gesetzt. Dann kehrt `readline()` auch zurück wenn das überschritten ist und zwar mit so viel Daten wie bis dahin gelesen werden konnten. Was anscheinend zweimal je Drittelsekunde eine leere Zeichenkette und einmal eine komplette Messung ist. Deswegen ja mein Vorschlag einfach das Timeout auf deutlich mehr als eine Sekunde zu setzen, dann wartet `readline()` eine Sekunde auf die Messung und gibt die dann zurück wenn sie kommt. Auf Empfängerseite könnte man sich das `sleep()` dann sparen.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@BlackJack: Das Timeout steht ja eben auf einer Sekunde. Wenn bereits nach einer Drittelsekunde als Return eine leere Zeichenkette kommt, dann hat das Messgerät reagiert und etwas gesendet, ohne dass das Timeout überschritten wurde. Was bringt dann die Erhöhung eines Timeouts?
BlackJack

@kbr: Ah, das hatte ich nicht gesehen dass das Timeout mittlerweile bei einer Sekunde liegt und nicht mehr bei 0.2. Wobei auch ”genau” eine Sekunde keine gute Idee ist wenn man nach einer Sekunde eine Antwort erwartet. So genau ist das ja alles nicht und dann könnte es trotzdem passieren, dass der Timeout ganz knapp vor der Antwort abläuft. Ich würde dann auch `data` prüfen ob da überhaupt etwas drin ist, um auf den Fall reagieren zu können, dass von der Gegenseite nichts mehr kommt. Also Beispielsweise Timeout 60 Sekunden, und wenn `data` dann leer ist, dann kann man recht sicher sein, dass da offenbar nix mehr kommt.
Regret
User
Beiträge: 17
Registriert: Freitag 20. Mai 2016, 10:58

So, sorry ich war das Wochenende über nicht mit dem Thema beschäftigt.

Morgen hab ich das Messgerät wieder und probier dann nochmal eure Vorschläge.
kbr hat geschrieben:@Regret: Das Messgerät antwortet nach Deinen bisherigen Posts öfter als nur einmal pro Sekunde, scheint aber nach einer Abfrage den nächsten Messwert erst mit einer Latenz von 1 Sekunde liefern zu können....

Ich bin mir nicht sicher, ob das Messgerät den nächsten Messwert erst mit einer Sekunde Latenz liefern kann. Wenn ich mit "Screen" auf die Serielle Schnittstelle zugreife seh ich im Terminal alles was an der Schnittstelle empfangen wird. (siehe http://www.fotos-hochladen.net/uploads/ ... y1025n.jpg). Hier sieht man ganz gut, dass ich einfach über Screen ein "s" über die Schnittstelle an das Messgerät versendet habe und es mir instant eine Antwort gibt (beispielsweise bei 00:18:02 drei mal in einer Sekunde, weil ich halt dreimal die Sekunde auf die Taste gedrückt habe).
Regret
User
Beiträge: 17
Registriert: Freitag 20. Mai 2016, 10:58

Hey Leute,

also ich hab das ganze jetzt nochmal getestet. Mein Skript lief zwar, das war aber nur Schein. Es gab nämlich die Messwerte des Gerätespeichers um 100 Werte in die Vergangenheit aus. (Ist aufgefallen als sich mal die Temperatur am Fühler geändert hat).

Ich hab mich also nochmal dran gesetzt und rausgefunden, dass es mit port.readline() zu tun hatte. Ich hab es mit port.readall() ersetzt und siehe da: Keine Leerzeilen mehr in der Ausgabe und der IST-Wert war direkt da. Dann musste ich nur noch den String zurecht stutzen und den Timeout anpassen bis wirklich ein Wert die Sekunde ausgegeben wurde. (bei einer Sekunde Timeout wurde nur jede zweite Sekunde ein Wert ausgegeben).

Also aktuell sieht das ganze so aus:

Code: Alles auswählen

#!/usr/bin/env python


import time
import serial

port = serial.Serial("/dev/ttyS0", 115200, timeout=0.5)

RefTemp = open("RefTemp.dat", "w") 	
RefTemp.close()
sleep = 1/3.
i = 0


try:
	RefTemp = open("RefTemp.dat", "w")
	while True:
		localtime   = time.localtime()
		timeString  = time.strftime("%Y.%m.%d %H:%M:%S", localtime)
		port.write('s\n')
		newline = port.readall()
		newline = newline[17:25]
		RefTemp.write('%s %s %s \n' % (i, newline, timeString))
		print i, newline, timeString
		i = i+1
		
		
		
except KeyboardInterrupt:
	pass
	RefTemp.close()
Die Kalibrierung hat damit hervorragend geklappt. Viele Dank für eure Unterstützung und Hilfestellung :)
Zuletzt geändert von Anonymous am Mittwoch 1. Juni 2016, 10:40, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

@Regret: dass ein readline andere Werte liefert als ein readall halte ich mal für ausgeschlossen. Es scheint eher noch ein falsches Zeileende-Zeichen zu sein. Und dass ein timeout von einer halben Sekunde Daten im Sekundentakt liefert ist auch komisch.

Das leeren der Datei in Zeile 9/10 ist unnötig, wird in Zeile 16 sowieso gemacht.
Für einen Zähler gibt es count aus dem itertools-Modul, statt des Selberzählen mit einer while-Schleife.
Regret
User
Beiträge: 17
Registriert: Freitag 20. Mai 2016, 10:58

@Sirius3: Vielen Dank für den Hinweis, das mit den Zähler kenn ich halt noch von einem Grundkurs in C++ vor Jahren. Aber ein "richtiger" Zähler ist natürlich eleganter.

Das mit dem Timeout versteh ich auch nicht ganz. Aber ich hab das Skript jetzt die ganze Nacht laufen lassen und mal eine Stunde "ausgewählt" das sollten eigentlich 3600 Messwerte sein, sind aber Effektiv 3594. Also ich denke die 6 fehlenden Messwerte lassen sich mit der aufsummierten Rechenzeit erklären oder?

Zu dem readline: meinst du mit Zeilenende das \n? Also ich mein generell ist es ja egal ob ich jetzt alles einles und einfach den String "zurecht schneide" oder ob ich readline nutze und diesen String anpasse oder?

Das leeren der Datei in 9/10 sollte eigentlich eher das erstellen der Datei sein. Im Normalfall gibt es die Datei nämlich noch garnicht und ich hatte gelesen das die mit "w" auf den Weg automatisch erstellt wird. Ich dachte eben bei dem Skript ich erstell erstmal die Datei und füll diese dann mit der Schleife. Könnte ich eigentlich den Dateinamen so wählen, dass der Zeitstempel zu Beginn integriert ist? Also ähnlich wie RefData_20160602_9004 ?
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Regret hat geschrieben:Das mit dem Timeout versteh ich auch nicht ganz. Aber ich hab das Skript jetzt die ganze Nacht laufen lassen und mal eine Stunde "ausgewählt" das sollten eigentlich 3600 Messwerte sein, sind aber Effektiv 3594. Also ich denke die 6 fehlenden Messwerte lassen sich mit der aufsummierten Rechenzeit erklären oder?
Bei einem timeout von 0.5 sec würde ich ca. 7200 Messwerte erwarten - mindestens. Was liefert das Messgerät wirklich zurück? Und mit welcher Latenz, falls es eine gibt? Wenn das klar ist kannst Du beginnen das Programm, ohne zu raten, sauber zu implementieren.
Regret
User
Beiträge: 17
Registriert: Freitag 20. Mai 2016, 10:58

Du hast natürlich recht, das habe ich auch erwartet. Aber in dem Fall hab ich halt einfach ausprobiert, bis es "gepasst" hast.

Ich bin eigentlich jetzt mit dem Kalibrieren durch aber das Thema beschäftigt mich trotzdem, weil das Skript eventuell noch Leute nach mir nutzen könnten. Ich hab mir jetzt überlegt das ich ja eigentlich auch mehr Messwerte wie einmal die Sekunde aufnehmen könnte und es dann in der vorhandenen while-Schleife mit einer if-Funktion so verarbeiten könnte: "Wenn der Zeitstempel mit der Zeile vorher exakt auf die Sekunde genau übereinstimmt verwerfe, ansonsten schreibe die Zeile." Damit würde ich umgehen das mir über eine Stunde gesehen 6 Messwerte flöten gehen und im Endeffekt wär es egal wie häufig mir das Gerät antwortet bzw. wie der Timeout gesetzt ist, hauptsache ich habe mindestens einen Messwert pro Sekunde, oder was haltet ihr davon?

Ich mein damit ist natürlich die Frage wieso ein Timeout von 0.5sek einen Messwert pro Sekunde resultiert nicht gelöst, aber eben die Problematik umgangen...

Viele Grüße
Antworten