Beckhoff Steuerung per ADS mit 20kHz auslesen

somebody246

Level-1
Beiträge
12
Reaktionspunkte
1
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,
ich wollte fragen, ob es möglich ist Variablen der SPS per ADS mit 20 kHz Frequenz auszulesen. Am liebsten wäre es mir, wenn das in Python möglich wäre. In Versuchen habe ich es auch immer wieder geschafft kurze alle Einträge lesen können, danach haben aber wieder die Werte für mehrere Millisekunden gefehlt. Hintergrund ist der, dass ich diese Werte gerne in eine Time Series Datenbank speichern würde, auf welche dann per Weboberfläche zugegriffen werden kann.
Hat jemand eine Idee wie das möglich ist?
Vielen Dank!
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Rein Interesse-halber: wozu braucht man das? Kommst Du mit Deiner ZylkusZeit auf 50 µs herunter?
Ja mit einer CX2062, diese wird zur Regelung eines Laserablenkkopfs verwendet. Die Aufzeichnung soll so schnell erfolgen, damit auch im Webinterface Messungen durchgeführt werden können.
 
Der Anwalt sagt: "Das kommt darauf an, aber ja, das geht".

Prinzipiell relevant sind die Anzahl der ADS-Packete (im Router) relevant. Wenn du jeden Wert per einzelnen Read-Request auslesen willst wird es nicht möglich sein.
Du musst dir also Packete holen mit vielen Werten (ein Array). Bitte aber nicht unendlich groß da es sonst irgendwann auch wieder wo anders Auswirkungen hat. Meine Empfehlung ist < 8 KByte zu bleiben. Damit einhergehend wirst du um eine "Verwaltung" nicht herumkommen. Am einfachsten wäre es wenn deine SPS die Packete verschickt (anstelle das du sie von Python aus liest).

Ansonsten müsste man ein Summenkommande haben (readwrite) da dieses in der PLC konsistent behandelt wird und man somit zeitgenau sagen "habe das Packet gelesen".

Last not least: Du kannst es auch per Notification realisieren - solltest aber entsprechend "große" Päckchen erlauben.



Guga

P.S. Damit man weiss was "abgeht" sollte man sich den ADSMonitor (TF6010 soviel ich mich erinnere) installieren und schauen was man da treibt. Es ist viel möglich aber nicht alles - und jedes System kann man über den Abgrund treiben.
 
Ja mit einer CX2062, diese wird zur Regelung eines Laserablenkkopfs verwendet. Die Aufzeichnung soll so schnell erfolgen, damit auch im Webinterface Messungen durchgeführt werden können.
Die Messungen müssen im Webinterface auch in "real time" verfügbar sein?
Sonst könntest Du in der SPS die Werte von x Messungen ansammeln und in einem Rutsch übertragen. Könnte mir vorstellen, dass die Übertragung von x-mal soviel Daten in x-mal so langen Abständen im Endeffekt die Schnittstelle weniger in Beschlag nimmt?

Edit:
Da war wieder einer schneller! ;)
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Guga,
danke schon einmal für die Tipps! Genau das per Notification habe ich probiert, ich bekomme in meiner Callback- Funktion aber immer nur einen (wahrscheinlich den aktuellsten) Wert. Ich dachte bei der Notification werden nicht abgeholte Werte in eine FIFO geschrieben. Auf diese kann ich aber nicht zugreifen. Der Weg so wäre mir am liebsten, weil es die Notification-Funktion schon einem Python-Paket (pyads) gibt.
 
Nein es muss keine echte "real time" sein, aber eine Aktualisierung ca jede Sekunde wäre schon gut.
Meine Ansteuerung der Klemmen erfolgt über Simulink-Modelle, habt ihr da dann eine Idee wie man bestimmten Werten dann zur Laufzeit eine solches Array zum Sammeln von Werten entwerfen könnte ohne die Simulink-Modelle zu verändern?
 
