FreeCAD as pre-post processor for MBDyn

About the development of the FEM module/workbench.

Moderator: bernd

josegegas
Posts: 241
Joined: Sat Feb 11, 2017 12:54 am
Location: New Zealand

Re: FreeCAD as pre-post processor for MBDyn

Post by josegegas »

JamesLiu wrote: Fri Nov 26, 2021 7:01 am
josegegas wrote: Sun Aug 08, 2021 2:00 pm Hi

So this has been probably the most challanging part of this project, at least so far. To simulate a CAM-follower such as in this example:

https://www.sky-engin.jp/en/MBDynExampl ... /ex13.html

The thing is that one needs a scalar function containig the shape of the cam. In FreeCAD of course the shape of the cam is determined by the CAD of the cam, so the challanging part was to convert the CAD shape of the cam into a scalar function. It took more than a month but finally got it. The algrithm will take the outer edges of the cam (or any other set of edges from a part), and generate a scalar function that follows the shape enclosed by the edges. This function can then be used for any purpose, in this case moving the followers:

The hole thing happens in the "AddScalarFunction" method of the "dynamics" class...
Is there any tutorial or instruction on this subject? I am trying to simulate gear transmission using your WB.
Hi.

I have not uploaded any tutorial on how to convert shapes into scalar functions yet. You may want to have a look at the reduction gear example:

https://www.sky-engin.jp/en/MBDynExampl ... /ex11.html

There is also an example in the gitlab of the project...
JamesLiu
Posts: 26
Joined: Sat Apr 28, 2018 6:23 am

Re: FreeCAD as pre-post processor for MBDyn

Post by JamesLiu »

The double pendulum with gears is very interesting! May I have the model for reference?

phpBB [video]
josegegas
Posts: 241
Joined: Sat Feb 11, 2017 12:54 am
Location: New Zealand

Re: FreeCAD as pre-post processor for MBDyn

Post by josegegas »

JamesLiu wrote: Thu Dec 02, 2021 10:45 am The double pendulum with gears is very interesting! May I have the model for reference?

phpBB [video]

Hi. Sure. I´ve been working the past few months on a new version of the workbench, fixing many problems the one in Gitlab has. Mainly the new version makes use of FreeCAD units and quantities, while the previous one treats numbers simply as floats... I will create a new repository and upload the new version, along with this and other examples, soon...
josegegas
Posts: 241
Joined: Sat Feb 11, 2017 12:54 am
Location: New Zealand

Re: FreeCAD as pre-post processor for MBDyn

Post by josegegas »

Hi.

I´m having some trouble with making joints parametric. Let me explain what I want to achieve. So far the workbench allows the user model pretty much any mechanism using rigid bodies. For this, I am implementing the joints MBDyn has to offer as Scripted objects for FreeCAD. This is the class to create objects for a "revolute pin" joint.

Code: Select all

import FreeCAD,FreeCADGui
import Draft
from sympy import Point3D, Line3D

