This sample script starts by opening a simple component which is then used to describe a basic turning workflow. It creates a setup, a few operations, pick some tools from a Fusion sample tool library using loops and queries and ends up post-processing the operations out using an NC Program.
import adsk.core, adsk.fusion, adsk.cam, traceback import time # Address/urn of the sample project to load by the script PROJECT_URN = 'urn:adsk.wipprod:fs.file:vf.484G2xc_Tx2ZOs6kSWmyXw?version=2' # CAM Samples -> API Samples -> Models -> Threaded_Mount # local turning tool library to use TURNING_TOOL_LIBRARY_NAME = 'Turning Tools (Metric)' def run(context): ui = None try: #################### Initialisation ##################### app = adsk.core.Application.get() ui = app.userInterface # Load by URN a specific sample project to demonstrate a basic turning workflow. doc = loadProjectFromURN(PROJECT_URN) if not doc: return design = adsk.fusion.Design.cast(doc.products.itemByProductType("DesignProductType")) if not design: ui.messageBox('No active Fusion design found.', 'Fusion', adsk.core.MessageBoxButtonTypes.OKButtonType, adsk.core.MessageBoxIconTypes.CriticalIconType) return # Switch to manufacturing space camWS: adsk.core.Workspace = ui.workspaces.itemById('CAMEnvironment') camWS.activate() # Get the products (to get CAM product later...) products: adsk.core.Products = doc.products #################### Find tools in sample tool library #################### # Get the tool libraries from the library manager camManager = adsk.cam.CAMManager.get() libraryManager: adsk.cam.CAMLibraryManager = camManager.libraryManager toolLibraries: adsk.cam.ToolLibraries = libraryManager.toolLibraries # Search for a specific turning tool library in local tool libraries toolLibrary: adsk.cam.ToolLibrary = None localLibLocationURL = toolLibraries.urlByLocation(adsk.cam.LibraryLocations.Fusion360LibraryLocation) localFolderURLs = toolLibraries.childAssetURLs(localLibLocationURL) for url in localFolderURLs: # search for tool library using its name name if url.leafName == TURNING_TOOL_LIBRARY_NAME: # Load tool library toolLibrary: adsk.cam.ToolLibrary = toolLibraries.toolLibraryAtURL(url) break # check tool library has been found if not toolLibrary: ui.messageBox(f'Failed to find tool library: "{TURNING_TOOL_LIBRARY_NAME}"', 'Fusion', adsk.core.MessageBoxButtonTypes.OKButtonType, adsk.core.MessageBoxIconTypes.CriticalIconType) return # Create some variables for the turning tools which will be used in the operations faceTool: adsk.cam.Tool = None roughingTool: adsk.cam.Tool = None # Searching the turning tool using a loop for the roughing operations for tool in toolLibrary: # Read the tool type toolType = tool.parameters.itemByName('tool_type').value.value hand = tool.parameters.itemByName('tool_hand').value.value shape = tool.parameters.itemByName('tool_insertType').value.value # Select the first face tool found if toolType == 'turning general' and hand == 'R' and shape == 'C' and not faceTool: tool.parameters.itemByName('tool_number').expression = '1' faceTool = tool # Search the roughing tool elif toolType == 'turning general' and hand == 'R' and shape == 'V' and not roughingTool: tool.parameters.itemByName('tool_number').expression = '2' roughingTool = tool # Exit when the 2 tools are found if faceTool and roughingTool: break #################### Create setup #################### cam: adsk.cam.CAM = adsk.cam.CAM.cast(products.itemByProductType("CAMProductType")) setups: adsk.cam.Setups = cam.setups setupInput: adsk.cam.SetupInput = setups.createInput(adsk.cam.OperationTypes.TurningOperation) # Create a list for the models to add to the setup Input models = [] # Identify the part or exit gracefully try: part: adsk.fusion.BRepBody = cam.designRootOccurrence.bRepBodies.item(0) except Exception as e: ui.messageBox('No part found in the current document, exiting sample script.', 'Fusion', adsk.core.MessageBoxButtonTypes.OKButtonType, adsk.core.MessageBoxIconTypes.CriticalIconType) return # Add the part to the model list models.append(part) # Pass the model list to the setup input setupInput.models = models # Create the setup setup: adsk.cam.Setup = setups.add(setupInput) # Change some properties of the setup setup.name = 'CAM Turning Basic Script Sample' setup.stockMode = adsk.cam.SetupStockModes.RelativeCylinderStock # Set offset mode setup.parameters.itemByName('job_stockOffsetMode').expression = "'simple'" # Set offset stock side setup.parameters.itemByName('job_stockOffsetSides').expression = '1 mm' # Set offset stock top setup.parameters.itemByName('job_stockOffsetTop').expression = '0.5 mm' # Set setup origin setup.parameters.itemByName('wcs_origin_boxPoint').value.value = 'top 1' #################### Face operation #################### # Create a face operation input faceInput: adsk.cam.OperationInput = setup.operations.createInput('turningFace') faceInput.tool = faceTool faceInput.displayName = 'Turning Facing Operation' faceInput.parameters.itemByName('tolerance').expression = '0.01 mm' faceInput.parameters.itemByName('stepover').expression = '0.75 * tool_diameter' faceInput.parameters.itemByName('direction').expression = "'outside to inside'" # Add the operation to the setup faceOp: adsk.cam.OperationBase = setup.operations.add(faceInput) #################### Adaptive operation #################### roughingInput = setup.operations.createInput('turningProfileRoughing') roughingInput.tool = roughingTool roughingInput.displayName = 'Turning Roughing Operation' roughingInput.parameters.itemByName('tolerance').expression = '0.1 mm' roughingInput.parameters.itemByName('depthOfCut').expression = '1.1 mm' # Add the operation to the setup roughingOp: adsk.cam.OperationBase = setup.operations.add(roughingInput) ##################### Generate operations #################### cam.generateToolpath(faceOp) genFuture: adsk.cam.GenerateToolpathFuture = cam.generateToolpath(roughingOp) adsk.doEvents() #################### ncProgram and post-processing #################### # Get the post library from library manager postLibrary: adsk.cam.PostLibrary = libraryManager.postLibrary # Query post library to get postprocessor list libraryLocation = adsk.cam.LibraryLocations.Fusion360LibraryLocation postQuery: adsk.cam.PostConfigurationQuery = postLibrary.createQuery(libraryLocation) postQuery.vendor = "Fanuc" postQuery.capability = adsk.cam.PostCapabilities.Turning postConfigs: list[adsk.cam.PostConfiguration] = postQuery.execute() # Find a post in the post library and import it to local library ncExtension = '' for config in postConfigs: if config.description == 'FANUC Turning': ncExtension = config.extension url = adsk.core.URL.create("user://") importedURL = postLibrary.importPostConfiguration(config, url, "NCProgramSampleTurnPost.cps") break # Get the imported local post config postConfig: adsk.cam.PostConfiguration = postLibrary.postConfigurationAtURL(importedURL) # Create NCProgramInput object ncInput: adsk.cam.NCProgramInput = cam.ncPrograms.createInput() ncInput.displayName = 'NC Program Sample' # Change some nc program parameters... ncFilename = 'NCProgramSample' ncParameters: adsk.cam.CAMParameters = ncInput.parameters ncParameters.itemByName('nc_program_filename').value.value = ncFilename ncParameters.itemByName('nc_program_openInEditor').value.value = True ncParameters.itemByName('nc_program_nc_extension').value.value = ncExtension # Set temp directory as output directory # Make the path valid for Fusion by replacing \\ to / in the path outputFolder = str(cam.temporaryFolder).replace('\\', '/') ncParameters.itemByName('nc_program_output_folder').value.value = outputFolder # Select the operations to generate ncInput.operations = [faceOp, roughingOp] # Add a new ncprogram from the ncprogram input newProgram: adsk.cam.NCProgram = cam.ncPrograms.add(ncInput) # Set post processor newProgram.postConfiguration = postConfig # Change some post parameters postParameters: adsk.cam.CAMParameters = newProgram.postParameters # NcProgram parameters are passed without units to the postprocessor postParameters.itemByName('builtin_tolerance').value.value = 0.01 postParameters.itemByName('builtin_minimumChordLength').value.value = 0.33 # Update/apply post parameters newProgram.updatePostParameters(postParameters) # Post-process # Set post options, by default post process only valid operations containing toolpath data postOptions = adsk.cam.NCProgramPostProcessOptions.create() # Ensure toolpaths are visible faceOp.isLightBulbOn = True roughingOp.isLightBulbOn = True # To avoid errors, post-process only when toolpath generation has completed while not genFuture.isGenerationCompleted: time.sleep(1) newProgram.postProcess(postOptions) # Advise where the NC file is located to indicate completion (adding a few Tabs '\t' so the file path is nicely printed on one line..) ui.messageBox(f'Setup, Operations and NCProgram created.\n\nThe results have been written to:\n{outputFolder}/{ncFilename}{ncExtension}\n\nPost processing is complete. \t\t\t\t\t', 'Fusion', adsk.core.MessageBoxButtonTypes.OKButtonType, adsk.core.MessageBoxIconTypes.InformationIconType) except: if ui: ui.messageBox('Failed:\n{}'.format(traceback.format_exc()), 'Fusion', adsk.core.MessageBoxButtonTypes.OKButtonType, adsk.core.MessageBoxIconTypes.CriticalIconType) def loadProjectFromURN(urn: str = None) -> adsk.core.Document: ''' Minimal self-contained function to load and return a document via URN or return None safely ''' doc: adsk.core.Document = None app = adsk.core.Application.get() if urn: try: # File not found causes an exception project: adsk.core.DataFile = app.data.findFileById(urn) if project: doc = app.documents.open(project, True) else: app.userInterface.messageBox(f'File not found for URN: {urn}!', 'Fusion', adsk.core.MessageBoxButtonTypes.OKButtonType, adsk.core.MessageBoxIconTypes.CriticalIconType) except Exception as e: if str(e)[0:38] == '3 : Design is located in another team.': # Although the document has been loaded, variable 'doc' may not be populated if not doc: doc: adsk.core.Document = adsk.core.Application.get().activeDocument elif str(e)[0:20] == '3 : file not found': app.userInterface.messageBox(f'File not found for URN: {urn}!', 'Fusion', adsk.core.MessageBoxButtonTypes.OKButtonType, adsk.core.MessageBoxIconTypes.CriticalIconType) else: # Abandon for unhandled errors, displaying the error message. app.userInterface.messageBox(f'Failed:{str(e)}\n{traceback.format_exc()}', 'Fusion', adsk.core.MessageBoxButtonTypes.OKButtonType, adsk.core.MessageBoxIconTypes.CriticalIconType) return doc