Manufacturing (CAM) API Feedback

prainsberry
Autodesk
Autodesk

Manufacturing (CAM) API Feedback

prainsberry
Autodesk
Autodesk

With the latest Fusion 360 release, available starting today, you will see a huge increase in the APIs available for the manufacturing workspace.  This is a massive release, that I know many of you have been waiting for!

 

See here for a comprehensive list of these new capabilities.

 

You'll notice that all of the new Manufacture functionality is designated as being in "Preview". We're being cautious and releasing it as a preview, so we can react to problems and suggestions for improvement and be open to making changes that might break compatibility.

 

Please test it out and let us know in this thread:

  • If you find something that doesn't work.
  • If something doesn't make sense.
  • If the documentation needs to be improved.
  • Also, feel free to share successes with the capabilities.

Depending on the feedback we get, the plan is to take it out of preview after one or two major releases. 



Patrick Rainsberry
Developer Advocate, Fusion 360
2 Likes
Reply
8,160 Views
60 Replies
Replies (60)

Joshua.mursic
Advocate
Advocate

I am using templates to do some awesome automation using these new API features. I am having a bit of an issue though. When I use a template and calculate all of the toolpaths, if the operation is a rest material operation and no toolpath is found, further operations down the line are compromised with the warning: "failed to generate rest material". I don't think this issue is exclusive to building operations using the API though, and also occurs during manual creation. Is there anyway to get around this issue?

 

The only work around I see right now is that instead of generating a collection of operations, or an entire setup, loop through each operation and generate it, then check if it has toolpath, and delete it if it doesn't. The only real issue with this is that this forces me to do each operation one at a time instead of calculating all of them at once.

0 Likes

jeff.pek
Community Manager
Community Manager

@Joshua.mursic - Can you share the script you're using so we can take a closer look with it?

Thanks,

  Jeff

0 Likes

Joshua.mursic
Advocate
Advocate

Its part of a large addon that is heavily configured to work on my computer, I will try to build a script that isolates the error this weekend. Thanks for the fast response

0 Likes

Joshua.mursic
Advocate
Advocate

@jeff.pek Here is an image of the problem while I work on the script. The toolpaths with the failed to generate rest warning still generate toolpath, but they do it as if the rest Machining option was off.

Joshuamursic_0-1691778905331.png

 

1 Like

ltomuta
Advisor
Advisor

You could instantiate a whole bunch of templated operations and generate them all at once but then go through them and perform cleanup, generate, repeat - until your setup has toolpaths on all operations.

 

Not sure if the available events help you do this clean enough though.

 

 

0 Likes

Joshua.mursic
Advocate
Advocate

This is exactly what I ended up doing, thanks for the suggestion. Heres the code I came up with.

def toolpathStatus(self,generate:adsk.cam.GenerateToolpathFuture,cleanUp=False):
    '''
    generate: cam.generateToolpath(setup)
    '''
    cam:adsk.cam.CAM = app.activeProduct
    #  create and show the progress dialog while the toolpaths are being generated.
    progress = ui.createProgressDialog()
    progress.isCancelButtonShown = True
    progress.show(f'Calculating Toolpath', '', 0, generate.numberOfOperations)
    
    # Enter a loop to wait while the toolpaths are being generated and update the progress dialog.
    while generate.isGenerationCompleted is False:
        generate.numberOfCompleted
        progress.progressValue = generate.numberOfCompleted
        if cleanUp == False: progress.message = f'Calculating Operations {generate.numberOfCompleted} of {generate.numberOfOperations}'
        if cleanUp == True: progress.message = f'Cleaning Up Operations {generate.numberOfCompleted} of {generate.numberOfOperations}'
        progress.title = f"Generating Toopath"
        if progress.wasCancelled:
            return "Stop"
        adsk.doEvents()
    
    #Check if the any operations have empty toolpath
    regenerateSetup = []
    for operation in generate.operations:
        if operation.hasWarning and "Empty toolpath" in operation.warning:
            if operation.parentSetup not in regenerateSetup:
                regenerateSetup.append(operation.parentSetup)
            app.log(f'Operation: {operation.name}. Empty toolpath.')
            app.log(f' ')
            operation.deleteMe()    
    
    #Loop through setups that had operations deleted becasue they were empty and recalculate the affected dependant ops
    for setup in regenerateSetup:
        operationsToRecalculate = adsk.core.ObjectCollection.create()
        for operation in setup.operations:
            if operation.isToolpathValid is False:
                operationsToRecalculate.add(operation)
        if operationsToRecalculate.count > 0:
            cleanUpGenerate = cam.generateToolpath(operationsToRecalculate)
            self.toolpathStatus(cleanUpGenerate,True)

    progress.hide()
