 # Simulating a cable based soft gripper This tutorial describes how to set up a simulation environment, a scene, using ..autolink::Sofa and how to use the ..autolink::SoftRobots plugin to model a virtual soft gripper driven by cables. The design of the gripper we are going to model is from [Taimoor Hassan et al. ](https://dl.acm.org/citation.cfm?id=2977533). Once modeled in Sofa the robot can be simulated and controlled as in:
Additional ..autolink::STLIB::CollisionMesh are required to precisely define the self-collision
behavior.
The finger.py file should now contain :
```python
# ... Same imports as in step 3 ...
from stlib3.physics.collision import ..autolink::STLIB::CollisionMesh
# ... Same as in step 3 ...
def Finger(parentNode):
# ... the finger
# ... the cable..
# ... the controller..
..autolink::STLIB::CollisionMesh(eobject,
surfaceMeshFileName="data/mesh/finger.stl", name="part0", collisionGroup=1)
..autolink::STLIB::CollisionMesh(eobject,
surfaceMeshFileName="data/mesh/fingerCollision_part1.stl", name="part1", collisionGroup=1)
..autolink::STLIB::CollisionMesh(eobject,
surfaceMeshFileName="data/mesh/fingerCollision_part2.stl", name="part2", collisionGroup=2)
```
The ..autolink::STLIB::CollisionMesh are set of triangles, each set can be part of one or multiple
collision group. By using the *"collisionGroup"* option you can specify the group of which the
..autolink::STLIB::CollisionMesh belong to. Triangle from different collision groupes are tested for
intersections and contact handling.
### Comments (things to present or do in this step)
- Explain the import of the CollisionMesh (if it was not done before)
- Explain the load of the mesh...
- Explain the role of collision group. Object in two different groups can collide.
- Explain the contactDistance parameters
## Step 5: Duplicating the finger to make a complete gripper
Now we have a working single finger we can duplicate it so that it can match the original soft gripper
robot design that contains three of them.

