Как создать синхронизацию с состояниями контроллера в двигателях? - PullRequest
0 голосов
/ 07 июня 2019

Синхронизация может использоваться для создания задержки при запуске или выключении одного и того же двигателя или для задержки включения или выключения между различными двигателями. Эта функция используется для защиты двигателей, избегая приводов с очень короткими интервалами. В аварийных ситуациях двигатели автоматически отключаются (приоритет со временем), чтобы избежать дальнейшего повреждения.

Запустите мой код, создав подпрограмму для чтения состояний машин, которая скажет мне, включен ли он или нет. Затем создайте подпрограмму, которая считывает машины, находящиеся в состоянии тревоги, затем я проверил, находится ли машина в состоянии тревоги. Ниже этого кода я создал подпрограмму, которая приводит в движение двигатели, а затем создал подпрограмму для запуска выходов на двигателях, которые должны быть подключены, и я закончил свой код с помощью else, где он отключает двигатели.


VAR_INPUT

ENABLE      :   BOOL    := FALSE;       (*ENABLES THE BLOCK OPERATION*)

DEV_STS1    :   BOOL    := FALSE;       (*REPRESENTS MOTOR STATUS 1 ON / OFF*)
DEV_STS2    :   BOOL    := FALSE;       (*REPRESENTS MOTOR STATUS 2 ON / OFF*)
DEV_STS3    :   BOOL    := FALSE;       (*REPRESENTS MOTOR STATUS 3 ON / OFF*)
DEV_STS4    :   BOOL    := FALSE;       (*REPRESENTS MOTOR STATUS 4 ON / OFF*)
DEV_STS5    :   BOOL    := FALSE;       (*REPRESENTS MOTOR STATUS 5 ON / OFF*)
DEV_STS6    :   BOOL    := FALSE;       (*REPRESENTS MOTOR STATUS 6 ON / OFF*)

DEV_ALA1    :   BOOL    := FALSE;       (*REPRESENTS MOTOR ALARM CONDITION 1*)
DEV_ALA2    :   BOOL    := FALSE;       (*REPRESENTS MOTOR ALARM CONDITION 2*)
DEV_ALA3    :   BOOL    := FALSE;       (*REPRESENTS MOTOR ALARM CONDITION 3*)
DEV_ALA4    :   BOOL    := FALSE;       (*REPRESENTS MOTOR ALARM CONDITION 4*)
DEV_ALA5    :   BOOL    := FALSE;       (*REPRESENTS MOTOR ALARM CONDITION 5*)
DEV_ALA6    :   BOOL    := FALSE;       (*REPRESENTS MOTOR ALARM CONDITION 6*)

T_MIN_ON    :   REAL    := 0.0;         (*MINIMUM TIME ON ONE SAME MOTOR / RANGE 0.0 ~ 9999.0 **)
T_MIN_OFF   :   REAL    := 0.0;         (*MINIMUM TIME OFF OF SAME MOTOR / RANGE 0.0 ~ 9999.0*)
T_ON_ON     :   REAL    := 0.0;         (*MINIMUM TIME BETWEEN TWO PARTS OF THE SAME MOTOR / RANGE 0.0 ~ 9999.0*)
T_ON_OTHER  :   REAL    := 0.0;         (*TIME BETWEEN TURN ON DIFFERENT MOTORS / RANGE 0.0 ~ 9999.0*)
T_OFF_OTHER :   REAL    := 0.0;         (*TIME BETWEEN TURN OFF DIFFERENT MOTORS / RANGE 0.0 ~ 9999.0*)
END_VAR

VAR_OUTPUT

REQ_DEV1    :   BOOL    := FALSE;       (*STATUS D0 MOTOR 1 (COMPRESSOR) ACCORDING TO THE TIMER LOGIC*)
REQ_DEV2    :   BOOL    := FALSE;       (*STATUS D0 MOTOR 2 (COMPRESSOR) ACCORDING TO THE TIMER LOGIC*)
REQ_DEV3    :   BOOL    := FALSE;       (*STATUS D0 MOTOR 3 (COMPRESSOR) ACCORDING TO THE TIMER LOGIC*)
REQ_DEV4    :   BOOL    := FALSE;       (*STATUS D0 MOTOR 4 (COMPRESSOR) ACCORDING TO THE TIMER LOGIC*)
REQ_DEV5    :   BOOL    := FALSE;       (*STATUS D0 MOTOR 5 (COMPRESSOR) ACCORDING TO THE TIMER LOGIC*)
REQ_DEV6    :   BOOL    := FALSE;       (*STATUS D0 MOTOR 6 (COMPRESSOR) ACCORDING TO THE TIMER LOGIC*)

END_VAR

VAR

DEV_STS     :   ARRAY[1..6] OF BOOL;    (*MOTOR STATUS READING ARRAY*)
DEV_ALA     :   ARRAY[1..6] OF BOOL;    (*ARRAY READING OF MOTORS ALARMS*)  
REQ_DEV     :   ARRAY[1..6] OF BOOL;    (*ARRAY TO MANIPULATE MOTORS STATES*)

