Forum: PC-Programmierung Python3 und PySerial: Diverse Probleme


von Bernd W. (berndwiebus) Benutzerseite


Angehängte Dateien:

Lesenswert?

Hallo

Ich habe das im Anhang befindliche noch sehr rohe Python 3 Skript 
"TestTerminal5b.py" geschrieben, um mich ein wenig in die serielle 
Kommunikation in Python einzuarbeiten.

Während das Senden unter Debian Squeeze erstmal funktioniert, habe ich 
mit dem Empfangen so meine Schwierigkeiten.
Hintergrund ist, das ich eigentlich kontinuierlich auf der Leitung 
lauschen möchte, und "Readline" nicht verwenden kann, weil das 
Empfangene nicht zwangsweise Zeilenenden enthält.
Also habe ich mir etwas zusammengestellt, das eine Anzahl von Bytes 
einliest bzw. einen Timeout bekommt, und ständig neu aufgerufen wird, in 
der Hoffnung, so nichts zu verlieren.
Das ganze ist aber wackelig (es ist ein rohes Konstrukt) und irgendwie 
vom Konzept her unelegant.

Nur fällt mir nichts besseres ein......


Der nächste Punkt ist der, das ich das Skript an jemanden weitergegeben 
habe, der Windows XP benutzt, und dort kommt immer eine Fehlermeldung:
File "C:\Programme\Python\lib\site-packages\serial\serialwin32.py", line
59, in open
    raise SerialException("could not open port %s: %s" % (self.portstr,
ctypes.WinError()))
serial.serialutil.SerialException: could not open port COM1: [Errno 5]
Zugriff verweigert.

Zugriffsrechte auf den Port hat er aber.

Das Problem tritt auf, sobald versucht wird, den Port konkret zu öffnen, 
z.B. mit "Ausgang = open(GlobVariables.stPort, mode="w")" in folgendem 
Codefragment:

1
def Send():
2
  
3
  print("Gewählt Baudrate:" + GlobVariables.stBaud + " an Port: " + GlobVariables.stPort)
4
  
5
  ser = serial.Serial(GlobVariables.stPort, int(GlobVariables.stBaud), timeout=1)
6
  
7
  Ausgang = open(GlobVariables.stPort, mode="w")
8
  Ausgang.write(EntrySendText.get())
9
  Ausgang.flush()  
10
  Ausgang.close()

Mein Verdacht ist nun, das unter Windows schon die Konfigurierung des 
Ports mit "ser = serial.Serial(GlobVariables.stPort, 
int(GlobVariables.stBaud), timeout=1)" den Port belegt und für jeden 
weiteren Zugriff spertrt, und der konkrete Zugriff darauf mit "Ausgang = 
open(GlobVariables.stPort, mode="w")" als erneutes Belegen verstanden 
wird, das nun verboten ist.

Meine Idee dagegen ist, wie im im Anhang befindlichen Skript den obigen 
Codeblock zu variieren, indem ich  den Port mit "ser.close()" ersteinmal 
wieder schliesse und freigebe, bevor ich konkret darauf zugreife. Siehe:

1
def Send():
2
  
3
  print("Gewählt Baudrate:" + GlobVariables.stBaud + " an Port: " + GlobVariables.stPort)
4
  
5
  ser = serial.Serial(GlobVariables.stPort, int(GlobVariables.stBaud), timeout=1)
6
  ser.close()
7
  Ausgang = open(GlobVariables.stPort, mode="w")
8
  Ausgang.write(EntrySendText.get())
9
  Ausgang.flush()  
10
  Ausgang.close()

Leider habe ich selber keine Möglichkeit, das unter XP zu probieren.

Meine Frage darum:
1) Funktioniert das so unter Windows?
2) Macht das nun unter Linux Probleme? (Bei mir scheint es zu laufen)
3) Hat jemand eine bessere Idee?

Mit freundlichem Gruß: Bernd Wiebus alias dl1eic
http://www.dl0dg.de

von masla (Gast)


Lesenswert?

Mit ser = serial.Serial(GlobVariables.stPort, int(GlobVariables.stBaud), 
timeout=1) wird der Port auch gleich geöffnet.
open() ist also nicht notwendig.
Jedenfalls meiner Meinung nach..

