Zeitstempel ADS .NET

dacripple

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

ich beschäftige seit kurzem mit der Beckhoff ADS .NET DLL (via LabVIEW).

Meine Frage:

Ist es möglich zyklisch Daten aus der SPS zu lesen (z.B. Analogwerte)?
Wie kommt man bei einer gelesenen Variable an den Abtastzeitpunkt (Zeitstempel), also an die Zeit in der die SPS den Analogwert eingelesen hat?

Wie wäre hier die richtige Vorgehensweise, bzw. mit welchen Funktionen der ADS .NET DLL lässt sich dies umsetzen?
Habt ihr hierfür evtl. Beispiele? Muss nicht LabVIEW sein, können auch C# Codeschnipsel sein...

Vielen Dank schon mal!
 
Ein Wert ist ein Wert, hat aber kein Wissen über seine Zeit.
Wenn du nun Werte abfragst klassische abfragst wird das nichts, es sei denn du hast in der SPS ein Wertetuppel das auch die Zeit integriert.
Die Alternative die ich dir empfehlen würde - wenigstens interpretiere ich "zyklische Werte" so das du über einen Zeitraum x zyklisch Werte abgreifen willst die Notification.
Letztendlich nutzt z.B. das Scope/Measurement genau das gleiche.
Die SPS speichert viele Werte einer Variable incl. Zeit ab und entsprechen der Konfiguration schickt es dir dann das Packet.

Also -> schau dir in deiner Sprache das Thema Notification an. Im Allgemeinen setzt man die Notification so dass nach 100 Werten das Packet von der PLC verschickt werden (und du eine entsprechende Callback im Labview hast wo du die Daten flott wegspeicherst bevor du sie dann spaetern aufbereitest...).
Ach ja: Der Zeitstempel ist das Filetime-Format.

Guga
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Du kannst per ADS mehrere Variablen gleichzeitig abfragen (SUMUP_READ/WRITE), so kannst du sicherstellen, daß die Steuerung den Analogwert und Zeitstempel zur gleichen Zeit (Zyklus) abfragt.

Um das zyklisch zu machen habe ich vor einer Weile mal mit Python/Qt über die ADS-Dll kommuniziert (nur ein Test, habe das dann nicht in die "produktive" Steuerung übernommen)

Hier ein Auszug:
Code:
class RefreshThread(QThread):
    callback = pyqtSignal(list)
    def __init__(self, vars, callback):
        QThread.__init__(self)
        self.vars = vars
        self.callback.connect(callback)
    def run(self):
        try:
            self.values = plc.getMultipleVariables(self.vars)
        except TcAdsDll.AdsError as e:
            self.values = [(None, e.code)]*len(self.vars)
        self.callback.emit(self.values)

class PlcModel(QAbstractItemModel):
def __init__(self, vars):
        QAbstractItemModel.__init__(self)
        self.vars = vars
[...]
        self.refresh()
        self.refreshTimer = QTimer(self)
        self.refreshTimer.timeout.connect(self.refresh)
        self.refreshTimer.start(100) #ms
[...]
    @pyqtSlot()
    def refresh(self):
        if hasattr(self, "t") and not self.t.isFinished(): return
        self.t = RefreshThread(self.vars, self.refreshed)
        self.t.start()
    @pyqtSlot(list)
    def refreshed(self, values):
        [hier Werte verarbeiten]
Kurze Erläuterung:
in der __init__-Methode wird ein Timer eingestellt (hier alle 100ms), der die refresh-Methode aufruft.
in der refresh-Methode wird ein Thread erstellt, der die Werte per ADS abfragt, und die fertigen Werte an die refreshed-Methode übergibt. Dabei wird überprüft, ob nicht schon ein Thread läuft, der noch auf Antwort wartet.
in der refreshed-Methode werden die Daten weiterverarbeitet (hier in einer Art aufbereitet, daß ein Qt-Modell die Daten für eine GUI aufbereiten kann)

die hier nicht aufgeführte Methode "getMultipleVariables" führt die eigentliche ADS-Kommunikation durch.
Einmalig ein SUMUP_WRITE um für die Variablen ein Handle zu bekommen (wird abgespeichert)
und bei jedem weiteren Aufruf ein SUMUP_READ um die Werte abzufragen
 
Zuletzt bearbeitet:
Hallo zusammen,

vielen Dank für eure Antworten.

Ich bekomme das ganze leider nicht ganz zum laufen.

Ich möchte im Prinzip die gleiche Funktionalität wie das TwinCAT Scope (Also die Daten laufend mitloggen).

