Verbindung zur einer Siemens SPS

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
RoterMilan
User
Beiträge: 5
Registriert: Mittwoch 5. Oktober 2011, 16:28

Hallo Forum,

ich möchte mittels eines einfachen Scriptes unter Zuhilfenahme der
libnodave eine Verbindung zu einer Siemens SPS herstellen.

Da ich programmiertechnisch noch in den Kinderschuhen stecke,
hoffe ich, das mir jemand weiterhelfen kann.

Hier ist mein Script.

Code: Alles auswählen

#!/usr/bin/python

import ctypes
import os

# .............................................................
# Dateipfad der Libnodave Datei im aktuellem Verzeichnis
Dateipfad = os.getcwd()
#DLL_LOC = Dateipfad + '/' + ('libnodave.dll')      # Windows     
DLL_LOC = Dateipfad + '/' + ('libnodave.so')        # Linux
dave = ctypes.cdll.LoadLibrary(DLL_LOC)

#..............................................................
# Debug on
dbg = dave.daveSetDebug('daveDebugAll')
#print dbg

# .............................................................

daveSysInfo = 0X03 

ip = "192.168.1.20"     # IP Adresse LOGO Modul
port = 102
ph = 0                  # Porthandle
di = 0                  # Dave Interface Handle
dc = 0                  # Dave Connection Handle

# ..............................................................
# Open connection
ph = dave.openSocket(port, ip)
if ph > 0:
    print "Port Handle O.K."
else:
    print "Port Handle N.O.K."    

di = dave.daveNewInterface(ph, ph, 'IF1', 0,'daveProtoISOTCP243', 'daveSpeed187k')
print "di :", di

res = dave.daveInitAdapter(di)
if res == 0:
    print "Init Adapter O.K."
else:
    print "Init Adapter N.O.K."    
    
dc = dave.daveNewConnection(di, 0, 1, 0 )       # daveNewConnection(di, MPI, rack, slot)
print "dc: ", dc

res = dave.daveConnectPLC(dc)
dave.daveSetTimeout(di, 5000000)
print "res: ", res
buf = ctypes.create_string_buffer(100)
print "buf :", buf


if res == 0:     
     #daveReadBytes(daveConnection, int area, int DB, int start, int len, void * buffer);
    res2 = dave.daveReadBytes(dc, daveSysInfo, 'daveDB', 1 , 2, 0)  
    print "ReadBytes " + str(res2)    
    

dave.daveDisconnectPLC(dc);
dave.closePort(ph)
Die Ausgabe in der Konsole dazu

/usr/bin/python -u "/home/achim/TestLOGO/LOGOTCP.py"
openSocket: enter OpenSocketopenSocket: OpenSocket: socket is 3
openSocket: Connected to host: 192.168.1.20
openSocket: setsockopt Success 0
Port Handle O.K.
di : 141470904
Init Adapter O.K.
dc: 141582448
res: 0
buf : <ctypes.c_char_Array_100 object at 0xb7772c44>
PDU header:
0:0x32,0x01,0x00,0x00,0x00,0x00,0x00,0x0E,0x00,0x00,
plen: 14 dlen: 0
Parameter:
0:0x04,0x01,0x12,0x0A,0x10,0x02,0x00,0x02,0x05,0x34,0x03,0x00,0x00,0x08,
_daveExchange PDU number: 65535
Unknown protocol on interface IF1

D.H. für mich:
Die Verbindung zur SPS steht, das Problem liegt im Befehl ReadBytes.

Ich habe schon viel Probiert und auch aus den mitgelieferten Beispielscripten versucht
den Befehl richtig zu Programmieren, klappt aber nicht.

Auch hier im Forum ist die Libnodave schon angesprochen, werde ich aber auch nicht schlauer draus.


Gruß

RoterMilan
Zuletzt geändert von Anonymous am Mittwoch 5. Oktober 2011, 19:58, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
BlackJack

@RoterMilan: Ich würde sagen Du solltest mal die C-Funktionssignatur mit den Argumenten vergleichen die Du da übergibst. Da passt einer ganz offensichtlich vom Typ her nicht.
RoterMilan
User
Beiträge: 5
Registriert: Mittwoch 5. Oktober 2011, 16:28

Hallo,

da habe ich leider (noch) keine Ahnung davon.
Habe schon alles Mögliche probiert

