What's new

URDF / XACRO from Assembly

Hi folks,

Preamble: I'm into robotics, and I'm getting to the point where I want to convert my assembly to URDF/XACRO + STL to load into PyBullet. I'm aware that ROS has a means of doing so that involves Gazebo, but it's quite cumbersome for my purposes, and I don't want to set up a massive infrastructure just to use one little aspect of it. I'm also aware that SolidWorks has a function to output models to URDF, but that's extra $$$ and/or putting my designs on the cloud. It dawned on me that it should be quite easy to write an Alibre script to take care of this, and that it could save some time when it comes to including inertial info, etc...

Now my question: I started experimenting with scripting this afternoon, and made some progress. However, it appears that the API might not provide a way to easily find the parts within an assembly. I can easily grab the Assembly, but it appears that accessing a Part requires knowing the name of the Part in advance and and then passing that into a function call. Is there a way to query the Assembly to get a list of the Parts so that I can loop through them? I only just started looking at the API, but I've gone through it multiple times and can't find a function or property that would provide me with this info.

Also, if anyone has already written such a script and is willing to share it, please let me know.

Thanks,
Bruce
 
Ok, next question is, does anyone know whether or not it's currently possible to use Alibre Script to programmatically compute the physical properties of a Part (Volume, Mass, Surface Area, Center of Mass, Moments of Inertia, etc...) instead of using the Inspect->Physical Properties menu item?
 

NateLiquidGravity

Alibre Super User
Mass is an easy one to get in Alibre Script.
Part.Mass

The rest are harder and require delving into the Alibre Design API side of things - but there are a few tricks to getting into the API.
Python:
Part._Part  # gives you the API access from the part
Assembly._Assembly  # gives you the API access from the assembly
I think you need to include the dll file to get the physical properties. I just made this code and it might work but I'm not at my PC to try it.

Edit: see updated code below.
 
Last edited:
Thanks Nate, impressive that you basically did that in your head! ;) I've learned a lot so far.

I had some minor issues with the path, but was able to get past it after adding some debugging-related code. I make no claims about the elegance of the changes.
import _winreg
import sys

def getalibrepath():
try:
hKey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,'SOFTWARE\\Alibre, Inc.\\Alibre Design\\27.0.0.27038')
print("hKey is ", hKey)
result = _winreg.QueryValueEx(hKey, 'HomeDirectory')
return result[0]
except Exception as e:
print("Exception:", e)
return ''

# Debug print for the Alibre path
alibre_path = getalibrepath()
print("Alibre Path:", alibre_path)

# Append Alibre path to sys.path
adjusted_alibre_path = alibre_path + 'Program'
print("adjusted Alibre Path:", adjusted_alibre_path)
sys.path.append(adjusted_alibre_path)

try:
import clr
clr.AddReferenceToFile('AlibreX')
import AlibreX
except Exception as e:
print("Failed to import clr or AlibreX", e)

try:
Assem = CurrentAssembly()
AD_Assem = Assem._Assembly

PhyProps = AD_Assem.PhysicalProperties(AlibreX.ADAccuracySetting.AD_VERY_HIGH)

print("Mass: ", PhyProps.Mass)
print("Volume: ", PhyProps.Volume)
print("Surface Area: ", PhyProps.SurfaceArea)
pX = 0.0
pY = 0.0
pZ = 0.0
PhyProps.GetCenterOfGravity(pX, pY, pZ)
print("Center of Gravity: ", pX, pY, pZ)
pXX = 0.0
pYY = 0.0
pZZ = 0.0
pYZ = 0.0
pZX = 0.0
pXY = 0.0
print("Moments of Inertia: ", PhyProps.GetMomentsOfInertia(pXX, pYY, pZZ, pYZ, pZX, pXY))
except Exception as e:
print("Failed to compute physical properties:", e)

The gives the following error for "Center of Gravity" when pX, pY, and pZ are passed in as 0.0:

('Failed to compute physical properties:', TypeError('expected StrongBox[float], got float',))

So I tried using clr.Reference to emulate passing by reference by wrapping the values (i.e.) pX = clr.Reference[System.Double](0.0) etc.., and made it through the error, but the calls now return None:

('Alibre Path:', 'C:\\Program Files\\Alibre Design 27.0.0.27038\\')
('adjusted Alibre Path:', 'C:\\Program Files\\Alibre Design 27.0.0.27038\\Program')
('Mass: ', 362.08506994832294)
('Volume: ', 362.08506994937062)
('Surface Area: ', 1775.1605989835534)
('Center of Gravity: ', None)
('Moments of Inertia: ', None)

