Module: utilities
Basic support functions for simpler creation of Exudyn models. Advanced functions for loading and animating solutions and for drawing a graph of the mbs system. This library requires numpy (as well as time and copy)
Author: Johannes Gerstmayr
Date: 2019-07-26 (created)
Function: GetOtherMarker
GetOtherMarker(mbs
, bodyNumber
, existingMarker
, show = True
)
- function description:creates a new marker for body with bodyNumber using another marker existingMarker, such that the new marker has the same reference position as the existing marker, working for MarkerBodyPosition (no rotations included); this alleviates creation of markers and calculation of localPosition
- input:
mbs
: multibody system where new marker is added tobodyNumber
: body where new marker shall be attached toexistingMarker
: marker number which serves as a referenceshow
: if True, marker is shown - output:returns marker number of new marker
- example:
#oBody0 = mbs.CreateRigidBody(...)
#oBody1 = mbs.CreateRigidBody(...)
marker0 = mbs.AddMarker(MarkerBodyPosition(bodyNumber=oBody0,localPosition=[1,0,0]))
#create joint from one marker (with rotation) and other body
mbs.AddObject(SphericalJoint(markerNumbers=[marker0, GetOtherMarker(mbs, oBody1, marker0)]))
Relevant Examples (Ex) and TestModels (TM) with weblink to github:
NGsolveFFRF.py (Ex)
Function: GetJointArgs
GetJointArgs(mbs
, markerNumber0 = None
, markerNumber1 = None
, rotationMarker0 = None
, rotationMarker1 = None
, bodyNumber0 = None
, bodyNumber1 = None
)
- function description:creates input args for joints, based on an exiting marker (markerNumber, may be rigid or flex body), with optional existing rotationMarker and uses another rigid body (given as bodyNumber) to create a new MarkerBodyRigid and rotationMarker; this alleviates creation of joint args, see the example; inputs are either markerNumber0 [, rotationMarker0], bodyNumber1 OR markerNumber1 [, rotationMarker1], bodyNumber0
- input:
mbs
: multibody system where new marker is added tomarkerNumber0
: markerNumber of existing rigid body markermarkerNumber1
: markerNumber of existing rigid body markerrotationMarker0
: joint marker rotation matrix for markerNumber0 (must be MarkerBodyRigid)rotationMarker1
: joint marker rotation matrix for markerNumber1 (must be MarkerBodyRigid)bodyNumber0
: existing body used to create new markerbodyNumber1
: existing body used to create new marker - output:returns dict with ‘markerNumbers’ list, ‘rotationMarker0’ and ‘rotationMarker1’, ready to be used as args
- example:
#oBody0 = mbs.CreateRigidBody(...)
#oBody1 = mbs.CreateRigidBody(...)
marker0 = mbs.AddMarker(MarkerBodyRigid(bodyNumber=oBody0,localPosition=[1,0,0]))
rotM0 = RotationMatrixX(0.5*pi)
#create joint from one marker (with rotation) and other body
mbs.AddObject(RevoluteJointZ(**GetJointArgs(mbs, markerNumber0=marker0,
rotationMarker0=rotM0,
bodyNumber1=oBody1)
Relevant Examples (Ex) and TestModels (TM) with weblink to github:
jointArgsTest.py (TM)
Function: ShowOnlyObjects
ShowOnlyObjects(mbs
, objectNumbers = []
, showOthers = False
)
- function description:function to hide all objects in mbs except for those listed in objectNumbers
- input:
mbs
: mbs containing objectobjectNumbers
: integer object number or list of object numbers to be shown; if empty list [], then all objects are shownshowOthers
: if True, then all other objects are shown again - output:changes all colors in mbs, which is NOT reversible
Function: HighlightItem
HighlightItem(SC
, mbs
, itemNumber
, itemType = exudyn.ItemType.Object
, showNumbers = True
)
- function description:highlight a certain item with number itemNumber; set itemNumber to -1 to show again all objects
- input:
mbs
: mbs containing objectitemNumbers
: integer object/node/etc number to be highlighteditemType
: type of items to be highlightedshowNumbers
: if True, then the numbers of these items are shown
Function: __UFsensorDistance
__UFsensorDistance(mbs
, t
, sensorNumbers
, factors
, configuration
)
- function description:internal function used for CreateDistanceSensor
Function: CreateDistanceSensorGeometry
CreateDistanceSensorGeometry(mbs
, meshPoints
, meshTrigs
, rigidBodyMarkerIndex
, searchTreeCellSize = [8,8,8]
)
- NOTE: this function is directly available in MainSystem (mbs); it should be directly called as mbs.CreateDistanceSensorGeometry(…). For description of the interface, see the MainSystem Python extensions, Function: CreateDistanceSensorGeometry
Function: CreateDistanceSensor
CreateDistanceSensor(mbs
, generalContactIndex
, positionOrMarker
, dirSensor
, minDistance = -1e7
, maxDistance = 1e7
, cylinderRadius = 0
, selectedTypeIndex = exudyn.ContactTypeIndex.IndexEndOfEnumList
, storeInternal = False
, fileName = ''
, measureVelocity = False
, addGraphicsObject = False
, drawDisplaced = True
, color = exudyn.graphics.color.red
)
- NOTE: this function is directly available in MainSystem (mbs); it should be directly called as mbs.CreateDistanceSensor(…). For description of the interface, see the MainSystem Python extensions, Function: CreateDistanceSensor
Function: UFsensorRecord
UFsensorRecord(mbs
, t
, sensorNumbers
, factors
, configuration
)
- function description:DEPRECATED: Internal SensorUserFunction, used in function AddSensorRecorder
- notes:Warning: this method is DEPRECATED, use storeInternal in Sensors, which is much more performant; Note, that a sensor usually just passes through values of an existing sensor, while recording the values to a numpy array row-wise (time in first column, data in remaining columns)
Function: AddSensorRecorder
AddSensorRecorder(mbs
, sensorNumber
, endTime
, sensorsWritePeriod
, sensorOutputSize = 3
)
- function description:DEPRECATED: Add a SensorUserFunction object in order to record sensor output internally; this avoids creation of files for sensors, which can speedup and simplify evaluation in ParameterVariation and GeneticOptimization; values are stored internally in mbs.variables[‘sensorRecord’+str(sensorNumber)] where sensorNumber is the mbs sensor number
- input:
mbs
: mbs containing objectsensorNumber
: integer sensor number to be recordedendTime
: end time of simulation, as given in simulationSettings.timeIntegration.endTimesensorsWritePeriod
: as given in simulationSettings.solutionSettings.sensorsWritePeriodsensorOutputSize
: size of sensor data: 3 for Displacement, Position, etc. sensors; may be larger for RotationMatrix or Coordinates sensors; check this size by calling mbs.GetSensorValues(sensorNumber) - output:adds an according SensorUserFunction sensor to mbs; returns new sensor number; during initialization a new numpy array is allocated in mbs.variables[‘sensorRecord’+str(sensorNumber)] and the information is written row-wise: [time, sensorValue1, sensorValue2, …]
- notes:Warning: this method is DEPRECATED, use storeInternal in Sensors, which is much more performant; Note, that a sensor usually just passes through values of an existing sensor, while recording the values to a numpy array row-wise (time in first column, data in remaining columns)
Relevant Examples (Ex) and TestModels (TM) with weblink to github:
Function: LoadSolutionFile
LoadSolutionFile(fileName
, safeMode = False
, maxRows = -1
, verbose = True
, hasHeader = True
)
- function description:read coordinates solution file (exported during static or dynamic simulation with option exu.SimulationSettings().solutionSettings.coordinatesSolutionFileName=’…’) into dictionary:
- input:
fileName
: string containing directory and filename of stored coordinatesSolutionFilesaveMode
: if True, it loads lines directly to load inconsistent lines as well; use this for huge files (>2GB); is slower but needs less memory!verbose
: if True, some information is written when importing file (use for huge files to track progress)maxRows
: maximum number of data rows loaded, if saveMode=True; use this for huge files to reduce loading time; set -1 to load all rowshasHeader
: set to False, if file is expected to have no header; if False, then some error checks related to file header are not performed - output:dictionary with ‘data’: the matrix of stored solution vectors, ‘columnsExported’: a list with integer values showing the exported sizes [nODE2, nVel2, nAcc2, nODE1, nVel1, nAlgebraic, nData], ‘nColumns’: the number of data columns and ‘nRows’: the number of data rows
Relevant Examples (Ex) and TestModels (TM) with weblink to github:
beltDriveALE.py (Ex), beltDriveReevingSystem.py (Ex), beltDrivesComparison.py (Ex), fourBarMechanism3D.py (Ex), kinematicTreeAndMBS.py (Ex), ACFtest.py (TM), ANCFbeltDrive.py (TM), ANCFgeneralContactCircle.py (TM)
Function: NumpyInt8ArrayToString
NumpyInt8ArrayToString(npArray
)
- function description:simple conversion of int8 arrays into strings (not highly efficient, so use only for short strings)
Function: BinaryReadIndex
BinaryReadIndex(file
, intType
)
- function description:read single Index from current file position in binary solution file
Function: BinaryReadReal
BinaryReadReal(file
, realType
)
- function description:read single Real from current file position in binary solution file
Function: BinaryReadString
BinaryReadString(file
, intType
)
- function description:read string from current file position in binary solution file
Function: BinaryReadArrayIndex
BinaryReadArrayIndex(file
, intType
)
- function description:read Index array from current file position in binary solution file
Function: BinaryReadRealVector
BinaryReadRealVector(file
, intType
, realType
)
- function description:read Real vector from current file position in binary solution file
- output:return data as numpy array, or False if no data read
Function: LoadBinarySolutionFile
LoadBinarySolutionFile(fileName
, maxRows = -1
, verbose = True
)
- function description:read BINARY coordinates solution file (exported during static or dynamic simulation with option exu.SimulationSettings().solutionSettings.coordinatesSolutionFileName=’…’) into dictionary
- input:
fileName
: string containing directory and filename of stored coordinatesSolutionFileverbose
: if True, some information is written when importing file (use for huge files to track progress)maxRows
: maximum number of data rows loaded, if saveMode=True; use this for huge files to reduce loading time; set -1 to load all rows - output:dictionary with ‘data’: the matrix of stored solution vectors, ‘columnsExported’: a list with integer values showing the exported sizes [nODE2, nVel2, nAcc2, nODE1, nVel1, nAlgebraic, nData], ‘nColumns’: the number of data columns and ‘nRows’: the number of data rows
Function: RecoverSolutionFile
RecoverSolutionFile(fileName
, newFileName
, verbose = 0
)
- function description:recover solution file with last row not completely written (e.g., if crashed, interrupted or no flush file option set)
- input:
fileName
: string containing directory and filename of stored coordinatesSolutionFilenewFileName
: string containing directory and filename of new coordinatesSolutionFileverbose
: 0=no information, 1=basic information, 2=information per row - output:writes only consistent rows of file to file with name newFileName
Function: InitializeFromRestartFile
InitializeFromRestartFile(mbs
, simulationSettings
, restartFileName
, verbose = True
)
- function description:recover initial coordinates, time, etc. from given restart file
- input:
mbs
: MainSystem to be operated withsimulationSettings
: simulationSettings which is updated and shall be used afterwards for SolveDynamic(…) or SolveStatic(…)restartFileName
: string containing directory and filename of stored restart file, as given in solutionSettings.restartFileNameverbose
: False=no information, True=basic information - output:modifies simulationSettings and sets according initial conditions in mbs
Function: SetSolutionState
SetSolutionState(mbs
, solution
, row
, configuration = exudyn.ConfigurationType.Current
, sendRedrawSignal = True
)
- function description:load selected row of solution dictionary (previously loaded with LoadSolutionFile) into specific state; flag sendRedrawSignal is only used if configuration = exudyn.ConfigurationType.Visualization
Function: AnimateSolution
AnimateSolution(mbs
, solution
, rowIncrement = 1
, timeout = 0.04
, createImages = False
, runLoop = False
)
- function description:This function is not further maintaned and should only be used if you do not have tkinter (like on some MacOS versions); use exudyn.interactive.SolutionViewer() instead! AnimateSolution consecutively load the rows of a solution file and visualize the result
- input:
mbs
: the system used for animationsolution
: solution dictionary previously loaded with LoadSolutionFile; will be played from first to last rowrowIncrement
: can be set larger than 1 in order to skip solution frames: e.g. rowIncrement=10 visualizes every 10th row (frame)timeout
: in seconds is used between frames in order to limit the speed of animation; e.g. use timeout=0.04 to achieve approximately 25 frames per secondcreateImages
: creates consecutively images from the animation, which can be converted into an animationrunLoop
: if True, the animation is played in a loop until ‘q’ is pressed in render window - output:renders the scene in mbs and changes the visualization state in mbs continuously
Relevant Examples (Ex) and TestModels (TM) with weblink to github:
NGsolvePistonEngine.py (Ex), SliderCrank.py (Ex), slidercrankWithMassSpring.py (Ex), sliderCrankFloatingTest.py (TM)
Function: DrawSystemGraph
DrawSystemGraph(mbs
, showLoads = True
, showSensors = True
, useItemNames = False
, useItemTypes = False
, addItemTypeNames = True
, multiLine = True
, fontSizeFactor = 1.
, layoutDistanceFactor = 3.
, layoutIterations = 100
, showLegend = True
, tightLayout = True
)
- NOTE: this function is directly available in MainSystem (mbs); it should be directly called as mbs.DrawSystemGraph(…). For description of the interface, see the MainSystem Python extensions, Function: DrawSystemGraph
Function: CreateTCPIPconnection
CreateTCPIPconnection(sendSize
, receiveSize
, IPaddress = '127.0.0.1'
, port = 52421
, bigEndian = False
, verbose = False
)
- function description:function which has to be called before simulation to setup TCP/IP socket (server) forsending and receiving data; can be used to communicate with other Python interpretersor for communication with MATLAB/Simulink
- input:
sendSize
: number of double values to be sent to TCPIP clientreceiveSize
: number of double values to be received from TCPIP clientIPaddress
: string containing IP address of client (e.g., ‘127.0.0.1’)port
: port for communication with clientbigEndian
: if True, it uses bigEndian, otherwise littleEndian is used for byte order - output:returns information (TCPIPdata class) on socket; recommended to store this in mbs.sys[‘TCPIPobject’]
- example:
mbs.sys['TCPIPobject'] = CreateTCPIPconnection(sendSize=3, receiveSize=2,
bigEndian=True, verbose=True)
sampleTime = 0.01 #sample time in MATLAB! must be same!
mbs.variables['tLast'] = 0 #in case that exudyn makes finer steps than sample time
def PreStepUserFunction(mbs, t):
if t >= mbs.variables['tLast'] + sampleTime:
mbs.variables['tLast'] += sampleTime
tcp = mbs.sys['TCPIPobject']
y = TCPIPsendReceive(tcp, np.array([t, np.sin(t), np.cos(t)])) #time, torque
tau = y[1]
exudyn.Print('tau=',tau)
return True
try:
mbs.SetPreStepUserFunction(PreStepUserFunction)
#%%++++++++++++++++++++++++++++++++++++++++++++++++++
mbs.Assemble()
[...] #start renderer; simulate model
finally: #use this to always close connection, even in case of errors
CloseTCPIPconnection(mbs.sys['TCPIPobject'])
#*****************************************
#the following settings work between Python and MATLAB-Simulink (client), and gives stable results(with only delay of one step):
# TCP/IP Client Send:
# priority = 2 (in properties)
# blocking = false
# Transfer Delay on (but off also works)
# TCP/IP Client Receive:
# priority = 1 (in properties)
# blocking = true
# Sourec Data type = double
# data size = number of double in packer
# Byte order = BigEndian
# timeout = 10
Relevant Examples (Ex) and TestModels (TM) with weblink to github:
TCPIPexudynMatlab.py (Ex)
Function: TCPIPsendReceive
TCPIPsendReceive(TCPIPobject
, sendData
)
- function description:call this function at every simulation step at which you intend to communicate withother programs via TCPIP; e.g., call this function in preStepUserFunction of a mbs model
- input:
TCPIPobject
: the object returned by CreateTCPIPconnection(…)sendData
: numpy array containing data (double array) to be sent; must agree with sendSize - output:returns array as received from TCPIP
- example:
mbs.sys['TCPIPobject']=CreateTCPIPconnection(sendSize=2, receiveSize=1, IPaddress='127.0.0.1')
y = TCPIPsendReceive(mbs.sys['TCPIPobject'], np.array([1.,2.]))
exudyn.Print(y)
Relevant Examples (Ex) and TestModels (TM) with weblink to github:
TCPIPexudynMatlab.py (Ex)
Function: CloseTCPIPconnection
CloseTCPIPconnection(TCPIPobject
)
- function description:close a previously created TCPIP connection
Relevant Examples (Ex) and TestModels (TM) with weblink to github:
TCPIPexudynMatlab.py (Ex)
CLASS TCPIPdata (in module utilities)
class description:
helper class for CreateTCPIPconnection and for TCPIPsendReceive