Basic Milling Workflow Sample

Description

Demonstrates the creation of a basic milling workflow from script

Demonstrates creating a setup, searching tool library to retrieve a tool, create a couple of machining operations and a NC program, ready for post processing.

Use the 2D Strategies model from the Fusion CAM Samples folder as your CAD model.

Code Samples

#include <Core/CoreAll.h>
#include <Fusion/FusionAll.h>
#include <Cam/CamAll.h>

using namespace adsk::core;
using namespace adsk::fusion;
using namespace adsk::cam;

extern "C" XI_EXPORT bool run(const char* context)
{
    /*
     * initialisation
     */
    Ptr<Application> app = Application::get();
    Ptr<UserInterface> ui = app->userInterface();

    // use existing document, load 2D Strategies model from the Fusion CAM Samples folder
    Ptr<Document> doc = app->activeDocument();

    // switch to manufacturing space
    Ptr<Workspace> camWS = ui->workspaces()->itemById("CAMEnvironment");
    camWS->activate();

    // get the CAM product
    Ptr<Products> products = doc->products();

    /*
     * Find tools in sample tool library
     */
    // get the tool libraries from the library manager
    Ptr<CAMManager> camManager = CAMManager::get();
    Ptr<CAMLibraryManager> libraryManager = camManager->libraryManager();
    Ptr<ToolLibraries> toolLibraries = libraryManager->toolLibraries();

    // we can use a library URl directly if we know its address (here we use Fusion"s Metric sample library)
    Ptr<URL> toolLibraryUrl = URL::create("systemlibraryroot://Samples/Milling Tools (Metric).json");

    // load tool library
    Ptr<ToolLibrary> toolLibrary = toolLibraries->toolLibraryAtURL(toolLibraryUrl);
    if (!toolLibrary)
    {
        ui->messageBox("Failed to load tool library");
        return false;
    }

    // create some variables for the milling tools which will be used in the operations
    Ptr<Tool> faceTool = nullptr;
    Ptr<Tool> adaptiveTool = nullptr;

    // searching the face mill and the bull nose using a loop for the roughing operations
    for (Ptr<Tool>& tool : toolLibrary)
    {
        // read the tool type
        Ptr<ChoiceParameterValue> toolTypeParameter = tool->parameters()->itemByName("tool_type")->value();
        std::string toolType = toolTypeParameter->value();

        // select the first face tool found
        if (toolType == "face mill" && !faceTool)
        {
            faceTool = tool;
        }

        // search the roughing tool
        else if (toolType == "bull nose end mill" && !adaptiveTool)
        {
            // we look for a bull nose end mill tool larger or equal to 10mm but less than 14mm
            Ptr<FloatParameterValue> diameterParameter = tool->parameters()->itemByName("tool_diameter")->value();
            double diameter = diameterParameter->value();
            if (diameter >= 1.0 && diameter < 1.4)
            {
                adaptiveTool = tool;
            }
        }

        // exit when the 2 tools are found
        if (faceTool && adaptiveTool)
        {
            break;
        }
    }

    if (!faceTool)
    {
        ui->messageBox("No face mill tool found");
        return false;
    }
    if (!adaptiveTool)
    {
        ui->messageBox("No bull nose end mill tool found");
        return false;
    }

    /*
     * create setup
     */
    Ptr<CAM> cam = products->itemByProductType("CAMProductType");
    Ptr<Setups> setups = cam->setups();
    Ptr<SetupInput> setupInput = setups->createInput(OperationTypes::MillingOperation());
    // create a list for the models to add to the setup Input
    std::vector<Ptr<Base>> models;
    Ptr<BRepBody> part = cam->designRootOccurrence()->bRepBodies()->item(0);
    // add the part to the model list
    models.push_back(part);
    // pass the model list to the setup input
    setupInput->models(models);
    // create the setup
    Ptr<Setup> setup = setups->add(setupInput);
    // change some properties of the setup
    setup->name() = "CAM Basic Script Sample";
    setup->stockMode(SetupStockModes::RelativeBoxStock);
    // set offset mode
    setup->parameters()->itemByName("job_stockOffsetMode")->expression("\"simple\"");
    // set offset stock side
    setup->parameters()->itemByName("job_stockOffsetSides")->expression("0 mm");
    // set offset stock top
    setup->parameters()->itemByName("job_stockOffsetTop")->expression("2 mm");
    // set setup origin
    Ptr<ChoiceParameterValue> wcs_origin_boxPoint = setup->parameters()->itemByName("wcs_origin_boxPoint")->value();
    wcs_origin_boxPoint->value("top 1");

    /*
     * face operation
     */
    // create a face operation input
    Ptr<OperationInput> faceInput = setup->operations()->createInput("face");
    faceInput->tool(faceTool);
    faceInput->displayName("Face Operation");
    faceInput->parameters()->itemByName("tolerance")->expression("0.01 mm");
    faceInput->parameters()->itemByName("stepover")->expression("0.75 * tool_diameter");
    faceInput->parameters()->itemByName("direction")->expression("\"climb\"");

    // add the operation to the setup
    Ptr<Operation> faceOp = setup->operations()->add(faceInput);

    /*
     * adaptive operation
     */
    Ptr<OperationInput> adaptiveInput = setup->operations()->createInput("adaptive");
    adaptiveInput->tool(adaptiveTool);
    adaptiveInput->displayName("Adaptive Roughing");
    adaptiveInput->parameters()->itemByName("tolerance")->expression("0.1 mm");
    adaptiveInput->parameters()->itemByName("maximumStepdown")->expression("5 mm");
    adaptiveInput->parameters()->itemByName("fineStepdown")->expression("0.25 * maximumStepdown");
    adaptiveInput->parameters()->itemByName("flatAreaMachining")->expression("false");

    // add the operation to the setup
    Ptr<Operation> adaptiveOp = setup->operations()->add(adaptiveInput);

    /*
     * generate operations
     */
    cam->generateToolpath(faceOp);
    cam->generateToolpath(adaptiveOp);

    /*
     * ncProgram and post-processing
     */
    // get the post library from library manager
    Ptr<PostLibrary> postLibrary = libraryManager->postLibrary();

    // query post library to get postprocessor list
    Ptr<PostConfigurationQuery> postQuery = postLibrary->createQuery(LibraryLocations::Fusion360LibraryLocation);
    postQuery->vendor("Autodesk");
    postQuery->capability(PostCapabilities::Milling);
    std::vector<Ptr<PostConfiguration>> postConfigs = postQuery->execute();

    Ptr<URL> importedURL;
    // find the "XYZ" post in the post library and import it to local library
    for (Ptr<PostConfiguration>& config : postConfigs)
    {
        if (config->description() == "XYZ")
        {
            Ptr<URL> configUrl = URL::create("user://");
            importedURL = postLibrary->importPostConfiguration(config, configUrl, "NCProgramSamplePost.cps");
        }
    }

    // get the imported local post config
    Ptr<PostConfiguration> postConfig = postLibrary->postConfigurationAtURL(importedURL);

    // create NCProgramInput object
    Ptr<NCProgramInput> ncInput = cam->ncPrograms()->createInput();
    ncInput->displayName("NC Program Sample");

    // change some nc program parameters...
    Ptr<CAMParameters> ncParameters = ncInput->parameters();
    Ptr<StringParameterValue> nc_program_filename = ncParameters->itemByName("nc_program_filename")->value();
    nc_program_filename->value("NCProgramSample");
    Ptr<BooleanParameterValue> nc_program_openInEditor = ncParameters->itemByName("nc_program_openInEditor")->value();
    nc_program_openInEditor->value(true);

    // set temp directory as output directory
    std::string outputFolder = cam->temporaryFolder();
    Ptr<StringParameterValue> nc_program_output_folder = ncParameters->itemByName("nc_program_output_folder")->value();
    nc_program_output_folder->value(outputFolder);

    // select the operations to generate (we skip steep_and_shallow here)
    ncInput->operations({faceOp, adaptiveOp});

    // add a new ncprogram from the ncprogram input
    Ptr<NCProgram> newProgram = cam->ncPrograms()->add(ncInput);

    // set post processor
    newProgram->postConfiguration(postConfig);

    // change some post parameter
    Ptr<CAMParameters> postParameters = newProgram->postParameters();
    Ptr<FloatParameterValue> builtin_tolerance = postParameters->itemByName("builtin_tolerance")->value();
    builtin_tolerance->value(0.01); // NcProgram parameters is pass as it is to the postprocessor (it has no units)
    Ptr<FloatParameterValue> builtin_minimumChordLength =
        postParameters->itemByName("builtin_minimumChordLength")->value();
    builtin_minimumChordLength->value(
        0.33); // NcProgram parameters is pass as it is to the postprocessor (it has no units)

    // update/apply post parameters
    newProgram->updatePostParameters(postParameters);

    // post-process
    // uncomment next lines to automatically postprocess operations (requires them to be calculated!)
    //
    // set post options, by default post process only valid operations containing toolpath data
    // postOptions = adsk.cam.NCProgramPostProcessOptions.create()

    // newProgram.postProcess(postOptions)
    // ui->messageBox("Post processing is complete. The results have been written to:\n" + outputFolder + "/" +
    // programName + ".nc");

    return true;
}
import adsk.core, adsk.fusion, adsk.cam, traceback
import os

