Apach3
Apach3

Reputation: 3

How to create a timing to to controller states in motors?

The timing can be used to create a delay in triggering or switching off the same motor or to create a delay in switching on or off between different motors. This is a feature used to protect the motors, avoiding drives with very short intervals. In alarm situations the motors are automatically disabled(priority over time) to avoid further damage.

Start my code by creating a sub routine to read the states of the machines this will tell me if it is on or off. Then create a subroutine that reads the machines that are in the alarm state, then I did a check if the machine is in an alarm state. Below this code I created a routine that drives the motors, and then create a routine to trigger the outputs on the motors must be connected and I finished my code with an else, where it turns off the motors.


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; 


I have not tested the code yet. But I usually use CFC to test.

Upvotes: 0

Views: 106

Answers (1)

Sergey Romanov
Sergey Romanov

Reputation: 3080

For CFC it might be OK but not for ST. In ST you have to use a different concept. I have a lot of questions to your code, but let me show you how I understood it and you will ask questions later.

First, create a type.

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

Now define global variables

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

Initialization might be different depending on CoDeSys version

Now our function block

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

I added some comments but the rest of the code have to be clear. I used ACTION as it is available as in CDS 2.3 as in CDS 3.5 but if you have 3.5 version, you can use METHOD instead.

Upvotes: 1

Related Questions