Dafür habe ich in der SPS ein INT-Array mit 100 Werten angelegt.
Jetzt habe ich die ADS .NET Funktion "Ereignisgesteuertes Lesen"(https://infosys.beckhoff.com/content/1031/tcsample_net/html/twincat.ads.sample03.htm?id=4958905367400929685
) genutzt.

Die SPS läuft mit 4ms Zykluszeit, und schreibt jeden Zyklus einen Wert eines Zählers in das Array (z.B. Array[0]=15, Array[1]=16, ..Array[99]=114)

Die Funktion nutze ich so:

hConnect[1] = tcClient.AddDeviceNotification("MAIN.Array",dataStream,1,2,
AdsTransMode.Cyclic,400,0,tbInt);

leider bekomme ich die Daten nicht synchron zur SPS ausgelesen.
So sehen meine Werte aus:
Werte.jpg
Da es der Wert eines Zählers ist, sollte das eigentliche eine gerade Linie sein...

Kann mir jemand weiterhelfen?

Vielen Dank!
 
Zuletzt bearbeitet:
Hilf mir mal auf die Sprünge. Was hast du dir bei den Parametern gedacht. Warum holst du dir aus dem Array einen Wert mit 2 Byte und das mit einem Offset von 1????
Ich hätte jetzt einen Offset von 0, 2, 4... erwartet aber nicht 1.



Es ist schon lange her seitdem ich die Funktion benutzt habe und deshalb macht noch nicht klick. Vom Prinzip (kommt auf die gewünschte Updatehäufigkeit nun an) würde ich nur für den Wert einen Notification setzen und das Array mal aussen vor lassen.



Ich gehe davon aus das du diese Methode nutzt.
https://infosys.beckhoff.de/content/1033/tcadsnetref/4017316107.html
Und die Parameter folgen dieser Beschreibung
https://infosys.beckhoff.com/content/1031/tcadsdll2/html/TcAdsDll_StrucAdsNotificationAttrib.htm


Aus meinen Quellen habe ich noch folgenden Kommentar gefunden (vielleicht hilfts):
Bei Cyclic wird bei AddDeviceNotification mit
nCycleTime = 10.000 [Einheit = 100 nsec => 1msec] und
nMaxDelay = 100.000 [Einheit = 100 nsec => 10msec]

alle 10msec 10 Werte erhalten in der ADS Device Nofication Request (ADS-Eben)


Guga
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hilf mir mal auf die Sprünge. Was hast du dir bei den Parametern gedacht. Warum holst du dir aus dem Array einen Wert mit 2 Byte und das mit einem Offset von 1????
Ich hätte jetzt z.B. einen Offset von 0, 2, 4... erwartet aber nicht 1. Genauso den MaxDelay != 0.



Es ist schon lange her seitdem ich die Funktion benutzt habe und deshalb machts nicht klick. Vom Prinzip (kommt auf die gewünschte Updatehäufigkeit nun an) würde ich nur für den Wert einen Notification setzen und das Array mal aussen vor lassen.



Ich gehe davon aus das du diese Methode nutzt.
https://infosys.beckhoff.de/content/1033/tcadsnetref/4017316107.html
Und die Parameter folgen dieser Beschreibung
https://infosys.beckhoff.com/content/1031/tcadsdll2/html/TcAdsDll_StrucAdsNotificationAttrib.htm


Aus meinen Quellen habe ich noch folgenden Kommentar gefunden (vielleicht hilfts):
Bei Cyclic wird bei AddDeviceNotification mit
nCycleTime = 10.000 [Einheit = 100 nsec => 1msec] und
nMaxDelay = 100.000 [Einheit = 100 nsec => 10msec]

alle 10msec 10 Werte erhalten in der ADS Device Nofication Request (ADS-Eben)


Guga
 
Ich glaube dein Problem ist, daß das Senden des Arrays nicht mit dem Schreibzyklus synchronisiert ist. Also z.B. schreibst du gerade Array[30], und dann wird das Array verschickt. dann hat Array[0..30] höhere Werte als Array [31..99]. Du müßtest also entweder das Senden so synchronisieren, daß du genau beim "Überlauf" von 99 nach 0 verschickst, oder den aktuellen Index mitverschicken, daß du das am anderen Ende nochmal umsortieren kannst.

Nachtrag: Man sieht in deinem Bild auch, daß diese "Phasenverschiebung" sich mit der Zeit verändert, auch das solltest du beachten, wenn du aus den verschickten Arrays den Werteverlauf rekonstruieren willst (evtl. fehlen welche, oder du hast welche doppelt)
 
Zuletzt bearbeitet:
Zurück
Oben