test_joint.py 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144
  1. from sympy.core.function import expand_mul
  2. from sympy.core.numbers import pi
  3. from sympy.core.singleton import S
  4. from sympy.functions.elementary.miscellaneous import sqrt
  5. from sympy.functions.elementary.trigonometric import (cos, sin)
  6. from sympy.core.backend import Matrix, _simplify_matrix, eye, zeros
  7. from sympy.core.symbol import symbols
  8. from sympy.physics.mechanics import (dynamicsymbols, Body, JointsMethod,
  9. PinJoint, PrismaticJoint, CylindricalJoint,
  10. PlanarJoint, SphericalJoint, WeldJoint)
  11. from sympy.physics.mechanics.joint import Joint
  12. from sympy.physics.vector import Vector, ReferenceFrame, Point
  13. from sympy.testing.pytest import raises, warns_deprecated_sympy
  14. Vector.simp = True
  15. t = dynamicsymbols._t # type: ignore
  16. def _generate_body(interframe=False):
  17. N = ReferenceFrame('N')
  18. A = ReferenceFrame('A')
  19. P = Body('P', frame=N)
  20. C = Body('C', frame=A)
  21. if interframe:
  22. Pint, Cint = ReferenceFrame('P_int'), ReferenceFrame('C_int')
  23. Pint.orient_axis(N, N.x, pi)
  24. Cint.orient_axis(A, A.y, -pi / 2)
  25. return N, A, P, C, Pint, Cint
  26. return N, A, P, C
  27. def test_Joint():
  28. parent = Body('parent')
  29. child = Body('child')
  30. raises(TypeError, lambda: Joint('J', parent, child))
  31. def test_coordinate_generation():
  32. q, u, qj, uj = dynamicsymbols('q u q_J u_J')
  33. q0j, q1j, q2j, q3j, u0j, u1j, u2j, u3j = dynamicsymbols('q0:4_J u0:4_J')
  34. q0, q1, q2, q3, u0, u1, u2, u3 = dynamicsymbols('q0:4 u0:4')
  35. _, _, P, C = _generate_body()
  36. # Using PinJoint to access Joint's coordinate generation method
  37. J = PinJoint('J', P, C)
  38. # Test single given
  39. assert J._fill_coordinate_list(q, 1) == Matrix([q])
  40. assert J._fill_coordinate_list([u], 1) == Matrix([u])
  41. assert J._fill_coordinate_list([u], 1, offset=2) == Matrix([u])
  42. # Test None
  43. assert J._fill_coordinate_list(None, 1) == Matrix([qj])
  44. assert J._fill_coordinate_list([None], 1) == Matrix([qj])
  45. assert J._fill_coordinate_list([q0, None, None], 3) == Matrix(
  46. [q0, q1j, q2j])
  47. # Test autofill
  48. assert J._fill_coordinate_list(None, 3) == Matrix([q0j, q1j, q2j])
  49. assert J._fill_coordinate_list([], 3) == Matrix([q0j, q1j, q2j])
  50. # Test offset
  51. assert J._fill_coordinate_list([], 3, offset=1) == Matrix([q1j, q2j, q3j])
  52. assert J._fill_coordinate_list([q1, None, q3], 3, offset=1) == Matrix(
  53. [q1, q2j, q3])
  54. assert J._fill_coordinate_list(None, 2, offset=2) == Matrix([q2j, q3j])
  55. # Test label
  56. assert J._fill_coordinate_list(None, 1, 'u') == Matrix([uj])
  57. assert J._fill_coordinate_list([], 3, 'u') == Matrix([u0j, u1j, u2j])
  58. # Test single numbering
  59. assert J._fill_coordinate_list(None, 1, number_single=True) == Matrix([q0j])
  60. assert J._fill_coordinate_list([], 1, 'u', 2, True) == Matrix([u2j])
  61. assert J._fill_coordinate_list([], 3, 'q') == Matrix([q0j, q1j, q2j])
  62. # Test invalid number of coordinates supplied
  63. raises(ValueError, lambda: J._fill_coordinate_list([q0, q1], 1))
  64. raises(ValueError, lambda: J._fill_coordinate_list([u0, u1, None], 2, 'u'))
  65. raises(ValueError, lambda: J._fill_coordinate_list([q0, q1], 3))
  66. # Test incorrect coordinate type
  67. raises(TypeError, lambda: J._fill_coordinate_list([q0, symbols('q1')], 2))
  68. raises(TypeError, lambda: J._fill_coordinate_list([q0 + q1, q1], 2))
  69. # Test if derivative as generalized speed is allowed
  70. _, _, P, C = _generate_body()
  71. PinJoint('J', P, C, q1, q1.diff(t))
  72. # Test duplicate coordinates
  73. _, _, P, C = _generate_body()
  74. raises(ValueError, lambda: SphericalJoint('J', P, C, [q1j, None, None]))
  75. raises(ValueError, lambda: SphericalJoint('J', P, C, speeds=[u0, u0, u1]))
  76. def test_pin_joint():
  77. P = Body('P')
  78. C = Body('C')
  79. l, m = symbols('l m')
  80. q, u = dynamicsymbols('q_J, u_J')
  81. Pj = PinJoint('J', P, C)
  82. assert Pj.name == 'J'
  83. assert Pj.parent == P
  84. assert Pj.child == C
  85. assert Pj.coordinates == Matrix([q])
  86. assert Pj.speeds == Matrix([u])
  87. assert Pj.kdes == Matrix([u - q.diff(t)])
  88. assert Pj.joint_axis == P.frame.x
  89. assert Pj.child_point.pos_from(C.masscenter) == Vector(0)
  90. assert Pj.parent_point.pos_from(P.masscenter) == Vector(0)
  91. assert Pj.parent_point.pos_from(Pj._child_point) == Vector(0)
  92. assert C.masscenter.pos_from(P.masscenter) == Vector(0)
  93. assert Pj.parent_interframe == P.frame
  94. assert Pj.child_interframe == C.frame
  95. assert Pj.__str__() == 'PinJoint: J parent: P child: C'
  96. P1 = Body('P1')
  97. C1 = Body('C1')
  98. Pint = ReferenceFrame('P_int')
  99. Pint.orient_axis(P1.frame, P1.y, pi / 2)
  100. J1 = PinJoint('J1', P1, C1, parent_point=l*P1.frame.x,
  101. child_point=m*C1.frame.y, joint_axis=P1.frame.z,
  102. parent_interframe=Pint)
  103. assert J1._joint_axis == P1.frame.z
  104. assert J1._child_point.pos_from(C1.masscenter) == m * C1.frame.y
  105. assert J1._parent_point.pos_from(P1.masscenter) == l * P1.frame.x
  106. assert J1._parent_point.pos_from(J1._child_point) == Vector(0)
  107. assert (P1.masscenter.pos_from(C1.masscenter) ==
  108. -l*P1.frame.x + m*C1.frame.y)
  109. assert J1.parent_interframe == Pint
  110. assert J1.child_interframe == C1.frame
  111. q, u = dynamicsymbols('q, u')
  112. N, A, P, C, Pint, Cint = _generate_body(True)
  113. parent_point = P.masscenter.locatenew('parent_point', N.x + N.y)
  114. child_point = C.masscenter.locatenew('child_point', C.y + C.z)
  115. J = PinJoint('J', P, C, q, u, parent_point=parent_point,
  116. child_point=child_point, parent_interframe=Pint,
  117. child_interframe=Cint, joint_axis=N.z)
  118. assert J.joint_axis == N.z
  119. assert J.parent_point.vel(N) == 0
  120. assert J.parent_point == parent_point
  121. assert J.child_point == child_point
  122. assert J.child_point.pos_from(P.masscenter) == N.x + N.y
  123. assert J.parent_point.pos_from(C.masscenter) == C.y + C.z
  124. assert C.masscenter.pos_from(P.masscenter) == N.x + N.y - C.y - C.z
  125. assert C.masscenter.vel(N).express(N) == (u * sin(q) - u * cos(q)) * N.x + (
  126. -u * sin(q) - u * cos(q)) * N.y
  127. assert J.parent_interframe == Pint
  128. assert J.child_interframe == Cint
  129. def test_pin_joint_double_pendulum():
  130. q1, q2 = dynamicsymbols('q1 q2')
  131. u1, u2 = dynamicsymbols('u1 u2')
  132. m, l = symbols('m l')
  133. N = ReferenceFrame('N')
  134. A = ReferenceFrame('A')
  135. B = ReferenceFrame('B')
  136. C = Body('C', frame=N) # ceiling
  137. PartP = Body('P', frame=A, mass=m)
  138. PartR = Body('R', frame=B, mass=m)
  139. J1 = PinJoint('J1', C, PartP, speeds=u1, coordinates=q1,
  140. child_point=-l*A.x, joint_axis=C.frame.z)
  141. J2 = PinJoint('J2', PartP, PartR, speeds=u2, coordinates=q2,
  142. child_point=-l*B.x, joint_axis=PartP.frame.z)
  143. # Check orientation
  144. assert N.dcm(A) == Matrix([[cos(q1), -sin(q1), 0],
  145. [sin(q1), cos(q1), 0], [0, 0, 1]])
  146. assert A.dcm(B) == Matrix([[cos(q2), -sin(q2), 0],
  147. [sin(q2), cos(q2), 0], [0, 0, 1]])
  148. assert _simplify_matrix(N.dcm(B)) == Matrix([[cos(q1 + q2), -sin(q1 + q2), 0],
  149. [sin(q1 + q2), cos(q1 + q2), 0],
  150. [0, 0, 1]])
  151. # Check Angular Velocity
  152. assert A.ang_vel_in(N) == u1 * N.z
  153. assert B.ang_vel_in(A) == u2 * A.z
  154. assert B.ang_vel_in(N) == u1 * N.z + u2 * A.z
  155. # Check kde
  156. assert J1.kdes == Matrix([u1 - q1.diff(t)])
  157. assert J2.kdes == Matrix([u2 - q2.diff(t)])
  158. # Check Linear Velocity
  159. assert PartP.masscenter.vel(N) == l*u1*A.y
  160. assert PartR.masscenter.vel(A) == l*u2*B.y
  161. assert PartR.masscenter.vel(N) == l*u1*A.y + l*(u1 + u2)*B.y
  162. def test_pin_joint_chaos_pendulum():
  163. mA, mB, lA, lB, h = symbols('mA, mB, lA, lB, h')
  164. theta, phi, omega, alpha = dynamicsymbols('theta phi omega alpha')
  165. N = ReferenceFrame('N')
  166. A = ReferenceFrame('A')
  167. B = ReferenceFrame('B')
  168. lA = (lB - h / 2) / 2
  169. lC = (lB/2 + h/4)
  170. rod = Body('rod', frame=A, mass=mA)
  171. plate = Body('plate', mass=mB, frame=B)
  172. C = Body('C', frame=N)
  173. J1 = PinJoint('J1', C, rod, coordinates=theta, speeds=omega,
  174. child_point=lA*A.z, joint_axis=N.y)
  175. J2 = PinJoint('J2', rod, plate, coordinates=phi, speeds=alpha,
  176. parent_point=lC*A.z, joint_axis=A.z)
  177. # Check orientation
  178. assert A.dcm(N) == Matrix([[cos(theta), 0, -sin(theta)],
  179. [0, 1, 0],
  180. [sin(theta), 0, cos(theta)]])
  181. assert A.dcm(B) == Matrix([[cos(phi), -sin(phi), 0],
  182. [sin(phi), cos(phi), 0],
  183. [0, 0, 1]])
  184. assert B.dcm(N) == Matrix([
  185. [cos(phi)*cos(theta), sin(phi), -sin(theta)*cos(phi)],
  186. [-sin(phi)*cos(theta), cos(phi), sin(phi)*sin(theta)],
  187. [sin(theta), 0, cos(theta)]])
  188. # Check Angular Velocity
  189. assert A.ang_vel_in(N) == omega*N.y
  190. assert A.ang_vel_in(B) == -alpha*A.z
  191. assert N.ang_vel_in(B) == -omega*N.y - alpha*A.z
  192. # Check kde
  193. assert J1.kdes == Matrix([omega - theta.diff(t)])
  194. assert J2.kdes == Matrix([alpha - phi.diff(t)])
  195. # Check pos of masscenters
  196. assert C.masscenter.pos_from(rod.masscenter) == lA*A.z
  197. assert rod.masscenter.pos_from(plate.masscenter) == - lC * A.z
  198. # Check Linear Velocities
  199. assert rod.masscenter.vel(N) == (h/4 - lB/2)*omega*A.x
  200. assert plate.masscenter.vel(N) == ((h/4 - lB/2)*omega +
  201. (h/4 + lB/2)*omega)*A.x
  202. def test_pin_joint_interframe():
  203. q, u = dynamicsymbols('q, u')
  204. # Check not connected
  205. N, A, P, C = _generate_body()
  206. Pint, Cint = ReferenceFrame('Pint'), ReferenceFrame('Cint')
  207. raises(ValueError, lambda: PinJoint('J', P, C, parent_interframe=Pint))
  208. raises(ValueError, lambda: PinJoint('J', P, C, child_interframe=Cint))
  209. # Check not fixed interframe
  210. Pint.orient_axis(N, N.z, q)
  211. Cint.orient_axis(A, A.z, q)
  212. raises(ValueError, lambda: PinJoint('J', P, C, parent_interframe=Pint))
  213. raises(ValueError, lambda: PinJoint('J', P, C, child_interframe=Cint))
  214. # Check only parent_interframe
  215. N, A, P, C = _generate_body()
  216. Pint = ReferenceFrame('Pint')
  217. Pint.orient_body_fixed(N, (pi / 4, pi, pi / 3), 'xyz')
  218. PinJoint('J', P, C, q, u, parent_point=N.x, child_point=-C.y,
  219. parent_interframe=Pint, joint_axis=Pint.x)
  220. assert _simplify_matrix(N.dcm(A)) - Matrix([
  221. [-1 / 2, sqrt(3) * cos(q) / 2, -sqrt(3) * sin(q) / 2],
  222. [sqrt(6) / 4, sqrt(2) * (2 * sin(q) + cos(q)) / 4,
  223. sqrt(2) * (-sin(q) + 2 * cos(q)) / 4],
  224. [sqrt(6) / 4, sqrt(2) * (-2 * sin(q) + cos(q)) / 4,
  225. -sqrt(2) * (sin(q) + 2 * cos(q)) / 4]]) == zeros(3)
  226. assert A.ang_vel_in(N) == u * Pint.x
  227. assert C.masscenter.pos_from(P.masscenter) == N.x + A.y
  228. assert C.masscenter.vel(N) == u * A.z
  229. assert P.masscenter.vel(Pint) == Vector(0)
  230. assert C.masscenter.vel(Pint) == u * A.z
  231. # Check only child_interframe
  232. N, A, P, C = _generate_body()
  233. Cint = ReferenceFrame('Cint')
  234. Cint.orient_body_fixed(A, (2 * pi / 3, -pi, pi / 2), 'xyz')
  235. PinJoint('J', P, C, q, u, parent_point=-N.z, child_point=C.x,
  236. child_interframe=Cint, joint_axis=P.x + P.z)
  237. assert _simplify_matrix(N.dcm(A)) == Matrix([
  238. [-sqrt(2) * sin(q) / 2,
  239. -sqrt(3) * (cos(q) - 1) / 4 - cos(q) / 4 - S(1) / 4,
  240. sqrt(3) * (cos(q) + 1) / 4 - cos(q) / 4 + S(1) / 4],
  241. [cos(q), (sqrt(2) + sqrt(6)) * -sin(q) / 4,
  242. (-sqrt(2) + sqrt(6)) * sin(q) / 4],
  243. [sqrt(2) * sin(q) / 2,
  244. sqrt(3) * (cos(q) + 1) / 4 + cos(q) / 4 - S(1) / 4,
  245. sqrt(3) * (1 - cos(q)) / 4 + cos(q) / 4 + S(1) / 4]])
  246. assert A.ang_vel_in(N) == sqrt(2) * u / 2 * N.x + sqrt(2) * u / 2 * N.z
  247. assert C.masscenter.pos_from(P.masscenter) == - N.z - A.x
  248. assert C.masscenter.vel(N).simplify() == (
  249. -sqrt(6) - sqrt(2)) * u / 4 * A.y + (
  250. -sqrt(2) + sqrt(6)) * u / 4 * A.z
  251. assert C.masscenter.vel(Cint) == Vector(0)
  252. # Check combination
  253. N, A, P, C = _generate_body()
  254. Pint, Cint = ReferenceFrame('Pint'), ReferenceFrame('Cint')
  255. Pint.orient_body_fixed(N, (-pi / 2, pi, pi / 2), 'xyz')
  256. Cint.orient_body_fixed(A, (2 * pi / 3, -pi, pi / 2), 'xyz')
  257. PinJoint('J', P, C, q, u, parent_point=N.x - N.y, child_point=-C.z,
  258. parent_interframe=Pint, child_interframe=Cint,
  259. joint_axis=Pint.x + Pint.z)
  260. assert _simplify_matrix(N.dcm(A)) == Matrix([
  261. [cos(q), (sqrt(2) + sqrt(6)) * -sin(q) / 4,
  262. (-sqrt(2) + sqrt(6)) * sin(q) / 4],
  263. [-sqrt(2) * sin(q) / 2,
  264. -sqrt(3) * (cos(q) + 1) / 4 - cos(q) / 4 + S(1) / 4,
  265. sqrt(3) * (cos(q) - 1) / 4 - cos(q) / 4 - S(1) / 4],
  266. [sqrt(2) * sin(q) / 2,
  267. sqrt(3) * (cos(q) - 1) / 4 + cos(q) / 4 + S(1) / 4,
  268. -sqrt(3) * (cos(q) + 1) / 4 + cos(q) / 4 - S(1) / 4]])
  269. assert A.ang_vel_in(N) == sqrt(2) * u / 2 * Pint.x + sqrt(
  270. 2) * u / 2 * Pint.z
  271. assert C.masscenter.pos_from(P.masscenter) == N.x - N.y + A.z
  272. N_v_C = (-sqrt(2) + sqrt(6)) * u / 4 * A.x
  273. assert C.masscenter.vel(N).simplify() == N_v_C
  274. assert C.masscenter.vel(Pint).simplify() == N_v_C
  275. assert C.masscenter.vel(Cint) == Vector(0)
  276. def test_pin_joint_joint_axis():
  277. q, u = dynamicsymbols('q, u')
  278. # Check parent as reference
  279. N, A, P, C, Pint, Cint = _generate_body(True)
  280. pin = PinJoint('J', P, C, q, u, parent_interframe=Pint,
  281. child_interframe=Cint, joint_axis=P.y)
  282. assert pin.joint_axis == P.y
  283. assert N.dcm(A) == Matrix([[sin(q), 0, cos(q)], [0, -1, 0],
  284. [cos(q), 0, -sin(q)]])
  285. # Check parent_interframe as reference
  286. N, A, P, C, Pint, Cint = _generate_body(True)
  287. pin = PinJoint('J', P, C, q, u, parent_interframe=Pint,
  288. child_interframe=Cint, joint_axis=Pint.y)
  289. assert pin.joint_axis == Pint.y
  290. assert N.dcm(A) == Matrix([[-sin(q), 0, cos(q)], [0, -1, 0],
  291. [cos(q), 0, sin(q)]])
  292. # Check combination of joint_axis with interframes supplied as vectors (2x)
  293. N, A, P, C = _generate_body()
  294. pin = PinJoint('J', P, C, q, u, parent_interframe=N.z,
  295. child_interframe=-C.z, joint_axis=N.z)
  296. assert pin.joint_axis == N.z
  297. assert N.dcm(A) == Matrix([[-cos(q), -sin(q), 0], [-sin(q), cos(q), 0],
  298. [0, 0, -1]])
  299. N, A, P, C = _generate_body()
  300. pin = PinJoint('J', P, C, q, u, parent_interframe=N.z,
  301. child_interframe=-C.z, joint_axis=N.x)
  302. assert pin.joint_axis == N.x
  303. assert N.dcm(A) == Matrix([[-1, 0, 0], [0, cos(q), sin(q)],
  304. [0, sin(q), -cos(q)]])
  305. # Check time varying axis
  306. N, A, P, C, Pint, Cint = _generate_body(True)
  307. raises(ValueError, lambda: PinJoint('J', P, C,
  308. joint_axis=cos(q) * N.x + sin(q) * N.y))
  309. # Check joint_axis provided in child frame
  310. raises(ValueError, lambda: PinJoint('J', P, C, joint_axis=C.x))
  311. # Check some invalid combinations
  312. raises(ValueError, lambda: PinJoint('J', P, C, joint_axis=P.x + C.y))
  313. raises(ValueError, lambda: PinJoint(
  314. 'J', P, C, parent_interframe=Pint, child_interframe=Cint,
  315. joint_axis=Pint.x + C.y))
  316. raises(ValueError, lambda: PinJoint(
  317. 'J', P, C, parent_interframe=Pint, child_interframe=Cint,
  318. joint_axis=P.x + Cint.y))
  319. # Check valid special combination
  320. N, A, P, C, Pint, Cint = _generate_body(True)
  321. PinJoint('J', P, C, parent_interframe=Pint, child_interframe=Cint,
  322. joint_axis=Pint.x + P.y)
  323. # Check invalid zero vector
  324. raises(Exception, lambda: PinJoint(
  325. 'J', P, C, parent_interframe=Pint, child_interframe=Cint,
  326. joint_axis=Vector(0)))
  327. raises(Exception, lambda: PinJoint(
  328. 'J', P, C, parent_interframe=Pint, child_interframe=Cint,
  329. joint_axis=P.y + Pint.y))
  330. def test_pin_joint_arbitrary_axis():
  331. q, u = dynamicsymbols('q_J, u_J')
  332. # When the bodies are attached though masscenters but axes are opposite.
  333. N, A, P, C = _generate_body()
  334. PinJoint('J', P, C, child_interframe=-A.x)
  335. assert (-A.x).angle_between(N.x) == 0
  336. assert -A.x.express(N) == N.x
  337. assert A.dcm(N) == Matrix([[-1, 0, 0],
  338. [0, -cos(q), -sin(q)],
  339. [0, -sin(q), cos(q)]])
  340. assert A.ang_vel_in(N) == u*N.x
  341. assert A.ang_vel_in(N).magnitude() == sqrt(u**2)
  342. assert C.masscenter.pos_from(P.masscenter) == 0
  343. assert C.masscenter.pos_from(P.masscenter).express(N).simplify() == 0
  344. assert C.masscenter.vel(N) == 0
  345. # When axes are different and parent joint is at masscenter but child joint
  346. # is at a unit vector from child masscenter.
  347. N, A, P, C = _generate_body()
  348. PinJoint('J', P, C, child_interframe=A.y, child_point=A.x)
  349. assert A.y.angle_between(N.x) == 0 # Axis are aligned
  350. assert A.y.express(N) == N.x
  351. assert A.dcm(N) == Matrix([[0, -cos(q), -sin(q)],
  352. [1, 0, 0],
  353. [0, -sin(q), cos(q)]])
  354. assert A.ang_vel_in(N) == u*N.x
  355. assert A.ang_vel_in(N).express(A) == u * A.y
  356. assert A.ang_vel_in(N).magnitude() == sqrt(u**2)
  357. assert A.ang_vel_in(N).cross(A.y) == 0
  358. assert C.masscenter.vel(N) == u*A.z
  359. assert C.masscenter.pos_from(P.masscenter) == -A.x
  360. assert (C.masscenter.pos_from(P.masscenter).express(N).simplify() ==
  361. cos(q)*N.y + sin(q)*N.z)
  362. assert C.masscenter.vel(N).angle_between(A.x) == pi/2
  363. # Similar to previous case but wrt parent body
  364. N, A, P, C = _generate_body()
  365. PinJoint('J', P, C, parent_interframe=N.y, parent_point=N.x)
  366. assert N.y.angle_between(A.x) == 0 # Axis are aligned
  367. assert N.y.express(A) == A.x
  368. assert A.dcm(N) == Matrix([[0, 1, 0],
  369. [-cos(q), 0, sin(q)],
  370. [sin(q), 0, cos(q)]])
  371. assert A.ang_vel_in(N) == u*N.y
  372. assert A.ang_vel_in(N).express(A) == u*A.x
  373. assert A.ang_vel_in(N).magnitude() == sqrt(u**2)
  374. angle = A.ang_vel_in(N).angle_between(A.x)
  375. assert angle.xreplace({u: 1}) == 0
  376. assert C.masscenter.vel(N) == 0
  377. assert C.masscenter.pos_from(P.masscenter) == N.x
  378. # Both joint pos id defined but different axes
  379. N, A, P, C = _generate_body()
  380. PinJoint('J', P, C, parent_point=N.x, child_point=A.x,
  381. child_interframe=A.x + A.y)
  382. assert expand_mul(N.x.angle_between(A.x + A.y)) == 0 # Axis are aligned
  383. assert (A.x + A.y).express(N).simplify() == sqrt(2)*N.x
  384. assert _simplify_matrix(A.dcm(N)) == Matrix([
  385. [sqrt(2)/2, -sqrt(2)*cos(q)/2, -sqrt(2)*sin(q)/2],
  386. [sqrt(2)/2, sqrt(2)*cos(q)/2, sqrt(2)*sin(q)/2],
  387. [0, -sin(q), cos(q)]])
  388. assert A.ang_vel_in(N) == u*N.x
  389. assert (A.ang_vel_in(N).express(A).simplify() ==
  390. (u*A.x + u*A.y)/sqrt(2))
  391. assert A.ang_vel_in(N).magnitude() == sqrt(u**2)
  392. angle = A.ang_vel_in(N).angle_between(A.x + A.y)
  393. assert angle.xreplace({u: 1}) == 0
  394. assert C.masscenter.vel(N).simplify() == (u * A.z)/sqrt(2)
  395. assert C.masscenter.pos_from(P.masscenter) == N.x - A.x
  396. assert (C.masscenter.pos_from(P.masscenter).express(N).simplify() ==
  397. (1 - sqrt(2)/2)*N.x + sqrt(2)*cos(q)/2*N.y +
  398. sqrt(2)*sin(q)/2*N.z)
  399. assert (C.masscenter.vel(N).express(N).simplify() ==
  400. -sqrt(2)*u*sin(q)/2*N.y + sqrt(2)*u*cos(q)/2*N.z)
  401. assert C.masscenter.vel(N).angle_between(A.x) == pi/2
  402. N, A, P, C = _generate_body()
  403. PinJoint('J', P, C, parent_point=N.x, child_point=A.x,
  404. child_interframe=A.x + A.y - A.z)
  405. assert expand_mul(N.x.angle_between(A.x + A.y - A.z)) == 0 # Axis aligned
  406. assert (A.x + A.y - A.z).express(N).simplify() == sqrt(3)*N.x
  407. assert _simplify_matrix(A.dcm(N)) == Matrix([
  408. [sqrt(3)/3, -sqrt(6)*sin(q + pi/4)/3,
  409. sqrt(6)*cos(q + pi/4)/3],
  410. [sqrt(3)/3, sqrt(6)*cos(q + pi/12)/3,
  411. sqrt(6)*sin(q + pi/12)/3],
  412. [-sqrt(3)/3, sqrt(6)*cos(q + 5*pi/12)/3,
  413. sqrt(6)*sin(q + 5*pi/12)/3]])
  414. assert A.ang_vel_in(N) == u*N.x
  415. assert A.ang_vel_in(N).express(A).simplify() == (u*A.x + u*A.y -
  416. u*A.z)/sqrt(3)
  417. assert A.ang_vel_in(N).magnitude() == sqrt(u**2)
  418. angle = A.ang_vel_in(N).angle_between(A.x + A.y-A.z)
  419. assert angle.xreplace({u: 1}) == 0
  420. assert C.masscenter.vel(N).simplify() == (u*A.y + u*A.z)/sqrt(3)
  421. assert C.masscenter.pos_from(P.masscenter) == N.x - A.x
  422. assert (C.masscenter.pos_from(P.masscenter).express(N).simplify() ==
  423. (1 - sqrt(3)/3)*N.x + sqrt(6)*sin(q + pi/4)/3*N.y -
  424. sqrt(6)*cos(q + pi/4)/3*N.z)
  425. assert (C.masscenter.vel(N).express(N).simplify() ==
  426. sqrt(6)*u*cos(q + pi/4)/3*N.y +
  427. sqrt(6)*u*sin(q + pi/4)/3*N.z)
  428. assert C.masscenter.vel(N).angle_between(A.x) == pi/2
  429. N, A, P, C = _generate_body()
  430. m, n = symbols('m n')
  431. PinJoint('J', P, C, parent_point=m * N.x, child_point=n * A.x,
  432. child_interframe=A.x + A.y - A.z,
  433. parent_interframe=N.x - N.y + N.z)
  434. angle = (N.x - N.y + N.z).angle_between(A.x + A.y - A.z)
  435. assert expand_mul(angle) == 0 # Axis are aligned
  436. assert ((A.x-A.y+A.z).express(N).simplify() ==
  437. (-4*cos(q)/3 - S(1)/3)*N.x + (S(1)/3 - 4*sin(q + pi/6)/3)*N.y +
  438. (4*cos(q + pi/3)/3 - S(1)/3)*N.z)
  439. assert _simplify_matrix(A.dcm(N)) == Matrix([
  440. [S(1)/3 - 2*cos(q)/3, -2*sin(q + pi/6)/3 - S(1)/3,
  441. 2*cos(q + pi/3)/3 + S(1)/3],
  442. [2*cos(q + pi/3)/3 + S(1)/3, 2*cos(q)/3 - S(1)/3,
  443. 2*sin(q + pi/6)/3 + S(1)/3],
  444. [-2*sin(q + pi/6)/3 - S(1)/3, 2*cos(q + pi/3)/3 + S(1)/3,
  445. 2*cos(q)/3 - S(1)/3]])
  446. assert A.ang_vel_in(N) == (u*N.x - u*N.y + u*N.z)/sqrt(3)
  447. assert A.ang_vel_in(N).express(A).simplify() == (u*A.x + u*A.y -
  448. u*A.z)/sqrt(3)
  449. assert A.ang_vel_in(N).magnitude() == sqrt(u**2)
  450. angle = A.ang_vel_in(N).angle_between(A.x+A.y-A.z)
  451. assert angle.xreplace({u: 1}) == 0
  452. assert (C.masscenter.vel(N).simplify() ==
  453. sqrt(3)*n*u/3*A.y + sqrt(3)*n*u/3*A.z)
  454. assert C.masscenter.pos_from(P.masscenter) == m*N.x - n*A.x
  455. assert (C.masscenter.pos_from(P.masscenter).express(N).simplify() ==
  456. (m + n*(2*cos(q) - 1)/3)*N.x + n*(2*sin(q + pi/6) +
  457. 1)/3*N.y - n*(2*cos(q + pi/3) + 1)/3*N.z)
  458. assert (C.masscenter.vel(N).express(N).simplify() ==
  459. - 2*n*u*sin(q)/3*N.x + 2*n*u*cos(q + pi/6)/3*N.y +
  460. 2*n*u*sin(q + pi/3)/3*N.z)
  461. assert C.masscenter.vel(N).dot(N.x - N.y + N.z).simplify() == 0
  462. def test_create_aligned_frame_pi():
  463. N, A, P, C = _generate_body()
  464. f = Joint._create_aligned_interframe(P, -P.x, P.x)
  465. assert f.z == P.z
  466. f = Joint._create_aligned_interframe(P, -P.y, P.y)
  467. assert f.x == P.x
  468. f = Joint._create_aligned_interframe(P, -P.z, P.z)
  469. assert f.y == P.y
  470. f = Joint._create_aligned_interframe(P, -P.x - P.y, P.x + P.y)
  471. assert f.z == P.z
  472. f = Joint._create_aligned_interframe(P, -P.y - P.z, P.y + P.z)
  473. assert f.x == P.x
  474. f = Joint._create_aligned_interframe(P, -P.x - P.z, P.x + P.z)
  475. assert f.y == P.y
  476. f = Joint._create_aligned_interframe(P, -P.x - P.y - P.z, P.x + P.y + P.z)
  477. assert f.y - f.z == P.y - P.z
  478. def test_pin_joint_axis():
  479. q, u = dynamicsymbols('q u')
  480. # Test default joint axis
  481. N, A, P, C, Pint, Cint = _generate_body(True)
  482. J = PinJoint('J', P, C, q, u, parent_interframe=Pint, child_interframe=Cint)
  483. assert J.joint_axis == Pint.x
  484. # Test for the same joint axis expressed in different frames
  485. N_R_A = Matrix([[0, sin(q), cos(q)],
  486. [0, -cos(q), sin(q)],
  487. [1, 0, 0]])
  488. N, A, P, C, Pint, Cint = _generate_body(True)
  489. PinJoint('J', P, C, q, u, parent_interframe=Pint, child_interframe=Cint,
  490. joint_axis=N.z)
  491. assert N.dcm(A) == N_R_A
  492. N, A, P, C, Pint, Cint = _generate_body(True)
  493. PinJoint('J', P, C, q, u, parent_interframe=Pint, child_interframe=Cint,
  494. joint_axis=-Pint.z)
  495. assert N.dcm(A) == N_R_A
  496. # Test time varying joint axis
  497. N, A, P, C, Pint, Cint = _generate_body(True)
  498. raises(ValueError, lambda: PinJoint('J', P, C, joint_axis=q * N.z))
  499. def test_locate_joint_pos():
  500. # Test Vector and default
  501. N, A, P, C = _generate_body()
  502. joint = PinJoint('J', P, C, parent_point=N.y + N.z)
  503. assert joint.parent_point.name == 'J_P_joint'
  504. assert joint.parent_point.pos_from(P.masscenter) == N.y + N.z
  505. assert joint.child_point == C.masscenter
  506. # Test Point objects
  507. N, A, P, C = _generate_body()
  508. parent_point = P.masscenter.locatenew('p', N.y + N.z)
  509. joint = PinJoint('J', P, C, parent_point=parent_point,
  510. child_point=C.masscenter)
  511. assert joint.parent_point == parent_point
  512. assert joint.child_point == C.masscenter
  513. # Check invalid type
  514. N, A, P, C = _generate_body()
  515. raises(TypeError,
  516. lambda: PinJoint('J', P, C, parent_point=N.x.to_matrix(N)))
  517. # Test time varying positions
  518. q = dynamicsymbols('q')
  519. N, A, P, C = _generate_body()
  520. raises(ValueError, lambda: PinJoint('J', P, C, parent_point=q * N.x))
  521. N, A, P, C = _generate_body()
  522. child_point = C.masscenter.locatenew('p', q * A.y)
  523. raises(ValueError, lambda: PinJoint('J', P, C, child_point=child_point))
  524. # Test undefined position
  525. child_point = Point('p')
  526. raises(ValueError, lambda: PinJoint('J', P, C, child_point=child_point))
  527. def test_locate_joint_frame():
  528. # Test rotated frame and default
  529. N, A, P, C = _generate_body()
  530. parent_interframe = ReferenceFrame('int_frame')
  531. parent_interframe.orient_axis(N, N.z, 1)
  532. joint = PinJoint('J', P, C, parent_interframe=parent_interframe)
  533. assert joint.parent_interframe == parent_interframe
  534. assert joint.parent_interframe.ang_vel_in(N) == 0
  535. assert joint.child_interframe == A
  536. # Test time varying orientations
  537. q = dynamicsymbols('q')
  538. N, A, P, C = _generate_body()
  539. parent_interframe = ReferenceFrame('int_frame')
  540. parent_interframe.orient_axis(N, N.z, q)
  541. raises(ValueError,
  542. lambda: PinJoint('J', P, C, parent_interframe=parent_interframe))
  543. # Test undefined frame
  544. N, A, P, C = _generate_body()
  545. child_interframe = ReferenceFrame('int_frame')
  546. child_interframe.orient_axis(N, N.z, 1) # Defined with respect to parent
  547. raises(ValueError,
  548. lambda: PinJoint('J', P, C, child_interframe=child_interframe))
  549. def test_sliding_joint():
  550. _, _, P, C = _generate_body()
  551. q, u = dynamicsymbols('q_S, u_S')
  552. S = PrismaticJoint('S', P, C)
  553. assert S.name == 'S'
  554. assert S.parent == P
  555. assert S.child == C
  556. assert S.coordinates == Matrix([q])
  557. assert S.speeds == Matrix([u])
  558. assert S.kdes == Matrix([u - q.diff(t)])
  559. assert S.joint_axis == P.frame.x
  560. assert S.child_point.pos_from(C.masscenter) == Vector(0)
  561. assert S.parent_point.pos_from(P.masscenter) == Vector(0)
  562. assert S.parent_point.pos_from(S.child_point) == - q * P.frame.x
  563. assert P.masscenter.pos_from(C.masscenter) == - q * P.frame.x
  564. assert C.masscenter.vel(P.frame) == u * P.frame.x
  565. assert P.ang_vel_in(C) == 0
  566. assert C.ang_vel_in(P) == 0
  567. assert S.__str__() == 'PrismaticJoint: S parent: P child: C'
  568. N, A, P, C = _generate_body()
  569. l, m = symbols('l m')
  570. Pint = ReferenceFrame('P_int')
  571. Pint.orient_axis(P.frame, P.y, pi / 2)
  572. S = PrismaticJoint('S', P, C, parent_point=l * P.frame.x,
  573. child_point=m * C.frame.y, joint_axis=P.frame.z,
  574. parent_interframe=Pint)
  575. assert S.joint_axis == P.frame.z
  576. assert S.child_point.pos_from(C.masscenter) == m * C.frame.y
  577. assert S.parent_point.pos_from(P.masscenter) == l * P.frame.x
  578. assert S.parent_point.pos_from(S.child_point) == - q * P.frame.z
  579. assert P.masscenter.pos_from(C.masscenter) == - l*N.x - q*N.z + m*A.y
  580. assert C.masscenter.vel(P.frame) == u * P.frame.z
  581. assert P.masscenter.vel(Pint) == Vector(0)
  582. assert C.ang_vel_in(P) == 0
  583. assert P.ang_vel_in(C) == 0
  584. _, _, P, C = _generate_body()
  585. Pint = ReferenceFrame('P_int')
  586. Pint.orient_axis(P.frame, P.y, pi / 2)
  587. S = PrismaticJoint('S', P, C, parent_point=l * P.frame.z,
  588. child_point=m * C.frame.x, joint_axis=P.frame.z,
  589. parent_interframe=Pint)
  590. assert S.joint_axis == P.frame.z
  591. assert S.child_point.pos_from(C.masscenter) == m * C.frame.x
  592. assert S.parent_point.pos_from(P.masscenter) == l * P.frame.z
  593. assert S.parent_point.pos_from(S.child_point) == - q * P.frame.z
  594. assert P.masscenter.pos_from(C.masscenter) == (-l - q)*P.frame.z + m*C.frame.x
  595. assert C.masscenter.vel(P.frame) == u * P.frame.z
  596. assert C.ang_vel_in(P) == 0
  597. assert P.ang_vel_in(C) == 0
  598. def test_sliding_joint_arbitrary_axis():
  599. q, u = dynamicsymbols('q_S, u_S')
  600. N, A, P, C = _generate_body()
  601. PrismaticJoint('S', P, C, child_interframe=-A.x)
  602. assert (-A.x).angle_between(N.x) == 0
  603. assert -A.x.express(N) == N.x
  604. assert A.dcm(N) == Matrix([[-1, 0, 0], [0, -1, 0], [0, 0, 1]])
  605. assert C.masscenter.pos_from(P.masscenter) == q * N.x
  606. assert C.masscenter.pos_from(P.masscenter).express(A).simplify() == -q * A.x
  607. assert C.masscenter.vel(N) == u * N.x
  608. assert C.masscenter.vel(N).express(A) == -u * A.x
  609. assert A.ang_vel_in(N) == 0
  610. assert N.ang_vel_in(A) == 0
  611. #When axes are different and parent joint is at masscenter but child joint is at a unit vector from
  612. #child masscenter.
  613. N, A, P, C = _generate_body()
  614. PrismaticJoint('S', P, C, child_interframe=A.y, child_point=A.x)
  615. assert A.y.angle_between(N.x) == 0 #Axis are aligned
  616. assert A.y.express(N) == N.x
  617. assert A.dcm(N) == Matrix([[0, -1, 0], [1, 0, 0], [0, 0, 1]])
  618. assert C.masscenter.vel(N) == u * N.x
  619. assert C.masscenter.vel(N).express(A) == u * A.y
  620. assert C.masscenter.pos_from(P.masscenter) == q*N.x - A.x
  621. assert C.masscenter.pos_from(P.masscenter).express(N).simplify() == q*N.x + N.y
  622. assert A.ang_vel_in(N) == 0
  623. assert N.ang_vel_in(A) == 0
  624. #Similar to previous case but wrt parent body
  625. N, A, P, C = _generate_body()
  626. PrismaticJoint('S', P, C, parent_interframe=N.y, parent_point=N.x)
  627. assert N.y.angle_between(A.x) == 0 #Axis are aligned
  628. assert N.y.express(A) == A.x
  629. assert A.dcm(N) == Matrix([[0, 1, 0], [-1, 0, 0], [0, 0, 1]])
  630. assert C.masscenter.vel(N) == u * N.y
  631. assert C.masscenter.vel(N).express(A) == u * A.x
  632. assert C.masscenter.pos_from(P.masscenter) == N.x + q*N.y
  633. assert A.ang_vel_in(N) == 0
  634. assert N.ang_vel_in(A) == 0
  635. #Both joint pos is defined but different axes
  636. N, A, P, C = _generate_body()
  637. PrismaticJoint('S', P, C, parent_point=N.x, child_point=A.x,
  638. child_interframe=A.x + A.y)
  639. assert N.x.angle_between(A.x + A.y) == 0 #Axis are aligned
  640. assert (A.x + A.y).express(N) == sqrt(2)*N.x
  641. assert A.dcm(N) == Matrix([[sqrt(2)/2, -sqrt(2)/2, 0], [sqrt(2)/2, sqrt(2)/2, 0], [0, 0, 1]])
  642. assert C.masscenter.pos_from(P.masscenter) == (q + 1)*N.x - A.x
  643. assert C.masscenter.pos_from(P.masscenter).express(N) == (q - sqrt(2)/2 + 1)*N.x + sqrt(2)/2*N.y
  644. assert C.masscenter.vel(N).express(A) == u * (A.x + A.y)/sqrt(2)
  645. assert C.masscenter.vel(N) == u*N.x
  646. assert A.ang_vel_in(N) == 0
  647. assert N.ang_vel_in(A) == 0
  648. N, A, P, C = _generate_body()
  649. PrismaticJoint('S', P, C, parent_point=N.x, child_point=A.x,
  650. child_interframe=A.x + A.y - A.z)
  651. assert N.x.angle_between(A.x + A.y - A.z) == 0 #Axis are aligned
  652. assert (A.x + A.y - A.z).express(N) == sqrt(3)*N.x
  653. assert _simplify_matrix(A.dcm(N)) == Matrix([[sqrt(3)/3, -sqrt(3)/3, sqrt(3)/3],
  654. [sqrt(3)/3, sqrt(3)/6 + S(1)/2, S(1)/2 - sqrt(3)/6],
  655. [-sqrt(3)/3, S(1)/2 - sqrt(3)/6, sqrt(3)/6 + S(1)/2]])
  656. assert C.masscenter.pos_from(P.masscenter) == (q + 1)*N.x - A.x
  657. assert C.masscenter.pos_from(P.masscenter).express(N) == \
  658. (q - sqrt(3)/3 + 1)*N.x + sqrt(3)/3*N.y - sqrt(3)/3*N.z
  659. assert C.masscenter.vel(N) == u*N.x
  660. assert C.masscenter.vel(N).express(A) == sqrt(3)*u/3*A.x + sqrt(3)*u/3*A.y - sqrt(3)*u/3*A.z
  661. assert A.ang_vel_in(N) == 0
  662. assert N.ang_vel_in(A) == 0
  663. N, A, P, C = _generate_body()
  664. m, n = symbols('m n')
  665. PrismaticJoint('S', P, C, parent_point=m*N.x, child_point=n*A.x,
  666. child_interframe=A.x + A.y - A.z,
  667. parent_interframe=N.x - N.y + N.z)
  668. # 0 angle means that the axis are aligned
  669. assert (N.x-N.y+N.z).angle_between(A.x+A.y-A.z).simplify() == 0
  670. assert (A.x+A.y-A.z).express(N) == N.x - N.y + N.z
  671. assert _simplify_matrix(A.dcm(N)) == Matrix([[-S(1)/3, -S(2)/3, S(2)/3],
  672. [S(2)/3, S(1)/3, S(2)/3],
  673. [-S(2)/3, S(2)/3, S(1)/3]])
  674. assert C.masscenter.pos_from(P.masscenter) == \
  675. (m + sqrt(3)*q/3)*N.x - sqrt(3)*q/3*N.y + sqrt(3)*q/3*N.z - n*A.x
  676. assert C.masscenter.pos_from(P.masscenter).express(N) == \
  677. (m + n/3 + sqrt(3)*q/3)*N.x + (2*n/3 - sqrt(3)*q/3)*N.y + (-2*n/3 + sqrt(3)*q/3)*N.z
  678. assert C.masscenter.vel(N) == sqrt(3)*u/3*N.x - sqrt(3)*u/3*N.y + sqrt(3)*u/3*N.z
  679. assert C.masscenter.vel(N).express(A) == sqrt(3)*u/3*A.x + sqrt(3)*u/3*A.y - sqrt(3)*u/3*A.z
  680. assert A.ang_vel_in(N) == 0
  681. assert N.ang_vel_in(A) == 0
  682. def test_cylindrical_joint():
  683. N, A, P, C = _generate_body()
  684. q0_def, q1_def, u0_def, u1_def = dynamicsymbols('q0:2_J, u0:2_J')
  685. Cj = CylindricalJoint('J', P, C)
  686. assert Cj.name == 'J'
  687. assert Cj.parent == P
  688. assert Cj.child == C
  689. assert Cj.coordinates == Matrix([q0_def, q1_def])
  690. assert Cj.speeds == Matrix([u0_def, u1_def])
  691. assert Cj.rotation_coordinate == q0_def
  692. assert Cj.translation_coordinate == q1_def
  693. assert Cj.rotation_speed == u0_def
  694. assert Cj.translation_speed == u1_def
  695. assert Cj.kdes == Matrix([u0_def - q0_def.diff(t), u1_def - q1_def.diff(t)])
  696. assert Cj.joint_axis == N.x
  697. assert Cj.child_point.pos_from(C.masscenter) == Vector(0)
  698. assert Cj.parent_point.pos_from(P.masscenter) == Vector(0)
  699. assert Cj.parent_point.pos_from(Cj._child_point) == -q1_def * N.x
  700. assert C.masscenter.pos_from(P.masscenter) == q1_def * N.x
  701. assert Cj.child_point.vel(N) == u1_def * N.x
  702. assert A.ang_vel_in(N) == u0_def * N.x
  703. assert Cj.parent_interframe == N
  704. assert Cj.child_interframe == A
  705. assert Cj.__str__() == 'CylindricalJoint: J parent: P child: C'
  706. q0, q1, u0, u1 = dynamicsymbols('q0:2, u0:2')
  707. l, m = symbols('l, m')
  708. N, A, P, C, Pint, Cint = _generate_body(True)
  709. Cj = CylindricalJoint('J', P, C, rotation_coordinate=q0, rotation_speed=u0,
  710. translation_speed=u1, parent_point=m * N.x,
  711. child_point=l * A.y, parent_interframe=Pint,
  712. child_interframe=Cint, joint_axis=2 * N.z)
  713. assert Cj.coordinates == Matrix([q0, q1_def])
  714. assert Cj.speeds == Matrix([u0, u1])
  715. assert Cj.rotation_coordinate == q0
  716. assert Cj.translation_coordinate == q1_def
  717. assert Cj.rotation_speed == u0
  718. assert Cj.translation_speed == u1
  719. assert Cj.kdes == Matrix([u0 - q0.diff(t), u1 - q1_def.diff(t)])
  720. assert Cj.joint_axis == 2 * N.z
  721. assert Cj.child_point.pos_from(C.masscenter) == l * A.y
  722. assert Cj.parent_point.pos_from(P.masscenter) == m * N.x
  723. assert Cj.parent_point.pos_from(Cj._child_point) == -q1_def * N.z
  724. assert C.masscenter.pos_from(
  725. P.masscenter) == m * N.x + q1_def * N.z - l * A.y
  726. assert C.masscenter.vel(N) == u1 * N.z - u0 * l * A.z
  727. assert A.ang_vel_in(N) == u0 * N.z
  728. def test_planar_joint():
  729. N, A, P, C = _generate_body()
  730. q0_def, q1_def, q2_def = dynamicsymbols('q0:3_J')
  731. u0_def, u1_def, u2_def = dynamicsymbols('u0:3_J')
  732. Cj = PlanarJoint('J', P, C)
  733. assert Cj.name == 'J'
  734. assert Cj.parent == P
  735. assert Cj.child == C
  736. assert Cj.coordinates == Matrix([q0_def, q1_def, q2_def])
  737. assert Cj.speeds == Matrix([u0_def, u1_def, u2_def])
  738. assert Cj.rotation_coordinate == q0_def
  739. assert Cj.planar_coordinates == Matrix([q1_def, q2_def])
  740. assert Cj.rotation_speed == u0_def
  741. assert Cj.planar_speeds == Matrix([u1_def, u2_def])
  742. assert Cj.kdes == Matrix([u0_def - q0_def.diff(t), u1_def - q1_def.diff(t),
  743. u2_def - q2_def.diff(t)])
  744. assert Cj.rotation_axis == N.x
  745. assert Cj.planar_vectors == [N.y, N.z]
  746. assert Cj.child_point.pos_from(C.masscenter) == Vector(0)
  747. assert Cj.parent_point.pos_from(P.masscenter) == Vector(0)
  748. r_P_C = q1_def * N.y + q2_def * N.z
  749. assert Cj.parent_point.pos_from(Cj.child_point) == -r_P_C
  750. assert C.masscenter.pos_from(P.masscenter) == r_P_C
  751. assert Cj.child_point.vel(N) == u1_def * N.y + u2_def * N.z
  752. assert A.ang_vel_in(N) == u0_def * N.x
  753. assert Cj.parent_interframe == N
  754. assert Cj.child_interframe == A
  755. assert Cj.__str__() == 'PlanarJoint: J parent: P child: C'
  756. q0, q1, q2, u0, u1, u2 = dynamicsymbols('q0:3, u0:3')
  757. l, m = symbols('l, m')
  758. N, A, P, C, Pint, Cint = _generate_body(True)
  759. Cj = PlanarJoint('J', P, C, rotation_coordinate=q0,
  760. planar_coordinates=[q1, q2], planar_speeds=[u1, u2],
  761. parent_point=m * N.x, child_point=l * A.y,
  762. parent_interframe=Pint, child_interframe=Cint)
  763. assert Cj.coordinates == Matrix([q0, q1, q2])
  764. assert Cj.speeds == Matrix([u0_def, u1, u2])
  765. assert Cj.rotation_coordinate == q0
  766. assert Cj.planar_coordinates == Matrix([q1, q2])
  767. assert Cj.rotation_speed == u0_def
  768. assert Cj.planar_speeds == Matrix([u1, u2])
  769. assert Cj.kdes == Matrix([u0_def - q0.diff(t), u1 - q1.diff(t),
  770. u2 - q2.diff(t)])
  771. assert Cj.rotation_axis == Pint.x
  772. assert Cj.planar_vectors == [Pint.y, Pint.z]
  773. assert Cj.child_point.pos_from(C.masscenter) == l * A.y
  774. assert Cj.parent_point.pos_from(P.masscenter) == m * N.x
  775. assert Cj.parent_point.pos_from(Cj.child_point) == q1 * N.y + q2 * N.z
  776. assert C.masscenter.pos_from(
  777. P.masscenter) == m * N.x - q1 * N.y - q2 * N.z - l * A.y
  778. assert C.masscenter.vel(N) == -u1 * N.y - u2 * N.z + u0_def * l * A.x
  779. assert A.ang_vel_in(N) == u0_def * N.x
  780. def test_planar_joint_advanced():
  781. # Tests whether someone is able to just specify two normals, which will form
  782. # the rotation axis seen from the parent and child body.
  783. # This specific example is a block on a slope, which has that same slope of
  784. # 30 degrees, so in the zero configuration the frames of the parent and
  785. # child are actually aligned.
  786. q0, q1, q2, u0, u1, u2 = dynamicsymbols('q0:3, u0:3')
  787. l1, l2 = symbols('l1:3')
  788. N, A, P, C = _generate_body()
  789. J = PlanarJoint('J', P, C, q0, [q1, q2], u0, [u1, u2],
  790. parent_point=l1 * N.z,
  791. child_point=-l2 * C.z,
  792. parent_interframe=N.z + N.y / sqrt(3),
  793. child_interframe=A.z + A.y / sqrt(3))
  794. assert J.rotation_axis.express(N) == (N.z + N.y / sqrt(3)).normalize()
  795. assert J.rotation_axis.express(A) == (A.z + A.y / sqrt(3)).normalize()
  796. assert J.rotation_axis.angle_between(N.z) == pi / 6
  797. assert N.dcm(A).xreplace({q0: 0, q1: 0, q2: 0}) == eye(3)
  798. N_R_A = Matrix([
  799. [cos(q0), -sqrt(3) * sin(q0) / 2, sin(q0) / 2],
  800. [sqrt(3) * sin(q0) / 2, 3 * cos(q0) / 4 + 1 / 4,
  801. sqrt(3) * (1 - cos(q0)) / 4],
  802. [-sin(q0) / 2, sqrt(3) * (1 - cos(q0)) / 4, cos(q0) / 4 + 3 / 4]])
  803. # N.dcm(A) == N_R_A did not work
  804. assert _simplify_matrix(N.dcm(A) - N_R_A) == zeros(3)
  805. def test_spherical_joint():
  806. N, A, P, C = _generate_body()
  807. q0, q1, q2, u0, u1, u2 = dynamicsymbols('q0:3_S, u0:3_S')
  808. S = SphericalJoint('S', P, C)
  809. assert S.name == 'S'
  810. assert S.parent == P
  811. assert S.child == C
  812. assert S.coordinates == Matrix([q0, q1, q2])
  813. assert S.speeds == Matrix([u0, u1, u2])
  814. assert S.kdes == Matrix([u0 - q0.diff(t), u1 - q1.diff(t), u2 - q2.diff(t)])
  815. assert S.child_point.pos_from(C.masscenter) == Vector(0)
  816. assert S.parent_point.pos_from(P.masscenter) == Vector(0)
  817. assert S.parent_point.pos_from(S.child_point) == Vector(0)
  818. assert P.masscenter.pos_from(C.masscenter) == Vector(0)
  819. assert C.masscenter.vel(N) == Vector(0)
  820. assert P.ang_vel_in(C) == (-u0 * cos(q1) * cos(q2) - u1 * sin(q2)) * A.x + (
  821. u0 * sin(q2) * cos(q1) - u1 * cos(q2)) * A.y + (
  822. -u0 * sin(q1) - u2) * A.z
  823. assert C.ang_vel_in(P) == (u0 * cos(q1) * cos(q2) + u1 * sin(q2)) * A.x + (
  824. -u0 * sin(q2) * cos(q1) + u1 * cos(q2)) * A.y + (
  825. u0 * sin(q1) + u2) * A.z
  826. assert S.__str__() == 'SphericalJoint: S parent: P child: C'
  827. assert S._rot_type == 'BODY'
  828. assert S._rot_order == 123
  829. assert S._amounts is None
  830. def test_spherical_joint_speeds_as_derivative_terms():
  831. # This tests checks whether the system remains valid if the user chooses to
  832. # pass the derivative of the generalized coordinates as generalized speeds
  833. q0, q1, q2 = dynamicsymbols('q0:3')
  834. u0, u1, u2 = dynamicsymbols('q0:3', 1)
  835. N, A, P, C = _generate_body()
  836. S = SphericalJoint('S', P, C, coordinates=[q0, q1, q2], speeds=[u0, u1, u2])
  837. assert S.coordinates == Matrix([q0, q1, q2])
  838. assert S.speeds == Matrix([u0, u1, u2])
  839. assert S.kdes == Matrix([0, 0, 0])
  840. assert P.ang_vel_in(C) == (-u0 * cos(q1) * cos(q2) - u1 * sin(q2)) * A.x + (
  841. u0 * sin(q2) * cos(q1) - u1 * cos(q2)) * A.y + (
  842. -u0 * sin(q1) - u2) * A.z
  843. def test_spherical_joint_coords():
  844. q0s, q1s, q2s, u0s, u1s, u2s = dynamicsymbols('q0:3_S, u0:3_S')
  845. q0, q1, q2, q3, u0, u1, u2, u4 = dynamicsymbols('q0:4, u0:4')
  846. # Test coordinates as list
  847. N, A, P, C = _generate_body()
  848. S = SphericalJoint('S', P, C, [q0, q1, q2], [u0, u1, u2])
  849. assert S.coordinates == Matrix([q0, q1, q2])
  850. assert S.speeds == Matrix([u0, u1, u2])
  851. # Test coordinates as Matrix
  852. N, A, P, C = _generate_body()
  853. S = SphericalJoint('S', P, C, Matrix([q0, q1, q2]),
  854. Matrix([u0, u1, u2]))
  855. assert S.coordinates == Matrix([q0, q1, q2])
  856. assert S.speeds == Matrix([u0, u1, u2])
  857. # Test too few generalized coordinates
  858. N, A, P, C = _generate_body()
  859. raises(ValueError,
  860. lambda: SphericalJoint('S', P, C, Matrix([q0, q1]), Matrix([u0])))
  861. # Test too many generalized coordinates
  862. raises(ValueError, lambda: SphericalJoint(
  863. 'S', P, C, Matrix([q0, q1, q2, q3]), Matrix([u0, u1, u2])))
  864. raises(ValueError, lambda: SphericalJoint(
  865. 'S', P, C, Matrix([q0, q1, q2]), Matrix([u0, u1, u2, u4])))
  866. def test_spherical_joint_orient_body():
  867. q0, q1, q2, u0, u1, u2 = dynamicsymbols('q0:3, u0:3')
  868. N_R_A = Matrix([
  869. [-sin(q1), -sin(q2) * cos(q1), cos(q1) * cos(q2)],
  870. [-sin(q0) * cos(q1), sin(q0) * sin(q1) * sin(q2) - cos(q0) * cos(q2),
  871. -sin(q0) * sin(q1) * cos(q2) - sin(q2) * cos(q0)],
  872. [cos(q0) * cos(q1), -sin(q0) * cos(q2) - sin(q1) * sin(q2) * cos(q0),
  873. -sin(q0) * sin(q2) + sin(q1) * cos(q0) * cos(q2)]])
  874. N_w_A = Matrix([[-u0 * sin(q1) - u2],
  875. [-u0 * sin(q2) * cos(q1) + u1 * cos(q2)],
  876. [u0 * cos(q1) * cos(q2) + u1 * sin(q2)]])
  877. N_v_Co = Matrix([
  878. [-sqrt(2) * (u0 * cos(q2 + pi / 4) * cos(q1) + u1 * sin(q2 + pi / 4))],
  879. [-u0 * sin(q1) - u2], [-u0 * sin(q1) - u2]])
  880. # Test default rot_type='BODY', rot_order=123
  881. N, A, P, C, Pint, Cint = _generate_body(True)
  882. S = SphericalJoint('S', P, C, coordinates=[q0, q1, q2], speeds=[u0, u1, u2],
  883. parent_point=N.x + N.y, child_point=-A.y + A.z,
  884. parent_interframe=Pint, child_interframe=Cint,
  885. rot_type='body', rot_order=123)
  886. assert S._rot_type.upper() == 'BODY'
  887. assert S._rot_order == 123
  888. assert _simplify_matrix(N.dcm(A) - N_R_A) == zeros(3)
  889. assert A.ang_vel_in(N).to_matrix(A) == N_w_A
  890. assert C.masscenter.vel(N).to_matrix(A) == N_v_Co
  891. # Test change of amounts
  892. N, A, P, C, Pint, Cint = _generate_body(True)
  893. S = SphericalJoint('S', P, C, coordinates=[q0, q1, q2], speeds=[u0, u1, u2],
  894. parent_point=N.x + N.y, child_point=-A.y + A.z,
  895. parent_interframe=Pint, child_interframe=Cint,
  896. rot_type='BODY', amounts=(q1, q0, q2), rot_order=123)
  897. switch_order = lambda expr: expr.xreplace(
  898. {q0: q1, q1: q0, q2: q2, u0: u1, u1: u0, u2: u2})
  899. assert S._rot_type.upper() == 'BODY'
  900. assert S._rot_order == 123
  901. assert _simplify_matrix(N.dcm(A) - switch_order(N_R_A)) == zeros(3)
  902. assert A.ang_vel_in(N).to_matrix(A) == switch_order(N_w_A)
  903. assert C.masscenter.vel(N).to_matrix(A) == switch_order(N_v_Co)
  904. # Test different rot_order
  905. N, A, P, C, Pint, Cint = _generate_body(True)
  906. S = SphericalJoint('S', P, C, coordinates=[q0, q1, q2], speeds=[u0, u1, u2],
  907. parent_point=N.x + N.y, child_point=-A.y + A.z,
  908. parent_interframe=Pint, child_interframe=Cint,
  909. rot_type='BodY', rot_order='yxz')
  910. assert S._rot_type.upper() == 'BODY'
  911. assert S._rot_order == 'yxz'
  912. assert _simplify_matrix(N.dcm(A) - Matrix([
  913. [-sin(q0) * cos(q1), sin(q0) * sin(q1) * cos(q2) - sin(q2) * cos(q0),
  914. sin(q0) * sin(q1) * sin(q2) + cos(q0) * cos(q2)],
  915. [-sin(q1), -cos(q1) * cos(q2), -sin(q2) * cos(q1)],
  916. [cos(q0) * cos(q1), -sin(q0) * sin(q2) - sin(q1) * cos(q0) * cos(q2),
  917. sin(q0) * cos(q2) - sin(q1) * sin(q2) * cos(q0)]])) == zeros(3)
  918. assert A.ang_vel_in(N).to_matrix(A) == Matrix([
  919. [u0 * sin(q1) - u2], [u0 * cos(q1) * cos(q2) - u1 * sin(q2)],
  920. [u0 * sin(q2) * cos(q1) + u1 * cos(q2)]])
  921. assert C.masscenter.vel(N).to_matrix(A) == Matrix([
  922. [-sqrt(2) * (u0 * sin(q2 + pi / 4) * cos(q1) + u1 * cos(q2 + pi / 4))],
  923. [u0 * sin(q1) - u2], [u0 * sin(q1) - u2]])
  924. def test_spherical_joint_orient_space():
  925. q0, q1, q2, u0, u1, u2 = dynamicsymbols('q0:3, u0:3')
  926. N_R_A = Matrix([
  927. [-sin(q0) * sin(q2) - sin(q1) * cos(q0) * cos(q2),
  928. sin(q0) * sin(q1) * cos(q2) - sin(q2) * cos(q0), cos(q1) * cos(q2)],
  929. [-sin(q0) * cos(q2) + sin(q1) * sin(q2) * cos(q0),
  930. -sin(q0) * sin(q1) * sin(q2) - cos(q0) * cos(q2), -sin(q2) * cos(q1)],
  931. [cos(q0) * cos(q1), -sin(q0) * cos(q1), sin(q1)]])
  932. N_w_A = Matrix([
  933. [u1 * sin(q0) - u2 * cos(q0) * cos(q1)],
  934. [u1 * cos(q0) + u2 * sin(q0) * cos(q1)], [u0 - u2 * sin(q1)]])
  935. N_v_Co = Matrix([
  936. [u0 - u2 * sin(q1)], [u0 - u2 * sin(q1)],
  937. [sqrt(2) * (-u1 * sin(q0 + pi / 4) + u2 * cos(q0 + pi / 4) * cos(q1))]])
  938. # Test default rot_type='BODY', rot_order=123
  939. N, A, P, C, Pint, Cint = _generate_body(True)
  940. S = SphericalJoint('S', P, C, coordinates=[q0, q1, q2], speeds=[u0, u1, u2],
  941. parent_point=N.x + N.z, child_point=-A.x + A.y,
  942. parent_interframe=Pint, child_interframe=Cint,
  943. rot_type='space', rot_order=123)
  944. assert S._rot_type.upper() == 'SPACE'
  945. assert S._rot_order == 123
  946. assert _simplify_matrix(N.dcm(A) - N_R_A) == zeros(3)
  947. assert _simplify_matrix(A.ang_vel_in(N).to_matrix(A)) == N_w_A
  948. assert _simplify_matrix(C.masscenter.vel(N).to_matrix(A)) == N_v_Co
  949. # Test change of amounts
  950. switch_order = lambda expr: expr.xreplace(
  951. {q0: q1, q1: q0, q2: q2, u0: u1, u1: u0, u2: u2})
  952. N, A, P, C, Pint, Cint = _generate_body(True)
  953. S = SphericalJoint('S', P, C, coordinates=[q0, q1, q2], speeds=[u0, u1, u2],
  954. parent_point=N.x + N.z, child_point=-A.x + A.y,
  955. parent_interframe=Pint, child_interframe=Cint,
  956. rot_type='SPACE', amounts=(q1, q0, q2), rot_order=123)
  957. assert S._rot_type.upper() == 'SPACE'
  958. assert S._rot_order == 123
  959. assert _simplify_matrix(N.dcm(A) - switch_order(N_R_A)) == zeros(3)
  960. assert _simplify_matrix(A.ang_vel_in(N).to_matrix(A)) == switch_order(N_w_A)
  961. assert _simplify_matrix(C.masscenter.vel(N).to_matrix(A)) == switch_order(N_v_Co)
  962. # Test different rot_order
  963. N, A, P, C, Pint, Cint = _generate_body(True)
  964. S = SphericalJoint('S', P, C, coordinates=[q0, q1, q2], speeds=[u0, u1, u2],
  965. parent_point=N.x + N.z, child_point=-A.x + A.y,
  966. parent_interframe=Pint, child_interframe=Cint,
  967. rot_type='SPaCe', rot_order='zxy')
  968. assert S._rot_type.upper() == 'SPACE'
  969. assert S._rot_order == 'zxy'
  970. assert _simplify_matrix(N.dcm(A) - Matrix([
  971. [-sin(q2) * cos(q1), -sin(q0) * cos(q2) + sin(q1) * sin(q2) * cos(q0),
  972. sin(q0) * sin(q1) * sin(q2) + cos(q0) * cos(q2)],
  973. [-sin(q1), -cos(q0) * cos(q1), -sin(q0) * cos(q1)],
  974. [cos(q1) * cos(q2), -sin(q0) * sin(q2) - sin(q1) * cos(q0) * cos(q2),
  975. -sin(q0) * sin(q1) * cos(q2) + sin(q2) * cos(q0)]]))
  976. assert _simplify_matrix(A.ang_vel_in(N).to_matrix(A) - Matrix([
  977. [-u0 + u2 * sin(q1)], [-u1 * sin(q0) + u2 * cos(q0) * cos(q1)],
  978. [u1 * cos(q0) + u2 * sin(q0) * cos(q1)]])) == zeros(3, 1)
  979. assert _simplify_matrix(C.masscenter.vel(N).to_matrix(A) - Matrix([
  980. [u1 * cos(q0) + u2 * sin(q0) * cos(q1)],
  981. [u1 * cos(q0) + u2 * sin(q0) * cos(q1)],
  982. [u0 + u1 * sin(q0) - u2 * sin(q1) -
  983. u2 * cos(q0) * cos(q1)]])) == zeros(3, 1)
  984. def test_weld_joint():
  985. _, _, P, C = _generate_body()
  986. W = WeldJoint('W', P, C)
  987. assert W.name == 'W'
  988. assert W.parent == P
  989. assert W.child == C
  990. assert W.coordinates == Matrix()
  991. assert W.speeds == Matrix()
  992. assert W.kdes == Matrix(1, 0, []).T
  993. assert P.dcm(C) == eye(3)
  994. assert W.child_point.pos_from(C.masscenter) == Vector(0)
  995. assert W.parent_point.pos_from(P.masscenter) == Vector(0)
  996. assert W.parent_point.pos_from(W.child_point) == Vector(0)
  997. assert P.masscenter.pos_from(C.masscenter) == Vector(0)
  998. assert C.masscenter.vel(P.frame) == Vector(0)
  999. assert P.ang_vel_in(C) == 0
  1000. assert C.ang_vel_in(P) == 0
  1001. assert W.__str__() == 'WeldJoint: W parent: P child: C'
  1002. N, A, P, C = _generate_body()
  1003. l, m = symbols('l m')
  1004. Pint = ReferenceFrame('P_int')
  1005. Pint.orient_axis(P.frame, P.y, pi / 2)
  1006. W = WeldJoint('W', P, C, parent_point=l * P.frame.x,
  1007. child_point=m * C.frame.y, parent_interframe=Pint)
  1008. assert W.child_point.pos_from(C.masscenter) == m * C.frame.y
  1009. assert W.parent_point.pos_from(P.masscenter) == l * P.frame.x
  1010. assert W.parent_point.pos_from(W.child_point) == Vector(0)
  1011. assert P.masscenter.pos_from(C.masscenter) == - l * N.x + m * A.y
  1012. assert C.masscenter.vel(P.frame) == Vector(0)
  1013. assert P.masscenter.vel(Pint) == Vector(0)
  1014. assert C.ang_vel_in(P) == 0
  1015. assert P.ang_vel_in(C) == 0
  1016. assert P.x == A.z
  1017. JointsMethod(P, W) # Tests #10770
  1018. def test_deprecated_parent_child_axis():
  1019. q, u = dynamicsymbols('q_J, u_J')
  1020. N, A, P, C = _generate_body()
  1021. with warns_deprecated_sympy():
  1022. PinJoint('J', P, C, child_axis=-A.x)
  1023. assert (-A.x).angle_between(N.x) == 0
  1024. assert -A.x.express(N) == N.x
  1025. assert A.dcm(N) == Matrix([[-1, 0, 0],
  1026. [0, -cos(q), -sin(q)],
  1027. [0, -sin(q), cos(q)]])
  1028. assert A.ang_vel_in(N) == u * N.x
  1029. assert A.ang_vel_in(N).magnitude() == sqrt(u ** 2)
  1030. N, A, P, C = _generate_body()
  1031. with warns_deprecated_sympy():
  1032. PrismaticJoint('J', P, C, parent_axis=P.x + P.y)
  1033. assert (A.x).angle_between(N.x + N.y) == 0
  1034. assert A.x.express(N) == (N.x + N.y) / sqrt(2)
  1035. assert A.dcm(N) == Matrix([[sqrt(2) / 2, sqrt(2) / 2, 0],
  1036. [-sqrt(2) / 2, sqrt(2) / 2, 0], [0, 0, 1]])
  1037. assert A.ang_vel_in(N) == Vector(0)
  1038. def test_deprecated_joint_pos():
  1039. N, A, P, C = _generate_body()
  1040. with warns_deprecated_sympy():
  1041. pin = PinJoint('J', P, C, parent_joint_pos=N.x + N.y,
  1042. child_joint_pos=C.y - C.z)
  1043. assert pin.parent_point.pos_from(P.masscenter) == N.x + N.y
  1044. assert pin.child_point.pos_from(C.masscenter) == C.y - C.z
  1045. N, A, P, C = _generate_body()
  1046. with warns_deprecated_sympy():
  1047. slider = PrismaticJoint('J', P, C, parent_joint_pos=N.z + N.y,
  1048. child_joint_pos=C.y - C.x)
  1049. assert slider.parent_point.pos_from(P.masscenter) == N.z + N.y
  1050. assert slider.child_point.pos_from(C.masscenter) == C.y - C.x