1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """The elements describing the joint group. The two MBDyn extensions
23 have been made.
24 The first one is L{BindingsHinge} for setting an angle vector between
25 two nodes orientation matrix at run time. Using the interface developed
26 with L{SphericalHinge} and L{Prismatic}, a new L{Coincidence} joint
27 that clamp two node has been created.
28 """
29 from mbdyn.general import NULL, EYE
30 from mbdyn.references import NONE_REF
31 from mbdyn.common import MANAGER
32
33 from mbdyn.elements_base import ElementWithNode
34
35 JOINT_CLASS = {}
36
38 """The top class for joints. Each joint has a type
39 and is attached to a node. Some of them will
40 also be able to manipulate a reference from the
41 L{mbdyn.bindings.joints} module.
42 """
43
45 ElementWithNode.__init__(self, name)
46 self.mbdyn_type = "joint"
47 self.group_key = "JOINT"
48 self.arg_names += ["joint_type", "node"]
49 self.control_data_with_values = [("joints", "+1 # %s" % name)]
50
52 """Set the MBDyn instance reference under the C{mbdyn_inst}
53 attribute. The reference will be from a class defined in the
54 L{mbdyn.bindings.joints} module."""
55 mbdyn_joints = self.simulation.wrapt_mbdyn.elts.joints
56 self.mbdyn_inst = mbdyn_joints.get_from_label(self.label)
57
58
60 """Description of a joint associated to two nodes.
61 """
62
64 CommonJoint.__init__(self, name)
65 self.node = None
66 self.node2 = None
67 self.mbdyn_node = None
68 self.mbdyn_node2 = None
69
71 """Does not make sense for a joint of 2 nodes"""
72 mess = "For a 'CommonJoint2Nodes', the method 'attach_to_node' "
73 mess += "is not relevant.\nUse 'set_node1' and 'set_node2' instead."
74 print mess
75
77 """Set the first node of the joint"""
78 self.node = node
79
81 """Set the second node of the joint"""
82 self.node2 = node
83
85 """Set the node labels (or index)"""
86 self.mbdyn_node = self.node.mbdyn_label
87 self.mbdyn_node2 = self.node2.mbdyn_label
88
89
91 """The clamp joint.
92 """
93
100
102 """Set the default on the clamp. It will be
103 a position and orientation matrix relative to the
104 attached node"""
105 self.set_position("node")
106 self.set_orientation_matrix("node")
107
114
122
123
124 JOINT_CLASS["Clamp"] = Clamp
125
126
128 """Set a distance between two nodes. There is no constraint
129 on the nodes orientation matrix.
130 """
131
132 - def __init__(self, name="Distance joint"):
137
139 """Set the constant distance between the two nodes"""
140 MANAGER.add_argument(self, "distance", value, com,
141 "const, %s" % str(value))
142
143
144 JOINT_CLASS["Distance"] = Distance
145
146
148 """Imposed rotation on a hinge.
149 """
150
151 - def __init__(self, name="drive hinge"):
152 CommonJoint2Nodes.__init__(self, name)
153 MANAGER.add_argument(self, "joint_type", "drive hinge")
154 MANAGER.add_argument(self, "hinge1", "hinge")
155 MANAGER.add_argument(self, "hinge2", "hinge")
156 self.class_key = "DriveHinge"
157
158 self.arg_names += ["hinge1", "orientation_matrix1",
159 "node2",
160 "hinge2", "orientation_matrix2",
161 "orientation_axis", "value"]
162
163 self.set_default()
164
173
177
181
183 """Set the relative orientation axis for the rotation"""
184 kargs["ref"] = NONE_REF
185 MANAGER.add_vector(self, "orientation_axis", args, kargs)
186
188 """Set the value of the rotation"""
189 MANAGER.add_argument(self, "value", value, com,
190 "const, %s" % str(value))
191
192
193 JOINT_CLASS["DriveHinge"] = DriveHinge
194
195
197 """A drive hinge joint having its angle vector set at
198 run time. This object is still in development and may lead
199 to unstable simulation.
200 """
201
202 - def __init__(self, name="bindings hinge"):
206
207
208 JOINT_CLASS["BindingsHinge"] = BindingsHinge
209
210
212 """Constraint the relative rotation of two nodes.
213 The hinge keyword is used to assign the joint initial orientation.
214 """
215
217 CommonJoint2Nodes.__init__(self, name)
218 self.class_key = "Prismatic"
219 MANAGER.add_argument(self, "joint_type", "prismatic")
220 MANAGER.add_argument(self, "hinge1", "hinge")
221 MANAGER.add_argument(self, "hinge2", "hinge")
222 self.arg_names += ["hinge1", "orientation_matrix1",
223 "node2",
224 "hinge2", "orientation_matrix2"]
225
231
235
239
240
241 JOINT_CLASS["Prismatic"] = Prismatic
242
243
245 """An abstract class used as decorator
246 for setting the common documentation on the L{RevoluteHinge}
247 and the L{RevolutePin} classes.
248 """
249
250 - def __init__(self, om1_name, om2_name):
251 self.doc = """The third axis of the revolute pin is supposed to be
252 the axis of rotation of the joint. This method will set
253 the C{%(om1)s} and the C{%(om2)s}
254 to the same value, that's why a matrix is expected. Example::
255
256 joint.set_rotation_axis(two=(0., 1., 0.),
257 three=(1., 0., 0.))
258
259 It will make the joint rotate along the M{x} axis of the joint
260 reference frame. In that example, the C{two} keyword is needed to
261 build the orientation matrix, it confirms that the second axis
262 of the joint reference frame is also the second axis of the
263 joint orientation matrix.
264 Another example for rotating along the C{y} axis::
265
266 joint.set_rotation_axis(one=(1., 0., 0.),
267 three=(0., 1., 0.))
268
269 You can still use that method if both orientation matrix are
270 the same and you know them. If both orientation matrix are not
271 the same, use C{set_%(om1)s} and C{set_%(om2)s} instead.
272 """ % {"om1" : om1_name, "om2" : om2_name}
273
275 """Set the documentation on the method"""
276 method.__doc__ = self.doc
277 return method
278
279
281 """A pivot hinge between two nodes.
282 The rotation will occur around the node 1, the axis being defined
283 by L{set_rotation_axis}.
284
285 If an offset is applied on a clamped node 1, the center of rotation
286 of the joint will move but the node will stay where it is.
287 If an offset is applied on the node 2, the node will move, modifying
288 its initial position due to the constraint.
289 """
290
291 - def __init__(self, name="revolute hinge"):
292 CommonJoint2Nodes.__init__(self, name)
293 self.class_key = "RevoluteHinge"
294 MANAGER.add_argument(self, "joint_type", "revolute hinge")
295 MANAGER.add_argument(self, "hinge1", "hinge")
296 MANAGER.add_argument(self, "hinge2", "hinge")
297 self.arg_names += [ "offset1", "hinge1",
298 "orientation_matrix1",
299 "node2",
300 "offset2", "hinge2",
301 "orientation_matrix2"]
302 self.set_default()
303
311
313 """Set the relative offset of the node 1"""
314 MANAGER.add_vector(self, "offset1", args, kargs)
315
319
321 """Set the relative offset of the node 2"""
322 MANAGER.add_vector(self, "offset2", args, kargs)
323
327
328 @_SetRevoluteDocumentation("orientation_matrix1", "orientation_matrix2")
332
333
334 JOINT_CLASS["RevoluteHinge"] = RevoluteHinge
335
336
338 """A pivot between a built-in node clamped to the ground
339 and the user one. The axis of rotation
340 is set thanks to the L{set_rotation_axis}.
341 """
342
343 - def __init__(self, name="revolute_pin"):
344 CommonJoint.__init__(self, name)
345 MANAGER.add_argument(self, "joint_type", "revolute pin")
346 self.class_key = "RevolutePin"
347 self.group_key = "JOINT"
348 self.arg_names += [ "offset", "hinge1",
349 "orientation_matrix","abs_pin_position",
350 "hinge2", "abs_pin_orientation_matrix"]
351 MANAGER.add_argument(self, "hinge1", "hinge")
352 MANAGER.add_argument(self, "hinge2", "hinge")
353
363
365 """Set the absolute pin position"""
366 MANAGER.add_vector(self, "abs_pin_position", args, kargs)
367
372
374 """Set the relative offset of the second connection"""
375 MANAGER.add_vector(self, "offset", args, kargs)
376
378 """Set the relative orientation matrix of the second connection"""
379 MANAGER.add_orientation_matrix(self, "orientation_matrix", args, kargs)
380
381 @_SetRevoluteDocumentation("abs_pin_orientation_matrix",
382 "orientation_matrix")
386
387
388 JOINT_CLASS["RevolutePin"] = RevolutePin
389
390
392 """A spherical hinge between two nodes.
393 """
394
395 - def __init__(self, name="spherical hinge"):
396 CommonJoint2Nodes.__init__(self, name)
397 MANAGER.add_argument(self, "joint_type", "spherical hinge")
398 MANAGER.add_argument(self, "hinge1", "hinge")
399 MANAGER.add_argument(self, "hinge2", "hinge")
400 self.class_key = "SphericalHinge"
401 self.arg_names += [ "offset1", "hinge1",
402 "orientation_matrix1",
403 "node2",
404 "offset2", "hinge2",
405 "orientation_matrix2"]
406 self.set_default()
407
415
417 """Set the relative offset of the node 1"""
418 MANAGER.add_vector(self, "offset1", args, kargs)
419
424
426 """Set the relative offset of the node 2"""
427 MANAGER.add_vector(self, "offset2", args, kargs)
428
432
433
434 JOINT_CLASS["SphericalHinge"] = SphericalHinge
435
436
437
438
440 """A joint that makes two nodes clamped to each other.
441 This joints does not exist in MBDyn but is based on
442 the Python interface.
443
444 This joint combines of a L{SphericalHinge}
445 and L{Prismatic}. The L{SphericalHinge} constraints the motion
446 of the two joints but allow rotations. The L{Prismatic} however
447 constraints the orientation matrix of the two nodes, both
448 have to stay the same which suppress the rotation.
449 Example making two nodes clamped::
450
451 ref = ReferenceFrame()
452 ref.set_position(10., 0., 0.)
453
454 node1 = StructuralNode()
455 node2 = StructuralNode()
456 node2.set_relative_from(ref)
457
458 joint = Coincidence()
459 joint.set_relative_from(ref)
460 joint.set_node1(node1)
461 joint.set_node2(node2)
462
463 Both joints can be accessed by the attributes:
464 C{spherical_hinge} and C{prismatic}.
465 """
466
468 if name == None:
469 self.name = "coincidence"
470 else:
471 self.name = "coincidence " + name
472 self.spherical_hinge = SphericalHinge("Spherical hinge " + self.name)
473 self.prismatic = Prismatic("Prismatic " + self.name)
474
475 self._joints = [self.spherical_hinge,
476 self.prismatic]
477 self.mbdyn_objects = self._joints
478
479 self.group_key = "JOINT"
480 self.class_key = "Coincidence"
481 self.set_default()
482
487
492
494 """Set the node 1 for the two joints"""
495 for joint in self._joints:
496 joint.set_node1(node1)
497
499 """Set the node 2 for the two joints"""
500 for joint in self._joints:
501 joint.set_node2(node2)
502
503
504 JOINT_CLASS["Coincidence"] = Coincidence
505