rigidbody.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. from sympy.core.backend import sympify
  2. from sympy.physics.vector import Point, ReferenceFrame, Dyadic
  3. from sympy.utilities.exceptions import sympy_deprecation_warning
  4. __all__ = ['RigidBody']
  5. class RigidBody:
  6. """An idealized rigid body.
  7. Explanation
  8. ===========
  9. This is essentially a container which holds the various components which
  10. describe a rigid body: a name, mass, center of mass, reference frame, and
  11. inertia.
  12. All of these need to be supplied on creation, but can be changed
  13. afterwards.
  14. Attributes
  15. ==========
  16. name : string
  17. The body's name.
  18. masscenter : Point
  19. The point which represents the center of mass of the rigid body.
  20. frame : ReferenceFrame
  21. The ReferenceFrame which the rigid body is fixed in.
  22. mass : Sympifyable
  23. The body's mass.
  24. inertia : (Dyadic, Point)
  25. The body's inertia about a point; stored in a tuple as shown above.
  26. Examples
  27. ========
  28. >>> from sympy import Symbol
  29. >>> from sympy.physics.mechanics import ReferenceFrame, Point, RigidBody
  30. >>> from sympy.physics.mechanics import outer
  31. >>> m = Symbol('m')
  32. >>> A = ReferenceFrame('A')
  33. >>> P = Point('P')
  34. >>> I = outer (A.x, A.x)
  35. >>> inertia_tuple = (I, P)
  36. >>> B = RigidBody('B', P, A, m, inertia_tuple)
  37. >>> # Or you could change them afterwards
  38. >>> m2 = Symbol('m2')
  39. >>> B.mass = m2
  40. """
  41. def __init__(self, name, masscenter, frame, mass, inertia):
  42. if not isinstance(name, str):
  43. raise TypeError('Supply a valid name.')
  44. self._name = name
  45. self.masscenter = masscenter
  46. self.mass = mass
  47. self.frame = frame
  48. self.inertia = inertia
  49. self.potential_energy = 0
  50. def __str__(self):
  51. return self._name
  52. def __repr__(self):
  53. return self.__str__()
  54. @property
  55. def frame(self):
  56. """The ReferenceFrame fixed to the body."""
  57. return self._frame
  58. @frame.setter
  59. def frame(self, F):
  60. if not isinstance(F, ReferenceFrame):
  61. raise TypeError("RigidBody frame must be a ReferenceFrame object.")
  62. self._frame = F
  63. @property
  64. def masscenter(self):
  65. """The body's center of mass."""
  66. return self._masscenter
  67. @masscenter.setter
  68. def masscenter(self, p):
  69. if not isinstance(p, Point):
  70. raise TypeError("RigidBody center of mass must be a Point object.")
  71. self._masscenter = p
  72. @property
  73. def mass(self):
  74. """The body's mass."""
  75. return self._mass
  76. @mass.setter
  77. def mass(self, m):
  78. self._mass = sympify(m)
  79. @property
  80. def inertia(self):
  81. """The body's inertia about a point; stored as (Dyadic, Point)."""
  82. return (self._inertia, self._inertia_point)
  83. @inertia.setter
  84. def inertia(self, I):
  85. if not isinstance(I[0], Dyadic):
  86. raise TypeError("RigidBody inertia must be a Dyadic object.")
  87. if not isinstance(I[1], Point):
  88. raise TypeError("RigidBody inertia must be about a Point.")
  89. self._inertia = I[0]
  90. self._inertia_point = I[1]
  91. # have I S/O, want I S/S*
  92. # I S/O = I S/S* + I S*/O; I S/S* = I S/O - I S*/O
  93. # I_S/S* = I_S/O - I_S*/O
  94. from sympy.physics.mechanics.functions import inertia_of_point_mass
  95. I_Ss_O = inertia_of_point_mass(self.mass,
  96. self.masscenter.pos_from(I[1]),
  97. self.frame)
  98. self._central_inertia = I[0] - I_Ss_O
  99. @property
  100. def central_inertia(self):
  101. """The body's central inertia dyadic."""
  102. return self._central_inertia
  103. @central_inertia.setter
  104. def central_inertia(self, I):
  105. if not isinstance(I, Dyadic):
  106. raise TypeError("RigidBody inertia must be a Dyadic object.")
  107. self.inertia = (I, self.masscenter)
  108. def linear_momentum(self, frame):
  109. """ Linear momentum of the rigid body.
  110. Explanation
  111. ===========
  112. The linear momentum L, of a rigid body B, with respect to frame N is
  113. given by:
  114. L = M * v*
  115. where M is the mass of the rigid body and v* is the velocity of
  116. the mass center of B in the frame, N.
  117. Parameters
  118. ==========
  119. frame : ReferenceFrame
  120. The frame in which linear momentum is desired.
  121. Examples
  122. ========
  123. >>> from sympy.physics.mechanics import Point, ReferenceFrame, outer
  124. >>> from sympy.physics.mechanics import RigidBody, dynamicsymbols
  125. >>> from sympy.physics.vector import init_vprinting
  126. >>> init_vprinting(pretty_print=False)
  127. >>> M, v = dynamicsymbols('M v')
  128. >>> N = ReferenceFrame('N')
  129. >>> P = Point('P')
  130. >>> P.set_vel(N, v * N.x)
  131. >>> I = outer (N.x, N.x)
  132. >>> Inertia_tuple = (I, P)
  133. >>> B = RigidBody('B', P, N, M, Inertia_tuple)
  134. >>> B.linear_momentum(N)
  135. M*v*N.x
  136. """
  137. return self.mass * self.masscenter.vel(frame)
  138. def angular_momentum(self, point, frame):
  139. """Returns the angular momentum of the rigid body about a point in the
  140. given frame.
  141. Explanation
  142. ===========
  143. The angular momentum H of a rigid body B about some point O in a frame
  144. N is given by:
  145. ``H = dot(I, w) + cross(r, M * v)``
  146. where I is the central inertia dyadic of B, w is the angular velocity
  147. of body B in the frame, N, r is the position vector from point O to the
  148. mass center of B, and v is the velocity of the mass center in the
  149. frame, N.
  150. Parameters
  151. ==========
  152. point : Point
  153. The point about which angular momentum is desired.
  154. frame : ReferenceFrame
  155. The frame in which angular momentum is desired.
  156. Examples
  157. ========
  158. >>> from sympy.physics.mechanics import Point, ReferenceFrame, outer
  159. >>> from sympy.physics.mechanics import RigidBody, dynamicsymbols
  160. >>> from sympy.physics.vector import init_vprinting
  161. >>> init_vprinting(pretty_print=False)
  162. >>> M, v, r, omega = dynamicsymbols('M v r omega')
  163. >>> N = ReferenceFrame('N')
  164. >>> b = ReferenceFrame('b')
  165. >>> b.set_ang_vel(N, omega * b.x)
  166. >>> P = Point('P')
  167. >>> P.set_vel(N, 1 * N.x)
  168. >>> I = outer(b.x, b.x)
  169. >>> B = RigidBody('B', P, b, M, (I, P))
  170. >>> B.angular_momentum(P, N)
  171. omega*b.x
  172. """
  173. I = self.central_inertia
  174. w = self.frame.ang_vel_in(frame)
  175. m = self.mass
  176. r = self.masscenter.pos_from(point)
  177. v = self.masscenter.vel(frame)
  178. return I.dot(w) + r.cross(m * v)
  179. def kinetic_energy(self, frame):
  180. """Kinetic energy of the rigid body.
  181. Explanation
  182. ===========
  183. The kinetic energy, T, of a rigid body, B, is given by:
  184. ``T = 1/2 * (dot(dot(I, w), w) + dot(m * v, v))``
  185. where I and m are the central inertia dyadic and mass of rigid body B,
  186. respectively, omega is the body's angular velocity and v is the
  187. velocity of the body's mass center in the supplied ReferenceFrame.
  188. Parameters
  189. ==========
  190. frame : ReferenceFrame
  191. The RigidBody's angular velocity and the velocity of it's mass
  192. center are typically defined with respect to an inertial frame but
  193. any relevant frame in which the velocities are known can be supplied.
  194. Examples
  195. ========
  196. >>> from sympy.physics.mechanics import Point, ReferenceFrame, outer
  197. >>> from sympy.physics.mechanics import RigidBody
  198. >>> from sympy import symbols
  199. >>> M, v, r, omega = symbols('M v r omega')
  200. >>> N = ReferenceFrame('N')
  201. >>> b = ReferenceFrame('b')
  202. >>> b.set_ang_vel(N, omega * b.x)
  203. >>> P = Point('P')
  204. >>> P.set_vel(N, v * N.x)
  205. >>> I = outer (b.x, b.x)
  206. >>> inertia_tuple = (I, P)
  207. >>> B = RigidBody('B', P, b, M, inertia_tuple)
  208. >>> B.kinetic_energy(N)
  209. M*v**2/2 + omega**2/2
  210. """
  211. rotational_KE = (self.frame.ang_vel_in(frame) & (self.central_inertia &
  212. self.frame.ang_vel_in(frame)) / sympify(2))
  213. translational_KE = (self.mass * (self.masscenter.vel(frame) &
  214. self.masscenter.vel(frame)) / sympify(2))
  215. return rotational_KE + translational_KE
  216. @property
  217. def potential_energy(self):
  218. """The potential energy of the RigidBody.
  219. Examples
  220. ========
  221. >>> from sympy.physics.mechanics import RigidBody, Point, outer, ReferenceFrame
  222. >>> from sympy import symbols
  223. >>> M, g, h = symbols('M g h')
  224. >>> b = ReferenceFrame('b')
  225. >>> P = Point('P')
  226. >>> I = outer (b.x, b.x)
  227. >>> Inertia_tuple = (I, P)
  228. >>> B = RigidBody('B', P, b, M, Inertia_tuple)
  229. >>> B.potential_energy = M * g * h
  230. >>> B.potential_energy
  231. M*g*h
  232. """
  233. return self._pe
  234. @potential_energy.setter
  235. def potential_energy(self, scalar):
  236. """Used to set the potential energy of this RigidBody.
  237. Parameters
  238. ==========
  239. scalar: Sympifyable
  240. The potential energy (a scalar) of the RigidBody.
  241. Examples
  242. ========
  243. >>> from sympy.physics.mechanics import Point, outer
  244. >>> from sympy.physics.mechanics import RigidBody, ReferenceFrame
  245. >>> from sympy import symbols
  246. >>> b = ReferenceFrame('b')
  247. >>> M, g, h = symbols('M g h')
  248. >>> P = Point('P')
  249. >>> I = outer (b.x, b.x)
  250. >>> Inertia_tuple = (I, P)
  251. >>> B = RigidBody('B', P, b, M, Inertia_tuple)
  252. >>> B.potential_energy = M * g * h
  253. """
  254. self._pe = sympify(scalar)
  255. def set_potential_energy(self, scalar):
  256. sympy_deprecation_warning(
  257. """
  258. The sympy.physics.mechanics.RigidBody.set_potential_energy()
  259. method is deprecated. Instead use
  260. B.potential_energy = scalar
  261. """,
  262. deprecated_since_version="1.5",
  263. active_deprecations_target="deprecated-set-potential-energy",
  264. )
  265. self.potential_energy = scalar
  266. def parallel_axis(self, point, frame=None):
  267. """Returns the inertia dyadic of the body with respect to another
  268. point.
  269. Parameters
  270. ==========
  271. point : sympy.physics.vector.Point
  272. The point to express the inertia dyadic about.
  273. frame : sympy.physics.vector.ReferenceFrame
  274. The reference frame used to construct the dyadic.
  275. Returns
  276. =======
  277. inertia : sympy.physics.vector.Dyadic
  278. The inertia dyadic of the rigid body expressed about the provided
  279. point.
  280. """
  281. # circular import issue
  282. from sympy.physics.mechanics.functions import inertia_of_point_mass
  283. if frame is None:
  284. frame = self.frame
  285. return self.central_inertia + inertia_of_point_mass(
  286. self.mass, self.masscenter.pos_from(point), frame)