FLAG_STS    :   ARRAY[1..6] OF BOOL;    (*ARRAY FOR PREVIOUS STATUS CONTROL OF MOTORS*)

IDX         :   USINT   := 0;           (*GENERIC INDEX TO HANDLE ARRAY*)
DEV_ON      :   USINT   := 0;           (*AMOUNT OF MOTORS MUST BE TURN ON*)

T_ON_INT    :   ARRAY[1..6] OF REAL;    (*INTERNAL TIME ON A SAME MOTOR*)
T_OFF_INT   :   ARRAY[1..6] OF REAL;    (*INTERNAL TIME OFF A SAME MOTOR*)
T_CYCLE     :   ARRAY[1..6] OF REAL;    (*CYCLE TIME OF SAME MOTOR*)

END_VAR

 IF ENABLE THEN
(*==================================================================================*)
                    (*READINGS OF MOTORS STATUS*)
(*==================================================================================*)
    DEV_STS[1] := DEV_STS1;
    DEV_STS[2] := DEV_STS2;
    DEV_STS[3] := DEV_STS3;
    DEV_STS[4] := DEV_STS4;
    DEV_STS[5] := DEV_STS5;
    DEV_STS[6] := DEV_STS6;

(*==================================================================================*)
                (*READINGS OF THE MOTORS ALARM STATUS*)
(*==================================================================================*)
    DEV_ALA[1] := DEV_ALA1;
    DEV_ALA[2] := DEV_ALA2;
    DEV_ALA[3] := DEV_ALA3;
    DEV_ALA[4] := DEV_ALA4;
    DEV_ALA[5] := DEV_ALA5;
    DEV_ALA[6] := DEV_ALA6;

(*==================================================================================*)
                (*CHECK IF ANY MOTOR IS ALARMED*) 
(*==================================================================================*)
    FOR IDX := 0 TO 6 BY 1 DO
        IF DEV_ALA[IDX] = TRUE THEN
            REQ_DEV[IDX] := FALSE;
        END_IF;
    END_FOR;

(*==================================================================================*)
                (*CHECKING WHAT MOTOR SHOULD BE TURN ON*)
(*==================================================================================*)

    FOR IDX := 0 TO 6 BY 1 DO
        IF DEV_STS[IDX] = TRUE THEN
            DEV_ON := DEV_ON + 1;
        END_IF;
    END_FOR;

(*==================================================================================*)
                            (*ACTING A MOTOR*)
(*==================================================================================*)
    FOR IDX := 0 TO 6 DO
        T_CYCLE[IDX] := T_ON_INT[IDX] + T_OFF_INT[IDX];
        IF DEV_STS[IDX] = TRUE AND FLAG_STS[IDX] = FALSE THEN
            IF T_CYCLE[IDX] > T_ON_ON THEN
                IF T_ON_INT[IDX] < T_MIN_OFF THEN
                    REQ_DEV[IDX] := TRUE;
                END_IF;
            END_IF;
        END_IF;

        IF DEV_STS[IDX] = FALSE AND FLAG_STS[IDX] = TRUE THEN
            IF T_ON_INT[IDX] >= T_MIN_ON THEN
                REQ_DEV[IDX] := FALSE;
            END_IF;
        END_IF;

        IF DEV_STS[IDX] = TRUE AND FLAG_STS[IDX] = TRUE THEN
            T_ON_INT[IDX] := T_ON_INT[IDX] + 1.0;
        END_IF;
    END_FOR;


(*==================================================================================*)
                            (*LEADING OUTPUTS*)
(*==================================================================================*)

    REQ_DEV1 := REQ_DEV[1] ;
    REQ_DEV2 := REQ_DEV[2] ;
    REQ_DEV3 := REQ_DEV[3] ;
    REQ_DEV4 := REQ_DEV[4] ;
    REQ_DEV5 := REQ_DEV[5] ;
    REQ_DEV6 := REQ_DEV[6] ;

(*==================================================================================*)
                                (*FLAG*)
(*==================================================================================*)

    FLAG_STS[1] := REQ_DEV1;
    FLAG_STS[2] := REQ_DEV2;
    FLAG_STS[3] := REQ_DEV3;
    FLAG_STS[4] := REQ_DEV4;
    FLAG_STS[5] := REQ_DEV5;
    FLAG_STS[6] := REQ_DEV6;

ELSE

    REQ_DEV1 := FALSE;
    REQ_DEV2 := FALSE;
    REQ_DEV3 := FALSE;
    REQ_DEV4 := FALSE; 
    REQ_DEV5 := FALSE; 
    REQ_DEV6 := FALSE;

END_IF; 


Я еще не тестировал код. Но я обычно использую CFC для тестирования.

1 Ответ

1 голос
/ 10 июня 2019

