Handling manual motions for a MotoLogix system.
Whenever you need to adjust a position, teach a user frame, calibrate a tool or move the robot for maintenance some manual motions are required.
Features:
- Jog axis (joints)
- Jog TCP (cartesian motion)
- Inching axis
- Inching TCP
- Handles the switching of
MLX.JoggingMode
. - Activates the selected Tool and User Frame for cartesian jog motions.
State machines:
nSmManualMotion
- handling the manual motionnSmSettings
- update settings for cartesian motion
Usage
Usually you only need one instance of this module – even if you have multiple MotoLogix systems and/or motion devices. By using a selector on the HMI you map the manual motion module to the desired system and motion device.
If you want to be able to perform manual motions simultaneous on multiple MotoLogix systems and/or motion devices you would need to create additional instances.
Create the (global) variable for the interface data. This is also used for connecting buttons or an HMI.
stManualMotion : MceManualMotionIO; // data for manual motion of MotoLogix motion devices
Create the instance:
fbManualMotion : MceManualMotion;
Map all relevant inputs (see MceManualMotionIO
)
to your HMI and/or other programs:
// this is just a portion of the relevant signals
GVL.stManualMotion.nMlxNumber := ...;
GVL.stManualMotion.nRobotNumber := ...;
GVL.stManualMotion.nOperatingMode := ...;
GVL.stManualMotion.bSystemReady := ...;
GVL.stManualMotion.bInchingMode := ...;
GVL.stManualMotion.aJogRobotAxisNeg := ...;
GVL.stManualMotion.aJogRobotAxisPos := ...;
GVL.stManualMotion.nJogType := ...;
GVL.stManualMotion.nCoordFrame := ...;
Call the instance:
// function call
fbManualMotion(
io := GVL.stManualMotion,
UserFrames := GVL.stUserFrames[<robot selection>],
MLX := GVL.stMLX[<mlx selection>]);
Map all relevant outputs (see MceManualMotionIO
)
to your HMI and/or other programs:
// this is just a portion of the relevant signals
... := GVL.stManualMotion.bIdle;
... := GVL.stManualMotion.bBusy;
... := GVL.stManualMotion.bDone;
... := GVL.stManualMotion.aJogRobotAxisNegIndicator;
... := GVL.stManualMotion.aJogRobotAxisPosIndicator;
Version history
0.1.0
Changes
- initial version
Overview
kind | name | type | default | comment |
---|---|---|---|---|
in_out | io | MceManualMotionIO | interface data | |
in_out | userFrames | MceUserFrames | collection of user frames for this robot | |
in_out | MLX | MLxData | MotoLogix shared memory variable |
Details
Interface data for this function.
Check the data type for more information.
userFrames
MceUserFrames
Collection of user frames for this robot.
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
(*Handling the manual motion.*)
FUNCTION_BLOCK MceManualMotion
(*
* -----------------------------------------------------------------------------
* Name : MceManualMotion
* Version : 0.1.0
* Date : 2022-04-14
* Author : deGroot
* Family : YaskawaMce
* Organisation : github.com/YaskawaEurope/mlx-examples
*
* -----------------------------------------------------------------------------
* Handling the manual motion.
* -----------------------------------------------------------------------------
*)
VAR_IN_OUT
io : MceManualMotionIO; (*interface data*)
userFrames : MceUserFrames; (*collection of user frames for this robot*)
MLX : MLxData; (*MotoLogix shared memory variable*)
END_VAR
VAR
bJogPressed : BOOL; (*some jog button pressed*)
bRunJog : BOOL; (*run jog commands*)
bUseRotSpeed : BOOL; (*use rotational speed*)
aDirections : ARRAY [0..5] OF SINT; (*jog motion per axis (0=standstill, 1=positive dir, -1=negative dir)*)
bOsrRunJog : BOOL; (*rising edge*)
bOperatingModeManual : BOOL; (*operating mode: manual*)
bTcpSettingsNeedUpdate : BOOL; (*settings for TCP jog need to be updated*)
bMlxNumberChanged : BOOL; (*value has changed*)
bJogTypeChanged : BOOL; (*value has changed*)
bRobotNumberChanged : BOOL; (*value has changed*)
bCoordFrameChanged : BOOL; (*value has changed*)
bToolChanged : BOOL; (*value has changed*)
bUserFrameChanged : BOOL; (*value has changed*)
bUpdateSettingsDone : BOOL; (*update settings: done*)
bUpdateSettings : BOOL; (*start update settings*)
aOneShots : ARRAY [0..0] OF BOOL; (*bits for creating one shot signals*)
nCoordFrameSelected : USINT; (*selected value*)
nUserFrameSelected : USINT; (*selected value*)
nToolSelected : USINT; (*selected value*)
nMlxNumberSelected : USINT; (*selected value*)
nRobotNumberSelected : USINT; (*selected value*)
nJogTypeSelected : USINT; (*selected value*)
i : DINT; (*index for FOR loops*)
fbJogAxis : MLxRobotJogAxes;
fbJogTcp : MLxRobotJogTCP;
fbSelectTool : MLxRobotSelectTool;
fbSetUserFrame : MLxRobotSetUserFrame;
fbMoveAxisRel : MLxRobotMoveAxisRelative;
fbMoveLinRel : MLxRobotMoveLinearRelative;
fbIdleTime : TON;
fbCoastTime : TON;
END_VAR
VAR CONSTANT
JOGTYPE_AXIS : USINT := 0; (*jog type: axis*)
JOGTYPE_TCP : USINT := 1; (*jog type: TCP*)
INCHING_DIST_AXIS : REAL := 0.1; (*inching distance for axis jog [deg]*)
INCHING_DIST_TCP : REAL := 0.1; (*inching distance for cartesian jog [mm or deg]*)
INCHING_SPEED : REAL := 10; (*inching speed [% rated]*)
INCHING_BF : SINT := -1; (*BlendFactor for inching [-1 to 8]*)
INCHING_ACC_DEC : REAL := 80; (*acceleration/deceleration for inching [% rated]*)
END_VAR
Logic
// -----------------------------------------------------------------------------
// init
// -----------------------------------------------------------------------------
io.bError := FALSE;
fbSelectTool.Enable := FALSE;
fbSetUserFrame.Enable := FALSE;
fbJogAxis.Enable := FALSE;
fbJogTcp.Enable := FALSE;
fbMoveAxisRel.Enable := FALSE;
fbMoveLinRel.Enable := FALSE;
fbIdleTime.IN := FALSE;
fbCoastTime.IN := FALSE;
MEMUtils.MemSet(
pbyBuffer := ADR(fbJogAxis.Directions),
byValue := 0,
dwSize := SIZEOF(fbJogAxis.Directions));
MEMUtils.MemSet(
pbyBuffer := ADR(fbJogTcp.Directions),
byValue := 0,
dwSize := SIZEOF(fbJogTcp.Directions));
MEMUtils.MemSet(
pbyBuffer := ADR(fbMoveAxisRel.DeltaPosition),
byValue := 0,
dwSize := SIZEOF(fbMoveAxisRel.DeltaPosition));
MEMUtils.MemSet(
pbyBuffer := ADR(fbMoveLinRel.DeltaPosition),
byValue := 0,
dwSize := SIZEOF(fbMoveLinRel.DeltaPosition));
// -----------------------------------------------------------------------------
// common
// -----------------------------------------------------------------------------
bOperatingModeManual := (io.nOperatingMode = GVL.OP_MANUAL);
// set jogging mode as default
MLX.JoggingMode := bOperatingModeManual;
// jog speed
io.fSpeed := LIMIT(0.1, io.fSpeed, 100);
// detect changes
bMlxNumberChanged := (io.nMlxNumber <> nMlxNumberSelected);
bRobotNumberChanged := (io.nRobotNumber <> nRobotNumberSelected);
bJogTypeChanged := (io.nJogType <> nJogTypeSelected);
bCoordFrameChanged := (io.nCoordFrame <> nCoordFrameSelected);
bToolChanged := (io.nTool <> nToolSelected);
bUserFrameChanged := (io.nUserFrame <> nUserFrameSelected);
IF bMlxNumberChanged OR
bRobotNumberChanged OR
bToolChanged OR
bUserFrameChanged THEN
bTcpSettingsNeedUpdate := TRUE;
END_IF;
// -----------------------------------------------------------------------------
// jog buttons to directions pos: 1, neg: -1
// -----------------------------------------------------------------------------
bJogPressed := FALSE;
bRunJog := FALSE;
bUseRotSpeed := FALSE;
FOR i := 0 TO 5 DO
aDirections[i] := 0;
IF io.aJogRobotAxisPos[i] OR io.aJogRobotAxisNeg[i] THEN
bJogPressed := TRUE;
END_IF;
IF io.aJogRobotAxisPos[i] AND NOT io.aJogRobotAxisNeg[i] THEN
aDirections[i] := 1;
bRunJog := TRUE;
IF (nJogTypeSelected = JOGTYPE_TCP) AND (i >= 3) THEN // TCP rotation?
bUseRotSpeed := TRUE;
END_IF;
ELSIF NOT io.aJogRobotAxisPos[i] AND io.aJogRobotAxisNeg[i] THEN
aDirections[i] := -1;
bRunJog := TRUE;
IF (nJogTypeSelected = JOGTYPE_TCP) AND (i >= 3) THEN // TCP rotation?
bUseRotSpeed := TRUE;
END_IF;
END_IF;
END_FOR;
//block other axis when rotating the TCP
IF bUseRotSpeed THEN
aDirections[0] := 0;
aDirections[1] := 0;
aDirections[2] := 0;
END_IF;
bOsrRunJog := bRunJog AND NOT aOneShots[0];
aOneShots[0] := bRunJog;
// -----------------------------------------------------------------------------
// state machine 1: manual motion
// -----------------------------------------------------------------------------
CASE io.nSmManualMotion OF
// -------------------------------------
// idle, not ready for jog
// -------------------------------------
0:
IF io.bSystemReady AND bOperatingModeManual THEN
io.nErrorCode := 0;
bTcpSettingsNeedUpdate := TRUE;
io.nSmManualMotion := 10;
END_IF;
// -------------------------------------
// ready for jog
// -------------------------------------
10:
nMlxNumberSelected := io.nMlxNumber;
nRobotNumberSelected := io.nRobotNumber;
nJogTypeSelected := io.nJogType;
nCoordFrameSelected := io.nCoordFrame;
IF bOsrRunJog THEN
io.nSmManualMotion := 11;
END_IF;
IF NOT bOperatingModeManual THEN
io.nSmManualMotion := 0;
END_IF;
// -------------------------------------
// jog selection
// -------------------------------------
11:
nMlxNumberSelected := io.nMlxNumber;
nRobotNumberSelected := io.nRobotNumber;
nJogTypeSelected := io.nJogType;
nCoordFrameSelected := io.nCoordFrame;
IF bRunJog THEN
// jog axis
IF (nJogTypeSelected = JOGTYPE_AXIS) THEN
IF (io.bInchingMode) THEN
io.nSmManualMotion := 25;
ELSE
io.nSmManualMotion := 20;
END_IF;
END_IF;
// jog cartesian
IF (nJogTypeSelected = JOGTYPE_TCP) THEN
IF bTcpSettingsNeedUpdate THEN
io.nSmManualMotion := 15;
ELSE
IF (io.bInchingMode) THEN
io.nSmManualMotion := 35;
ELSE
io.nSmManualMotion := 30;
END_IF;
END_IF;
END_IF;
ELSE
io.nSmManualMotion := 10;
END_IF;
// -------------------------------------
// update TCP settings
// -------------------------------------
15:
IF bUpdateSettingsDone THEN
IF (io.bInchingMode) THEN
io.nSmManualMotion := 35;
ELSE
io.nSmManualMotion := 30;
END_IF;
END_IF;
IF bRobotNumberChanged OR bMlxNumberChanged THEN
io.nErrorCode := 1000 + io.nSmManualMotion;
io.nSmManualMotion := 99;
END_IF;
// -------------------------------------
// jog axis with MLxRobotJogAxes
// -------------------------------------
20:
FOR i := 0 TO 5 DO
fbJogAxis.Directions[i] := aDirections[i];
END_FOR;
fbJogAxis.Enable := TRUE;
IF fbJogAxis.Sts_EN AND fbJogAxis.Sts_DN THEN
IF fbJogAxis.Sts_ER THEN
io.nErrorCode := 1000 + io.nSmManualMotion;
io.nSmManualMotion := 99;
ELSE
io.nSmManualMotion := 21;
END_IF;
END_IF;
IF bRobotNumberChanged OR bMlxNumberChanged THEN
io.nErrorCode := 1000 + io.nSmManualMotion;
io.nSmManualMotion := 99;
END_IF;
// -------------------------------------
// jog axis - idle time
// -------------------------------------
21:
fbIdleTime.IN := TRUE;
fbCoastTime.IN := TRUE;
IF fbIdletime.Q THEN
IF NOT bRunJog OR
NOT bOperatingModeManual OR
bJogTypeChanged THEN
io.nSmManualMotion := 22;
ELSE
io.nSmManualMotion := 11;
END_IF;
END_IF;
// -------------------------------------
// jog axis - coasting
// -------------------------------------
22:
fbCoastTime.IN := TRUE;
IF fbCoastTime.Q THEN
io.nSmManualMotion := 50;
END_IF;
// -------------------------------------
// inch axis with MLxRobotMoveAxisRelative
// -------------------------------------
25:
FOR i := 0 TO 5 DO
fbMoveAxisRel.DeltaPosition[i] :=
(INCHING_DIST_AXIS * SINT_TO_REAL(aDirections[i]));
END_FOR;
MLX.JoggingMode := FALSE;
fbMoveAxisRel.Enable := TRUE;
IF fbMoveAxisRel.Sts_EN AND fbMoveAxisRel.Sts_DN THEN
IF fbMoveAxisRel.Sts_ER THEN
io.nErrorCode := 1000 + io.nSmManualMotion;
io.nSmManualMotion := 99;
END_IF;
IF fbMoveAxisRel.Sts_PC THEN
io.nSmManualMotion := 50;
END_IF;
END_IF;
IF bRobotNumberChanged OR bMlxNumberChanged THEN
io.nErrorCode := 1000 + io.nSmManualMotion;
io.nSmManualMotion := 99;
END_IF;
// -------------------------------------
// jog TCP with MLxRobotJogTCP
// -------------------------------------
30:
FOR i := 0 TO 5 DO
fbJogTcp.Directions[i] := aDirections[i];
END_FOR;
fbJogTcp.Enable := TRUE;
IF fbJogTcp.Sts_EN AND fbJogTcp.Sts_DN THEN
IF fbJogTcp.Sts_ER THEN
io.nErrorCode := 1000 + io.nSmManualMotion;
io.nSmManualMotion := 99;
ELSE
io.nSmManualMotion := 31;
END_IF;
END_IF;
IF bRobotNumberChanged OR bMlxNumberChanged THEN
io.nErrorCode := 1000 + io.nSmManualMotion;
io.nSmManualMotion := 99;
END_IF;
// -------------------------------------
// jog TCP - idle time
// -------------------------------------
31:
fbIdleTime.IN := TRUE;
fbCoastTime.IN := TRUE;
IF fbIdletime.Q THEN
IF NOT bRunJog OR
NOT bOperatingModeManual OR
bJogTypeChanged OR
bCoordFrameChanged OR
bToolChanged THEN
io.nSmManualMotion := 32;
ELSE
io.nSmManualMotion := 11;
END_IF;
END_IF;
// -------------------------------------
// jog TCP - coasting
// -------------------------------------
32:
fbCoastTime.IN := TRUE;
IF fbCoastTime.Q THEN
io.nSmManualMotion := 50;
END_IF;
// -------------------------------------
// inch TCP with MLxRobotMoveLinearRelative
// -------------------------------------
35:
FOR i := 0 TO 5 DO
fbMoveLinRel.DeltaPosition.TCPPosition[i] :=
(INCHING_DIST_TCP * SINT_TO_REAL(aDirections[i]));
END_FOR;
MLX.JoggingMode := FALSE;
fbMoveLinRel.Enable := TRUE;
IF fbMoveLinRel.Sts_EN AND fbMoveLinRel.Sts_DN THEN
IF fbMoveLinRel.Sts_ER THEN
io.nErrorCode := 1000 + io.nSmManualMotion;
io.nSmManualMotion := 99;
END_IF;
IF fbMoveLinRel.Sts_PC THEN
io.nSmManualMotion := 50;
END_IF;
END_IF;
IF bRobotNumberChanged OR bMlxNumberChanged THEN
io.nErrorCode := 1000 + io.nSmManualMotion;
io.nSmManualMotion := 99;
END_IF;
// -------------------------------------
// done
// -------------------------------------
50:
IF NOT bJogPressed THEN
IF io.bSystemReady AND bOperatingModeManual THEN
io.nSmManualMotion := 10;
ELSE
io.nSmManualMotion := 0;
END_IF;
END_IF;
// -------------------------------------
// state machine error
// -------------------------------------
99:
io.bError := TRUE;
IF NOT bRunJog THEN
io.nSmManualMotion := 0;
END_IF;
ELSE
io.nSmManualMotion := 0;
END_CASE;
// -----------------------------------------------------------------------------
// reset
// -----------------------------------------------------------------------------
IF NOT io.bsystemReady THEN
io.nSmManualMotion := 0;
END_IF;
// -----------------------------------------------------------------------------
// outputs
// -----------------------------------------------------------------------------
io.bIdle := (io.nSmManualMotion = 0) OR (io.nSmManualMotion = 10);
bUpdateSettings := (io.nSmManualMotion = 15);
io.bDone := (io.nSmManualMotion = 50);
io.bBusy := (io.nSmManualMotion > 10) AND (io.nSmManualMotion < 50);
io.bCoasting := (io.nSmManualMotion = 22) OR (io.nSmManualMotion = 32) ;
FOR i := 0 TO 5 DO
IF io.bBusy THEN
io.aJogRobotAxisNegIndicator[i] := io.aJogRobotAxisNeg[i];
io.aJogRobotAxisPosIndicator[i] := io.aJogRobotAxisPos[i];
END_IF;
IF NOT io.bBusy AND NOT io.bCoasting THEN
io.aJogRobotAxisNegIndicator[i] := FALSE;
io.aJogRobotAxisPosIndicator[i] := FALSE;
END_IF
END_FOR;
// -----------------------------------------------------------------------------
// state machine 2: settings
// -----------------------------------------------------------------------------
CASE io.nSmSettings OF
// -------------------------------------
// idle
// -------------------------------------
0:
IF bUpdateSettings OR
(bTcpSettingsNeedUpdate AND io.bSystemReady AND bOperatingModeManual AND io.bIdle) THEN
io.nErrorCode := 0;
io.nSmSettings := 10;
END_IF;
// -------------------------------------
// select tool
// -------------------------------------
10:
// init
MEMUtils.MemSet(
pbyBuffer := ADR(fbSelectTool.ToolData),
byValue := 0,
dwSize := SIZEOF(fbSelectTool.ToolData));
fbSelectTool.RobotNumber := io.nRobotNumber;
fbSelectTool.ToolNumber := io.nTool;
fbSelectTool.Enable := TRUE;
IF fbSelectTool.Sts_EN AND fbSelectTool.Sts_DN THEN
IF fbSelectTool.Sts_ER THEN
io.nErrorCode := 2000 + io.nSmSettings;
io.nSmSettings := 99;
ELSE
nToolSelected := io.nTool;
io.nSmSettings := 20;
END_IF;
END_IF;
// -------------------------------------
// set user frame
// -------------------------------------
20:
// init
MEMUtils.MemSet(
pbyBuffer := ADR(fbSetUserFrame.UserFrameData),
byValue := 0,
dwSize := SIZEOF(fbSetUserFrame.UserFrameData));
fbSetUserFrame.UserFrameData.CoordFrame :=
userFrames.aFrames[io.nUserFrame].aVector;
fbSetUserFrame.RobotNumber := io.nRobotNumber;
fbSetUserFrame.UserFrameNumber := io.nUserFrame;
fbSetUserFrame.Enable := TRUE;
IF fbSetUserFrame.Sts_EN AND fbSetUserFrame.Sts_DN THEN
IF fbSetUserFrame.Sts_ER THEN
io.nErrorCode := 2000 + io.nSmSettings;
io.nSmSettings := 99;
ELSE
nUserFrameSelected := io.nUserFrame;
io.nSmSettings := 30;
END_IF;
END_IF;
// -------------------------------------
// zero-distance motion with MLxRobotMoveAxisRelative (updates actual position)
// -------------------------------------
30:
// init
MEMUtils.MemSet(
pbyBuffer := ADR(fbMoveAxisRel.DeltaPosition),
byValue := 0,
dwSize := SIZEOF(fbMoveAxisRel.DeltaPosition));
MLX.JoggingMode := FALSE;
fbMoveAxisRel.Enable := TRUE;
IF fbMoveAxisRel.Sts_EN AND fbMoveAxisRel.Sts_DN THEN
IF fbMoveAxisRel.Sts_ER THEN
io.nErrorCode := 2000 + io.nSmSettings;
io.nSmSettings := 99;
END_IF;
IF fbMoveAxisRel.Sts_PC THEN
nUserFrameSelected := io.nUserFrame;
io.nSmSettings := 50;
END_IF;
END_IF;
// -------------------------------------
// done
// -------------------------------------
50:
bTcpSettingsNeedUpdate := FALSE;
IF NOT bUpdateSettings THEN
io.nSmSettings := 0;
END_IF;
// -------------------------------------
// state machine error
// -------------------------------------
99:
io.bError := TRUE;
io.nSmSettings := 0;
ELSE
io.nSmSettings := 0;
END_CASE;
// -----------------------------------------------------------------------------
// reset
// -----------------------------------------------------------------------------
IF NOT io.bsystemReady THEN
io.nSmSettings := 0;
END_IF;
// -----------------------------------------------------------------------------
// outputs
// -----------------------------------------------------------------------------
bUpdateSettingsDone := (io.nSmSettings = 50);
// -----------------------------------------------------------------------------
// FB calls
// -----------------------------------------------------------------------------
fbIdleTime(PT:=io.tIdleTime);
fbCoastTime(PT:=io.tCoastTime);
fbSelectTool( MLX := MLX );
fbSetUserFrame( MLX := MLX );
fbJogAxis(
RobotNumber := nRobotNumberSelected,
Speed := io.fSpeed,
MLX:= MLX);
fbJogTcp(
RobotNumber := nRobotNumberSelected,
Speed := io.fSpeed,
UseRotationalSpeed := bUseRotSpeed,
SpeedUnits := 0,
CoordFrame := nCoordFrameSelected,
MLX := MLX);
fbMoveAxisRel(
RobotNumber := nRobotNumberSelected,
BlendFactor := INCHING_BF,
BlendType := 0,
Speed := INCHING_SPEED,
Acceleration := INCHING_ACC_DEC,
Deceleration := INCHING_ACC_DEC,
MLX := MLX );
fbMoveLinRel(
RobotNumber := nRobotNumberSelected,
BlendFactor := INCHING_BF,
BlendType := 0,
Speed := INCHING_SPEED,
UseRotationalSpeed := bUseRotSpeed,
SpeedUnits := 0,
Acceleration := INCHING_ACC_DEC,
Deceleration := INCHING_ACC_DEC,
CoordFrame := nCoordFrameSelected,
MLX := MLX);
Implementation
fbManualMotion : ARRAY[0..0] OF MceManualMotion;
fbManualMotion[0]( io := dummy, userFrames := dummy, MLX := dummy );