Skip to main content

Programmatisches Anlegen von Kurvenscheiben

Ab CODESYS SoftMotion Version 4.17.0.0 gibt es mit dem Funktionsbaustein CamBuilder eine Schnittstelle zum programmatischen Anlegen von Kurvenscheiben, direkt in der IEC-Applikation.

Für weitere Informationen siehe Beispiel Kurvenscheiben programmatisch erstellen

Verwendung des Funktionsbausteins CamBuilder (ab SM 4.17.0.0)

Folgende Kurvenscheibe wird standardmäßig erzeugt, wenn ein Kurvenscheibenobjekt im Gerätebaum angelegt wird:

_sm_img_cam_diagram.png

Die Kurvenscheibe besteht aus drei Polynomen fünften Grades mit den folgenden vier Randwerten

X

Y

V

A

0

0

0

0

120

120

1

0

240

240

1

0

360

360

0

0

Um diese Kurvenscheibe programmatisch zu erzeugen, wird zunächst eine Instanz des Funktionsbausteins CamBuilder deklariert:

VAR
    camBuilder : SMCB.CamBuilder;
END_VAR

Im Implementierungsteil muss die CamBuilder-Instanz zunächst initialisiert werden. Danach können drei Segmente vom Typ Poly5 über die Methode Append angehängt werden:

camBuilder.Init();
 
camBuilder.Append(
    SMCB.Poly5(
	SMCB.BoundImplicit(),
	SMCB.Bound(120, 120, 1)));
camBuilder.Append(
    SMCB.Poly5(
	SMCB.BoundImplicit(),
	SMCB.Bound(240, 240, 1)));
camBuilder.Append(
    SMCB.Poly5(
        SMCB.BoundImplicit(),
        SMCB.Bound(360, 360)));

Die Polynome werden über die linken und rechten Randbedingungen definiert. Im Beispiel wird für den linken Rand immer die Funktion BoundImplicit verwendet. Dadurch wird die rechte Randbedingung des vorherigen Segments übernommen. Wenn für das erste Segment als linken Rand die Funktion BoundImplicit verwendet wird, wird bei Null gestartet: Im vorliegenden Beispiel mit Poly5-Segment bei (X, Y, V, A) = (0, 0, 0, 0).

Zur Verwendung mit den Funktionsbausteinen MC_CamTableSelect und MC_CamIn muss die im Funktionsbaustein CamBuilder definierte Kurvenscheibe schließlich in eine MC_CamRef überführt werden. Dafür gibt es, je nachdem wo der CamBuilder aufgerufen wird, zwei Möglichkeiten:

  1. Aufruf des CamBuilders in der Bustask:

    Zuerst muss der Deklarationsteil um entsprechende Instanzen erweitert werden:

    VAR
        ...
        camRef : MC_CAM_REF;
        aCamSegments : ARRAY[1..3] OF SMC_CAM_SEGMENT;
    END_VAR

    Danach wird die Funktionsbausteininstanz MC_CAM_REF initialisiert und mit der Methode Write des Funktionsbausteins CamBuilder geschrieben.

    SMCB.InitCamRef(camRef, ADR(aCamSegments), XSIZEOF(aCamSegments));
    camBuilder.Write(camRef);
  2. Aufruf des CamBuilders in einer anderen Task (Multitask, Multicore):

    Zuerst wird in einer GVL eine Multitask/Multicore sichere Instanz der Kurvenscheibe angelegt, auf die sowohl die Bustask als auch die CamBuilder-Task zugreifen.

    VAR_GLOBAL
        safeCam : SMCB.CAM_REF_MULTICORE_SAFE;
    END_VAR

    Aus der Bustask wird nun das Erstellen der Kurvenscheibe in der anderen Task gestartet.

    1. Damit in der Bustask festgestellt werden kann, wann die neue Kurvenscheibe in der anderen Task fertig geschrieben wurde, merkt sich das Programm in STATE_INIT_ONLINE_TABLE_MULTITASK die CamId vor dem Erstellen der Kurvenscheibe.

    2. Anschließend wird im Zustand STATE_START_CREATE_ONLINE_TABLE_MULTITASK das Erstellen der Kurvenscheibe in der anderen Task gestartet.

    3. Abschließend wird im Zustand STATE_READ_ONLINE_TABLE_MULTITASK die erstellte Kurvenscheibe ausgelesen.

    PROGRAM BUS_TASK
    VAR
        state : UDINT;
        error : SMC_ERROR;
        camIdBeforeCreate : UDINT;
        camSegments: ARRAY[0..99] OF SMC_CAM_SEGMENT;
        camRef: MC_CAM_REF;
    END_VAR
    VAR CONSTANT
        STATE_INIT_ONLINE_TABLE_MULTITASK : UDINT := 0;
        STATE_START_CREATE_ONLINE_TABLE_MULTITASK : UDINT := 10;
        STATE_READ_ONLINE_TABLE_MULTITASK : UDINT := 20;
        STATE_ERROR : UDINT := 1000;
    END_VAR
    
    
    CASE state OF
    STATE_INIT_ONLINE_TABLE_MULTITASK:
        camIdBeforeCreate := GVL.safeCam.CamId;
    
        state := STATE_START_CREATE_ONLINE_TABLE_MULTITASK;
    
    STATE_START_CREATE_ONLINE_TABLE_MULTITASK:
        CamBuilderTask.BuildCam := TRUE;
    
        state := STATE_READ_ONLINE_TABLE_MULTITASK;
    
    STATE_READ_ONLINE_TABLE_MULTITASK:
        IF CamBuilderTask.Error THEN
            error := CamBuilderTask.ErrorId;
            state := state + STATE_ERROR;
        ELSIF GVL.safeCam.CamId <> camIdBeforeCreate THEN
            error := GVL.safeCam.GetCopy(
                camRef:= camRef,
                pCamSegments:= ADR(camSegments),
                arraySize:= XSIZEOF(camSegments));
    
            IF error = SMC_NO_ERROR THEN
                state := state + 10;
            ELSE
                state := state + STATE_ERROR;
            END_IF
        END_IF
    END_CASE

    In der CamBuilder-Task wird die Multitask/Multicore sichere Kurvenscheibe mit dem Aufruf CamBuilder.WriteMulticoreSafe() geschrieben:

    PROGRAM CamBuilderTask
    VAR_INPUT
        BuildCam : BOOL;
    END_VAR
    VAR_OUTPUT
        Error : BOOL;
        ErrorId : SMC_ERROR;
    END_VAR
    VAR
        camBuilder : SMCB.CamBuilder;
    END_VAR
    
    IF BuildCam THEN
        BuildCam := FALSE;
    
        camBuilder.Init();
        camBuilder.Append(SMCB.Poly5(SMCB.BoundImplicit(), SMCB.Bound(120, 120, 1)));
        camBuilder.Append(SMCB.Poly5(SMCB.BoundImplicit(), SMCB.Bound(240, 240, 1)));
        camBuilder.Append(SMCB.Poly5(SMCB.BoundImplicit(), SMCB.Bound(360, 360)));
         
        Error := camBuilder.IsErrorPending(errorID=> ErrorId);
    
        IF NOT Error THEN
            ErrorId := camBuilder.WriteMulticoreSafe(GVL.safeCam);
            Error := ErrorId <> SMC_NO_ERROR;
        END_IF
    END_IF

