```{raw} latex \clearpage ``` (sec-item-objectconnectorrigidbodyspringdamper)= # ObjectConnectorRigidBodySpringDamper An 3D spring-damper element acting on relative displacements and relative rotations of two rigid body (position+orientation) markers. It represents a penalty-based rigid joint (or prismatic, revolute, etc.) ```{image} /docs/figures/itemImages/ObjectConnectorRigidBodySpringDamper.png :width: 500 ``` **Simpler**: [`mbs.CreateRigidBodySpringDamper`](#sec-mainsystemextensions-createrigidbodyspringdamper) adds this item, with what it needs, in one call. ## Interface - Python names: `ObjectConnectorRigidBodySpringDamper` or `RigidBodySpringDamper`, and `VRigidBodySpringDamper` for its visualization - Nodes it takes: [](#sec-item-nodegenericdata) - Markers it acts on: those providing `Position` and `Orientation`: [](#sec-item-markerbodyrigid), [](#sec-item-markernoderigid), [](#sec-item-markersuperelementrigid), [](#sec-item-markerkinematictreerigid) ## Parameters The parameters of the item; in a dictionary, its type is 'ConnectorRigidBodySpringDamper': | name | type | size | default | description | |---|---|---|---|---| | **name** | String | | '' | connector's unique name | | **markerNumbers** | ArrayMarkerIndex | | [ invalid (-1), invalid (-1) ] | list of markers used in connector | | **nodeNumber** | NodeIndex | | invalid (-1) | (symbol: $n_d$) node number of a NodeGenericData (size depends on application) for dataCoordinates for user functions (e.g., implementing contact/friction user function) | | **stiffness** | Matrix6D | 36 | np.zeros((6,6)) | stiffness [SI:N/m or Nm/rad] of translational, torsional and coupled springs; act against relative displacements in x, y, and z-direction as well as the relative angles (calculated as Euler angles); in the simplest case, the first 3 diagonal values correspond to the local stiffness in x,y,z direction and the last 3 diagonal values correspond to the rotational stiffness around x,y and z axis | | **damping** | Matrix6D | 36 | np.zeros((6,6)) | damping [SI:N/(m/s) or Nm/(rad/s)] of translational, torsional and coupled dampers; very similar to stiffness, however, the rotational velocity is computed from the angular velocity vector | | **rotationMarker0** | Matrix3D | 9 | [[1,0,0], [0,1,0], [0,0,1]] | local rotation matrix for marker 0; stiffness, damping, etc. components are measured in local coordinates relative to rotationMarker0 | | **rotationMarker1** | Matrix3D | 9 | [[1,0,0], [0,1,0], [0,0,1]] | local rotation matrix for marker 1; stiffness, damping, etc. components are measured in local coordinates relative to rotationMarker1 | | **offset** | Vector6D | 6 | [0.,0.,0.,0.,0.,0.] | translational and rotational offset considered in the spring force calculation | | **useIntrinsicFormulation** | Bool | | False | if True, the joint uses the intrinsic formulation, which is independent on order of markers, using a mid-point and mid-rotation for evaluation and application of connector forces and torques; this uses a Lie group formulation; in this case, the force/torque vector is computed from the stiffness matrix times the 6-vector of the SE3 matrix logarithm between the two marker positions/rotations, see the equations | | **activeConnector** | Bool | | True | flag, which determines, if the connector is active; used to deactivate (temporarily) a connector or constraint | | **springForceTorqueUserFunction** | ObjectConnectorRigidBodySpringDamperSpringForceTorqueUserFunction | | 0 | (symbol: $\mathrm{UF} \in \Rcal^6$) A Python function which computes the 6D force-torque vector (3D force + 3D torque) between the two rigid body markers, if activeConnector=True; see description below | | **postNewtonStepUserFunction** | ObjectConnectorRigidBodySpringDamperPostNewtonStepUserFunction | | 0 | (symbol: $\mathrm{UF}_{PN} \in \Rcal$) A Python function which computes the error of the PostNewtonStep; see description below | | **visualization** | VObjectConnectorRigidBodySpringDamper | | | parameters for visualization of item | Renamed parameters, still taken with a `DeprecationWarning`: `intrinsicFormulation` (deprecated since 1.12.258, removed in 2031): use `useIntrinsicFormulation`. Deprecated parameters, which still work and give a `DeprecationWarning` when set other than their default: `rotationMarker0` (deprecated since 1.12.244, removed in 2031): give the rotation to marker 0 as its localHT, e.g. MarkerBodyRigid(bodyNumber=b, localHT=exu.HT(rotation=A, translation=p)); `rotationMarker1` (deprecated since 1.12.244, removed in 2031): give the rotation to marker 1 as its localHT, e.g. MarkerBodyRigid(bodyNumber=b, localHT=exu.HT(rotation=A, translation=p)). ## Visualization parameters The parameters of `VObjectConnectorRigidBodySpringDamper`, given as `visualization`: | name | type | size | default | description | |---|---|---|---|---| | **show** | Bool | | True | set true, if item is shown in visualization and false if it is not shown | | **drawSize** | float | | -1. | drawing size = diameter of spring; size == -1.f means that default connector size is used | | **color** | Float4 | 4 | [-1.,-1.,-1.,-1.] | RGBA connector color; if R==-1, use default color | ## Drawing Drawn as [all connectors](#sec-drawing-objectsconnector); a sphere of diameter `drawSize` at each marker and a cylinder between them; with `connectors.showJointAxes` the frames of both markers. Settings beyond those of all connectors: [`connectors.jointAxesLength`](#sec-vsettingsconnectors), [`connectors.jointAxesRadius`](#sec-vsettingsconnectors), [`connectors.showJointAxes`](#sec-vsettingsconnectors), [`general.axesTiling`](#sec-vsettingsgeneral), [`general.cylinderTiling`](#sec-vsettingsgeneral), [`general.sphereTiling`](#sec-vsettingsgeneral). ## Output variables Available as `OutputVariableType` in sensors, `Get...Output()` and other functions: ```{tabularcolumns} \Y{0.25}\Y{0.25}\Y{0.5} ``` | output variable | symbol | description | |---|---|---| | DisplacementLocal | $\LU{J0}{\Delta\pv}$ | relative displacement in local joint0 coordinates | | Displacement | $\LU{0}{\pv}_{m1} - \LU{0}{\pv}_{m0}$ | global vector from marker m0 to marker m1 | | HomogeneousTransformationLocal | $\LU{J0}{\Hm}_{J1} = \LU{0}{\Hm}_{J0}^{-1}\,\LU{0}{\Hm}_{J1}$ | the joint frame $J1$ relative to the joint frame $J0$: the relative rotation matrix $\LU{0}{\Rot}_{J0}\tp\LU{0}{\Rot}_{J1}$ and the relative position $\LU{0}{\Rot}_{J0}\tp(\LU{0}{\pv}_{m1}-\LU{0}{\pv}_{m0})$; for a joint the identity up to its free axes and its drift; returned and stored as HomogeneousTransformation | | VelocityLocal | $\LU{J0}{\Delta\vv}$ | relative translational velocity in local joint0 coordinates | | Rotation | $\LU{J0}{\ttheta}= [\theta_0,\theta_1,\theta_2]\tp$ | relative rotation parameters (Tait Bryan Rxyz); these are the angles used for calculation of joint torques (e.g. if cX is the diagonal rotational stiffness, the moment for axis X reads mX=cX*phiX, etc.) | | AngularVelocityLocal | $\LU{J0}{\Delta\tomega}$ | relative angular velocity in local joint0 coordinates | | ForceLocal | $\LU{J0}{\fv}$ | joint force in local joint0 coordinates | | TorqueLocal | $\LU{J0}{\mv}$ | joint torque in in local joint0 coordinates | | PotentialEnergy | $V = \frac{1}{2} (\uv - \uv_\mathrm{off})\tp \Km\, (\uv - \uv_\mathrm{off})$ | with the six relative displacements and rotations $\uv$ in the joint frame, as the force law uses them - conserved exactly only for small rotations; zero if not active; raises for a springForceTorqueUserFunction | (description-objectconnectorrigidbodyspringdamper)= ## Detailed description ### Definition of quantities | input parameter | symbol | description | |---|---|---| | stiffness | $\kv \in \mathbb{R}^{6\times 6}$ | stiffness in $J0$ coordinates | | damping | $\dv \in \mathbb{R}^{6\times 6}$ | damping in $J0$ coordinates | | offset | $\LUR{J0}{\vv}{\mathrm{off}} \in \mathbb{R}^{6}$ | offset in $J0$ coordinates | | rotationMarker0 | $\LU{m0,J0}{\Rot}$ | rotation matrix which transforms from joint 0 into marker 0 coordinates | | rotationMarker1 | $\LU{m1,J1}{\Rot}$ | rotation matrix which transforms from joint 1 into marker 1 coordinates | | markerNumbers[0] | $m0$ | global marker number m0 | | markerNumbers[1] | $m1$ | global marker number m1 | | intermediate variables | symbol | description | |---|---|---| | marker m0 position | $\LU{0}{\pv}_{m0}$ | current global position which is provided by marker m0 | | marker m0 orientation | $\LU{0,m0}{\Rot}$ | current rotation matrix provided by marker m0 | | marker m1 position | $\LU{0}{\pv}_{m1}$ | accordingly | | marker m1 orientation | $\LU{0,m1}{\Rot}$ | current rotation matrix provided by marker m1 | | marker m0 velocity | $\LU{0}{\vv}_{m0}$ | current global velocity which is provided by marker m0 | | marker m1 velocity | $\LU{0}{\vv}_{m1}$ | accordingly | | marker m0 velocity | $\LU{m0}{\tomega}_{m0}$ | current local angular velocity vector provided by marker m0 | | marker m1 velocity | $\LU{m1}{\tomega}_{m1}$ | current local angular velocity vector provided by marker m1 | | Displacement | $\LU{0}{\Delta\pv}$ | $\LU{0}{\pv}_{m1} - \LU{0}{\pv}_{m0}$ | | Velocity | $\LU{0}{\Delta\vv}$ | $\LU{0}{\vv}_{m1} - \LU{0}{\vv}_{m0}$ | | DisplacementLocal | $\LU{J0}{\Delta\pv}$ | $\left(\LU{0,m0}{\Rot}\LU{m0,J0}{\Rot}\right)\tp \LU{0}{\Delta\pv}$ | | VelocityLocal | $\LU{J0}{\Delta\vv}$ | $\left(\LU{0,m0}{\Rot}\LU{m0,J0}{\Rot}\right)\tp \LU{0}{\Delta\vv}$ | | AngularVelocityLocal | $\LU{J0}{\Delta\tomega}$ | $\left(\LU{0,m0}{\Rot}\LU{m0,J0}{\Rot}\right)\tp \left( \LU{0,m1}{\Rot} \LU{m1}{\tomega} - \LU{0,m0}{\Rot} \LU{m0}{\tomega} \right)$ | ### Connector forces If `activeConnector = True`, the vector spring force is computed as $$ \vp{\LU{J0}{\fv_{SD}}}{\LU{J0}{\mv_{SD}}} = \kv \left( \vp{\LU{J0}{\Delta\pv}}{\LU{J0}{\ttheta}} - \LUR{J0}{\vv}{\mathrm{off}}\right) + \dv \vp{\LU{J0}{\Delta\vv}}{\LU{J0}{\Delta\omega}} $$ For the application of joint forces to markers, $[\LU{J0}{\fv_{SD}},\,\LU{J0}{\mv_{SD}}]\tp$ is transformed into global coordinates. if `activeConnector = False`, $\LU{J0}{\fv_{SD}}$ and $\LU{J0}{\mv_{SD}}$ are set to zero. If the springForceTorqueUserFunction $\mathrm{UF}$ is defined and `activeConnector = True`, $\fv_{SD}$ instead becomes ($t$ is current time) $$ \fv_{SD} = \mathrm{UF}(mbs, t, i_N, \LU{J0}{\Delta\pv}, \LU{J0}{\ttheta}, \LU{J0}{\Delta\vv}, \LU{J0}{\Delta\tomega}, \mathrm{stiffness}, \mathrm{damping}, \mathrm{rotationMarker0}, \mathrm{rotationMarker1}, \mathrm{offset}) $$ and `iN` represents the itemNumber (=objectNumber). **Userfunction**: `springForceTorqueUserFunction(mbs, t, itemNumber, displacement, rotation, velocity, angularVelocity, stiffness, damping, rotJ0, rotJ1, offset)` A user function, which computes the 6D spring-damper force-torque vector depending on mbs, time, local quantities (displacement, rotation, velocity, angularVelocity, stiffness), which are evaluated at current time, which are relative quantities between both markers and which are defined in joint J0 coordinates. As relative rotations are defined by Tait-Bryan rotation parameters, it is recommended to use this connector for small relative rotations only (except for rotations about one axis). Furthermore, the user function contains object parameters (stiffness, damping, rotationMarker0/1, offset). Note that itemNumber represents the index of the object in mbs, which can be used to retrieve additional data from the object through `mbs.GetObjectParameter(itemNumber, ...)`, see the according description of `GetObjectParameter`. Detailed description of the arguments and local quantities: | arguments / return | type or size | description | |---|---|---| | `mbs` | MainSystem | provides MainSystem mbs in which underlying item is defined | | `t` | Real | current time in mbs | | `itemNumber` | Index | integer number $i_N$ of the object in mbs, allowing easy access to all object data via mbs.GetObjectParameter(itemNumber, ...) | | `displacement` | Vector3D | $\LU{J0}{\Delta\pv}$ | | `rotation` | Vector3D | $\LU{J0}{\ttheta}$ | | `velocity` | Vector3D | $\LU{J0}{\Delta\vv}$ | | `angularVelocity` | Vector3D | $\LU{J0}{\Delta\tomega}$ | | `stiffness` | Matrix6D | copied from object | | `damping` | Matrix6D | copied from object | | `rotJ0` | Matrix3D | rotationMarker0 copied from object | | `rotJ1` | Matrix3D | rotationMarker1 copied from object | | `offset` | Vector6D | copied from object | | **return value** | Vector6D | list or numpy array of computed spring force-torque | *Example*: ```python #define simple force for spring-damper: def UFforce(mbs, t, itemNumber, displacement, rotation, velocity, angularVelocity, stiffness, damping, rotJ0, rotJ1, offset): k = stiffness #passed as list u = displacement return [u[0]*k[0][0],u[1]*k[1][1],u[2]*k[2][2], 0,0,0] #markerNumbers and parameters taken from mini example mbs.AddObject(RigidBodySpringDamper(markerNumbers = [mGround, mBody], stiffness = np.diag([k,k,k, 0,0,0]), damping = np.diag([0,k*0.01,0, 0,0,0]), offset = [0,0,0, 0,0,0], springForceTorqueUserFunction = UFforce)) ``` **Userfunction**: `postNewtonStepUserFunction(mbs, t, itemNumber, dataCoordinates, displacement, rotation, velocity, angularVelocity, stiffness, damping, rotJ0, rotJ1, offset)` A user function which computes the error of the PostNewtonStep $\varepsilon_{PN}$, a recommended for stepsize reduction $t_{recom}$ (use values > 0 to recommend step size or values < 0 else; 0 gives minimum step size) and the updated dataCoordinates $\dv^k$ of `NodeGenericData` $n_d$. Except from `dataCoordinates`, the arguments are the same as in `springForceTorqueUserFunction`. The `postNewtonStepUserFunction` should be used together with the dataCoordinates in order to implement a active set or switching strategy for discontinuous events, such as in contact, friction, plasticity, fracture or similar. Detailed description of the arguments and local quantities: | arguments / return | type or size | description | |---|---|---| | `mbs` | MainSystem | provides MainSystem mbs in which underlying item is defined | | `t` | Real | current time in mbs | | `itemNumber` | Index | integer number $i_N$ of the object in mbs, allowing easy access to all object data via mbs.GetObjectParameter(itemNumber, ...) | | `dataCoordinates` | Vector | $\dv^{k-1} = [d_0^{k-1},\; d_1^{k-1},\; \ldots]$ for previous post Newton step $k-1$ | | `displacement` | Vector3D | $\LU{J0}{\Delta\pv}$ | | `rotation` | Vector3D | $\LU{J0}{\ttheta}$ | | `velocity` | Vector3D | $\LU{J0}{\Delta\vv}$ | | `angularVelocity` | Vector3D | $\LU{J0}{\Delta\tomega}$ | | `stiffness` | Matrix6D | copied from object | | `damping` | Matrix6D | copied from object | | `rotJ0` | Matrix3D | rotationMarker0 copied from object | | `rotJ1` | Matrix3D | rotationMarker1 copied from object | | `offset` | Vector6D | copied from object | | **return value** | Vector | $\left[\varepsilon_{PN},\; t_{recom},\; d_0^{k},\; d_1^{k}, ...\right]$ where $k$ indicates the current step | (miniexample-objectconnectorrigidbodyspringdamper)= ## Mini example ```python #example with rigid body at [0,0,0], 1kg under initial velocity k=500 nBody = mbs.AddNode(RigidRxyz(initialVelocities=[0,1e3,0, 0,0,0])) oBody = mbs.AddObject(RigidBody(mass=1, inertia=[1,1,1,0,0,0], nodeNumber=nBody)) mBody = mbs.AddMarker(MarkerNodeRigid(nodeNumber=nBody)) mGround = mbs.AddMarker(MarkerBodyRigid(bodyNumber=oGround, localPosition = [0,0,0])) mbs.AddObject(RigidBodySpringDamper(markerNumbers = [mGround, mBody], stiffness = np.diag([k,k,k, 0,0,0]), damping = np.diag([0,k*0.01,0, 0,0,0]), offset = [0,0,0, 0,0,0])) #assemble and solve system for default parameters mbs.Assemble() mbs.SolveDynamic(exu.SimulationSettings()) #check result at default integration time exu.sys['testResult'] = mbs.GetNodeOutput(nBody, exu.OutputVariableType.Displacement)[1] ``` Examples (Ex) and TestModels (TM) that show this item, with weblink to github: [`connectorRigidBodySpringDamperTest.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/TestModels/connectorRigidBodySpringDamperTest.py) (TM), [`rigidBodySpringDamperIntrinsic.py`](https://github.com/jgerstmayr/EXUDYN/blob/master/python/TestModels/rigidBodySpringDamperIntrinsic.py) (TM)