Problematik mit OPC-Ua Verbindung in Twincat 3

PhuongTran1983

Level-1
Beiträge
67
Reaktionspunkte
3
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,

ich habe ein Problem mit der OPC-Ua Verbindung und könntet Ihr mir bitte weiterhelfen.

Ich habe einen OPC Ua Server in einer SPS am Laufen. In TC3 habe ich ein kleines Programm "PRG_Read" anhand eines Beispiels von Beckhoff geschrieben, um die Daten von einem OPC Server zu lesen. Der Ablauf des Programms wird in 7 verschiedenen State vom OPC Ua-Connect bis zum Disconnect aufgeteilt (s. Unten).

Der Client konnte den Server zugreifen. Es hat aber nur das Problem, dass die Daten in den Client sehr langsam geholt wurden. Wie kann man die Taktzyklus für den Client definieren. D.h. Beispielweise greift der Client den Server je nach 50ms einmal zu.

Hat jemand dieses Thema schon mal beschäftigt. Könnte mir bitte Lösungsvorschläge geben.

Vielen Dank und viele Grüße,

Phuong Tran
CASE iState OF
0: (* idle *)
bTest := TRUE;
IF bTest THEN

bTest := FALSE;
bError := FALSE;
nErrorID := 0;
SessionConnectInfoEx.tConnectTimeout := T#5S;
SessionConnectInfoEx.tSessionTimeout := T#5S;
SessionConnectInfoEx.sApplicationName := '';
SessionConnectInfoEx.eSecurityMode := eUASecurityMsgMode_None;
SessionConnectInfoEx.eSecurityPolicyUri := eUASecurityPolicy_None;
SessionConnectInfoEx.eTransportProfileUri := eUATransportProfileUri_UATcp;//eUATransportProfileUri_UATcp;
iState := iState + 1;

END_IF
1: (* open UA session *)
fbUA_ConnectEx(
Execute := TRUE,
ServerURL := sOpcUaServerUrl,
SessionConnectInfo := SessionConnectInfoEx,
Timeout := T#5S,
ConnectionHdl => nConnectionHdl
);
IF NOT fbUA_ConnectEx.Busy THEN
fbUA_ConnectEx(Execute := FALSE);
IF NOT fbUA_ConnectEx.Error THEN
(* session open *)
iState := iState + 1;
ELSE
bError := TRUE;
nErrorID := fbUA_ConnectEx.ErrorID;
nConnectionHdl := 0;
iState := 0; (* idle *)
END_IF
END_IF
2: (* GetNS Index *)
fbUA_GetNamespaceIndex(
Execute := TRUE,
ConnectionHdl := nConnectionHdl,
NamespaceUri := sNamespaceUri,
NamespaceIndex => nNamespaceIndex
);
IF NOT fbUA_GetNamespaceIndex.Busy THEN
fbUA_GetNamespaceIndex(Execute := FALSE);
IF NOT fbUA_GetNamespaceIndex.Error THEN
(* session closed *)
iState := iState + 1; (* idle *)
ELSE
bError := TRUE;
nErrorID := fbUA_GetNamespaceIndex.ErrorID;
iState := 6; (* idle *)
END_IF
END_IF
3: (* Get Node Handle *)

NodeIDs[1].eIdentifierType := eUAIdentifierType_String;
NodeIDs[1].nNamespaceIndex := nNamespaceIndex;
NodeIDs[1].sIdentifier := 'MAIN.P';

NodeIDs[2].eIdentifierType := eUAIdentifierType_String;
NodeIDs[2].nNamespaceIndex := nNamespaceIndex;
NodeIDs[2].sIdentifier := 'MAIN.Q';

NodeIDs[3].eIdentifierType := eUAIdentifierType_String;
NodeIDs[3].nNamespaceIndex := nNamespaceIndex;
NodeIDs[3].sIdentifier := 'MAIN.I';

NodeIDs[4].eIdentifierType := eUAIdentifierType_String;
NodeIDs[4].nNamespaceIndex := nNamespaceIndex;
NodeIDs[4].sIdentifier := 'MAIN.U';

NodeIDs[5].eIdentifierType := eUAIdentifierType_String;
NodeIDs[5].nNamespaceIndex := nNamespaceIndex;
NodeIDs[5].sIdentifier := 'MAIN.Lampe';
fbUA_NodeGetHandleList(
Execute := TRUE,
ConnectionHdl := nConnectionHdl,
NodeIDCount := NodeIDCount,
NodeIDs := NodeIDs,
NodeHdls => nNodeHdls
);
IF NOT fbUA_NodeGetHandleList.Busy THEN
fbUA_NodeGetHandleList(Execute := FALSE);
IF NOT fbUA_NodeGetHandleList.Error THEN
(* session closed *)
iState := iState + 1; (* idle *)
ELSE
bError := TRUE;
nErrorID := fbUA_NodeGetHandleList.ErrorID;
iState := 6; (* idle *)
END_IF
END_IF

4: (* UA_Read *)
cbData[1] := SIZEOF(stReadListData.P);
cbData[2] := SIZEOF(stReadListData.Q);
cbData[3] := SIZEOF(stReadListData.I);
cbData[4] := SIZEOF(stReadListData.U);
cbData[5] := SIZEOF(stReadListData.Lampe);
cbDataTotal := SIZEOF(stReadListData);

