
    \hq                        S r SSKJrJr  SSKJrJrJrJr  SSK	J
r
  SSKJr  SSKJr  SSKJr  SSKJrJr  / S	Qr " S
 S\5      r " S S\5      r " S S\5      r " S S\5      r " S S\5      r " S S\5      r " S S\5      rg)zEImplementations of actuators for linked force and torque application.    )ABCabstractmethod)Ssympifyexpsign)PinJoint)Torque)PathwayBase)	RigidBody)ReferenceFrameVector)ActuatorBaseForceActuatorLinearDamperLinearSpringTorqueActuatorDuffingSpringCoulombKineticFrictionc                   4    \ rS rSrSrS r\S 5       rS rSr	g)r      zAbstract base class for all actuator classes to inherit from.

Notes
=====

Instances of this class cannot be directly instantiated by users. However,
it can be used to created custom actuator types through subclassing.

c                     g)z!Initializer for ``ActuatorBase``.N selfs    X/var/www/auris/envauris/lib/python3.13/site-packages/sympy/physics/mechanics/actuator.py__init__ActuatorBase.__init__#   s        c                     g)at  Loads required by the equations of motion method classes.

Explanation
===========

``KanesMethod`` requires a list of ``Point``-``Vector`` tuples to be
passed to the ``loads`` parameters of its ``kanes_equations`` method
when constructing the equations of motion. This method acts as a
utility to produce the correctly-structred pairs of points and vectors
required so that these can be easily concatenated with other items in
the list of loads and passed to ``KanesMethod.kanes_equations``. These
loads are also in the correct form to also be passed to the other
equations of motion method classes, e.g. ``LagrangesMethod``.

Nr   r   s    r   to_loadsActuatorBase.to_loads'   s    " 	r   c                 4    U R                   R                   S3$ )z&Default representation of an actuator.z())	__class____name__r   s    r   __repr__ActuatorBase.__repr__:   s    ..))*"--r   r   N)
r%   
__module____qualname____firstlineno____doc__r   r   r!   r&   __static_attributes__r   r   r   r   r      s%      $.r   r   c                       \ rS rSrSrS r\S 5       r\R                  S 5       r\S 5       r	\	R                  S 5       r	S r
S	 rS
rg)r   ?   a	  Force-producing actuator.

Explanation
===========

A ``ForceActuator`` is an actuator that produces a (expansile) force along
its length.

A force actuator uses a pathway instance to determine the direction and
number of forces that it applies to a system. Consider the simplest case
where a ``LinearPathway`` instance is used. This pathway is made up of two
points that can move relative to each other, and results in a pair of equal
and opposite forces acting on the endpoints. If the positive time-varying
Euclidean distance between the two points is defined, then the "extension
velocity" is the time derivative of this distance. The extension velocity
is positive when the two points are moving away from each other and
negative when moving closer to each other. The direction for the force
acting on either point is determined by constructing a unit vector directed
from the other point to this point. This establishes a sign convention such
that a positive force magnitude tends to push the points apart, this is the
meaning of "expansile" in this context. The following diagram shows the
positive force sense and the distance between the points::

   P           Q
   o<--- F --->o
   |           |
   |<--l(t)--->|

Examples
========

To construct an actuator, an expression (or symbol) must be supplied to
represent the force it can produce, alongside a pathway specifying its line
of action. Let's also create a global reference frame and spatially fix one
of the points in it while setting the other to be positioned such that it
can freely move in the frame's x direction specified by the coordinate
``q``.

>>> from sympy import symbols
>>> from sympy.physics.mechanics import (ForceActuator, LinearPathway,
...     Point, ReferenceFrame)
>>> from sympy.physics.vector import dynamicsymbols
>>> N = ReferenceFrame('N')
>>> q = dynamicsymbols('q')
>>> force = symbols('F')
>>> pA, pB = Point('pA'), Point('pB')
>>> pA.set_vel(N, 0)
>>> pB.set_pos(pA, q*N.x)
>>> pB.pos_from(pA)
q(t)*N.x
>>> linear_pathway = LinearPathway(pA, pB)
>>> actuator = ForceActuator(force, linear_pathway)
>>> actuator
ForceActuator(F, LinearPathway(pA, pB))

Parameters
==========

force : Expr
    The scalar expression defining the (expansile) force that the actuator
    produces.
pathway : PathwayBase
    The pathway that the actuator follows. This must be an instance of a
    concrete subclass of ``PathwayBase``, e.g. ``LinearPathway``.

c                     Xl         X l        g)aC  Initializer for ``ForceActuator``.

Parameters
==========

force : Expr
    The scalar expression defining the (expansile) force that the
    actuator produces.
pathway : PathwayBase
    The pathway that the actuator follows. This must be an instance of
    a concrete subclass of ``PathwayBase``, e.g. ``LinearPathway``.

