Serielle Schnittstelle

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.
Antworten
wattwurm
User
Beiträge: 29
Registriert: Sonntag 25. Januar 2015, 17:27
Wohnort: Nordsee

Moin,
ich bekomme von einen Arduino Temperaturwerte die ich mit Python2 über serielle Schnittstelle abfrage:

Code: Alles auswählen

#!/usr/bin/env python2
# coding: utf-8
import serial

def rauchgastemperatur():
    ### with verwenden!
    with serial.Serial('/dev/ttyUSB0') as tty:
        #tty = serial.Serial('/dev/ttyUSB0')
        #while True:
        #    print tty.readline()
        temperatur = tty.readline()
    #Abbruch einbauen!!!
    #tty.close()
    #print tty 
    return temperatur

def main():
    #wegen Abbruch (strg+c)
    try:
         while True:
            print rauchgastemperatur()
    except KeyboardInterrupt:
        serial.Serial('/dev/ttyUSB0').close()       
        print serial.Serial('/dev/ttyUSB0')
if __name__== '__main__':
    main()
Ausgabe:

Code: Alles auswählen

thomas@raspberry:~/heizung$ ./testSerial.py 


22

22

27

26

22

22

^CSerial<id=0xb6cd3fb0, open=True>(port='/dev/ttyUSB0', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)
Frage1:
Wieso wird die die Schnittstelle nicht geschlossen? "open=True>(port='/dev/ttyUSB0)"


Frage2:
Wie bekomme ich die Leerzeichen(zeilen) weg? (evtl. kommen die aber auch schon vom Arduino :?: )


Danke + Gruß
Thomas
Benutzeravatar
__blackjack__
User
Beiträge: 13063
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@wattwurm: Ad 1: Du öffnest die Schnittstelle einmal in der `rauchgastemperatur()`-Funktion. Dort wird sie durch das ``with`` auch wieder geschlossen.

Dann öffnest Du die Schnittstelle im ``except KeyboardInterrupt:``-Zweig und schliesst sie gleich wieder. Das ist total sinnlos. Und dann kommt das ``print`` wo Du die Schnittstelle ebenfalls noch einmal öffnest und, nun ja, dann ist sie halt offen. Lass den Unsinn im ``except`` einfach komplett sein.

Ad 2: Es kommt ein Zeilenende vom Arduino, und eines durch ``print``. Ich würde das vom Arduino entfernen.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python2
# coding: utf-8
from __future__ import absolute_import, division, print_function
import serial


def main():
    try:
        with serial.Serial('/dev/ttyUSB0') as lines:
            for line in lines:
                print(line, end='')
    except KeyboardInterrupt:
        pass  # Intentionally ignored.


if __name__ == '__main__':
    main()
Edit: Und steig auf Python 3 um. :-)
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
wattwurm
User
Beiträge: 29
Registriert: Sonntag 25. Januar 2015, 17:27
Wohnort: Nordsee

Danke Blackjack!
Lass den Unsinn im ``except`` einfach komplett sein.
:lol:
ok, ich wollte damit auch nur prüfen ob dei Schnittstelle nun geschlossen ist oder nicht (das ging ja nach hinten los) :roll:

Code: Alles auswählen

from __future__ import absolute_import, division, print_function
<-- Das gucke ich mir gleich an.
wattwurm
User
Beiträge: 29
Registriert: Sonntag 25. Januar 2015, 17:27
Wohnort: Nordsee

@Blackjack, dass Script läuft, die Leerzeilen sind weg.
Ich denke auch das es besser wäre die Leerzeilen im Arduino zu killen, da muß ich mal suchen wie das geht.

Code: Alles auswählen

from __future__ import absolute_import, division, print_function
Das mit Python3 werde ich mir mal überlegen
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich wuerde die genau NICHT im Arduino killen. Die serielle Schnittstelle braucht ein Protokoll. Das einfachste, was man machen kann, ist immer zeilenweise einlesen. Und darum solltest du daran nicht rumfummeln.
Benutzeravatar
__blackjack__
User
Beiträge: 13063
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Die Frage ist vielleicht auch ob es nicht sinnvoll wäre die Zeilen mit den Ziffernfolgen tatsächlich in Zahlen umwandeln.

Zum Thema Python 3: Bei Python 2 ist dieses Jahr Ende. Neues damit anzufangen macht eher keinen Sinn.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
DeaD_EyE
User
Beiträge: 1016
Registriert: Sonntag 19. September 2010, 13:45
Wohnort: Hagen
Kontaktdaten:

