|
from sympy import Symbol, S |
|
from sympy.physics.vector import ReferenceFrame, Dyadic, Point, dot |
|
from sympy.physics.mechanics.body_base import BodyBase |
|
from sympy.physics.mechanics.inertia import inertia_of_point_mass, Inertia |
|
from sympy.utilities.exceptions import sympy_deprecation_warning |
|
|
|
__all__ = ['RigidBody'] |
|
|
|
|
|
class RigidBody(BodyBase): |
|
"""An idealized rigid body. |
|
|
|
Explanation |
|
=========== |
|
|
|
This is essentially a container which holds the various components which |
|
describe a rigid body: a name, mass, center of mass, reference frame, and |
|
inertia. |
|
|
|
All of these need to be supplied on creation, but can be changed |
|
afterwards. |
|
|
|
Attributes |
|
========== |
|
|
|
name : string |
|
The body's name. |
|
masscenter : Point |
|
The point which represents the center of mass of the rigid body. |
|
frame : ReferenceFrame |
|
The ReferenceFrame which the rigid body is fixed in. |
|
mass : Sympifyable |
|
The body's mass. |
|
inertia : (Dyadic, Point) |
|
The body's inertia about a point; stored in a tuple as shown above. |
|
potential_energy : Sympifyable |
|
The potential energy of the RigidBody. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy import Symbol |
|
>>> from sympy.physics.mechanics import ReferenceFrame, Point, RigidBody |
|
>>> from sympy.physics.mechanics import outer |
|
>>> m = Symbol('m') |
|
>>> A = ReferenceFrame('A') |
|
>>> P = Point('P') |
|
>>> I = outer (A.x, A.x) |
|
>>> inertia_tuple = (I, P) |
|
>>> B = RigidBody('B', P, A, m, inertia_tuple) |
|
>>> # Or you could change them afterwards |
|
>>> m2 = Symbol('m2') |
|
>>> B.mass = m2 |
|
|
|
""" |
|
|
|
def __init__(self, name, masscenter=None, frame=None, mass=None, |
|
inertia=None): |
|
super().__init__(name, masscenter, mass) |
|
if frame is None: |
|
frame = ReferenceFrame(f'{name}_frame') |
|
self.frame = frame |
|
if inertia is None: |
|
ixx = Symbol(f'{name}_ixx') |
|
iyy = Symbol(f'{name}_iyy') |
|
izz = Symbol(f'{name}_izz') |
|
izx = Symbol(f'{name}_izx') |
|
ixy = Symbol(f'{name}_ixy') |
|
iyz = Symbol(f'{name}_iyz') |
|
inertia = Inertia.from_inertia_scalars(self.masscenter, self.frame, |
|
ixx, iyy, izz, ixy, iyz, izx) |
|
self.inertia = inertia |
|
|
|
def __repr__(self): |
|
return (f'{self.__class__.__name__}({repr(self.name)}, masscenter=' |
|
f'{repr(self.masscenter)}, frame={repr(self.frame)}, mass=' |
|
f'{repr(self.mass)}, inertia={repr(self.inertia)})') |
|
|
|
@property |
|
def frame(self): |
|
"""The ReferenceFrame fixed to the body.""" |
|
return self._frame |
|
|
|
@frame.setter |
|
def frame(self, F): |
|
if not isinstance(F, ReferenceFrame): |
|
raise TypeError("RigidBody frame must be a ReferenceFrame object.") |
|
self._frame = F |
|
|
|
@property |
|
def x(self): |
|
"""The basis Vector for the body, in the x direction. """ |
|
return self.frame.x |
|
|
|
@property |
|
def y(self): |
|
"""The basis Vector for the body, in the y direction. """ |
|
return self.frame.y |
|
|
|
@property |
|
def z(self): |
|
"""The basis Vector for the body, in the z direction. """ |
|
return self.frame.z |
|
|
|
@property |
|
def inertia(self): |
|
"""The body's inertia about a point; stored as (Dyadic, Point).""" |
|
return self._inertia |
|
|
|
@inertia.setter |
|
def inertia(self, I): |
|
|
|
if len(I) != 2 or not isinstance(I[0], Dyadic) or not isinstance(I[1], Point): |
|
raise TypeError("RigidBody inertia must be a tuple of the form (Dyadic, Point).") |
|
|
|
self._inertia = Inertia(I[0], I[1]) |
|
|
|
|
|
|
|
I_Ss_O = inertia_of_point_mass(self.mass, |
|
self.masscenter.pos_from(I[1]), |
|
self.frame) |
|
self._central_inertia = I[0] - I_Ss_O |
|
|
|
@property |
|
def central_inertia(self): |
|
"""The body's central inertia dyadic.""" |
|
return self._central_inertia |
|
|
|
@central_inertia.setter |
|
def central_inertia(self, I): |
|
if not isinstance(I, Dyadic): |
|
raise TypeError("RigidBody inertia must be a Dyadic object.") |
|
self.inertia = Inertia(I, self.masscenter) |
|
|
|
def linear_momentum(self, frame): |
|
""" Linear momentum of the rigid body. |
|
|
|
Explanation |
|
=========== |
|
|
|
The linear momentum L, of a rigid body B, with respect to frame N is |
|
given by: |
|
|
|
``L = m * v`` |
|
|
|
where m is the mass of the rigid body, and v is the velocity of the mass |
|
center of B in the frame N. |
|
|
|
Parameters |
|
========== |
|
|
|
frame : ReferenceFrame |
|
The frame in which linear momentum is desired. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.physics.mechanics import Point, ReferenceFrame, outer |
|
>>> from sympy.physics.mechanics import RigidBody, dynamicsymbols |
|
>>> from sympy.physics.vector import init_vprinting |
|
>>> init_vprinting(pretty_print=False) |
|
>>> m, v = dynamicsymbols('m v') |
|
>>> N = ReferenceFrame('N') |
|
>>> P = Point('P') |
|
>>> P.set_vel(N, v * N.x) |
|
>>> I = outer (N.x, N.x) |
|
>>> Inertia_tuple = (I, P) |
|
>>> B = RigidBody('B', P, N, m, Inertia_tuple) |
|
>>> B.linear_momentum(N) |
|
m*v*N.x |
|
|
|
""" |
|
|
|
return self.mass * self.masscenter.vel(frame) |
|
|
|
def angular_momentum(self, point, frame): |
|
"""Returns the angular momentum of the rigid body about a point in the |
|
given frame. |
|
|
|
Explanation |
|
=========== |
|
|
|
The angular momentum H of a rigid body B about some point O in a frame N |
|
is given by: |
|
|
|
``H = dot(I, w) + cross(r, m * v)`` |
|
|
|
where I and m are the central inertia dyadic and mass of rigid body B, w |
|
is the angular velocity of body B in the frame N, r is the position |
|
vector from point O to the mass center of B, and v is the velocity of |
|
the mass center in the frame N. |
|
|
|
Parameters |
|
========== |
|
|
|
point : Point |
|
The point about which angular momentum is desired. |
|
frame : ReferenceFrame |
|
The frame in which angular momentum is desired. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.physics.mechanics import Point, ReferenceFrame, outer |
|
>>> from sympy.physics.mechanics import RigidBody, dynamicsymbols |
|
>>> from sympy.physics.vector import init_vprinting |
|
>>> init_vprinting(pretty_print=False) |
|
>>> m, v, r, omega = dynamicsymbols('m v r omega') |
|
>>> N = ReferenceFrame('N') |
|
>>> b = ReferenceFrame('b') |
|
>>> b.set_ang_vel(N, omega * b.x) |
|
>>> P = Point('P') |
|
>>> P.set_vel(N, 1 * N.x) |
|
>>> I = outer(b.x, b.x) |
|
>>> B = RigidBody('B', P, b, m, (I, P)) |
|
>>> B.angular_momentum(P, N) |
|
omega*b.x |
|
|
|
""" |
|
I = self.central_inertia |
|
w = self.frame.ang_vel_in(frame) |
|
m = self.mass |
|
r = self.masscenter.pos_from(point) |
|
v = self.masscenter.vel(frame) |
|
|
|
return I.dot(w) + r.cross(m * v) |
|
|
|
def kinetic_energy(self, frame): |
|
"""Kinetic energy of the rigid body. |
|
|
|
Explanation |
|
=========== |
|
|
|
The kinetic energy, T, of a rigid body, B, is given by: |
|
|
|
``T = 1/2 * (dot(dot(I, w), w) + dot(m * v, v))`` |
|
|
|
where I and m are the central inertia dyadic and mass of rigid body B |
|
respectively, w is the body's angular velocity, and v is the velocity of |
|
the body's mass center in the supplied ReferenceFrame. |
|
|
|
Parameters |
|
========== |
|
|
|
frame : ReferenceFrame |
|
The RigidBody's angular velocity and the velocity of it's mass |
|
center are typically defined with respect to an inertial frame but |
|
any relevant frame in which the velocities are known can be |
|
supplied. |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy.physics.mechanics import Point, ReferenceFrame, outer |
|
>>> from sympy.physics.mechanics import RigidBody |
|
>>> from sympy import symbols |
|
>>> m, v, r, omega = symbols('m v r omega') |
|
>>> N = ReferenceFrame('N') |
|
>>> b = ReferenceFrame('b') |
|
>>> b.set_ang_vel(N, omega * b.x) |
|
>>> P = Point('P') |
|
>>> P.set_vel(N, v * N.x) |
|
>>> I = outer (b.x, b.x) |
|
>>> inertia_tuple = (I, P) |
|
>>> B = RigidBody('B', P, b, m, inertia_tuple) |
|
>>> B.kinetic_energy(N) |
|
m*v**2/2 + omega**2/2 |
|
|
|
""" |
|
|
|
rotational_KE = S.Half * dot( |
|
self.frame.ang_vel_in(frame), |
|
dot(self.central_inertia, self.frame.ang_vel_in(frame))) |
|
translational_KE = S.Half * self.mass * dot(self.masscenter.vel(frame), |
|
self.masscenter.vel(frame)) |
|
return rotational_KE + translational_KE |
|
|
|
def set_potential_energy(self, scalar): |
|
sympy_deprecation_warning( |
|
""" |
|
The sympy.physics.mechanics.RigidBody.set_potential_energy() |
|
method is deprecated. Instead use |
|
|
|
B.potential_energy = scalar |
|
""", |
|
deprecated_since_version="1.5", |
|
active_deprecations_target="deprecated-set-potential-energy", |
|
) |
|
self.potential_energy = scalar |
|
|
|
def parallel_axis(self, point, frame=None): |
|
"""Returns the inertia dyadic of the body with respect to another point. |
|
|
|
Parameters |
|
========== |
|
|
|
point : sympy.physics.vector.Point |
|
The point to express the inertia dyadic about. |
|
frame : sympy.physics.vector.ReferenceFrame |
|
The reference frame used to construct the dyadic. |
|
|
|
Returns |
|
======= |
|
|
|
inertia : sympy.physics.vector.Dyadic |
|
The inertia dyadic of the rigid body expressed about the provided |
|
point. |
|
|
|
""" |
|
if frame is None: |
|
frame = self.frame |
|
return self.central_inertia + inertia_of_point_mass( |
|
self.mass, self.masscenter.pos_from(point), frame) |
|
|