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.

function MyInit($axes[] as axis)
   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 with function definitions
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.

// Program without function declarations
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.

function <FunctionName>(<ArgumentList>) as <ReturnType>
   <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.

function <FunctionName>(<ArgumentList>)
   <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 without a return value
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> as <DataType>
<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.

program
   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.

program
   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.

program
   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.

function Foo($axes[] as axis)
   // 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 that returns no 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.

function MyFunc($inputVal as real)
   // 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.

program
   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.

program
   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.

program
   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.

<FunctionName>(<ArgumentList>)
<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.

program
   // 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.

program
   // 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.

program
   // 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.

program
   // 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.

program
   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.

program
   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.

sync(nonblocking)<FunctionCall>
sync(nonblocking, <Task>) <FunctionCall>
sync(blocking)<FunctionCall>
sync(blocking, <Task>) <FunctionCall>

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.

program
   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.

// $globProgVar is a program global variable since it is declared outside
// 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.

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 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.

program
   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.

// This program executes on Task 1
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.

program
   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