effektive Suche über 28 Datenbaustein

Grimsey

Level-2
Beiträge
543
Reaktionspunkte
32
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen,

ich muss innerhalb der SPS Daten aus 28 Datenbausteinen auslesen. Diese Datenbausteinen bilden ein Lager ab und beinhalten den Fachinhalt (Palettendaten 80 Byte) und einen Fachstatus (4 Byte).
Innerhalb der Datenbausteine sind 2 Arrays (X und Y) angelegt die von 1..61 (X) und 1..12 (Y) laufen. Auf Grund der daraus resultierenden Größe der DBs sind die 28 Datenbausteine in 7 4er Gruppen angelegt. Die Bausteinnummern laufen von 111...114, 121..124, 131..134 und so weiter.

Ich benötige nun an verschiedenen Stellen eine Funktion, die mir auf Grund der Koordinaten sowohl die Palettendaten als auch den Status eines Faches zurückliefert.
Es gibt aber auch Anwendungsfälle, in denen das gesamte Lager durchsucht werden muss, d.h. der Inhalt aller Fächer aller 28 Datenbausteine muss der Reihe nach angeschaut und ausgewertet werden.
Als Ausgangsvariable wird eine Fachnummer übergeben, die sich aus den Koordinaten zusammensetzt (Regal, X, Y und Z [das Lager hat 2 Fachtiefen).
Ich habe die Suchroutine nun so gestaltet, dass ich mit Hilfe von 4 FOR-Schleifen alle Datenbausteine durchlaufe, den Fachstatus auslese und anschließend die Daten auswerte. Klappt prinzipiell wirklich gut. Da Problem ist allerdings die Laufzeit der CPU. Zum Einsatz kommt in diesem Fall eine 417-4. Das Durchlaufen der Schleife mit Auslesen der Fachdaten treibt die Zykluszeit allerdings auf rund 110 ms nach oben.

Ich bin nun auf der Suche nach einer Möglichkeit, die Suchroutine zu optimieren/zu verändern.

Hat hier jemand vielleicht einen Tipp, wie man dies effektiv bewerkstelligen bzw. wo man noch etwas optimieren kann?

Hier einmal ein Auszug aus dem bisherigen Code

Code:
VAR_TEMP
    i:                  INT;
    j:                  INT;
    tX:                 INT;
    tY:                 INT;
    tZ:                 INT;
    tRegal:             INT;
    tFachnummer:        DINT;
    tleer:              ARRAY[1..15] OF INT;
    tbelegt:            ARRAY[1..15] OF INT;
    tleer_gesperrt:     ARRAY[1..15] OF INT;
    tbelegt_gesperrt:   ARRAY[1..15] OF INT;
END_VAR


VAR    
    tPalettenDaten:     "UDT_Palette";
    tFachDaten:         "UDT_Facheigenschaften";    
END_VAR


BEGIN
    // Variablen zurücksetzen
    i:=0;
    FOR i:= 1 TO 15 DO
        tleer[i] := 0;
        tleer_gesperrt[i] := 0;
        tbelegt[i] := 0;
        tbelegt_gesperrt[i] := 0;    
    END_FOR;


    tRegal:=0;
    tX:=0;
    tY:=0;
    tZ:=0;
    
         FOR tRegal := 1 TO 14 BY 1 DO
           FOR tX := 1 TO 61 BY 1 DO
                FOR tY := 1 TO 12 BY 1 DO
                    FOR tZ := 1 TO 2 BY 1 DO


                    // Fachnummer erstellen und an FC übergeben              
                    FC_KonvertKoordinaten(iRegalnummer := tRegal
                                                   ,iX := tX
                                                   ,iY := tY
                                                   ,iZ := tZ
                                          ,oFachnummer := tFachnummer
                                          );
                    // FC gibt als Rückgabewert die PalettenDaten und den Fachstatus zurück
                    FC_FachAuslesen(iFachnummer :=  tFachnummer// IN: DINT
                                    ,iZielPalettenDaten := tPalettenDaten // IN: ANY
                                    ,iZielFachDaten := tFachDaten  // IN: ANY
                                    ); // VOID                                                             


                    // Fachstatus auslesen und Fächer mit den verschiedenen Zuständen zählen                                                   
                    IF tFachDaten.Belegt = false THEN                        
                        IF tFachDaten.Gesperrt = false THEN
                            tleer[tRegal] := tleer[tRegal] + 1;
                        ELSE
                            tleer_gesperrt[tRegal] := tleer_gesperrt[tRegal] + 1;
                        END_IF;                    
                    ELSE                    
                        IF tFachDaten.Gesperrt = false THEN
                            tbelegt[tRegal] := tbelegt[tRegal] + 1;
                        ELSE
                            tbelegt_gesperrt[tRegal] := tbelegt_gesperrt[tRegal] + 1;
                        END_IF;                    
                    END_IF;   
                                                                             
                    END_FOR;
                END_FOR;
           END_FOR;
        END_FOR;
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

der FC_FachAuslesen holt vmtl die Daten aus Deinen DBs. Vielleicht solltest Du den ausbauen, dass gleich alle Daten pro DB in einem Array oder so gespeichert werden. Du öffnest und schließt die DBs im Rahmen Deiner Schleifen ja zig 1000 mal. Ich denke, das kostet viel Zeit.
 
Danke für Eure Hinweise,

der "FC_FachAuslesen" bildet anhand der Fachnummer/Koordinaten einen Any-Pointer. Dieser wird dann auf die Zeiger "iZielPalettenDaten" und "iZielFachDaten" zurückgeben. Erst im oben gezeigten Code greife ich dann auf DBs zu.
Die Schleife ohne Inhalt treibt die Zykluszeit alleine schon auf knapp 30 ms hoch.
Das Zusammensetzen der Fachnummer habe ich jetzt ohne den separaten Bausteinaufruf gemacht und berechne diese nun direkt innerhalb der Schleife. Das hat schon einmal ordentlich Zeit gespart.

Die Idee mit dem Aufteilen auf mehrere Zyklen hatte ich auch schon und werde diese mal ausprobieren.
 
Wenn ich das richtig gezählt habe hat deine innerste Schleife 20496 Durchläufe. Ich würde den innersten Teil darum so kurz wie möglich gestalten. Warum wird die UDT tPalettenDaten ausgelesen wenn es nicht benötigt wird? Weg damit.

So wie es aussieht benötigst du nur 3 Bool-Variablen aus dem Datensatz.
Ist zwar unschön das symbolische Konzept teilweise aufzugeben, aber du könntest dir eine Funktion schreiben die anhand der übergebenen Indizes die Absolutadresse (DB Nummer, Byte und Bit) berechnet und wirklich nur die Zustände dieser 3 Bits zurückgibt.

Oder komplett anderer Ansatz:
Wer setzt denn den Befehl ab ob ein Platz gesperrt oder freigegeben wird? Evtl. kann man anhand der gegebenen Befehle die Anzahlen erhöhen und verringern, sodass man alle Plätze höchstens bei Neuanlauf der SPS durchsuchen muss.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Oder komplett anderer Ansatz:
Wer setzt denn den Befehl ab ob ein Platz gesperrt oder freigegeben wird? Evtl. kann man anhand der gegebenen Befehle die Anzahlen erhöhen und verringern, sodass man alle Plätze höchstens bei Neuanlauf der SPS durchsuchen muss.

es wird immer einen geben, der mal alles durchsucht haben will... IMMER ;)