Mit CR/LF bzw LF lässt sich ein Serielles Protokoll zeilenbasiert behandeln. Sendet man hingegen irgendein anderes Steuerzeichen am Zeilenende, muss man erstmal gucken wie man das mit PySerial macht. Ein binäres Protokoll würde eine Bytefolge für den Start benötigen und eine feste Definition des Protokolls.

Ich würde einfach die Methode str.rstrip() benutzen, um das Zeilenende aus dem String zu entfernen.
Mal angenommen du wechselst jetzt auf Python 3, dann würde dein Code weiterhin funktionieren, aber bei der Ausgabe hättest du die präsentation als Bytes: b'das was du empfangen hast'
PySerial empfängt und sendet bytes. In der Schliefe müsstest du dann die Zeile dekodieren.

Bytes -> decode() -> String
String -> encode() -> Bytes

Code: Alles auswählen

# Python 3
        with serial.Serial('/dev/ttyUSB0') as lines:
            for line in lines:
                line = line.rstrip().decode()
                print(line, end='')
sourceserver.info - sourceserver.info/wiki/ - ausgestorbener Support für HL2-Server
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

Da es sich um Zahlen handelt, die sicher irgendwie weiterverarbeitet werden sollen, am besten gleich umwandeln:

Code: Alles auswählen

        with serial.Serial('/dev/ttyUSB0') as lines:
            for line in lines:
                temperature = int(line)
                print(temperature)
wattwurm
User
Beiträge: 29
Registriert: Sonntag 25. Januar 2015, 17:27
Wohnort: Nordsee

Hallo,
ich habe nun mal die Strings in Integer umgewandelt.
Nun kommt aber folgende Fehlermeldung:

Traceback (most recent call last):
File "serial_byte_convert.py", line 8, in <module>
print(int(line))
ValueError: invalid literal for int() with base 10: ''

Da wird wohl versucht was umzuwandeln was aber nicht möglich ist (Leerzeile, Leerzeichen oder NULL character).
Kann es sein das die Serielle Übertragung noch nicht vollständig beendet, bzw. gestartet ist?
Wie kann man dem entgegenwirken?

Ich dachte an sowas:

Code: Alles auswählen

  if type(x) == int:
        ...
    else:
        ....
habe aber gelesen das sei nicht so elegant?

Ohne Umwandlung laufen die Scripte und man sieht die Problemstellen, jeweils 1. Zeile:

Code: Alles auswählen

/heizung$ python3 serial_byte.py 
<class 'str'> 			[color=#BF00BF]<<<<<<<=======[/color]
<class 'str'> 198
<class 'str'> 199
<class 'str'> 198
<class 'str'> 196
<class 'str'> 193
<class 'str'> 193

Code: Alles auswählen

~/heizung$ python3 serial2arduino.py
b'\x00\n'			[color=#804080]<<<===[/color]
b'27\r\n'
b'27\r\n'
b'26\r\n'
b'23\r\n'
b'21\r\n'
^Xb'22\r\n'
Danke und Gruß
Thomas
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

Du startest irgendwo mit der Übertragung, da kann e s eben sein, dass die erste Nachricht korrupt ist.
wattwurm
User
Beiträge: 29
Registriert: Sonntag 25. Januar 2015, 17:27
Wohnort: Nordsee

Ja, dass kann ich mir vorstellen, man steigt ja auch nicht in einem fahrenden Zug ein.
Habe es nun so geschrieben (zumindest läuft es).

Geht es auch ohne die while-Schleife?

Code: Alles auswählen

~/heizung$ cat serial2arduino.py
#!/usr/bin/env python3
#coding: utf-8
import serial
def main():
    while True:
        try:
            with serial.Serial('/dev/ttyUSB0') as lines:
                for line in lines:
                    print(int(line))
        except ValueError:
            print('->NaN<-: Warten')
        except KeyboardInterrupt:
             #pass
             break

if __name__ == '__main__':
    main()

Code: Alles auswählen

/heizung$ python3 serial2arduino.py
->NaN<-: Warten
141
141
141
142
144
145
146
145
144
^Cthomas@raspberry:~/heizung$
Benutzeravatar
__blackjack__
User
Beiträge: 13063
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@wattwurm: Ich denke schon.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten