TIA Puffer programmieren

W@stl

Level-2
Beiträge
65
Reaktionspunkte
7
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo liebe Codierer,

ich nutze dieses Forum sehr oft, und komme auch meistens nur durch die Suche zur Lösung...
aber diesmal stoße ich grade an meine Programmiergrenzen...


Ich habe einen kleinen Puffer mit 11 Werkstückträgern (=WT) auf einem Laufband.
jeder Platz hat einen 'belegt' Sensor.

wenn ein WT auf einem Platz eingelagert wird, verweilt es dort 2h bis eine Art Prüfung abgelaufen ist.
ist dieses fertig, wird es wieder ausgelagert. (somit ist der 1.Platz frei)
werden während dieser Zeit weitere WT eingelagert, werden diese auf die nächsten freien Plätze gefahren.

ist der 1. Platz wieder frei, sollen die hinten anstehenden WT´s um einen verschoben werden.
also eine art Schieberegister. eigentlich nicht all zu schwer...

mein Problem ist jetzt, dass ich jeden einzelnen Platz übers HMI beliebig deaktivieren kann. (wg. defekten an Leitungen o.ä.)

wenn also beispielsweise Platz 3 und 5 deaktiviert sind , sollen diese auch nicht mehr angefahren werden.
--> wenn Platz 1 frei ist, dann soll wie folgt verschoben werden:
-2 auf 1
-4 auf 2
-6 auf 4 ...


für diesen Puffer hab ich ein array[0..11] of 'Datentyp' erstellt. (0=default zum Löschen)

meine ersten Ideen waren, dass ich die 11 Sensoren auf ein Temp-Array schreibe, und mir daraus mit einer FOR-schleife die Freien Plätze suche.
(frei = nicht belegt und nicht deaktiviert)
das funktioniert auch wunderbar.
somit kann ich mir auch den letzten freien Platz suchen und den nächsten WT dort hin fahren lassen.

nun hab ich aber meine Probleme dabei, dass ich beim Verschieben der Daten den deaktivierten Platz auslasse und dafür auf den nächsten Platz schreibe.

ich hab es hoffendlich verständlich erklährt, was ich machen möchte.
und vielleicht habt ihr ein paar bessere Ideen wie ich... :ROFLMAO:

in SCL bin ich noch etwas unerfahren, komme aber eigentlich ganz gut zurecht...
vielen Dank schon mal!
MfG W@stl
 
Werden die Plätze auch physikalisch verschoben bzw. die WT von Platz zu Platz oder nur in Deinen Daten?
Wenn nur in den Daten, warum dann überhaupt?
Die Plätze können also gesperrt (deaktiviert) werden.
Die WT können fertig oder unfertig sein. Muss der zuerst fertig gewordene auf den zum ZeitPunkt des FertigWerdens ersten freien Platz? Will sagen ist die ReihenFolge des FertigWerdens relevant?
Irgendwie schweben mir zwei Arrays vor:
Array Platz mit PlatzNr als Index und den Informationen deaktivierter Platz, belegter Platz und der zugeordneten WT-Nr.
Array WT mit der WT-Nr als Index und allen erdenklichen Daten, die einem WT zugeordnet sind.
Da es anscheinend "nur" um 11 Plätze bzw. 11 WT geht, denke ich, dass Du gut ohne irgendwelche Sortiererei auskommen kannst und dennoch eine übersichtliche VisuDarstellung behältst.
Wahrscheinlich habe ich den "KnackPunkt" Deines Problems noch nicht richtig verstanden.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Guten Morgen!

ja, die WT werden Physikalisch eingelagert und verschoben.
Die WT können fertig oder unfertig sein. Muss der zuerst fertig gewordene auf den zum ZeitPunkt des FertigWerdens ersten freien Platz? Will sagen ist die ReihenFolge des FertigWerdens relevant?
in dem sinne eigentlich nicht, da die Zeit der WT startet (und stoppt, sobald verschoben wird (TONR)), sobald sie angekommen sind.
die Plätze werden (physikalisch gar nicht anders machbar) nacheinander angefahren.
somit ist immer der erste Platz zuerst fertig.