Implizite und explizite Randbedingungen

Eine mit BoundImplicit definierte implizite Randbedingung führt dazu, dass der Übergang zum angrenzenden Segment so glatt wie möglich ist. Dafür muss die Randbedingung des angrenzenden Segments explizit über die Methode Bound definiert sein. Wenn also die linke Randbedingung eines Segments implizit ist, muss die rechte Randbedingung des vorherigen Segments explizit sein. Umgekehrt muss bei einer impliziten rechten Randbedingung die linke Randbedingung des nachfolgenden Segments explizit sein.

Der häufigste Anwendungsfall ist vermutlich, dass wie im obigen Beispiel nur die rechten Randbedingungen der Segmente explizit angegeben werden. Durch die impliziten linken Randbedingungen sind die Segmentübergänge automatisch so glatt wie möglich und es gibt keine Lücken im Definitionsbereich. Ein einfaches Beispiel, bei dem es hilfreich ist, von diesem Vorgehen abzuweichen, ist das folgende:

Die Slaveachse soll von Position 20 bis 100 mit konstanter Geschwindigkeit fahren:

camBuilder.Append(
    SMCB.Line(
        SMCB.Bound(20, 20),
        SMCB.Bound(100, 100)));

Davor und danach soll mit einem Segment vom Typ Poly5 beschleunigt und verzögert werden:

camBuilder.Append(
    SMCB.Poly5(
        SMCB.BoundImplicit(),
        SMCB.BoundImplicit()));
camBuilder.Append(
    SMCB.Line(
        SMCB.Bound(20, 20),
        SMCB.Bound(100, 100)));
camBuilder.Append(
    SMCB.Poly5(
        SMCB.BoundImplicit(),
        SMCB.Bound(120, 120, 0)));

Die so definierte Kurvenscheibe hat unerwünschte Beschleunigungs- und Verzögerungsphasen in den Poly5-Segmenten (Geschwindigkeit in blau):

_sm_img_cam_diagram2.png

Um diese zu vermeiden, reicht es, im Segment vom Typ Line die Masterposition anzupassen, beispielsweise die des linken Rands von 20 auf 30 und die es rechten Rands von 100 auf 90:

...
camBuilder.Append(
    SMCB.Line(
        SMCB.Bound(30, 20),
        SMCB.Bound(90, 100)));
...
_sm_img_cam_diagram3.png

Eine Anpassung der Segmente vom Typ Poly5 ist nicht nötig, weil sie aufgrund der über die Funktion BoundImplicit definierten Randbedingungen automatisch so glatt wie möglich an das Line-Segment angefügt werden.

