MceStartStop

1.1.2

Start/stop logic for a MotoLogix system. This also implements a robot controller speed override.

For these purposes it uses two states machines:

Usage

Each MotoLogix system needs its own MceStartStop instance.

We start by creating the (global) variables for the interface data. These variables are also used for connecting buttons or an HMI.

stStartStop : ARRAY [0..GVL.MLX_UBOUND] OF MceStartStopIO; // data for start/stop of a MotoLogix system
Using a global constant to set the array size makes life easier.

Now we create the instances:

fbMceStartStop : ARRAY [0..GVL.MLX_UBOUND] OF MceStartStop;

Map all relevant inputs (see MceStartStopIO) to your HMI and/or to higher level state machines.

// this is just a portion of the relevant signals
GVL.stStartStop[0].bStart := ...;
GVL.stStartStop[0].bStop := ...;
GVL.stStartStop[0].bHoldRestart := ;
GVL.stStartStop[0].fSpeedOverride := ...;
GVL.stStartStop[0].bExternalConditionsOk := ...;

Since we defined the variables as arrays we can process the function calls in a loop:

// function call
FOR i := 0 TO GVL.MLX_UBOUND DO
  fbStartStop[i](
    io := GVL.stStartStop[i],
    MLX := GVL.stMLX[i]);
END_FOR;

Map all relevant outputs (see MceStartStopIO) to your HMI and/or to higher level state machines.

// this is just a portion of the relevant signals
... := GVL.stStartStop[0].bServoOn;
... := GVL.stStartStop[0].bIdle;
... := GVL.stStartStop[0].bHoldActive;

Version history

1.1.2

  Rioual

Changes

Changed:
  • requires MceStartStopIO data type version 0.3.0
Fixed:
  • error when enabling bFlush while the robot is moving
  • speed override value not sent to the robot controller (only relevant for Siemens)
show full history

1.1.1

  Rioual

Changes

Changed:
  • requires MceStartStopIO data type version 0.3.0
Removed:
  • input blinkSignals no longer used

1.1.0

  Rioual

Changes

Added:
  • state machine monitoring
Changed:
  • requires MceStartStopIO data type version 0.3.0
Fixed:
  • servos are no longer aborted when robot controller status takes time to update

1.0.0

  Rioual

Changes

Added:
  • reset the state machine if servos are disabled by the robot controller
  • reset after stop
Changed:
  • requires MceStartStopIO data type version 0.3.0
  • add check for system state to prevent flipping between states
  • avoid error if teach pendant key switch is not in remote mode

0.2.0

  deGroot

Changes

Changed:
  • FB names according style guide
  • don’t brutally force the state machine to 0 on lost connection

0.1.0

  deGroot

Changes

Added:
  • initial version

Overview

kindnametypedefaultcomment
in_outioMceStartStopIOinterface data
in_outMLXMLxDataMotoLogix shared memory variable

Details

Interface data for this function.

Check the data type for more information.

MLX

MLxData

The MotoLogix variable which acts as the shared memory for a MotoLogix system.

Check the YaskawaMLx library for more information.

Source code

Declarations

(*Start/stop logic + speed override*)
FUNCTION_BLOCK MceStartStop

(*
 * -----------------------------------------------------------------------------
 * Name               : MceStartStop
 * Version            : 1.1.2
 * Date               : 2025-06-05
 * Author             : Rioual
 * Family             : YaskawaMce
 * Organisation       : github.com/YaskawaEurope/mlx-examples
 * 
 * -----------------------------------------------------------------------------
 * Start/stop logic + speed override
 * -----------------------------------------------------------------------------
 *)

VAR_IN_OUT
  io : MceStartStopIO; (*interface data*)
  MLX : MLxData; (*MotoLogix shared memory variable*)
END_VAR