N)forcepathway)r   r0   r1   s      r   r   ForceActuator.__init__   s     
r   c                     U R                   $ )z4The magnitude of the force produced by the actuator.)_forcer   s    r   r0   ForceActuator.force        {{r   c                 x    [        U S5      (       a  S[        U5       S3n[        U5      e[        USS9U l        g Nr4   zCan't set attribute `force` to  as it is immutable.TstricthasattrreprAttributeErrorr   r4   r   r0   msgs      r   r0   r5      E    4""24;- @   !%%eD1r   c                     U R                   $ )z7The ``Pathway`` defining the actuator's line of action._pathwayr   s    r   r1   ForceActuator.pathway        }}r   c                     [        U S5      (       a  S[        U5       S3n[        U5      e[        U[        5      (       d-  S[        U5       S[        U5       S[         S3n[        U5      eXl        g NrE   z!Can't set attribute `pathway` to r9   Value z! passed to `pathway` was of type 
, must be .r=   r>   r?   
isinstancer   type	TypeErrorrE   r   r1   rA   s      r   r1   rF      ~    4$$4T']O D   !%%';//g'H=/K=;  C. r   c                 L    U R                   R                  U R                  5      $ )ao  Loads required by the equations of motion method classes.

Explanation
===========

``KanesMethod`` requires a list of ``Point``-``Vector`` tuples to be
passed to the ``loads`` parameters of its ``kanes_equations`` method
when constructing the equations of motion. This method acts as a
utility to produce the correctly-structred pairs of points and vectors
required so that these can be easily concatenated with other items in
the list of loads and passed to ``KanesMethod.kanes_equations``. These
loads are also in the correct form to also be passed to the other
equations of motion method classes, e.g. ``LagrangesMethod``.

Examples
========

The below example shows how to generate the loads produced by a force
actuator that follows a linear pathway. In this example we'll assume
that the force actuator is being used to model a simple linear spring.
First, create a linear pathway between two points separated by the
coordinate ``q`` in the ``x`` direction of the global frame ``N``.

>>> from sympy.physics.mechanics import (LinearPathway, Point,
...     ReferenceFrame)
>>> from sympy.physics.vector import dynamicsymbols
>>> q = dynamicsymbols('q')
>>> N = ReferenceFrame('N')
>>> pA, pB = Point('pA'), Point('pB')
>>> pB.set_pos(pA, q*N.x)
>>> pathway = LinearPathway(pA, pB)

Now create a symbol ``k`` to describe the spring's stiffness and
instantiate a force actuator that produces a (contractile) force
proportional to both the spring's stiffness and the pathway's length.
Note that actuator classes use the sign convention that expansile
forces are positive, so for a spring to produce a contractile force the
spring force needs to be calculated as the negative for the stiffness
multiplied by the length.

>>> from sympy import symbols
>>> from sympy.physics.mechanics import ForceActuator
>>> stiffness = symbols('k')
>>> spring_force = -stiffness*pathway.length
>>> spring = ForceActuator(spring_force, pathway)

The forces produced by the spring can be generated in the list of loads
form that ``KanesMethod`` (and other equations of motion methods)
requires by calling the ``to_loads`` method.

>>> spring.to_loads()
[(pA, k*q(t)*N.x), (pB, - k*q(t)*N.x)]

A simple linear damper can be modeled in a similar way. Create another
symbol ``c`` to describe the dampers damping coefficient. This time
instantiate a force actuator that produces a force proportional to both
the damper's damping coefficient and the pathway's extension velocity.
Note that the damping force is negative as it acts in the opposite
direction to which the damper is changing in length.

>>> damping_coefficient = symbols('c')
>>> damping_force = -damping_coefficient*pathway.extension_velocity
>>> damper = ForceActuator(damping_force, pathway)

Again, the forces produces by the damper can be generated by calling
the ``to_loads`` method.

>>> damper.to_loads()
[(pA, c*Derivative(q(t), t)*N.x), (pB, - c*Derivative(q(t), t)*N.x)]

)r1   r!   r0   r   s    r   r!   ForceActuator.to_loads   s    P ||$$TZZ00r   c                 h    U R                   R                   SU R                   SU R                   S3$ )z&Representation of a ``ForceActuator``.(, ))r$   r%   r0   r1   r   s    r   r&   ForceActuator.__repr__  s.    ..))*!DJJ<r$,,qIIr   )r4   rE   r0   r1   N)r%   r(   r)   r*   r+   r   propertyr0   setterr1   r!   r&   r,   r   r   r   r   r   ?   ss    AF"   \\2 2   ^^   H1TJr   r   c                       \ rS rSrSr\R                  4S jr\S 5       r	\	R                  S 5       r	\S 5       r\R                  S 5       r\S 5       r\R                  S	 5       rS
 rSrg)r   i  a  A spring with its spring force as a linear function of its length.

Explanation
===========

Note that the "linear" in the name ``LinearSpring`` refers to the fact that
the spring force is a linear function of the springs length. I.e. for a
linear spring with stiffness ``k``, distance between its ends of ``x``, and
an equilibrium length of ``0``, the spring force will be ``-k*x``, which is
a linear function in ``x``. To create a spring that follows a linear, or
straight, pathway between its two ends, a ``LinearPathway`` instance needs
to be passed to the ``pathway`` parameter.

A ``LinearSpring`` is a subclass of ``ForceActuator`` and so follows the
same sign conventions for length, extension velocity, and the direction of
the forces it applies to its points of attachment on bodies. The sign
convention for the direction of forces is such that, for the case where a
linear spring is instantiated with a ``LinearPathway`` instance as its
pathway, they act to push the two ends of the spring away from one another.
Because springs produces a contractile force and acts to pull the two ends
together towards the equilibrium length when stretched, the scalar portion
of the forces on the endpoint are negative in order to flip the sign of the
forces on the endpoints when converted into vector quantities. The
following diagram shows the positive force sense and the distance between
the points::

   P           Q
   o<--- F --->o
   |           |
   |<--l(t)--->|

Examples
========

To construct a linear spring, an expression (or symbol) must be supplied to
represent the stiffness (spring constant) of the spring, alongside a
pathway specifying its line of action. Let's also create a global reference
frame and spatially fix one of the points in it while setting the other to
be positioned such that it can freely move in the frame's x direction
specified by the coordinate ``q``.

>>> from sympy import symbols
>>> from sympy.physics.mechanics import (LinearPathway, LinearSpring,
...     Point, ReferenceFrame)
>>> from sympy.physics.vector import dynamicsymbols
>>> N = ReferenceFrame('N')
>>> q = dynamicsymbols('q')
>>> stiffness = symbols('k')
>>> pA, pB = Point('pA'), Point('pB')
>>> pA.set_vel(N, 0)
>>> pB.set_pos(pA, q*N.x)
>>> pB.pos_from(pA)
q(t)*N.x
>>> linear_pathway = LinearPathway(pA, pB)
>>> spring = LinearSpring(stiffness, linear_pathway)
>>> spring
LinearSpring(k, LinearPathway(pA, pB))

This spring will produce a force that is proportional to both its stiffness
and the pathway's length. Note that this force is negative as SymPy's sign
convention for actuators is that negative forces are contractile.

>>> spring.force
-k*sqrt(q(t)**2)

To create a linear spring with a non-zero equilibrium length, an expression
(or symbol) can be passed to the ``equilibrium_length`` parameter on
construction on a ``LinearSpring`` instance. Let's create a symbol ``l``
to denote a non-zero equilibrium length and create another linear spring.

>>> l = symbols('l')
>>> spring = LinearSpring(stiffness, linear_pathway, equilibrium_length=l)
>>> spring
LinearSpring(k, LinearPathway(pA, pB), equilibrium_length=l)

The spring force of this new spring is again proportional to both its
stiffness and the pathway's length. However, the spring will not produce
any force when ``q(t)`` equals ``l``. Note that the force will become
expansile when ``q(t)`` is less than ``l``, as expected.

>>> spring.force
-k*(-l + sqrt(q(t)**2))

Parameters
==========

stiffness : Expr
    The spring constant.
pathway : PathwayBase
    The pathway that the actuator follows. This must be an instance of a
    concrete subclass of ``PathwayBase``, e.g. ``LinearPathway``.
equilibrium_length : Expr, optional
    The length at which the spring is in equilibrium, i.e. it produces no
    force. The default value is 0, i.e. the spring force is a linear
    function of the pathway's length with no constant offset.

See Also
========

ForceActuator: force-producing actuator (superclass of ``LinearSpring``).
LinearPathway: straight-line pathway between a pair of points.

c                 (    Xl         X l        X0l        g)a  Initializer for ``LinearSpring``.

Parameters
==========

stiffness : Expr
    The spring constant.
pathway : PathwayBase
    The pathway that the actuator follows. This must be an instance of
    a concrete subclass of ``PathwayBase``, e.g. ``LinearPathway``.
equilibrium_length : Expr, optional
    The length at which the spring is in equilibrium, i.e. it produces
    no force. The default value is 0, i.e. the spring force is a linear
    function of the pathway's length with no constant offset.

N)	stiffnessr1   equilibrium_length)r   r^   r1   r_   s       r   r   LinearSpring.__init__p  s    " #"4r   c                 d    U R                   * U R                  R                  U R                  -
  -  $ )z/The spring force produced by the linear spring.)r^   r1   lengthr_   r   s    r   r0   LinearSpring.force  s*      3 3d6M6M MNNr   c                     [        S5      eNz%Can't set computed attribute `force`.r?   r   r0   s     r   r0   rc         EFFr   c                     U R                   $ )z*The spring constant for the linear spring.)
_stiffnessr   s    r   r^   LinearSpring.stiffness  s     r   c                 x    [        U S5      (       a  S[        U5       S3n[        U5      e[        USS9U l        g )Nrj   z#Can't set attribute `stiffness` to r9   Tr:   )r=   r>   r?   r   rj   )r   r^   rA   s      r   r^   rk     sF    4&&6tI6G H  !  !%%!)D9r   c                     U R                   $ )z7The length of the spring at which it produces no force._equilibrium_lengthr   s    r   r_   LinearSpring.equilibrium_length  s     '''r   c                 x    [        U S5      (       a  S[        U5       S3n[        U5      e[        USS9U l        g Nro   z,Can't set attribute `equilibrium_length` to r9   Tr:   r=   r>   r?   r   ro   r   r_   rA   s      r   r_   rp     J    4.//?*+,,@B  !%%#*+=d#K r   c                     U R                   R                   SU R                   SU R                   3nU R                  [
        R                  :X  a  US-  nU$ USU R                   S3-  nU$ )z%Representation of a ``LinearSpring``.rV   rW   rX   , equilibrium_length=)r$   r%   r^   r1   r_   r   Zeror   strings     r   r&   LinearSpring.__repr__  sp    NN++,Adnn-=R~N""aff,cMF  -d.E.E-FaHHFr   )ro   rj   r_   r1   r^   N)r%   r(   r)   r*   r+   r   rx   r   rZ   r0   r[   r^   r_   r&   r,   r   r   r   r   r     s    fP ?@ff 5* O O \\G G   : : ( ( L Lr   r   c                       \ rS rSrSrS r\S 5       r\R                  S 5       r\S 5       r	\	R                  S 5       r	S r
S	rg
)r   i  a  A damper whose force is a linear function of its extension velocity.

Explanation
===========

Note that the "linear" in the name ``LinearDamper`` refers to the fact that
the damping force is a linear function of the damper's rate of change in
its length. I.e. for a linear damper with damping ``c`` and extension
velocity ``v``, the damping force will be ``-c*v``, which is a linear
function in ``v``. To create a damper that follows a linear, or straight,
pathway between its two ends, a ``LinearPathway`` instance needs to be
passed to the ``pathway`` parameter.

A ``LinearDamper`` is a subclass of ``ForceActuator`` and so follows the
same sign conventions for length, extension velocity, and the direction of
the forces it applies to its points of attachment on bodies. The sign
convention for the direction of forces is such that, for the case where a
linear damper is instantiated with a ``LinearPathway`` instance as its
pathway, they act to push the two ends of the damper away from one another.
Because dampers produce a force that opposes the direction of change in
length, when extension velocity is positive the scalar portions of the
forces applied at the two endpoints are negative in order to flip the sign
of the forces on the endpoints wen converted into vector quantities. When
extension velocity is negative (i.e. when the damper is shortening), the
scalar portions of the fofces applied are also negative so that the signs
cancel producing forces on the endpoints that are in the same direction as
the positive sign convention for the forces at the endpoints of the pathway
(i.e. they act to push the endpoints away from one another). The following
diagram shows the positive force sense and the distance between the
points::

   P           Q
   o<--- F --->o
   |           |
   |<--l(t)--->|

Examples
========

To construct a linear damper, an expression (or symbol) must be supplied to
represent the damping coefficient of the damper (we'll use the symbol
``c``), alongside a pathway specifying its line of action. Let's also
create a global reference frame and spatially fix one of the points in it
while setting the other to be positioned such that it can freely move in
the frame's x direction specified by the coordinate ``q``. The velocity
that the two points move away from one another can be specified by the
coordinate ``u`` where ``u`` is the first time derivative of ``q``
(i.e., ``u = Derivative(q(t), t)``).

>>> from sympy import symbols
>>> from sympy.physics.mechanics import (LinearDamper, LinearPathway,
...     Point, ReferenceFrame)
>>> from sympy.physics.vector import dynamicsymbols
>>> N = ReferenceFrame('N')
>>> q = dynamicsymbols('q')
>>> damping = symbols('c')
>>> pA, pB = Point('pA'), Point('pB')
>>> pA.set_vel(N, 0)
>>> pB.set_pos(pA, q*N.x)
>>> pB.pos_from(pA)
q(t)*N.x
>>> pB.vel(N)
Derivative(q(t), t)*N.x
>>> linear_pathway = LinearPathway(pA, pB)
>>> damper = LinearDamper(damping, linear_pathway)
>>> damper
LinearDamper(c, LinearPathway(pA, pB))

This damper will produce a force that is proportional to both its damping
coefficient and the pathway's extension length. Note that this force is
negative as SymPy's sign convention for actuators is that negative forces
are contractile and the damping force of the damper will oppose the
direction of length change.

>>> damper.force
-c*sqrt(q(t)**2)*Derivative(q(t), t)/q(t)

Parameters
==========

damping : Expr
    The damping constant.
pathway : PathwayBase
    The pathway that the actuator follows. This must be an instance of a
    concrete subclass of ``PathwayBase``, e.g. ``LinearPathway``.

See Also
========

ForceActuator: force-producing actuator (superclass of ``LinearDamper``).
LinearPathway: straight-line pathway between a pair of points.

c                     Xl         X l        g)a  Initializer for ``LinearDamper``.

Parameters
==========

damping : Expr
    The damping constant.
pathway : PathwayBase
    The pathway that the actuator follows. This must be an instance of
    a concrete subclass of ``PathwayBase``, e.g. ``LinearPathway``.

N)dampingr1   )r   r~   r1   s      r   r   LinearDamper.__init__  s     r   c                 J    U R                   * U R                  R                  -  $ )z0The damping force produced by the linear damper.)r~   r1   extension_velocityr   s    r   r0   LinearDamper.force%  s     }T\\<<<<r   c                     [        S5      ere   rf   rg   s     r   r0   r   *  rh   r   c                     U R                   $ )z+The damping constant for the linear damper.)_dampingr   s    r   r~   LinearDamper.damping.  rG   r   c                 x    [        U S5      (       a  S[        U5       S3n[        U5      e[        USS9U l        g )Nr   z!Can't set attribute `damping` to r9   Tr:   )r=   r>   r?   r   r   )r   r~   rA   s      r   r~   r   3  sE    4$$4T']O D   !%%5r   c                 h    U R                   R                   SU R                   SU R                   S3$ )z%Representation of a ``LinearDamper``.rV   rW   rX   )r$   r%   r~   r1   r   s    r   r&   LinearDamper.__repr__=  s.    ..))*!DLL>DLL>KKr   )r   r~   r1   N)r%   r(   r)   r*   r+   r   rZ   r0   r[   r~   r&   r,   r   r   r   r   r     sn    \|  = = \\G G   ^^6 6Lr   r   c                      \ rS rSrSrSS jr\S 5       r\S 5       r	\	R                  S 5       r	\S 5       r\R                  S	 5       r\S
 5       r\R                  S 5       r\S 5       r\R                  S 5       rS rS rSrg)r   iB  a  Torque-producing actuator.

