Tool Table Example Program

The INI file, AeroScript library file, and AeroScript example program that follow show you how to use custom T-codes to make a custom tool table. You can also use T commands to modify programmed motion by configuring the settings for each tool. For instructions about how to use these files together, see the program comments in ToolTable_TestProgram.ascript.

IMPORTANT: You can get these files from the Automation1 installation under release/Examples/AeroScript. Aerotech recommends that you upload them from the installation to the root directory of the Controller File System. If you copy the code for each file into the Programming module, you must use the exact file names that are listed here. You can upload or add these files in any order, but they must be in the root directory.

If you write a custom tool table, the motion that the controller generates will change based on the settings that you configure for each tool. You can use the T command (T20, T0, T($iglobal[0]), etc.) to select the tools that you configured. For more information about custom T-codes, see Custom T-Codes.

ToolTable_Configuration.ini - This is an INI file that lets you define all of your custom tool settings. For more information about INI files, see File INI.

; The format of the tool table INI file depends on the implementation of ToolTable_Library.ascriptlib.
; The ToolData struct defined in ToolTable_Library.ascriptlib and the processing in the AeroScript loadTool() function
; determines what data this file needs to make available. This example shows a simple tool table implementation
; with similar data to what would be configured for the A3200 tool table feature.
;
; See the ToolData AeroScript struct and the loadTool() function in ToolTable_Library.ascriptlib for how this data is used and stored.
; Note that you must specify a tool in this file using the syntax and format shown below for it to be possible to select the tool in
; your program. You cannot specify more tools than the defined MAX_TOOLS value in ToolTable_Library.ascriptlib.

; Distance units specified in millimeters (primary)
[Tool.1]
AxisX = X
AxisY = Y
AxisZ = Z
ToolRadius = 7.62
ToolRadiusWear = 1.27
ToolOffsetX = 7.62
ToolOffsetY = 7.62
CutterLength = 8.382
Feedrate = 500.0
SpindleSpeed = 180.0
Units = Primary

; Distance units specified in inches (secondary)
[Tool.2]
AxisX = X
AxisY = Y
AxisZ = Z
ToolRadius = 0.30
ToolRadiusWear = 0.05
ToolOffsetX = 0.30
ToolOffsetY = 0.30
CutterLength = 0.33
Feedrate = 500.0
SpindleSpeed = 180.0
Units = Secondary

ToolTable_Library.ascriptlib - This is an AeroScript tool table library that you can upload to your controller to start using tools immediately. For information about how to compile a library file, see Working with Compiled Programs and Libraries. For information about how to load a compiled library file, see Program Automation Module.

//! @unique-id ToolTable_Library
//! @version 1.0.0

// Tool Table Example:
// The purpose of this library is to utilize several AeroScript features to implement custom tool tables.
// It parses custom tools from the ToolTable_Configuration.ini file, or another file if you specify one
// using LoadAllTools(). See ToolTable_TestProgram.ascript for an example of how to use this library.

// This value defines the maximum number of tools that the library can load from a single configuration file.
// WARNING: A larger maximum number of tools will increase the time it takes to load tools with LoadAllTools().
//          This is true even if you do not configure the maximum number of tools.
#define MAX_TOOLS 20

struct ToolData
	$axisX as axis
	$axisY as axis
	$axisZ as axis

	$offsetX as real
	$offsetY as real
	$cutterLength as real

	$radius as real
	$radiusWear as real

	$feedrate as real
	$spindleSpeed as real
	$units as DistanceUnits

	$available as integer
	$numAxes as integer
end

// In-memory store of tool data, so that the tool table INI file does not need to be read and parsed
// each time any operation using tools is performed.
var $ToolData[MAX_TOOLS] as ToolData

// Track the currently active tool, selected by T-codes, so that this can be retrieved by consumers
// of this library to determine which tool is currently selected using the $ActiveTool property.
var $activeToolInternal as integer = 0