was ähnliches wie einen Array als Platznummer habe ich schon mit:
Code:
#tempErstesFreiesFeld := 1;    // Temp initialisieren
    
    FOR #tempFORErstesFreiesFeld := 1 TO 11 DO
        
        IF #Daten.Platz[#tempErstesFreiesFeld].frei
        THEN
            EXIT;
        ELSE
            #tempErstesFreiesFeld := #tempErstesFreiesFeld + 1;
        END_IF;
    END_FOR;

das selbe habe ich mit dem letzten freien Platz und den belegten Plätzen gemacht.

ich müsste jetzt 'nur' noch den WT samt Speicher über einen dazwischen liegenden gesperrten Platz fahren/speichern. (und die Zeit danach weiterlaufen lassen)
und dass können ja mehrere sein, nicht nur einer.
und das ist gerade mein Knack-Punkt...

danke für Hilfe!
mfg W@stl
 
Hast Du wirklich 11 Sensoren oder meinst Du mit Sensoren einfach nur irgendwelche internen Variablen?
Wenn Du einzelne Plätze herausnehmen willst, wie löst Du dann das Problem das die Sensoren an einer anderen Stelle sind als das Produkt das auf dem Laufband liegt (welches in der Regel ja immer nacheinander steht um Platz nicht zu verschwenden), ebenfalls - wie soll die Visu die belegte Position 3, physikalisch aber belegte Position 2 anzeigen die ja gesperrt sein würde?
 
es sind 11 Näherungsschalter vorhanden, für jedes WT einen, jeweils auch 1 Vereinzeller, dass das WT an der richtigen Stelle stehen bleibt.
wenn 1 Platz deaktiviert wird, dann kann der Bediener diesen Platz auch rücksetzen, dann muss das WT entnommen werden.

hätt ich alles vielleicht dazu schreiben sollen... :) Sorry!
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich finde dass für solche Aufgaben ist die eigentliche Arbeit die Daten zu vorbereiten.
Wenn man die Daten ordentlich vorbereitet hat schreibt die Code "von sich selbst".

Hier ein Vorschlag. Anstatt Platz 0 für die Daten zum einlagern habe ich eine IN. Finde ich mehr intuitiv. Aber du kannst es umändern wenn du willst.

Code:
IN/OUT: 
ARRAY[1..11] OF STRUCT
// 1: Erste Platz, immer für auslagern verwendet
// 2..11: Verweil-Plätze
.gesperrt : BOOL
.belegt : BOOL
.daten : UDT of "WT_daten"

IN:
gesperrte_plaetze: ARRAY[1..11] OF BOOL ; // Von HMI
WT_einlagern_daten : UDT "WT_Daten"

IN/OUT:
jetzt_einlagern // freien Platz finden und Daten von "einlagern" auf 1..11 belegen. Von aussen gesetzt, von innen zurückgesetzt
jetzt_auslagern // platz 1 auslagern. Von aussen gesetzt, von innen zurückgesetzt

OUT:
es_gibt_mind_einen_freien_platz : BOOL
alle_freie_plateze_belegt : BOOL
fehler_beim_einlagern : BOOL // impuls
WT_wurde_eingelagert : BOOL // impuls
WT_wurde_ausgelagert : BOOL // impuls
WT_auslagern_daten : UDT "WT_Daten" // edit: Wenn dies als en FC programmiert ist, muss die Daten bei "WT_wurde_ausgelagert" in eine weitere Zwischenablage kopiert werden. 
// Dies weil wenn die OUT Daten nur beim "WT_wurde_ausgelagert" aktualisert werden, sind die Daten bei den nächste Durchlauft nicht definiert. 
// Diese verhalten gibt es nicht bei ein FB.
 
Zuletzt bearbeitet:
Folgender Entwurf (ungetestet!) verwaltet nur die 11 Plätze.
Für ein schlüssigeres Konzept fehlen mir nähere Angaben.
Etliches muss noch "drumherum" geregelt werden, siehe auch Kommentar am CodeEnde.
Code:
VAR_IN_OUT
    iobNewWPCwaiting : BOOL ; // neuer WT wartet auf Einlagern
    ioScr :             INT ; // ZielPlatzNr
    ioDst :             INT ; // QuellPlatzNr
END_VAR
VAR_OUTPUT
    outFirstEnabSpc :   INT ;
END_VAR
VAR_TEMP
    idx :               INT ;
END_VAR
VAR_STATIC
    statFirstFreeSpc :  INT ; 
    statNextOccupSpc :  INT ; 
    statFirstEnabSpc :  INT ;