anderer Ansatz: die CPU für das einsetzen, was sie kann und die Datenverwaltung dahin auslagern, wo sie hingehört? externe Datenbank ... das macht nicht nur die CPU schlanker sondern das System bei entsprechend gut eingerichteter Replikation ausfallsicherer
 
alles soweit richtig :)
der hier gezeigte Code ist ein Beispiel und erst der Anfang. Eine Routine zu haben, die mir gleich beide Daten bereitstellt halte ich für recht sinnvoll da ich diese wahrscheinlich noch öfter benötigen werden. Und ich habe ungern für jeden Fall einen extra Baustein. Auch wenn es das hier durchaus beschleunigen würde.

Das ermitteln der belegten Fächer ist als Beispiel zu verstehen. Diesen speziellen Anwendungsfall kann man auch anders lösen, das ist mir bewusst. Mir geht es vielmehr um das Durchsuchen des ganzen Lagers.

@vierlagig: das Lager wird bei uns sowohl in der SPS als auch in einer Datenbank gehalten. Der Hintergrund ist der, dass der Kunde auch bei Ausfall seiner Datenbank weiter produzieren muss/möchte und wir daher die doppelte Datenhaltung machen. Wir sind damit bisher sehr gut gefahren...hatten bis jetzt aber auch nicht so ein großes Lager mit 7 Gassen und 2 Fachtiefen.
 
