Skip to main content

通过编程创建凸轮

作为 CODESYS SoftMotion 版本 4.17.0.0, CamBuilder 功能块提供了在 IEC 应用程序中直接以编程方式创建凸轮的接口。

有关详细信息,请参阅示例: 通过编程创建凸轮

使用 CamBuilder 功能块(自 SM 4.17.0.0 起)

在设备树中创建凸轮对象时,默认创建以下凸轮:

_sm_img_cam_diagram.png

凸轮由三个五次多项式组成,具有以下四个边界值:

X

Y

V

A

0

0

0

0

120

120

1

0

240

240

1

0

360

360

0

0

要以编程方式创建此凸轮, CamBuilder 功能块首先声明:

VAR
    camBuilder : SMCB.CamBuilder;
END_VAR

在实现部分, CamBuilder 实例必须先初始化。三个类型的段 Poly5 然后可以使用 Append 方法:

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

多项式通过左边界条件和右边界条件定义。在本例中, BoundImplicit 函数始终用于左边界。因此,将应用前一段的右边界条件。如果 BoundImplicit 函数用作第一个段的左边界,那么它从零开始:在这个例子中,Poly5 段位于 (X, Y, V, A) = (0, 0, 0, 0)。

MC_CamTableSelectMC_CamIn 使用功能块,凸轮定义在 CamBuilder 最后必须将功能块转换为 MC_CamRef。有两种方法可以执行此操作,具体取决于调用 CamBuilder 的位置

  1. 在总线任务中调用 CamBuilder:

    首先,声明部分必须通过相应的实例进行扩展:

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

    然后是函数块实例 MC_CAM_REF 使用初始化和写入 Write 的方法 CamBuilder 功能块。

    SMCB.InitCamRef(camRef, ADR(aCamSegments), XSIZEOF(aCamSegments));
    camBuilder.Write(camRef);
  2. 在另一项任务(多任务、多核)中调用 CamBuilder:

    首先,在 GVL 中创建 Cam 的多任务/多核安全实例,总线任务和 CamBuilder 任务均可访问该实例。

    VAR_GLOBAL
        safeCam : SMCB.CAM_REF_MULTICORE_SAFE;
    END_VAR

    然后,从总线任务开始在另一个任务中创建摄像头。

    1. 为了确定总线任务中何时在另一个任务中写入新摄像头,程序会记住 CamIdSTATE_INIT_ONLINE_TABLE_MULTITASK 在创建摄像头之前。

    2. 然后,在另一个任务中开始创建摄像头 STATE_START_CREATE_ONLINE_TABLE_MULTITASK 州。

    3. 然后,将创建的摄像头读入 STATE_READ_ONLINE_TABLE_MULTITASK 州。

    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

    在 CamBuilder 任务中,多任务/多核安全摄像头是通过调用编写的 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

隐式和显式边界条件

隐式边界条件定义为 BoundImplicit 确保与相邻段的过渡尽可能平稳。为此,需要使用 Bound 方法。因此,如果某段的左边界条件是隐式的,则前一段的右边界条件必须是显式的。相反,如果右边界条件是隐式的,则后一段的左边界条件必须是显式的。

最常见的用例大概是仅明确指定段的右边界条件,如上例所示。由于隐式左边界条件,段过渡自动尽可能平滑,并且定义区域中没有间隙。以下示例是一个简单的案例,偏离此方法是有帮助的:

从属轴应以恒定速度从位置 20 移动到 100:

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

在此之前和之后, Poly5 段用于加速和减速:

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

以此方式定义的凸轮在 Poly5 段中具有不必要的加速和减速阶段(速度以蓝色表示):

_sm_img_cam_diagram2.png

为了避免这种情况,只需调整类型段中的主位置即可 Line (例如左边界从 20 到 30,右边界从 100 到 90):

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

无需调整字型 Poly5 因为它们会根据使用定义的边界条件自动尽可能平滑地添加到线段 BoundImplicit 功能。

错误处理

Append 方法 CamBuilder 功能块返回 TRUE 当成功添加段时,返回 FALSE 如果发生错误。发生错误后,无法再添加任何段,并且 CamBuilder 功能块必须使用重新初始化 Init 方法。可以使用 IsErrorPending 方法:

camBuilder.IsErrorPending(errorId=> errorId);

手动创建数据结构 MC_CAM_REF(SM 4.17.0.0 之前)

重要

建议使用 SM3_CamBuilder 图书馆 CODESYS SoftMotion 4.17.0.0。

凸轮的数据结构

在项目编译时,创建的凸轮数据将在内部转换为全局变量列表。通过单击 显示生成的代码 在凸轮编辑器中,您可以显示自动创建的全局变量。

每个凸轮由数据结构表示 MC_CAM_REF。您可以通过 IEC 程序或预处理函数和功能块访问此数据结构。它可通过 SM3_Basic 图书馆。

描述凸轮的功能块也可由 IEC 程序在运行时生成或填充。

7. 例子

数据结构定义:

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

实例化数据结构:

Cam: MC_CAM_REF;
Cam_PointArray : mySMC_CAMTable_LREAL_10000_2;

计算凸轮:

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;


手动生成的凸轮

无需使用凸轮编辑器即可在 IEC 程序中创建凸轮。

8. 例子

宣言:

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

执行:

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


生成的凸轮可以在 MC_CamTableSelect 功能块及其输出再次用于 MC_CamIn

编译凸轮定义

在编译时,类型变量 MC_CAM_REF 为凸轮创建。它们包括凸轮每个部分的描述。这种数据结构被传递给 MC_凸轮表选择 功能块。结构是 SM3_Basic 图书馆。