AGLink und VB.Net --> Umsteiger von Softing OPC

Beiträge
7
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Guten Abend,

dies ist mein erster Beitrag.
Nach einiger Zeit steige ich nun wieder ins Programmieren ein. Früher konnte ich relativ einfach mit Softing OPC die Kommunikation zu meinen SPS ermöglichen.

Jetzt bin ich aktuell dabei mich in AGLink einzuarbeiten und habe mir ein erstes kleines Beispiel mit Hilfe der Anleitungen geschrieben.

Allerdings erhalte ich immer in dieser Zeile result = opc.agl.Symbolic_ReadMixEx(readwritestructures)
folgende Fehlermeldung:

22.11.2019 17:18:11 Fehler in Sub: Polling in Zeile: 283
Message:
Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
Stacktrace:
bei Accon.AGLink.Converter.ToGcHandle(SymbolicRW[] buffer)
bei Accon.AGLink.AGL4.Symbolic_ReadMixEx(Int32 connNr, SymbolicRW[] symbolicRW, Int32& sError, Int32 timeout)
bei Accon.AGLink.AGLink4Tia.Symbolic_ReadMixEx(SymbolicRW[] symbolicRw, Int32& sError, Int32 timeout)
bei Accon.AGLink.AGLink4Tia.Symbolic_ReadMixEx(SymbolicRW[] symbolicRw)
bei XXXXXX\frm_haupt.vb:Zeile 283.

Es klappt alles bis zu der entsprechenden Zeile. SPS-Nummer wird ausgelesen. TIA-Symbole werden vom PLC gelesen etc.


Der aus meinen Augen relevante Code-Teil sieht wie folgt aus:
Try
opc = New progparas With {
.verbose = True,
.agl = AGL4ConnectionFactory.CreateTiaInstance(0, 0, 1)
}
Dim result As Integer
opc.agl.Connect()
Dim out As String = ""
opc.agl.ReadMLFBNr(out)
MsgBox("SPS-Nummer:" & out)
'Laden der Symbole von der SPS
Dim rootNodeHandle As IntPtr
rootNodeHandle = IntPtr.Zero
'result = AGL4.Symbolic_LoadAGLinkSymbolsFromFile("C:\Best-Ablage\test.agl", paras.roothandle)
result = AGL4.Symbolic_LoadAGLinkSymbolsFromPLC(opc.project, opc.roothandle)
If result = AGL4.AGL40_SUCCESS Then
MsgBox("erfolgreich geladen")
Else
MsgBox("Fehler beim laden : " & result)
MsgBox(AGL4.GetErrorMsg(result, "unbekannter Fehler"))
End If
Dim symbols(9) As String
symbols(0) = "PLC.Blocks.DB_Programmdaten.Dat_Satz_Nr_P2"
symbols(1) = "PLC.Blocks.DB_Programmdaten.Dat_Satz_Nr_P2"
symbols(2) = "PLC.Blocks.DB_Programmdaten.Dat_Satz_Nr_P2"
symbols(3) = "PLC.Blocks.DB_Programmdaten.Dat_Satz_Nr_P3"
symbols(4) = "PLC.Blocks.I_DB_Stueckzahl.Sp_Flanke_Istwert"
symbols(5) = "PLC.Blocks.DB_Programmdaten.Dat_Satz_Nr_P2"
symbols(6) = "PLC.Blocks.DB_Programmdaten.Dat_Satz_Nr_P2"
symbols(7) = "PLC.Blocks.DB_Programmdaten.Dat_Satz_Nr_P2"
symbols(8) = "PLC.Blocks.DB_Programmdaten.Dat_Satz_Nr_P2"
symbols(9) = "PLC.Blocks.DB_Programmdaten.Dat_Satz_Nr_P2"

