AGLINK C# mehrere Daten auslesen (Performance)(CPU 100%)

RobotSox

Member
Beiträge
9
Punkte Reaktionen
0
Zuviel Werbung?
->Hier kostenlos registrieren
Hallo,

ich versuche mich an der AGLink Bibliothek in der Programmiersprache C#.
Ich lese bereits erfolgreich Variablen aus der Sinumerik 840d SL aus dem NCK Bereich aus. (Motortemperatur, Strom, Drehzahl)

Nun habe ich allerdings das Problem das bei 31 Achsen welche die 3 Variablen in 50ms Takt per AGLink abrufen, die PC CPU bei 100% klebt.

Das ganze ist so aufgebaut, das für jede Achse ein eigener Thread neben dem "Mainthread mit aktiver PLC Verbindung" geöffnet wird, und dort in einer Schleife mit 50ms Timer die Abfragen ausgeführt werden und in einer SQL Datenbank abgespeichert werden.

Ist das vorgehen so falsch?

Ich habe zu Testzwecken bereits das Schreiben in die DB abgeschaltet, sodass nur AGLink Funktionen ausgeführt werden --> CPU immer noch bei 90-100%

Gibt es Ratschläge bzw. Ideen für das Verhalten?

Danke im Vorraus :)
 

Heinileini

Well-known member
Beiträge
4.120
Punkte Reaktionen
827
Ich würde ausprobieren, ob es (besser) funktioniert, wenn die Telegramme in grösseren zeitlichen Abständen abgeschickt werden, z.B. 100 ms oder mehr.
Noch besser: warten bis der vorausgegangene Auftrag abgearbeitet ist.
 
OP
R

RobotSox

Member
Beiträge
9
Punkte Reaktionen
0
Zuviel Werbung?
->Hier kostenlos registrieren
z.B. die Funktion Motorstrom aus NCK auslesen:
C#:
public Double ReadStromistwert(Int32 connnr, Int32 timeout)
        {
            Int32 result = 0;
            AGL4.NckDataRW[] rwfield = new AGL4.NckDataRW[1];
            rwfield[0] = new AGL4.NckDataRW();
            rwfield[0].Area = AGL4.NCK_Area.eNCK_AreaNCK;
            rwfield[0].Block = AGL4.NCK_Block.eNCK_BlockSEMA;
            rwfield[0].Column = 123;
            rwfield[0].Row = (byte)Axis;
            rwfield[0].RowCount = 1;
            rwfield[0].Unit = 1; //(byte)Channel;
            rwfield[0].DDEVarType = AGL4.NCK_DDEVarFormat.eNCK_LE_Float64;
            rwfield[0].BuffLen = 8;
            rwfield[0].Buff = new Byte[rwfield[0].BuffLen];
            rwfield[0].Result = 0;

            result = AGL4.NCK_ReadMixEx(connnr, ref rwfield, timeout);

            if (result < 0)
            {
                // Error happened.
                String errormsg = "";
                AGL4.GetErrorMsg(result, out errormsg);
            }

            return System.BitConverter.ToDouble(rwfield[0].Buff, 0);
        }

Diese wird dann in einem Timer aufgerufen:

C#:
public System.Timers.Timer Timer50ms = new System.Timers.Timer();

public void EventTimer50ms(object sender, ElapsedEventArgs e)
        {
            Drehzahl = ReadDrehzahl(formMain.m_iConnNo, 30000);

            if (ReadTemperatur(formMain.m_iConnNo, 30000) != 0)
            {
                Temperatur = ReadTemperatur(formMain.m_iConnNo, 30000);
            }

            Strom = ReadStromistwert(formMain.m_iConnNo, 30000);
            Override = ReadAchsoverride(formMain.m_iConnNo, 30000);
            Motordrehmoment = ReadDrehmoment(formMain.m_iConnNo, 30000);
            UpdateDatabase();
        }
 

Matze001

Well-known member
Beiträge
2.481
Punkte Reaktionen
481
Moin,

kannst Du die Abfragen nicht in eine Abfrage zusammenbauen, statt für jeden Wert eine Abfrage zu senden.

Außerdem würde ich

Code:
 if (ReadTemperatur(formMain.m_iConnNo, 30000) != 0)
            {
                Temperatur = ReadTemperatur(formMain.m_iConnNo, 30000);
            }

durch

