test_joint.py 57 KB

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