minute read

Command Queue in the C API

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

The Basics

In the C 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, make sure that you read the Commands page first. This page builds on that information.

When you execute non-queued AeroScript commands through the C API, a quantity of fixed overhead occurs. When you execute two commands, one immediately after the other, there is some delay that occurs between the commands. This delay averages from 3 to 5 milliseconds, based on network latency and the performance of the PC. It also includes all the network latency delays that might occur.

IMPORTANT: If this delay is not compatible with your production environment, use Command Queue.

Command Queue lets you queue 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 the 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 C 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 will execute first. Then the AeroScript commands will execute.

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

  • Your process cannot accept the delay that occurs between AeroScript commands that are executing.
  • 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.

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.

If the command queue is emptied, this will interrupt any velocity blending or lookahead synchronization and the axes will decelerate to zero velocity. Make sure that you add AeroScript commands to the command queue faster than the command queue can execute them.

Tip: After you begin a command queue, you might want to pause it. Then you can add many AeroScript commands before you continue the command queue.

How to Use

Command Queue is part of the controller runtime. Thus the Automation1 controller must be running before you do work with a command queue. For more information, 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. Use the Automation1_CommandQueue_Begin() function. This function gives you an Automation1CommandQueue handle. 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 returns an error.
Copy
bool Automation1_CommandQueue_Begin(Automation1Controller controller, int32_t taskIndex, int32_t commandCapacity, bool shouldBlockIfFull, Automation1CommandQueue* commandQueueOut);

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.

You can use functions to add AeroScript commands to the command queue. These functions require an Automation1CommandQueue handle. 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 functions 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.
Copy
bool Automation1_CommandQueue_Enable(Automation1CommandQueue commandQueue, int32_t* axes, int32_t axesLength);
bool Automation1_CommandQueue_MoveLinear(Automation1CommandQueue commandQueue, int32_t* axes, int32_t axesLength, double* distances, int32_t distancesLength, double coordinatedSpeed);
bool Automation1_CommandQueue_Disable(Automation1CommandQueue commandQueue, int32_t* axes, int32_t axesLength);

To see a list of all the C functions that you can use for Command Queue, refer to the Full Reference section of this page.

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.
Copy
bool Automation1_CommandQueue_GetStatus(Automation1CommandQueue commandQueue, Automation1CommandQueueStatus* commandQueueStatusOut);

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 Automation1_CommandQueue_WaitForEmpty() function. This function blocks until the command queue is fully empty. Then this function returns and your code execution continues.

Copy
bool Automation1_CommandQueue_WaitForEmpty(Automation1CommandQueue commandQueue, int32_t millisecondsTimeout);

When you are done using the command queue, call the Automation1_CommandQueue_End() function. This function ends the command queue, frees memory, and returns the task to its normal state.

Copy
Automation1_CommandQueue_End(Automation1CommandQueue commandQueue, int32_t millisecondsTimeout);

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 Automation1_CommandQueue_WaitForEmpty() function when you end the command queue. This function 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 Automation1CommandQueue handle. To make a new command queue, you must call the Automation1_CommandQueue_Begin() function again.

Execute Custom AeroScript

You can execute most AeroScript commands through the C API. In some special cases, you have to execute custom AeroScript directly or execute a file with custom AeroScript.

Execute Custom AeroScript Directly

To execute custom AeroScript directly, use the Automation1_CommandQueue_Execute function to specify the arbitrary AeroScript that you want to add to the command queue. Refer to the example that follows.

Copy
bool Automation1_CommandQueue_Execute(Automation1CommandQueue commandQueue, const char* aeroScriptText);

aeroScriptText can include multiple lines of AeroScript. You can separate multiple lines of AeroScript with newline characters, including CR, NL, CRNL. If Automation1TaskStatusItem_ProgramLineNumber and Automation1TaskStatusItem_CommandQueueLineNumber have multiple lines, they will be incremented by the number of lines in the string. If Automation1TaskStatusItem_CommandQueueExecutedCount and Automation1CommandQueueStatus struct member NumberOfExecutedCommands have multiple lines, they will be incremented by 1 because there is a difference between lines of AeroScript and a command that has multiple lines of AeroScript. If you append a newline to the end of aeroScriptText, Automation1TaskStatusItem_ProgramLineNumber, Automation1TaskStatusItem_CommandQueueLineNumber, Automation1TaskStatusItem_CommandQueueExecutedCount, and Automation1CommandQueueStatus struct member NumberOfExecutedCommands will be incremented an additional time. To prevent this, do not add a newline to the end.

