Can't drive cylindrical joint rotation with API

Can't drive cylindrical joint rotation with API

Anonymous
Not applicable
1,599 Views
11 Replies
Message 1 of 12

Can't drive cylindrical joint rotation with API

Anonymous
Not applicable

Trying to drive a cylindrical joint rotation (that drives a mechanism through other joints) but not successful.  The attached model is a trivial example (without the final mechanism), using this script:

 

import adsk.core, adsk.fusion, adsk.cam, traceback
import math

def run(context):
    app = adsk.core.Application.get()
    ui = app.userInterface

    try:
        design = adsk.fusion.Design.cast(app.activeProduct)
        root = design.rootComponent

        crankJoint = root.joints.itemByName('Crankshaft to Bearing')
        crankAngle = adsk.fusion.CylindricalJointMotion.cast(crankJoint.angle)

        for step in range(0,180,1):
            angle = (math.pi / 90) * step 
            crankAngle = angle
            app.activeViewport.refresh()

    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

When executed, nothing happens.

 

But, this script fragment does work for a revolute joint

 

        driveJoint = root.joints.itemByName('Lever 1 to Foundation')
        revMotion = adsk.fusion.RevoluteJointMotion.cast(driveJoint.jointMotion)
        app.activeViewport.refresh()

        for step in range(0,360,1):
            angle = (math.pi / 90) * step 
            revMotion.rotationValue = angle
            app.activeViewport.refresh()

 

The documentation suggests that the property for CylindricalJointMotion should be "rotationValue" . . . but this generates a run error.  The script editor suggest the property "angle" which does not generate a run error but also doesn't do anything.  The property "jointMotion" used for the revolute joint works (for the revolute joint) but it seems that it would be ambiguous for a cylindrical joint since it has both rotational and sliding motions . . . it, also generates a run error.

 

Thoughts?

Thanks

 

 

 

0 Likes
1,600 Views
11 Replies
Replies (11)
Message 2 of 12

Anonymous
Not applicable

p.s.

Even the revolute joint behavior seems erratic.  For a range of 360 degrees, I've gotten 2 revolutions.  For a range of 1440 degrees (4 revolutions intended) it usually stops before the completion of the 4th revolution, hanging for a while before returning to the UI; however, I once got 8 revolutions.  

 

I notice that this process pegs CPU 2 at 100% (using a Core i7 9th gen processor) while the other CPUs don't show additional activity.  Could the Python interpreter and model math be getting out of sync?

 

Also, I'm trying to find a reliable way to vary the playback speed.  I've tried timing loops and sleep(), but haven't found a suitable solution yet.

 

Thanks

0 Likes
Message 3 of 12

Anonymous
Not applicable

p.p.s

My error . . . it's making 2 degree steps as written.  But this doesn't impact the erratic behavior.

0 Likes
Message 4 of 12

Anonymous
Not applicable

Update for revolute joint.

 

The attached trivial model, now with a revolute joint, runs properly (sometimes) with this script:

 

import adsk.core, adsk.fusion, adsk.cam, traceback
import math

app = adsk.core.Application.get()
design = adsk.fusion.Design.cast(app.activeProduct)
root = design.rootComponent

def run(context):
    ui = None
    try:

        ui  = app.userInterface
        ui.messageBox('Starting Revolute Joint Animation')


        msg = 'Number of Revolutions [1-4]'
        (iptStr, cancelled) = ui.inputBox(msg)
        if cancelled:
            return

        revs = max(1,min(int(iptStr),4))


        msg = 'Number of Sub-Steps [1-10]'
        (iptStr, cancelled) = ui.inputBox(msg)
        if cancelled:
            return

        noSubSteps = max(1,min(int(iptStr),10))


        for i in range(revs):
            stepAngle(noSubSteps)
        
        ui.messageBox('Finished')

    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

def stepAngle(subSteps):
        driveJoint = root.joints.itemByName('Crankshaft to Bearing')
        revMotion = adsk.fusion.RevoluteJointMotion.cast(driveJoint.jointMotion)

        for step in range(0,360 * subSteps,1):
            angle = (math.pi / 180) * step / subSteps
            revMotion.rotationValue = angle
            app.activeViewport.refresh()

 

The sub-step input is, in effect, a speed control with a large number running more slowly.

 

The problem is that it works, sometimes, and freezes mid-way at other times. 

 

The behavior is the same with both this trivial model and a more complex mechanism.

 

I tried using delays between model updates . . . it worked but didn't fix the freezing problem and wasn't smooth enough for a speed control . . . leading to the sub-step solution.

 

I still need a similar solution for cylindrical joints.

 

Thanks,

 

 

 

 

 

 

 

 

 

0 Likes
Message 5 of 12

Anonymous
Not applicable

Sorry to keep replying to myself, but seems I'm always past the edit timeout . . .

 