VAR
  fbAbort : MLxAbort;
  fbEnable : MLxEnable;
  fbReset : MLxReset;
  fbHold : MLxHold;
  fbRestart : MLxRestart;
  fbSetGlobalParameter : MLxSetGlobalParameter;
  fbStop : MLxStop;
  fbIdleTime : TON;
  fSpeedOverrideStored : REAL; (*stored value for comparison*)
  bOsrStart : BOOL; (*rising edge*)
  bOsrStop : BOOL; (*rising edge*)
  bOsrHoldRestart : BOOL; (*rising edge*)
  bOsrFlush : BOOL; (*rising edge*)
  bOsrServoOn : BOOL; (*rising edge*)
  bAllConditionsOk : BOOL; (*external- and internal conditions ok*)
  aOneShots : ARRAY [0..4] OF BOOL; (*bits for one shot signals*)
  stStateMonitoringData : ARRAY [0..1] OF MceStateMonitoringData; (*monitor the elapsed time of a state*)
END_VAR

VAR CONSTANT
  DELAY_TIME : INT := 500; (*delay time before allowing state transition*)
END_VAR

Logic

// -----------------------------------------------------------------------------
// init
// -----------------------------------------------------------------------------
io.bError := FALSE;
fbAbort.Enable := FALSE;
fbEnable.Enable := FALSE;
fbHold.Enable := FALSE;
fbReset.Enable := FALSE;
fbRestart.Enable := FALSE;
fbStop.Enable := FALSE;
fbSetGlobalParameter.Enable := FALSE;
fbIdletime.IN := FALSE;


// -----------------------------------------------------------------------------
// common
// -----------------------------------------------------------------------------
// rising edge signals
bOsrStart := io.bStart AND NOT aOneShots[0];
aOneShots[0] := io.bStart;
bOsrStop := io.bStop AND NOT aOneShots[1];
aOneShots[1] := io.bStop;
bOsrFlush:= io.bFlush AND NOT aOneShots[2];
aOneShots[2] := io.bFlush;
bOsrServoOn:= io.bServoOn AND NOT aOneShots[3];
aOneShots[3] := io.bServoOn;
bOsrHoldRestart:= io.bHoldRestart AND NOT aOneShots[4];
aOneShots[4] := io.bHoldRestart;

bAllConditionsOk :=
  io.bExternalConditionsOk AND
  MLX.Signals.MLXGatewayConnected AND
  MLX.Signals.RemoteMode AND NOT
  MLX.Signals.EStop1Pressed AND NOT
  MLX.Signals.EStop2Pressed AND NOT
  MLX.Signals.EStop3Pressed AND NOT
  MLX.Signals.GuardCircuitOpen;


// -----------------------------------------------------------------------------
// State machine: system start/stop
// -----------------------------------------------------------------------------
CASE io.nSmStartStop OF
  // -------------------------------------
  // idle, not ready for start
  // -------------------------------------
  0:
    IF bAllConditionsOk AND NOT io.bStop AND NOT io.bFlush THEN
      io.nSmStartStop := 1;
    END_IF;

  // -------------------------------------
  // ready for start
  // -------------------------------------
  1:
    IF bAllConditionsOk THEN
      // start
      IF bOsrStart THEN
        io.nErrorCode := 0;
        io.nSmStartStop := 10;
      END_IF;

      // abort if system still enabled
      // (e.g. caused by pendant operations in PLAY mode)
      IF (MLX.SystemState = 3) OR (MLX.SystemState = 4) THEN
        io.nErrorCode := 0;
        io.nSmStartStop := 70;
      END_IF;
    END_IF;

    IF NOT bAllConditionsOk OR io.bStop OR io.bFlush THEN
      io.nSmStartStop := 0;
    END_IF;

  // -------------------------------------
  // reset system with MLxReset
  // -------------------------------------
  10:
    fbReset.Enable := TRUE;
    IF fbReset.Sts_EN AND fbReset.Sts_DN THEN
      IF fbReset.Sts_ER THEN
        io.nErrorCode := 1000 + io.nSmStartStop;
        io.nSmStartStop := 70;
      ELSE
        io.nSmStartStop := 20;
      END_IF;
    END_IF;

