Hallo Forum
Ich schreibe hier und heute zum ersten Mal.
( Soll ich mich explizit vorstellen? - in manchen Foren ist das ueblich.....)
Mein Problem ist aus meiner Sicht kein Problem.
Leider ist es fuer mich ein grosses Problem
Folgender *uralter* und sehr simpler GW-BASIC-Code liegt mir vor und funktioniert auf entsprechender Hardware einwandfrei:
100 OPEN "COM1:2400,N,8,2,CS10000,DS" FOR RANDOM AS #1
130 CLS
200 INPUT " Loknr. (1-80) "; LN
210 INPUT " Geschw. (0-15) "; GE
300 PRINT #1, CHR$(GE); CHR$(LN);
Das Ganze soll nun auf einem aktuellen Laptop mittels Python realisiert werden.
Dazu habe ich nach vielen Stunden folgenden Code bereitgestellt, der - wie kann es auch anders sein - nicht funktioniert.
import serial
interface=serial.Serial('COM6', 2400, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_TWO, timeout=10)
lok= hex(42)
print (lok)
speed = hex(5)
print (speed)
interface.write(b'\r0x5')
interface.write(b'\r0x2a')
print(b'\r0x5\r')
print(b'\r0x2a\r')
interface.close()
Alles an Hilfe ist willkommen, vielen Dank
Matze
GWBASIC vs. Python - serielle Uebertragung
Serial-Objekte öffnet man wie Dateien innerhalb eines with-Statements.
Ein "funktioniert nicht" ist keine gute Fehlerbeschreibung. Hier kann man raten, was Du eigentlich übertragen willst. Woher hast Du "\r0x5" her?
Ein "funktioniert nicht" ist keine gute Fehlerbeschreibung. Hier kann man raten, was Du eigentlich übertragen willst. Woher hast Du "\r0x5" her?
Code: Alles auswählen
import serial
with serial.Serial('COM6',
2400,
bytesize=serial.EIGHTBITS,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_TWO,
timeout=10) as interface:
lok = 42
speed = 5
interface.write(bytes([speed, lok]))
- __blackjack__
- User
- Beiträge: 13112
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@Zellsius: Die beiden "\r" bei den gesendeten Daten sind komisch, weil die an der Stelle nicht dem entsprechen was das BASIC-Programm macht. Da werden erst zwei Daten-Bytes gesendet und dann sendet das PRINT noch einen Wagenrücklauf *nach* den beiden Datenbytes. Also das Beispiel von Sirius3 noch um eine 13 nach `speed` und `lok` ergänzt.
Edit: Gnarf, stimmt gar nicht, das BASIC-Programm sendet gar keinen Wagenrücklauf, also 100% das Beispiel von Sirius3.
GW-BASIC-Programme kann man übrigens auch mit Python ausführen lassen: http://robhagemans.github.io/pcbasic/
Edit: Gnarf, stimmt gar nicht, das BASIC-Programm sendet gar keinen Wagenrücklauf, also 100% das Beispiel von Sirius3.
GW-BASIC-Programme kann man übrigens auch mit Python ausführen lassen: http://robhagemans.github.io/pcbasic/
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Hallo nochmals
Alles funktioniert nun soweit einwandfrei - wenn da nicht dieses immer wieder auftretende *Aber.........* waere.
Durch die Verwendung des with-Statements wird die Verbindung nach jedem Aufruf wieder getrennt bzw. geschlossen und muss beim naechsten Auslesen der Daten neu geoeffnet werden.
Mein Programm hat jedoch die Hauptaufgabe, ZWEI COM-Ports staendig geoeffnet zu haben.
Vom einen wird gelesen, in den anderen wird geschrieben.
Jedes Mal, wenn ich die Ports neu oeffne, dauert das eine gewisse Zeit ( einer davon ist Bluetooth) und es kommt hin und wieder vor, dass da noch irgendwelche Zeichen im Buffer waren und die Verbindung nicht wieder hergestellt werden konnte.
Meinetwegen duerfen die Ports jedoch staendig an meinen Code gebunden sein, sie werden anderweitig nicht benoetigt.
Gibt es da eine clevere Vorgehensweise?
Gerne sende ich auch meinen bisherigen Code - aber dann bitte als Nachricht oder auch per Email.
Vielen Dank nochmals fuer die bisherige ( einfache aber geniale) Hilfe.
Matze
Alles funktioniert nun soweit einwandfrei - wenn da nicht dieses immer wieder auftretende *Aber.........* waere.
Durch die Verwendung des with-Statements wird die Verbindung nach jedem Aufruf wieder getrennt bzw. geschlossen und muss beim naechsten Auslesen der Daten neu geoeffnet werden.
Mein Programm hat jedoch die Hauptaufgabe, ZWEI COM-Ports staendig geoeffnet zu haben.
Vom einen wird gelesen, in den anderen wird geschrieben.
Jedes Mal, wenn ich die Ports neu oeffne, dauert das eine gewisse Zeit ( einer davon ist Bluetooth) und es kommt hin und wieder vor, dass da noch irgendwelche Zeichen im Buffer waren und die Verbindung nicht wieder hergestellt werden konnte.
Meinetwegen duerfen die Ports jedoch staendig an meinen Code gebunden sein, sie werden anderweitig nicht benoetigt.
Gibt es da eine clevere Vorgehensweise?
Gerne sende ich auch meinen bisherigen Code - aber dann bitte als Nachricht oder auch per Email.
Vielen Dank nochmals fuer die bisherige ( einfache aber geniale) Hilfe.
Matze
- __blackjack__
- User
- Beiträge: 13112
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@Zellsius: ``with`` sorgt dafür, dass ”augeräumt” wird, wenn der Programmfluss den ``with``-Block verlässt. Du musst den Code halt so schreiben, dass der Block erst am Programmende verlassen wird, beziehungsweise zu einem Zeitpunkt wo die Verbindung nicht mehr benötigt wird.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Hallo _blackjack_ , hallo sparrow
Gegen die Veroeffentlichung des Codes steht: meine Blamage
Ihr zwei habt mich herausgefordert, das habt ihr nun davon.
Anbei der ( vollkommen laienhafte ) Code.
Edit:
Der Code wurde nicht uebermittelt.
Ich muss schauen, woran das lag..................
Gegen die Veroeffentlichung des Codes steht: meine Blamage
Ihr zwei habt mich herausgefordert, das habt ihr nun davon.
Anbei der ( vollkommen laienhafte ) Code.
Edit:
Der Code wurde nicht uebermittelt.
Ich muss schauen, woran das lag..................
import serial
import time
impulse =0
Gesamtstrecke= 2680
Weg_bis_Bruecke = 1320
Bremstraegheit = 4 # das muss noch mit der Geschwindigkeitsstufe verknuepft werden
lok = 16
speed = 3
licht = 16
funktion = 0
with serial.Serial('COM1',2400,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_TWO,timeout=10) as interface:
interface.write(bytes([speed+licht+funktion, lok]))
with serial.Serial('COM6',9600,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_ONE,timeout=10) as wagen:
erhaltenes_Zeichen = wagen.read()
while impulse < Weg_bis_Bruecke:
erhaltener_String = str(wagen.readline())
gekuerzter_String = erhaltener_String[3 : -6]
impulse = int(gekuerzter_String)
print(impulse)
speed = 0
with serial.Serial('COM1',2400,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_TWO,timeout=10) as interface:
interface.write(bytes([speed+licht+funktion, lok]))
print ("Brücke erreicht!")
print ("Warte 10 Sekunden......")
time.sleep(2) # die ersten 2 von 10 Sekunden........
speed = 3
with serial.Serial('COM1',2400,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_TWO,timeout=10) as interface:
interface.write(bytes([speed+licht+funktion, lok]))
with serial.Serial('COM6',9600,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_ONE,timeout=10) as wagen:
erhaltenes_Zeichen = wagen.read()
while impulse < Gesamtstrecke:
erhaltener_String = str(wagen.readline())
gekuerzter_String = erhaltener_String[3 : -6]
impulse = int(gekuerzter_String)
print(impulse)
print ("Jetzt fahre ich zum Startpunkt")
speed = 0
with serial.Serial('COM1',2400,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_TWO,timeout=10) as interface:
interface.write(bytes([speed+licht+funktion, lok]))
print ("Komplette Runde gedreht!")
print ("Programm erfolgreich durchlaufen.")
import time
impulse =0
Gesamtstrecke= 2680
Weg_bis_Bruecke = 1320
Bremstraegheit = 4 # das muss noch mit der Geschwindigkeitsstufe verknuepft werden
lok = 16
speed = 3
licht = 16
funktion = 0
with serial.Serial('COM1',2400,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_TWO,timeout=10) as interface:
interface.write(bytes([speed+licht+funktion, lok]))
with serial.Serial('COM6',9600,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_ONE,timeout=10) as wagen:
erhaltenes_Zeichen = wagen.read()
while impulse < Weg_bis_Bruecke:
erhaltener_String = str(wagen.readline())
gekuerzter_String = erhaltener_String[3 : -6]
impulse = int(gekuerzter_String)
print(impulse)
speed = 0
with serial.Serial('COM1',2400,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_TWO,timeout=10) as interface:
interface.write(bytes([speed+licht+funktion, lok]))
print ("Brücke erreicht!")
print ("Warte 10 Sekunden......")
time.sleep(2) # die ersten 2 von 10 Sekunden........
speed = 3
with serial.Serial('COM1',2400,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_TWO,timeout=10) as interface:
interface.write(bytes([speed+licht+funktion, lok]))
with serial.Serial('COM6',9600,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_ONE,timeout=10) as wagen:
erhaltenes_Zeichen = wagen.read()
while impulse < Gesamtstrecke:
erhaltener_String = str(wagen.readline())
gekuerzter_String = erhaltener_String[3 : -6]
impulse = int(gekuerzter_String)
print(impulse)
print ("Jetzt fahre ich zum Startpunkt")
speed = 0
with serial.Serial('COM1',2400,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_TWO,timeout=10) as interface:
interface.write(bytes([speed+licht+funktion, lok]))
print ("Komplette Runde gedreht!")
print ("Programm erfolgreich durchlaufen.")
Ich bin mal so frei und poste deinen Code in Code-Tags, damit die Einrückung erhalten bleibt.
Code-Tags werden automatisch eingefügt, wenn du den </>-Button im "vollständigen Editor" drückst.
Code-Tags werden automatisch eingefügt, wenn du den </>-Button im "vollständigen Editor" drückst.
Code: Alles auswählen
import serial
import time
impulse =0
Gesamtstrecke= 2680
Weg_bis_Bruecke = 1320
Bremstraegheit = 4 # das muss noch mit der Geschwindigkeitsstufe verknuepft werden
lok = 16
speed = 3
licht = 16
funktion = 0
with serial.Serial('COM1',2400,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_TWO,timeout=10) as interface:
interface.write(bytes([speed+licht+funktion, lok]))
with serial.Serial('COM6',9600,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_ONE,timeout=10) as wagen:
erhaltenes_Zeichen = wagen.read()
while impulse < Weg_bis_Bruecke:
erhaltener_String = str(wagen.readline())
gekuerzter_String = erhaltener_String[3 : -6]
impulse = int(gekuerzter_String)
print(impulse)
speed = 0
with serial.Serial('COM1',2400,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_TWO,timeout=10) as interface:
interface.write(bytes([speed+licht+funktion, lok]))
print ("Brücke erreicht!")
print ("Warte 10 Sekunden......")
time.sleep(2) # die ersten 2 von 10 Sekunden........
speed = 3
with serial.Serial('COM1',2400,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_TWO,timeout=10) as interface:
interface.write(bytes([speed+licht+funktion, lok]))
with serial.Serial('COM6',9600,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_ONE,timeout=10) as wagen:
erhaltenes_Zeichen = wagen.read()
while impulse < Gesamtstrecke:
erhaltener_String = str(wagen.readline())
gekuerzter_String = erhaltener_String[3 : -6]
impulse = int(gekuerzter_String)
print(impulse)
print ("Jetzt fahre ich zum Startpunkt")
speed = 0
with serial.Serial('COM1',2400,bytesize=serial.EIGHTBITS,parity=serial.PARITY_NONE,stopbits=serial.STOPBITS_TWO,timeout=10) as interface:
interface.write(bytes([speed+licht+funktion, lok]))
print ("Komplette Runde gedreht!")
print ("Programm erfolgreich durchlaufen.")
- __blackjack__
- User
- Beiträge: 13112
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@Zellsius: Also so grundsätzlich das was schon gesagt wurde. Wenn der Programmfluss den ``with``-Block verlässt wird dem/den Objekten die hinter dem ``with`` erstellt werden gesagt sie sollen bitte ”aufräumen”. Was `Serial`-Objekte dazu bringt sich zu schliessen. Du darfst also nicht für jeden Schreib- oder Lesevorgang neue `Serial`-Objekte erstellen, sondern für die beiden Schnittstellen jeweils nur eines und das dann durchgehend verwenden.
Sonstige Anmerkungen: Wird bei Gelegenheit mal einen Blick in den Style Guide for Python Code.
Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase).
Da wiederholt sich einiges an Code das man in Funktionen heraus ziehen sollte.
Python hat keine spezielle Syntax für nachprüfende Schleifen, die drückt man deshalb idiomatisch als Endlosschleife aus, die nach einem entsprechenden Test mit ``break`` verlassen wird. Dann muss man keinen unnötigen Dummywert vor der Schleife definieren.
Byte-Objekte wandelt man nicht mit `str()` in Zeichenkettendarstellungen um um danach auf der *Darstellung* eines Byteobjekts mit Slicing zu operieren. Da hier eine Bytefolge in eine Zahl umgewandelt werden soll, braucht auch man gar keine Zeichenkette. Und `int()` kommt auch mit „Whitespace“-Bytewerten vor und nach den Ziffern klar:
Nur falls da etwas steht mit dem `int()` nicht zurecht kommt, müsste man das entfernen. Das geht dann aber auch auf dem `bytes`-Objekt.
Ungetestet:
Ein bisschen komisch ist das überlesen eines Bytes von der `wagen`-Verbindung. Eventuell sollte man das nur nach dem öffnen der Verbindung machen‽
Sonstige Anmerkungen: Wird bei Gelegenheit mal einen Blick in den Style Guide for Python Code.
Namen werden in Python klein_mit_unterstrichen geschrieben. Ausnahmen sind Konstanten (KOMPLETT_GROSS) und Klassen (PascalCase).
Da wiederholt sich einiges an Code das man in Funktionen heraus ziehen sollte.
Python hat keine spezielle Syntax für nachprüfende Schleifen, die drückt man deshalb idiomatisch als Endlosschleife aus, die nach einem entsprechenden Test mit ``break`` verlassen wird. Dann muss man keinen unnötigen Dummywert vor der Schleife definieren.
Byte-Objekte wandelt man nicht mit `str()` in Zeichenkettendarstellungen um um danach auf der *Darstellung* eines Byteobjekts mit Slicing zu operieren. Da hier eine Bytefolge in eine Zahl umgewandelt werden soll, braucht auch man gar keine Zeichenkette. Und `int()` kommt auch mit „Whitespace“-Bytewerten vor und nach den Ziffern klar:
Code: Alles auswählen
In [14]: int(b" 4711 \r\n")
Out[14]: 4711
Ungetestet:
Code: Alles auswählen
#!/usr/bin/env python3
import time
from serial import Serial, STOPBITS_TWO
LOK_NUMMER = 16
LOK_LICHT = 16
LOK_FUNKTION = 0
def set_speed(interface, value):
interface.write(bytes([value + LOK_LICHT + LOK_FUNKTION, LOK_NUMMER]))
def drive_to_impulse_count(interface, wagen, speed, target_impulse_count):
set_speed(interface, speed)
_ = wagen.read()
while True:
impulse_count = int(wagen.readline())
print(impulse_count)
if impulse_count >= target_impulse_count:
break
def main():
with Serial("COM1", 2400, stopbits=STOPBITS_TWO, timeout=10) as interface:
with Serial("COM6", timeout=10) as wagen:
gesamtstrecke = 2680
weg_bis_bruecke = 1320
assert weg_bis_bruecke < gesamtstrecke
drive_to_impulse_count(interface, wagen, 3, weg_bis_bruecke)
set_speed(interface, 0)
print("Brücke erreicht!")
print("Warte 10 Sekunden......")
time.sleep(2) # Die ersten 2 von 10 Sekunden.
drive_to_impulse_count(interface, wagen, 3, gesamtstrecke)
print("Jetzt fahre ich zum Startpunkt")
set_speed(interface, 0)
print("Komplette Runde gedreht!")
print("Programm erfolgreich durchlaufen.")
if __name__ == "__main__":
main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
sparrow: Vielen Dank fuer den Hinweis, aber ich weiss leider nicht, wo ich diesen Button finde bzw. wo ich ihn suchen muss.
Als IDE verwende ich Thonny.
---------------------------------
blackjack:
Dein Code lief auf Anhieb
Zu der Umwandlung bzw. dem Beschneiden des Strings:
Ja, es werden Zeichen empfangen, welche nicht INT-tauglich sind.
Das an COM6: angeschlossene Geraet sendet ein * zu Beginn des Strings und ein % an dessen Ende.
Ausserdem sendet das Geraet auch fuehrende Nullen bis zu einer siebenstelligen Zahl.
Ein typischer String koennte also sein: *0000456%
Das waeren dann 456 Impulse seit dem letzten Reset.
Ich schreibe dir das, weil ich beim Start des Programms sporadisch immer wieder einmal einen Fehler erhalte mit folgendem Wortlaut:
impulse = int(gekuerzter_String)
ValueError: invalid literal for int() with base 10: ''
Starte ich das Programm einfach erneut, taucht der Fehler ( meistens) nicht mehr auf.
Da ich deinen Code ein klein wenig an die Stringbeschneidung angepasst habe, ist dieser Fehler nun nicht wirklich passend.
Ich suche jetzt nach dem Button, den sparrow mir nannte und dann poste ich den aktuellen Code nochmals in einem separaten Beitrag.
Bitte also kurz abwarten, ich bleibe am Ball.
Als IDE verwende ich Thonny.
---------------------------------
blackjack:
Dein Code lief auf Anhieb
Zu der Umwandlung bzw. dem Beschneiden des Strings:
Ja, es werden Zeichen empfangen, welche nicht INT-tauglich sind.
Das an COM6: angeschlossene Geraet sendet ein * zu Beginn des Strings und ein % an dessen Ende.
Ausserdem sendet das Geraet auch fuehrende Nullen bis zu einer siebenstelligen Zahl.
Ein typischer String koennte also sein: *0000456%
Das waeren dann 456 Impulse seit dem letzten Reset.
Ich schreibe dir das, weil ich beim Start des Programms sporadisch immer wieder einmal einen Fehler erhalte mit folgendem Wortlaut:
impulse = int(gekuerzter_String)
ValueError: invalid literal for int() with base 10: ''
Starte ich das Programm einfach erneut, taucht der Fehler ( meistens) nicht mehr auf.
Da ich deinen Code ein klein wenig an die Stringbeschneidung angepasst habe, ist dieser Fehler nun nicht wirklich passend.
Ich suche jetzt nach dem Button, den sparrow mir nannte und dann poste ich den aktuellen Code nochmals in einem separaten Beitrag.
Bitte also kurz abwarten, ich bleibe am Ball.
Code: Alles auswählen
# BR03 faehrt aufs hintere Abstellgleis
import time
from serial import Serial, STOPBITS_TWO
LOK_NUMMER = 30
LOK_LICHT = 16
LOK_FUNKTION = 0
weg_bis_weiche = 2200
weg_bis_abstellgleis = 2500
weg_bis_endpunkt = 3272
def set_speed(interface, value):
interface.write(bytes([value + LOK_LICHT + LOK_FUNKTION, LOK_NUMMER]))
def drive_to_impulse_count(interface, wagen, speed, target_impulse_count):
set_speed(interface, speed)
_ = wagen.read()
while True:
erhaltener_String = str(wagen.readline())
gekuerzter_String = erhaltener_String[3 : -6]
impulse = int(gekuerzter_String)
print(impulse)
if impulse>= target_impulse_count:
break
def main():
with Serial("COM1", 2400, stopbits=STOPBITS_TWO, timeout=10) as interface:
with Serial("COM6", timeout=10) as wagen:
drive_to_impulse_count(interface, wagen, 5, weg_bis_weiche)
set_speed(interface, 0)
print("Weiche erreicht!")
print("Warte 5 Sekunden......")
time.sleep(6)
print("Weiche wird in zwei Sekunden geschaltet.")
time.sleep(2)
interface.write(bytes([33, 10]))
time.sleep(2)
print("Lok wird auf Abstellgleis gefahren.")
time.sleep(2)
drive_to_impulse_count(interface, wagen, 15, weg_bis_weiche) # Fahrtrichtung wechseln
time.sleep(0.2)
drive_to_impulse_count(interface, wagen, 2, weg_bis_abstellgleis) # langsam rueckwaerts fahren
set_speed(interface, 0)
print("Jetzt fahre ich zum Startpunkt")
print("Warte 5 Sekunden......")
time.sleep(6)
drive_to_impulse_count(interface, wagen, 15, weg_bis_abstellgleis) # Fahrtrichtung wechseln
time.sleep(0.2)
drive_to_impulse_count(interface, wagen, 5, weg_bis_endpunkt)
set_speed(interface, 0)
time.sleep(0.2)
interface.write(bytes([34, 10]))
print("Komplette Runde gedreht!")
print("Die Weiche wurde zurueckgestellt.")
print("Programm erfolgreich durchlaufen.")
if __name__ == "__main__":
main()