CATIA V5 Automation

Measuring Mass and Inertia

Advertisements

You have probably used the Inertia measure function in CATIA to get mass and inertia measures but did you know that you can automate those measurements as well?  The inertia object that you may use in your programs works just like the interactive command and provides all the same capabilities you are used to.  In this article, I will show how to program with the inertia object and as usual I will provide sample code and some handy reusable functions.

What is not covered in this article

Before we get started, I want to point out that this article is meant to show you how to program mass and inertia measurements.  I will not explain what inertia is or what the various values mean.  There are plenty of engineering resources out there to do that.  Also, the inertia measure can give strange or even incorrect results depending on how you use it.  However, these behaviors are exactly the same when you program the measures as when you perform the interactively so be sure to take some time and understand how the tool works.  Below I quickly listed a few of the things that can affect the result (this is not a complete list):

A quick caution about the future availability of some API’s

Some of the techniques that I will show in this article have special notes in the help documentation stating that they will be deprecated in a future release.  However, the documentation has said that for a long time.  For now, I confirmed that they work in V5R18 and V5R20 but you should still take this into consideration because it could potentially render your program useless in the future.  Specifically, the API that I am referring to is the Inertias object.  This object is used to get inertia information from specific objects within a CATPart as opposed to measuring the entire CATPart.

What information does the Inertia object provide?

The values you are able to measure are listed below along with their units.

Property Units
Mass kg
Density kg/m3 (solid/volume)  kg/m2 (surface)
Position of the center of gravity m
Inertia matrix kgm2
Principal axes kgm2
Principal moments kgm2

Measuring a part or product as a whole

CATIA V5 allows you to measure the inertia of a single part or a product.  In the case of a product, a single set of values are returned that reflect all of the child parts at all levels below that product in the assembly.  This means there is no need to individually measure all of the child parts.

Here is a handy reusable function that will retrieve an Inertia object for a product.


Function GetProductInertia(ByRef iProd As Product) As Inertia

  'If successful, this function will return an inertia object
  'Otherwise, Nothing is returned (you should check the return value)

  Dim objInertia As Inertia

  On Error Resume Next

  Set objInertia = iProd.ReferenceProduct.GetTechnologicalObject("Inertia")
  If Err.Number = 0 Then
    Set GetProductInertia = objInertia
  Else
    Set GetProductInertia = Nothing
End If

End Function


Now lets look at how to use this function in an assembly.  In the example below, you should select any product or part instance in the assembly then run this code.


Sub Test_GetProductInertia_AssyExample()

  'Select a product first, then run this sub.

  Dim objProd As Product

  Set objProd = CATIA.ActiveDocument.Selection.Item2(1).Value
  Set objInertia = GetProductInertia(objProd)
  If Not (objInertia Is Nothing) Then
    'Retrieve the mass just to show it worked
    MsgBox objInertia.Mass
  Else
    MsgBox "The Inertia could not be retrieved!"
  End If

End Sub

You can actually use the same function when a part is open in it’s own window.  You are probably thinking that is no product to reference when the part is open in it’s own window!  Not true!  Every part always has a reference product associated with it that you just don’t see when it is open in its own window. That reference product is used to create an instance when that part is inserted into a product.  So all we need to do is access it and pass it to our handy function.


Sub Test_GetProductInertia_PartInOwnWindowExample()

  Set objProd = CATIA.ActiveDocument.Product
  Set objInertia = GetProductInertia(objProd)
  If Not (objInertia Is Nothing) Then
    'Retrieve the mass just to show it worked
    MsgBox objInertia.Mass
  Else
    MsgBox "The Inertia could not be retrieved!"
  End If

End Sub

Measuring geometry inside a part

Before covering this technique, I just want to again mention that the ability to retrieve an Inertia object on a specific item within a part is made possible by the Inertias object.  This currently works fine through V5R20 but the help documentation states that it is going to be deprecated in a future release so beware.

The help documentation really does not give you any indication of what types of objects within a part can be measured.  Because of this, the common belief out there is that you just can’t measure the inertia of specific geometry inside a part.  Like many, I was stumped as well until I did a project where I needed this functionality so I did a LOT of trial and error and figured out how it works.

What I found is that you can only measure the inertia of a body or a geometrical set.  If you pass any other kind of geometry to create an Inertia object, it will fail.  Measuring the inertia of a body makes perfect sense because the body really encompasses the complete shape of that solid.  However, measuring the inertia of a geometrical set probably doesn’t make a whole lot of sense unless that set only contains one surface.  Sometimes that may be the case but what kind of work around can we create to measure a specific surface?  I developed a solution for that.  I have to admit it is not very elegant, but it works like a charm.  Below, I will tackle each of these cases individually.

Measuring the inertia of a body

This case is very straightforward and easy.  As always, I like to develop reusable functions so I built one to retrieve the inertia of a body as shown below.


Function GetBodyInertia(ByRef iPart As Part, ByRef iBody As Body) As Inertia

  'If successful, this function will return an inertia object

  Dim objSPAWorkbench As Workbench
  Dim objInertia As Inertia

  On Error Resume Next

  Set objSPAWorkbench = iPart.Parent.GetWorkbench("SPAWorkbench")
  Set objInertia = objSPAWorkbench.Inertias.Add(iBody)
  If Err.Number = 0 Then
    Set GetBodyInertia = objInertia
  Else
    Set GetBodyInertia = Nothing
  End If

End Function

Now let’s look at an example use case.  In this example, I assume a part is open in it’s own window and the main PartBody contains some solid geometry.