Dim readwritestructures(symbols.Length) As AGL4.SymbolicRW
Dim errorposition As Integer = 0
For i = 0 To symbols.Length - 1
result = AGL4.Symbolic_CreateAccessByPath(opc.roothandle, symbols(i), readwritestructures(i).AccessHandle, errorposition)
If result <> AGL4.AGL40_SUCCESS Then
Dim errormsg As String = ""
AGL4.GetErrorMsg(result, errormsg)
MsgBox("Symbol " & i & " error:" & errormsg & " position " & errorposition)
End If
Next
Dim buffersize As Integer = 0
For i = 0 To symbols.Length - 1
result = AGL4.Symbolic_GetAccessBufferSize(readwritestructures(i).AccessHandle, buffersize)
If result <> AGL4.AGL40_SUCCESS Then
Dim errormsg As String = ""
AGL4.GetErrorMsg(result, errormsg)
MsgBox("buffersizeerror:" & errormsg)
End If
Dim buffer(buffersize - 1) As Byte
MsgBox("i: " & i & " Buffersize:" & buffersize)
readwritestructures(i).Buffer = buffer
readwritestructures(i).BufferLen = buffersize
Next
result = opc.agl.Symbolic_ReadMixEx(readwritestructures)
If result <> AGL4.AGL40_SUCCESS Then
Dim errormsg As String = ""
AGL4.GetErrorMsg(result, errormsg)
MsgBox("readmixex:" & errormsg)
End If
Dim valuetype As AGL4.ValueType
valuetype = AGL4.ValueType.UNDEFINED
For i = 4 To 4 ' symbols.Length - 1 'Achtung, ich will bewusst nur Symbol 4 im ersten Schritt lesen
result = AGL4.Symbolic_GetAccessElementValueType(readwritestructures(i).AccessHandle, valuetype)
If result <> AGL4.AGL40_SUCCESS Then
Dim errormsg As String = ""
AGL4.GetErrorMsg(result, errormsg)
MsgBox("Symbol " & i & " errorelement valuetype:" & errormsg)
End If

Dim systemtype As AGL4.SystemType
systemtype = AGL4.SystemType.UNDEFINED
'For i = 4 To 4 'symbols.Length - 1
result = AGL4.Symbolic_GetAccessElementSystemType(readwritestructures(i).AccessHandle, systemtype)
If result <> AGL4.AGL40_SUCCESS Then
Dim errormsg As String = ""
AGL4.GetErrorMsg(result, errormsg)
MsgBox("Symbol " & i & " errorelement systemtype:" & errormsg)
End If

Dim accessbufferelementcount As Integer = 0
result = AGL4.Symbolic_GetAccessBufferElementCount(readwritestructures(0).AccessHandle, accessbufferelementcount)
MsgBox("buffersize:" & buffersize)
MsgBox("systemtype:" & systemtype)
MsgBox("valuetype:" & valuetype)
For j = 0 To accessbufferelementcount
Select Case valuetype
Case AGL4.ValueType.UINT8
Dim value As Byte
value = 0
result = AGL4.Symbolic_GetAccessBufferUInt8(readwritestructures(i).AccessHandle, readwritestructures(i).Buffer, readwritestructures(i).BufferLen, j, value)
MsgBox(j & ": " & value)
End Select
Next
Next



Catch ex As Exception
fehler(ex, "Polling")
End Try


Wäre super, wenn ein Erfahrener mir helfen könnte :)

Vielen Dank und viele Grüße,

Sönke
 
Hallo Sönke,

mir fällt hier nur folgendes auf:

Code:
                Dim buffer(buffersize - 1) As Byte
                MsgBox("i: " & i & " Buffersize:" & buffersize)
                readwritestructures(i).Buffer = buffer
                readwritestructures(i).BufferLen = buffersize

Hier wird immer wieder dieselbe Variable buffer (re)allokiert. Teste bitte einmal:

Code:
                ReDim readwritestructures(i).Buffer(buffersize-1)
                readwritestructures(i).BufferLen = buffersize

Dann wird direkt der zur Struktur gehörende Puffer allokiert.
Bei weiteren Fragen einfach melden.

Und verwende doch bitte für Programmausschnitte die Code-Option, ist einfach übersichtlicher.

Viele Grüße
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Guten Abend Rainer,

erstmal Danke für die erste Hilfe.

Der Fehler bleibt erstmal bestehen. Die Hinweise von oben sind eingebaut worden.

Ich konnte den Sachverhalt jetzt schon insoweit eingrenzen, dass es anscheinend mit der RW-STructure zu tun hat (ich habe den Zugriff auf die MLFB-Nummer wiederholt geprüft):

opc.agl.ReadMLFBNr(out)
MsgBox("3. SPS-Nummer:" & out) NUMMER WIRD KORREKT AUSGEGEBEN