class Revolutepin:
    def __init__(self, obj, label, node, reference1, reference2):       
             
        #Get the center of mass or the center of the two references
        try:
            x2 = FreeCAD.Units.Quantity(reference1.Curve.Center[0],FreeCAD.Units.Unit('mm'))  
            y2 = FreeCAD.Units.Quantity(reference1.Curve.Center[1],FreeCAD.Units.Unit('mm'))  
            z2 = FreeCAD.Units.Quantity(reference1.Curve.Center[2],FreeCAD.Units.Unit('mm'))  
        except:    
            x2 = FreeCAD.Units.Quantity(reference1.CenterOfMass[0],FreeCAD.Units.Unit('mm'))  
            y2 = FreeCAD.Units.Quantity(reference1.CenterOfMass[1],FreeCAD.Units.Unit('mm'))  
            z2 = FreeCAD.Units.Quantity(reference1.CenterOfMass[2],FreeCAD.Units.Unit('mm')) 
       
        try:
            x3 = FreeCAD.Units.Quantity(reference2.Curve.Center[0],FreeCAD.Units.Unit('mm'))  
            y3 = FreeCAD.Units.Quantity(reference2.Curve.Center[1],FreeCAD.Units.Unit('mm'))  
            z3 = FreeCAD.Units.Quantity(reference2.Curve.Center[2],FreeCAD.Units.Unit('mm')) 
        except:
            x3 = FreeCAD.Units.Quantity(reference2.CenterOfMass[0],FreeCAD.Units.Unit('mm'))  
            y3 = FreeCAD.Units.Quantity(reference2.CenterOfMass[1],FreeCAD.Units.Unit('mm'))  
            z3 = FreeCAD.Units.Quantity(reference2.CenterOfMass[2],FreeCAD.Units.Unit('mm')) 
        

        #Calculate the joint´s absolute position:
        x = (x2+x3)/2
        y = (y2+y3)/2
        z = (z2+z3)/2
            
        #Calculate the joint possition relative to it's node (relative offset):        
        x1 = x-node.absolute_position_X
        y1 = y-node.absolute_position_Y
        z1 = z-node.absolute_position_Z
                
        obj.addExtension("App::GroupExtensionPython") 
        
        #Create scripted object:
        obj.addProperty("App::PropertyString","label","Revolute pin","label",1).label = label
        obj.addProperty("App::PropertyString","node_label","Revolute pin","node_label",1).node_label = node.label
        obj.addProperty("App::PropertyString","joint","Revolute pin","joint",1).joint = 'revolute pin'
        obj.addProperty("App::PropertyString","plugin_variables","Revolute pin","plugin_variables",1).plugin_variables = "none"
        
        #pin possition relative to it's node:
        obj.addProperty("App::PropertyDistance","relative_offset_X","Relative offset","relative_offset_X",1).relative_offset_X = x1
        obj.addProperty("App::PropertyDistance","relative_offset_Y","Relative offset","relative_offset_Y",1).relative_offset_Y = y1
        obj.addProperty("App::PropertyDistance","relative_offset_Z","Relative offset","relative_offset_Z",1).relative_offset_Z = z1
        
        #Absolute pin position:                
        obj.addProperty("App::PropertyDistance","absolute_pin_position_X","Absolute pin position","absolute_pin_position_X",1).absolute_pin_position_X = x
        obj.addProperty("App::PropertyDistance","absolute_pin_position_Y","Absolute pin position","absolute_pin_position_Y",1).absolute_pin_position_Y = y
        obj.addProperty("App::PropertyDistance","absolute_pin_position_Z","Absolute pin position","absolute_pin_position_Z",1).absolute_pin_position_Z = z                        
        
        #Animation parameters:
        obj.addProperty("App::PropertyEnumeration","animate","Animation","animate")
        obj.animate=['false','true']

        obj.addProperty("App::PropertyEnumeration","frame","Animation","frame")
        obj.frame=['global','local']        
        
        obj.addProperty("App::PropertyFloat","force vector multiplier","Animation","force vector multiplier").force_vector_multiplier = 1.0
        
        obj.Proxy = self
        
        #Add joint´s rotation axis. This axis determines the "absolute_pin_orientation_matrix":
        p1 = FreeCAD.Vector(x2, y2, z2)
        p2 = FreeCAD.Vector(x3, y3, z3)
        #Create the rotation axis:
        l = Draft.makeLine(p1, p2)
        l.Label = 'z: joint: '+ label          
        l.ViewObject.LineColor = (0.00,0.00,1.00)
        l.ViewObject.PointColor = (0.00,0.00,1.00)
        l.ViewObject.DrawStyle = u"Dashed"   
        l.ViewObject.LineWidth = 1.00
        l.ViewObject.PointSize = 1.00
        
             
        #Add the vector to visualize reaction forces
        Llength = FreeCAD.Units.Quantity(FreeCAD.ActiveDocument.getObjectsByLabel("X")[0].End[0]/4,FreeCAD.Units.Unit('mm'))
        p1 = FreeCAD.Vector(x, y, z)
        p2 = FreeCAD.Vector(x+Llength, y+Llength, z+Llength)    
        d = Draft.makeLine(p1, p2)
        d.ViewObject.LineColor = (1.00,0.00,0.00)
        d.ViewObject.PointColor = (1.00,0.00,0.00)  
        d.ViewObject.LineWidth = 1.00
        d.ViewObject.PointSize = 1.00
        d.ViewObject.EndArrow = True
        d.ViewObject.ArrowType = u"Arrow"
        d.ViewObject.ArrowSize = str(Llength/75)#+' mm'
        d.Label = "jf: "+ label         

        #absolute orientation:            
        obj.addProperty("App::PropertyString","absolute_pin_orientation_matrix","Orientation","absolute_pin_orientation_matrix",1).absolute_pin_orientation_matrix = ""#"3, " + str(l1.direction[0]) + ", "+ str(l1.direction[1]) + ", " + str(l1.direction[2]) + ", " +"2, guess"                     
        
        #relative orientation:   
        obj.addProperty("App::PropertyString","relative_orientation_matrix","Orientation","relative_orientation_matrix",1).relative_orientation_matrix = ""#"3, " + str(l1.direction[0]) +", "+ str(l1.direction[1]) + ", " + str(l1.direction[2]) + ", " +"2, guess"                     


    def execute(self, fp):
        #precission = int(FreeCAD.ActiveDocument.getObjectsByLabel('MBDyn')[0].precision)#Max number of decimal places        
        ##############################################################################Calculate the new absolute orientation:            
        ZZ = FreeCAD.ActiveDocument.getObjectsByLabel("z: joint: "+fp.label)[0]#get the joint´s rotation axis
        
        #Two 3D points that define the joint´s line:
        p1, p2 = Point3D(ZZ.Start[0], ZZ.Start[1], ZZ.Start[2]), Point3D(ZZ.End[0], ZZ.End[1], ZZ.End[2]) 
        l1 = Line3D(p1, p2)#Line that defines the joint
        
        magnitude = (l1.direction[0]**2+l1.direction[1]**2+l1.direction[2]**2)**0.5#Calculate the vector´s magnitude
        
        #generate the orientation matrix:
        fp.absolute_pin_orientation_matrix = "3, "+ str(l1.direction[0]/magnitude) +", "+ str(l1.direction[1]/magnitude) + ", " + str(l1.direction[2]/magnitude) + ", " +"2, guess"                
                        
        ##############################################################################Recalculate the offset, in case the node was moved: 
        #get and update the absolute pin position:
        x = FreeCAD.Units.Quantity((ZZ.Start[0] + ZZ.End[0])/2,FreeCAD.Units.Unit('mm')) 
        y = FreeCAD.Units.Quantity((ZZ.Start[1] + ZZ.End[1])/2,FreeCAD.Units.Unit('mm')) 
        z = FreeCAD.Units.Quantity((ZZ.Start[2] + ZZ.End[2])/2,FreeCAD.Units.Unit('mm')) 
        
        fp.absolute_pin_position_X = x
        fp.absolute_pin_position_Y = y
        fp.absolute_pin_position_Z = z
        
        #get the node:
        node = FreeCAD.ActiveDocument.getObjectsByLabel("structural: "+fp.node_label)[0]
        
        #Re-calculate the joint possition relative to it's node (relative offset)        
        x1 = x - node.absolute_position_X
        y1 = y - node.absolute_position_Y
        z1 = z - node.absolute_position_Z

        #Update the offset:
        fp.relative_offset_X = x1
        fp.relative_offset_Y = y1
        fp.relative_offset_Z = z1           
        
        ##############################################################################Calculate the new relative orientation:            
        zz = FreeCAD.ActiveDocument.getObjectsByLabel("z: joint: "+fp.label)[0]
        p11, p22 = Point3D(zz.Start[0], zz.Start[1], zz.Start[2]), Point3D(zz.End[0], zz.End[1], zz.End[2]) 
        l11 = Line3D(p11, p22)
        zzmagnitude1 = (l11.direction[0]**2+l11.direction[1]**2+l11.direction[2]**2)**0.5
                
        #generate the relative orientation matrix:
        #fp.relative_orientation_matrix = "3, "+ str(round(l1.direction[0]/zzmagnitude,precission)) +", "+ str(round(l1.direction[1]/zzmagnitude,precission)) + ", " + str(round(l1.direction[2]/zzmagnitude,precission)) + ", " +"2, "+ str(round(l2.direction[0]/yymagnitude,precission)) +", "+ str(round(l2.direction[1]/yymagnitude,precission)) + ", " + str(round(l2.direction[2]/yymagnitude,precission))                
        fp.relative_orientation_matrix = "3, "+ str(l11.direction[0]/zzmagnitude1) +", "+ str(l11.direction[1]/zzmagnitude1) + ", " + str(l11.direction[2]/zzmagnitude1) + ", " +"2, guess"#+ str(round(l2.direction[0]/yymagnitude,precission)) +", "+ str(round(l2.direction[1]/yymagnitude,precission)) + ", " + str(round(l2.direction[2]/yymagnitude,precission))                
        
        FreeCAD.Console.PrintMessage("REVOLUTE PIN JOINT: " +fp.label+" successful recomputation...\n")