Na gut, dann musst du halt im Kleinen optimieren.

Z.B. die Statistikinformationen nicht in einem Array ablegen, sondern in einzelnen Variablen und dann mit einem Case den entsprechenden Wert erhöhen.

Anstatt
Code:
tleer:              ARRAY[1..15] OF INT;
ein
Code:
tleer_1 : INT;
tleer_2 : INT;
...

und
Code:
CASE tRegal OF:
1: 
 tleer_1 := tleer_1 + 1;
...

Braucht zwar mehr Codespeicher, ist aber schneller weil die Zeigerberechnung wegfällt..
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ggf. Compileroptionen anpassen falls noch nicht geschehen. Es lässt sich der Baustein aber nicht mehr online beobachten, und ob du das OK-Flag brauchst musst du selber entscheiden.

{SetOKFlag := 'n'; OptimizeObjectCode := 'y'; SCL_CreateDebugInfo := 'n'}
 
Hallo,

ich würde dir als erstes vorschlagen deinen kleinen Helferbaustein in AWL zu schreiben. Dein SCL Compiler macht viel zu viel Code für diese kleine Aufgabe. In AWL kannst du das ganze schlanker und damit nicht so zeitintensiv abhandeln.
Da ich auch schon oft das durchsuchen großer Datenmengen programmiert habe, kann ich dir sagen das der Vorschlag von vierlagig goldrichtig ist. Dein Kunde kann bei einer solchen Datenmenge nicht verlangen das das durchsuchen in 120ms fertig ist. 5s warten ist bei dieser Menge meiner Meinung nach gerechtfertigt.
Also auf mehrere Zyklen aufteilen.

Bis denn dann

Teddy
 
ich würde dir als erstes vorschlagen deinen kleinen Helferbaustein in AWL zu schreiben. Dein SCL Compiler macht viel zu viel Code für diese kleine Aufgabe.

Wenn du in SCL die Überprüfung der Arraygrenzen und die Debug-Info ausschaltest, dann erzeugt SCL auch sehr kompakten Code.
Ich trau mich beinahe wetten, dass du es auf einer 300er in AWL nicht wesentlicher schneller hinbekommst.

Ansonsten hast du recht ... Aufteilen in mehrere Zyklen ist hier die sinnvollste Lösung

Gruß
Dieter
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich löse solche Aufgaben mit einem Index DB.
Dann muss man nicht immer alles durchsuchen, sondern man findet in dem Index wo und ob eine Palette vorhanden ist.
Dann erst wird in die entsprechenden DB nachgelesen.

Ein PLC ist und hat keine Datenbank. ;)


bike
 
Ich löse solche Aufgaben mit einem Index DB.
Dann muss man nicht immer alles durchsuchen, sondern man findet in dem Index wo und ob eine Palette vorhanden ist.
Dann erst wird in die entsprechenden DB nachgelesen.

Du kannst auch für jedes Taballenfeld einen eigenen DB verwenden.
Damit bist du bei allen Suchvorgängen schneller.
Ausserdem kannst du damit die Datenbank im laufenden Betrieb erweitern.