Dim buffersize As Integer = 0
For i = 0 To symbols.Length - 1
result = AGL4.Symbolic_GetAccessBufferSize(readwritestructures(i).AccessHandle, buffersize)
If result <> AGL4.AGL40_SUCCESS Then
Dim errormsg As String = ""
AGL4.GetErrorMsg(result, errormsg)
MsgBox("buffersizeerror:" & errormsg)​
End If
MsgBox("i: " & i & " Buffersize:" & buffersize)
opc.agl.ReadMLFBNr(out)
MsgBox("4. SPS-Nummer:" & out)
'Dim buffer(buffersize - 1) As Byte
ReDim readwritestructures(i).Buffer(buffersize - 1)
readwritestructures(i).BufferLen = buffersize
Next
opc.agl.ReadMLFBNr(out)
MsgBox("5. SPS-Nummer:" & out)
NUMMER WIRD KORREKT AUSGEGEBEN

result = opc.agl.Symbolic_ReadMixEx(readwritestructures)
Hier kommt der Fehler


Ich hatte auch zwischenzeitlich noch versucht gehabt, wie in einem Beispiel von C#, die RW-STructure anders zu definieren. Auch ohne Erfolg.

Dim readwritestructures(symbols.Length) As AGL4.SymbolicRW
'For i = 0 To symbols.Length - 1
'readwritestructures(i) = New AGL4.SymbolicRW
'Next

So wie ich es sehe, muss irgendetwas noch nicht passen bei der Bestimmung des Buffersizes.

Viele Grüße,

Sönke
 
Zuletzt bearbeitet:
So, Problem gefunden und gelöst !!!

Es lag an was banalem, wie fast vermutet.

Ich hatte in folgender Zeile das RW-Array um ein Feld zu groß gemacht und damit nicht gefüllt später. Anfängerfehler :eek:
Dim readwritestructures(symbols.Length-1) As AGL4.SymbolicRW

Beim Suchen und Einarbeiten sind mir allerdings zwei kleine Fragen aufgekommen:
1) Ich habe in den AGLink Extensions die Funktionen "CyclicReader" und "NCKCyclicReader" gefunden. Gibt es Anwendungsbeispiele?
2) Die grundsätzliche Vorgehensweise verstehe ich aus dem API-Guide sehr gut. Wofür steht aber "NCK" in dem Fall? Wann wird am besten welche angewendet?

Vielen Dank,

Sönke
 
Die NCK-Funktionen sind für den Zugriff auf die Sinumerik. Sie sind nicht für den Zufriff auf eine "normale" SPS zu verwenden.
Bei den Beispielen muss ich schauen, bin allerdings heute und morgen in Nürnberg auf der Messe.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Guten Morgen Herr Hönle,

