Beispiel #1
0
class ElasticMaterialObject(SofaObject):
    def __init__(self,
                 attachedTo=None,
                 volumeMeshFileName=None,
                 name="ElasticMaterialObject",
                 rotation=[0.0, 0.0, 0.0],
                 translation=[0.0, 0.0, 0.0],
                 surfaceMeshFileName=None,
                 collisionMesh=None,
                 withConstrain=True,
                 surfaceColor=[1.0, 1.0, 1.0],
                 poissonRatio=0.3,
                 youngModulus=18000,
                 totalMass=1.0,
                 solver=None):

        self.node = Node(attachedTo, name)
        ElasticMaterialObject.createPrefab(self, volumeMeshFileName, name,
                                           rotation, translation,
                                           surfaceMeshFileName, collisionMesh,
                                           withConstrain, surfaceColor,
                                           poissonRatio, youngModulus,
                                           totalMass, solver)

    @staticmethod
    def createPrefab(self,
                     volumeMeshFileName=None,
                     name="ElasticMaterialObject",
                     rotation=[0.0, 0.0, 0.0],
                     translation=[0.0, 0.0, 0.0],
                     surfaceMeshFileName=None,
                     collisionMesh=None,
                     withConstrain=True,
                     surfaceColor=[1.0, 1.0, 1.0],
                     poissonRatio=0.3,
                     youngModulus=18000,
                     totalMass=1.0,
                     solver=None):
        if self.node == None:
            Sofa.msg_error(
                "Unable to create the elastic object because it is not attached to any node. Please fill the attachedTo parameter"
            )
            return None

        if volumeMeshFileName == None:
            Sofa.msg_error(
                self.node,
                "Unable to create an elastic object because there is no volume mesh provided."
            )
            return None

        if volumeMeshFileName.endswith(".msh"):
            self.loader = self.node.createObject('MeshGmshLoader',
                                                 name='loader',
                                                 filename=volumeMeshFileName,
                                                 rotation=rotation,
                                                 translation=translation)
        elif volumeMeshFileName.endswith(".gidmsh"):
            self.loader = self.node.createObject('GIDMeshLoader',
                                                 name='loader',
                                                 filename=volumeMeshFileName,
                                                 rotation=rotation,
                                                 translation=translation)
        else:
            self.loader = self.node.createObject('MeshVTKLoader',
                                                 name='loader',
                                                 filename=volumeMeshFileName,
                                                 rotation=rotation,
                                                 translation=translation)

        if solver == None:
            self.integration = self.node.createObject('EulerImplicit',
                                                      name='integration')
            self.solver = self.node.createObject('SparseLDLSolver',
                                                 name="solver")

        self.container = self.node.createObject(
            'TetrahedronSetTopologyContainer', src='@loader', name='container')
        self.dofs = self.node.createObject('MechanicalObject',
                                           template='Vec3d',
                                           name='dofs')

        ## To be properly simulated and to interact with gravity or inertia forces, an elasticobject
        ## also needs a mass. You can add a given mass with a uniform distribution for an elasticobject
        ## by adding a UniformMass component to the elasticobject node
        self.mass = self.node.createObject('UniformMass',
                                           totalMass=totalMass,
                                           name='mass')

        ## The next component to add is a FEM forcefield which defines how the elasticobject reacts
        ## to a loading (i.e. which deformations are created from forces applied onto it).
        ## Here, because the elasticobject is made of silicone, its mechanical behavior is assumed elastic.
        ## This behavior is available via the TetrahedronFEMForceField component.
        self.forcefield = self.node.createObject('TetrahedronFEMForceField',
                                                 template='Vec3d',
                                                 method='large',
                                                 name='forcefield',
                                                 poissonRatio=poissonRatio,
                                                 youngModulus=youngModulus)

        if withConstrain:
            self.node.createObject('LinearSolverConstraintCorrection',
                                   solverName=self.solver.name)

        if collisionMesh:
            self.addCollisionModel(collisionMesh, rotation, translation)

        if surfaceMeshFileName:
            self.addVisualModel(surfaceMeshFileName, surfaceColor, rotation,
                                translation)

    def addCollisionModel(self,
                          collisionMesh,
                          rotation=[0.0, 0.0, 0.0],
                          translation=[0.0, 0.0, 0.0]):
        self.collisionmodel = self.node.createChild('CollisionModel')
        self.collisionmodel.createObject('MeshSTLLoader',
                                         name='loader',
                                         filename=collisionMesh,
                                         rotation=rotation,
                                         translation=translation)
        self.collisionmodel.createObject('TriangleSetTopologyContainer',
                                         src='@loader',
                                         name='container')
        self.collisionmodel.createObject('MechanicalObject',
                                         template='Vec3d',
                                         name='dofs')
        self.collisionmodel.createObject('Triangle')
        self.collisionmodel.createObject('Line')
        self.collisionmodel.createObject('Point')
        self.collisionmodel.createObject('BarycentricMapping')

    def addVisualModel(self, filename, color, rotation, translation):
        self.visualmodel = VisualModel(parent=self.node,
                                       surfaceMeshFileName=filename,
                                       color=color,
                                       rotation=rotation,
                                       translation=translation)

        ## Add a BarycentricMapping to deform the rendering model to follow the ones of the
        ## mechanical model.
        self.visualmodel.mapping = self.visualmodel.node.createObject(
            'BarycentricMapping', name='mapping')