END_VAR

if ioScr = 0 and ioDst = 0 then  // wenn TransportAuftrag abgearbeitet, dann ...
    statFirstFreeSpc := 0 ; // Nr des ersten nicht belegten und nicht gesperrten Platzes
    statNextOccupSpc := 0 ; // Nr des nächsten belegten und nicht gesperrten Platzes
    statFirstEnabSpc := 0 ; // Nr des ersten nicht gesperrten Platzes
    for idx := 1 to 11 do
        if aSpace[idx].bInhib Then // wenn aktueller Platz gesperrt, dann nichts tun
        elsif aSpace[idx].bOccup then // wenn aktueller Platz belegt, dann ...
            if statFirstFreeSpc > 0 and statNextOccupSpc = 0 then statNextOccupSpc := idx ; end_if ;
            if statFirstEnabSpc = 0 then statFirstEnabSpc := idx ; end_if ;
        else // wenn aktueller Platz frei, dann ...
            if statFirstFreeSpc = 0 then statFirstFreeSpc := idx ; end_if ; 
            if statFirstEnabSpc = 0 then statFirstEnabSpc := idx ; end_if ; 
        end_if ;
    end_for ;
    if aSpace[statFirstEnabSpc].bDone then // wenn WerkStück auf erstem ungesperrten Platz fertig ist
        ioScr := statFirstEnabSpc ; // WT auslagern
    elsif statNextOccupSpc > statFirstFreeSpc then // wenn WerkStück aufrücken kann
        ioScr := statNextOccupSpc ; // WT verschieben
        ioDst := statFirstFreeSpc ;
    elsif statFirstFreeSpc > 0 and iobNewWPCwaiting then // wenn neues WerkStück auf Einlagerung wartet
        ioDst := statFirstFreeSpc ; // WT einlagern
        iobNewWPCwaiting := false ;
    end_if ;
end_if ;
outFirstEnabSpc := statFirstEnabSpc ;

// Die obige Routine schreibt den TransportAuftrag nach 'ioScr' und 'ioDst'.
//    'ioScr'<>0 und 'ioDst'=0  : Auslagern von PlatzNr laut 'ioScr' 
//    'ioScr'<>0 und 'ioDst'<>0 : Verschieben von PlatzNr laut 'ioScr' nach PlatzNr laut 'ioDst'
//    'ioScr'=0  und 'ioDst'<>0 : Einlagern nach PlatzNr laut 'ioDst'  
// Der TransportAuftrag muss anderweitig ausgeführt und wenn er beendet ist, 
//     müssen 'ioScr' und 'ioDst' gelöscht werden. 
// Es werden hier nur die Plätze verwaltet - unabhängig davon, welcher WT sich wo befindet. 
// Die Information, wann ein WT auf Platz laut 'outFirstEnabSpc' fertig ist, muss anderweitig 
//     in 'aSpace[outFirstEnabSpc][B].bDone[/B]' aktualisiert werden. 
// Die BelegtBits 'aSpace[1..11][B].bOccup[/B]' müssen anderweitig mit den SensorMeldungen aktualisiert werden. 
// Die GesperrtBits 'aSpace[1..11][B].bInhib[/B]' werden über die Visu eingegeben.
// 'iobNewWPCwaiting' wird anderweitig gesetzt, wenn ein WT zum Einlagern bereitgestellt wird und
//     von dieser Routine rückgesetzt, wenn der EinlagerAuftrag ausgegeben wird.
 
Servus!

ich hab die lösung gefunden!
mehr dazu heut Abend! (hab jetzt grad keine Zeit :grin:)
Danke vorab!!

mfg W@stl
 
Zuviel Werbung?
-> Hier kostenlos registrieren
n´Abend allerseits!

jetzt hab ich Zeit für den 2. Teil der Antwort.:ROFLMAO:

für das Verschieben der Daten habe ich 2 FOR-Schleifen erstellt, wie schon im 2. Post geschrieben.
(das speichern des neuen WT auf den Letzten freien Platz, und das löschen des 1. fertigen WT lasse ich jetzt hier weg.)


eine Schleife zählt von 1 bis 11, um den ersten Freien Platz zu suchen. -->temporär
und die andere Schleife zählt von <Variable> bis 11, um den ersten belegten Platz zu suchen -->statisch