Execute Custom AeroScript from a File

You can have the C API read from a file and 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 with all of your AeroScript or if you want to separate your AeroScript process from your custom C application. The specified file can only include simple lines of AeroScript. The file cannot have variables, if statements, loops, or other control flow statements.

To execute an MDK file that has lines of AeroScript, use the Automation1_CommandQueue_ExecuteFromMdkFile() function. To execute a controller file that has lines of AeroScript, use the Automation1_CommandQueue_ExecuteFromControllerFile() function. For more information about the MDK and controller file systems, see Working with Files.

Aerotech recommends that you set the argument 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, then Automation1_CommandQueue_Execute or Automation1_CommandQueue_ExecuteFromFile will return false.

To increase throughput, lines of AeroScript from the file are added to the command queue as commands that have multiple lines. The numberOfLinesPerCommand argument defines how many file lines to read from the file for each command. You can set the numberOfLinesPerCommand to 1000, which works in most cases. If the command queue is empty before the file is fully read, set the numberOfLinesPerCommand to more than 1000. The value of the numberOfLinesPerCommand depends on the performance of your PC and is not deterministic.

WARNING: 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 Automation1_CommandQueue_ExecuteFromMdkFile or Automation1_CommandQueue_ExecuteFromControllerFile return, there can be lines of AeroScript from the file that have not executed and are still in the command queue. Use the Automation1_CommandQueue_WaitForEmpty method to make sure all AeroScript commands have executed. Refer to the example that follows.

Copy
Automation1CommandQueue commandQueueOut = NULL;
if (!Automation1_CommandQueue_Begin(controller, 1, 100, true, &commandQueueOut)) { /* handle error */}
if (!Automation1_CommandQueue_ExecuteFromMdkFile(commandQueueOut,   "MovePvt20kHz.txt" , 1000)) { /* handle error */ }
if (!Automation1_CommandQueue_WaitForEmpty(commandQueue, -1)) { /* handle error */ }

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

Example Code

Copy
int32_t task1 = 1;
int32_t axisX = 0;
double distance1 = 10.0;
double distance2 = 10.0;
Automation1CommandQueue commandQueue = NULL;

// Begin a new command queue on task 1.
if (!Automation1_CommandQueue_Begin(controller, task1, 10, true, &commandQueue)) { /* handle error */ }

// First, pause the command queue so that you can add all the commands before they are executed.
if (!Automation1_CommandQueue_Pause(commandQueue)) { /* handle error */ }

// Add all the AeroScript commands that you want to execute.
if (!Automation1_CommandQueue_VelocityBlendingOn(commandQueue)) { /* handle error */ }
if (!Automation1_CommandQueue_Enable(commandQueue, &axisX, 1)) { /* handle error */ }
if (!Automation1_CommandQueue_MoveLinear(commandQueue, &axisX, 1, &distance1, 1, 5.0)) { /* handle error */ }
if (!Automation1_CommandQueue_MoveLinear(commandQueue, &axisX, 1, &distance2, 1, 5.0)) { /* handle error */ }
if (!Automation1_CommandQueue_Disable(commandQueue, &axisX, 1)) { /* handle error */ }
if (!Automation1_CommandQueue_VelocityBlendingOff(commandQueue)) { /* handle error */ }

// Resume the command queue so that all the commands that you added start to execute.
if (!Automation1_CommandQueue_Resume(commandQueue)) { /* handle error */ }

// 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.
if (!Automation1_CommandQueue_WaitForEmpty(commandQueue, -1)) { /* handle error */ }

// At this time, end the command queue.
// You can also call the Automation1_CommandQueue_End() function to abort the command that is currently executing and discard the remaining commands.
if (!Automation1_CommandQueue_End(commandQueue, -1)) { /* handle error */ }

// Set the command queue handle to null because it is not valid after you end the command queue.
commandQueue = NULL;

Thread Safety

The Automation1_CommandQueue_Begin() function is thread safe. You can call it from two or more threads without interference.

The Automation1_CommandQueue_End() function is not thread safe. Only one thread should call this function for a single Automation1CommandQueue handle.

The other Automation1_CommandQueue_ functions and the Automation1CommandQueue handle are not thread safe. Only one thread at a time can call these functions or access this handle. If it is necessary for two or more threads to call these functions or access this handle, you must use locks to limit the access.

Full Reference

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

Automation1CommandQueueStatus struct

Represents the status of a command queue on an Automation1 controller.

Functions