Explanation
===========

A ``TorqueActuator`` is an actuator that produces a pair of equal and
opposite torques on a pair of bodies.

Examples
========

To construct a torque actuator, an expression (or symbol) must be supplied
to represent the torque it can produce, alongside a vector specifying the
axis about which the torque will act, and a pair of frames on which the
torque will act.

>>> from sympy import symbols
>>> from sympy.physics.mechanics import (ReferenceFrame, RigidBody,
...     TorqueActuator)
>>> N = ReferenceFrame('N')
>>> A = ReferenceFrame('A')
>>> torque = symbols('T')
>>> axis = N.z
>>> parent = RigidBody('parent', frame=N)
>>> child = RigidBody('child', frame=A)
>>> bodies = (child, parent)
>>> actuator = TorqueActuator(torque, axis, *bodies)
>>> actuator
TorqueActuator(T, axis=N.z, target_frame=A, reaction_frame=N)

Note that because torques actually act on frames, not bodies,
``TorqueActuator`` will extract the frame associated with a ``RigidBody``
when one is passed instead of a ``ReferenceFrame``.

Parameters
==========

torque : Expr
    The scalar expression defining the torque that the actuator produces.
axis : Vector
    The axis about which the actuator applies torques.
target_frame : ReferenceFrame | RigidBody
    The primary frame on which the actuator will apply the torque.