0 Likes

Joshua.mursic
Advocate
Advocate

There are a couple of bugs I have found:

First when trying to use parts of a component that is an external reference, the CadObjectParamater Input is rejected and left empty. I posted about it here.  When the link is broken on the same item so it is no longer an external reference, the parts can be used for input.

https://forums.autodesk.com/t5/fusion-360-api-and-scripts/origin-cadobjectparametervalue-on-a-linked...

 

Also,  we don't seem to be able to change the parameters of the postprocessor. When we try to get the parameter inside to post processor we can read it but cannot change its value.

def post(setup):
    ncInput = cam.ncPrograms.createInput()
    ncInput.operations = list(setup.operations)
    newProgram = cam.ncPrograms.add(ncInput)

    #Get the post configuration
    camManager = adsk.cam.CAMManager.get()
    libraryManager = camManager.libraryManager
    postLibraries = libraryManager.postLibrary
    cloudFolder = postLibraries.urlByLocation(adsk.cam.LibraryLocations.CloudLibraryLocation)
    cloudPostlibrary = postLibraries.childAssetURLs(cloudFolder)
    # Get Templates
    for cloudPost in cloudPostlibrary:
        postName = cloudPost.toString()
        if "test_post.cps" in postName:
            postUrl = adsk.core.URL.create(postName)
            # postConfiguration = postLibraries.postConfigurationAtURL(postUrl)
            # return postUrl.toString()
            postConfig =  postLibraries.postConfigurationAtURL(postUrl)

    # Error if not found
    ui.messageBox(f"Could not find Postprocessor 'test_post.cps'")

    newProgram.postConfiguration = postConfig

    #Try to change the post parameters
    newProgram.postParameters.itemByName('coolant_Toggle').value.value = False
    newProgram.postParameters.itemByName('coolant_Toggle').expression = "false"

    #post the program
    postOptions = adsk.cam.NCProgramPostProcessOptions.create()
    postSuccessful = newProgram.postProcess(postOptions)

 

 

 

 

 

 

0 Likes

kandennti
Mentor
Mentor

It seems that "job_stockMode" in adsk.cam.SetupInput.parameters is not correctly reflected.

(ver 2.0.16985)

 

The following script is meaningless, it only creates multiple setups, but I have it create the stock settings as shown in the image below.

1.png

 

# Fusion360API Python script

import traceback
import adsk.core as core
import adsk.cam as cam


def run(context):
    ui: core.UserInterface = None
    try:
        app: core.Application = core.Application.get()
        ui = app.userInterface

        camObj: cam.CAM = get_cam_product()

        # create setup
        for _ in range(3):
            create_setup(
                camObj,
            )

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


def create_setup(
    camObj: cam.CAM,
    ) -> None:

    setups: cam.Setups = camObj.setups
    setupIpt: cam.SetupInput = setups.createInput(
        cam.OperationTypes.MillingOperation
    )

    set_cam_parameter(
        setupIpt,
        'job_stockMode',
        'default',
    )

    set_cam_parameter(
        setupIpt,
        'job_stockOffsetMode',
        'keep',
    )

    setups.add(setupIpt)


def set_cam_parameter(
    camEntity,
    name: str,
    value: str,
) -> bool:
    try:
        prm: cam.CAMParameter = camEntity.parameters.itemByName(
            name
        )
        if not prm: return False

        prm.value.value = value

        return True

    except:
        return False


def get_cam_product() -> cam.CAM:
    app: core.Application = core.Application.get()
    activete_cam_env()

    return app.activeProduct