fbUA_ReadList(
Execute := TRUE,
ConnectionHdl := nConnectionHdl,
NodeHdlCount := NodeHdlCount, // 2
NodeHdls := nNodeHdls,
stNodeAddInfo := stNodeAddInfo,
pVariable := ADR(stReadListData),
cbData := cbData ,
cbDataTotal := cbDataTotal
);
IF NOT fbUA_ReadList.Busy THEN
fbUA_ReadList( Execute := FALSE, cbData_R => cbData_R);
IF NOT fbUA_ReadList.Error THEN
(* session closed *)
iState := iState + 1; (* idle *)
ELSE
bError := TRUE;
nErrorID := fbUA_ReadList.ErrorID;
iState := 6; (* idle *)
END_IF
END_IF

5: (* Release Node Handle *)
fbUA_NodeReleaseHandleList(
Execute := TRUE,
ConnectionHdl := nConnectionHdl,
NodeHdlCount := NodeHdlCount,
NodeHdls := nNodeHdls
);
IF NOT fbUA_NodeReleaseHandleList.Busy THEN
fbUA_NodeReleaseHandleList(Execute := FALSE);
IF NOT fbUA_NodeReleaseHandleList.Error THEN
(* session closed *)
iState := iState + 1; (* idle *)
ELSE
bError := TRUE;
nErrorID := fbUA_NodeReleaseHandleList.ErrorID;
iState := 6; (* idle *)
END_IF
END_IF
6: (* close session *)
fbUA_Disconnect(
Execute := TRUE,
ConnectionHdl := nConnectionHdl
);
IF NOT fbUA_Disconnect.Busy THEN
fbUA_Disconnect(Execute := FALSE);
bBusy := FALSE;
IF NOT fbUA_Disconnect.Error THEN
(* session closed *)
iState := 0; (* idle *)

IF NOT bError THEN
bDone := TRUE;
END_IF
ELSE
bError := TRUE;
nErrorID := fbUA_Disconnect.ErrorID;
iState := 0; (* idle *)
nConnectionHdl := 0;
END_IF
END_IF
END_CASE
 

Anhänge

  • TF6100_OPCUA_ClientSample.zip
    836,3 KB · Aufrufe: 10
Hallo,

Wenn Deine Taktung 10ms ist und Du wirklich das gesamte Programm jedes mal durchläufst, baust Du jedes mal neue TCP Verbindung auf, NS holen, Hdls holen etc. Dann würde ich erwarten, dass Du ca alle 60ms einen Wert bekommst?

D.h. einfach nur die Statemachine umstellen, sodass nach Hdl holen immer wieder das ReadList getriggered wird sollte helfen.
Erst beim Runterfahren ReleaseHdl / Disconnect

Gruss
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

Danke Dir für die Rückmeldung. Ich werde es gleich checken.

laut dem aktuellen Beispielprogramm konnte ich nur den Server mit Taktung ca. 400ms zugreifen. Das ist aber zu langsam für eine OPC-Verbindung.

Viele Grüße,

Phuong Tran
 
Hallo,

ich habe gerade die Statemaschine umgebaut. Das ist korrekt wie Du geschrieben hast. Ich habe aber nicht verstanden, was machen die andere State wie ReleaseHdl / Disconnect. Kannst Du mir bitte nochmals kurz erklären.

Viele Grüße,

Phuong Tran
 
Hallo,

Die FBs sind einzeln im Infosys von Beckhoff beschrieben.

Im Prinzip bilden sie 1:1 die entsprechenden UA-Dienstaufrufe (Part 7 der Spec) ab.
Wobei GetHandle heisst auf UA Ebene RegisterNode ... warum die PLCopen das anders genannt hat, weiss ich auch nicht.
Konkret:
- ReleaseHdl gibt das Handle im Server und der Beckhoff-Cient-Firmware frei, was durch GetHandle angelegt und vom Server geholt wurde.
- Disconnect beendet die OPCUA Verbindung, die sonst aufrecht erhalten wird.

Gruss
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

es hat bei mir funktioniert. Aber leider kann man nur maximal 10 Datenpunkte im Programm anbinden. Falls man mehr als 10 Variablen im OPC Server zugrifft, muss ein weiteres Programm geschrieben werden. Das ist ein bisschen komisch, warum die Anzahl der Datenpunkte so begrenzt ist.

Trotzdem vielen Dank für Deine wirkliche Unterstützung. Es hat mir viel geholfen.

Viele Grüße,

Phuong Tran
 
Hallo,

1) Die 10 Einträge für ein ReadList sind eine Vorgabe der Library - kann man überschreiben.
Allerdings erzeugt das auf beiden Systemen eine höhere Last, wenn die Read befehle dann ausgeführt/ausgewertet werden;
es kann durchaus Sinn machen die Befehle aufzuteilen.
2) ...du kannst in jedem Fall über eine UA Verbindung (also einen ConnectionHdl) mehrere ReadList nutzen. Du musst nicht mehrere Verbindungen aufbauen.

Gruss
Vielelicht wäre es gut, wenn Du zur Verwendung neben dem Infosys auch noch as PLCOpen Dokument nimmst - das ist frei (nach registierung bei der PLCOpen) runterladbar.

Gruss
 
oder du packst deine Variablen in eine Struktur, dann kannst du bis zu 16 kByte Daten schreiben, egal wie viele Variablen es sind.
Quelle


Grüße Sidame00
 
Zurück
Oben