ich habe am Wochenende (Freizeitprogrammierer :) ) mal weiter gemacht.
Ich habe einen Cyclicreader und die Readwritestruktur global erstellt.
Code:
[LEFT][COLOR=#222222][FONT=Verdana]Public cyclicreader As ICyclicReader[/FONT][/COLOR]
[COLOR=#222222][FONT=Verdana]Public readwritestructures_rw40() As AGL4.DATA_RW40[/FONT][/COLOR][/LEFT]


Anschließend die Initialisierung des Readers wie folgt erfolgreich durchgeführt. Im ersten Schritt hier nur mit einem Objektknoten M.01
Code:
[LEFT][COLOR=#222222][FONT=Verdana]Public Sub start_cyclicreader(ByVal intervall As Integer, ByVal informonlyondatachange As Boolean)
   'Lege erstmal statisch die RWs an
   Try
      opc = New progparas With {
         .verbose = True,
         .agl = AGL4ConnectionFactory.CreateTiaInstance(0, 0, 1)
      }
   Dim result As Integer
   opc.agl.Connect()[/FONT][/COLOR]
[COLOR=#222222][FONT=Verdana]   'Laden der Symbole von der SPS
   Dim rootNodeHandle As IntPtr
   rootNodeHandle = IntPtr.Zero
   result = AGL4.Symbolic_LoadAGLinkSymbolsFromPLC(opc.agl.ConnNr, opc.roothandle)
   If result = AGL4.AGL40_SUCCESS Then
      MsgBox("erfolgreich geladen")
   Else 
      MsgBox("Fehler beim laden : " & result)
      Dim errortext As String = ""
      AGL4.GetErrorMsg(result, errortext) 
      MsgBox("Fehler: " & errortext)
   End If
   Dim symbols(0) As String
   symbols(0) = "M0.1"
   ReDim readwritestructures_rw40(symbols.Length - 1)[/FONT][/COLOR]
[COLOR=#222222][FONT=Verdana]   Dim errorposition As Integer = 0[/FONT][/COLOR]
[COLOR=#222222][FONT=Verdana]   For i = 0 To symbols.Length - 1
      result = AGL4.Text2DataRW(symbols(i), readwritestructures_rw40(i))
      If result = AGL4.AGL40_SUCCESS Then
      MsgBox("i: erfolgreich geladen")
   Else
      MsgBox("Fehler beim laden i: " & result)
      Dim errortext As String = ""
      AGL4.GetErrorMsg(result, errortext)
      MsgBox("Fehler: " & errortext)
      End If
   Next[/FONT][/COLOR][/LEFT]

Das funktioniert soweit auch fehlerfrei und läuft durch.
Allerdings komme ich jetzt nicht recht weiter.
Mit "Dim handle As Integer = 0" und "result = AGL4.InitCyclicRead(opc.agl.ConnNr, 1000, True, readwritestructures_rw40, handle, 1000)" gibt die Fehlermeldung "Funktion wird nicht unterstützt" zurück.

Das einzige Beispiel welches ich in den Samples finden konnte, befindet sich in der Datei "NCK-Samples 2010". Hier wird ein Cyclicreader allerdings komplett anders erstellt.
Die dort genannte Funktion " m_cyclicReader = base.Connection.Aglink.CreateCyclicNCKReader();" finde ich weder in den Referenzhandbüchern, noch im API-Guide.

Über eine kleine Hilfe wäre ich dankbar.
Ich möchte gerne ähnlich wie im Beispiel über ein "Ondatareceived-Ereignis" zyklisch die PLC-Änderungen verarbeiten.


Viele Grüße,
Sönke Schlüter
 
Zuletzt bearbeitet:
Was für eine SPS ist den angeschlossen (MLFBNr)? Funktioniert das Lesen und ggf. Schreiben ohne CyclicReader?
Bitte zukünftig Codeausschnitte als Code (das #-Zeichen in der Toolbar) kennzeichnen. Dies erhöht die Lesbarkeit.
Und wie gesagt, die NCK-Funktionen beim Zugriff auf eine SPS total vergessen. Diese sind nur für eine Sinumerik-Steuerung!
 
Wennes sich um eine S7-1200 oder S7-1500 handelt, dann unterstützt die das CyclicRead nicht. Hier hilft nur pollen und auf Wertänderung prüfen.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Guten Abend,

dann kommen wir der Lösung näher. ;)
Also, Lesen und Schreiben funktioniert über die entsprechenden Funktionen. Leider handelt es sich um eine S7-1500. :confused:
Die Information, dass der Cyclicreader nicht funktioniert, habe ich nirgendwo gefunden.

Gibt es ein Code-Schnipsel zum Pollen? Hab dort in den Beispielen auch nichts finden können. Sonst mache ich mich an die Arbeit.

Viele Grüße,

Sönke

P.S.: #-Zeichen jetzt gefunden, ändere alten Beitrag für die Nachwelt noch ab. Danke!
 
Guten Abend,

ich habe eben nochmal alle 29 durchgeschaut.
Es wird nur bei zweien zyklisch zugegriffen. Das aber mit Cyclicreader und NCK.
Wenn die Frage rhetorisch war, dann bitte für mich den Wink mit dem Zaunpfahl;)

Ansonsten habe ich jetzt mal 80% von nem Polling fertig. Werde morgen Abend weitermachen :)
 
Zuletzt bearbeitet:
Ja, klar.
Ich habe zum Pollen ohne NCK / Cyclicreader in den Samples Nichts gefunden.
Aber wie gesagt... kein Spezialist. Lasse mich gerne mit dem Zaunpfahl hinweisen im Zweifel. Habe alle Beispiel durchgeschaut. Die zyklischen Beispiele verwenden alle die cyclicreader.cs und sind damit nicht anwendbar.
 
Nach erfolgreichem Lesen einen Timer starten und, falls in der Zwischenzeit nicht abgebrochen oder das Programm beendet werden soll, den Leseauftrag erneut starten.
Wenn nicht erfolgreich gelsen wurde, dann die Fehlerbehandlung durchführen. Hierbei sowohl den Rückgabewert der Lesefunktion als auch die Rückgabewerte der einzelnen Variablen beachten. Es könnte ja sein, dass eine einzelne Variable gar nicht existoert und deshalb nicht gelesen werden kann.
 
Zurück
Oben