Skip to main content

Crear cámaras mediante programación

A partir de CODESYS SoftMotion versión 4.17.0.0, la CamBuilder El bloque de funciones proporciona una interfaz para crear levas mediante programación directamente en la aplicación IEC.

Para obtener más información, consulte el ejemplo: Crear cámaras mediante programación

Usando el bloque de funciones CamBuilder (a partir de SM 4.17.0.0)

La siguiente cámara se crea de forma predeterminada cuando se crea un objeto de cámara en el árbol de dispositivos:

_sm_img_cam_diagram.png

La leva consta de tres polinomios de quinto grado con los siguientes cuatro valores límite:

X

Y

V

A

0

0

0

0

120

120

1

0

240

240

1

0

360

360

0

0

Para crear esta cámara mediante programación, una instancia de la CamBuilder El bloque de funciones se declara primero:

VAR
    camBuilder : SMCB.CamBuilder;
END_VAR

En la parte de implementación, el CamBuilder La instancia primero debe inicializarse. Tres segmentos de tipo Poly5 Luego se puede agregar usando el Append método:

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

Los polinomios se definen mediante las condiciones de contorno izquierda y derecha. En el ejemplo, el BoundImplicit La función siempre se utiliza para el límite izquierdo. Como resultado, se aplica la condición de contorno derecho del segmento anterior. Si el BoundImplicit La función se utiliza como límite izquierdo para el primer segmento, luego comienza en cero: en este ejemplo, con el segmento Poly5 en (X, Y, V, A) = (0, 0, 0, 0).

Cuando el MC_CamTableSelect y MC_CamIn se utilizan bloques de funciones, la leva definida en CamBuilder el bloque de funciones finalmente tiene que convertirse en un MC_CamRef. Hay dos maneras de hacerlo, dependiendo de dónde se llame al CamBuilder

  1. Llamar a CamBuilder en la tarea del bus:

    En primer lugar, la parte de la declaración debe ser extendida por las instancias correspondientes:

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

    Luego, la instancia del bloque de funciones MC_CAM_REF se inicializa y escribe con el Write método del CamBuilder bloque de funciones.

    SMCB.InitCamRef(camRef, ADR(aCamSegments), XSIZEOF(aCamSegments));
    camBuilder.Write(camRef);
  2. Llamar al CamBuilder en otra tarea (multitarea, multinúcleo):

    En primer lugar, se crea una instancia de la cámara segura para múltiples tareas/multinúcleo en una GVL, a la que acceden tanto la tarea bus como la tarea CamBuilder.

    VAR_GLOBAL
        safeCam : SMCB.CAM_REF_MULTICORE_SAFE;
    END_VAR

    A continuación, la creación de la cámara en la otra tarea se inicia desde la tarea del bus.

    1. Para determinar en la tarea del bus cuándo se escribió la nueva cámara en la otra tarea, el programa recuerda el CamId en STATE_INIT_ONLINE_TABLE_MULTITASK antes de crear la cámara.

    2. A continuación, se inicia la creación de la cámara en la otra tarea del STATE_START_CREATE_ONLINE_TABLE_MULTITASK estado.

    3. A continuación, la cámara creada se lee en el STATE_READ_ONLINE_TABLE_MULTITASK estado.

    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

    En la tarea CamBuilder, la cámara multitarea/segura para múltiples núcleos se escribe llamando 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

Condiciones de contorno implícitas y explícitas

Una condición de frontera implícita definida con BoundImplicit se asegura de que la transición al segmento adyacente sea lo más suave posible. Para hacer esto, la condición de contorno del segmento adyacente debe definirse explícitamente usando el Bound método. Entonces, si la condición de frontera izquierda de un segmento es implícita, entonces la condición de frontera derecha del segmento anterior tiene que ser explícita. Por el contrario, si la condición de frontera derecha está implícita, entonces la condición de frontera izquierda del segmento posterior tiene que ser explícita.

El caso de uso más común es presumiblemente que solo se especifican explícitamente las condiciones de contorno correctas de los segmentos, como en el ejemplo anterior. Debido a las condiciones implícitas del límite izquierdo, las transiciones de los segmentos son automáticamente lo más suaves posible y no hay espacios en el área de definición. El siguiente ejemplo es un caso sencillo en el que resulta útil desviarse de este enfoque:

El eje esclavo debe viajar a velocidad constante desde la posición 20 a 100:

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

Antes y después de esto, un Poly5 El segmento se utiliza para aceleración y desaceleración:

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 leva así definida tiene fases de aceleración y desaceleración no deseadas en los segmentos Poly5 (velocidad en azul):

_sm_img_cam_diagram2.png

Para evitar esto, es suficiente ajustar la posición del maestro en el segmento de tipo Line (por ejemplo, el del límite izquierdo de 20 a 30 y el del límite derecho de 100 a 90):

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

No es necesario ajustar los segmentos de tipo Poly5 porque se agregan automáticamente al segmento de línea de la manera más suave posible debido a las condiciones de contorno definidas usando el BoundImplicit función.

Manejo de errores

El Append método de la CamBuilder retornos del bloque de funciones TRUE cuando un segmento se ha agregado exitosamente y regresa FALSE si ha ocurrido un error. Después de un error, no se pueden agregar más segmentos y el CamBuilder El bloque de funciones debe reinicializarse utilizando el Init método. La causa del error se puede determinar utilizando el IsErrorPending método:

camBuilder.IsErrorPending(errorId=> errorId);

Creación manual de la estructura de datos MC_CAM_REF (antes de SM 4.17.0.0)

Importante

Se recomienda utilizar el SM3_CamBuilder biblioteca a partir de CODESYS SoftMotion 4.17.0.0.

Estructuras de datos de levas.

Al compilar el proyecto, los datos de la cámara creados se convierten internamente en una lista de variables globales. Haciendo click Mostrar código generado En el editor de cámaras, puede mostrar las variables globales creadas automáticamente.

Cada cámara está representada por la estructura de datos. MC_CAM_REF. Puede acceder a esta estructura de datos mediante el programa IEC o mediante funciones de preprocesamiento y bloques de funciones. Está disponible por el SM3_Basic biblioteca.

El programa IEC también puede generar o completar un bloque de funciones que describe una leva en tiempo de ejecución.

ejemplo 7. Ejemplo

Definición de la estructura de datos:

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

Creación de instancias de la estructura de datos:

Cam: MC_CAM_REF;
Cam_PointArray : mySMC_CAMTable_LREAL_10000_2;

Calculando la leva:

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;


Cámaras generadas manualmente

Se puede crear una leva en un programa IEC sin utilizar el editor de levas.

ejemplo 8. Ejemplo

Declaración:

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

Implementación:

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


Esta leva generada se puede especificar en el MC_CamTableSelect bloque de funciones y su salida se utiliza nuevamente para MC_CamIn.

Compilación de definiciones de cámaras

En tiempo de compilación, variables de tipo MC_CAM_REF se crean para una cámara. Incluyen una descripción de cada segmento de la leva. Las estructuras de datos de este tipo se pasan al MC_CamTableSelect bloque de funciones. La estructura es parte de la SM3_Basic biblioteca.