The main idea is quite simple. The constructor gets two references (reference1 and reference2), which are shapes the user selects in the GUI. The line passing through the center of mass of these two references determines the joint´s position and orientation. The position of the joint is the center point of this line, and the orientation of the joint is the same as the orientation of the line. (This is how other programs, such as Adams and Ansys motion, define joints too...)

So far it works perfectly, but the problem is that it i not parametric, so that if the CAD model is changed, the joint does not change accordingly, and the user is forced to delete and create the joint again. I am working now on making the joints parametric, and so I need to store, as a property of the scripted object, the two shapes provided as references. I have tried:

Code: Select all

        obj.addProperty("Part::PropertyPartShape","reference_1","References","reference_1").reference_1 = reference1
        obj.addProperty("Part::PropertyPartShape","reference_2","References","reference_2").reference_2 = reference2


But the thing is that this seems to store a copy of the reference shape, and not a link to the reference. So that this does not help me to make the joint parametric.

I have tried using App::PropertyLinkSubList, as someone suggested, but I do not quite understand how this works and I have not been able to find any complete example either...

Any ideas will be very welcome...
T-Garnier
Posts: 18
Joined: Sat Jun 27, 2020 5:30 am

Re: FreeCAD as pre-post processor for MBDyn

Post by T-Garnier »

