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_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:
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 MethodeWrite
des FunktionsbausteinsCamBuilder
geschrieben.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_MULTITASK
dieCamId
vor dem Erstellen der Kurvenscheibe.Anschließend wird im Zustand
STATE_START_CREATE_ONLINE_TABLE_MULTITASK
das Erstellen der Kurvenscheibe in der anderen Task gestartet.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):

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_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.
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
.