Code:
 var TmpTemperatur = ReadTemperatur(formMain.m_iConnNo, 30000)
 
 if (TmpTemperatur != 0)
            {
                Temperatur = TmpTemperatur;
            }

ersetzen, dann sparst Du Dir einmal das lesen der Temperatur.

Grüße

Marcel
 

Rainer Hönle

Well-known member
Beiträge
5.667
Punkte Reaktionen
989
Zuviel Werbung?
->Hier kostenlos registrieren
Jede Variable in einem eigenen AGL4.NCK_ReadMixEx aufzurufen ist leider die ineffizienteste Art und Weise für den Zugriff. Mach das Array doch so groß wie insgesamt Variablen pro Achse benötigt werden, packe alle Variablen (5??) in das Array, mache einen einzigen Leseaufruf pro Achse und spare dir das doppelte Lesen der Temperatur.
Zu prüfen wäre noch, ob die sl in der Lage ist, im 50 ms Takt die Werte der 31 Achsen überhaupt zu liefern.
 

Peter Gedöns

Well-known member
Beiträge
599
Punkte Reaktionen
148
welche 840Dsl ist da im Einsatz ? die kleinen NCU können das sicher nicht leisten.
sind da wirklich 31 Achsen aktiv ? . Für eine Funktion die immer die werte der Aktiven Achsen ausliest ,würde ich das Array Aktive Achsen aus dem DB7 auswerten.
Ich kenne den AG Link nicht. Kann er Werte aus dem Antrieb lesen ? wenn ja könnte das vielleicht helfen . Dazu muss man aber erst mal die Achs Antriebs Zuordnung aufdröseln.
 
OP
R

RobotSox

Member
Beiträge
9
Punkte Reaktionen
0
Vielen Dank erstmal für die Antworten.
Nachdem ich die FUnktion umgebaut habe, das ich die gewünschten NCK-Parameter mit einem AGLink Call auslese, liegt die CPu Last bei nur mehr 20-30% :)

Ich habe aber noch das Problem, das Teilweiße als "ausgelesener Wert" immer nur NULL zurückommt statt dem eigentlichen Wert.
Sprich bei 7 von 10 Aufrufen kommt er richtige aktuelle Wert zurück, bei den anderen 3 Aufrufen kommt allerdings nur NULL.
Hat hier jemand vllt auch eine Idee?