//! @summary Get the currently selected tool. Read-only.
//! @return The currently selected tool on this task.
library property $ActiveTool as integer
	get
		return $activeToolInternal
	end
end

//////////////////////////////////////////////////////////////////////////////////////////////////////////

//! @summary Check whether cutter radius compensation or cutter offset compensation is currently active.
//! @return Whether cutter radius or cutter offset compensation is currently active on this task.
function isCutterCompensationActive() as integer
	// Cutter radius compensation
	var $cutterRadiusEnabling           = getTaskStatus1Bit(TaskStatus1.CutterRadiusEnabling)
	var $cutterRadiusDisabling          = getTaskStatus1Bit(TaskStatus1.CutterRadiusDisabling)
	var $cutterRadiusActiveLeft         = getTaskStatus2Bit(TaskStatus2.CutterRadiusActiveLeft)
	var $cutterRadiusActiveRight        = getTaskStatus2Bit(TaskStatus2.CutterRadiusActiveRight)

	// Cutter offset compensation
	var $cutterOffsetsEnablingPositive  = getTaskStatus1Bit(TaskStatus1.CutterOffsetsEnablingPositive)
	var $cutterOffsetsEnablingNegative  = getTaskStatus1Bit(TaskStatus1.CutterOffsetsEnablingNegative)
	var $cutterOffsetsDisabling         = getTaskStatus1Bit(TaskStatus1.CutterOffsetsDisabling)
	var $cutterOffsetsActiveNegative    = getTaskStatus2Bit(TaskStatus2.CutterOffsetsActiveNegative)
	var $cutterOffsetsActivePositive    = getTaskStatus2Bit(TaskStatus2.CutterOffsetsActivePositive)

	// If any of the above status bits are high, then cutter radius or offset compensation is currently active.
	return ($cutterRadiusEnabling || $cutterRadiusDisabling || $cutterRadiusActiveLeft ||
		$cutterRadiusActiveRight || $cutterOffsetsEnablingPositive || $cutterOffsetsEnablingNegative ||
		$cutterOffsetsDisabling || $cutterOffsetsActiveNegative || $cutterOffsetsActivePositive)
end


//! @summary Get a Task Status 1 bit.
//! @argument $maskedBit The bit to get.
//! @return 1 if the specified bit is high, 0 otherwise.
function getTaskStatus1Bit($maskedBit as TaskStatus1) as integer
	return (StatusGetTaskItem(TaskGetIndex(), TaskStatusItem.TaskStatus1, $maskedBit) == $maskedBit)
end

//! @summary Get a Task Status 2 bit.
//! @argument $maskedBit The bit to get.
//! @return 1 if the specified bit is high, 0 otherwise.
function getTaskStatus2Bit($maskedBit as TaskStatus2) as integer
	return (StatusGetTaskItem(TaskGetIndex(), TaskStatusItem.TaskStatus2, $maskedBit) == $maskedBit)
end


