Home › Forum › SOFA › Using SOFA › [SOLVED] Harmonic excitation with constantForceField (Python Controller)
Tagged: 64_bits, SOFA_1806, Windows_10
- This topic has 4 replies, 4 voices, and was last updated 4 years, 1 month ago by
Hugo.
-
AuthorPosts
-
4 February 2019 at 09:42 #12981
Nassim
BlockedHi everyone,
For a project, I need to create an harmonic excitation to make a cylinder jump.
For that, I have created a python controller which creates a ConstantForcefield on the cylinder in the axis +Y, and then I tried to change the value of it in an harmonic form thanks to a cos function.
I have created a loop from 0 to 90°, so that my cos can evolve from 1 to 0.
However, in the scene, we can’t see the evolution of the force, we directly have the final value of the force=0, so my cylinder doesn’t jump.
Here is the controller:import sys import Sofa import math class KeyboardControl(Sofa.PythonScriptController): def initGraph(self,node): print 'initGraph called (python side)' self.CFF=node.createObject('ConstantForceField', name="CFF", force="0 0 0 0 0 0" ) return 0 def onKeyPressed(self,k): if k=="Z" : for i in range(0,90): force = self.CFF.findData('force').value force[0][1] =math.cos((i*math.pi)/180) self.CFF.findData('force').value = force print("oscillator") return 0
Do you know how can I do to have my force evolving in the time in an harmonic form and especially, see the effect in real time on the scene thanks to my controller?
Thank you really much for your help.
Best regards,
Nassim4 February 2019 at 17:21 #12983Hugo
KeymasterHey @nassim,
I guess the force that you expect to apply is supposed to be change progressively while the simulation is running. Right ? If so, the force must depend on the current time.
The function onKeyPressed is called only when a key is pressed. But you could use instead the function onBeginAnimationStep which is called at each beginning of simulation step.
About the time, you can access this information in the root node:
rootNode.findData('time').value
I hope this helps
BestHugo
6 February 2019 at 16:08 #13005Damien Marchal
BlockedHi Nassim,
For what you want to do I can see two approach.
The first one is to implement your own controller to manipulate the data field at each animation step.import Sofa import math class MyController(Sofa.PythonScriptController): def __init__(self, node, dofs): '''With SofaPython it is mandatory to pass at least one argument that is the node. not doing that will crash Sofa ''' self.dofs = dofs self.currentTime = 0.0 self.scaleFactor = 10.0 def onBeginAnimationStep(self, dt): '''This method is called automatically by Sofa at each timestep''' self.currentTime += dt force = self.dofs.findData('position').value force[0][0] = math.cos((self.currentTime*self.scaleFactor*math.pi)/180) force[0][1] = math.sin((self.currentTime*self.scaleFactor*math.pi)/180) self.dofs.findData('position').value = force def createScene(rootNode): '''Move an object in real-time by reading new values from a python file''' v = rootNode.createObject("MechanicalObject", name="dofs", position=[0.0,0.0,0.0]) v.showObject = True v.showObjectScale = 10.0 MyController(rootNode, v)
The other rely on the STLIB which feature an animation package, it would look like that:
# coding: utf-8 # splib is available here: https://github.com/SofaDefrost/STLIB import splib import math ## This function is called by the animation manager at each timestep, the factor ## is updated to indicate how much has progress the animation. ## The factor is between [0, 1] 0 is the begin of the animation, 1 is the end. def harmonicAnimation(target, factor, scaleFactor): t = [ math.cos((factor*scaleFactor*math.pi)/180), 0, math.sin((factor*scaleFactor*math.pi)/180)] print("I'm updating the position using: ", factor, " new pos is", t) target.position = t def createScene(rootNode): from splib.animation import animate, AnimationManager ## This will create a single AnimationManager python script controller that will animate all the ## animation on the scene. AnimationManager(rootNode) # The object t = rootNode.createObject("MechanicalObject", position=[0,0,0]) t.showObject=True t.showObjectScale=10 # This fire up an animation, # The movement is computed using the "myanimate" function # The target of the animation is the 't' object # This animation will have 0.5 second duration (simulation time) # 'ping-pong' means that the animation will repeat to-from. animate(harmonicAnimation, {"target" : t, "scaleFactor" : 1.0}, duration=1.0, mode="pingpong" )
Tell us if you succeed.
Damien.19 July 2020 at 01:19 #16902Pasquale94
BlockedHello Everyone.
I know the topic is old ,but I was searching a solution to impose a sinusoidal force field to my project too, for this reason I read this topic ahah.
Anyway, I find the solution that can solve your issue @Nasim, I wrote the controller in this way:
import sys import Sofa import math class controller(Sofa.PythonScriptController): def initGraph(self,node): self.node = node self.body = self.node.getChild('ElasticBody') self.dofs = self.body.getObject('dofs') self.CFF = self.body.createObject('ConstantForceField', name="CFF" ,indices="14", force=[0,0,0]) self.currentTime = 0.0 self.scaleFactor = 1000.0 return 0 def onBeginAnimationStep(self, dt): self.currentTime += dt if (self.currentTime > 0): self.CFF.findData('force').value = [0,10000000*math.sin((self.currentTime*self.scaleFactor*math.pi)/180),0]
21 July 2020 at 16:59 #16918Hugo
KeymasterThanks a lot for sharing @pasquale94!
Good community move, thumbs up.Hugo
-
AuthorPosts
- You must be logged in to reply to this topic.