minute read

Command Queue in the .NET API

You are reading our Automation1 API documentation for the .NET programming language.

In the .NET API, Command Queue lets you execute AeroScript commands on the Automation1 controller in a first-in, first-out process.

IMPORTANT: Before you read more about the command queue, read the .NET API Commands page. This page adds to that information.

The Basics

When you execute non-queued AeroScript commands through the .NET API, a quantity of fixed overhead occurs. There will be some delay between commands when you execute two of them, one right after the other. This delay averages from 3 to 5 milliseconds, based on the performance of the PC. It also includes all the network latency delays that might occur. If this delay is not compatible with your production environment, use Command Queue.

Command Queue lets you queue up multiple commands on the controller to prevent overhead and delay. Some AeroScript commands are available only in Command Queue because they cannot accept this overhead and delay. These commands include all the AeroScript commands that require Lookahead Synchronization, such as velocity blending, cutter radius compensation, and corner rounding. If you execute a series of MovePt() or MovePvt() commands, this process also requires a command queue. If you do not use one, your profile will stutter and drop out because of the delay that occurs between commands. If you are doing submillisecond PVTs, you must add the PVTs inside of a CriticalSectionStart() / CriticalSectionEnd() block. If you do not use the critical section functions, the motion will not be continuous. Refer to the Task Scheduling section on the Task and Program Functions page for more information.

A command queue on a task stores all the AeroScript commands that you add. It executes them sequentially, in the order that they were added, which is a first-in, first-out process. If you add AeroScript commands to the command queue, the .NET function that you called to add the commands does not block unless the conditions that follow occur:

  • The command queue is full.
  • You specified the command queue to block when it is full.

If these two conditions do not occur, the AeroScript commands are added to the command queue. But all the commands that were previously added execute first. Then the AeroScript commands will execute.

Typically, a command queue is necessary for you to use when one of these use-cases apply:

  • Your process cannot accept the delay that occurs between executing AeroScript commands.
  • You want to use AeroScript commands that are compatible only with a command queue.

A command queue exists on a specific controller task. That task can execute only queued commands while the command queue is active. While a command queue is active, the restrictions that follow apply:

  • Non-queued AeroScript commands cannot execute.
  • AeroScript programs cannot run.
  • You cannot use retrace.
  • You cannot use interrupt motion.
  • You cannot use the AeroScript sync statement to execute a function on the controller task where a command queue exists. You can use the AeroScript sync statement to execute a function on a different task.
  • You cannot use the AeroScript statements that follow:
    • program statement
    • if statement
    • switch statement
    • goto statement
    • break statement
    • continue statement
    • while loop
    • for loop
    • foreach loop
    • repeat loop
  • You cannot declare an AeroScript variable, struct, enum, property, or function.
  • You cannot execute the AeroScript functions that follow:
    • ProgramStop()
    • ProgramPause()
    • ProgramReset()
    • ProgramRestart()
    • ProgramLoad()
    • ProgramStepInto()
    • ProgramStepOver()
    • ProgramStepOut()
  • AeroScript functions apply all relative paths as absolute paths.

How to Use

In the .NET API, Command Queue is part of the Controller.Runtime property. For all the APIs that operate under this property, the Automation1 controller must be running before you can do work with a command queue. For more information about this property, see the Controller page. If you reset the Automation1 controller, this process will stop all the active command queues.

To use a command queue, you must first begin a command queue on a specific task and with a specific AeroScript command capacity. The shouldBlockIfFull argument controls the behavior of how an AeroScript command is added to a command queue that is full:

  • If you specify the argument as true, the add blocks until the AeroScript command can be added to the queue.
  • If you specify the argument as false, the add throws an exception.

Refer to the example that follows.

Copy
CommandQueue commandQueue = controller.Runtime.Commands.BeginCommandQueue(string taskName, int commandCapacity, bool shouldBlockIfFull);

The command capacity specifies the maximum number of AeroScript commands that you can add to the command queue before it is full. When the command queue is full, you cannot continue to add new AeroScript commands. A larger command capacity uses more controller memory. The controller memory is limited.

WARNING: If you specify a command capacity that is too large, memory allocation errors can occur. If they occur, you must decrease your command capacity.

When the command queue begins on a specific task, non-queued AeroScript commands cannot execute and AeroScript programs cannot run on that task.

When the command queue begins on a specific task, the execution of commands is not paused. Thus, AeroScript commands that you add to the queue will immediately start to execute and the state of the task becomes Queue Running. If you enable the feedhold state on the task, the state of the task stays Queue Running.

If you want to pause the execution of commands in the command queue, use the Pause method. This method pauses the execution of commands from the command queue after the controller finishes executing the current command and the state of the task becomes Queue Paused. Refer to the example that follows.

Copy
commandQueue.Pause();

If the execution of commands in the command queue is paused, you can use the Resume method to resume the execution of commands. Refer to the example that follows.

Copy
commandQueue.Resume();

The CommandQueue object has the Commands property. You can use this property to add AeroScript commands to the command queue. When you add AeroScript commands, they are not executed immediately. Instead, they are queued for execution. All the commands that you previously added are executed first. Then the newest AeroScript commands that you added will execute. These methods do not block unless the conditions that follow occur:

  • The command queue is full.
  • You specified the command queue to block when it is full.