//! @summary Helper function to load a single tool from the tool table INI file.
//! @argument $toolFile The path to the tool table file from which to load the tool.
//! @argument $toolName The name of the tool, as specified in the tool table file.
//! @argument $toolData The ToolData struct to write this tool's data to. Output argument.
function loadTool($toolFile as string, $toolName as string, ref $toolData as ToolData)
	var $axisNameX, $axisNameY, $axisNameZ as string

	if (FileIniFindSection($toolFile, $toolName))
		$axisNameX = FileIniReadValue($toolFile, $toolName, "AxisX", "")
		$axisNameY = FileIniReadValue($toolFile, $toolName, "AxisY", "")
		$axisNameZ = FileIniReadValue($toolFile, $toolName, "AxisZ", "")

		if StringEquals($axisNameX, "") || StringEquals($axisNameY, "")
			TaskSetError(TaskGetIndex(), "Tool '" + $toolName + "' is missing one or more axes.")
		end

		var $numAxes as integer = 2

		var $unitsType as string = FileIniReadValue($toolFile, $toolName, "Units", "Primary")

		$toolData.axisX        = @($axisNameX)
		$toolData.axisY        = @($axisNameY)

		if StringEquals($axisNameZ, "")
			$toolData.axisZ    = @2
		else
			$toolData.axisZ    = @($axisNameZ)
			$numAxes = 3
		end

		$toolData.radius       = StringToReal(FileIniReadValue($toolFile, $toolName, "ToolRadius", "0.0"))
		$toolData.radiusWear   = StringToReal(FileIniReadValue($toolFile, $toolName, "ToolRadiusWear", "0.0"))
		$toolData.offsetX      = StringToReal(FileIniReadValue($toolFile, $toolName, "ToolOffsetX", "0.0"))
		$toolData.offsetY      = StringToReal(FileIniReadValue($toolFile, $toolName, "ToolOffsetY", "0.0"))
		$toolData.cutterLength = StringToReal(FileIniReadValue($toolFile, $toolName, "CutterLength", "0.0"))
		$toolData.feedrate     = StringToReal(FileIniReadValue($toolFile, $toolName, "Feedrate", "0.0"))
		$toolData.spindleSpeed = StringToReal(FileIniReadValue($toolFile, $toolName, "SpindleSpeed", "0.0"))

		if StringEquals(StringToUpperCase($unitsType), "PRIMARY")
			$toolData.units    = DistanceUnits.Primary
		elseif StringEquals(StringToUpperCase($unitsType), "SECONDARY")
			$toolData.units    = DistanceUnits.Secondary
		else
			TaskSetError(TaskGetIndex(), "Tool '"+ $toolName +"' specified an invalid unit value: '" + $unitsType + "'")
		end

		$toolData.available    = true
		$toolData.numAxes      = $numAxes
	else
		// Tools that are not found are marked unavailable. Attempting to select a tool that was not configured will
		// result in a task error. The tool is given default values here to ensure all values are initialized.
		$toolData.available    = false
		$toolData.axisX        = @0
		$toolData.axisY        = @1
		$toolData.axisZ        = @2
		$toolData.radius       = 0
		$toolData.radiusWear   = 0
		$toolData.offsetX      = 0
		$toolData.offsetY      = 0
		$toolData.cutterLength = 0
		$toolData.feedrate     = 100
		$toolData.spindleSpeed = 360
		$toolData.units        = DistanceUnits.Primary
		$toolData.numAxes      = 3
	end
end


//! @summary Clears the given tool's configuration.
//! @argument $activeTool The number (as it would be stored in $activeToolInternal) of the tool to clear.
function clearActiveTool($activeTool as integer)
	// Modify this function if you need T0 to perform other actions when clearing a tool.
	var $activeToolIndex = 0
	if $activeTool != 0
		$activeToolIndex = $activeTool - 1
	end

	// Reset distance units to primary.
	SetupTaskDistanceUnits(DistanceUnits.Primary)

	// If there was already a tool active, make sure to clear the correct axes.
	if $activeTool != 0 && $ToolData[$activeToolIndex].available
		if $ToolData[$activeToolIndex].numAxes == 3
			CutterCompensationSetAxes([$ToolData[$activeToolIndex].axisX,
										$ToolData[$activeToolIndex].axisY,
										$ToolData[$activeToolIndex].axisZ])
			CutterCompensationSetOffsets([0.0, 0.0, 0.0])
		else
			CutterCompensationSetAxes([$ToolData[$activeToolIndex].axisX,
										$ToolData[$activeToolIndex].axisY])
			CutterCompensationSetOffsets([0.0, 0.0])
		end
	else
		CutterCompensationSetAxes([@0, @1, @2])
		CutterCompensationSetOffsets([0.0, 0.0, 0.0])
	end

	// Radius compensation is always cleared.
	CutterCompensationSetRadius(0.0)
end


