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: 

Manufacturing (CAM) API Feedback

60 REPLIES 60
Reply
Message 1 of 61
prainsberry
8153 Views, 60 Replies

Manufacturing (CAM) API Feedback

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
60 REPLIES 60
Message 41 of 61
Joshua.mursic
in reply to: prainsberry

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.

Message 42 of 61
jeff.pek
in reply to: prainsberry

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

Thanks,

  Jeff

Message 43 of 61
Joshua.mursic
in reply to: jeff.pek

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

Message 44 of 61
Joshua.mursic
in reply to: jeff.pek

@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

 

Message 45 of 61
ltomuta
in reply to: Joshua.mursic

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.

 

 

Message 46 of 61
Joshua.mursic
in reply to: ltomuta

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()
Message 47 of 61
Joshua.mursic
in reply to: prainsberry

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)

 

 

 

 

 

 

Message 48 of 61
kandennti
in reply to: prainsberry

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',
    )

 

 

Message 49 of 61
kandennti
in reply to: prainsberry

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

Message 50 of 61
scottmoyse
in reply to: jeff.pek

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

Message 51 of 61
scottmoyse
in reply to: prainsberry

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

Message 52 of 61

Very nice

Message 53 of 61
fusionPTYNN
in reply to: prainsberry

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!

Message 54 of 61

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

Message 55 of 61

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

Message 56 of 61

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()))

 

Message 57 of 61
dames123
in reply to: prainsberry

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

 

Thanks.

Message 58 of 61
kandennti
in reply to: dames123

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.

Message 59 of 61
dames123
in reply to: kandennti

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

 

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

Message 60 of 61

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

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

Post to forums  

Autodesk Design & Make Report