With the trivial model and a simple mechanism, the script and model often hang.  The only way around this seems to be to reboot the PC (re-running 360 doesn't seem enough) and doing this gets only one good run.

 

BUT . . . I just ran the latest script against a more complex model (10 cylindrical joints and several motion links).  Since I couldn't drive the primary cylindrical joint (and converting it to a revolute trashed the model), I drove it (the cylindrical joint) with a motion link that used a revolute joint and used the script to drive that revolute joint.  So far, it's worked consistently!

 

This is above my pay grade, but it seems that the modeler may be coming back to the script too soon for simple models (which probably return more quickly than for a complex model) and the modeler delay to increment the more complex model eliminates some sort of race condition?

 

I'll keep testing but it seems that (at least on my system) simple models don't work reliably . . . and that's not a good thing.

0 Likes
Message 6 of 12

Anonymous
Not applicable

And yet another observation . . .

 

While the more complex model animates reliably as reported, I've gotten it to fail with an addition.

 

I capture these design mode animations with SNAGIT.  I can run the script on the more complex model multiple times with varying inputs without SNAGIT (and no reboots) and it hasn't failed yet.   

 

But, it always fails when I try a SNAGIT video screen capture, unfortunately making the animation useless for my application.  I can make a successful run without SNAGIT, then failure with SNAGIT, then successful without SNAGIT, repeating the cycle multiple times with the same results.

 

Running Windows 10 on a Core i7 9th Gen Lenovo Legion laptop  with Nvidia Geforce GTX graphics and 16 GB of system RAM.  Although I use dual monitors, everything I've reported so far is displayed on the 1920x1080 laptop monitor.

0 Likes
Message 7 of 12

BrianEkins
Mentor
Mentor
Accepted solution

I didn't try any of your code but I think you need to add a call to adsk.doEvents()  just before the refresh call.  The reason for this is that everything is running in a single thread the the UI is blocked while your script is running.  Calling doEvents gives Fusion a chance to process any requests currently on the queue.

 

Also, if you're creating an animation, you shouldn't need to use Snagit to capture the screen.  Instead, you can use the Viewport.saveAsImageFile method.  Using this you can even save the view at a higher resolution than your screen.

 

---------------------------------------------------------------
Brian Ekins
Inventor and Fusion 360 API Expert
Website/Blog: https://EkinsSolutions.com
Message 8 of 12

Anonymous
Not applicable
Accepted solution

Brian,

 

Thank you!!!  Amazing what one line of code can do.

 

It now works with two levels of model complexity and with SNAGIT.

 

I'll try your animation capture suggestion.  SNAGIT does have the advantage of cropping to the desired portion of the view port and directly writing .mp4 files saving a little video editing time when adequate, but higher resolution certainly may be useful in some cases.  Great suggestion.

 

Again, can't thank you enough.

0 Likes
Message 9 of 12

Anonymous
Not applicable

Brian,

 

But one more thing . . .

 

I still can't get the API to drive a cylindrical joint (my original post) without the motion link hack to a revolute joint.  Should you have time, I'd be interested in guidance for that.

 

Again, thanks for your help.

0 Likes
Message 10 of 12

BrianEkins
Mentor
Mentor
Accepted solution

Here's a little script I tested it with and it's working for me.  The model I tested it with has a cylindrical joint in the root component that I renamed "Motor".  It changes the offset value from 0 to 4 cm and at the same time changes the rotation angle 720 degrees.

def DriveCylindricalJoint(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        ui  = app.userInterface
        des = adsk.fusion.Design.cast(app.activeProduct)
        root = adsk.fusion.Component.cast(des.rootComponent)

        # Find the joint in the root component named "Motor".
        joint = root.joints.itemByName('Motor')

        # Get the cylindrical joint motion object from the joint
        cylMotion = adsk.fusion.CylindricalJointMotion.cast(joint.jointMotion)

        # Animation the joint by changing both the offset and angle.
        totalOffset = 4
        totalRotate = math.pi * 4
        for i in range(360):
            offset = (4 / 360) * i
            rotate = (totalRotate / 360) * i

            cylMotion.rotationValue = rotate
            cylMotion.slideValue = offset

            adsk.doEvents()
    except:
        if ui:
            ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
---------------------------------------------------------------
Brian Ekins
Inventor and Fusion 360 API Expert
Website/Blog: https://EkinsSolutions.com
Message 11 of 12

Anonymous
Not applicable
Accepted solution

Brian,

 

Many thanks, again.  Problem solved and works with my models.

 

I'm embarrassed at having to ask things I should probably be able to find myself.  I've been at this only a few days and must be missing some essential documentation.  I tried to follow a link to the API manual but the link I tried was broken.   I've downloaded a massive API manual in PDF format (possibly assembled by a user?) but it seems to be less than current.  Where's the best place to find answers to the sort of questions I'm asking?

0 Likes
Message 12 of 12

BrianEkins
Mentor
Mentor
Accepted solution

There can always be more and better documentation but the best place to start is here:

http://help.autodesk.com/view/fusion360/ENU/?guid=GUID-A92A4B10-3781-4925-94C6-47DA85A4F65A

Read through the topics in the User Manual and use the Reference Manual as-needed to get detailed information about the object and the functions they support.

---------------------------------------------------------------
Brian Ekins
Inventor and Fusion 360 API Expert
Website/Blog: https://EkinsSolutions.com