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:

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_VARIm 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:
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_REFinitialisiert und mit der MethodeWritedes FunktionsbausteinsCamBuildergeschrieben.SMCB.InitCamRef(camRef, ADR(aCamSegments), XSIZEOF(aCamSegments)); camBuilder.Write(camRef);
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.
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_MULTITASKdieCamIdvor dem Erstellen der Kurvenscheibe.Anschließend wird im Zustand
STATE_START_CREATE_ONLINE_TABLE_MULTITASKdas Erstellen der Kurvenscheibe in der anderen Task gestartet.Abschließend wird im Zustand
STATE_READ_ONLINE_TABLE_MULTITASKdie 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):

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)));
...
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.
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_TYPEInstanziierung 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.
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_VARImplementierung:
(* 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.