Sequencing Design

Sequences should have a clearly defined start and end. They should always move in an increasing number order, not jump around. Skipping steps is acceptable, but they should not go backwards.

Keep in mind the following State machine. This state machine controls the operation that the sequence runs. It should be able to force the sequence to start any operation and know when the operation is complete.

Here we have defined

    LIFT_READY:
    LIFT_DONE:
    LIFT_ERROR:

as special steps that are the handshakes between the State and the Sequence

The name of the entry point of a sequence should indicate that it is a starting step. Other steps within a specific sequence should not be entered without caution.

STATE_READY:
        
    liftSequence.step =    LIFT_READY;

    if( moveTarget ){
        state = STATE_MOVE_ABSOLUTE;
        moveAbs.position = TargetPos;
    }
    else if( moveZero ){
        state = STATE_MOVE_ABSOLUTE;
        moveAbs.position = 0;
    }
    else if( executeLift ){
        state = STATE_LIFT;
    }    

STATE_MOVE_ABSOLUTE:

    // State with a fully contained function block
    // The moveAbs block is configured before entering the state
    //  by populating the position based on a command

    IF moveAbs.error THEN

        Alarm( "Motion Error!" );

        state = STATE_READY;

    ELSIF moveAbs.done THEN

        state = STATE_READY;

    ELSIF NOT moveAbs.busy THEN
        // State execution
        moveAbs.execute := TRUE;
        
    END_IF

STATE_LIFT:

    //Fully contained state, with partially contained sequence.
    //  The state is responsible for initiating a sequence.
    //  The sequence is implemented elsewhere, and ends in the DONE or ERROR step
    //  Any step other than READY, DONE or ERROR is part of the process, 
    //  and should be ignored by this state machine

    CASE liftSequence.step  OF
        LIFT_READY:

            status = "Lift Sequence Started"    
            state = STATE_READY;
            liftSequence.step = LIFT_START_SEQUENCE;

        LIFT_DONE:

            status = "Lift Sequence Finished"    
            state =                 STATE_READY;
            liftSequence.step =    LIFT_READY;

        LIFT_ERROR:

            Alarm( "Lift Sequence Errored!" );
            status = "Lift Sequence Errored"    
            state =                 STATE_READY;
            liftSequence.step =    LIFT_READY;

        DEFAULT:

            status = "Executing Lift Sequence"    

    END_IF 

...

moveTarget =    0;
moveZero =      0;
executeLift =   0;

moveAbs();
moveAbs.execute := FALSE;

Implementing the sequence

Sequences work well when defined in ACTIONS. There is some debate at to whether these actions should be called continuously or only when the action is meant to be active. I will not weigh in on that right now.

ACTION MySequence1
    CASE liftSequence.step  OF
        LIFT_SEQUENCE_MySequence1_Start:

            status = "Starting Lift Sequence 1"    

            liftSequence.step = LIFT_SEQUENCE_MySequence1_Step1

        LIFT_SEQUENCE_MySequence1_Step1:

            status = "Executing Lift Sequence 1 Step 1"    

            liftSequence.step = LIFT_SEQUENCE_MySequence1_Step2

        LIFT_SEQUENCE_MySequence1_Step2:

            status = "Executing Lift Sequence 1 Step 2"    

            liftSequence.step = LIFT_SEQUENCE_MySequence1_Step3

        LIFT_SEQUENCE_MySequence1_Step3:

            status = "Executing Lift Sequence 1 Step 3"    

            liftSequence.step = LIFT_DONE

        //These could be covered by default
        LIFT_READY,
        LIFT_DONE,
        LIFT_ERROR:
            //Do nothing        
        DEFAULT:         
            //Do nothing        
    END_IF 
END_ACTION    

ACTION MySequence2
    CASE liftSequence.step  OF
        LIFT_SEQUENCE_MySequence2_Start:

            status = "Starting Lift Sequence 2"    

            liftSequence.step = LIFT_SEQUENCE_MySequence2_Step1

        LIFT_SEQUENCE_MySequence2_Step1:

            status = "Executing Lift Sequence 2 Step 1"    

            liftSequence.step = LIFT_SEQUENCE_MySequence2_Step2

        LIFT_SEQUENCE_MySequence2_Step2:

            status = "Executing Lift Sequence 2 Step 2"    

            liftSequence.step = LIFT_SEQUENCE_MySequence2_Step3

        LIFT_SEQUENCE_MySequence2_Step3:

            status = "Executing Lift Sequence 2 Step 3"    

            liftSequence.step = LIFT_DONE

        //These could be covered by default
        LIFT_READY,
        LIFT_DONE,
        LIFT_ERROR:
            //Do nothing        
        DEFAULT:
            //Do nothing        

    END_IF 
END_ACTION