def activete_cam_env() -> None:
    app: core.Application = core.Application.get()
    ui: core.UserInterface = app.userInterface

    camWS: core.Workspace = ui.workspaces.itemById('CAMEnvironment') 
    camWS.activate()

 

 

 

When the new document is created and executed, the first setup is set as desired, but the second and subsequent setups are set to "From preceding setup".

1.png

 

However, you can change the create_setup function as follows
If you change the parameters after adding setups.add, you will get the correct result.

 

def create_setup(
    camObj: cam.CAM,
    ) -> None:

    setups: cam.Setups = camObj.setups
    setupIpt: cam.SetupInput = setups.createInput(
        cam.OperationTypes.MillingOperation
    )
    setup: cam.Setup = setups.add(setupIpt)

    set_cam_parameter(
        setup,
        'job_stockMode',
        'default',
    )

    set_cam_parameter(
        setup,
        'job_stockOffsetMode',
        'keep',
    )

 

 

0 Likes

kandennti
Mentor
Mentor

The hole recognition sample here has multiple errors and cannot be run as is.

https://help.autodesk.com/view/fusion360/ENU/?guid=GUID-7249049A-3CC8-489C-9187-D9960EB07607 


Here is a corrected version that is error-free.

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

_app: adsk.core.Application = adsk.core.Application.get()
_ui:adsk.core.UserInterface = _app.userInterface

def run(context):
    try:
        # Get the first body in the root component.
        des: adsk.fusion.Design = _app.activeDocument.products.itemByProductType('DesignProductType')
        body = des.rootComponent.bRepBodies[0]

        # Recognize the holes in the body.
        holeGroups = adsk.cam.RecognizedHoleGroup.recognizeHoleGroups([body])
        _app.log(f"Hole Group count: {holeGroups.count}")

        # Print out information about the found holes in the TEXT COMMAND window in Fusion.
        holeGroup: adsk.cam.RecognizedHoleGroup
        for holeGroup in holeGroups:
            # Process each hole within this group.
            _app.log(f"   Holes in Group count: {holeGroup.count}")
            hole: adsk.cam.RecognizedHole
            for hole in holeGroup:
                _app.log(f"      Segments in hole: {hole.segmentCount}")
                for i in range(hole.segmentCount):
                    # Display information about each segment of the current hole.
                    segment: adsk.cam.RecognizedHoleSegment = hole.segment(i)

                    _app.log(f'         Segment {i}')
                    if segment.holeSegmentType == adsk.cam.HoleSegmentType.HoleSegmentTypeCone:
                        _app.log(f'            Segment Type: Cone')
                    elif segment.holeSegmentType == adsk.cam.HoleSegmentType.HoleSegmentTypeFlat:
                        _app.log(f'            Segment Type: Flat')
                    elif segment.holeSegmentType == adsk.cam.HoleSegmentType.HoleSegmentTypeCylinder:
                        _app.log(f'            Segment Type: Cylinder')
                    elif segment.holeSegmentType == adsk.cam.HoleSegmentType.HoleSegmentTypeTorus:
                        _app.log(f'            Segment Type: Torus')

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

 

Also, I feel that the pocket recognition image does not match the description.

1.png

2 Likes

scottmoyse
Mentor
Mentor

Did this fix make it into the September release?


Scott Moyse
Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.


EESignature


RevOps Strategy Manager at Toolpath. New Zealand based.

Co-founder of the Grumpy Sloth full aluminium billet mechanical keyboard project

0 Likes

scottmoyse
Mentor
Mentor

Does anyone have a list of the available CAM events we can track? I'm hoping for events like:

  1. onOperationRename
  2. onOperationEdit
  3. onOperationGenerate
  4. onOperationReOrder

or events to that effect.


Scott Moyse
Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.


EESignature


RevOps Strategy Manager at Toolpath. New Zealand based.

Co-founder of the Grumpy Sloth full aluminium billet mechanical keyboard project

0 Likes

whitetowelrail
Community Visitor
Community Visitor

Very nice

0 Likes

fusionPTYNN
Explorer
Explorer

Hello Fusion 360 Community,

 