// -------------------------------------
  // enable system with MLxEnable
  // -------------------------------------
  20:
    fbEnable.Enable := TRUE;
    IF fbEnable.Sts_EN AND fbEnable.Sts_DN AND (MLX.SystemState <> 1)
      AND (MLX.SystemState <> 2) THEN
      IF fbEnable.Sts_ER THEN
        io.nErrorCode := 1000 + io.nSmStartStop;
        io.nSmStartStop := 70;
      ELSE
        io.nSmStartStop := 30;
      END_IF;
    END_IF;

  // -------------------------------------
  // system ready for processing motion commands
  // -------------------------------------
  30:
    // Hold initiated by start button
    IF bOsrHoldRestart AND (MLX.SystemState = 4) THEN
        io.nSmStartStop := 35;
    END_IF;

    // Hold initiated by pendant button
    IF (MLX.SystemState = 6) THEN
        io.nSmStartStop := 40;
    END_IF;

    // Flush
    IF bOsrFlush THEN
      io.nSmStartStop := 50;
    END_IF;

    IF bOsrStop OR NOT bAllConditionsOk THEN
      io.nSmStartStop := 60;
    END_IF;

    IF MLX.Signals.AllDrivesDisabled AND (io.nSmStartStopTime >= DELAY_TIME) THEN
      io.nSmStartStop := 0;
    END_IF;

  // -------------------------------------
  // hold motion with MLxHold
  // -------------------------------------
  35:
    fbHold.Enable := TRUE;
    IF fbHold.Sts_EN AND fbHold.Sts_DN AND (MLX.SystemState <> 5) THEN
      IF fbHold.Sts_ER THEN
        io.nErrorCode := 1000 + io.nSmStartStop;
        io.nSmStartStop := 70;
      ELSE
        io.nSmStartStop := 40;
      END_IF;
    END_IF;

  // -------------------------------------
  // system held (restart with start button)
  // -------------------------------------
  40:
    // Restart initiated by start button
    IF bOsrHoldRestart AND (MLX.NumberOfQueuedErrors = 0) THEN
        io.nSmStartStop := 45;
    END_IF;

    // Flush
    IF bOsrFlush THEN
      io.nSmStartStop := 50;
    END_IF;

    IF bOsrStop OR NOT bAllConditionsOk THEN
      io.nSmStartStop := 60;
    END_IF;

    IF MLX.Signals.AllDrivesDisabled AND (io.nSmStartStopTime >= DELAY_TIME) THEN
      io.nSmStartStop := 0;
    END_IF;

  // -------------------------------------
  // restart motion with MLxRestart
  // -------------------------------------
  45:
    fbRestart.Enable := TRUE;
    IF fbRestart.Sts_EN AND fbRestart.Sts_DN THEN
      IF fbRestart.Sts_ER THEN
        io.nErrorCode := 1000 + io.nSmStartStop;
        io.nSmStartStop := 70;
      ELSE
        IF (MLX.SystemState <> 6) THEN
          io.nSmStartStop := 30;
        END_IF;
      END_IF;
    END_IF;

  // -------------------------------------
  // stop and flush buffered motions with MLxStop
  // -------------------------------------
  50:
    fbStop.Enable := TRUE;
    IF fbStop.Sts_EN AND fbStop.Sts_DN AND (MLX.SystemState <> 9)
      AND (MLX.SystemState <> 10) AND (MLX.SystemState <> 11) AND (MLX.SystemState <> 4) THEN
      IF fbStop.Sts_ER THEN
        io.nErrorCode := 1000 + io.nSmStartStop;
        io.nSmStartStop := 70;
      ELSE
        io.nSmStartStop := 51;
      END_IF;
    END_IF;

  // -------------------------------------
  // reset system with MLxReset
  // -------------------------------------
  51:
    fbReset.Enable := TRUE;
    IF fbReset.Sts_EN AND fbReset.Sts_DN THEN
      IF fbReset.Sts_ER THEN
        io.nErrorCode := 1000 + io.nSmStartStop;
        io.nSmStartStop := 70;
      ELSE
        io.nSmStartStop := 30;
      END_IF;
    END_IF;

  // -------------------------------------
  // finish buffered motions
  // (for future)
  // -------------------------------------
  60:
    io.nSmStartStop := 70;

  // -------------------------------------
  // abort motion and disable system with MLxAbort
  // -------------------------------------
  70:
    IF NOT MLX.Signals.MLXGatewayConnected OR NOT MLX.Signals.RemoteMode THEN
      io.nSmStartStop := 0;
    ELSE
      fbAbort.Enable := TRUE;
      IF fbAbort.Sts_EN AND fbAbort.Sts_DN AND (MLX.SystemState <> 7) THEN
        IF fbAbort.Sts_ER OR (io.nErrorCode > 0) THEN
          IF (io.nErrorCode = 0) THEN
            io.nErrorCode := 1000 + io.nSmStartStop;
          END_IF;
          io.nSmStartStop := 99;
        ELSE
          io.nSmStartStop := 0;
        END_IF;
      END_IF;
    END_IF;

  // -------------------------------------
  // state machine error
  // -------------------------------------
  99:
    io.bError := TRUE;
    io.nSmStartStop := 0;

  ELSE
    io.nSmStartStop := 0;