Sub Test_GetBodyInertia()

  'Assume a part is open in it's own window
  'We will get the inertia of the main PartBody

  Dim objPart As Part
  Dim objBody As Body
  Dim objInertia As Inertia

  Set objPart = CATIA.ActiveDocument.Part
  Set objBody = objPart.MainBody
  Set objInertia = GetBodyInertia(objPart, objBody)

  If Not (objInertia Is Nothing) Then
    'Retrieve the mass just to show it worked
    MsgBox objInertia.Mass
  Else
    MsgBox "The Inertia could not be retrieved!"
  End If

End Sub

Measuring the inertia of a geometrical set

This case is almost identical to the case for a body listed above.  Again, I have developed a reusable function as shown below.


Function GetGeoSetInertia(ByRef iPart As Part, _
                           ByRef iGeoSet As HybridBody) As Inertia

  'If successful, this function will return an inertia object

  Dim objSPAWorkbench As Workbench
  Dim objInertia As Inertia

  On Error Resume Next

  Set objSPAWorkbench = iPart.Parent.GetWorkbench("SPAWorkbench")
  Set objInertia = objSPAWorkbench.Inertias.Add(iGeoSet)

  If Err.Number = 0 Then
    Set GetGeoSetInertia = objInertia
  Else
    Set GetGeoSetInertia = Nothing
  End If

End Function

Now let’s look at an example use case.  In this example, I assume a part is open in it’s own window and I will retrieve the inertia of the first geometrical set (make sure it has some surface data in it).


Sub Test_GetGeoSetInertia()

  'Assume a part is open in it's own window
  'We will get the inertia of the first geometrical set in the part

  Dim objPart As Part
  Dim objGeoSet As HybridBody
  Dim objInertia As Inertia

  Set objPart = CATIA.ActiveDocument.Part
  Set objGeoSet = objPart.HybridBodies.Item(1)

  Set objInertia = GetGeoSetInertia(objPart, objGeoSet)
  If Not (objInertia Is Nothing) Then
    'Retrieve the mass just to show it worked
    MsgBox objInertia.Mass
  Else
    MsgBox "The Inertia could not be retrieved!"
  End If

End Sub

Measuring the inertia of a specific surface

As I mentioned earlier, you can only measure the inertia of a body or geometrical set so I had to improvise a bit and create a workaround here.  This certainly is not beautiful but it works quite well.  Essentially, you just pass the surface to be measured and I create a temporary geometrical set in the part then create a join of that surface in that temporary geometrical set.  This way, there is only one surface in the set and the calculations will be correct (as always, you should confirm/set the material density being used as well – see discussion later in this article).


Function GetSurfInertia(ByRef iPart As Part, ByRef iSurf As HybridShape, _
                          ByRef oGeoSet As HybridBody) As Inertia

  'If successful, this function will return an inertia object
  'iSurf must be a surface
  'oGeoSet is the temp geo set that is created by this function (returned thru the variable passed in)
  'This geo set cannot be deleted until you are done with the inertia object or else calls to the 
  'Inertia object will fail.  You should delete the temp geo set at that point

  Dim objRef As Reference
  Dim intType As Integer
  Dim objHB As HybridBody
  Dim objJoin As HybridShapeAssemble
  Dim objSPAWorkbench As Workbench
  Dim objInertia As Inertia

  'Make sure some geometry was passed in
  If Not (iSurf Is Nothing) Then

    'Ensure the HybridShape is in fact a surface
    Set objRef = iPart.CreateReferenceFromObject(iSurf)
    intType = iPart.HybridShapeFactory.GetGeometricalFeatureType(objRef)

    If intType = 5 Then  '5=surface

      'Create a new geo set in the part and a join of the surf
      Set objHB = iPart.HybridBodies.Add
      objHB.Name = "Temp_ForInertiaMeasure"

      'Create a join of the surface
      Set objJoin = iPart.HybridShapeFactory.AddNewJoin(objRef, objRef)
      objJoin.RemoveElement 2
      iPart.UpdateObject objJoin

      'Append the join to the temp geo set
      objHB.AppendHybridShape objJoin

      'Create an inertia object from the temp geo set
      On Error Resume Next
      Set objSPAWorkbench = iPart.Parent.GetWorkbench("SPAWorkbench")
      Set objInertia = objSPAWorkbench.Inertias.Add(objHB)
      If Err.Number = 0 Then

        'Return the Inertia object
        Set GetSurfInertia = objInertia

        'Return the geo set that was created
        Set oGeoSet = objHB

        Exit Function

      End If

    End If

  End If

  'If got to here it failed so just return nothing
  Set GetSurfInertia = Nothing

End Function

Now let’s look at an example use case.  In this example, I assume a part is open in it’s own window and I simply search for all surfaces in the part and retrieve an inertia object for the first one found.


Sub Test_GetSurfInertia()

  'Assume a part is open in it's own window
  'We will get the inertia of the first surface found in the first geometrical set

  Dim objSurf As HybridShape
  Dim objPart As Part
  Dim objGeoSet As HybridBody
  Dim objInertia As Inertia

  'Get the surface then retrieve it's inertia 
  Set objSurf = objSel.Item2(1).Value
  Set objPart = CATIA.ActiveDocument.Part
  Set objInertia = GetSurfInertia(objPart, objSurf, objGeoSet)

  'If an Inertia object was returned, get the mass
  If Not (objInertia Is Nothing) Then
    'Retrieve the mass just to show it worked
    MsgBox objInertia.Mass
  Else
    MsgBox "The Inertia could not be retrieved!"
  End If

  'Make sure to delete the temp geo set once you
  'are done making all calls to the Inertia object
  objPart.HybridShapeFactory.DeleteObjectForDatum _
  objPart.CreateReferenceFromObject(objGeoSet)

End Sub

Other comments

Advertisements