ObjectContactCurveCircles
A contact model between a curve defined by piecewise segments and a set of circles. The 2D curve may corotate in 3D with the underlying marker and also defines the plane of action for the circles. [REQUIRES FURTHER TESTING]
Interface
Python names:
ObjectContactCurveCirclesorCamFollowerContactPlanar, andVCamFollowerContactPlanarfor its visualizationNodes it takes: NodeGenericData
Markers it acts on: those providing
PositionandOrientation: MarkerBodyRigid, MarkerNodeRigid, MarkerSuperElementRigid, MarkerKinematicTreeRigid
Parameters
The parameters of the item; in a dictionary, its type is ‘ContactCurveCircles’:
name |
type |
size |
default |
description |
|---|---|---|---|---|
name |
String |
‘’ |
constraints’s unique name |
|
markerNumbers |
ArrayMarkerIndex |
2 |
[ invalid (-1), invalid (-1) ] |
(symbol: \([m0,m_{c0},m_{c1},\ldots]\tp\)) list of \(n_c+1\) markers; marker \(m0\) represents the marker carrying the curve; all other markers represent centers of \(n_c\) circles, used in connector |
nodeNumber |
NodeIndex |
invalid (-1) |
(symbol: \(n_d\)) node number of a NodeGenericData with nDataVariablesPerSegment dataCoordinates per segment, needed for discontinuous iteration; data variables contain values from last PostNewton iteration: data[0+3i] is the circle number, data[1+3i] is the gap, data[2+3*i] is the tangential velocity (and thus contains information if it is stick or slip) |
|
circlesRadii |
NumpyVector |
[] |
(symbol: \([r_{c0},r_{c1}, \ldots]\tp \in \Rcal^{n_c}\)) Vector containing radii of \(n_c\) circles [SI:m]; number according to size of markerNumbers-1 |
|
segmentsData |
PyMatrixContainer |
[] |
(symbol: \(\Dm \in \Rcal^{n_s \times 4}\)) matrix containing a set of two planar point coordinates in each row, representing segments attached to marker \(m0\) and undergoing contact with the circles; for segment \(s0\) row 0 reads \([p_{0x,s0},\,p_{0y,s0},\,p_{1x,s0},\,p_{1y,s0}]\); note that the segments must be ordered such that going from \(\pv_0\) to \(\pv_1\), the exterior lies on the right (positive) side. MatrixContainer has to be provided in dense mode! |
|
polynomialData |
PyMatrixContainer |
[] |
(symbol: \(\Pm \in \Rcal^{n_s \times n_p}\)) matrix containing coefficients for special polynomial enhancements of the linear segments; each row contains coefficients for polynomials for the according segment, prescribing slopes at beginning and end of segment as well as curvature at beginning and end of segment; slopes and curvatures are defined in a local x/y coordinate system where x is the segment axis (start: x=0; x-axis points towards end point) and the segment normal is in y-direction; MatrixContainer has to be provided in dense mode! |
|
dynamicFriction |
UReal |
0. |
(symbol: \(\mu_d\)) dynamic friction coefficient: the friction force is \(\mu_d \vert f_N\vert \), regularized below frictionProportionalZone, see the equation; 0: no friction |
|
frictionProportionalZone |
UReal |
0.001 |
(symbol: \(v_{reg}\)) limit velocity [SI:m/s] up to which the friction force is proportional to the tangential velocity (regularization, against numerical oscillations); 0: no regularization |
|
contactStiffness |
Real |
0. |
(symbol: \(k_c\)) normal contact stiffness [SI:N/(m*m)] |
|
contactDamping |
Real |
0. |
(symbol: \(d_c\)) linear normal contact damping [SI:N/(m s)]; this damping is a simplification of real contact dissipation and should be used with care. |
|
contactModel |
UInt |
0 |
(symbol: \(m_\mathrm{contact}\)) number of contact model: 0) linear model for stiffness and damping, only proportional to penetration; contact force is computed from \(l_\mathrm{seg}\left(p \cdot \cdot k_c + \dot p \cdot d_c \right)\) as long as \(p>0\); while this is numerically more stable, it gives jumps in forces when sliding over contact geometry 1) contact force proportional to integral over penetration area of circle with segments, giving a smoother contact force when sliding over geometry; |
|
activeConnector |
Bool |
True |
flag, which determines, if the connector is active; used to deactivate (temporarily) a connector or constraint |
|
gapPerSegment |
NumpyVector |
[] |
temporary vector for computed gap |
|
gapPerSegment_t |
NumpyVector |
[] |
temporary vector for computed gap velocity |
|
segmentsForceLocalX |
NumpyVector |
[] |
temporary vector for contact force per segment in local X-direction |
|
segmentsForceLocalY |
NumpyVector |
[] |
temporary vector for contact force per segment in local Y-direction |
|
visualization |
VObjectContactCurveCircles |
parameters for visualization of item |
Visualization parameters
The parameters of VObjectContactCurveCircles, 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; draws curve and circles with given radii; uses visualizationSettings circleTiling for circles and circleTiling/2 for tiling of non-straight segments |
|
color |
Float4 |
4 |
[-1.,-1.,-1.,-1.] |
RGBA connector color; if R==-1, use default color |
Drawing
Drawn as all connectors; with connectors.showContact, the curve as lines with points at its segments, and the circles of the markers with general.circleTiling segments.
Settings beyond those of all connectors: connectors.showContact, contact.contactPointsDefaultSize, contact.tilingCurves, general.circleTiling, general.sphereTiling.
Output variables
Available as OutputVariableType in sensors, Get...Output() and other functions:
output variable |
symbol |
description |
|---|---|---|
DisplacementLocal |
\([g_0,\,g_1,\,\ldots]\tp\) |
per segment, the gap of the circle closest to it (< 0: penetration), from the current configuration; the largest float if there is no circle |
VelocityLocal |
\([\dot g_0,\,\dot g_1,\,\ldots]\tp\) |
per segment, the normal relative velocity of that circle |
ForceLocal |
\([f_{x,0},\,f_{y,0},\,f_{x,1},\,\ldots]\tp\) |
per segment, the contact force - normal and friction - on the circle in contact with it, in the frame of marker m0, with the contact states of the data node; zero without contact |
Detailed description
Further testing is required, as the class description says.
Definition of quantities
intermediate variables |
symbol |
description |
|---|---|---|
marker m0 position, orientation |
\(\LU{0}{\pv}_{m0}\), \(\LU{0,m0}{\Rot}\) |
the frame carrying the curve, which lies in its \(x\)-\(y\) plane; a rotation of it is given to the marker as its |
circle markers |
\(\LU{0}{\pv}_{c_i}\) |
centers of the \(n_c\) circles with radii |
segments |
\(\Dm\) |
|
polynomials |
\(\Pm\) |
|
data coordinates |
\(\xv\) |
per segment, the state of the last post Newton step |
Geometric relations
The circle centers are transformed into the frame of the curve and projected into its plane. For each segment and each circle, the gap is the distance of the circle center from the segment minus the radius; a segment takes the circle with the largest penetration. The penetration is integrated along the part of the segment in contact, so that the contact stiffness does not depend on how finely the curve is divided.
Connector forces
Per segment in contact, the normal force follows from contactStiffness, contactDamping and the
integrated penetration, as contactModel selects; it acts in the plane of the curve on the circle
center and, with opposite sign, on marker 0 with the torque of its lever arm. A segment must be short
enough that only one circle touches it at a time, which the connector warns about.
With dynamicFriction \(\mu_d > 0\), a friction force acts in the tangential direction \(\tv\) of the contact,
against the tangential relative velocity \(v_t\) of the circle center against the curve,
with frictionProportionalZone \(v_{reg}\) (0: no regularization); there is no sticking state.
Mini example
#a planar body with a circle of radius 0.1 resting on a curve of line segments (the ground line y=0)
node = mbs.AddNode(NodeRigidBody2D(referenceCoordinates=[0,0.1,0]))
body = mbs.AddObject(ObjectRigidBody2D(nodeNumber=node, mass=1, inertia=0.01))
mbs.AddLoad(LoadForceVector(markerNumber=mbs.AddMarker(MarkerBodyPosition(bodyNumber=body)), loadVector=[0,-10,0]))
mCurve = mbs.AddMarker(MarkerBodyRigid(bodyNumber=oGround, localPosition=[0,0,0]))
mCircle = mbs.AddMarker(MarkerBodyRigid(bodyNumber=body, localPosition=[0,0,0]))
segments = np.array([[1,0, -1,0]]) #one segment [x0,y0, x1,y1]; the contact side is to the left of 1->0
nData = mbs.AddNode(NodeGenericData(numberOfDataCoordinates=3, initialCoordinates=[-1,0,0]))
mbs.AddObject(ObjectContactCurveCircles(markerNumbers=[mCurve, mCircle], nodeNumber=nData, circlesRadii=[0.1],
segmentsData=exu.MatrixContainer(segments),
contactStiffness=1e4, contactDamping=100))
mbs.Assemble()
mbs.SolveDynamic()
#at rest: 0.1 - F/k
exu.sys['testResult'] = mbs.GetNodeOutput(node, exu.OutputVariableType.Position)[1] #0.099
Relevant Examples (Ex) and TestModels (TM) with weblink to github: camFollowerExample.py (Ex), chainDriveExample.py (Ex), contactCurvePolynomial.py (Ex), contactCurveWithLongCurve.py (Ex), contactCurveCirclesFrictionTest.py (TM), contactCurveExample.py (TM)