Tagged: SOFA Soft Robots Mesh
28 January 2021 at 0 h 51 min #18409
Currently, I have a soft robotic finger that will be pneumatically actuated through three separate chambers. I would like to control it via sofa so I have been following pneunet tutorial as it is very similar to what I would like to do.
The robotic finger has 7 different components, all with different material properties (stiffnesses etc). I can create a mesh from the step file for these 7 volumes, however when I import it into SOFA, all 7 components move independently. I believe that gmsh created different volumetric meshes for each volume. My first attempt to solve this issue was to update my CAD model so that the entire finger is one component, create the mesh, then update the stiffness of different components of the finger in SOFA. Currently I have a solid finger of all one material that can be simulated in SOFA, however I have not found a way to separately define different parts of the mesh with different force fields.
My question now is, what is the correct approach to attaching/combining different meshes/components with different material properties? For example, if I was to have two cubes of different materials and I would like to attach them together in SOFA (so that they act as one object), how would I go about this?
Thank you28 January 2021 at 10 h 56 min #18410JonnyParticipant
you should be able to define different sections of your finger with BoxROI and then create a child of your object with a separate forcefield. Following the pneunet gripper tutorial it would look like this (step3-StiffLayer):
finger.createObject('BoxROI', name='boxROISubTopo', box='-100 22.5 -8 -19 28 8') modelSubTopo = finger.createChild('modelSubTopo') modelSubTopo.createObject('Mesh', email@example.com', tetrahedra="@boxROISubTopo.tetrahedraInROI", name='container') modelSubTopo.createObject('TetrahedronFEMForceField', template='Vec3d', name='FEM', method='large', poissonRatio='0.3', youngModulus='1500')
Also, it should be possible to have a separate mesh for each component (with different material properties) in Sofa and then attach them with something like
BilateralInteractionConstraint. I have tried something similar once without any success so if the first approach works for you, I think that’s the easier way to do it. But maybe someone knows how to properly use those components – I would be interested to hear that as well.
Jonny28 January 2021 at 19 h 15 min #18414
Thank you for your response. I did see from the pneunet tutorial I could use boxROI to define a stiff layer. The issue is the areas I would like to change are not easily captured via boxes. For example, I will need to define a cylinder that is in the center of the finger of a different stiffness, thus the use of the BoxROI makes that difficult.
Do you know if there are other options to define ROIs in SOFA? If I am limited to boxROI then it would be difficult to properly define all portions of the finger. Otherwise, I will look into the attach constraints.
Thanks28 January 2021 at 22 h 29 min #18415JonnyParticipant
I see, that makes things a little more complicated.
There are other options to define ROI – you can read more about them and find example scenes here: ROI selection
Maybe a combination of those will work for you.31 January 2021 at 2 h 40 min #184481 February 2021 at 19 h 02 min #18472
no I have not solved it. I think the solution is to use attachconstraints when trying to combine complex meshes of different properties. My issue is that I cannot find any tutorials or guides on how to use it when writing python code (using a .pyscn file)
if anyone can provide guidance or a python tutorial/guide on how to use the attachconstraints that would help tremendously.
Thanks11 February 2021 at 18 h 08 min #18576
Are the faces of your meshes coherent (same number of point and same location of each point) ? If so, you could set on each face Bilateral constraint (if you use a FreeMotionAnimationLoop = solving constraint using the Lagrange multipliers) or AttachConstraint.
If each mesh is different (different resolution), then it will be difficult.
An alternative: you could define your object as one single object and define heterogeneous values of the stiffness. Which mechanical constitutive law are you using? TetrahedronFEMForceField right ? If so, you can define a global “youngModulus” and then define a factor per tetrahedron (vector “localStiffnessFactor”).
Hugo15 February 2021 at 23 h 50 min #18679
Thank you for your response, you are correct, each mesh has a different shape and the points are not at the same location. I tried to use attach constraint but because the points are not exact, the motion is very unstable.
I am trying to define heterogenous values for the stiffness using the tetrahedromFEMForceField. The issue now is, I cant seem to use the ROI functions to determine which parts of the mesh to redefine with a higher stiffness. I am using boxROI and tetrahedraInROI to define nodes with the new forcefields, however the BoxROI only lets me define min/max points of the box and gives little control over orientation and position. For example, I need to define a cylinder through the central axes of the actuator with a higher stiffness however I am not sure how to identify the tetrahedron in that cylinder using an ROI when defining a new force field. There is not a cylinderROI I can use if I am not mistaken.16 February 2021 at 8 h 55 min #18681
Have you noticed that with BoxROI you can define both the “box” data field or the “orientedBox” data field?
This should do the job as you expect.
Hugo17 February 2021 at 20 h 17 min #18711
Thanks for the response, I am looking at the documentation for BoxROI and see that I can do this now. I am trying to get it to work but it does not seem to be working properly for me using python. Could you provide an example or somewhere that I can find an implementation of this so I can figure out how to use it?
Anoush25 February 2021 at 23 h 28 min #18752
There you are:
def createGraph(self,rootNode): # rootNode rootNode.createObject('RequiredPlugin', name='SofaOpenglVisual') rootNode.createObject('RequiredPlugin', name='SofaImplicitOdeSolver') rootNode.createObject('RequiredPlugin', name='SofaLoader') rootNode.createObject('RequiredPlugin', name='SofaGeneralSimpleFem') rootNode.createObject('VisualStyle', displayFlags='showBehaviorModels') rootNode.createObject('DefaultPipeline', name='CollisionPipeline', verbose='0') rootNode.createObject('BruteForceDetection', name='N2') rootNode.createObject('DefaultContactManager', name='collision response', response='default') rootNode.createObject('DiscreteIntersection') rootNode.createObject('MeshObjLoader', name='LiverSurface', filename='mesh/liver-smooth.obj') # rootNode/Liver Liver = rootNode.createChild('Liver') self.Liver = Liver Liver.gravity = '0 -9.81 0' Liver.createObject('EulerImplicitSolver', rayleighStiffness='0.1', name='cg_odesolver', rayleighMass='0.1') Liver.createObject('CGLinearSolver', threshold='1e-09', tolerance='1e-09', name='linear solver', iterations='25') Liver.createObject('MeshGmshLoader', name='meshLoader', filename='mesh/liver.msh') Liver.createObject('TetrahedronSetTopologyContainer', src='@meshLoader', name='topo') Liver.createObject('MechanicalObject', src='@meshLoader', name='dofs') Liver.createObject('TetrahedronSetGeometryAlgorithms', name='GeomAlgo', template='Vec3d') Liver.createObject('DiagonalMass', massDensity='1', name='computed using mass density') Liver.createObject('TetrahedralCorotationalFEMForceField', poissonRatio='0.3', name='FEM', computeGlobalMatrix='0', method='large', template='Vec3d', youngModulus='3000') Liver.createObject('FixedConstraint', indices='3 39 64', name='FixedConstraint') Liver.createObject('BoxROI', box='-1 4 -1 1 6 1', drawBoxes='1', name='boxROI', drawPoints='1') # rootNode/Liver/Visu Visu = Liver.createChild('Visu') self.Visu = Visu Visu.tags = 'Visual' Visu.gravity = '0 -9.81 0' Visu.createObject('OglModel', src='@../../LiverSurface', name='VisualModel') Visu.createObject('BarycentricMapping', input='@../dofs', name='visual mapping', output='@VisualModel') # rootNode/Liver/Surf Surf = Liver.createChild('Surf') self.Surf = Surf Surf.gravity = '0 -9.81 0' Surf.createObject('SphereLoader', filename='mesh/liver.sph') Surf.createObject('MechanicalObject', position='@[-1].position', name='spheres') Surf.createObject('SphereCollisionModel', listRadius='@[-2].listRadius', name='CollisionModel') Surf.createObject('BarycentricMapping', input='@../dofs', name='sphere mapping', output='@spheres') return 0;
To help you visualize your BoxROI, you can activate the
drawBoxes='true'boolean data AND the “Behavior Models” in the View widget of runSofa.
- You must be logged in to reply to this topic.