Hello @treiFMCJL ,
The basic workflow of milling and turning operations is almost the same; you can refer to the script below for more details.
import adsk.core
import adsk.fusion
import adsk.cam
import traceback
import time
def run(context):
ui = None
try:
#################### Initialisation #####################
app = adsk.core.Application.get()
ui = app.userInterface
PROJECT_URN = 'urn:adsk.wipprod:dm.lineage:YlsP6ejaTuOf_j_PIHMWBQ'
# Load by URN a specific sample project to demonstrate a basic milling workflow.
doc = loadProjectFromURN(PROJECT_URN)
if doc is None:
return
design = adsk.fusion.Design.cast(
doc.products.itemByProductType("DesignProductType"))
if not design:
ui.messageBox('No active Fusion design found.')
return
design.timeline.moveToEnd()
# Switch to manufacturing space
camWS: adsk.core.Workspace = ui.workspaces.itemById('CAMEnvironment')
camWS.activate()
# Get the CAM product
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
# We can use a library URl directly if we know its address (here we use Fusion's Metric sample library)
url = adsk.core.URL.create(
'systemlibraryroot://Samples/Turning Tools (Metric).json')
# Load tool library
toolLibrary: adsk.cam.ToolLibrary = toolLibraries.toolLibraryAtURL(url)
# Create some variables for the milling tools which will be used in the operations
faceTool: adsk.cam.Tool = None
adaptiveTool: 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 adaptiveTool:
tool.parameters.itemByName('tool_number').expression = '2'
adaptiveTool = tool
# Exit when the 2 tools are found
if faceTool and adaptiveTool:
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.')
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 = 'Trun Face 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 ####################
adaptiveInput = setup.operations.createInput('turningProfileRoughing')
adaptiveInput.tool = adaptiveTool
adaptiveInput.displayName = 'Turning Roughing'
adaptiveInput.parameters.itemByName('tolerance').expression = '0.1 mm'
adaptiveInput.parameters.itemByName(
'depthOfCut').expression = '1.1 mm'
# Add the operation to the setup
adaptiveOp: adsk.cam.OperationBase = setup.operations.add(
adaptiveInput)
##################### Generate operations ####################
cam.generateToolpath(faceOp)
genFuture: adsk.cam.GenerateToolpathFuture = cam.generateToolpath(
adaptiveOp)
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 the "XYZ" 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")
# 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, adaptiveOp]
# 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
adaptiveOp.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
ui.messageBox(f'The results have been written to:\n{outputFolder}/{ncFilename}{ncExtension}',
# Prevent line breaks of the pathname
'Post processing is complete \t\t\t\t\t')
except:
if ui:
ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))
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 is not None:
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}!')
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 doc is None:
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}!')
else:
# Abandon for unhandled errors, displaying the error message.
app.userInterface.messageBox(
f'Failed:{str(e)}\n{traceback.format_exc()}')
return doc