Package mbdyn :: Package elts :: Module joint
[hide private]

Source Code for Module mbdyn.elts.joint

  1  #!/usr/bin/env python 
  2  # -*- coding: utf-8 -*- 
  3  # 
  4  # This file is part of MBDyn sim suite. 
  5  # Copyright (C) 2007 André ESPAZE, as part of a Master thesis supervised by 
  6  # Martin O.L.Hansen (DTU) and Nicolas Chauvat (Logilab) 
  7   
  8  # MBDyn sim suite is free software; you can redistribute it and/or modify 
  9  # it under the terms of the GNU General Public License as published by 
 10  # the Free Software Foundation; either version 2 of the License, or 
 11  # (at your option) any later version. 
 12  # 
 13  # This program is distributed in the hope that it will be useful, 
 14  # but WITHOUT ANY WARRANTY; without even the implied warranty of 
 15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 16  # GNU General Public License for more details. 
 17  # 
 18  # You should have received a copy of the GNU General Public License 
 19  # along with this program; if not, write to the Free Software 
 20  # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
 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   
37 -class CommonJoint(ElementWithNode):
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
44 - def __init__(self, name):
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
51 - def get_mbdyn_instance(self):
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
59 -class CommonJoint2Nodes(CommonJoint):
60 """Description of a joint associated to two nodes. 61 """ 62
63 - def __init__(self, name):
64 CommonJoint.__init__(self, name) 65 self.node = None 66 self.node2 = None 67 self.mbdyn_node = None 68 self.mbdyn_node2 = None
69
70 - def attach_to_node(self, node):
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
76 - def set_node1(self, node):
77 """Set the first node of the joint""" 78 self.node = node
79
80 - def set_node2(self, node):
81 """Set the second node of the joint""" 82 self.node2 = node
83
84 - def set_node_label(self):
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
90 -class Clamp(CommonJoint):
91 """The clamp joint. 92 """ 93
94 - def __init__(self, name="clamp"):
95 CommonJoint.__init__(self, name) 96 self.class_key = "Clamp" 97 MANAGER.add_argument(self, "joint_type", "clamp") 98 self.arg_names += ["position", "orientation_matrix"] 99 self.set_default()
100
101 - def set_default(self):
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
108 - def set_position(self, *args, **kargs):
109 """Set the clamp joint position""" 110 if args[0] == "node": 111 MANAGER.add_argument(self, "position", "node") 112 else: 113 MANAGER.add_vector(self, "position", args, kargs)
114
115 - def set_orientation_matrix(self, *args, **kargs):
116 """Set the clamp joint orientation matrix""" 117 if args[0] == "node": 118 MANAGER.add_argument(self, "orientation_matrix", "node") 119 else: 120 MANAGER.add_orientation_matrix(self, 121 "orientation_matrix", args, kargs)
122 123 124 JOINT_CLASS["Clamp"] = Clamp 125 126
127 -class Distance(CommonJoint2Nodes):
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"):
133 CommonJoint2Nodes.__init__(self, name) 134 MANAGER.add_argument(self, "joint_type", "distance") 135 self.arg_names += ["node2", "distance"] 136 self.class_key = "Distance"
137
138 - def set_constant_distance(self, value, com=None):
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
147 -class DriveHinge(CommonJoint2Nodes):
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
165 - def set_default(self):
166 """Set the default on a hinge joint. It will be a identity matrix 167 for the two orientation matrix, an orientation axis along M{z} 168 and a null angle""" 169 self.set_orientation_matrix1(EYE) 170 self.set_orientation_matrix2(EYE) 171 self.set_orientation_axis(0., 0., 1.) 172 self.set_value(0.)
173
174 - def set_orientation_matrix1(self, *args, **kargs):
175 """Set the relative orientation matrix of the first node""" 176 MANAGER.add_orientation_matrix(self, "orientation_matrix1", args, kargs)
177
178 - def set_orientation_matrix2(self, *args, **kargs):
179 """Set the relative orientation matrix of the second node""" 180 MANAGER.add_orientation_matrix(self, "orientation_matrix2", args, kargs)
181
182 - def set_orientation_axis(self, *args, **kargs):
183 """Set the relative orientation axis for the rotation""" 184 kargs["ref"] = NONE_REF 185 MANAGER.add_vector(self, "orientation_axis", args, kargs)
186
187 - def set_value(self, value, com=None):
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
196 -class BindingsHinge(DriveHinge):
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"):
203 DriveHinge.__init__(self, name) 204 MANAGER.add_argument(self, "joint_type", "bindings hinge") 205 self.class_key = "BindingsHinge"
206 207 208 JOINT_CLASS["BindingsHinge"] = BindingsHinge 209 210
211 -class Prismatic(CommonJoint2Nodes):
212 """Constraint the relative rotation of two nodes. 213 The hinge keyword is used to assign the joint initial orientation. 214 """ 215
216 - def __init__(self, name="prismatic"):
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
226 - def set_default(self):
227 """Set the hinge joint default. It will be a identity orientation 228 matrix for its two connections.""" 229 self.set_orientation_matrix1(EYE) 230 self.set_orientation_matrix2(EYE)
231
232 - def set_orientation_matrix1(self, *args, **kargs):
233 """Set the relative orientation matrix of the first node""" 234 MANAGER.add_orientation_matrix(self, "orientation_matrix1", args, kargs)
235
236 - def set_orientation_matrix2(self, *args, **kargs):
237 """Set the relative orientation matrix of the second node""" 238 MANAGER.add_orientation_matrix(self, "orientation_matrix2", args, kargs)
239 240 241 JOINT_CLASS["Prismatic"] = Prismatic 242 243
244 -class _SetRevoluteDocumentation:
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
274 - def __call__(self, method):
275 """Set the documentation on the method""" 276 method.__doc__ = self.doc 277 return method
278 279
280 -class RevoluteHinge(CommonJoint2Nodes):
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
304 - def set_default(self):
305 """Set the default for a pivot hinge. It will be a null offset and 306 and identity matrix for its two connections""" 307 self.set_offset1(NULL) 308 self.set_orientation_matrix1(EYE) 309 self.set_offset2(NULL) 310 self.set_orientation_matrix2(EYE)
311
312 - def set_offset1(self, *args, **kargs):
313 """Set the relative offset of the node 1""" 314 MANAGER.add_vector(self, "offset1", args, kargs)
315
316 - def set_orientation_matrix1(self, *args, **kargs):
317 """Set the orientation matrix of the node 1""" 318 MANAGER.add_orientation_matrix(self, "orientation_matrix1", args, kargs)
319
320 - def set_offset2(self, *args, **kargs):
321 """Set the relative offset of the node 2""" 322 MANAGER.add_vector(self, "offset2", args, kargs)
323
324 - def set_orientation_matrix2(self, *args, **kargs):
325 """Set the orientation matrix of the node 2""" 326 MANAGER.add_orientation_matrix(self, "orientation_matrix2", args, kargs)
327 328 @_SetRevoluteDocumentation("orientation_matrix1", "orientation_matrix2")
329 - def set_rotation_axis(self, *args, **kargs):
330 self.set_orientation_matrix1(*args, **kargs) 331 self.set_orientation_matrix2(*args, **kargs)
332 333 334 JOINT_CLASS["RevoluteHinge"] = RevoluteHinge 335 336
337 -class RevolutePin(CommonJoint):
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
354 - def set_default(self):
355 """Set the default on the pivot joint. The first connection, 356 called absolute pin, will have a null offset and an identity 357 matrix. It will be the same for the second connection, attached 358 to the user node""" 359 self.set_abs_pin_position(NULL) 360 self.set_abs_pin_orientation_matrix(EYE) 361 self.set_offset(NULL) 362 self.set_orientation_matrix(EYE)
363
364 - def set_abs_pin_position(self, *args, **kargs):
365 """Set the absolute pin position""" 366 MANAGER.add_vector(self, "abs_pin_position", args, kargs)
367
368 - def set_abs_pin_orientation_matrix(self, *args, **kargs):
369 """Set the absolute pin orientation matrix""" 370 MANAGER.add_orientation_matrix(self, "abs_pin_orientation_matrix", 371 args, kargs)
372
373 - def set_offset(self, *args, **kargs):
374 """Set the relative offset of the second connection""" 375 MANAGER.add_vector(self, "offset", args, kargs)
376
377 - def set_orientation_matrix(self, *args, **kargs):
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")
383 - def set_rotation_axis(self, *args, **kargs):
384 self.set_abs_pin_orientation_matrix(*args, **kargs) 385 self.set_orientation_matrix(*args, **kargs)
386 387 388 JOINT_CLASS["RevolutePin"] = RevolutePin 389 390
391 -class SphericalHinge(CommonJoint2Nodes):
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
408 - def set_default(self):
409 """Set the default on a spherical hinge. It will be a null offset 410 and an identity matrix for both connections""" 411 self.set_offset1(NULL) 412 self.set_orientation_matrix1(EYE) 413 self.set_offset2(NULL) 414 self.set_orientation_matrix2(EYE)
415
416 - def set_offset1(self, *args, **kargs):
417 """Set the relative offset of the node 1""" 418 MANAGER.add_vector(self, "offset1", args, kargs)
419
420 - def set_orientation_matrix1(self, *args, **kargs):
421 """Set the orientation matrix of the node 1""" 422 MANAGER.add_orientation_matrix(self, "orientation_matrix1", 423 args, kargs)
424
425 - def set_offset2(self, *args, **kargs):
426 """Set the relative offset of the node 2""" 427 MANAGER.add_vector(self, "offset2", args, kargs)
428
429 - def set_orientation_matrix2(self, *args, **kargs):
430 """Set the orientation matrix of the node 2""" 431 MANAGER.add_orientation_matrix(self, "orientation_matrix2", args, kargs)
432 433 434 JOINT_CLASS["SphericalHinge"] = SphericalHinge 435 436 437 # Special joint that does not exist in MBDyn 438
439 -class Coincidence:
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
467 - def __init__(self, name=None):
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
483 - def set_default(self):
484 """Set the default for the two joints""" 485 for joint in self._joints: 486 joint.set_default()
487
488 - def set_relative_from(self, ref):
489 """Set the reference frame for the two joints""" 490 for joint in self._joints: 491 joint.set_relative_from(ref)
492
493 - def set_node1(self, node1):
494 """Set the node 1 for the two joints""" 495 for joint in self._joints: 496 joint.set_node1(node1)
497
498 - def set_node2(self, node2):
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