Beispiel #2
0
class ServoMotor(SofaObject):
    """A S90 servo motor

    This prefab is implementing a S90 servo motor.
    https://servodatabase.com/servo/towerpro/sg90

    The prefab ServoMotor is composed of:
    - a visual model
    - a mechanical model composed two rigids. One rigid is for the motor body
      while the other is implementing the servo rotating wheel.
    - a KinematicMotorController to compute from an input angle the new orientation of the
      servo wheel according to its parent frame.

    The prefab has the following parameters:
    - translation       to change default location of the servo (default [0.0,0.0,0.0])
    - rotation          to change default rotation of the servo (default [0.0,0.0,0.0,1])
    - scale             to change default scale of the servo (default 1)
    - doAddVisualModel  to control wether a visual model is added (default True)

    The prefab have the following property:
    - angle     use this to specify the angle of rotation of the servo motor

    Example of use in a Sofa scene:

    def createScene(root):
        ...
        servo = ServoMotor(root)

        ## Direct access to the components
        servo.node.angle = 1.0
        servo.dofs.showObjects = False

        ## Indirect access to the components
        get(servo.node, "dofs.showObjects").value = False
        get(servo.node, "servowheel.dofs.showObjects").value = False
    """

    def __init__(self, parent, translation=[0.0, 0.0, 0.0], rotation=[0.0, 0.0, 0.0], scale=[1.0, 1.0, 1.0], doAddVisualModel=True):
        self.node = Node(parent, "ServoMotor")
        self.node.addNewData("angle",
                             "ServoMotor Properties",
                             "The angular position of the motor (in radians)", "double", 0.0)
        self.angle = self.node.findData("angle")

        self.dofs = self.node.createObject("MechanicalObject", size=1,
                                           name="dofs",
                                           translation=translation, rotation=rotation, scale3d=scale,
                                           template='Rigid3', showObject=True, showObjectScale=15)

        self.servowheel = ServoWheel(self.node)
        self.controller = KinematicMotorController(self.node, self.dofs, self.servowheel.dofs,
                                                   self.servowheel.node.map,
                                                   angleValue=self.angle.getLinkPath())

        if doAddVisualModel:
            self.addVisualModel()

    def addVisualModel(self):
        visual = self.node.createChild("VisualModel")
        visual.createObject("MeshSTLLoader", name="loader", filename="../data/mesh/SG90_servomotor.stl")
        visual.createObject("MeshTopology", src="@loader")
        visual.createObject("OglModel", color=[0.15, 0.45, 0.75, 0.7], writeZTransparent=True)
        visual.createObject("RigidMapping", index=0)