Ich habe noch im Hinterkopf dass die Protokollzeit von ADS bei 1-2ms pro Request liegt. Wenn sich das in den letzten Jahren nicht geändert hat, hast du da schonmal einen Flaschenhals.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
@somebody264.
Um prinzipiell auszuprobieren ob dein System das entsprechende Datensampling hergibt ist es am einfachsten einmal das Measurement-Projekt zu nutzen und sich den/die Werte aufzuzeichnen.
Dieses arbeitet auch per ADS-Notification.
Auf Router bzw. Wireshark-Ebene kann eine Notification mehrere Datenpunkte enthalten. Jeder Datenpunkt kommt mit seinem eigenen Zeitstempel daher.
Wie es jetzt in der Python-Lib gelöst ist kann ich dir nicht sagen. In C++ (also nah an der Physik) gibt es für jedes Datenpacket eine Callback. In der .Net Variante erhälst du für jeden Zeitstempel einen Callback.
Musst halt mal auf die Größe schauen. Der Zeitstempel kannst du in der Callback auslesen.
Prinzipiell bei Notifications. Die Callback schnell wieder verlassen und die Werte wegkopieren.

@MasterOhh. Die 1-2msec gelten nach wie vor - für einzelne ADS-Befehle (also z.B. ADSRead..). Der Notificaiton gibst du aber mit wie viele Daten / Packet max enthalten sein sollen.

Guga
 
Zuletzt bearbeitet:
Okay, ja das Measurement-Projekt hab ich bereits ausprobiert und da scheint alles zu funktionieren. Ich denke mal mit C++ wird auch die TcAdsDLL verwendet um auf die ADS Daten zuzugreifen, das funktioniert in Python genauso. So wie ich das bei dir verstehe bedeutet das, dass bei einem Callback Aufruf mehrer Datenpunkte abgreifen kann?
Außerdem habe ich jetzt mit dem ADSViewer mir die Pakete angeschaut und festgestellt, dass ich immer wieder den Fehler 1282(ROUTERRR_MAILBOXFULL) habe. Kann ich die Mailbox irgendwie vergrößern? Der Fehler entsteht wahrscheinlich dadurch, dass die ADS-Daten nicht abgeholt werden oder?
 
Meine Ansteuerung der Klemmen erfolgt über Simulink-Modelle, habt ihr da dann eine Idee wie man bestimmten Werten dann zur Laufzeit eine solches Array zum Sammeln von Werten entwerfen könnte ohne die Simulink-Modelle zu verändern?
Das heisst, Du lässt wegen der erhofften bzw. erforderlichen Performance den SPS-Code generieren. Simulink-Modelle? Also mehrere? Befindet sich denn der bisher benutzte "DatenSammel-und-an-die-Aussenwelt-Übergabe-Punkt" in der SPS so unzugänglich tief vergraben in einem oder mehreren der Simulink-Modelle, so dass man sie ändern müsste?
Edit: Wenn ja, vielleicht trotzdem erstrebenswert?

Außerdem habe ich jetzt mit dem ADSViewer mir die Pakete angeschaut und festgestellt, dass ich immer wieder den Fehler 1282(ROUTERRR_MAILBOXFULL) habe. Kann ich die Mailbox irgendwie vergrößern? Der Fehler entsteht wahrscheinlich dadurch, dass die ADS-Daten nicht abgeholt werden oder?
Bei dem Stichwort Mailbox fällt mir ein: ich hatte mal mit einem PufferBereich zu tun, der nicht gleichzeitig beschrieben und ausgelesen werden konnte, sondern nur abwechselnd. Hinzu kamen stark variierende Latenzzeiten zwischen der Freigabe zum Beschreiben und dem tatsächlichen Beginn des Beschreibens. Meine Lösung war, einen zweiten solchen Puffer anzulegen und die beiden immer abwechselnd zu beschreiben, während der jeweils andere ungestört ausgelesen werden konnte. Dadurch wurde die Geschwindigkeit (im Gegensatz zum belegten PufferBereich) zwar nicht verdoppelt, aber immerhin deutlich stärker erhöht, als ich mir von der Massnahme überhaupt erhofft hatte. Ich weiss allerdings nicht, ob dieser Ansatz sich auf Mailboxen anwenden liesse und auch Wirkung zeigen würde.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Wofür brauchst du jetzt die 20kHz-Werte. In einem Echtzeitkontext da diese dann wieder in dein Simulink-Modell zurückmüssen?
Oder aber einfach nur für eine "spätere" Auswertung (e.g. Fourieranalysen...)