reaction_frame : ReferenceFrame | RigidBody | None
    The secondary frame on which the actuator will apply the torque. Note
    that the (equal and opposite) reaction torque is applied to this frame.

Nc                 4    Xl         X l        X0l        X@l        g)a  Initializer for ``TorqueActuator``.

Parameters
==========

torque : Expr
    The scalar expression defining the torque that the actuator
    produces.
axis : Vector
    The axis about which the actuator applies torques.
target_frame : ReferenceFrame | RigidBody
    The primary frame on which the actuator will apply the torque.
reaction_frame : ReferenceFrame | RigidBody | None
   The secondary frame on which the actuator will apply the torque.
   Note that the (equal and opposite) reaction torque is applied to
   this frame.

N)torqueaxistarget_framereaction_frame)r   r   r   r   r   s        r   r   TorqueActuator.__init__t  s    & 	(,r   c                     [        U[        5      (       d-  S[        U5       S[        U5       S[         S3n[	        U5      eU " UUR
                  UR                  UR                  5      $ )a  Alternate constructor to instantiate from a ``PinJoint`` instance.

Examples
========

To create a pin joint the ``PinJoint`` class requires a name, parent
body, and child body to be passed to its constructor. It is also
possible to control the joint axis using the ``joint_axis`` keyword
argument. In this example let's use the parent body's reference frame's
z-axis as the joint axis.

>>> from sympy.physics.mechanics import (PinJoint, ReferenceFrame,
...     RigidBody, TorqueActuator)
>>> N = ReferenceFrame('N')
>>> A = ReferenceFrame('A')
>>> parent = RigidBody('parent', frame=N)
>>> child = RigidBody('child', frame=A)
>>> pin_joint = PinJoint(
...     'pin',
...     parent,
...     child,
...     joint_axis=N.z,
... )

Let's also create a symbol ``T`` that will represent the torque applied
by the torque actuator.

>>> from sympy import symbols
>>> torque = symbols('T')

To create the torque actuator from the ``torque`` and ``pin_joint``
variables previously instantiated, these can be passed to the alternate
constructor class method ``at_pin_joint`` of the ``TorqueActuator``
class. It should be noted that a positive torque will cause a positive
displacement of the joint coordinate or that the torque is applied on
the child body with a reaction torque on the parent.

>>> actuator = TorqueActuator.at_pin_joint(torque, pin_joint)
>>> actuator
TorqueActuator(T, axis=N.z, target_frame=A, reaction_frame=N)

Parameters
==========

torque : Expr
    The scalar expression defining the torque that the actuator
    produces.
pin_joint : PinJoint
    The pin joint, and by association the parent and child bodies, on
    which the torque actuator will act. The pair of bodies acted upon
    by the torque actuator are the parent and child bodies of the pin
    joint, with the child acting as the reaction body. The pin joint's
    axis is used as the axis about which the torque actuator will apply
    its torque.

rJ   z# passed to `pin_joint` was of type rK   rL   )rN   r	   r>   rO   rP   
joint_axischild_interframeparent_interframe)clsr   	pin_jointrA   s       r   at_pin_jointTorqueActuator.at_pin_joint  st    t )X..i))L	?#:hZq:  C.   &&''	
 	
r   c                     U R                   $ )z5The magnitude of the torque produced by the actuator.)_torquer   s    r   r   TorqueActuator.torque  s     ||r   c                 x    [        U S5      (       a  S[        U5       S3n[        U5      e[        USS9U l        g )Nr   z Can't set attribute `torque` to r9   Tr:   )r=   r>   r?   r   r   )r   r   rA   s      r   r   r     sE    4##3DL> B   !%%vd3r   c                     U R                   $ )z%The axis about which the torque acts.)_axisr   s    r   r   TorqueActuator.axis       zzr   c                     [        U S5      (       a  S[        U5       S3n[        U5      e[        U[        5      (       d-  S[        U5       S[        U5       S[         S3n[        U5      eXl        g )Nr   zCan't set attribute `axis` to r9   rJ   z passed to `axis` was of type rK   rL   )r=   r>   r?   rN   r   rO   rP   r   )r   r   rA   s      r   r   r     s}    4!!1$t* >   !%%$''d$B:,j3  C. 
r   c                     U R                   $ z:The primary reference frames on which the torque will act.)_target_framer   s    r   r   TorqueActuator.target_frame  s     !!!r   c                 .   [        U S5      (       a  S[        U5       S3n[        U5      e[        U[        5      (       a  UR
                  nOB[        U[        5      (       d-  S[        U5       S[        U5       S[         S3n[        U5      eXl	        g )Nr   z&Can't set attribute `target_frame` to r9   rJ   z& passed to `target_frame` was of type rK   rL   )
r=   r>   r?   rN   r   framer   rO   rP   r   )r   r   rA   s      r   r   r     s    4))9$|:L9M N& '  !%%lI..'--LL.99l+, -\*+:n5EQH  C. )r   c                     U R                   $ r   )_reaction_framer   s    r   r   TorqueActuator.reaction_frame  s     ###r   c                 4   [        U S5      (       a  S[        U5       S3n[        U5      e[        U[        5      (       a  UR
                  nOE[        U[        5      (       d0  Ub-  S[        U5       S[        U5       S[         S3n[        U5      eXl	        g )Nr   z(Can't set attribute `reaction_frame` to r9   rJ   z( passed to `reaction_frame` was of type rK   rL   )
r=   r>   r?   rN   r   r   r   rO   rP   r   )r   r   rA   s      r   r   r     s    4*++;'((<>  !%%ni00+11N>>::* n-. //0
>:J!M  C. -r   c                     [        U R                  U R                  U R                  -  5      /nU R                  b=  UR                  [        U R                  U R                  * U R                  -  5      5        U$ )av  Loads required by the equations of motion method classes.

Explanation
===========

``KanesMethod`` requires a list of ``Point``-``Vector`` tuples to be
passed to the ``loads`` parameters of its ``kanes_equations`` method
when constructing the equations of motion. This method acts as a
utility to produce the correctly-structred pairs of points and vectors
required so that these can be easily concatenated with other items in
the list of loads and passed to ``KanesMethod.kanes_equations``. These
loads are also in the correct form to also be passed to the other
equations of motion method classes, e.g. ``LagrangesMethod``.

Examples
========

The below example shows how to generate the loads produced by a torque
actuator that acts on a pair of bodies attached by a pin joint.

>>> from sympy import symbols
>>> from sympy.physics.mechanics import (PinJoint, ReferenceFrame,
...     RigidBody, TorqueActuator)
>>> torque = symbols('T')
>>> N = ReferenceFrame('N')
>>> A = ReferenceFrame('A')
>>> parent = RigidBody('parent', frame=N)
>>> child = RigidBody('child', frame=A)
>>> pin_joint = PinJoint(
...     'pin',
...     parent,
...     child,
...     joint_axis=N.z,
... )
>>> actuator = TorqueActuator.at_pin_joint(torque, pin_joint)

The forces produces by the damper can be generated by calling the
``to_loads`` method.

>>> actuator.to_loads()
[(A, T*N.z), (N, - T*N.z)]

Alternatively, if a torque actuator is created without a reaction frame
then the loads returned by the ``to_loads`` method will contain just
the single load acting on the target frame.

>>> actuator = TorqueActuator(torque, N.z, N)
>>> actuator.to_loads()
[(N, T*N.z)]

)r
   r   r   r   r   append)r   loadss     r   r!   TorqueActuator.to_loads(  sd    j 4$$dkk$))&;<
 *LL 3 3dkk\$))5KLMr   c                     U R                   R                   SU R                   SU R                   SU R                   3nU R
                  b  USU R
                   S3-  nU$ US-  nU$ )z'Representation of a ``TorqueActuator``.rV   z, axis=z, target_frame=z, reaction_frame=rX   )r$   r%   r   r   r   r   ry   s     r   r&   TorqueActuator.__repr__c  s     ~~&&'qWTYYK H --.0 	 *)$*=*=)>a@@F  cMFr   )r   r   r   r   r   r   r   r   N)r%   r(   r)   r*   r+   r   classmethodr   rZ   r   r[   r   r   r   r!   r&   r,   r   r   r   r   r   B  s    /b-0 D
 D
L   ]]4 4   
[[  " " * *" $ $ . .(9v
r   r   c                   B   \ rS rSrSr\R                  4S jr\S 5       r	\	R                  S 5       r	\S 5       r\R                  S 5       r\S 5       r\R                  S	 5       r\S
 5       r\R                  S 5       r\S 5       r\R                  S 5       rS rSrg)r   ip  a  A nonlinear spring based on the Duffing equation.

Explanation
===========

Here, ``DuffingSpring`` represents the force exerted by a nonlinear spring based on the Duffing equation:
F = -beta*x-alpha*x**3, where x is the displacement from the equilibrium position, beta is the linear spring constant,
and alpha is the coefficient for the nonlinear cubic term.

Parameters
==========

linear_stiffness : Expr
    The linear stiffness coefficient (beta).
nonlinear_stiffness : Expr
    The nonlinear stiffness coefficient (alpha).
pathway : PathwayBase
    The pathway that the actuator follows.
equilibrium_length : Expr, optional
    The length at which the spring is in equilibrium (x).
c                     [        USS9U l        [        USS9U l        [        USS9U l        [	        U[
        5      (       d  [        S5      eX0l        g )NTr:   z+pathway must be an instance of PathwayBase.)r   linear_stiffnessnonlinear_stiffnessr_   rN   r   rP   rE   )r   r   r   r1   r_   s        r   r   DuffingSpring.__init__  sP     '(8 F#*+>t#L ")*<T"J';//IJJr   c                     U R                   $ r   )_linear_stiffnessr   s    r   r   DuffingSpring.linear_stiffness  s    %%%r   c                 x    [        U S5      (       a  S[        U5       S3n[        U5      e[        USS9U l        g )Nr   z*Can't set attribute `linear_stiffness` to r9   Tr:   )r=   r>   r?   r   r   )r   r   rA   s      r   r   r     sJ    4,--=()**>@  !%%!()9$!Gr   c                     U R                   $ r   )_nonlinear_stiffnessr   s    r   r   !DuffingSpring.nonlinear_stiffness  s    (((r   c                 x    [        U S5      (       a  S[        U5       S3n[        U5      e[        USS9U l        g )Nr   z-Can't set attribute `nonlinear_stiffness` to r9   Tr:   )r=   r>   r?   r   r   )r   r   rA   s      r   r   r     sJ    4/00@+,--AC  !%%$+,?$M!r   c                     U R                   $ r   rD   r   s    r   r1   DuffingSpring.pathway  s    }}r   c                     [        U S5      (       a  S[        U5       S3n[        U5      e[        U[        5      (       d-  S[        U5       S[        U5       S[         S3n[        U5      eXl        g rI   rM   rQ   s      r   r1   r     rR   r   c                     U R                   $ r   rn   r   s    r   r_    DuffingSpring.equilibrium_length  s    '''r   c                 x    [        U S5      (       a  S[        U5       S3n[        U5      e[        USS9U l        g rr   rs   rt   s      r   r_   r     ru   r   c                     U R                   R                  U R                  -
  nU R                  * U-  U R                  US-  -  -
  $ )z)The force produced by the Duffing spring.   )r1   rb   r_   r   r   )r   displacements     r   r0   DuffingSpring.force  sI     ||**T-D-DD%%%4t7O7OR^`aRa7aaar   c                 x    [        U S5      (       a  S[        U5       S3n[        U5      e[        USS9U l        g r8   r<   r@   s      r   r0   r     rB   r   c           
          U R                   R                   SU R                   SU R                   SU R                   SU R
                   S3
$ )NrV   rW   rw   rX   )r$   r%   r   r   r1   r_   r   s    r   r&   DuffingSpring.__repr__  sW    >>**+1(()D,D,D+ER~ V&&*&=&=%>aA 	Br   )ro   r4   r   r   rE   r_   r   r   N)r%   r(   r)   r*   r+   r   rx   r   rZ   r   r[   r   r1   r_   r0   r&   r,   r   r   r   r   r   p  s	   , [\Z`Z`   & & H H ) ) N  N   ^^    ( ( L L b b
 \\2 2Br   r   c                       \ rS rSrSrSSSS.S jr\S 5       r\S 5       r\S 5       r	\S	 5       r
\S
 5       r\S 5       r\R                  S 5       rS rSrg)r   i  a1  Coulomb kinetic friction with Stribeck and viscous effects.

Explanation
===========

This represents a Coulomb kinetic friction with the Stribeck and viscous effect,
described by the function:

.. math::
    F = (\mu_k f_n + (\mu_s - \mu_k) f_n e^{-(\frac{v}{v_s})^2}) \text{sign}(v) + \sigma  v

where :math:`\mu_k` is the coefficient of kinetic friction, :math:`\mu_s` is the
coefficient of static friction, :math:`f_n` is the normal force, :math:`v` is the
relative velocity, :math:`v_s` is the Stribeck friction coefficient, and
:math:`\sigma` is the viscous friction constant.

The default friction force is :math:`F = \mu_k f_n`.
When specified, the actuator includes:

- Stribeck effect: :math:`(\mu_s - \mu_k) f_n e^{-(\frac{v}{v_s})^2}`
- Viscous effect: :math:`\sigma v`

Notes
=====

The actuator makes the following assumptions:

- The actuator assumes relative motion is non-zero.
- The normal force is assumed to be a non-negative scalar.
- The resultant friction force is opposite to the velocity direction.
- Each point in the pathway is fixed within separate objects that are sliding relative to each other. In other words, these two points are fixed in the mutually sliding objects.

This actuator has been tested for straightforward motions, like a block sliding
on a surface.

The friction force is defined to always oppose the direction of relative velocity :math:`v`.
Specifically:

- The default Coulomb friction force :math:`\mu_k f_n \text{sign}(v)` is opposite to :math:`v`.
- The Stribeck effect :math:`(\mu_s - \mu_k) f_n e^{-(\frac{v}{v_s})^2} \text{sign}(v)` is also opposite to :math:`v`.
- The viscous friction term :math:`\sigma v` is opposite to :math:`v`.

Examples
========

The below example shows how to generate the loads produced by a Coulomb kinetic
friction actuator in a mass-spring system with friction.

>>> import sympy as sm
>>> from sympy.physics.mechanics import (dynamicsymbols, ReferenceFrame, Point,
...     LinearPathway, CoulombKineticFriction, LinearSpring, KanesMethod, Particle)

>>> x, v = dynamicsymbols('x, v', real=True)
>>> m, g, k, mu_k, mu_s, v_s, sigma = sm.symbols('m, g, k, mu_k, mu_s, v_s, sigma')

>>> N = ReferenceFrame('N')
>>> O, P = Point('O'), Point('P')
>>> O.set_vel(N, 0)
>>> P.set_pos(O, x*N.x)

>>> pathway = LinearPathway(O, P)
>>> friction = CoulombKineticFriction(mu_k, m*g, pathway, v_s=v_s, sigma=sigma, mu_s=mu_k)
>>> spring = LinearSpring(k, pathway)
>>> block = Particle('block', point=P, mass=m)

>>> kane = KanesMethod(N, (x,), (v,), kd_eqs=(x.diff() - v,))
>>> friction.to_loads()
    [(O, (g*m*mu_k*sign(sign(x(t))*Derivative(x(t), t)) + sigma*sign(x(t))*Derivative(x(t), t))*x(t)/Abs(x(t))*N.x), (P, (-g*m*mu_k*sign(sign(x(t))*Derivative(x(t), t)) - sigma*sign(x(t))*Derivative(x(t), t))*x(t)/Abs(x(t))*N.x)]
>>> loads = friction.to_loads() + spring.to_loads()
>>> fr, frstar = kane.kanes_equations([block], loads)
>>> eom = fr + frstar
>>> eom
    Matrix([[-k*x(t) - m*Derivative(v(t), t) + (-g*m*mu_k*sign(v(t)*sign(x(t))) - sigma*v(t)*sign(x(t)))*x(t)/Abs(x(t))]])

Parameters
==========

f_n : sympifiable
    The normal force between the surfaces. It should always be a non-negative scalar.
mu_k : sympifiable
    The coefficient of kinetic friction.
pathway : PathwayBase
    The pathway that the actuator follows.
v_s : sympifiable, optional
    The Stribeck friction coefficient.
sigma : sympifiable, optional
    The viscous friction coefficient.
mu_s : sympifiable, optional
    The coefficient of static friction. Defaults to mu_k, meaning the Stribeck effect evaluates to 0 by default.

References
==========

.. [Moore2022] https://moorepants.github.io/learn-multibody-dynamics/loads.html#friction.
.. [Flores2023] Paulo Flores, Jorge Ambrosio, Hamid M. Lankarani,
        "Contact-impact events with friction in multibody dynamics: Back to basics",
        Mechanism and Machine Theory, vol. 184, 2023. https://doi.org/10.1016/j.mechmachtheory.2023.105305.
.. [Rogner2017] I. Rogner, "Friction modelling for robotic applications with planar motion",
        Chalmers University of Technology, Department of Electrical Engineering, 2017.

N)v_ssigmamu_sc                    Ub
  [        USS9OSU l        Ub
  [        USS9OU R                  U l        [        USS9U l        Ub
  [        USS9OSU l        Uc  US:X  a
  [        USS9OSU l        X0l        g )NTr:      r   g{Gz?)r   _mu_k_mu_s_f_n_sigma_v_sr1   )r   mu_kf_nr1   r   r   r   s          r   r   CoulombKineticFriction.__init__J  ss    373CWT$/
373CWT$/
C-	5:5FgeD1A14C1HGC-RV	r   c                     U R                   $ )z$The coefficient of kinetic friction.)r   r   s    r   r   CoulombKineticFriction.mu_kR  r   r   c                     U R                   $ )z#The coefficient of static friction.)r   r   s    r   r   CoulombKineticFriction.mu_sW  r   r   c                     U R                   $ )z&The normal force between the surfaces.)r   r   s    r   r   CoulombKineticFriction.f_n\       yyr   c                     U R                   $ )z!The viscous friction coefficient.)r   r   s    r   r   CoulombKineticFriction.sigmaa  r6   r   c                     U R                   $ )z"The Stribeck friction coefficient.)r   r   s    r   r   CoulombKineticFriction.v_sf  r   r   c                 T   U R                   R                  nU R                  U R                  -  nU R                  U R                  -  nU R
                  b   X2-
  [        XR
                  -  S-  * 5      -  OSnU R                  b  U R                  U-  OSnX$-   [        U5      * -  U-
  $ )N   r   )	r1   r   r   r   r   r   r   r   r   )r   vf_cf_maxstribeck_termviscous_terms         r   r0   CoulombKineticFriction.forcek  s    LL++ii$(("		DHH$CG88CWa((lQ->,>(??]^)-)?tzzA~Q#Qx/,>>r   c                     [        S5      ere   rf   rg   s     r   r0   r   t  rh   r   c                     U R                   R                   SU R                   SU R                   SU R                   SU R
                   SU R                   SU R                   S3$ )NrV   rW    rX   )r$   r%   r   r   r   r1   r   r   r   s    r   r&   CoulombKineticFriction.__repr__x  s\    >>**+1TZZL4::,a99+R~R		{";;-q" 	#r   )r   r   r   r   r   r1   )r%   r(   r)   r*   r+   r   rZ   r   r   r   r   r   r0   r[   r&   r,   r   r   r   r   r     s    dL 37d            ? ? \\G G#r   r   N)r+   abcr   r   sympyr   r   r   r   sympy.physics.mechanics.jointr	   sympy.physics.mechanics.loadsr
   sympy.physics.mechanics.pathwayr   !sympy.physics.mechanics.rigidbodyr   sympy.physics.vectorr   r   __all__r   r   r   r   r   r   r   r   r   r   <module>r      s    K # ' ' 2 0 7 7 7$.3 $.NEJL EJPl= l^IL= ILXk\ k\	qBM qBfX#] X#r   