plccodesysstructured-textiec61131-3

How do I automate/optimize D/Y connection selection based on selected input voltage and motor plate voltage values?


I have a test setup with six (6) selectable load motors and four (4) possible input voltage options. The motors are divided into three (3) motor sets, each containing two (2) motors (i.e. 1M1 1M2, 2M1 2M2 and 3M1 3M2 where the first number is the motor set number and Mx the motor).

I want to automate the D/Y connection selection of a selected motor based on the motor plate voltage values and the selected input voltage according to the following table

Selected Input Voltage Motor Connection (Delta / Wye)
230 V 230V D
400 V 400V D / 400V Y (D if the motor is 230/400 and Y if the motor is 400/690)
500 V 400V D / 400V Y (D if the motor is 230/400 and Y if the motor is 400/690)
690 V 690V Y

I'm using Automation Builder 2.5 (with AC500 V3 PLC) and Structured Text (ST) according to IEC 61131-3.

I need to check which input voltage and motor is selected and then check the motor plate voltage values (the motor plate values are initialized elsewhere in the program) for the selected motor and connect it according to the table above.

Currently I have solved the issue with IF-ELSIF statements like so:

(*Check motor plate voltage values and the selected voltage and connect the motors to Delta or Wye based on the selections*)

IF gxAutoDYSwitch THEN //TRUE = automatic D/Y selection is enabled

(*The code for all the motor sets when Input voltage is 230 V*)

(*Input voltage is 400 V -> Motor connection 400 V D if selected motor is 230/400 V and 400 V Y if selected motor is 400/690 V*)

IF gx400VSelected THEN //400 V input voltage is selected
        
//Motor set 1 Motor 1
    IF MotorSet1.Motor1.MotorVoltageDelta = 230 AND MotorSet1.Motor1.MotorVoltageWye = 400 AND MotorSet1.Motor1.Selected THEN
                MotorSet1.Motor1.DeltaConnected := TRUE;
                MotorSet1.Motor1.WyeConnected   := FALSE;
                    
            ELSIF   MotorSet1.Motor1.MotorVoltageDelta = 400 AND MotorSet1.Motor1.MotorVoltageWye = 690 AND MotorSet1.Motor1.Selected THEN
                MotorSet1.Motor1.WyeConnected   := TRUE;
                MotorSet1.Motor1.DeltaConnected := FALSE;
        END_IF

//Motor set 1 Motor 2
    IF MotorSet1.Motor2.MotorVoltageDelta = 230 AND MotorSet1.Motor2.MotorVoltageWye = 400 AND MotorSet1.Motor2.Selected THEN
                MotorSet1.Motor2.DeltaConnected := TRUE;
                MotorSet1.Motor2.WyeConnected   := FALSE;
                    
        ELSIF   MotorSet1.Motor2.MotorVoltageDelta = 400 AND MotorSet1.Motor2.MotorVoltageWye = 690 AND  MotorSet1.Motor2.Selected THEN
                MotorSet1.Motor2.WyeConnected   := TRUE;
                MotorSet1.Motor2.DeltaConnected := FALSE;
        END_IF

//Motor set 2 Motor 1 code here written in a similar manner here
//Motor set 2 Motor 2 code here written in a similar manner here
//Motor set 3 Motor 1 code here written in a similar manner here
//Motor set 3 Motor 2 code here written in a similar manner here
(*The code for all the motor sets when Input voltage is 500 V*)
(*The code for all the motor sets when Input voltage is 690 V*)    
  END_IF

gxAutoDYSwitch is a BOOLean variable that is used to enable or disable this automatic feature (so that the operator may override the automatic selection if needed for a specific test case). To save space I've only provided the code for motor set 1 and the 400 V case. The other cases (for all the input voltages and motor sets) are written in a similar manner.

What I want to achieve: An automatic D/Y selection for any selected motor from a set of six (6) motors based on the motor plate values of the selected motor and the selected supply voltage.

Now I know my code should work as intended, but I was wondering if there is a more efficient way to achieve the same result, since as the way it is currently written it takes roughly 200 lines of code to achieve what I want.

For those of you who are wondering I've created a MotorSet STRUCT and a Motor STRUCT, the MotorSet STRUCT contains two Motor STRUCTs and the Motor STRUCT contains all the relevant properties (like the motor plate values and some indications) of a motor.


Solution

  • If you want to execute the same code on a large set of objects, you need to somehow place them all in an array and loop over them.

    For example:

    TYPE MotorSet :
    UNION
        Motors: ARRAY [1..2] OF Motor;
        // optional if the number of motors in the set may vary,
        //   in which case, set it during initialize, and then
        //   loop over 1 TO Count instead
        Count: USINT;
    END_UNION
    END_TYPE
    
    motorSets: ARRAY [1..3] OF MotorSet;
    
    // optional if you want to continue accessing motor sets with separate variables;
    MotorSet1: REFERENCE TO MotorSet REF= motorSets[1];
    MotorSet2: REFERENCE TO MotorSet REF= motorSets[2];
    MotorSet3: REFERENCE TO MotorSet REF= motorSets[3];
    
    // loop iterators
    i: DINT;
    j: DINT;
    
    FOR i := 1 TO 3 DO
        // if the number of motors in the set varies,
        //   use j := 1 TO motorSets[i].Count instead
        FOR j := 1 TO 2 DO
            IF motorSets[i].Motors[j].MotorVoltageDelta = 230 AND motorSets[i].Motors[j].MotorVoltageWye = 400 AND motorSets[i].Motors[j].Selected THEN
                motorSets[i].Motors[j].DeltaConnected := TRUE;
                motorSets[i].Motors[j].WyeConnected := FALSE;
            ELSIF motorSets[i].Motors[j].MotorVoltageDelta = 400 AND motorSets[i].Motors[j].MotorVoltageWye = 690 AND motorSets[i].Motors[j].Selected THEN
                motorSets[i].Motors[j].WyeConnected := TRUE;
                motorSets[i].Motors[j].DeltaConnected := FALSE;
            END_IF
        END_FOR
    END_FOR
    

    Alternatively, you could put the logic into a separate function and pass a pointer/reference to the motor:

    // motorLogicFunc accepts motor as an IN_OUT (or reference)
    
    motorLogicFunc(motor := MotorSet1.Motor1);
    motorLogicFunc(motor := MotorSet1.Motor2);
    motorLogicFunc(motor := MotorSet2.Motor1);
    // etc