Functions
A function is a sequence of program instructions that perform a specific task, grouped together in a unit. The language has different types of functions – those that are pre-defined in the Aerotech API, such as Home() or Enable(), and those that are user-defined.
Aerotech Standard Library API Functions
API functions are provided in order to perform common functionality with the controller. They are included in the Standard Library, similar to the libraries commonly packaged with compilers of programming languages such as C or C++.
As an example, the Enable() function is defined to be part of the Aerotech Standard Language API by using elements of the language, but is not part of the language itself. “Enable” is not a keyword in AeroScript, but is instead an identifier similar to “printf“ in the C programming language.
User-Defined Functions
User-Defined Function Overview
Users can define functions to modularize their code, allowing the same set of instructions to be executed multiple times from different locations in the program. An example of a user-defined function is as follows.
Enable($axes)
Home($axes)
end
A program block must exist in a program that contains function definitions in order to separate the main program from the function definitions. The program block must exist at the program global scope.
program
MyInit([X, Y])
G1 X10 Y10
end
function MyInit($axes[] as axis)
Enable($axes)
Home($axes)
end
If no functions are defined in a program, then the program block is optional.
Enable([X, Y])
Home([X, Y])
G1 X10 Y10
G1 X15 Y11
The following syntax is used for defining a function that returns a value.
<CodeBlock>
end
The <FunctionName> must be a valid identifier (see Valid Identifier Format), and cannot be the same as any of the Reserved Keywords or any axis name. The <FunctionName> is case-sensitive. For example, both MyFunc and MYFUNC can be used to refer to the same function.
A function can also be defined as not having a return value, as seen in the following syntax.
<CodeBlock>
end
Function Arguments
The <ArgumentList> is a list of zero or more arguments to pass to a function. Arguments in the list are separated by commas, and can consist of any data type that has been previously defined.
function MySet($index as integer, $value as real)
$rglobal[$index] = $value
end
// Function with a return value
function MyAdd($val1 as integer, $val2 as integer) as integer
return $val1 + $val2
end
The syntax for declaring a function argument in the <ArgumentList> is similar to the declaration of a member of a struct. Refer to Valid Variable Name Format for the proper way for defining the <ArgumentName>.
<ArgumentName>[<DimensionSize>] as <DataType>
<ArgumentName>[<Dimension1Size>][<Dimension2Size>] as <DataType>
<ArgumentName>[<Dimension1Size>][<Dimension2Size>][<Dimension3Size>] as <DataType>
By default, arguments are passed to a function as read-only. Attempting to modify a read-only argument within a function will result in a compilation error. However, arguments can be modified within the function if they are specified with the ref modifier, as seen in the following example.
var $counter as integer
// Stores $rglobal[0] into $counter
GetCounter($counter)
end
function GetCounter(ref $counter as integer)
$counter = $rglobal[0]
end
Function arguments that are defined with the ref modifier can only accept variables, not constant literals. In addition, the data type of a variable that is passed to a ref argument must match the data type of that ref argument. For example, a real variable cannot be specified to a ref argument that is defined as being an integer.
var $myVar as real
// The following statement causes a compiler error because variables
// passed for arguments with the ref modifier
MyFunc(3)
// The following statement is illegal (causes a compiler error) because
// the variable $myVar is a real, but the function expects an integer
// variable
MyFunc($myVar)
end
function MyFunc(ref $value as integer)
$value = $iglobal[0]
end
A function can either return nothing, or it can return a single scalar (non-array) value. By passing arguments to a function with the ref modifier, you are able to “return” more than one value, including arrays.
Controller global variables (such as $rglobal[], $iglobal[], and $sglobal[]) cannot be passed to a function as an argument that was specified with the ref modifier. In addition, a property cannot be passed to a function as an argument that was specified with the ref modifier.
The dimensions of array arguments must match those defined in the function definition.
var $matrix1[3][3] as integer
var $matrix2[5][5] as integer
// Expected dimensions ([3][3]) and actual dimensions ([3][3]) match
FillMatrix($matrix1)
// Error, expected dimensions don't match actual dimensions ([5][5])
FillMatrix($matrix2)
end
function FillMatrix(ref $matrix[3][3] as integer)
// ...
end
For array arguments in a function, the lengths of each array dimension are optional. Empty brackets can be specified for array dimensions, and the length of each dimension can be determined at runtime. Because the size of array dimensions do not need to be specified for array arguments, users can determine the size of an array dimension at runtime by using the intrinsic length() function.
// Get the number of axes specified
var $numAxes as integer = length($axes)
end
Function Return Value
A function can be defined to either return no value or return one value.
function Foo($value as integer)
$iglobal[0] = $value
end
// Function that returns a value
function Bar($index as integer) as integer
return $iglobal[$index]
end
If a function returns a value, the data type of that value can be any of the fundamental data types (integer, real, string, axis, or handle), or a user-defined enum type. Aggregate data types, such as an array of values or a user-defined struct, cannot be returned from a function. However, aggregate data types can be modified by a function by specifying an argument with the desired data type with the ref modifier.
Function Body Definition
Local user-defined variables may be declared within a function, and their scope will last until the end of the function. In addition, controller global variables as well as program global variables may be used within a function. Refer to Variable Scope for more information.
Something to note is that user variables in a function cannot be declared with a name that matches one of the arguments of the function. The following example shows a case of an improper variable declaration within a function.
// Illegal declaration because $inputVal is already defined to be a
// function argument
var $inputVal as real
// ...
end
Array variables declared at the program scope must have dimension sizes that are known at compilation time. However, array variables that are declared within a function may have dimensions whose size is determined by a runtime expression.
var $progArray[3] as integer // OK
var $progBad[$iglobal[2]] as real // Error, using runtime expression
end
function Foo($num as integer)
var $subArray[$num] // OK
end
Function Overloading
The concept of function overloading is the ability to create multiple functions that each have the same name but different implementations. To differentiate between multiple functions that have the same name:
-
The number arguments must differ, or:
-
The data types of arguments must differ
In many cases, the compiler will be able to determine which function to call based on the number and data types of arguments that are passed in.
var $myVar as real
// Calls MyPrint()
MyPrint()
// Calls MyPrint($input as integer)
MyPrint(123)
// Calls MyPrint($input as string)
MyPrint("Hello")
// Calls MyPrint($input as integer)
// This is because $myVar (a real) can be converted to an integer
$myVar = 10.0
MyPrint($myVar)
// Causes a compiler error because none of the MyPrint() overloads
// accept an argument which can implicitly be converted from an axis
MyPrint(X)
end
function MyPrint()
end
function MyPrint($input as integer)
end
function MyPrint($input as string)
end
In some cases, the compiler cannot determine the correct function to call based on the arguments that were passed to the function. If the compiler cannot make a decision, then a compilation error occurs.
var $result as real
var $array[2] as integer
// Can't determine which function to call since [1, 2] can be
// interpreted as both an array of integers or an array of real values
$result = MyAdd([1, 2])
// Ambiguities can be resolved by specifying a variable with the correct
// type to a function; the following will call the first function below
$array[0] = 1
$array[1] = 1
$result = MyAdd($array)
end
// This function accepts an array of integer values
function MyAdd($vals[2] as integer) as integer
return $vals[0] + $vals[1]
end
// This function accepts an array of real values
function MyAdd($vals[2] as real) as real
return $vals[0] + $vals[1]
end
An important thing to note is that the return type of a function cannot be used to differentiate between different overloaded functions. For example, declaring the following set of functions in the same program would be invalid because it is impossible for the compiler to differentiate between them.
program // Can't determine which function to call MyAdd(1, 2) end function MyAdd($val1 as integer, $val2 as integer) as integer return $val1 + $val2 end // Illegal definition function MyAdd($val1 as integer, $val2 as integer) $rglobal[0] = $val1 + $val2
end
Note that both Aerotech API functions and user-defined functions may be overloaded provided that proper overloading rules are followed. For example, the Aerotech API Home() command can be overloaded to accept a second argument that is not a list of axes, allowing you to extend the functionality provided by Aerotech.
Calling a Function
Simple Function Calling
Use the following syntax to call a function.
<Return> = <FunctionName>(<ArgumentList>)
The <ArgumentList> contains zero or more comma-separated arguments. The arguments should match the types of, or at least be able to be converted to, the types defined in a command definition. For example, a function may accept a single argument with the real type, but the function may be called with an integer if there is no overloaded function that accepts a real argument. There is a small amount of extra execution overhead when passing a real value to a function that accepts an integer argument because the controller must ensure that the real value represents a valid integer value.
However, some arguments cannot be implicitly converted from one type to another – for example, a string value cannot be passed to a function that accepts a single real argument.
The <Return> is not required when calling a function that returns a value. Omitting the <Return> can be useful when calling a function whose return value is not significant.
// Ignore the function's return value
MyFunc(3.0)
end
// This function returns a value
function MyFunc($input as real) as real
$rglobal[0] = $input
return $rglobal[0]
end
However, specifying a <Return> when the function does not return a value will result in a compilation error.
// This causes a compiler error
$rglobal[0] = MyOtherFunc()
end
// This function does not return a value
function MyOtherFunc()
$rglobal[10] = 10
end
If a function returns a value, then a call to that function can be used as an expression. For example, a function call can be an argument to another function or an operand in a mathematical expression.
// Move axis X to the position returned by GetNextPos()
G1 X(GetNextPos())
// Use the result of MyAdd2(3, 4) as an argument to another call to
// MyAdd2()
$rglobal[3] = MyAdd2(MyAdd2(3, 4), 5)
end
// This function returns a real value
function GetNextPos() as real
// Store the current value of $rglobal[0] in a local function variable
var $pos as real = $rglobal[0]
// Increment $rglobal[0] by 1
$rglobal[0]++
// Return the original value of $rglobal[0]
return $pos
end
// This function returns an integer value
function MyAdd2($val1 as integer, $val2 as integer) as integer
// Add the two arguments and return the result
return $val1 + $val2
end
Synchronizing Function Calls With Motion
When you use the velocity blending, cutter radius compensation, or corner rounding features, the controller must execute the program ahead of motion so that it can precalculate the moves and speeds. This operation is known as lookahead. When lookahead is active, user-defined functions are not normally synchronized with motion and will execute before motion functions that you specified in previous program lines. Refer to Lookahead Synchronization for more information.
// Enable velocity blending, which enables lookahead
VelocityBlendingOn()
MoveLinear(X, 10, 100)
MoveLinear(X, 30, 75)
// As a result of lookahead, the controller executes the following
// function call before it finishes producing motion for the previous
// move
SetGlobalVariable(32)
MoveLinear(X, 55, 80)
MoveLinear(X, 80, 30)
VelocityBlendingOff()
end
sync function SetGlobalVariable($value as integer)
$iglobal[0] = $value
end
You can use the sync() statement to synchronize a function call with motion while lookahead is active. Synchronizing a function call with motion will cause the controller to start executing the code in the function when the controller finishes generating motion from the function on the previous program line. This behavior is useful if you want to execute AeroScript code that is synchronized with motion while lookahead is active during a velocity blending, cutter radius compensation, or corner rounding sequence.
VelocityBlendingOn()
MoveLinear(X, 10, 100)
sync(nonblocking, 2) SetGlobalVariable(32) // Synchronized with motion
MoveLinear(X, 55, 80)
VelocityBlendingOff()
end
sync function SetGlobalVariable($value as integer)
$iglobal[0] = $value
end
You can use the sync() statement to execute a function on the current task or on a different task. The behavior of sync() statements depends on the state of the specified task at the time that the function is called. For example, a sync() statement that executes a function on a task on which lookahead is active can disable lookahead temporarily on that task, which can cause a slowdown to zero velocity during velocity blending, or a change in programmed part geometry in a cutter radius compensation or corner rounding sequence. Refer to the following example for a program that executes synchronized functions on two different tasks, assuming that the program is not run on Task 3.
VelocityBlendingOn()
MoveLinear(X, 10, 100)
MoveLinear(X, 30, 75)
// Execute SetGlobalVariable() on this task, synchronously with motion
sync(nonblocking) SetGlobalVariable(0, 1)
// Execute SetGlobalVariable() on Task 3, synchronously with motion
sync(nonblocking, 3) SetGlobalVariable(1, 10)
MoveLinear(X, 55, 80)
MoveLinear(X, 80, 30)
VelocityBlendingOff()
end
sync function SetGlobalVariable($index as integer, $value as integer)
$iglobal[$index] = $value
end
The function that you call with sync() must be a user-defined function that you defined in the same program, or a user-defined function from a library that you import.
Syntax for Calling a Function Synchronously
Use the following syntax to use a sync() statement.
The syntax of the <FunctionCall> is the same as a normal function call that is not specified to a sync() statement. Refer to Simple Function Calling for the syntax of a <FunctionCall>.
If you specify the blocking keyword, the controller waits for the called function to finish executing before executing the next program line. If you specify the nonblocking keyword, the program will not wait for the called function to finish executing before executing the next program line. Refer to the Blocking and Non-Blocking Motion-Synchronized Function Calls section for more information.
Use the <Task> argument to specify the task on which the function will execute. The <Task> argument may be any numeric expression. If you do not specify a <Task> argument, the controller will execute the function in the sync() statement on the current task.
Enable([X, Y])
Home([X, Y])
VelocityBlendingOn(X)
MoveLinear(X, 10, 100)
// Execute StartJogging() synchronously on Task 2
sync(nonblocking, 2) StartJogging(Y)
// Execute SetGlobalVariable() synchronously on the current task
sync(nonblocking) SetGlobalVarible(6)
MoveLinear(X, 30, 50)
end
sync function StartJogging($axis as axis)
MoveFreerun($axis, 50)
end
sync function SetGlobalVariable($value as integer)
$iglobal[3] = $value
end
Declaring a Function That Can Execute Synchronously
A function that you specify in a sync() statement must be defined according to the following rules:
-
You must specify the sync keyword before the function keyword.
-
Any function arguments must be one of the following types:
- integer
- real
- axis
- handle
- enum
-
Any function arguments have the following restrictions:
-
The arguments cannot be specified with the ref modifier.
-
No array, struct, or string arguments are permitted.
-
-
You cannot specify a return type for the function.
-
Program global variables cannot be used within the function.
// of the program/end block
var $globProgVar as real
program
sync(blocking) Foo(3)
end
// This is a valid synchronous function definition
sync function SetIGlobal0($value as integer)
$iglobal[0] = $value
end
// The following synchronous function definition will cause a compiler
// error because the ref modifier is used with an argument
sync function UpdateValue(ref $value as integer)
$value = 3
end
// The following synchronous function definition will cause a compiler
// error because the function returns a value
sync function GetPosition($axis as axis) as real
return StatusGetAxisItem($axis, AxisStatusItem.PositionCommand)
end
// The following synchronous function definition will cause a compiler
// error because the function accesses a program global variable
sync function UpdateProgramVariable($value as real)
$globProgVar = $value
end
Blocking and Non-Blocking Motion-Synchronized Function Calls
Use the blocking keyword in a sync() statement to cause the program to wait for the controller to finish executing the function before executing the next program line in the program. For example, specify the blocking keyword to a sync() statement during a cutter radius compensation or corner rounding sequence to cause the controller to execute the function synchronously with motion without affecting the geometry of the path that you programmed and to prevent further motion in the sequence until the controller finishes executing the function.
Use the nonblocking keyword in a sync() statement to cause the controller to execute the next program line in the program to execute without waiting for the function to complete. For example, specify the nonblocking keyword to a sync() statement during a velocity blending sequence to execute the function synchronously with motion. If you execute the function on the current task and the function completes very quickly, or if you execute the function on a different task, you can prevent decelerations to zero velocity during the velocity blending sequence.
Blocking Motion-Synchronized Function Calls
Use the blocking keyword in a sync() statement to cause the program to wait for the controller to finish executing the function before executing the next program line in the program.
In a cutter radius compensation or corner rounding sequence, if you execute a function from the Functions That Lookahead Cannot Look Through section of Lookahead Synchronization, the controller will temporarily disable lookahead, which can prevent those features from generating the correct motion, such as not rounding corners in a corner rounding sequence. In a cutter radius compensation or corner rounding sequence, you can specify those functions in a function that you call with a sync() statement using the blocking keyword to prevent those functions from temporarily disabling lookahead and causing the controller to generate incorrect motion, while causing the controller to wait for the function to finish executing. Refer to the following example to see how you can use a sync() statement to execute a function synchronously with motion during a cutter radius compensation sequence without affecting the programmed path and waiting until the function completes.
Enable([X, Y, Z])
Home([X, Y, Z])
// Start a cutter radius compensation sequence
G44 X Y
G43 P0.025
G41 G1 X5 Y5
G1 Y10
G1 X10
// Perform a blocking synchronous function call in the middle of the
// cutter radius compensation sequence
sync(blocking) TriggerFreerun(Z)
G1 Y-10
G1 X-10
// Deactivate cutter radius compensation
G40 X0 Y0
end
sync function TriggerFreerun($axis as axis)
// MoveFreerun() would normally affect the geometry of the cutter
// radius compensation sequence, but executing as part of a sync()
// statement causes it to preserve the correct geometry
MoveFreerun($axis, 100)
end
In a velocity blending sequence, use the blocking keyword in a sync() statement to cause the controller to decelerate to zero velocity before executing the specified function. Refer to the following example to see how you can use a sync() statement to execute a function synchronously with motion during a velocity blending sequence while forcing a slowdown to zero velocity.
Enable(X)
Home(X)
// Start a velocity blending sequence
VelocityBlendingOn()
MoveLinear(X, 10, 25)
// Perform a blocking synchronous function call in the middle of the
// velocity blending sequence, forcing a slowdown to zero velocity
// before the function executes
sync(blocking) SetAnalogOutput(Z, 2.5)
MoveLinear(X, 30, 30)
// Deactivate velocity blending
VelocityBlendingOn()
end
sync function TriggerFreerun($axis as axis)
// AnalogOutputSet() is synchronized with motion, so specifying it
// between the moves in the program above would cause it to execute
// without forcing a slowdown to zero velocity; However, calling the
// function in a blocking sync() statement forces the controller to
// decelerate motion before the function is called
MoveFreerun($axis, 100)
end
Non-Blocking Motion-Synchronized Function Calls
Use the nonblocking keyword in a sync() statement to cause the controller to execute the next program line in the program to execute without waiting for the function to complete.
In a cutter radius compensation or corner rounding sequence, if you execute a function from the Functions That Lookahead Cannot Look Through section of Lookahead Synchronization, the controller will temporarily disable lookahead, which can prevent those features from generating the correct motion, such as not rounding corners in a corner rounding sequence. In a cutter radius compensation or corner rounding sequence, you can specify those functions in a function that you call with a sync() statement using the nonblocking keyword to prevent those functions from temporarily disabling lookahead and causing the controller to generate incorrect motion, while causing the controller to execute the next program line before the controller finishes executing the function. Refer to the following example to see how you can use a sync() statement to execute a function synchronously with motion during a cutter radius compensation sequence without affecting the programmed path and immediately continuing program execution without waiting until the function completes.
program
Enable([X, Y, Z])
Home([X, Y, Z])
// Start a cutter radius compensation sequence
G44 X Y
G43 P0.025
G41 G1 X5 Y5
G1 Y10
G1 X10
// Perform a non-blocking synchronous function call in the middle of the
// cutter radius compensation sequence; the controller will immediately
// start executing the next move (G1 Y-10) without waiting for the
// DoMotion() function to finish executing
sync(nonblocking, 2) DoMotion(Z)
G1 Y-10
G1 X-10
// Deactivate cutter radius compensation
G40 X0 Y0
end
sync function DoMotion($axis as axis)
MoveAbsolute($axis, 100, 50)
WaitForMotionDone($axis)
MoveAbsolute($axis, 0, 75)
end
In a velocity blending sequence, use the nonblocking keyword in a sync() statement to cause the controller to execute the specified function synchronously with motion without decelerating to zero velocity. If you specify the current task to the sync() statement, and the function takes longer than one millisecond to execute, a slowdown to zero velocity can occur. You can specify a different task to the sync() statement to prevent a slowdown to zero velocity in velocity blending mode. Refer to the following example to see how you can use a sync() statement to execute a function synchronously with motion during a velocity blending sequence without affecting the velocity blending that occurs on the X axis, and immediately continuing program execution without waiting until the function completes.
Enable([X, Y])
Home([X, Y])
// Perform motion with velocity blending
VelocityBlendingOn()
G1 X10 F30
G1 X20 F50
// Perform a non-blocking synchronous function call on Task 2
// Since a call to Home() can take multiple milliseconds to execute,
// executing this function on the current task could cause a
// deceleration to zero velocity
sync(nonblocking, 2) TriggerHome(Y)
// Continue the velocity blending sequence
G1 X15 F25
G1 X25 F10
// Disable velocity blending mode
VelocityBlendingOff()
end
sync function TriggerHome($axis as axis)
// Home() would normally cause a slowdown to zero velocity when
// executed in a velocity blending sequence, but executing it in a
// non-blocking synchronous function call causes it to not slow down if
// executed on a different task
Home($axis)
end
Restrictions When Calling a Function Synchronously
If the task that you specify to a sync() statement is currently performing an AeroScript operation that is synchronized with motion, an error will occur if the function that you specify to the sync() statement contains an AeroScript operation that is synchronized with motion. For example, if a program on Task 2 is currently executing a MoveLinear() function, you cannot execute a sync() statement that calls a function with a MoveRapid() function on Task 2 at the same time. Refer to the Function Synchronization During Lookahead section of Lookahead Synchronization for operations that are synchronized with motion.
If you execute a sync() statement from a task that is currently performing velocity blending, cutter radius compensation, or corner rounding, the function that you execute cannot have any of the same axes that are active as part of those features.
Next Topic: Libraries