Ich benutze eine ältere pyserial-Version , auch unter WinXP.
http://sourceforge.net/projects/relaycontrol/?source=directory

Gruß

masla

von Bernd W. (berndwiebus) Benutzerseite


Lesenswert?

Bernd Wiebus schrieb:

> Während das Senden unter Debian Squeeze erstmal funktioniert, habe ich
> mit dem Empfangen so meine Schwierigkeiten.
~~~~~~~
> Das ganze ist aber wackelig (es ist ein rohes Konstrukt) und irgendwie
> vom Konzept her unelegant.

Wackelig insoweit, das ich es geschafft habe, bisher einmal Daten zu 
empfangen.
Ansonsten kommt meist NICHTS.
Allerdings, komischerweise, wenn ich rohe Binärdaten zum Senden 
verwende, bekomme ich manchmal eine Fehlermeldung, das sie nicht utf8 
decodiert werden können??????
Also scheint doch irgendwas anzukommen.

Ich verwende einen USB zu Seriell Adapter (ttyUSB0) auf beiden Seiten. 
Mit CuteCom auf beiden Seiten keine Probleme. CuteCom benutze ich auch 
als Gegenstelle für "TestTerminal5b.py".

> Nur fällt mir nichts besseres ein......
Ich bin sehr ratlos.

Mit freundlichem Gruß: Bernd Wiebus alias dl1eic
http://www.dl0dg.de

von THaala (Gast)


Lesenswert?

Schau Dich doch mal beim RepRap - Projekt um.
Die benutzen Python-scripts zum kommunizieren mit dem Arduino.

Meiner Erfahung nach funktionieren diese Dinge auch zufriedenstellend 
und zuverlässig.

Die Stichworte wären PRONTERFACE bzw. Repetier-Host

Ich hoffe das hilft.

Gruß Thilo

von THaala (Gast)


Lesenswert?

Habe z.B. das hier gefunden:

https://github.com/kliment/Printrun/blob/master/pronsole.py


Gruß T.

von adsf (Gast)


Lesenswert?

kannst du den empfangen wenn du in einer endlosschleife nur liest?
Falls ja, dann lager das lesen in einen thread aus, ein Beispiel ist in 
den Beispielen zu pyserial zu finden.

von Bernd W. (berndwiebus) Benutzerseite


Lesenswert?

Hallo Masla, Thilo und adsf.

Danke für Eure Tipps.

> Mit ser = serial.Serial(GlobVariables.stPort, int(GlobVariables.stBaud),
> timeout=1) wird der Port auch gleich geöffnet.
> open() ist also nicht notwendig.
> Jedenfalls meiner Meinung nach..

Interessant. Werde ich beim nächsten größeren Umbau garantiert 
probieren. Aber zumindest eine Angabe, ob ich den Port zum lesen oder 
schreiben öffne müsste ich noch hineinbringen, oder habe ich es hier mit 
extrem fortschrittlichen Duck-typing zu tun?

> Habe z.B. das hier gefunden:
> https://github.com/kliment/Printrun/blob/master/pronsole.py

Auch interessant. Die benutzen wohl irgendwas anderes als pyserial, weil 
ich im Header nichts mit "import serial" finde. Ist natürlich Python 2, 
kann ja sein, dass das dafür anders lautet. Jedenfalls muss ich da noch 
mal in die Tiefe gehen. Offensichtlich ist es für mich jedenfalls noch 
nicht.  Könnte auch sein, das pyserial erst von irgendeinem der anderen 
verwendeten Module verwendet wird.

> kannst du den empfangen wenn du in einer endlosschleife nur liest?
> Falls ja, dann lager das lesen in einen thread aus, ein Beispiel ist in
> den Beispielen zu pyserial zu finden.