The operations created using createFromCAMTemplate2 are added to the end of the parent setup. However, I have a requirement to add them to the start of the setup. I've searched through the documentation but couldn't find a direct way to change the sequence of operations within a setup.

 

Is there a specific method or property that allows me to control the sequence of operations in a CAM setup? Or is there an alternative approach to achieve this?

Any insights or guidance on this matter would be greatly appreciated. Thank you in advance for your time and assistance!

1 Like

nicole.debowski
Autodesk
Autodesk

Hi@fusionPTYNN 

There are new methods allowing you to do that, they're just not showing up in the documentation yet. All of those methods are on the OperationBase class and should be available to you already:
- moveBefore(OperationBase targetOperationBase)
- moveAfter(OperationBase targetOperationBase)
- moveInto(OperationBase targetContainer) // i.e. a Setup or CAMFolder
Related to the above, the following have also been added:
- copyBefore(OperationBase targetOperationBase)
- copyAfter(OperationBase targetOperationBase)
- copyInto(OperationBase targetContainer) // i.e. a Setup or CAMFolder

2 Likes

fusionPTYNN
Explorer
Explorer

I have v 2.0.18460 of API libraries and don't have these methods. How I can update the libraries?

Zrzut ekranu 2024-03-06 211441.png

0 Likes

nicole.debowski
Autodesk
Autodesk

The methods do not auto complete in VS Code yet. The below snippet should work, just tried it on 2.0.18460 on my machine.

import os.path, sys
import adsk.core, adsk.fusion, adsk.cam, traceback

def run(context):
    ui = None
    try:
        app = adsk.core.Application.get()
        doc = app.activeDocument
        ui = app.userInterface
        ui.messageBox("This script needs a project with atleast 2 setups and 2 operations in each setup")
        products = doc.products
        cam = adsk.cam.CAM.cast(products.itemByProductType("CAMProductType"))
        setup1 = cam.setups[0]
        setup2 = cam.setups[1]

        operation11 = setup1.operations[0]
        operation12 = setup1.operations[1]
        operation21 = setup2.operations[0]

        operation11.moveAfter(operation21)
        operation21.moveBefore(operation12)
        operation12.moveInto(setup2)

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

 

2 Likes

dames123
Advocate
Advocate

Is there a way to create NCPrograms from each Setup (without posting) via the API?

 

Thanks.

0 Likes

kandennti
Mentor
Mentor

Hi @dames123 -San.

 

This is a topic for reporting bugs, etc., so if this is a question, it would be better to create a new topic.


A sample NC program was created for each setup.

# Fusion360API Python script

import traceback
import adsk.core as core
import adsk.fusion as fusion
import adsk.cam as cam

def run(context):
    ui: core.UserInterface = None
    try:
        app: core.Application = core.Application.get()
        ui = app.userInterface

        camObj: cam.CAM = app.activeProduct

        # https://help.autodesk.com/view/fusion360/ENU/?guid=GUID-995d634e-a8ef-4f2b-a826-1d32171f4998
        ncPrograms: cam.NCPrograms = camObj.ncPrograms
        for setup in camObj.setups:
            ncIpt: cam.NCProgramInput = ncPrograms.createInput()
            ncIpt.displayName = setup.name
            ncParameters = ncIpt.parameters
            ncParameters.itemByName('nc_program_filename').value.value = setup.name
            ncParameters.itemByName('nc_program_openInEditor').value.value = True
            ncIpt.operations = [setup]

            ncPrograms.add(ncIpt)

        ui.messageBox("Done")

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


Since this is only a minimum setup, I think it is necessary to make more settings for cps files, post properties, etc. in practice.

0 Likes

dames123
Advocate
Advocate

Sorry about that. I didn't realize this is just for bugs.

 

Thanks so much for the code. This will definitely get me started.

1 Like

maurizio_manzi
Advocate
Advocate

Hello,
A future-request:

Now, I can't not one of all the "avoid/machine surfaces" values in a advanced swarf operation over the API.
For example have all offset values the same parameter-Name ("clearance"), and not one is changed, if I set this over the API. Also all other parameters in this field can't be adjusted over the API.
(please see pic).

Best regards

Maurizio

 

04-04-_2024_15-20-02.png

0 Likes