Erklär doch einfach bitte mal was du machst und speziell was deine Simulink-Modelle so treiben (sollen).

Für die spätere Auswertung würde ich bei ADS bleiben. Die Mailbox-Full löst du nicht indem du sie größer machst. Das Measurement funktioniert ja auch und somit ist das Problem vermutlich in deinem Python-Code zu suchen.
Die C++-Schnittstelle ist sehr eng angelehnt an das was auf dem "Kabel" abläuft. Eine Notification die nicht abgeholt wurde braucht routerspeicher. Bei 20kS, und jeder Sampleplunkt kommt mit einem 8 Byte Zeitstempel kannst du dir ja vorstellen wie schnell jeder Speicher verwendet wird wenn du beim abholen nicht sauber arbeitest.

Lass doch mal einen Screenshot vom AdsMonitor vom AddDeviceNotification rüberwachsen - bitte mit der Detailansicht. Ich habe nämlich keine Lust Bits zu decodieren.
Dann kann ich dir auch sagen wie viele Samples auf dem Kabel / Notification im allgemeinen geschickt werden. Das ist aber im Decoder vom AdsMonitor selber auch recht gut zu sehen (such/filter halt mal nach dem Typ DeviceNotification).

Schick doch mal einen Link wo der Python-Mist codiert ist. Vielleicht finde ich ja zwei Minuten mir das anzuschauen und verstehe es dann auch noch (habe noch nie Python codiert). Dann kann ich dir mehr sagen ob die Callback hier dann für jedes Telegramm oder wie in .Net über eine Zwischenschicht dann wirklich für jeden Einzelwert/Zeitpunkt aufgerufen wird.

Guga

Guga
 
Sorry für die späte Antwort! Die 20kHz-Werte werden nur zur späteren Auswertung und zur Darstellung im Browser benötigt. Der Wunsch ist, dass der Service später gestartet werden kann, man beliebige ADS-Variablen anfragt und diese dann geloggt werden. Also von der Funktionalität ähnlich wie das Measurement. Ein Eingriff in die Simulink-Modelle ist möglich, aber würde ich nur ungern machen, da die Lösung möglichst flexibel sein soll.
Und hier ist die Bibliothek die ich nutze: https://github.com/stlehmann/pyads. Die Bibliothek benutzt dabei TcAdsDLL mittels ctypes.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Es ist notwendig bein Anmelden der Notification das Cycle und MaxDelay entsprechend einzustellen.
Bin kein Python-Spezi, aber das müsste bei PyAds in der 'class NotificationAttrib(object)' einzustellen sein.
Versuch mal nTransMode von 3, und nMaxDelay von 1000ms.
 
Ich lese aus dem Screenshot folgendes heraus.

#1: Du hast die Notifications nicht abgeholt und deshalb ist die Mailbox = Router voll und dann kommt die Fehlermeldung Geht ganz schnell. Rechnung mit dem großen Daumen.
Wenn du davon ausgehst das die reinen Daten alle 10ms ca 4kByte sind. Das wären dann ca 8000 Notifications im 10msec Takt oder aber 80 Sekunden. Overhead wegen der Verwaltung gibt es noch obendrauf.
#2: Du bekommst jede 10msec einen Brocken mit Werten einer einzelnen Variable (zwei Byte). Und in dem Brocken sind die Werte von 187 unterschiedlichen Zeiten.