At this point the `finger.py` file should contain something similar to:
```python
# -*- coding: utf-8 -*-
import Sofa.Core
import Sofa.constants.Key as Key
from stlib3.scene import ..autolink::STLIB::Node
from stlib3.physics.deformable import ..autolink::STLIB::ElasticMaterialObject
from stlib3.physics.constraints import ..autolink::STLIB::FixedBox
from stlib3.physics.collision import ..autolink::STLIB::CollisionMesh
from splib3.loaders import loadPointListFromFile
from softrobots.actuators import ..autolink::SoftRobots::PullingCable
class FingerController(Sofa.Core.Controller):
def __init__(self, *args, **kwargs):
Sofa.Core.Controller.__init__(self,args,kwargs)
self.cable = args[0]
self.name = "FingerController"
def onKeypressedEvent(self, e):
displacement = self.cable.CableConstraint.value[0]
if e["key"] == Key.plus:
displacement += 1.
elif e["key"] == Key.minus:
displacement -= 1.
if displacement < 0:
displacement = 0
self.cable.CableConstraint.value = [displacement]
def Finger(parentNode=None, name="Finger",
rotation=[0.0, 0.0, 0.0], translation=[0.0, 0.0, 0.0],
fixingBox=[-10.0,-10.0,-10.0,10.0,10.0,10.0], pullPointLocation=[0.0,0.0,0.0]):
finger = ..autolink::STLIB::Node(parentNode, name)
eobject = ..autolink::STLIB::ElasticMaterialObject(finger,
volumeMeshFileName="data/mesh/finger.vtk",
poissonRatio=0.3,
youngModulus=100,
totalMass=0.5,
surfaceColor=[0.0, 0.8, 0.7],
surfaceMeshFileName="data/mesh/finger.stl",
rotation=rotation,
translation=translation)
..autolink::STLIB::FixedBox(eobject, atPositions=fixingBox, doVisualization=True)
cable=..autolink::SoftRobots::PullingCable(eobject,
"PullingCable",
pullPointLocation=pullPointLocation,
rotation=rotation,
translation=translation,
cableGeometry=loadPointListFromFile("data/mesh/cable.json"));
FingerController(eobject, cable)
..autolink::STLIB::CollisionMesh(eobject, name="CollisionMesh",
surfaceMeshFileName="data/mesh/finger.stl",
rotation=rotation, translation=translation,
collisionGroup=[1, 2])
..autolink::STLIB::CollisionMesh(eobject, name="CollisionMeshAuto1",
surfaceMeshFileName="data/mesh/fingerCollision_part1.stl",
rotation=rotation, translation=translation,
collisionGroup=[1])
..autolink::STLIB::CollisionMesh(eobject, name="CollisionMeshAuto2",
surfaceMeshFileName="data/mesh/fingerCollision_part2.stl",
rotation=rotation, translation=translation,
collisionGroup=[2])
return finger
```
The file `gripper.py` should contain:
```python
from grippercontroller import GripperController
from finger import Finger
def Gripper(parentNode=None):
selfNode = parentNode.createChild("Gripper")
f1 = Finger(selfNode, "Finger1",
rotation=[0, 0, 105],
translation=[20.0,0.0, 0.0],
fixingBox=[-20, -10, 0, 20, 10, 15],
pullPointLocation=[3, 10.5, 3])
f2 = Finger(selfNode, "Finger2",
rotation=[180, 0, 65],
translation=[-10.0,0.0, -4.0],
fixingBox=[-20, -10, -30, 20, 10, 0],
pullPointLocation=[3, 10.5, -7])
f3 = Finger(selfNode, "Finger3",
rotation=[180, 0, 65],
translation=[-10.0,0.0, 34.0],
fixingBox=[-20, -10, 0, 20, 10, 50],
pullPointLocation=[3, 10.5, 31.5])
GripperController(selfNode, [f1,f2,f3])
return selfNode
```
### Comments (things to present or do in this step)
- In `gripper.py`, show how to add one finger at default position and location. Do not forget that you can start Sofa
with the -i option for an automatic reload of the gripper.py each time the source file is changed.
- In `gripper.py`, duplicate the Finger object and change the location, orientation and fixing point so that it match
the desired robot geometry of the gripper. Do not forget that you can start Sofa with the -i option for an automatic
reload of the gripper.py each time the source file is changed.
- Attach the GripperController to the Gripper object. So that when you press CTRL+UP/DOWN/LEFT/RIGHT the gripper is moving.
## Step 6: Putting everything in a single simulation.
Open the `cablegripper.py` and add the Cube, the Floor and the Gripper which should result in something similar to:
```python
from stlib3.scene import ..autolink::STLIB::MainHeader, ..autolink::STLIB::ContactHeader
from stlib3.physics.rigid import ..autolink::STLIB::Floor, ..autolink::STLIB::Cube
from gripper import Gripper
def createScene(rootNode):
"""This is my first scene"""
..autolink::STLIB::MainHeader(rootNode, gravity=[0.0, -981.0, 0.0], plugins=["SoftRobots"])
..autolink::STLIB::ContactHeader(rootNode, alarmDistance=4, contactDistance=3, frictionCoef=0.08)
Gripper(rootNode)
..autolink::STLIB::Floor(rootNode, name="Floor",
color=[1.0,0.0,0.0,1.0],
translation=[0.0,-160.0,0.0],
isAStaticObject=True)
..autolink::STLIB::Cube(rootNode, name="Cube",
uniformScale=20.0,
color=[1.0,1.0,0.0,1.0],
totalMass=0.03,
volume=20,
inertiaMatrix=[1000.0,0.0,0.0,0.0,1000.0,0.0,0.0,0.0,1000.0],
translation=[0.0,-130.0,10.0])
return rootNode
```
## Conclusion
Congratulation, you have completed this tutorial. You are strongly encouraged to pursue with the other tutorial and
read the thematical documentations.
If you have any comments or suggestions, please submit issues on our ..autolink::github/SoftRobots page.