I've tried various ways to coerce the behavior it's looking for by trying Systems.Collections.Generic.List and System.Double, but now I'm stuck. I don't have any experience with .NET, and I haven't touched Windows for over 20 years, so I'm uncertain what to try next. Any thoughts?

Cheers,
Bruce
 

NateLiquidGravity

Alibre Super User
Yeah that was from my head but also using reference materials on my smartphone.

Unable to test I forgot to append the "Program" to the path the registry returned. I fixed that and put the function back to how it was. The function should make it work in future Alibre releases without knowing ahead of time what their version number will be - hopefully.

I also made it more difficult at the end than it needed to be - Ironpython automatically did the byref passes in these method calls and returned a list of the values. I was 50/50 on if that would work the way I had it.

I also added the other things that show in the Physical Properties tool and made it look cleaner.
See these changes in the code below - but keep in mind the results will be in Alibre Designs internal model units - not the file's units or the scripts units - so you may need to convert them to your desired units.
Python:
import _winreg
def getalibrepath():
    try:
        hKey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE,'Software\\Alibre, Inc.\\Alibre Design')
        result = _winreg.QueryValueEx(hKey, 'HomeDirectory')
        return result[0]
    except Exception, e:
        try:
            keystring = r'SOFTWARE\Alibre, Inc.\Alibre Design' + '\\' + str(Global.Root.Version).split(' ')[1].replace(',','.')
            hKey = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, keystring)
            result = _winreg.QueryValueEx(hKey, 'HomeDirectory')
            return result[0]
        except Exception, e:
            print('Failed to get HomeDirectory')
            return ''
    return ''

import sys
import os
ADPath = getalibrepath()
ADPathProgram = os.path.join(ADPath, "Program")
sys.path.append(ADPathProgram)
import clr
clr.AddReferenceToFile('AlibreX')
import AlibreX

Assem = CurrentAssembly()
AD_Assem = Assem._Assembly

PhyProps = AD_Assem.PhysicalProperties(AlibreX.ADAccuracySetting.AD_VERY_HIGH)

print('Mass:')
print(PhyProps.Mass)
print('\nVolume:')
print(PhyProps.Volume)
print('\nSurface Area:')
print(PhyProps.SurfaceArea)
print('\nCenter Of Gravity:')
print(PhyProps.GetCenterOfGravity())
print('\nMoments Of Inertia:')
print(PhyProps.GetMomentsOfInertia())
print('\nPrincipal Moments Of Inertia:')
print(PhyProps.GetPrincipalMomentsOfInertia())
print('\nPrincipal Axis1:')
print(PhyProps.GetPrincipalAxis1())
print('\nPrincipal Axis2:')
print(PhyProps.GetPrincipalAxis2())
print('\nPrincipal Axis3:')
print(PhyProps.GetPrincipalAxis3())
Extents = PhyProps.GetExtents()
print('\nExtents:')
for p in Extents:
    print(p.X, p.Y, p.Z)
print('\nParts Count:')
print(PhyProps.PartsCount)
print('\nFaces Count:')
print(PhyProps.FacesCount)
print('\nEdges Count:')
print(PhyProps.EdgesCount)
print('\nVertices Count:')
print(PhyProps.VerticesCount)
print('\nUnique Parts Count:')
print(PhyProps.UniquePartsCount)
 
Last edited:
Continuing on this thread that will hopefully ultimately lead to a URDF generator, how does one use AlibreScript to access the Constraints defined within an Assembly? The only reference to Constraints that I've found so far is the enum documentation. Is there a way to determine how Parts are bound together?

Thanks,
Bruce
 

NateLiquidGravity

Alibre Super User
Alibre Script doesn't have much support for accessing constraints like that. Using the API IADAssemblyConstraint has Participants.
Previously it had an error and would not give either target if one was missing but I'm told that is fixed now.
 

hazzards

New Member
Exciting thread! I *just* started looking into this as well. Anyone interested in putting something up on GitHub? We might have different goals. I'd like to be able to output for Omniverse or Gazebo us, and possibly Ansys or Matlab at times, depending on what I want to simulate.
I just started and spend about 10 minutes/month on this. LOL. My biggest question on the design is if I have to do anything special regarding constraints to help with joint generation.
 
Top