Basic Milling Workflow Sample
Description
Demonstrates the creation of a basic milling workflow from scriptDemonstrates 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;
}