Ein PLC ist und hat keine Datenbank. :wink:

Vielleicht erkennt ja Siemens mal die Notwendigkeit und integriert eine DB in die S7-2500 :p

Schönen Sonntag

Gruß
Dieter
 
Ich meinte auch nicht einen DB pro Fach, sondern einen DB pro Feld / Kriterium.
Vergleich zu bikes Index-DB.

Gruß
Dieter

Macht es nicht Sinn nur die Fächer die beladen sind weiter zu betrachten?
Für jedes Fach in dem DB nur die Information ob voll oder leer.
Dann bei voll die Adresse wo die Daten liegen mit einem Pointer bauen.
Das habe ich bei einer Anlage so realisiert.

Habe ich wohl nicht klar genug geschrieben, was ich mit Index gemeint habe.


bike
 
Macht es nicht Sinn nur die Fächer die beladen sind weiter zu betrachten?
Das Programm muß auch dann ohne Zykluszeitüberschreitung funktionieren, wenn das Lager voll ist. Programm-Abkürzungen sind normalerweise "nice", bringen aber nichts bei vollem Lager.

1 DB je Tabellenspalte/Kriterium:
Ich kann mir nicht vorstellen, daß allein dadurch Suchvorgänge wesentlich schneller werden. Es sei denn, die Tabellenspalte ist sortiert oder indiziert.

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Das Programm muß auch dann ohne Zykluszeitüberschreitung funktionieren, wenn das Lager voll ist. Programm-Abkürzungen sind normalerweise "nice", bringen aber nichts bei vollem Lager.

1 DB je Tabellenspalte/Kriterium:
Ich kann mir nicht vorstellen, daß allein dadurch Suchvorgänge wesentlich schneller werden. Es sei denn, die Tabellenspalte ist sortiert oder indiziert.

Harald

Ein Lager mit über 20000 Plätzen in der PLC verwalten geht in die Hose.
Ich habe es so verstanden, dass ein Randomsystem mit 20000 Nummern vorhanden ist.
Ich habe ein System mit 9999 Nummern mit einem IndexDB programmiert und das funktioniert seit 3 Jahren ohne viel Ärger.

Bei mir um die Ecke ist ein Auslieferungslager eines Verlags das mit PLCs und zur Datenhaltung mit einer Datenbank betrieben wird.
Denn wenn wirklich 20000 Plätze vorhanden sind, wer überwacht und wie wird editiert?
Mit einer 417er wird das wohl nicht so echt klappen.

Ich würde es so anlegen und wenn dann die Zykluszeit in die Knie geht, dann kann man relativ leicht den Suchvorgang splitten.

Man kann an jeder Lösung eine Schwachstelle finden oder eine hinein interpretieren.


bike
 
Es gibt natürlich verschiedene Strategieen eine Lagerverwaltung. Mit den heutigen CPUs ist es möglich das Lager komplett in der SPS zu verwalten.
Meist fährt man zweigleisig.
Der Normalbetrieb läuft über Materialflussrechner und der Notbetrieb über SPS. Beim Umschalten wird ein Datenabgleich zwischen Systemen durchgeführt.

Gruß
Dieter
 
Der Normalbetrieb läuft über Materialflussrechner und der Notbetrieb über SPS. Beim Umschalten wird ein Datenabgleich zwischen Systemen durchgeführt.

Das stimmt bedingt, denn ein System mit mehr als 20000 Teilen in einer PLC sinnvoll verwalten, ist nicht sinnvoll.
Wie soll da eine Überprüfung und ggF editieren und Inventur möglich sein?
Das ist schon in einem normalen Datenbanksystem ein Akt bis es gut und praktikabel funktioniert.

Aber wir zerbrechen uns den Kopf und zeigen Lösungen auf, jetzt ist der TE an der Reihe sich eine Lösung zu erarbeiten.


bike
 
Zurück
Oben