Skip to main content

Creazione di camme a livello di codice

Come di CODESYS SoftMotion versione 4.17.0.0, il CamBuilder Il blocco funzione fornisce un'interfaccia per la creazione di camme a livello di programmazione direttamente nell'applicazione IEC.

Per ulteriori informazioni, vedere l'esempio: Creazione di camme a livello di codice

Utilizzo del blocco funzione CamBuilder (a partire da SM 4.17.0.0)

Per impostazione predefinita, quando si crea un oggetto camma nell'albero dei dispositivi, viene creata la seguente camma elettronica:

_sm_img_cam_diagram.png

La camma è composta da tre polinomi di quinto grado con i seguenti quattro valori limite:

X

Y

V

A

0

0

0

0

120

120

1

0

240

240

1

0

360

360

0

0

Per creare questa camma a livello di codice, un'istanza di CamBuilder il blocco funzione viene dichiarato per primo:

VAR
    camBuilder : SMCB.CamBuilder;
END_VAR

Nella parte di implementazione, il CamBuilder l'istanza deve prima essere inizializzata. Tre segmenti di tipo Poly5 può quindi essere aggiunto utilizzando il file Append metodo:

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)));

I polinomi sono definiti tramite le condizioni al contorno sinistra e destra. Nell'esempio, il BoundImplicit la funzione viene sempre utilizzata per il confine sinistro. Di conseguenza, viene applicata la condizione al contorno destra del segmento precedente. Se la BoundImplicit viene utilizzata come limite sinistro per il primo segmento, quindi inizia da zero: in questo esempio, con il segmento Poly5 in (X, Y, V, A) = (0, 0, 0, 0).

Quando il MC_CamTableSelect e MC_CamIn vengono utilizzati i blocchi funzionali, la camma è definita in CamBuilder il blocco funzionale deve infine essere convertito in un MC_CamRef. Esistono due modi per farlo, a seconda di dove viene chiamato CamBuilder

  1. Chiamare il CamBuilder nel task del bus:

    Innanzitutto, la parte della dichiarazione deve essere estesa dalle istanze corrispondenti:

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

    Quindi l'istanza del blocco funzionale MC_CAM_REF viene inizializzato e scritto utilizzando Write metodo del CamBuilder blocco funzionale.

    SMCB.InitCamRef(camRef, ADR(aCamSegments), XSIZEOF(aCamSegments));
    camBuilder.Write(camRef);
  2. Chiamare CamBuilder in un'altra attività (multitask, multicore):

    Innanzitutto, viene creata un'istanza multitask/multicore-safe della videocamera in un GVL, a cui si accede sia dal task bus che dal task CamBuilder.

    VAR_GLOBAL
        safeCam : SMCB.CAM_REF_MULTICORE_SAFE;
    END_VAR

    Quindi la creazione della camma nell'altra attività viene avviata dall'attività del bus.

    1. Per determinare nell'operazione del bus quando la nuova camma è stata scritta nell'altra operazione, il programma ricorda CamId nel STATE_INIT_ONLINE_TABLE_MULTITASK prima che la camma venga creata.

    2. Quindi la creazione della camma viene avviata nell'altra attività nel STATE_START_CREATE_ONLINE_TABLE_MULTITASK stato.

    3. Quindi, la cam creata viene letta nel STATE_READ_ONLINE_TABLE_MULTITASK stato.

    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

    Nel task CamBuilder, la cam multitask/multicore-safe viene scritta chiamando CamBuilder.WriteMulticoreSafe():

    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

Condizioni al contorno implicite ed esplicite

Una condizione al contorno implicita definita con BoundImplicit assicura che la transizione al segmento adiacente sia il più agevole possibile. Per fare ciò, la condizione al contorno del segmento adiacente deve essere definita esplicitamente utilizzando il Bound metodo. Quindi se la condizione al contorno sinistra di un segmento è implicita, allora la condizione al contorno destra del segmento precedente deve essere esplicita. Viceversa, se la condizione al contorno destra è implicita, allora la condizione al contorno sinistra del segmento successivo deve essere esplicita.

Il caso d'uso più comune è presumibilmente che solo le giuste condizioni al contorno dei segmenti siano specificate esplicitamente, come nell'esempio sopra. A causa delle condizioni al contorno sinistro implicite, le transizioni dei segmenti sono automaticamente il più fluide possibile e non ci sono spazi vuoti nell'area di definizione. L’esempio seguente è un caso semplice in cui è utile deviare da questo approccio:

L'asse slave dovrebbe spostarsi a velocità costante dalla posizione 20 a 100:

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

Prima e dopo questo, a Poly5 il segmento viene utilizzato per l'accelerazione e la decelerazione:

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)));

La camma così definita presenta fasi di accelerazione e decelerazione indesiderate nei segmenti Poly5 (velocità in blu):

_sm_img_cam_diagram2.png

Per evitare ciò è sufficiente regolare la posizione del master nel segmento di tipo Line (ad esempio, quello del confine sinistro da 20 a 30 e quello del confine destro da 100 a 90):

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

Non è necessario modificare i segmenti del tipo Poly5 perché vengono aggiunti automaticamente al segmento di linea nel modo più fluido possibile a causa delle condizioni al contorno definite utilizzando BoundImplicit funzione.

Gestione degli errori

IL Append metodo del CamBuilder ritorni del blocco funzione TRUE quando un segmento è stato aggiunto con successo e ritorna FALSE se si è verificato un errore. Dopo un errore non è possibile aggiungere altri segmenti e il file CamBuilder il blocco funzione deve essere reinizializzato utilizzando il comando Init metodo. La causa dell'errore può essere determinata utilizzando IsErrorPending metodo:

camBuilder.IsErrorPending(errorId=> errorId);

Creazione manuale della struttura dati MC_CAM_REF (prima di SM 4.17.0.0)

Importante

Si consiglia di utilizzare il SM3_CamBuilder biblioteca a partire da CODESYS SoftMotion 4.17.0.0.

Strutture dati delle camme

Durante la compilazione del progetto, i dati camma creati vengono convertiti internamente in un elenco di variabili globali. Cliccando Visualizza il codice generato nell'editor camme è possibile visualizzare le variabili globali create automaticamente.

Ogni camma è rappresentata dalla struttura dati MC_CAM_REF. È possibile accedere a questa struttura dati tramite il programma IEC o preelaborando funzioni e blocchi funzionali. È disponibile presso il SM3_Basic biblioteca.

Un blocco funzione che descrive una camma può anche essere generato o popolato dal programma IEC in fase di esecuzione.

Esempio 7. Esempio

Definizione della struttura dei dati:

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

Istanziare la struttura dei dati:

Cam: MC_CAM_REF;
Cam_PointArray : mySMC_CAMTable_LREAL_10000_2;

Calcolo della camma:

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;


Camme generate manualmente

È possibile creare una camma elettronica in un programma IEC senza utilizzare l'editor camma.

Esempio 8. Esempio

Dichiarazione:

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

Implementazione:

(* 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);


Questa camma generata può essere specificata nel file MC_CamTableSelect blocco funzione e il suo output riutilizzato MC_CamIn.

Compilazione delle definizioni di camma

In fase di compilazione, variabili di tipo MC_CAM_REF vengono creati per una camma. Includono una descrizione di ciascun segmento della camma. Strutture dati di questo tipo vengono passate al file MC_CamTableSelect blocco funzione. La struttura fa parte del SM3_Basic biblioteca.