//! @summary Function to perform setup or other customized actions before configuring a tool.
//! @argument $toolNum The number of the tool being selected.
function preToolSelectAction($toolNum as integer)
	// You could use this function to do any pre-configuration setup, such as stopping motion and preparing a system
	// for tool or part exchange.

	// Track which tool is currently active.
	$activeToolInternal = $toolNum
end

//////////////////////////////////////////////////////////////////////////////////////////////////////////

//! @summary Load all tools from a tool table INI file on the controller.
//! @argument $toolFile The path to the tool table INI file from which to load tools.
library function LoadAllTools($toolFile as string)
	CriticalSectionStart(200)

	var $toolNum as integer

	for $toolNum = 0 to MAX_TOOLS - 1
		var $toolName as string = "Tool." + IntegerToString($toolNum + 1)
		loadTool($toolFile, $toolName, $ToolData[$toolNum])
	end

	CriticalSectionEnd()
end

// Direct T-code handler, allowing T-words (e.g. T100) to dispatch to this library.
library gcode T
	// The selected tool number can be retrieved using the 'argument(T)' syntax.
	var $toolNum as integer = argument(T)
	var $index as integer

	// Map number to in-memory tool cache index.
	if $toolNum == 0
		$index = $toolNum
	else
		$index = $toolNum - 1
	end

	// Check that specified tool number is valid.
	if (($index < 0) || ($toolNum > MAX_TOOLS))
		TaskSetError(TaskGetIndex(), "You must select a tool between 1 and " + IntegerToString(MAX_TOOLS) + ", or select 0 to disable the active tool.")
	end

	// Get the currently active tool before changing, so we can determine which axes were
	// affected by the previous tool if we need to deselect it.
	var $activeToolBackup = $activeToolInternal

	// Perform setup actions before the tool is configured.
	preToolSelectAction($toolNum)

	CriticalSectionStart(200)

	if $toolNum == 0
		// T0 is special syntax that selects the "null tool", which clears cutter radius and offset compensation values.
		clearActiveTool($activeToolBackup)
	else
		if $activeToolBackup != 0
			// There was a tool already active. It must be cleared first.
			clearActiveTool($activeToolBackup)
		end

		// Check that cutter radius compensation or cutter offset compensation is not enabled. The tool will not be able to be
		// activated if cutter radius or cutter offset compensation are currently enabled.
		if isCutterCompensationActive()
			TaskSetError(TaskGetIndex(), "You cannot use tools while cutter radius compensation or cutter offset compensation is active.")
		end

		// Enable the specified tool if it is configured.
		if $ToolData[$index].available
			// Set the task units based on the tool's configuration. This is NOT reset after configuring the tool.
			SetupTaskDistanceUnits($ToolData[$index].units)

			// Configure cutter radius compensation and cutter offset compensation, based on the number of axes the tool uses.
			if $ToolData[$index].numAxes == 3
				CutterCompensationSetAxes([$ToolData[$index].axisX, $ToolData[$index].axisY, $ToolData[$index].axisZ])
				CutterCompensationSetRadius($ToolData[$index].radius - $ToolData[$index].radiusWear)
				CutterCompensationSetOffsets([$ToolData[$index].offsetX, $ToolData[$index].offsetY, $ToolData[$index].cutterLength])
			else
				CutterCompensationSetAxes([$ToolData[$index].axisX, $ToolData[$index].axisY])
				CutterCompensationSetRadius($ToolData[$index].radius - $ToolData[$index].radiusWear)
				CutterCompensationSetOffsets([$ToolData[$index].offsetX, $ToolData[$index].offsetY])
			end

			// Configure feedrate and spindle speed.
			F$ToolData[$index].feedrate
			S$ToolData[$index].spindleSpeed
		else
			// The selected tool was within range, but did not have a configuration in the tool table INI file.
			TaskSetError(TaskGetIndex(), "Tool " + IntegerToString($toolNum) + " is not configured in your tool file.")
		end
	end

	CriticalSectionEnd()
end

//////////////////////////////////////////////////////////////////////////////////////////////////////////