Ha, das ist ja gerade das merkwürdige. Mir ist es genau zweimal 
gelungen, das Programm zu starten und dann etwas zu empfangen. Und zwar 
auf den kurzen Blick sogar recht gut und zuverlässig. Ich habe darum die 
"Hoffnung" das ich selber etwas mit den Parametereinstellungen 
zerdengelt habe, und durch "irgendetwas" dann doch mal den passenden 
Parameter einstelle. In dem Zusammenhang werde ich also mein Konstrukt 
noch einmal heftigst durchsuchen müssen.
Auf der anderen Seite lese ich bei falschen Parametereinstellungen unter 
CuteCom meist noch irgendwelchen Müll.....hier kriege ich nur manchmal 
eine Fehlermeldung bezüglich misslungenem utf8 decoding, wenn ich eine 
Binärdatei sende.....achselzuck.

Leider bin ich z.Z. etwas eingeschränkt und komme erst die nächsten Tage 
wieder dazu, mir vorübergehend ein Hardwaresetup hinzustellen, mit dem 
ich wieder serielle Schnittstellen (per USB Adapter) betreiben und 
untersuchen kann.

Ob das ganze dann auch unter Windows läuft, ist wieder eine andere 
Nummer. Erst muss es überhaupt hier unter Linux laufen.....dann schaue 
ich weiter. Alles der Reihe nach.

Mit freundlichem Gruß: Bernd Wiebus alias dl1eic
http://www.dl0dg.de

von Yalu X. (yalu) (Moderator)


Lesenswert?

Deinen eigenen Code habe ich mir nicht im Detail angeschaut, da mir
gerade etwas die Zeit dazu fehlt.

Hier sind trotzdem ein paar Hinweise zu deinen letzten Fragen:

Bernd Wiebus schrieb:
>> Mit ser = serial.Serial(GlobVariables.stPort, int(GlobVariables.stBaud),
>> timeout=1) wird der Port auch gleich geöffnet.
>> open() ist also nicht notwendig.
>> Jedenfalls meiner Meinung nach..
>
> Interessant. Werde ich beim nächsten größeren Umbau garantiert
> probieren.

Auszug aus der pySerial-Doku in 
http://pyserial.sourceforge.net/pyserial_api.html :
1
class serial.Serial
2
3
__init__(port=None, baudrate=9600, bytesize=EIGHTBITS,
4
         parity=PARITY_NONE, stopbits=STOPBITS_ONE, timeout=None,
5
         xonxoff=False, rtscts=False, writeTimeout=None,
6
         dsrdtr=False, interCharTimeout=None)
7
    ...
8
    The port is immediately opened on object creation, when a port
9
    is given. It is not opened when port is None and a successive
10
    call to open() will be needed.

Wenn du also für das Argument port einen Namen oder eine Nummer
angibst, wird das Device sofort geöffnet, und ein nachfolgendes open
macht dann logischerweise Schwierigkeiten:

- Windows meckert, weil die Schnittstelle bereits geöffnet ist.

- Unter Linux kannst du die Schnittstelle zwar mehrmals parallel öffnen,
  was kann aber zum Datenchaos führen kann, wenn mehrere Threads oder
  Prozesse versuchen, davon zu lesen.

> Aber zumindest eine Angabe, ob ich den Port zum lesen oder schreiben
> öffne müsste ich noch hineinbringen, oder habe ich es hier mit extrem
> fortschrittlichen Duck-typing zu tun?

Serielle Schnittstellen werden üblicherweise immer zum Lesen und zum
Schreiben geöffnet. Das macht auch pySerial so.

> Auch interessant. Die benutzen wohl irgendwas anderes als pyserial,
> weil ich im Header nichts mit "import serial" finde.

Der Zugriff auf die serielle Schnittstelle verbirgt sich im Modul
printcore :

  https://github.com/kliment/Printrun/blob/master/printcore.py

Dort wird serial importiert.

Wie ich beim Überfliegen deines Codes gesehen habe, öffnest und schließt
du die Schnittstelle mehrmals. Sendet der Gegenüber Daten, während die
Schnittstelle gerade geschlossen ist, gehen diese Daten verloren. Öffne
die Schnittstelle nur ein einziges Mal am Anfang des Programms, und lass
das am besten das Serial -Objekt bei dessen Instanziierung (wie in der
pySerial-Doku beschrieben) selber machen. Danach kannst du nach Belieben
mit den Member-Funktionen write und read Daten senden und empfangen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.