res2 = dave.daveReadBytes(dc, daveSysInfo, 'daveDB', 1 , 2, 'NULL')
res2 = dave.daveReadBytes(dc, daveSysInfo, 'daveDB', 1 , 2, buf)
res2 = dave.daveReadBytes(dc, daveSysInfo, 'daveDB', 1 , 2, 0)

etc.

ich denke es liegt an den Rückgabewerten, sprich den Datensätzen aus der SPS.
Hier brauche ich einwenig Hilfestellung.
O.G. Versuche habe ich den Beispieldateien in VB, Pascal, Perl etc. entnommen,
funktionieren leider nicht bei mir.

Gruß

RotoerMilan
BlackJack

@RoterMilan: Ohne Ahnung wild herumprobieren wird Dich hier nicht weit bringen. Wenn man `ctypes` verwendet, muss man sowohl von Python als auch von C die Grundlagen verstehen, um nachvollziehen zu können wie `ctypes` die jeweiligen Datentypen aufeinander abbildet und was bei Aufrufen von C-Funktionen hinter den Kulissen passiert. Und man muss C-Deklarationen von Datentypen und Funktionen lesen und verstehen können.

Der Datentyp `int` ist in beiden Sprachen eine ganze Zahl — 'daveDB' ist ganz offensichtlich keine Zahl, sondern eine Zeichenkette. Was hier passiert ist, dass die Zeichenkette in C als Adresse des ersten Buchstabens übergeben wird, also eine Zahl. Denn in C ist letztendlich am Ende alles eine Zahl, weil dass das einzige ist womit der Prozessor etwas anfangen kann. Nur ist so ein mehr oder weniger zufälliger Wert innerhalb des Adressraumes eines Prozesses sicher nicht das, was die Funktion haben will wenn das Argument in C als `int` deklariert ist.

Der zweite offensichtliche Fehler beim Aufruf der Funktion ist das letzte Argument. Dort wird die Adresse eine Puffers erwartet wo die Bytes hingeschrieben werden sollen. Die Adresse 0 ist sicher nicht das richtige Ziel — dort müsste `buf` stehen. Wenn man es ganz genau nimmt, eigentlich ``pointer(buf)`` beziehungsweise ``byref(buf)`` (beide Funktionen sind aus dem `ctypes`-Modul). `ctypes` hält es da aber wie C und erlaubt bei einem erwarteten Zeigertypen auch einen Array-Typ und übergibt nicht das Array selbst sondern einen Zeiger darauf, also seine Adresse.

„Trial & error-Programmierung“ ist bei `ctypes` eine eher schlechte Idee, weil man dabei die nette Umgebung von Python verlässt, wo es sehr schwer ist ein Programm zum abstürzen zu bringen. Man bekommt dort eigentlich immer eine Ausnahme, die einen schnell zum Fehler führt, sowohl was die Art betrifft, als auch über den Traceback die genaue Stelle im Quelltext und den Weg im Programmablauf dort hin anhand der Funktions- und Methodenaufrufe. Bei Fehlern die man mit `ctypes` macht, kann einem wie bei C, allerdings ganz einfach das Programm ohne weitere Fehlermeldung hart abschmieren.
RoterMilan
User
Beiträge: 5
Registriert: Mittwoch 5. Oktober 2011, 16:28

Hallo BlackJack,

Danke für deine Erklärungen.
Ich habe noch einiges "Versucht", d.h Integer Werte zu Übergeben etc.
Funktioniert leider nichts. Da ich mittlerweile seit gut 3 Wochen mit diesem Problem kämpfe,
werde ich es wohl aufgeben.
Mir fehlt halt doch noch grundlegendes Wissen über Python und evtl. auch C.

vielen Dank nochmal.


MfG

RoterMilan
ms4py
User
Beiträge: 1178
Registriert: Montag 19. Januar 2009, 09:37

Musst du zu Linux kompatibel sein? Wenn nicht, verwende doch die Siemens OPC DAAutomation Schnittstelle (sopcdaauto.dll) und spreche diese über win32com aus dem pywin32 Paket an. Diese Kombination funktioniert bei mir ganz hervorragend.
„Lieber von den Richtigen kritisiert als von den Falschen gelobt werden.“
Gerhard Kocher

http://ms4py.org/
Antworten