- vermutlich hast du in der AddDeviceNotification für maxDelay das entsprechende für 10msec ausgefüllt.
- ich persönlich setze in AddDeviceNotification für Cycletime immer auf 0 (entspricht dann : so schnell wie die Task rennt)
- da sich der Wert zwischen zwei einzelnen Zeiten nicht ändert ist der TransmittionMode vermutlich ADSTRANS_SERVERCYCLE

Also eigentlich alles korrekt, du musst jetzt nur schauen das du deine Callback auch schnell abarbeitest.
Schreib dir gegebenfalls mal als Debug-Wert analog beim Beckhoff-Beispiel die relevanten Daten raus und vergleiche sie mit dem ADSMonitor.
https://infosys.beckhoff.de/content/1031/tc3_adsdll2/9007199379565835.html.

Zur Frage wie viele Daten du in ein Packet packst würde ich mich vom Measruement inspierieren lassen (per ADSMonitor schauen was passiert).

Ich muss mich auch noch korrigieren, die C++ Callback wird für jede einzelnen NotificationHandle (siehe Bild) aufgerufen. Das Bild zeigt zwei Werte die gleichzeitig gesampled wurden und als ein Brocken verschickt werden.

Soweit ich es sehe ist das im Python identisch.


bild.jpg
 
ADS1.jpg
Okay, ich nutze jetzt CycleTime von 0 und ein maxDelay von 100ms und ADSTRANS_SERVERCYCLE. Im Moment rufe ich nur eine Funktion auf, die nichts macht. Also an einer zu langsamen Verarbitungszeit kann es eigenlich auch nicht liegen. Was mich auch am meisten verwundert ist, dass der Fehler, wie im Screenshot, nicht durchgänig auftriftt.
Könnte es sein, dass mir Windows einen Strich durch die Rechnung macht, weil es die Callback-Funktion nicht an die Reihe lässt? Oder könnte es ein Problem sein, dass ich das ganze gerade auf einer virtuellen SPS ausprobiere? Ich habe nämlcih der virtuellen SPS statt einem geteilten Core einen isolated Core zugewiesen und ich habe zumindest das Gefühl, dass es jetzt ein wenig besser läuft.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
So ich scheine das Problem jetzt gelöst zu haben. Ich kann es selber nicht glauben, aber ich habe anstatt das Programm mit einer while(true){do nothing}-Schleife mit einer einer if-Abfrage, welche auf eine Eingabe wartet, am Leben gehalten und jetzt funktioniert die Abfrage problemsolos mit 20kHz.
Vielen Dank für Hilfe von euch allen! :)
 
... ich habe anstatt das Programm mit einer while(true){do nothing}-Schleife mit einer einer if-Abfrage, welche auf eine Eingabe wartet, am Leben gehalten und jetzt funktioniert die Abfrage problemsolos mit 20kHz.
Das verstehe ich nicht. Eine IF-Abfrage wartet auf eine Eingabe? Ist das eine Eingabe von der Sorte, die das Programm "anhält", bis endlich die Eingabe erfolgt ist?
 
Genau, einfach eine Abfrage, die darauf wartet, ob etwas in der Kommandozeile abgeschickt wurde. Ich denke bei der while-Schleife wird wahrscheinlich irgendwie probiert diese zu optimieren, da in ihr ja eigentlich nichts geschieht. Das geht hier wohl schief. Ich kann mir das ganze aber auch nicht ganz erklären.
Ich habe gerade herausgefunden, dass auch while True: time.sleep(1), also schlafe immer wieder für eine Sekunde genauso funktioniert. Vielleicht ist auch das Python-Programm damit beschäftigt immer wieder die Bedingung auszuwerten, wenn in der Schleife nichts passiert.
 
Zurück
Oben