TIA Suche nach Bool = TRUE in UDT

DCDCDC

Level-3
Beiträge
3.741
Reaktionspunkte
1.069
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo zusammen..

Ich habe eine Schleife zum Überprüfen ob die Position des Einfachpositionierers valide ist für alle Datensätze

UDT:
Code:
Position    Real    0.0        True    True    True    False    mm
Velocity    Real    0.0        True    True    True    False    mm/s
AccDcc        Real    0.0        True    True    True    False    mm/s²
ToPosition    Bool    false    True    True    True    False   
InPosition    Bool    false    True    True    True    False

Schleife:
Code:
IF #Igus.Out.Referenced THEN
    FOR #j := 0 TO "AXIS_POS_MAX" BY 1 DO
        "FC_AxisInPosition"(ActualPosition := #Control.ActualPosition,
                            Position := #PositionData[#j].Position,
                            ToleranceWindow := #AXIS_TOLERANCE,
                            InPosition => #PositionData[#j].InPosition);
    END_FOR;
END_IF;

Jetzt würde ich gerne für ein Gesamtfertig ein Bit basteln (Rückmeldung vom Controller das Fertig/InPos und Rückmeldung von FC_AxisInPosition). Wie "suche" ich jetzt am besten nach dem InPosition in der UDT?

Wenn ich #PositionData[#j].InPosition nehme, klappt's nicht, weil es immer false ausgewertet wird. Die Schleife funktioniert auch so weit, wenn nicht mehr in Position dann falls, auch beim Überfahren anderer Positionswerte wird nichts Pseudo-True.. also ist immer nur ein InPosition der ganzen Struktur True.

Ideen?

Danke!
 
Sorry - ich verstehe das gerade nicht - ich komme mit deiner Erklärung für mich nicht klar.
Vielleicht versuchst du es mit deiner Beschreibung und der zugehörigen Frage noch einmal ...
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Falls ich Dich richtig verstehe:

Im FC_AxisInPosition müsstest Du als INOUT InPosition setzen, wenn die Position passt.
Also im FC hinzufügen
Code:
IF (Positionsabfrage+-Toleranz) then
  InPosition:=TRUE;
END_IF;
Vor der Schleife aber InPosition:=FALSE zum initialisieren einmal setzen.

Somit würde während des Durchgangs an jedem der #j-Indexe die Position abgefragt und bei einer InPosition gesetzt. Wichtig ist die IF-Abfrage
und kein
InPosition:=(Positionsabfrage+-Toleranz);
da dies sowohl TRUE als auch FALSE liefert und nur der letzte Schleifendurchgang das Ergebnis liefern wird.
 
FC_AxisInPosition sieht von innen so aus:
Code:
#InPosition := 0;
IF ((#ActualPosition <= #Position + #ToleranceWindow) AND (#ActualPosition >= #Position - #ToleranceWindow)) THEN
    #InPosition := 1;
END_IF;

Ich möchte einfach nur das jeweilige InPosition des Positionsdatensatzes (Array of UDT) mit dem Fertigsignal des Controller Bausteins ver-und-en. Gerne als Schleife oder andere Funktion.. damit's dynamisch bleibt falls sich was an der Anzahl der Positionsdatensätze ändert (Array[0.."AXIS_POS_MAX"] of "UDT_AxisPosData")

Die Funktion tut auch das was sie soll, mir gehts um die Weiterverarbeitung des InPosition Signals. Da würde ich einfach gerne ein Sammelbit kreieren was auf das InPosition aller UDT's im Array schaut.
 
Wenn ich #PositionData[#j].InPosition nehme, klappt's nicht, weil es immer false ausgewertet wird. Die Schleife funktioniert auch so weit, wenn nicht mehr in Position dann falls, auch beim Überfahren anderer Positionswerte wird nichts Pseudo-True.. also ist immer nur ein InPosition der ganzen Struktur True.
Hähh??? :unsure:

Willst Du auswerten, ob alle #PositionData[#j].InPosition TRUE sind, oder mindestens eine, oder genau eine, oder keine?
Oder willst Du wissen, bei welchem #j das #PositionData[#j].InPosition TRUE ist? Das erste was gefunden wird?

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hähh??? :unsure:

Willst Du auswerten, ob alle #PositionData[#j].InPosition TRUE sind, oder mindestens eine, oder genau eine, oder keine?
Oder willst Du wissen, bei welchem #j das #PositionData[#j].InPosition TRUE ist? Das erste was gefunden wird?

Harald
Genau das eine welches gerade True ist, falls es eins gibt.
 
Ich hab auch so einen ähnlichen Baustein (denke ich). Ich hab für EPOS Anwendungen standardmäßig 32 Positionen vorgesehen die als Array of Bool „PositionErreicht“ ausgegeben werden. Im Ablauf sage ich dem Antrieb nur „Sollposition := KonstanteGrundstellung“ und warte auf „PositionErreicht[KonstanteGrundstellung]“. Ist das dein Ziel?
 
Ich hab auch so einen ähnlichen Baustein (denke ich). Ich hab für EPOS Anwendungen standardmäßig 32 Positionen vorgesehen die als Array of Bool „PositionErreicht“ ausgegeben werden. Im Ablauf sage ich dem Antrieb nur „Sollposition := KonstanteGrundstellung“ und warte auf „PositionErreicht[KonstanteGrundstellung]“. Ist das dein Ziel?
So ähnlich aber ja, ich hab ein übergeordnetes Start/Done Signal in einer anderen Struktur, die ich für die verschiedenen Bedienmöglichkeiten hernehme (Hand/Auto), Hab auch noch ein ToPosition-Signal im Datensatz.. möchte im Endeffekt in der Sequenz nur mein ToPosition Signal setzen müssen und dann auf das Gesamtfertig warten.. der Rest passiert in der Funktion. Quasi nur den sichtbaren Handshake in der Sequenz haben.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Bei mir hat sich gezeigt dass es sich auszahlt ein „Fahrauftrag fertig und in Position“ und „In Position“ getrennt zu haben. Das erste für den Ablauf, das zweite für Verriegelung usw. Das zweite „In Position“ hast du ja schon fertig. Du musst nur alle PositionOk Signale nach „außen bringen“ und dann im Array per aussagekräftiger Konstante abfragen. Also zB „PositionErreicht[KonstanteStation1]“.

Wenn du kein PositionOk vom Antrieb selbst erhältst löscht du das zweite Array „PositionErreicht“ einfach vollständig ab.
 
Hi,
Bin mir nicht sicher ob ich dein Problem richtig verstehe...
Der Code unten macht eigendlich genau das was du oben schreibst. Vielleicht etwas aufgeräumter.

Bei der For-Schleife kann man sich das "By" sparen wenn die Schrittweite 1 ist. (Der Programmierer ist halt faul.)
Für einen Einzeiler würde ich keinen Baustein anlegen und aufrufen braucht nur Speicher ist unübersichlich und langsamer. Besonders in Schleifen.
"IF ... Then" braucht du nicht, da das Berechnungsergebnis direkt zugewiesen werden kann.
Zur Berechnung: Es wird der Betrag des Abstandes zwischen Ist und Soll ermittelt. Ist dieser kleiner dem Toleranzfensters dann ist das Ergebnis true, sonnst false.
Einzige Ergänzung das Sammelbit.

Code:
IF #Igus.Out.Referenced THEN
    Sammelbit := FALSE;
    FOR #j := 0 TO "AXIS_POS_MAX" DO
        #PositionData[#j].InPosition := ABS(#Control.ActualPosition - #PositionData[#j].Position) <= #AXIS_TOLERANCE:
        IF #PositionData[#j].InPosition THEN
            Sammelbit := TRUE;
        END_IF;
    END_FOR;
END_IF;
 
Persönlich gehe ich dies anders an:
Für jeden Positionierbefehl habe ich einen Datensatz in einem Array.
Die Positionierung erfolgt wenn auf ein "Go_Pos" der jeweilige Indexwert geschrieben wird.
z.B.: Go_Pos := 5 startet die Positionierung mit dem Datensatz 5 .
Üblicher Weise lege ich Konstanten für diese Verfahrsätze an, ist übersichtlicher "Go_Pos := Grundstellung" .
Ist die Positionierung fertig wird in eine zweite Variable "In_Pos" der Wert von "Go_Pos" kopiert.

Das verhindert auch lang laufende Forschleifen in jedem Zyklus.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Genau das eine welches gerade True ist, falls es eins gibt.
Für Gesamtfertig ein #AxisInAnyPosition basteln und die Position, wo .InPosition TRUE ist:
Code:
#temp_AxisInAnyPosition := FALSE;
#temp_whichPosition := 0; //oder irgendeinen "unmöglichen" Wert

FOR #j := 0 TO "AXIS_POS_MAX" BY 1 DO
    "FC_AxisInPosition"(ActualPosition := #Control.ActualPosition,
                        Position := #PositionData[#j].Position,
                        ToleranceWindow := #AXIS_TOLERANCE,
                        InPosition => #PositionData[#j].InPosition);

    IF #PositionData[#j].InPosition THEN // (*)
        #temp_AxisInAnyPosition := TRUE;
        #temp_whichPosition := #j; //merken, bei welcher Position .InPosition TRUE ist
        EXIT; //falls die Suche beim ersten gefundenen TRUE abgebrochen werden kann
    END_IF;
END_FOR;

#AxisInAnyPosition := #temp_AxisInAnyPosition;
#whichPosition := #temp_whichPosition;

(*) Falls in der Schleife der "FC_AxisInPosition" immer für alle Positionen aufgerufen werden muß, aber nur von der ersten (niedrigsten) gefundenen Position das #j gemerkt werden soll, dann:
Code:
    IF #PositionData[#j].InPosition AND NOT #temp_AxisInAnyPosition THEN


FC_AxisInPosition sieht von innen so aus:
Code:
#InPosition := 0;
IF ((#ActualPosition <= #Position + #ToleranceWindow) AND (#ActualPosition >= #Position - #ToleranceWindow)) THEN
    #InPosition := 1;
END_IF;
#InPosition ist Bool? Dann schreib nicht solch ein Logik-Desaster, sondern einfach:
Code:
#InPosition := (#ActualPosition <= #Position + #ToleranceWindow) AND (#ActualPosition >= #Position - #ToleranceWindow);
Oder formuliere die Logik in FUP/KOP, wenn Du es in SCL nicht kannst. ;)

Harald
 
Du musst nur alle PositionOk Signale nach „außen bringen“ und dann im Array per aussagekräftiger Konstante abfragen. Also zB „PositionErreicht[KonstanteStation1]“.
Sieht man durch den Code nicht, hab ich aber schon.. mache ich über InOut.. weil ich faul bin hab ich für alle drei Achsen den gleichen FB (natürlich eindeutige Istanz DBs bevor wieder jemand Schnappatmung bekommt).

Bei der For-Schleife kann man sich das "By" sparen wenn die Schrittweite 1 ist. (Der Programmierer ist halt faul.)
Dass ich's nicht brauch weiß ich.. mach ich nur aus einer Angewöhnung raus.

#InPosition ist Bool? Dann schreib nicht solch ein Logik-Desaster, sondern einfach:
Ja.. weiß ich auch dass es so geht, wende ich aber viel zu selten an.. die Variante wie bei mir ist einfach so tief in meinem Kopf abgespeichert.
Hab's auch abgeändert.

Oder formuliere die Logik in FUP/KOP, wenn Du es in SCL nicht kannst. ;)
Solche Kommentare brauch es wirklich nicht und sind einfach nur toxisch.

So geht's jetzt:
Code:
#InPosition := 0;
IF #Igus.Out.Referenced THEN
    FOR #j := 0 TO "AXIS_POS_MAX" BY 1 DO
        #PositionData[#j].InPosition := 0;
        #PositionData[#j].InPosition := (#Igus.PositionData.ActualPosition <= #PositionData[#j].Position + #AXIS_TOLERANCE) AND (#Igus.PositionData.ActualPosition >= #PositionData[#j].Position - #AXIS_TOLERANCE);
        IF #PositionData[#j].InPosition THEN
            #InPosition := 1;
        END_IF;
    END_FOR;
END_IF;

Mit
Code:
#PositionData[#j].InPosition := ABS(#Control.ActualPosition - #PositionData[#j].Position) <= #AXIS_TOLERANCE:
ging's nicht, da war bei mehr als einer Position das InPosition TRUE

Danke euch!
 
Mit
Code:
#PositionData[#j].InPosition := ABS(#Control.ActualPosition - #PositionData[#j].Position) <= #AXIS_TOLERANCE:
ging's nicht, da war bei mehr als einer Position das InPosition TRUE
das ist ja auch nicht dasselbe wie in deinem Code-Schnipsel der läuft - das müßte dann ja so heißen :
Code:
#PositionData[#j].InPosition := abs(#Igus.PositionData.ActualPosition - #PositionData[#j].Position) <= #AXIS_TOLERANCE ;

allerdings hast du hier noch einen Fehler drin :
Code:
IF #Igus.Out.Referenced THEN
    FOR #j := 0 TO "AXIS_POS_MAX" BY 1 DO
        #PositionData[#j].InPosition := 0;  // diese Zeile ist über
        #PositionData[#j].InPosition := (#Igus.PositionData.ActualPosition <= #PositionData[#j].Position + #AXIS_TOLERANCE) AND (#Igus.PositionData.ActualPosition >= #PositionData[#j].Position - #AXIS_TOLERANCE);
        IF #PositionData[#j].InPosition THEN  // diese Zeile sollte besser anders sein
            #InPosition := 1;
        END_IF;
        // nämlich :
         #InPosition := #PositionData[#j].InPosition ;
    END_FOR;
END_IF;
 
Zuviel Werbung?
-> Hier kostenlos registrieren
allerdings hast du hier noch einen Fehler drin :
Code:
[...]
[QUOTE="Larry Laffer, post: 887181, member: 6250"]

IF #PositionData[#j].InPosition THEN // diese Zeile sollte besser anders sein
#InPosition := 1;
END_IF;
// nämlich :
#InPosition := #PositionData[#j].InPosition ;
[/QUOTE]
[...]
[QUOTE="Larry Laffer, post: 887181, member: 6250"]
Die IF-Abfrage ist schon richtig, sie ist doch für das Sammelbit, das hier #InPosition heißt.

Sollte er wirklich diese Änderung umsetzen, so würde in jedem Schleifendurchlauf entweder FALSE oder TRUE geschrieben wodurch nur der letzte Schleifendurchlauf entscheidet ob FALSE oder TRUE eingetragen wird, bei der IF-Abfrage jedoch nur wenn TRUE ist und daher würde irgendein TRUE stehen bleiben.
 
Genau das eine welches gerade True ist, falls es eins gibt.
Du erwartest in Wirklichkeit zwei Ergebnisse:
- Ja, es ist mindestens 1 passende Position im Array enthalten und
- Falls ja, dann die IndexNr, auf welchem Platz im Array selbiges gefunden wurde.
Da würde ich einfach gerne ein Sammelbit kreieren was auf das InPosition aller UDT's im Array schaut.
Hier schreibst Du aber, dass Du nur 1 Ergebnis haben willst in Form eines Sammelbits.
Ich würde eher die gefundene IndexNr als Ergebnis liefern. Daraus kann man dann immer noch ableiten, ob überhaupt irgendwo im Array etwas passendes gefunden wurde.

Irgendwo hast Du geschrieben, dass nur bei maximal 1 Index ein passendes TRUE gefunden werden kann.
Damit hast Du zwei Möglichkeiten:
1. Du kannst die Suche abbrechen, sobald Du bei einem der Einträge das TRUE findest und verlässt Dich dann darauf, dass keine weiteren TRUE kommen können.
2. Du bist misstrauisch und suchst weiter, ob noch mindestens ein weiteres TRUE vorhanden ist, um diesen Fehler aufdecken und melden zu können.
Ich würde zu 2. neigen und auch das Ergebnis der FehlerErkennung als IndexNr übergeben.
Bei 2. würde ich die Suche beim Auffinden des zweiten TRUE abbrechen. Durch wiederholtes Abragen mit ggfs Reparatur der fehlerhaften Position kann man dann evtl. vorhandene weitere Fehler noch aufspüren.
 
Irgendwo hast Du geschrieben, dass nur bei maximal 1 Index ein passendes TRUE gefunden werden kann.
Damit hast Du zwei Möglichkeiten:
1. Du kannst die Suche abbrechen, sobald Du bei einem der Einträge das TRUE findest und verlässt Dich dann darauf, dass keine weiteren TRUE kommen können.
Werde ich denke ich so machen, gestern noch mal getestet. Erst kommt das Fertig vom Controller, dann wird das Sammelbit false und sobald die Position in der Toleranz ist, wird das Sammelbit wieder TRUE, dann knall ich da noch ein EXIT hin, dann muss die Schleife nicht unnötig durchrudern
 
Zuviel Werbung?
-> Hier kostenlos registrieren
#InPosition ist Bool? Dann schreib nicht solch ein Logik-Desaster, sondern einfach:
Ja.. weiß ich auch dass es so geht, wende ich aber viel zu selten an.. die Variante wie bei mir ist einfach so tief in meinem Kopf abgespeichert.
Hab's auch abgeändert.

Oder formuliere die Logik in FUP/KOP, wenn Du es in SCL nicht kannst. ;)
Solche Kommentare brauch es wirklich nicht und sind einfach nur toxisch.
Tja, das weiß ich ja nicht, daß Du es eigentlich richtig kannst, aber absichtlich falsch programmierst.

Die Mehrfachzuweisung an Variablen ist nicht nur umständlich, sondern auch ein Programmierfehler, wenn man das mit Variablen macht, auf die von außen zugegriffen wird. Wenn z.B. ein HMI auf #InPosition zugreift und anzeigt, dann wird die Anzeige am HMI flackern, sprich: zeitweilig auch den falschen Wert 0 anzeigen.

Wenn überhaupt, dann darf man dieses "ich initialisiere erstmal mit 0 und schreibe später nochmal das richtige Ergebnis rein" nur mit internen Variablen machen, auf die nicht von außen zugegriffen werden kann oder garantiert nicht zugegriffen wird.

In Deinem Fall ist #InPosition sogar ein FC-Output. Merke: mache niemals Mehrfachzuweisungen oder nur bedingte Zuweisungen an Outputs! Wenn der Output per Referenz übergeben wird, dann ändert sich bei der Zuweisung die außen angeschlossene Variable. Das wird lustig bei Multitasking... Wenn das TIA konsequent und konsistent wäre, müßte es eigentlich auch die nur bedingten Zuweisungen an den Output anmeckern...


So geht's jetzt:
Code:
#InPosition := 0;
IF #Igus.Out.Referenced THEN
    FOR #j := 0 TO "AXIS_POS_MAX" BY 1 DO
        #PositionData[#j].InPosition := 0;
        #PositionData[#j].InPosition := (#Igus.PositionData.ActualPosition <= #PositionData[#j].Position + #AXIS_TOLERANCE) AND (#Igus.PositionData.ActualPosition >= #PositionData[#j].Position - #AXIS_TOLERANCE);
        IF #PositionData[#j].InPosition THEN
            #InPosition := 1;
        END_IF;
    END_FOR;
END_IF;
Das ist auch wieder der selbe Mist mit einer Output-Variable.

#InPosition := 0; Mehrfachzuweisung an Output
IF #Igus.Out.Referenced THEN
FOR #j := 0 TO "AXIS_POS_MAX" BY 1 DO
#PositionData[#j].InPosition := 0; völlig sinnfrei
#PositionData[#j].InPosition := (#Igus.PositionData.ActualPosition ... );
IF #PositionData[#j].InPosition THEN
#InPosition := 1; Mehrfachzuweisung an Output
END_IF;
END_FOR;
END_IF;

Im übrigen sollte man bei Zuweisungen an Bool-Variablen TRUE und FALSE verwenden, auch wenn das TIA die Verwendung von 1 und 0 für schlampige Programmierer so durchgehen läßt...

Harald
 
Das war a
Tja, das weiß ich ja nicht, daß Du es eigentlich richtig kannst, aber absichtlich falsch programmierst.

Die Mehrfachzuweisung an Variablen ist nicht nur umständlich, sondern auch ein Programmierfehler, wenn man das mit Variablen macht, auf die von außen zugegriffen wird. Wenn z.B. ein HMI auf #InPosition zugreift und anzeigt, dann wird die Anzeige am HMI flackern, sprich: zeitweilig auch den falschen Wert 0 anzeigen.

Wenn überhaupt, dann darf man dieses "ich initialisiere erstmal mit 0 und schreibe später nochmal das richtige Ergebnis rein" nur mit internen Variablen machen, auf die nicht von außen zugegriffen werden kann oder garantiert nicht zugegriffen wird.

In Deinem Fall ist #InPosition sogar ein FC-Output. Merke: mache niemals Mehrfachzuweisungen oder nur bedingte Zuweisungen an Outputs! Wenn der Output per Referenz übergeben wird, dann ändert sich bei der Zuweisung die außen angeschlossene Variable. Das wird lustig bei Multitasking... Wenn das TIA konsequent und konsistent wäre, müßte es eigentlich auch die nur bedingten Zuweisungen an den Output anmeckern...



Das ist auch wieder der selbe Mist mit einer Output-Variable.

#InPosition := 0; Mehrfachzuweisung an Output
IF #Igus.Out.Referenced THEN
FOR #j := 0 TO "AXIS_POS_MAX" BY 1 DO
#PositionData[#j].InPosition := 0; völlig sinnfrei
#PositionData[#j].InPosition := (#Igus.PositionData.ActualPosition ... );
IF #PositionData[#j].InPosition THEN
#InPosition := 1; Mehrfachzuweisung an Output
END_IF;
END_FOR;
END_IF;

Im übrigen sollte man bei Zuweisungen an Bool-Variablen TRUE und FALSE verwenden, auch wenn das TIA die Verwendung von 1 und 0 für schlampige Programmierer so durchgehen läßt...

Harald

Das war ne allgemeine Aussage, solche Kommentare helfen niemandem, außer dem Ego der Person, der sie äußert. (Hab auch einfach in dem ein oder anderen Projekt schlechte Erfahrungen mit Programmierern gemacht, die der Meinung waren allwissen und Alleskönner zu sein. Was niemand von uns ist.

Hab jetzt die Mehrfachzuweisungen entfernt.

Danke!
 
Zurück
Oben