def run(context):
    ui = None
    try:

        #################### initialisation #####################
        app = adsk.core.Application.get()
        ui  = app.userInterface
        
        # use existing document, load 2D Strategies model from the Fusion CAM Samples folder
        doc = app.activeDocument

        # switch to manufacturing space
        camWS = ui.workspaces.itemById('CAMEnvironment') 
        camWS.activate()

        # get the CAM product
        products = doc.products


        #################### Find tools in sample tool library ####################
        # get the tool libraries from the library manager
        camManager = adsk.cam.CAMManager.get()
        libraryManager = camManager.libraryManager
        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/Milling Tools (Metric).json')
        
        # load tool library
        toolLibrary = toolLibraries.toolLibraryAtURL(url)

        # create some variables for the milling tools which will be used in the operations
        faceTool = None
        adaptiveTool = None
       
        # searching the face mill and the bull nose using a loop for the roughing operations
        for tool in toolLibrary:
            # read the tool type
            toolType = tool.parameters.itemByName('tool_type').value.value 
            
            # select the first face tool found
            if toolType == 'face mill' and not faceTool:
                faceTool = tool  
            
            # search the roughing tool
            elif toolType == 'bull nose end mill' and not adaptiveTool:
                # we look for a bull nose end mill tool larger or equal to 10mm but less than 14mm
                diameter = tool.parameters.itemByName('tool_diameter').value.value
                if diameter >= 1.0 and diameter < 1.4: 
                    adaptiveTool = tool

            # exit when the 2 tools are found
            if faceTool and adaptiveTool:
                break

      
        #################### create setup ####################
        cam = adsk.cam.CAM.cast(products.itemByProductType("CAMProductType"))
        setups = cam.setups
        setupInput = setups.createInput(adsk.cam.OperationTypes.MillingOperation)
        # create a list for the models to add to the setup Input
        models = [] 
        part = cam.designRootOccurrence.bRepBodies.item(0)
        # 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 = setups.add(setupInput) 
        # change some properties of the setup
        setup.name = 'CAM Basic Script Sample'  
        setup.stockMode = adsk.cam.SetupStockModes.RelativeBoxStock
        # set offset mode
        setup.parameters.itemByName('job_stockOffsetMode').expression = "'simple'"
        # set offset stock side
        setup.parameters.itemByName('job_stockOffsetSides').expression = '0 mm'
        # set offset stock top
        setup.parameters.itemByName('job_stockOffsetTop').expression = '2 mm'
        # set setup origin
        setup.parameters.itemByName('wcs_origin_boxPoint').value.value = 'top 1'
        

        #################### face operation ####################
        # create a face operation input
        input = setup.operations.createInput('face')
        input.tool = faceTool
        input.displayName = 'Face Operation'       
        input.parameters.itemByName('tolerance').expression = '0.01 mm'
        input.parameters.itemByName('stepover').expression = '0.75 * tool_diameter'
        input.parameters.itemByName('direction').expression = "'climb'"

        # add the operation to the setup
        faceOp = setup.operations.add(input)


        #################### adaptive operation ####################
        input = setup.operations.createInput('adaptive')
        input.tool = adaptiveTool
        input.displayName = 'Adaptive Roughing'
        input.parameters.itemByName('tolerance').expression = '0.1 mm' 
        input.parameters.itemByName('maximumStepdown').expression = '5 mm' 
        input.parameters.itemByName('fineStepdown').expression = '0.25 * maximumStepdown'
        input.parameters.itemByName('flatAreaMachining').expression = 'false'

        # add the operation to the setup
        adaptiveOp = setup.operations.add(input)

        ##################### generate operations ####################
        cam.generateToolpath(faceOp)
        cam.generateToolpath(adaptiveOp)
            

        #################### ncProgram and post-processing ####################
        # get the post library from library manager
        postLibrary = libraryManager.postLibrary

        # query post library to get postprocessor list
        postQuery = postLibrary.createQuery(adsk.cam.LibraryLocations.Fusion360LibraryLocation)
        postQuery.vendor = "Autodesk"
        postQuery.capability = adsk.cam.PostCapabilities.Milling
        postConfigs = postQuery.execute()

        # find the "XYZ" post in the post library and import it to local library
        for config in postConfigs:
            if config.description == 'XYZ':
                url = adsk.core.URL.create("user://")
                importedURL = postLibrary.importPostConfiguration(config, url, "NCProgramSamplePost.cps")

        # get the imported local post config
        postConfig = postLibrary.postConfigurationAtURL(importedURL)
       
        # create NCProgramInput object
        ncInput = cam.ncPrograms.createInput()
        ncInput.displayName = 'NC Program Sample'

        # change some nc program parameters...
        ncParameters = ncInput.parameters
        ncParameters.itemByName('nc_program_filename').value.value = 'NCProgramSample'
        ncParameters.itemByName('nc_program_openInEditor').value.value = True

        # set user desktop as output directory (Windows and Mac)
        # make the path valid for Fusion by replacing \\ to / in the path
        desktopDirectory = os.path.expanduser("~/Desktop").replace('\\', '/') 
        ncParameters.itemByName('nc_program_output_folder').value.value = desktopDirectory
        
        # select the operations to generate (we skip steep_and_shallow here)
        ncInput.operations = [faceOp, adaptiveOp]

        # add a new ncprogram from the ncprogram input
        newProgram = cam.ncPrograms.add(ncInput)

        # set post processor
        newProgram.postConfiguration = postConfig

        # change some post parameter
        postParameters = newProgram.postParameters
        postParameters.itemByName('builtin_tolerance').value.value = 0.01  # NcProgram parameters is pass as it is to the postprocessor (it has no units)
        postParameters.itemByName('builtin_minimumChordLength').value.value = 0.33  # NcProgram parameters is pass as it is to the postprocessor (it has no units)

        # update/apply post parameters
        newProgram.updatePostParameters(postParameters)

        # post-process
        # uncomment next lines to automatically postprocess operations (requires them to be calculated!)
        # 
        # set post options, by default post process only valid operations containing toolpath data
        # postOptions = adsk.cam.NCProgramPostProcessOptions.create()

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