Jump to content

Empfohlene Beiträge

Geschrieben (bearbeitet)

Hallo Eisenbahner,

nachdem ich so manch tolle Anleitung hier erhalten habe, möchte ich mich zum Dank revanchieren.

Durch meine Beschäftigung mit dem Raspbery und elektronischen (Eisenbahn-)Basteleien lernte ich die Programmiersprache Python kennen und bin begeistert.

Leider habe ich weder im InterNet noch hier im Forum irgendwelche direkten Tips für die Verbindung Python/3D-Studio gefunden. So dauerte das Einarbeiten entsprechend lang.

Teil 1  Senden von Kommandos an das 3D-Studio am Beispiel Fahren einer Lok
(kleinstmögliches Programm)

1. Aus dem InterNet wird Python heruntergeladen und installiert. Die Voreinstellungen  können übernommen werden.

2. Zuerst muss das 3D-Studio mit einem Gleisplan und einer Lok gestartet werden. Die Lok erhält den Namen lok (klein geschrieben, willkürlich von mir gewählt).

3. Als Kommando-Port für Befehle an das 3D-Studio wird der voreingestellte Port 31385 beibehalten. Der Ereignis-Port kann ebenfalls beibehalten werden - er wird hier jedoch nicht benötigt.

4. Zur Erinnerung: Für jeden an das 3D-Studio gesendete Befehl gibt es je nach Befehl stets mindestens eine 1 (Kommunikation gelungen) oder eine 0 (Kommunikation misslungen) zurück.

5. Programm (Nummerierung am Zeilenanfang weglassen):

  1. import socket
  2. mySocket = socket.socket()
  3. host = "127.0.0.1"
  4. port = 31285
  5. mySocket.connect((host,port))
  6. mySocket.send(bytes("371;lok;1;8\n","utf-8"))
  7. datenbytes = mySocket.recv(24)
  8. print("Antwort als Bytes: ", datenbytes)

Erklärung

  1. Das Paket socket (für die Datenverbindung) wird geladen.Es ist in der Sprache Python automatisch vorhanden, aber nicht automatisch in den eigenen Programmen eingebunden.
  2. Eine Instanz der Klasse  socket wird erstellt. Die Benennung ist frei wählbar. Ich lass die Namen meiner Instanzen meist mit my beginnen ; so hier: mySocket.
  3. Adresse des eigenen Rechners (die heißen in der Regel immer so oder localhost).
  4. Der vom 3D-Studio voreingestellte Port.
  5. Verbindungsaufbau meines Programms mit dem 3D-Studio
  6. Der Befehl 371;lok;1;8 (die lok genannte Lokomotive soll vorwärts fahren mit Tempo 80. (kein Tippfehler! die hier eingegebene Zahl multipliziert das 3D-Studio automatisch mit 10).
    Da das 3D-Studio  den Befehl in Byte-Form benötigt, muss der als String geschriebene Befehl umgewandelt werden. Das geschieht mit der Methode bytes(). Außerdem muss auch der notwendige Zeilenumbruch mit \n explizit dargestellt werden. Die bytes()-Methode verlangt überdies noch das Bestimmen einer Kodierart (hier: utf-8).
    Die Lok muss sich jetzt in Bewegung setzen.
  7. Die Antwort des 3D-Studios wird in die Variable datenbytes geschrieben. Die Zahl 24 gibt die geschätzte mögliche Größe der empfangenen Mitteilung an. Dort könnte auch eine größere oder kleinere Zahl stehen (probieren).
  8. Endlich wird die Antwort gedruckt (kann entfallen).
  9. Man kann die Antwort noch in einen String umwandeln und dann drucken: 
    datenstring = str(datenbytes,"utf-8")
    print("Antword als String: ", datenstring) 

Anmerkung: Sollten 2 PC in einem Netzwerk miteinander verbunden sein, so sollte Python auf dem einen PC und das 3D-Studio auf dem anderen laufen. Dann muss lediglich die obige Adresse 127.0.0.1 ausgetauscht werden gegen die des PCs, auf dem das 3D-Studio läuft. Die Adresse erhält man unter anderem, wenn man in der Verwaltungssoftware einer Fritz.Box unter Heimnetzwerk nachschaut, im Internet nach "eigene IP-Adresse" sucht oder in die Systemsteuerung von WINDOWS guckt.

 

Teil 2:  Das Empfangen der Ereignismitteilungen vom 3D-Studio

Lesen der Ereignisse

Hier wieder das kleinstmögliche Programm (ohne Zeilennummern eingeben, Einrückungen beachten))

  1.  import socket
  2.  host = "127.0.0.1"
  3.  port2 = 31286
  4.  mySocket = socket.socket()
  5.  mySocket.connect((host,port2))
  6.  while (True):
  7.     antwort = mySocket.recv(1024)
  8.     print(antwort)

Erklärung:

  1. Importieren des Moduls socket für die Datenverbindung
  2. Adresse des eigenen Rechners. Alternativ: host="localhost"
  3. Vom 3D-Studio voreingestellter Port für die Ereignisübertragung
  4. Instanz der Klasse socket wird erstellt mit Voreinstellungen
  5. Verbindungsaufbau meines Programms mit dem 3D-Studio.
    Im Gegensatz zum Senden wird jetzt der voreingestellte Port für die Ereignisübertragung gewählt!
  6. Beginn einer Endlosschleife
  7. Die Mitteilungen des 3D-Studios in Form von Bytes werden in die Variable antwort geschrieben.
  8. Drucken der Variablen in Byte-Form

