Zuviel Werbung? - > Hier kostenlos beim SPS-Forum registrieren

Seite 6 von 12 ErsteErste ... 45678 ... LetzteLetzte
Ergebnis 51 bis 60 von 117

Thema: Programmierwettbewerb, 5. Aufgabe - Inkrementalgeber Korrektur

  1. #51
    Registriert seit
    06.10.2003
    Beiträge
    3.448
    Danke
    454
    Erhielt 509 Danke für 411 Beiträge

    Standard


    Zuviel Werbung?
    -> Hier kostenlos registrieren
    Hier ist meine Lösung in Step7-SCL. Ich wollte eigentlich noch eine kleine Testumgebung in Flexible mitliefern. Diese ist jedoch noch nicht so ganz publikumsreif.

    Code:
    (************************************************************************************************************************)
    {SetOKFlag := 'y' ; OptimizeObjectCode := 'y'}
    (************************************************************************************************************************)
    FUNCTION_BLOCK "ABS_WERTGEBER_GETRIEBE_2"
    TITLE = '' 
    (************************************************************************************************************************)
    // Beschreibung
    // ¯¯¯¯¯¯¯¯¯¯¯¯
    // Erfasst wird die Änderung "dX" des Eingangswertes "X" seit der letzten Abtastung. Hierzu ist es zunächst notwendig,
    // den positiven und den negativen Überlauf zu erfassen. Aus den ermittelten Änderungen "dX" wird eine Summe für den
    // Ausgangswert "iY" gebildet. Der Bereich für diesen Ausgangswert ergibt sich aus dem Eingangsbereich "RANGE" und dem
    // Übersetzungsverhältnis "A:B". Bei RANGE=2^16=65536 und A:B=1:2 ergibt sich z.Bsp. ein Bereich
    // Y_BEREICH=65536*A/B=32768. Bei einer Umdrehung des Eingangs ergeben sich bei diesem Beispiel zwei Umdrehungen am Ausgang.
    // Nahezu beliebige Übersetzungsverhältnisse sind möglich, z.Bsp. auch 1000:1001. An der ermittelten Summe "iY" werden
    // ebenfalls der positive und negative Überlauf, bezogen auf "Y_BEREICH" berücksichtigt. Um einen Incrementalgeber mit
    // dem selben "RANGE" des Eingangs zu emulieren, wird "iY" am Ende ganz einfach auf "RANGE" normiert (Y2). Bei dem
    // genannten Beispiel enstehen am Ausgang "Y2" zwei Umdrehungen von 0..65535 bei einer Umdrehung am Eingang. Da kein
    // Increment des Eingangssignals verloren geht, wird eine höchst mögliche Genauigkeit umgesetzt.
    //
    // Einschränkungen
    // ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
    // Zur Erfassung eines Überlaufs am Eingang muss das Eingangssignal mindestens mehr als 2x je Umdrehung abgefragt werden.
    // Normalerweisekein Problem.
    // Bei ungünstigen Parametern kann es zu einem Berechnungsfehler kommen. In diesem Fall wird der Ausgang "ERROR" gesetzt.
    // Mit dem "RESET" wird der Ausgang "ERROR" zurückgesetzt.
    //
    
    VAR_INPUT
      X                         : WORD;                         // aktueller Wert vom Incrementalgeber, z.Bsp. 0..65535
      RANGE                     : DINT := 65536;                // Nennbereich, Anzahl Incremente, z.Bsp. 2^16=65536
      A                         : DINT := 1;                    // Übersetzungsverhältnis (A:B)
      B                         : DINT := 1;                    // Übersetzungsverhältnis (A:B)
      RESET                     : BOOL := false;                // Setzt den Ausgangswert auf den Eingangswert
    END_VAR
    
    VAR_OUTPUT
      Y1                        : DINT;                         // Ausgangswert, Bereich je nach Übersetzung
      Y2                        : DINT;                         // Ausgangswert, normiert auf "RANGE", z.Bsp. 2^16=65536
      ERROR                     : BOOL;                         // interner Fehler, Parameter überdenken
    END_VAR
    
    VAR
      aX                        : DINT;                         // Eingangswertes vom letzem Zyklus
      dX                        : DINT;                         // Änderung des Eingangswertes seit letzem Zyklus
      iX                        : DINT;                         // Eingangswert, als DINT
      iY                        : DINT;                         // Ausgangswert, Bereich je nach Übersetzung
      FLM_RESET                 : BOOL;                         // Flankenmerker
    END_VAR
    
    VAR_TEMP
      Y_BEREICH                 : DINT;                         // interner, korrigierter Bereich
    END_VAR
    
    
    BEGIN
    
       // Parameter umwandeln
       iX := WORD_TO_DINT(X);
    
       // Reset
       IF RESET AND NOT FLM_RESET THEN
          aX := iX;
          iY := iX * A DIV B;
          ERROR := false;
       END_IF;
       FLM_RESET := RESET;
    
       // Ausgangs-Bereich je nach Übersetzung
       Y_BEREICH := RANGE * A DIV B;
    
       // Änderung des Eingangswertes seit letzem Zyklus
       dX := iX - aX;
       aX := iX;
    
       // Eingang positiver Überlauf
       IF dX < -(RANGE DIV 2) THEN
          dX := dX + RANGE;
    
       // Eingang negativer Überlauf
       ELSIF dX >= (RANGE DIV 2) THEN
          dX := dX - RANGE;
       END_IF;
    
       // Ausgangswert, Bereich je nach Übersetzung
       iY := iY + dX;
    
       // Ausgang positiver Überlauf
       IF iY >= Y_BEREICH THEN
          iY := iY - Y_BEREICH;
       END_IF;
    
       // Ausgang negativer Überlauf
       IF iY < 0 THEN
          iY := iY + Y_BEREICH;
       END_IF;
    
       // Ausgabe
       Y1 := iY;
       Y2 := TRUNC(DINT_TO_REAL(iY) * RANGE / Y_BEREICH);
    
       // bei Berechnungsfehler, enstsprechende Ausgaben
       IF NOT OK THEN
          Y1 := 0;
          Y2 := 0;
          ERROR := true;
       END_IF;
    
    
    END_FUNCTION_BLOCK
    Gruß, Onkel
    Es gibt viel mehr Leute, die freiwillig aufgeben, als solche, die echt scheitern.
    Henry Ford

  2. #52
    Registriert seit
    19.01.2010
    Ort
    Graz / Austria
    Beiträge
    100
    Danke
    6
    Erhielt 10 Danke für 8 Beiträge

    Standard

    Zitat Zitat von bits'bytes Beitrag anzeigen
    Hallo, ich hätte das jetzt mal korrigiert und hoffe das passt....
    Leider nicht, gib einmal folgende Geberwerte der Reihe nach ein:
    20000, 40000, 60000, 50
    Dann kommt nach dem Überlauf Sprung von 60000 auf 50 nicht 705 als korrigierter Wert wie in unserer Tabelle heraus, sondern 50.
    Siehe auch Screenshot.
    Ist mir da was beim kopieren und einfügen vom Code passiert, oder ist das bei dir auch so?


    Michi
    Angehängte Grafiken Angehängte Grafiken

  3. #53
    Registriert seit
    19.01.2010
    Ort
    Graz / Austria
    Beiträge
    100
    Danke
    6
    Erhielt 10 Danke für 8 Beiträge

    Standard

    Zitat Zitat von StructuredTrash Beitrag anzeigen
    Mit der internen Verwaltung der skalierten Position als REAL sollte es klappen.
    Ich habe es mal von 0 aus einmal ins Negative und zurück sowie bis zum zweiten Überlauf in positive Richtung getestet. Bis dahin sieht es gut aus.
    Zitat Zitat von bits'bytes Beitrag anzeigen
    Bei mir summiert sich hier eine (wahrscheinliche) Ungenauigkeit auf
    Bei einem tatsächlichem Geber Stand von 62500 (Skalierung 1.01, d.h. 100 --> 101) sollte der korrigierte Geber 63125 sein. Mit deinem Code komme ich bei mir auf 63106.
    Bei mir taucht das selbe Problem auf.
    Wenn ich ihn länger vorwärts laufen lasse und dann wieder zurück, dann kammt er nicht wieder auf seinen 0 Punkt zurück.
    Siehe auch Screenshots.
    Angehängte Grafiken Angehängte Grafiken

  4. #54
    Registriert seit
    19.01.2010
    Ort
    Graz / Austria
    Beiträge
    100
    Danke
    6
    Erhielt 10 Danke für 8 Beiträge

    Standard

    Hallo Onkel,

    schaut gut aus dein Programm und sehr schön dokumentiert.
    Allerdings habe ich nach mehreren Umdrehungen eine kleine Abweichung zwischen meinem und deinem Baustein und ich weiß im Moment noch nicht genau, welcher von beiden Bausteinen daneben liegt.

    Das "DIV" im Code habe ich durch eine normale Division ersetzt das dies bei B&R nicht erkannt wurde. Das ist hoffentlich eh nichts anderes als eine normale Division, oder? (Bin nicht so fit auf Siemens)
    "Y_BEREICH := RANGE * A DIV B;" -> "Y_BEREICH := RANGE * A / B;"

    Oder gibt es hier bei der Verhältnis Rechnung irgendwo eine Ungenauigkeit?
    Eingestellt habe ich 100:101.

    Ich werde mal meinen Code posten, eventuell findest du hier noch irgendwas warum die beiden anfangen abzuweichen. - Genug für heute, jetzt brauche ich mal wieder ein bißchen Schlaf.

    Michi
    Angehängte Grafiken Angehängte Grafiken
    Geändert von MichaelUray (05.12.2013 um 04:00 Uhr)

  5. #55
    Registriert seit
    19.01.2010
    Ort
    Graz / Austria
    Beiträge
    100
    Danke
    6
    Erhielt 10 Danke für 8 Beiträge

    Standard

    Nachdem die ersten Programmvorschläge ja schon gekommen sind, findet ihr hier den Programmcode meines Bausteins:

    Bausteindeklaration:
    Code:
    FUNCTION_BLOCK EncoderCorrection
        VAR_INPUT
            EncoderValue : UINT; (*Encoder value input*)
            CorrectAtValue : INT; (*If the encoder moves more than this value, then the output value gets corrected by CorrectByValue*)
            CorrectByValue : INT; (*The output value gets corrected by this value*)
            Reset : BOOL; (*The reset adapts the input to the corrected value*)
        END_VAR
        VAR_OUTPUT
            CorrectedValue : UINT; (*Corrected value output*)
        END_VAR
        VAR
            EncoderValueOld : UINT; (*Stores the last encoder value*)
            EncoderChangeSinceLastCorrection : INT; (*Positive / negative change since the last correction*)
        END_VAR
    END_FUNCTION_BLOCK
    Funktionsblock:
    Code:
    (*
     ********************************************************************
     * COPYRIGHT --  
     ********************************************************************
     * Library: EncHelper
     * Datei: EncoderCorrection.st
     * Autor: MichaelUray
     * Erstellt: 22. November 2013
     ********************************************************************
     * Implementierung der Library EncHelper
     ********************************************************************
     This function block corrects an input encoder value by two given
     parameters.
     If the encoder moves more than "CorrectAtValue" the encoder output
     gets corrected by "CorrectByValue".
     If the change of the encoder input is more than the half of UINT
     an overflow of the input value is assumed.
    *)
    
     
    FUNCTION_BLOCK EncoderCorrection
        (* Calculate internal encoder value by the change of the input since the last call *)
        CorrectedValue := CorrectedValue + (EncoderValue - EncoderValueOld);
        EncoderChangeSinceLastCorrection := EncoderChangeSinceLastCorrection + (EncoderValue - EncoderValueOld);
        EncoderValueOld := EncoderValue;
    
        IF Reset THEN
            (* Adapts the input encoder value to the corrected value *)
            CorrectedValue := EncoderValue;
            EncoderChangeSinceLastCorrection := 0;
        ELSE
            (* Positive change *)
            IF EncoderChangeSinceLastCorrection > 0 AND EncoderChangeSinceLastCorrection >= CorrectAtValue AND CorrectAtValue <> 0 THEN
                (* Calculate how often the correction is required and correct it with the correction factor multiplied by this value *)
                CorrectedValue := CorrectedValue + (CorrectByValue * (EncoderChangeSinceLastCorrection / CorrectAtValue));
                (* Keep the remainder of the division on the encoder change *)
                EncoderChangeSinceLastCorrection := EncoderChangeSinceLastCorrection MOD CorrectAtValue;
            END_IF
            
            (* Negative change *)
            IF EncoderChangeSinceLastCorrection < 0 AND 0-EncoderChangeSinceLastCorrection >= CorrectAtValue AND CorrectAtValue <> 0 THEN
                (* Calculate how often the correction is required and correct it with the correction factor multiplied by this value *)
                CorrectedValue := CorrectedValue - (CorrectByValue * (0-EncoderChangeSinceLastCorrection / CorrectAtValue));
                (* Keep the remainder of the division on the encoder change *)
                EncoderChangeSinceLastCorrection := EncoderChangeSinceLastCorrection MOD CorrectAtValue;
            END_IF
        END_IF
    END_FUNCTION_BLOCK

    Der Test Code (in C):

    Deklaration:
    Code:
    _LOCAL                                     plcbit                boReset;
    _LOCAL                                     plcbit                boFwd;
    _LOCAL                                     plcbit                boBwd;
    _LOCAL                 signed         short    int                    siTurnCount;
    _LOCAL                unsigned     short     int                 Encoder_M;
    
    _LOCAL                EncoderCorrection_typ                    ENC_CORR;
    Initialisierung:
    Code:
        ENC_CORR.CorrectAtValue = 100;
        ENC_CORR.CorrectByValue = 1;

    Tesprogramm (Cyclic):
    Code:
        if (boReset)
        {
            if (!Encoder) boReset = 0;
            Encoder = 0;
            Encoder_M = 0;
            siTurnCount = 0;
        }
        
        /* Turn counter */
        if (Encoder_M != Encoder)
        {
            if (Encoder > Encoder_M)
            {
                if (Encoder - Encoder_M > 32767)
                    siTurnCount--;
            }
            else
            {
                if (Encoder_M - Encoder > 32767)
                    siTurnCount++;
            }
            Encoder_M = Encoder;
        }
    
        /* Forward / Backward with randomized numbers */
        if (boFwd)                
            Encoder += 5000 + rand() % 100;
        if (boBwd)
            Encoder -= 5000 + rand() % 100;
        
        /* Funktion call */
        ENC_CORR.Reset = boReset;
        ENC_CORR.EncoderValue = Encoder;
        EncoderCorrection(&ENC_CORR);

    Michi

    PS:
    Achja, falls noch jemanden das Kennwort des ZIP Files intessiert, es lautet "Vermutungen".

  6. #56
    Registriert seit
    25.11.2010
    Ort
    OWL
    Beiträge
    757
    Danke
    27
    Erhielt 166 Danke für 144 Beiträge

    Standard

    Zitat Zitat von bits'bytes Beitrag anzeigen
    Hallo,
    habe das mal durchlaufen lassen.

    Bei mir summiert sich hier eine (wahrscheinliche) Ungenauigkeit auf
    Ja, bei kleinen Schrittweiten (<50) macht die Real-Ungenauigkeit mir auch einen Strich durch die Rechnung. Mit setScalFact und varScalReal als LREAL wird es natürlich wesentlich besser, aber eine kleine Ungenauigkeit bleibt immer (von 0 bis 62500 mit Schrittweite 1 -> varScalReal = 63125.0000000383). Wahrscheinlich wird man das in der Praxis hinnehmen können, es sei denn, der Antrieb wird nur an hohen Feiertagen referenziert.

  7. #57
    Registriert seit
    06.10.2003
    Beiträge
    3.448
    Danke
    454
    Erhielt 509 Danke für 411 Beiträge

    Standard

    Hallo Michi

    Zitat Zitat von MichaelUray Beitrag anzeigen
    ..Allerdings habe ich nach mehreren Umdrehungen eine kleine Abweichung zwischen meinem und deinem Baustein ..
    Eine Ungenauigkeit bei der Real-Berechnung könnte bei ungünstigen Werten bei mir möglich sein. Einen Fehler, welcher sich mit jeder Undrehung aufsummiert, kann ich jedoch ausschließen.


    Gruß, Onkel
    Es gibt viel mehr Leute, die freiwillig aufgeben, als solche, die echt scheitern.
    Henry Ford

  8. #58
    Registriert seit
    25.06.2008
    Ort
    Blomberg/Lippe
    Beiträge
    1.297
    Danke
    51
    Erhielt 130 Danke für 124 Beiträge

    Standard

    Ich dachte der Einsendeschluss wäre der 15.12.
    Davor sollte eigentlich nichts veröffenlich werden. Mit Wettbewerb hat das nix mehr zutun.
    Warum Ungenauigkeit und warum REAL? Man muss doch nur hoch- oder runterzählen.
    Gruß
    Mobi


    „Das Einfache kompliziert zu machen ist alltäglich. Das Komplizierte einfach zu machen –
    das ist Kreativität“ (Charles Mingus).

  9. Folgender Benutzer sagt Danke zu Mobi für den nützlichen Beitrag:

    PN/DP (05.12.2013)

  10. #59
    Registriert seit
    22.06.2009
    Ort
    Sassnitz
    Beiträge
    11.315
    Danke
    932
    Erhielt 3.329 Danke für 2.688 Beiträge

    Standard

    Zitat Zitat von Mobi Beitrag anzeigen
    Ich dachte der Einsendeschluss wäre der 15.12.
    Davor sollte eigentlich nichts veröffenlich werden. Mit Wettbewerb hat das nix mehr zutun.



    Warum Ungenauigkeit und warum REAL? Man muss doch nur hoch- oder runterzählen.


    Harald
    Es ist immer wieder überraschend, wie etwas plötzlich funktioniert, sobald man alles richtig macht.

    FAQ: Linkliste SIMATIC-Kommunikation über Ethernet

  11. #60
    Registriert seit
    05.12.2013
    Ort
    Graz / Austria
    Beiträge
    149
    Danke
    9
    Erhielt 2 Danke für 2 Beiträge

    Standard


    Zuviel Werbung?
    -> Hier kostenlos registrieren
    Hallo allerseits !

    -Was würde passieren wenn der Inkrementalwert über den Höchstwert hin und her pendelt , wie könnte man dann die Motordrehrichtung erkennen , ohne sich die letzten 2 zyklen zu merken ?

    -Könnte man die Motordrehrichtung nicht als IN -Parameter eingeben (die ist doch wilkürlich gewählt . oder )?
    ( ... könnte auch sein das ich was falsch verstehe !)

Ähnliche Themen

  1. Programmierwettbewerb, 4. Aufgabe
    Von Onkel Dagobert im Forum Stammtisch
    Antworten: 6
    Letzter Beitrag: 15.12.2011, 18:57
  2. Programmierwettbewerb, 3. Aufgabe
    Von Chräshe im Forum Stammtisch
    Antworten: 7
    Letzter Beitrag: 05.12.2011, 20:43
  3. Programmierwettbewerb, 2. Aufgabe
    Von LargoD im Forum Stammtisch
    Antworten: 14
    Letzter Beitrag: 02.08.2011, 22:27
  4. Bitte um korrektur
    Von Arnold999 im Forum Simatic
    Antworten: 34
    Letzter Beitrag: 15.06.2010, 21:21
  5. Mechanische Korrektur
    Von PG710 im Forum Simatic
    Antworten: 11
    Letzter Beitrag: 20.11.2008, 15:26

Stichworte

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •