Sunteți pe pagina 1din 8

5.

7 Using Python based move preprocessors

MachSim has the capability of processing each move with a custom Python script.
You can use it to:
a) change the axis values
b) synthesize new values. (Insert new moves in the simulation)

To enable it, add a line like this to the machine .xml file:

a) for chaning axis values:


<preprocessor fileName="preprocessor.py" instance="preprocessor" />

b) for inserting new moves into the simulation:


<preprocessor fileName="preprocessor.py" instance="preprocessor" type="inserter" />

fileName is the path to python script that needs to be processed. It can be relative to machine directory or full path.
instance is the name of the python object declared in script. It will be used to process each move.
type is the type of preprocessing. When missing it is assumed that preprocessing will change axis values. When declared as
"inserter" it will insert additional moves into the simulation.

Multiple <preprocessor ../> tags may be used in xml file.

One important thing to remember is that changing axis values is done via method ProcessMove and insertion of new moves is
done via GetNewMoves nethod. The discussion further will treat methods separatelly as there are differencies in the parameters
passed to them.

5.7.1 MachSim python interpreter


MachSim does not use installed python program on the computer where it runs. Instead he is compiled with a python interpreter. In
this case it is important to validate your script with a similar version. To find out which version requires MachSim one can use the
next script (setup).

a) xml tag
<preprocessor fileName="module1.py" instance="move_filter" />

b) module1.py
#-------------------------------------------------------
import sys

class Module1:

VERSION = 1
TYPE = "move"
AXIS = []

def __init__(self):
self.count = 0
self.f = open(__file__+".log", "w+")

def ProcessMove(self, environment, operation, move):


if self.count == 0:
(major,minor,micro,release,serial) = tuple(sys.version_info)
ver = "python version {0:d}.{1:d}.{2:d}".format(major,minor,micro)
self.f.write("%s\n" % ver)
self.f.close()
self.count += 1

move_filter = Module1()
#-------------------------------------------------------

Start machine simulation, load machine definition. It should be enough to get a call to move_filter.ProcessMove.
In the machine directory look for log file module1.py.log
It may contain a string similar with: python version 2.7.1

5.7.2 Minimum requirements to change axis values (ProcessMove)


The minimum required by the MachSim python implementation is:
a) xml tag
<preprocessor fileName="module1.py" instance="move_filter" />

b) module1.py
#-------------------------------------------------------
class Module1:

VERSION = 1
TYPE = "move"
AXIS = []

def ProcessMove(self, environment, operation, move):


pass

move_filter = Module1()
#-------------------------------------------------------

VERSION is mandatory class attribute with value 1.


TYPE is mandatory class attribute with value "move".
AXIS is mandatory class attribute.
ProcessMove is mandatory class method having 4 parameters.
move_filter is mandatory object having same name as xml's instance attribute.

Obviously the script above does nothing. It just declares the minimum necessary to change axis values.

5.7.3 ProcessMove method parameters


I will use a 5AxHeadHead machine with 5 axes : X, Y, Z, C, B and a CL file to load a simple simulation and log into file
module1.py.log the parameters passed by MachSim to method ProcessMove.

The setup for python is:

a) A snippet from 5AxHeadHead.xml file with <preprocessor .../> tag

<machine_definition>
<machine_data name="5AxHeadHead" version="1.7" units="metric" />
<preprocessor fileName="module1.py" instance="move_filter" />
<axis id="X" type="translation" ...

b) module1.py
#-------------------------------------------------------
class Module1:

VERSION = 1
TYPE = "move"
AXIS = ['X','Y','Z','C','B']

def __init__(self):
self.f = open(__file__+".log", "w+")
self.count = 0
return

def DebugMove(self, environment, operation, move):


self.f.write("\ncount: %d\n" % self.count)
self.f.write("environment: %s\n" % environment)
self.f.write("operation: %s\n" % operation)
self.f.write("move: %s\n" % move)
self.f.flush()
self.count += 1

def ProcessMove(self, environment, operation, move):


self.DebugMove(environment, operation, move)
move_filter = Module1()
#-------------------------------------------------------

c) module1.py.log - the logging file with the structure of ProcessMove parameters.


#-------------------------------------------------------
environment: {'globalMoveCount': 434}

operation: {
'comment': '"Sample 5 axis operation"',
'tool': {
'comment': ('"Sample tool"',),
'number': 1,
'name': 'tool'
},
'number': 1,
'transform': {
'workpiece_transform': (1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0),
'holder_transform': (1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, -12.0, 0.0, 0.0, 0.0, 1.0)
},
'size': 434}

move: {
'simulationIndex': 121,
'axisValue': {'Y': 1.5460000038146973, 'X': -48.779998779296875, 'C': 0.0, 'Z': 18.0, 'B': 0.0},
'globalIndex': 120
}
#-------------------------------------------------------

d) ProcessMove parameters:

environment [ 'globalMoveCount' ] => total number of moves in the simulation.

operation [ 'comment' ] => current operation comment

operation [ 'tool' ] [ 'comment' ] => comment for the first tool of the current operation

operation [ 'tool' ] [ 'number' ] => number of the first tool of the current operation

operation [ 'tool' ] [ 'name' ] => name of the first tool of the current operation

operation [ 'number' ] => current operation number

operation [ 'transform' ] [ 'workpiece_transform' ] => a tuple with 16 values representing the 4x4 matrix applied to machine's
workpiece_transform.

operation [ 'transform' ] [ 'holder_transform' ] => a tuple with 16 values representing the 4x4 matrix applied to machine's
holder_transform.

operation [ 'size' ] => total number of moves of the current operation

move [ 'simulationIndex' ] => 1 based index of current move acczoss entire simulation
move [ 'globalIndex' ] = 0 based index of current move across entire simulation.

move [ 'axisValue' ] [ 'Y' ] => provide access to axis value. Changed value will be visible to machine simulation.

5.7.4 Limit machine movement on Z axis using ProcessMove method


a) xml tag
<preprocessor fileName="module1.py" instance=" preserve_axes_limit" />

b) module1.py
#-------------------------------------------------------
class Module1:
VERSION = 1
TYPE = "move"
AXIS = ['X','Y','Z','C','B']

def ProcessMove(self, environment, operation, move):


if move[ 'axisValue' ] [ 'Z' ] > 20:
move [ 'axisValue' ] [ 'Z' ] = 20.

preserve_axes_limit = Module1()
#-------------------------------------------------------

5.7.5 Minimum requirements to insert new moves (GetNewMoves)


The minimum required by the MachSim python implementation is:

a) xml tag
<preprocessor fileName="module1.py" instance="move_insert" type="inserter" />

b) module1.py
#-------------------------------------------------------
class Module1:

VERSION = 1
TYPE = "move"
AXIS = []

def GetNewMoves(self, environment, operation, currMove, nextMove):


pass

move_insert = Module1()
#-------------------------------------------------------

VERSION is mandatory class attribute with value 1.


TYPE is mandatory class attribute with value "move".
AXIS is mandatory class attribute.
GetNewMoves is mandatory class method having 5 parameters.
move_filter is mandatory object having same name as xml's instance attribute.

Obviously the script above does nothing. It just declares the minimum necessary to use insert of new values functionality. In this
mode modifing axis values of existing moves is not possible. Only isertion is possible.

5.7.6 GetNewMoves method parameters


I will use a 5AxHeadHead machine with 5 axes : X, Y, Z, C, B and a CL file to load a simple simulation and log into file
module1.py.log the parameters passed by MachSim to method GetNewMoves.

The setup for python is:

a) xml tag
<preprocessor fileName="module1.py" instance="move_insert" type="inserter" />

b) module1.py
#-------------------------------------------------------
class Module1:

VERSION = 1
TYPE = "move"
AXIS = ['X','Y','Z','C','B']

def __init__(self):
self.f = open(__file__+".log", "w+")
self.count = 0
return

def DebugMove(self, environment, operation, move, nextmove):


self.f.write("\ncount: %d\n" % self.count)
self.f.write("environment: %s\n" % environment)
self.f.write("operation: %s\n" % operation)
self.f.write("move: %s\n" % move)
self.f.write("nextmove: %s\n" % nextmove)
self.f.flush()
self.count += 1

def GetNewMoves(self, environment, operation, move, nextmove):


self.DebugMove(environment, operation, move, nextmove)

# return value object to insert 1 move


insert_move_on_origin = {
'forwardInsertion' : 0 ,
'newMovesList' : [ { 'axisValue' : { 'X' : 0, 'Y' : 0, 'Z' : 0, 'B' : 0, 'C' : 0 } } ]
}

if move [ 'relativeIndex' ] == 0:
return insert_move_on_origin

move_insert = Module1()
#-------------------------------------------------------

c) module1.py.log - the logging file with the structure of GetNewMoves parameters.


#-------------------------------------------------------
environment: { }
operation: {
'comment': '"Sample 5 axis operation"',
'tool': {
'comment': ('"Sample tool"',),
'number': 1,
'name': 'tool'
},
'number': 1,
'transform': {
'workpiece_transform': (1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0),
'holder_transform': (1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, -12.0, 0.0, 0.0, 0.0, 1.0)},
'size': 434}

move: {
'relativeIndex': 431,
'axisValue': {'Y': -6.306000232696533, 'X': -39.33300018310547, 'C': 0.0, 'Z': 14.050000190734863, 'B': 0.0}, 'time':
0.004000000189989805
}
nextmove: {
'relativeIndex': 431,
'axisValue': {'Y': -6.482999801635742, 'X': -45.29499816894531, 'C': 0.0, 'Z': 24.049999237060547, 'B': 0.0}, 'time':
0.006000000052154064
}

#-------------------------------------------------------

d) GetNewMoves parameters:

environment => empty dictionary

operation [ 'comment' ] => current operation comment

operation [ 'tool' ] [ 'comment' ] => comment for the first tool of the current operation