Refer to the example that follows.

Copy
commandQueue.Commands.Motion.Enable(string axis);
commandQueue.Commands.Motion.MoveLinear(string axis, double distance, double coordinatedSpeed);
commandQueue.Commands.Motion.Disable(string axis);

To see a list of all the .NET properties and methods that you can use for Command Queue, refer to the Full Reference section.

While the command queue is active, you can examine its status to find the information that follows:

  • The number of AeroScript commands that were executed.
  • The number of AeroScript commands in the command queue that still need to be executed.

Refer to the example that follows.

Copy
commandQueue.Status.IsEmpty
commandQueue.Status.NumberOfExecutedCommands
commandQueue.Status.NumberOfUnexecutedCommands

Each time that you access the Status property, you get a new status from the controller. For best results, access the Status property one time only to get the most current status. Then use the returned CommandQueueStatus object until you need to get the most current status of the controller again. If you do not do this and try to access the Status property too many times, bugs known as race conditions can occur. These bugs occur when the status of the task changes between multiple accesses of the property.

If you want to wait for the command queue to empty and complete its execution of all the commands that you added to it, use the WaitForEmpty method. This method blocks until the command queue is fully empty. Then this method returns and your code execution continues. Refer to the example that follows.

Copy
commandQueue.WaitForEmpty();

When you are done using the command queue, call the EndCommandQueue method to end the command queue and return the task to its normal state. Refer to the example that follows.

Copy
controller.Runtime.Commands.EndCommandQueue(CommandQueue commandQueue);

If you end a command queue that is currently executing a command, that command is aborted and all the queued AeroScript commands are discarded. To prevent this from occurring, use the WaitForEmpty method when you end the command queue. This method makes sure that the command queue is not executing commands.

After you end the command queue, non-queued AeroScript commands can execute and AeroScript programs can run on that task. You cannot continue to use the CommandQueue object. To make a new command queue, you must call the BeginCommandQueue method again.

Execute Custom AeroScript

You can execute most AeroScript commands through the .NET API. In some special cases, you must execute custom AeroScript directly or execute a file that includes custom AeroScript.

Execute Custom AeroScript Directly

To execute custom AeroScript directly, use the CommandQueue.Commands.Execute method to specify the arbitrary AeroScript that you want to add to the command queue. Refer to the example that follows.

Copy
commandQueue.Commands.Execute(string stringAeroScript);

stringAeroScript can include multiple lines of AeroScript. You can separate lines of AeroScript with newline characters, including CR, NL, CRNL. If the string has multiple lines, TaskStatusItem.ProgramLineNumber and TaskStatusItem.CommandQueueLineNumber will be incremented by the number of lines in the string, but TaskStatusItem.CommandQueueExecutedCount and CommandQueueStatus.NumberOfExecutedCommands will be incremented by 1. This occurs because there is a difference between lines of AeroScript and a command that has multiple lines of AeroScript. If you add a newline to the end of stringAeroScript, TaskStatusItem.ProgramLineNumber, TaskStatusItem.CommandQueueLineNumber, TaskStatusItem.CommandQueueExecutedCount, and CommandQueueStatus.NumberOfExecutedCommands will be incremented an additional time. To prevent this, do not add a newline to the end.

Execute Custom AeroScript from a File

The .NET API can automatically insert lines of AeroScript as commands into a command queue. You can do this with an MDK file or a controller file. This process can help you if you already have a file that includes all of your AeroScript or if you want to separate your AeroScript process from your custom .NET application. The specified file can include only simple lines of AeroScript. The file cannot include variables, if statements, loops, or other control flow statements.

To execute an MDK file that has lines of AeroScript, use the CommandQueue.Commands.ExecuteFromMdkFile method. To execute a controller file that has lines of AeroScript, use the CommandQueue.Commands.ExecuteFromControllerFile method. For more information about the MDK and controller file systems, see Working with Files.

Aerotech recommends that you set CommandQueue.ShouldBlockIfFull to true when you create the command queue that is executed from a file. If it is set to false and the command queue fills while reading the file, a ControllerOperationException will be thrown.

To increase throughput, lines of AeroScript from the file are added to the command queue as commands that have multiple lines. By default, numberOfLinesPerCommand is set to 1000, which works in most cases. The numberOfLinesPerCommand argument defines how many file lines to read from the file for each command. If the command queue is empty before the file is fully read, call the overload of CommandQueue.Commands.ExecuteFromMdkFile or CommandQueue.Commands.ExecuteFromControllerFile with the numberOfLinesPerCommand argument set to a value greater than 1000. The value of the numberOfLinesPerCommand depends on the performance of your PC and is not deterministic.

IMPORTANT: If you specify a value for numberOfLinesPerCommand that is too large, memory allocation errors can occur. If you get memory allocation errors, decrease the value of the numberOfLinesPerCommand.