Fehlerbehandlung

Die Methode Append des Funktionsbausteins CamBuilder gibt TRUE zurück, wenn ein Segment erfolgreich angehängt wurde, und FALSE, wenn es einen Fehler gab. Nach einem Fehler können keine weiteren Segmente angehängt werden und der Funktionsbaustein CamBuilder muss über die Methode Init neu initialisiert werden. Die Fehlerursache kann über die Methode IsErrorPending ermittelt werden:

camBuilder.IsErrorPending(errorId=> errorId);

Manuelles Anlegen der Datenstruktur MC_CAM_REF (vor SM 4.17.0.0)

Wichtig

Es wird empfohlen, ab CODESYS SoftMotion 4.17.0.0 die Bibliothek SM3_CamBuilder zu verwenden.

Datenstrukturen der Kurvenscheibe

Mit dem Übersetzen des Projekts werden die erstellten Kurvenscheibendaten intern in eine globale Variablenliste umgewandelt. Mit dem Befehl Zeige generierten Code an im Kurvenscheibeneditor können Sie die automatisch erzeugten globalen Variablen anzeigen.

Jede Kurvenscheibe wird repräsentiert durch die Datenstruktur MC_CAM_REF. Sie können auf diese Datenstruktur mittels IEC-Programm, aber auch durch Vorverarbeitungsfunktionen und Funktionsbausteine zugreifen. Sie wird von der Bibliothek SM3_Basic zur Verfügung gestellt.

Ein Funktionsbaustein, der eine Kurvenscheibe beschreibt, kann auch vom IEC-Programm zur Laufzeit erzeugt oder befüllt werden.

Beispiel 7. Beispiel

Definition der Datenstuktur:

TYPE mySMC_CAMTable_LREAL_10000_2 :
STRUCT
        Table: ARRAY[0..9999] OF ARRAY[0..1] OF LREAL;
        (* set all scaling definitions to 0 and 1
           result: all values of the table are not scaled *)
        fEditorMasterMin: REAL := 0;
        fEditorMasterMax: REAL := 1;
        fEditorSlaveMin: REAL := 0;
        fEditorSlaveMax: REAL := 1;
        fTableMasterMin: REAL := 0;
        fTableMasterMax: REAL := 1;
        fTableSlaveMin: REAL := 0;
        fTableSlaveMax: REAL := 1;
END_STRUCT
END_TYPE

Instanziierung der Datenstruktur:

Cam: MC_CAM_REF;
Cam_PointArray : mySMC_CAMTable_LREAL_10000_2;

Berechnung einer Kurvenscheibe:

Cam.byType:=2;
Cam.byVarType:=6;
Cam.nTappets:=0;
Cam.strCAMName:='myCAM';
Cam.pce:= ADR(CAM_PointArray);
FOR i:=0 TO 9999 DO
        (* example cam: master 0..360, slave 0..100,
           constant velocity *)
        Cam_PointArray.Table[i][0]:=UDINT_TO_LREAL(I)/10000 * 360;             (* X *)
        Cam_PointArray.Table[i][1]:=UDINT_TO_LREAL(I)/10000 * 100;             (* Y *)
END_FOR
Cam.nElements:=10000
Cam.xStart:=0.0;
Cam.xEnd:=360.0;


Manuell erzeugte Kurvenscheibe

Eine Kurvenscheibe kann ohne Verwendung des Kurvenscheibeneditors in einem IEC-Programm erzeugt werden.

Beispiel 8. Beispiel

Deklaration:

VAR
i: INT;
CAM: MC_CAM_REF := (
        byType:=2, (* non-equidistant *)
        byVarType:=2, (* UINT *)
        nElements:=128,
        xStart:=0,
        xEnd:=360);
Table: SMC_CAMTable_UINT_128_2 := (
        fEditorMasterMin := 0, fEditorMasterMax := 360,
        fTableMasterMin := 0, fTableMasterMax := 6000,
        fEditorSlaveMin := 0, fEditorSlaveMax := 360,
        fTableSlaveMin := 0, fTableSlaveMax := 6000);
END_VAR

Implementierung:

(* Create cam disk (example straight line); unambiguous *)
FOR i:=0 TO 127 DO
        Table.Table[i][0] := Table.Table[i][1] := REAL_TO_UINT(i / 127.0 * 6000);
END_FOR
(* Link pointer; must be done in every cycle! *)
CAM.pce := ADR(Table);


Diese so erzeugte Kurvenscheibe kann in den Baustein MC_CamTableSelect eingegeben und dessen Ausgang wieder für MC_CamIn verwendet werden.

Kompilieren einer Kurvenscheibendefinition

Während des Kompilierens werden für eine Kurvenscheibe Variablen des Typs MC_CAM_REF angelegt. Sie enthalten eine Beschreibung jedes Segments der Kurvenscheibe. Datenstrukturen dieser Art werden dem Funktionsbaustein MC_CamTableSelect übergeben. Die Struktur ist Teil der Bibliothek SM3_Basic.