C#:
public void GetNCKData()
        {
            //Motorstrom
            Int32 result = 0;
            AGL4.NckDataRW[] rwfield = new AGL4.NckDataRW[5];
            rwfield[0] = new AGL4.NckDataRW();
            rwfield[0].Area = AGL4.NCK_Area.eNCK_AreaNCK;
            rwfield[0].Block = AGL4.NCK_Block.eNCK_BlockSEMA;
            rwfield[0].Column = 123;
            rwfield[0].Row = (byte)Axis;
            rwfield[0].RowCount = 1;
            rwfield[0].Unit = 1; //(byte)Channel;
            rwfield[0].DDEVarType = AGL4.NCK_DDEVarFormat.eNCK_LE_Float64;
            rwfield[0].BuffLen = 8;
            rwfield[0].Buff = new Byte[rwfield[0].BuffLen];
            rwfield[0].Result = 0;

            //Motordrehzahl
            rwfield[1] = new AGL4.NckDataRW();
            rwfield[1].Area = AGL4.NCK_Area.eNCK_AreaNCK;
            rwfield[1].Block = AGL4.NCK_Block.eNCK_BlockSEMA;
            rwfield[1].Column = 136;
            rwfield[1].Row = (byte)Axis;
            rwfield[1].RowCount = 1;
            rwfield[1].Unit = 1;// (byte)Channel;
            rwfield[1].DDEVarType = AGL4.NCK_DDEVarFormat.eNCK_LE_Float64;
            rwfield[1].BuffLen = 8;
            rwfield[1].Buff = new Byte[rwfield[0].BuffLen];
            rwfield[1].Result = 0;

            //Motordrehmoment
            rwfield[2] = new AGL4.NckDataRW();
            rwfield[2].Area = AGL4.NCK_Area.eNCK_AreaNCK;
            rwfield[2].Block = AGL4.NCK_Block.eNCK_BlockSEMA;
            rwfield[2].Column = 183;
            rwfield[2].Row = (byte)Axis;
            rwfield[2].RowCount = 1;
            rwfield[2].Unit = 1;// (byte)Channel;
            rwfield[2].DDEVarType = AGL4.NCK_DDEVarFormat.eNCK_LE_Float64;
            rwfield[2].BuffLen = 8;
            rwfield[2].Buff = new Byte[rwfield[0].BuffLen];
            rwfield[2].Result = 0;

            //Achsoverride
            rwfield[3] = new AGL4.NckDataRW();
            rwfield[3].Area = AGL4.NCK_Area.eNCK_AreaNCK;
            rwfield[3].Block = AGL4.NCK_Block.eNCK_BlockSEMA;
            rwfield[3].Column = 159;
            rwfield[3].Row = (byte)Axis;
            rwfield[3].RowCount = 1;
            rwfield[3].Unit = 1;// (byte)Channel;
            rwfield[3].DDEVarType = AGL4.NCK_DDEVarFormat.eNCK_LE_Float64;
            rwfield[3].BuffLen = 8;
            rwfield[3].Buff = new Byte[rwfield[0].BuffLen];
            rwfield[3].Result = 0;

            //Motortemperatur
            rwfield[4] = new AGL4.NckDataRW();
            rwfield[4].Area = AGL4.NCK_Area.eNCK_AreaFeedDrive;
            rwfield[4].Block = AGL4.NCK_Block.eNCK_BlockM;
            rwfield[4].Column = 35;
            rwfield[4].Row = (byte)Axis;
            rwfield[4].RowCount = 1;
            rwfield[4].Unit = (byte)Channel;
            rwfield[4].DDEVarType = AGL4.NCK_DDEVarFormat.eNCK_LE_Float32;
            rwfield[4].BuffLen = 4;
            rwfield[4].Buff = new Byte[rwfield[0].BuffLen];
            rwfield[4].Result = 0;

            result = AGL4.NCK_ReadMixEx(formMain.m_iConnNo, ref rwfield, 30000);

            if (result < 0)
            {
                // Error happened.
                String errormsg = "";
                AGL4.GetErrorMsg(result, out errormsg);
            }

            Strom = System.BitConverter.ToDouble(rwfield[0].Buff, 0);
            Drehzahl = System.BitConverter.ToDouble(rwfield[1].Buff, 0);
            Motordrehmoment = System.BitConverter.ToDouble(rwfield[2].Buff, 0);
            Override = System.BitConverter.ToDouble(rwfield[3].Buff, 0);
            Temperatur = System.BitConverter.ToSingle(rwfield[4].Buff, 0);
        }

ALS NC kommt eine 840dSL NCU 720.3 PN zum Einsatz
 

DeltaMikeAir

User des Jahres 2018
Beiträge
9.728
Punkte Reaktionen
2.299
Nachdem ich die FUnktion umgebaut habe, das ich die gewünschten NCK-Parameter mit einem AGLink Call auslese, liegt die CPu Last bei nur mehr 20-30%
Wo liegt denn die CPU Auslastung, wenn der CALL nicht ausgeführt wird ( damit man mal ein Gefühl hat, wieviel das auslesen tatsächlich die Auslastung anhebt )?
 

Larry Laffer

Supermoderator
Teammitglied
Beiträge
13.050
Punkte Reaktionen
2.699
@Rainer:
läuft AGL4.NCK_ReadMixEx denn synchron ?

@TE:
Warum deklarierst und instanzierst du innerhalb von GetNCKData alle rwfield-Elemente immer wieder neu ? Es reicht doch wenn du das einmal beim Start der Software ausführst ...?
 
OP
R

RobotSox

Member
Beiträge
9
Punkte Reaktionen
0
Zuviel Werbung?
->Hier kostenlos registrieren
Die Auslastung erscheint mir trotzdem noch viel zu hoch.
Werden denn jedesmal alle 31 Achsen ausgelesen?
Wie erfolgt der Aufruf genau? Also ein Timer pro Achse?
Es wird erstmal ausgelesen wieviele Achsen die Maschine besitzt und dann wird für jede Achse ein Timer geöffnet welcher die Daten abfragt.
Im Testfall sind es derzeit 6 Achsen die ausgelesen werden. Habe es auch bereits mit nur 2 Achsen probiert, da funktioniert noch alles ohne Null Rückgabe, ab 3 Achsen tauchen hier und da die nullen wieder auf.

Die normale PC CPU Last liegt auch bei 15%-20%.
 
Oben