About the App::PropertyLinkSubList, did you check those links:
https://forum.freecadweb.org/viewtopic.php?t=37288
https://wiki.freecadweb.org/LinkSubList
User avatar
Pauvres_honteux
Posts: 728
Joined: Sun Feb 16, 2014 12:05 am
Location: Far side of the moon

Re: FreeCAD as pre-post processor for MBDyn

Post by Pauvres_honteux »

josegegas wrote: Thu Dec 02, 2021 2:09 pm ... a new version of the workbench ...
Any chance some future version will work with files, as in the gears in your youtube video would be separate files? In other words, them files move with respect to each other.
josegegas
Posts: 241
Joined: Sat Feb 11, 2017 12:54 am
Location: New Zealand

Re: FreeCAD as pre-post processor for MBDyn

Post by josegegas »

Pauvres_honteux wrote: Fri Dec 03, 2021 6:49 am
josegegas wrote: Thu Dec 02, 2021 2:09 pm ... a new version of the workbench ...
Any chance some future version will work with files, as in the gears in your youtube video would be separate files? In other words, them files move with respect to each other.
The new version works with links to parts, so that the independent parts are in separate files. Is this what you mean?
rock.vice
Posts: 22
Joined: Sat Jan 02, 2021 6:12 pm

Re: FreeCAD as pre-post processor for MBDyn

Post by rock.vice »

josegegas wrote: Sat Dec 04, 2021 3:59 am
The new version works with links to parts, so that the independent parts are in separate files. Is this what you mean?
Hi Jose,
nice to hear that you are further developing this powerful workbench.
Can you evaluate the possibility to put the items/functions/tools, that you make available in different menus, in a single drop down menu as it is for many other workbenches? In my opinion this would help to have a cleaner and more compact UI, separating clearly the features of the workbench from the features of the main program.

Please take this just as a suggestion, I really appreciate the work you are doing. In case you consider the current UI much suitable for the workflow you have in mind just discard my request

Thank you for your effort,
Rock.V
User avatar
Pauvres_honteux
Posts: 728
Joined: Sun Feb 16, 2014 12:05 am
Location: Far side of the moon

Re: FreeCAD as pre-post processor for MBDyn

Post by Pauvres_honteux »

josegegas wrote: Sat Dec 04, 2021 3:59 am The new version works with links to parts, so that the independent parts are in separate files. Is this what you mean?
Hmm, let's see if we are talking about the same things here.

What i was asking for was, moving the whole file with all its content with repect to other files with all their content.
Is this what you are talking about as well?

Or do you mean extracting/copying the solids out of the files and placing/pasting the solids in a new file together with other pasted solids? Then simulating/moving these solids with respect to each other?
josegegas
Posts: 241
Joined: Sat Feb 11, 2017 12:54 am
Location: New Zealand

Re: FreeCAD as pre-post processor for MBDyn

Post by josegegas »

Pauvres_honteux wrote: Sat Dec 04, 2021 10:51 am
josegegas wrote: Sat Dec 04, 2021 3:59 am The new version works with links to parts, so that the independent parts are in separate files. Is this what you mean?
Hmm, let's see if we are talking about the same things here.

What i was asking for was, moving the whole file with all its content with repect to other files with all their content.
Is this what you are talking about as well?

Or do you mean extracting/copying the solids out of the files and placing/pasting the solids in a new file together with other pasted solids? Then simulating/moving these solids with respect to each other?
This is what I mean:

https://www.youtube.com/watch?v=pcd0LlX ... iv54AaABAg
Post Reply