Community
Fusion API and Scripts
Got a new add-in to share? Need something specialized to be scripted? Ask questions or share what you’ve discovered with the community.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Driving Joint ob sub Assembly using Python Add-In API

3 REPLIES 3
SOLVED
Reply
Message 1 of 4
oliver.ege
239 Views, 3 Replies

Driving Joint ob sub Assembly using Python Add-In API

Hello,

I am trying to drive multiple joints inside of a Assembly(more specifically the model of a Robot) which is used inside of another assembly.

My Code is working if the Assembly of the Robot is the root Assembly however if the Robot is inside of another Assembly my script does not work anymore, it throws no exception, however the Joints in the view do not get updated.

Here is the code that I am using to get the Joints:

app = None
ui = None
product = None
design = None
rootComp = None
allComps = None
urComp = None
try:
    app = adsk.core.Application.get()
    ui = app.userInterface
    product = app.activeProduct
    design = adsk.fusion.Design.cast(product)
    rootComp = design.rootComponent
    allComps = design.allComponents
    for comp in allComps:
        if comp.name.startswith("eSeries_UR10e"):
            urComp = comp
            ui.messageBox(comp.name)
    
    joints = urComp.allJoints
    urjoints = [None]*6
    for joint in joints:
        if joint.name.startswith("Base"):
            urjoints[0] = adsk.fusion.RevoluteJointMotion.cast(joint.jointMotion)
            print("found Base")
        elif joint.name.startswith("Shoulder"):
            urjoints[1] = adsk.fusion.RevoluteJointMotion.cast(joint.jointMotion)
            print("found Shoulder")
        elif joint.name.startswith("Elbow"):
            urjoints[2] = adsk.fusion.RevoluteJointMotion.cast(joint.jointMotion)
            print("found Elbow")
        elif joint.name.startswith("Wrist1"):
            urjoints[3] = adsk.fusion.RevoluteJointMotion.cast(joint.jointMotion)
            print("found Wrist1")
        elif joint.name.startswith("Wrist2"):
            urjoints[4] = adsk.fusion.RevoluteJointMotion.cast(joint.jointMotion)
            print("found Wrist2")
        elif joint.name.startswith("Wrist3"):
            urjoints[5] = adsk.fusion.RevoluteJointMotion.cast(joint.jointMotion)
            print("found Wrist3")
    axisinversion = [1,1,-1,-1,1,1]

And this is the code I use to drive the joints using a custom event handler:

class ThreadEventHandler(adsk.core.CustomEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            realurjoints = robot.joints
            for i in range(6):
                urjoints[i].rotationValue = realurjoints[i] * axisinversion[i]
            app.activeViewport.refresh()
            adsk.doEvents()
            
        except:
            if ui:
                ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

I get the positions that the joints should go to using robot.joints.

The strange thing is that the rotationValue of each RevoluteJointMotion gets updated correctly but not displayed when the robot is inside of another assembly.

Thanks for the help.

 

Greetings from Germany

Oli

3 REPLIES 3
Message 2 of 4
BrianEkins
in reply to: oliver.ege

The problem is the context of the joint you're editing. The documentation needs a section describing how joints work.

 

Here's an example that hopefully illustrates the issue you're running into.

 

Let's say you create an assembly calls BoxAsm with two components and you ground one of them and create a joint call "Motor" between them. The joint exists in the root component and you can access it using the Component.joints or Component.allJoints properties. Editing the joint will cause the part to move.

 

Now let's say you create another assembly and insert an instance of BoxAsm into it. And to better illustrate a point, let's say you insert a second instance of BoxAsm so you now see BoxAsm:1 and BoxAsm:2 in the root component. You can reposition each "Motor" joint independently for each of the assemblies even though there is only one BoxAsm component. What happens when you have subassemblies that contain joints is Fusion treats every joint as if it is in the root component.  In this example, because there are two occurrences of BoxAsm, there are two instances of the Motor joint available at the root level.  They're not available using the Component.joints property because the root component doesn't directly own these joints but you can get them using the Component.allJoints property. This provides a flat list of ALL joints in the entire assembly, regardless of where they exist.

 

In this example, allJoints will return two joints for the "Motor" joint. However, they're not quite the same because they have a different path from the root to the joint. The path is defined by the occurrence tree so the path for one of the joints is BoxAsm:1/Motor and the other is BoxAsm:2/Motor. In the context of the root component, Fusion treats these as two different joints and will allow you to change their values independently.

 

Your code is going straight to the component that contains the joint and changing the value on that joint. That change is ignored because it's only joints that are in the context of the root component that is used. There are a couple of ways to solve this. Here's one way. First here is a section of your original code:

    rootComp = design.rootComponent
    allComps = design.allComponents
    for comp in allComps:
        if comp.name.startswith("eSeries_UR10e"):
            urComp = comp
            ui.messageBox(comp.name)
    
    joints = urComp.allJoints
    urjoints = [None]*6
    for joint in joints:
        if joint.name.startswith("Base"):
            urjoints[0] = adsk.fusion.RevoluteJointMotion.cast(joint.jointMotion)
            print("found Base")

 

And here's a modified version that is adding the occurrence path to the joint.

    rootComp = design.rootComponent
    occ = rootComp.occurrences.itemByName("eSeries_UR10e:1")
    urComp = occ.component

    urjoints = [None]*6
    for joint in urComp.joints:
        joint = joint.createForAssemblyContext(occ)
        if joint.name.startswith("Base"):
            urjoints[0] = adsk.fusion.RevoluteJointMotion.cast(joint.jointMotion)
            print("found Base")

 

Hopefully, this helps. 

---------------------------------------------------------------
Brian Ekins
Inventor and Fusion 360 API Expert
Website/Blog: https://EkinsSolutions.com
Message 3 of 4
BrianEkins
in reply to: BrianEkins

I did a test using your original code with a few modifications and a simple assembly with the number of joints your program had. The movement turned out kind of interesting and couldn't help but create an animation of it. It does demonstrate having two instances of the same assembly and driving them independently.

---------------------------------------------------------------
Brian Ekins
Inventor and Fusion 360 API Expert
Website/Blog: https://EkinsSolutions.com
Message 4 of 4
oliver.ege
in reply to: oliver.ege

Thanks for this fast and outstanding help and clarification.

It would actually be useful if the documentation would be updated to include this since i did expect something like that but was unable to resolve it by my self.

 

Greetings from Germany

Oli

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report