END_CASE;


// -----------------------------------------------------------------------------
// outputs
// -----------------------------------------------------------------------------
io.bServoOn :=
  (io.nSmStartStop = 30) OR
  (io.nSmStartStop = 35) OR
  (io.nSmStartStop = 40) OR
  (io.nSmStartStop = 45) OR
  (io.nSmStartStop = 50) OR
  (io.nSmStartStop = 51) OR
  (io.nSmStartStop = 60);

io.bIdle :=
  (io.nSmStartStop = 0) OR
  (io.nSmStartStop = 1);

io.bHoldActive := (io.nSmStartStop = 40);

// -----------------------------------------------------------------------------
// State machine: speed override
// -----------------------------------------------------------------------------
CASE io.nSmSpeedOverride OF
  // -------------------------------------
  // idle
  // -------------------------------------
  0:
    fbIdletime.IN := TRUE;
    IF fbIdletime.Q AND io.bServoOn
      AND (io.fSpeedOverride <> fSpeedOverrideStored) THEN
      fSpeedOverrideStored := io.fSpeedOverride;
      io.nErrorCode := 0;
      io.nSmSpeedOverride := 10;
    END_IF;

  // -------------------------------------
  // send speed override
  // -------------------------------------
  10:
    fbSetGlobalParameter.Enable := TRUE;
    IF fbSetGlobalParameter.Sts_EN AND fbSetGlobalParameter.Sts_DN THEN
      IF fbSetGlobalParameter.Sts_ER THEN
        io.nErrorCode := 2000 + io.nSmSpeedOverride;
        io.nSmSpeedOverride := 99;
      ELSE
        io.nSmSpeedOverride := 0;
      END_IF;
    END_IF;

  // -------------------------------------
  // state machine error
  // -------------------------------------
  99:
    io.bError := TRUE;
    io.nSmSpeedOverride := 0;

END_CASE;

// send speed override at every rising edge of system ready
IF bOsrServoOn THEN
  fSpeedOverrideStored := -1;
END_IF;

// -----------------------------------------------------------------------------
// state monitoring
// -----------------------------------------------------------------------------
io.nSmStartStopTime := MceStateMonitoring(nState := io.nSmStartStop,
                                          bFreezeTimer := io.bIdle,
                                          stateData := stStateMonitoringData[0]);
io.nSmSpeedOverrideTime := MceStateMonitoring(nState := io.nSmSpeedOverride,
                                              bFreezeTimer := (io.nSmSpeedOverride = 0),
                                              stateData := stStateMonitoringData[1]);

// -----------------------------------------------------------------------------
// FB calls
// -----------------------------------------------------------------------------
fbAbort(MLX := MLX);
fbEnable(MLX := MLX);
fbHold(MLX := MLX);
fbReset(MLX := MLX);
fbRestart(MLX := MLX);
fbStop(MLX := MLX);
fbSetGlobalParameter(
  ParameterType := 0,
  ParameterValue := LIMIT(0.0, io.fSpeedOverride, 150.0),
  MLX := MLX);
fbIdletime(PT := T#10MS);

Implementation

Snippet of the function call:
fbStartStop : ARRAY[0..0] OF MceStartStop;

fbStartStop[0]( io := dummy,  MLX := dummy );

Pages built with Hugo - 10 Dec 2025 17:29 CET