ToolTable_TestProgram.ascript - This is an AeroScript program that shows you how to use custom tools to change how motion is generated by the controller. For information about how to collect and configure 2D and 3D data signals, see 2D Data Collection, 3D Data Collection, and Working with Plots.

// Tool Table Example:
// Demonstrates how you can write your own AeroScript tool table library to perform
// motion with tools.
//
// This file shows how to use the ToolTable_Library.ascriptlib to manage your own tool table.
// Your custom tools are defined in ToolTable_Configuration.ini.
//
// Steps to run this example:
// 1. Upload ToolTable_Configuration.ini, ToolTable_Library.ascriptlib, and ToolTable_TestProgram.ascript to the
//    controller file system using the Controller Files tab of the Configure workspace. Ensure that these files
//    are at the controller file system root.
// 2. Open ToolTable_Library.ascriptlib and ToolTable_TestProgram.ascript in the Develop workspace.
// 3. Compile ToolTable_Library.ascriptlib.
// 4. In Program Automation, in the Compiled Libraries tab, select Add Library and add ToolTable_Library.a1lib.
//    Select Save All and reset the controller when prompted. Alternatively, you can remove the "import" line
//    below and configure the compiled library to be auto-imported.
// 5. Configure data signals, if you want to view the plots generated by this program in 2D or 3D.
//    See below for a list of signals to configure.
// 6. Compile and run ToolTable_TestProgram.ascript.

// This library could also be configured to be auto-imported, which would allow all programs on all
// tasks to access tool table functionality without needing an import statement.
import "ToolTable_Library.a1lib" as dynamic

//! @summary Draw a 3D shape that looks like a concave dish if tools 1 and 2 are applied.
//! @argument $width Width of the dish square.
//! @argument $height Height of the concave part of the dish.
function DrawShape($width as real, $height as real)
	// For more information on the G-codes used in this function, refer to the G-Code Programming Help topic.
	// Make the task run in incremental target mode (G91), rather than absolute target mode.
	G91
	// Activate left-side cutter radius compensation (G41), negative cutter offset compensation (G144),
	// and perform a lead-on move (G1).
	G41 G144 G1 X$width
	// Perform linear moves to draw the shape (G1).
	G1 X$width Y$width Z$height
	G1 X$width Y-$width Z-$height
	G1 X-$width Y-$width Z$height
	G1 X-$width Y$width Z-$height
	G1 X$width Y$width Z$height
	// Disable cutter radius compensation (G40), cutter offset compensation (G149), and perform
	// a lead-off move (G1).
	G40 G149 G1 Y$width

	// Move into position for next draw.
	G1 X$width Y$width Z-$height
end

program
	Enable([X,Y,Z])
	Home([X,Y,Z])

	// Load all tools from the specified configuration file into memory.
	LoadAllTools("ToolTable_Configuration.ini")

	// Ensure no tool is already selected.
	T0

	// To view the shapes that are drawn by this example program in the Data Visualizer module,
	// you will need to configure the following signals manually in the Visualize workspace
	// Configure Signals menu for 3D:
	//  1. PositionCommand (Axis X)
	//  2. PositionCommand (Axis Y)
	//  3. PositionCommand (Axis Z)

	AppDataCollectionSnapshot()

	// Select tools and then draw shapes.
	T1
	DrawShape(10, 4)

	// Selecting a tool will configure the task to operate in the tool's units,
	// either Primary or Secondary, as if you had used the AeroScript function
	// SetupTaskDistanceUnits(). Deselecting a tool with T0 will revert the task
	// to Primary units.
	T2
	DrawShape(0.393701, 0.15748)

	// The $ActiveTool property allows us to read which tool is currently selected.
	// $iglobal[0] should now equal 2, which is the currently active tool.
	$iglobal[0] = $ActiveTool

	T0
	DrawShape(10, 4)

	AppDataCollectionStop()

	Home([X,Y,Z])
	Disable([X,Y,Z])
end