When CommandQueue.Commands.ExecuteFromMdkFile or CommandQueue.Commands.ExecuteFromControllerFile return, there can be lines of AeroScript from the file that have not executed and are still in the command queue. Use the CommandQueue.WaitForEmpty method to make sure all AeroScript commands have executed. Refer to the example that follows.

Copy
CommandQueue commandQueue = controller.Runtime.Commands.BeginCommandQueue("Task 1", 100, true);
commandQueue.Commands.ExecuteFromMdkFile("MovePvt20kHz.txt", 1000);
commandQueue.WaitForEmpty();

Executing blank lines on the command queue will not cause an exception.

AeroScript Commands

You can use AeroScript commands to change the state of a command queue.

If the execution of queued AeroScript commands from the command queue is not currently paused, use the functions that follow to pause the execution of commands from the queue.

Copy
CommandQueuePause()
CommandQueuePause($task as integer)

If the execution of queued AeroScript commands from the command queue is currently paused, use the function that follows to resume the execution of commands from the queue.

Copy
CommandQueueStart($task as integer)

Use the functions that follow to end the command queue.

Copy
CommandQueueStop()
CommandQueueStop($task as integer)

Keep a Command Queue Full

WARNING: You must keep the command queue populated at all times. If the command queue is not populated, your process will stall and motion problems might occur.

When the command queue begins on a task, the controller executes all the commands that are in the command queue as quickly as possible. If the controller automatically executes commands from the command queue more quickly than you can add them, the command queue will not have a sufficient quantity of commands to execute. This condition is known as a starvation of the command queue.

While the command queue is active, you can examine its status to find the number of times that a starvation of the command queue has occurred. Refer to the example that follows.

Copy
commandQueue.Status.NumberOfTimesEmptied

For the axes that you specify to a command, the controller automatically decelerates them to zero velocity to prevent motion problems from occurring when all the conditions that follow are true:

  • Velocity Blending mode is enabled on the task.
  • A starvation of the command queue occurs.
  • The most recently executed command from the command queue is a MoveCcw(), MoveCw(), or MoveLinear() command.

But when the two conditions that follow are true, the controller does not automatically decelerate the axes that you specify to a command to zero velocity:

  • A starvation of the command queue occurs.
  • The most recently executed command from the command queue is a MovePt() or MovePvt() command.

As a result, motion problems can occur.

To prevent a starvation of the command queue, do one or more of the options that follow:

  • Issue a Dwell() command as the first command. Also issue it in other important locations. When you issue the Dwell() command in multiple locations, you get more time to add commands to the command queue before the controller executes them.

  • Pause the command queue before you add more commands. You can pause the command queue by using the CommandQueue.Pause() method. You can also issue a CommandQueuePause() command as the first command.

  • Issue a wait statement first. Then use the CommandQueueCount task status item to make the first command wait for the command queue to fill with a specified number of commands before the controller executes them. Refer to the code sample that follows:

Copy
commandQueue.Execute("wait(StatusGetTaskItem ... >= 20)");

Example Code

For more information about how to use a command queue, refer to the example program that follows.

Copy
// Begin a new command queue on task 1.
CommandQueue commandQueue = controller.Runtime.Commands.BeginCommandQueue("Task 1", 10, true);
 
// First, pause the command queue so you can add all the commands before they are executed.
commandQueue.Pause();
 
// Add all the AeroScript commands that you want to execute.
commandQueue.Commands.AdvancedMotion.VelocityBlendingOn();
commandQueue.Commands.Motion.Enable("X");
commandQueue.Commands.Motion.MoveLinear("X", 10, 5);
commandQueue.Commands.Motion.MoveLinear("X", 5, 5);
commandQueue.Commands.Motion.Disable("X");
commandQueue.Commands.AdvancedMotion.VelocityBlendingOff();
 
// Resume the command queue so that all the commands that you added start to execute.
commandQueue.Resume();
 
// Here you can do other things such as more process, get status, etc. 
// You can do these things because the command queue is executing commands on the controller and is not blocking your code execution.
 
// Here you wait to make sure that the command queue executes all the commands. You must do this before you end the command queue.
// When you end the command queue, this process aborts all motion and commands.
commandQueue.WaitForEmpty();
 
// At this time, end the command queue.
// You can also call CommandQueue.EndCommandQueue to abort the command that is currently executing and discard the remaining commands.
controller.Runtime.Commands.EndCommandQueue(commandQueue);

Thread Safety

The Controller.Runtime.Commands.BeginCommandQueue method is thread safe. You can call it from two or more threads without interference.

The CommandQueue class is not thread safe. Only one thread at a time can access an instance of this class. If it is necessary for two or more threads to access or change an instance of this class, you must use locks to limit the access. You must also use locks when you pass a CommandQueue instance to the Controller.Runtime.Commands.EndCommandQueue method.

The Controller.Runtime.Commands.EndCommandQueue method is thread safe. You can call it from two or more threads without interference. But if you pass the CommandQueue instance into this method, this instance is not thread safe. If it is necessary for two or more threads to access or change an instance of the CommandQueue class, you must use locks to limit the access.

Full Reference

For more information about the properties and methods that are available for Command Queue, refer to the lists that follow.

CommandQueue Properties

CommandQueue Methods

CommandQueueStatus Properties