Share

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>
#include <chrono>
#include <thread>
#include <algorithm>

#ifdef _WINDOWS
#include <shlwapi.h>
#else
#include <stdlib.h>
#endif

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();
    Ptr<Document> doc = nullptr;

    // Load by URN a specific sample project to demonstrate a basic milling workflow.
    std::string urn = "urn:adsk.wipprod:fs.file:vf.KoBHzV4mTOiNvFStiBwpzA?version=1"; // Production

    // Load 2D Strategies model from the Fusion CAM Samples folder
    Ptr<DataFile> sampleFile = app->data()->findFileById(urn);
    if (sampleFile)
    {
        doc = app->documents()->open(sampleFile, true);
    }

    // Did we find our document?
    if (!doc)
    {
        ui->messageBox("Sample file not found, using the current document.", "", MessageBoxButtonTypes::OKButtonType);

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

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

    Ptr<Products> products = doc->products();
    if (!products)
        return false;

    // Check if the document has a CAMProductType. It will return if there are no CAM operations in it.
    Ptr<CAM> camProduct = products->itemByProductType("CAMProductType");
    if (!camProduct)
    {
        ui->messageBox(
            "There are no CAM operations in the active document. This script requires the active document to contain "
            "at least one CAM operation.",
            "No CAM Operations Exist",
            MessageBoxButtonTypes::OKButtonType,
            MessageBoxIconTypes::CriticalIconType);
        return false;
    }

    // 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);
    if (!part)
    {
        ui->messageBox(
            "No part found in the current document, exiting sample script.", "", MessageBoxButtonTypes::OKButtonType);
        return false;
    }
    // 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'"); // Must be single quotes inside double quotes

    // 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);
    Ptr<GenerateToolpathFuture> genFuture = 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;
    std::string ncExtension;
    // Find the "XYZ" post in the post library and import it to local library
    for (Ptr<PostConfiguration>& config : postConfigs)
    {
        if (config->description() == "XYZ")
        {
            ncExtension = config->extension();
            Ptr<URL> configUrl = URL::create("user://");
            importedURL = postLibrary->importPostConfiguration(config, configUrl, "NCProgramSamplePost.cps");
            break;
        }
    }

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

    // Variable outputFolder may contain backslashes but nc_program_output_folder requires forward slashes
    std::replace_if(
        outputFolder.begin(), outputFolder.end(), [](char ch) { return ch == '\\'; }, '/');

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

    // NcProgram parameters are passed without units to the postprocessor
    Ptr<FloatParameterValue> builtin_tolerance = postParameters->itemByName("builtin_tolerance")->value();
    builtin_tolerance->value(0.01);

    Ptr<FloatParameterValue> builtin_minimumChordLength =
        postParameters->itemByName("builtin_minimumChordLength")->value();
    builtin_minimumChordLength->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
    Ptr<NCProgramPostProcessOptions> postOptions = NCProgramPostProcessOptions::create();

    // Ensure toolpaths are visible
    faceOp->isLightBulbOn(true);
    adaptiveOp->isLightBulbOn(true);

    // To avoid errors, post-process only when toolpath generation has completed
    if (!genFuture)
        return false;
    while (!genFuture->isGenerationCompleted())
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }
    newProgram->postProcess(postOptions);

    // Advise where the NC file is located to indicate completion
    ui->messageBox(
        "The result has been written to:\n" + outputFolder + "/" + nc_program_filename->value() + ncExtension,
        "Post processing is complete  \t\t\t\t\t");

    return true;
}


Was this information helpful?