Anmerkung: Sollen die beiden Programme zusammengefasst werden, so ist zu beachten, dass wegen der verschiedenen Ports ein zweites socket-Objekt erstellt werden muss.

 

  1. import socket
  2. mySocket = socket.socket()
  3. host = "127.0.0.1"
  4. port = 31285
  5. mySocket.connect((host,port))
  6. mySocket.send(bytes("371;lok;1;8\n","utf-8"))
  7. datenbytes = mySocket.recv(24)
  8. print("Antwort als Bytes: ", datenbytes)
  9.  port2 = 31286
  10.  mySocket2 = socket.socket()
  11.  mySocket2.connect((host,port2))
  12.  while (True):
  13.     antwort = mySocket2.recv(1024)
  14.     print(antwort)

Grüße GPG

Bearbeitet von GPG
Überarbeitung des Artikels
Geschrieben (bearbeitet)

Steuerschnittstelle programmieren mit Python3 und Tkinter

Teil 3: Simples Fahrpult
Beispiel für das Übertragen von Kommandos an das 3D-Studio in einem Fenster

Zeilen ab dem #-Zeichen sind Kommentare und für den Programmablauf nicht relevant.
Einrückungen sind in Python wichtig!

Fahrpulz.JPG.fbeeb1f695a4e1a312fcd472b1fbedfa.JPG

#########################################                                   
####  Programm: Fahrpult.pyw
####  Einfaches Fahrpult
#### 3 Geschwindigkeiten pro Richtung
#### und Halt-Buttom
#########################################

from tkinter import *                                                   # Modul tkinter (zuständig für die Fenstergestaltung) wird importiert
import socket                                                             # Modul socket (zuständig für die Datenübertragung) wird importiert

def fahren(v):                                                             # das Unterprogramm fahren mit einer Werteübergabe beim Aufruf wird definiert
    v_string = str(v)                                                     # der übergebene Wert wird in einen String verwandelt
    adress_string = "371;lok;1;" + v_string + "\n"        # das Kommando für das Fahren der Lok wird zu einem String zusammengebaut
    adress_bytes = (bytes(adress_string ,"utf-8"))      # Umwandlung des Strings in Bytes
    c.send(adress_bytes)                                            # das Byte wird gesendet
    print(v)                                                                   # die folgenden print-Anweisungen dienen nur der Kontrolle im Python-Shell
    print(v_string)
    print(adress_string)
    print(adress_bytes)
    
host = "127.0.0.1"                                                      # Adresse des PCs, auf dem das 3D-Studio läuft
port = 31285                                                              # vom 3D-Studio voreingestellter Port für den Datenempfang
c=socket.socket()                                                      # mein Objekt für die Datenübertragung wird erstellt (in den Programmen oben mySocket genannt)
c.connect((host,port))                                                # Verbindung wird hergestellt

myfenster = Tk()                                                        # Das Objekt eines Window-Fensters wird erstellt, d.h. ein reales Fenster wird erstellt
myfenster.title("Fahrpult")                                          # Titel des Fensters 

mybutton_fahren1 = Button (master=myfenster, text=" <<<  ", command=lambda:fahren(-20))   # Die Buttons fürs Fahren werden erstellt, zuerst deren Namen
mybutton_fahren2 = Button (master=myfenster, text="   <<  ", command=lambda:fahren(-10))   # dann werden deren Platzierungen im Fenster  festgelegt
mybutton_fahren3 = Button (master=myfenster, text="   <    ", command=lambda:fahren(  -2))   # mit Text wird die Aufschrift festgelegt
mybutton_halten4 = Button (master=myfenster, text="HALT",  command=lambda:fahren(   0))   # command legt fest, welches Unterprogramm beim
mybutton_fahren5 = Button (master=myfenster, text="   >   ", command=lambda:fahren(    2))    # Anklicken gestartet wird
mybutton_fahren6 = Button (master=myfenster, text="  >>  ", command=lambda:fahren(   10))   # lambda ermöglicht die Mitgabe eines Wertes
mybutton_fahren7 = Button (master=myfenster, text="  >>> ", command=lambda:fahren(  20))   # der Wert steht in Klammen

mybutton_fahren1.pack(side ='left', padx='5',pady='5')     # die Methode pack() ordnet die Platzierung der Buttons im Fenster
mybutton_fahren2.pack(side ='left', padx='5')                   # side= 'left bedeutet: Buttons nebeneinander anordnen
mybutton_fahren3.pack(side ='left', padx='5')                   # padx und pady legt den Abstand der Buttons vom Rand und von einander in  x- und y-Richtung fest
mybutton_halten4.pack(side ='left', padx='5')
mybutton_fahren5.pack(side ='left', padx='5')
mybutton_fahren6.pack(side ='left', padx='5')
mybutton_fahren7.pack(side ='left', padx='5')

myfenster.mainloop()                                                        #  mainloop organisiert das Funktionieren des Fensters
 

Bearbeitet von GPG
Überarbeitung des Artikels
Geschrieben

Hallo GPG,
hochinteressant, dass das mit so wenig Befehlen möglich ist.
Was muß jetzt noch getan werden, dass das in zwei parallelen Threads läuft?

Gruß
  Andy

  • 2 Wochen später...

Erstelle ein Benutzerkonto oder melde dich an, um zu kommentieren

Du musst ein Benutzerkonto besitzen, um einen Kommentar verfassen zu können

Benutzerkonto erstellen

Neues Benutzerkonto für unsere Community erstellen.

Neues Benutzerkonto erstellen

Anmelden

Du hast bereits ein Benutzerkonto? Melde dich hier an.

Jetzt anmelden
×
×
  • Neu erstellen...