mit diesen 2 Variablen kann ich jetzt den belegten Platz auf den freien Platz kopieren (und den kopierten dann löschen)
nach dem Kopieren erhöhe ich die Variable für den belegen Platz und die zusätzliche Variable (für den Anfangswert der Schleife) um 1.

so 'scanne' ich in den weiteren durchläufen nicht die kompletten 11 Plätze ab, sondern erst wieder ab dem letzten kopierten Platz.
und kann so den nächsten Platz auf den frei gewordenen Platz kopieren.
also ähnlich wie Heinileini schon geschrieben hatte.
den Quellplatz auf den Zielplatz kopieren, der vorher gespeichert wurde.

Danke! an dieser Stelle! das war quasi der Gedanke, der mir gefehlt hatte...:s12:

danach vergleiche ich noch den ersten Freien mit dem letzten belegtem Platz, obs noch was zum kopieren gibt,
ansonsten lösche ich die 2 Variablen, dass ich für das nächste kopieren schon vorbereitet bin.

und für die Paar Zeilen Code hab ich mir viel zu lange Gedanken gemacht :sm11:
ich hoffe es bewährt sich dann auch in der Praxis an der Anlage...

Schönen Abend noch! und Danke noch mal!
MfG W@stl :s11:
 
Nachschlag zu meinem Entwurf aus #7 (zus. Kommentare zur Wirkungsweise):
Code:
// Das Scannen (For-Schleife) und die AuftragsBildung pausieren, bis ein Auftrag zu Ende ausgeführt ist.
// Beim ScanVorgang werden alle 11 Plätze ausgewertet - vorzeitiges Abbrechen der Schleife wäre möglich, 
// allerdings mit zusätzlichen Aufwand und mit fraglichem Vorteil.
// Das Scannen beginnt immer mit Platz 1, also unabhängig von der Vorgeschichte, sprich unabhängig vom 
// zuletzt ausgeführten TransportAuftrag. Aktuelle Änderungen im SperrZustand der Plätze werden dadurch
// unverzüglich wirksam. 
// Unklar ist, welche Strategie gewünscht ist bei belegten Plätzen, die gleichzeitig gesperrt sind, daher 
// werden gesperrte Plätze konsequent ignoriert. AuslagerAufträge sind für solche Plätze nicht vorgesehen.
// Das Auslagern eines fertigen WT ist "im Prinzip" von allen 11 Plätzen möglich, jedoch nur vom ersten 
// ungesperrten Platz (d.h., wenn die Plätze 1..10 gesperrt sind, kann sogar vom ungesperrten Platz 11
// ausgelagert werden). Die Routine ist funktionsfähig, sobald bzw. solange mindestens einer der 11 Plätze 
// ungesperrt ist.
// Nach einem kompletten Scan aller 11 Plätze sind alle nötigen Informationen gesammelt, ggfs den nächsten 
// TransportAuftrag (theoretisch bis zu drei TransportAufträge) zu generieren.
// Ein möglicher AuslagerAuftrag hat die höchste Priorität ("zuerst Platz schaffen") und ein möglicher 
// EinlagerAuftrag hat die geringste Priorität ("aufräumen geht vor einlagern"). 
// D.h. die VerschiebeAufträge haben die mittlere Priorität.
// Dadurch wird ein WT direkt auf den ersten freien Platz eingelagert (und nicht zuerst auf dem letzten 
// freien Platz zwischengelagert).
// Sobald ein TransportAuftrag als durchgeführt gemeldet wird, wird erneut gescannt. 
// TransportAufträge, die sich aus dem vorherigen ScanVorgang evtl. noch hätten bilden lassen, werden ver-
// worfen. Dadurch bezieht sich der nächste TransportAuftrag immer auf die aktuell vorgefundene Situation.
// Wird ein Platz frei, sodass ein WT von einem Platz mit einer grösseren Nr aufrücken kann, so wird der 
// WT vom nächstliegenden belegten, aber nicht gesperrten Platz aufgerückt. 
// Dies kann eine Lawine von VerschiebeAufträgen auslösen (1<-2, 2<-3, u.s.w. 9<-10, 10<-11), aber so ist
// gewährleistet, dass kein WT in der Warteschlange hängenbleibt, während er von Neuzugängen überholt wird.
 
Zurück
Oben