Skip to content

Example Stations

While XTS is constantly being used in more complex and interesting ways, many applications are relatively basic: a closed loop with various "stations" along the track where movers need to stop and be worked on. To compensate for differences in the cycle times of these various station processes, intermediate positions are typically specified between these stations where movers can line up and wait for the next station to be free.

The SPT_XTS library contains some example implementations of station logic. These function blocks can be "plugged in" directly to FB_Component_XPU and used as-is, or can be easily copied and modified to implement custom application-specific logic.

FB_XTS_QueueStation

(FINAL, extends FB_XTS_StationBase)

A queue station will always accept movers from an upstream station, as long as the number of currently assigned movers doesn't exceed MaxNumberOfMovers. Upon accepting a new mover, it is commanded to move to the first Stop Position (any other defined stop positions are ignored) using the dynamics specified in the station configuration.

When the downstream station is ready for movers (CanAcceptMovers property = TRUE) the first mover in the buffer is immediately released from the QueueStation and passed to the downstream station. It's possible that this condition is satisfied before the mover ever arrives at the QueueStation; it could even happen in the same PLC scan where the mover was accepted by the QueueStation. In this case, the mover will not stop at the QueueStation's Stop Position.

Properties

Property Type Access Description
MaxNumberOfMovers UDINT RW Get/Set the maximum number of movers that can be in a queue at a time

Overriding FB_XTS_StationBase

While much of the logic built in to FB_XTS_StationBase is reused, a few things were overridden and modified to create the queue.

CanAcceptMover

(from I_XTS_ApplicationStation)

Queues need to accept incoming movers as long as there is room for them:

CanAcceptMover := NumberOfAssignedMovers < _MaxNumberOfMovers;

CanReleaseMover

(from I_XTS_ApplicationStation)

Queues can always release movers as long as it has one to release:

CanReleaseMover := NumberOfAssignedMovers > 0;

Resetting()

(from FB_PackML_BaseModule)

The base Resetting() logic sends movers to discrete positions according to the Stop Positions configured. Queues will only send movers to the first Stop Position, allowing collision avoidance to maintain a suitable gap between them:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
METHOD PROTECTED Resetting

// Need a copy of .Queue so we can index through array
ipMovers := MoverQueue.Queue;
CASE SequenceState OF
    0:
        _Busy := TRUE;
        MoverTracker.Clear();
        SequenceState := SequenceState + 10;

    10:
        //Determine if any movers have been assigned to this station
        IF NumberOfAssignedMovers <> 0 THEN
            SequenceState := 100;
        ELSE
            SequenceState := 1000;
        END_IF

    100:
        MoverTracker.Clear();
        FOR i := 1 TO NumberOfAssignedMovers DO
            IF ipMovers[i] <> 0 THEN
                IF NOT ipMovers[i].Busy THEN
                    //Queue stations always command movers to position 1
                    StopPosition := StopPositions[1];
                    StopPosition := GetStopPosition(StopPosition);
                    IF ipMovers[i].MoveAbsoluteCA(StopPosition, TRUE, RecoveryMoveComplete) THEN
                        MoverTracker.Set(i);
                    END_IF
                END_IF
            END_IF
        END_FOR

        IF MoverTracker.NumberCompleted = NumberOfAssignedMovers THEN
            RecoveryMoveComplete := TRUE;
            SequenceState        := 1000;
        END_IF

    1000:
        _Busy := FALSE;
        SUPER^.Resetting();
END_CASE

Execute()

(from FB_PackML_BaseModule)

There is no Execute() logic defined in the base station; that is left up to the application developer. In the case of a queue, the process in Execute() is to take ownership of a mover from the upstream station and command it to move to the first Stop Position. There is no additional state machine required; as long as queues are in the Execute state, they are constantly pulling movers from the upstream station.

1
2
3
METHOD PROTECTED Execute

GetMovers();

GetMovers()

(from FB_XTS_StationBase)

GetMovers() is a helper method which asks the associated InfoStation for a mover and then commands the mover to the first Stop Position. The actual logic for passing the mover's interface pointer from one station to the next is internal to the InfoStation. The application need only call GetMover() on the InfoStation and wait for the return value TRUE, at which point the new mover will be available in MoverQueue.LastMover.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
METHOD PROTECTED GetMovers : BOOL

CASE SequenceState OF
    0:
        //Don't combine this with state 20 -- there is a dead scan for method cleanup/returns
        IF CanAcceptMover THEN
            SequenceState := SequenceState + 10;
        END_IF

    10:
        IF ipInfoStation.GetMover() THEN
            // Ask for a new mover      
            SequenceState := SequenceState + 10;
        END_IF

    20:
        //Make sure we don't page fault
        IF MoverQueue.LastMover <> 0 THEN
            // Call new mover to this station--use only stop position 1
            StopPosition := StopPositions[1];
            StopPosition := GetStopPosition(StopPosition);
            IF MoverQueue.LastMover.MoveAbsoluteCA(StopPosition, TRUE, FALSE) THEN
                SequenceState := 0;
            END_IF
        ELSE
            SequenceState := 0;
        END_IF
END_CASE

FB_XTS_SimpleStation

(FINAL, extends FB_XTS_StationBase)

SimpleStations have one or many Stop Positions defined by the XTS Configurator. The number of Stop Positions dictates how many movers the station will accept at a time. A simple state machine is implemented:

  • GetMovers will ask the upstream station for movers until there is one mover for each Stop Position in the buffer and they have all arrived at their assigned Stop Position.
  • InProcess starts a timer that simulates the cycle time of a station's intended process
  • ReleaseMovers signals to the downstream station that movers are available and sends them along as requested

Tip

For many applications, the logic in FB_XTS_SimpleStation is adequate with the exception of the simulated process timer. This was the design intent of FB_XTS_StationBase. By simply extending FB_XTS_StationBase and overriding Execute(), many different application-specific station types can be developed without having to re-write code.

Properties

Property Type Access Description
SimulatedProcessTime TIME RW Get/Set the preset time for the process simulation timer

Overriding FB_XTS_StationBase

Execute()

(from FB_PackML_BaseModule)

There is no Execute() logic defined in the base station; that is left up to the application developer. SimpleStations employ a basic state machine. The GetMovers() method will return TRUE when all required movers have been acquired and are in position ready to be processed. Note that GetMovers() is defined in FB_XTS_StationBase and is unchanged in SimpleStations.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
METHOD PROTECTED Execute

CASE StationState OF
    E_ApplicationStationState.eApplicationStationState_GetMovers:
        IF NOT _DisableStation THEN
            IF GetMovers() THEN
                StationState := E_ApplicationStationState.eApplicationStationState_InProcess;
            END_IF
        END_IF

    E_ApplicationStationState.eApplicationStationState_InProcess:
        ProcessSimulationTimer_TON(IN := NOT _Pause);
        IF ProcessSimulationTimer_TON.Q THEN
            ProcessSimulationTimer_TON(IN := FALSE);
            StationState := E_ApplicationStationState.eApplicationStationState_ReleaseMovers;
        END_IF

    E_ApplicationStationState.eApplicationStationState_ReleaseMovers:
        IF (NumberOfAssignedMovers = 0) THEN
            // Downstream station has accepted all of our movers
            StationState := E_ApplicationStationState.eApplicationStationState_GetMovers;
        END_IF
END_CASE