Start/stop logic for a MotoLogix system. This also implements a robot controller speed override.
For these purposes it uses two states machines:
nSmStartStop- handling the start/stop (resulting in changing theMLX.systemState)nSmSpeedOverride- handling the controller speed override
Usage
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
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
Changes
- requires
MceStartStopIOdata type version0.3.0
- error when enabling
bFlushwhile the robot is moving - speed override value not sent to the robot controller (only relevant for Siemens)
show full history
1.1.1
Changes
- requires
MceStartStopIOdata type version0.3.0
- input
blinkSignalsno longer used
1.1.0
Changes
- state machine monitoring
- requires
MceStartStopIOdata type version0.3.0
- servos are no longer aborted when robot controller status takes time to update
1.0.0
Changes
- reset the state machine if servos are disabled by the robot controller
- reset after stop
- requires
MceStartStopIOdata type version0.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
Changes
- FB names according style guide
- don’t brutally force the state machine to 0 on lost connection
0.1.0
Changes
- initial version
Overview
| kind | name | type | default | comment |
|---|---|---|---|---|
| in_out | io | MceStartStopIO | interface data | |
| in_out | MLX | MLxData | MotoLogix shared memory variable |
Details
Interface data for this function.
Check the data type for more information.
MLX
MLxDataThe 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
fbStartStop : ARRAY[0..0] OF MceStartStop;
fbStartStop[0]( io := dummy, MLX := dummy );