Для CFC это может быть нормально, но не для ST. В ST вы должны использовать другую концепцию. У меня много вопросов к вашему коду, но я покажу вам, как я это понял, и вы зададите вопросы позже.

Сначала создайте тип.

TYPE MOTOR : STRUCT
        State:  BOOL;    (* State of the motor translated to DO *)
        Task:   BOOL;    (* Do we want to turn this motor off or on *)
        Alarm:  BOOL;    (* Motor alarm *)
        TimerOnMax: TP;  (* Timer to maximum work for motor *)
        TimerOnMin: TP;  (* Timer to maximum work for motor *)
        TimerOff:   TP;  (* Timer for minimum pause between work *)
        TimeOnMax: TIME; (* Maximum time for motor to work *)
        TimeOnMin: TIME; (* Minimum time for motor to work *)
        TimeOff:   TIME; (* Minimum time for motor to rest *)
    END_STRUCT
END_TYPE

Теперь определите глобальные переменные

VAR_GLOBAL
    (* Array of motors to manage *)
    stMotors: ARRAY[1.._MOTORS_NUM] OF MOTOR := [
        _MOTORS_NUM(TimeOnMax := T#1h, TimeOnMin := T#10m, TimeOff := T#30m)
    ];
END_VAR

VAR_GLOBAL CONSTANT
    _MOTORS_NUM: INT := 6; (* Number of motors in array *)
END_VAR

Инициализация может отличаться в зависимости от версии CoDeSys

Теперь наш функциональный блок

FUNCTION_BLOCK ManageMotors
    VAR_INPUT
        ENABLE: BOOL; (* Enable motor management *)
        M_NUM: INT; (*  Number of motors to be working *)
    END_VAR
    VAR
        iCount: INT; (* Index for circle *)
        iNumOfMotors: INT; (* Number of currently working motors *)
    END_VAR

    IF NOT ENABLE THEN
        actTurnOffAll();
        actApply();
        RETURN;
    END_IF;

    actCountWroking();

    FOR iCount := 1 TO _MOTORS_NUM DO
        (* If motor in alarm state turn it off *)
        IF stMotors[iCount].Alarm AND stMotors[iCount].State THEN
            stMotors[iCount].Task := FALSE;
            iNumOfMotors := iNumOfMotors - 1;
        END_IF;

        (* If motor works longer that allowed time turn it off *)
        IF stMotors[iCount].State AND
            stMotors[iCount].Task AND
            NOT stMotors[iCount].TimerOnMax.Q
        THEN
            stMotors[iCount].Task := FALSE;
            iNumOfMotors := iNumOfMotors - 1;
        END_IF;

        (* If amout of working motors more that allowed number turn one off *)
        IF iNumOfMotors > M_NUM AND
            stMotors[iCount].State AND
            stMotors[iCount].Task AND
            NOT stMotors[iCount].TimerOnMin.Q
        THEN
            stMotors[iCount].Task := FALSE;
            iNumOfMotors := iNumOfMotors - 1;
        END_IF;

        (* If amount of working motors less then required turn one motor on *)
        IF iNumOfMotors < M_NUM AND
            NOT stMotors[iCount].State AND
            NOT stMotors[iCount].Task AND
            NOT stMotors[iCount].TimerOff.Q
        THEN
            stMotors[iCount].Task := TRUE;
            iNumOfMotors := iNumOfMotors + 1;
        END_IF;

        stMotors[iCount].TimerOnMax(
            IN := (stMotors[iCount].Task AND NOT stMotors[iCount].State),
            PT := stMotors[iCount].TimeOnMax
        );

        stMotors[iCount].TimerOnMin(
            IN := (stMotors[iCount].Task AND NOT stMotors[iCount].State),
            PT := stMotors[iCount].TimeOnMin
        );

        stMotors[iCount].TimerOff(
            IN := (NOT stMotors[iCount].Task AND stMotors[iCount].State),
            PT := stMotors[iCount].TimeOff
        );
    END_FOR;

    actApply();

    ACTION actCountWroking:
        iNumOfMotors := 0;
        FOR iCount := 1 TO _MOTORS_NUM DO
            IF stMotors[iCount].State THEN
                iNumOfMotors := iNumOfMotors + 1;
            END_IF;
        END_FOR;
    END_ACTION;

    ACTION actTurnOffAll:
        FOR iCount := 1 TO _MOTORS_NUM DO
            stMotors[iCount].Task := FALSE;
        END_FOR;
    END_ACTION;

    ACTION actApply:
        FOR iCount := 1 TO _MOTORS_NUM DO
            stMotors[iCount].State := stMotors[iCount].Task;
        END_FOR;
    END_ACTION;
END_FUNCTION_BLOCK

Я добавил несколько комментариев, но остальная часть кода должна быть понятной. Я использовал ACTION, так как он доступен как в CDS 2.3, так и в CDS 3.5, но если у вас версия 3.5, вы можете использовать METHOD.

...