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



## RobotSox (14 Oktober 2021)

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 (14 Oktober 2021)

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.


----------



## RobotSox (14 Oktober 2021)

Mit der Zeit erhöhen habe ich bereits probiert, bringt jedoch wenig Erfolg…

Wie kann ich denn Abfragen ob der Auftrag noch läuft bzw schon abgearbeitet ist ?


----------



## DeltaMikeAir (14 Oktober 2021)

Ich hänge mal @Rainer Hönle hier mit an


----------



## Matze001 (14 Oktober 2021)

Poste doch mal einen Codeschnipsel, vielleicht wird dann erkennbar ob man etwas optimieren könnte.


----------



## RobotSox (14 Oktober 2021)

z.B. die Funktion Motorstrom aus NCK auslesen:

```
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:


```
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();
        }
```


----------



## Gerhard Bäurle (15 Oktober 2021)

@DELTALOGIC Support – könnt ihr etwas dazu sagen bzw. @Rainer Hönle nochmal anstupsen?


----------



## Matze001 (15 Oktober 2021)

Moin,

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

Außerdem würde ich 


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

durch


```
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 (15 Oktober 2021)

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 (16 Oktober 2021)

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.


----------



## RobotSox (18 Oktober 2021)

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?


```
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


----------



## Rainer Hönle (18 Oktober 2021)

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?


----------



## DeltaMikeAir (18 Oktober 2021)

RobotSox schrieb:


> 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 (18 Oktober 2021)

@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 ...?


----------



## RobotSox (18 Oktober 2021)

Rainer Hönle schrieb:


> 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%.


----------