operation [ 'tool' ] [ 'number' ] => number of the first tool of the current operation

operation [ 'tool' ] [ 'name' ] => name of the first tool of the current operation
operation [ 'number' ] => current operation number

operation [ 'transform' ] [ 'workpiece_transform' ] => a tuple with 16 values representing the 4x4 matrix applied to machine's
workpiece_transform.

operation [ 'transform' ] [ 'holder_transform' ] => a tuple with 16 values representing the 4x4 matrix applied to machine's
holder_transform.

operation [ 'size' ] => total number of moves of the current operation

move [ 'relativeIndex' ] => 0 based index of current move across entire simulation

move [ 'axisValue' ] [ 'Y' ] => provide access to axis value. Changed value will NOT be visible to machine simulation.

move [ 'time' ] => time in seconds needed to complete this move when MachSim runs in time-base mode.

nextmove [ 'relativeIndex' ] => 0 based index of next move across entire simulation

nextmove [ 'axisValue' ] [ 'Y' ] => provide access to axis value. Changed value will NOT be visible to machine simulation.

nextmove [ 'time' ] => time in seconds needed to complete next move when MachSim runs in time-base mode.

insert_move_on_origin [ 'forwardInsertion' ] => 1 to insert move after current move or 0 to insert move before current move

insert_move_on_origin [ 'newMovesList' ] => list with the new moves to be inserted

insert_move_on_origin [ 'newMovesList' ] [ 0 ] [ 'axisValue' ] [ 'X' ] => X value for a new move at position 0 in list.

5.7.7 Insert 2 moves at the beginning of simulation using GetNewMoves method


a) xml tag:
<preprocessor fileName="module1.py" instance="insert_new_moves" type="inserter" />

b) module1.py
#-------------------------------------------------------
class Module1:

VERSION = 1
TYPE = "move"
AXIS = ['X','Y','Z','C','B']

def __init__(self):
self.insert_moves_from_machine_origin = {
'forwardInsertion': 0,
'newMovesList': [{'axisValue': {'X':500, 'Y':500, 'Z':900, 'B':0, 'C':0} },
{'axisValue': {'X':500, 'Y':500, 'Z':850, 'B':0, 'C':0} }
]}

def GetNewMoves(self, environment, operation, move, nextmove):


if move[ 'relativeIndex' ] == 0:
return self.insert_moves_from_machine_origin

insert_new_moves = Module1()
#-------------------------------------------------------

5.7.8 Sample of a real-life preprocessing script


The following script automatically closes and opens the machine doors at the start/end of the simulation and spins a warning light.
Also, all of the axis values and operation properties are logged to a file with the same name but with the .log extension.
import time
from math import *

LOGGING_ENABLED = True

LOG_FILE = __file__.replace(".py", ".log")

def Log(text):
if LOGGING_ENABLED:
f = open(LOG_FILE, "a+t")
f.write(text)
f.close()

def LogMove(operation, move):


if LOGGING_ENABLED:
Log("operation=%r, move=%r\n" % (operation, move))

class DoorClosePreprocessorBase(object):

def __init__(self, axisName, closedValue, openedValue, stepsToClose):


self.__axisName = axisName
self.__closedValue = closedValue
self.__openedValue = openedValue
self.__stepsToClose = stepsToClose
self.__moveScale = (self.__closedValue - self.__openedValue) / self.__stepsToClose

def ProcessMove(self, environment, operation, move):


globalIndex = move["globalIndex"]
globalMoveCount = environment["globalMoveCount"]
if globalIndex <= self.__stepsToClose:
value = self.__openedValue + globalIndex * self.__moveScale
else:
threshold = globalMoveCount - self.__stepsToClose - 1
if globalIndex >= threshold:
value = self.__closedValue - (globalIndex - threshold) * self.__moveScale
else:
value = self.__closedValue
move["axisValue"][self.__axisName] = value

class DoorClosePreprocessor(object):

VERSION = 1
TYPE = "move"
AXIS = ["LH-Door", "RH-Door"]

def __init__(self):
stepsToClose = 50
self.__leftDoor = DoorClosePreprocessorBase("LH-Door", 0.0, -499.0, stepsToClose)
self.__rightDoor = DoorClosePreprocessorBase("RH-Door", 0.0, 499.0, stepsToClose)

def ProcessMove(self, environment, operation, move):


LogMove(operation, move)
self.__leftDoor.ProcessMove(environment, operation, move)
self.__rightDoor.ProcessMove(environment, operation, move)

class WarningLightPreprocessor(object):

VERSION = 1
TYPE = "move"
AXIS = ["Light"]

def ProcessMove(self, environment, operation, move):


LogMove(operation, move)
move["axisValue"]["Light"] = (move["globalIndex"] * 5.0) % 360.0

doorClosePreprocessor = DoorClosePreprocessor()
warningLightPreprocessor = WarningLightPreprocessor()
Log("Preprocessor module imported - %s\n" % time.strftime("%a, %d %B %Y, %H:%M:%S"))

S-ar putea să vă placă și