6.5. XILab scripts

XILab scripting language is implemented using QtScript, which in turn is based on ECMAScript.

ECMAScript is the scripting language standardized by Ecma International in the ECMA-262 specification and ISO/IEC 16262.

QtScript (and, by extension, XILab) uses third edition of the ECMAScript standard.

6.5.1. Brief description of the language

6.5.1.1. Data Types

ECMAScript supports nine primitive data types. Values of type Reference, List, and Completion are used only as intermediate results of expression evaluation and cannot be stored as properties of objects. The rest of the types are:

  • Undefined,
  • Null,
  • Boolean,
  • String,
  • Number,
  • Object.

6.5.1.2. Statements

Most common ECMAScript language statements are summarized below:

Name Usage Description
Block {[<statement list>]} Several statements may be grouped into a block using braces.
Variable declaration var <varialble declaration list> Variables are declared using “var” keyword.
Empty statement ; Semicolon denotes an empty instruction. It is not required to end a line with a semicolon.
Conditional execution if (<condition>) <instruction> [ else <instruction> ] Conditional execution is done using “if … else” keywords. If a condition is true, then “if”-block instruction is executed, else an “else”-block instruction is executed.
Loop do <loop body> while (<condition>) while (<condition>) <loop body> for ([<initialization>]; [<condition>]; [<iterative statement>]) <loop body> Loops have several forms. A “do … while …” loop executes loop body and then checks if condition is true or false to see whether it should stop or continue running. A “while … do …” loop repeatedly checks the condition and executes loop body if it is true. A “for …” loop executes an initialization statement once, then executes an iterative statement and loop body while the condition is true.
Return return [<expression>] Stops function execution and returns expression as a result.
Exception throw <expression> Generates or “throws” an exception, which may be processed by the “try” statement (see below).
Try-catch block try <block> catch (<identifier>) <block> try <block> finally <block> try <block> catch (<identifier>) <block> finally <block> Used together with exceptions. This statement tries to execute its “try”-block. If an exception is thrown in it, then a “catch”-block is executed. Finally a “finally”-block is executed unconditionally. Either a “catch” or a “finally” block may be omitted.

6.5.1.3. Variable statements

Variables are declared using var keyword. A declared variable is placed within visibility scope that corresponds to the function in which it is declared. If the variable is declared outside of functions, it is placed in the global visibility scope. Variable is created when the function within which it was declared, or, if the variable is global, at the start of the application. When a variable is created it is initialized with Undefined value. If a variable is created with initialization, the initialization does not occur in the moment of variable creation, it happens when the string with the var statement executes.

6.5.1.4. Reserved words

The following words are the reserved keywords in the language and may not be used as identifiers:

break     else        new     var
case      finally     return  void
catch     for         switch  while
continue  function    this    with
default   if          throw
delete    in          try
do        instanceof  typeof

The following words are used as keywords in proposed extensions and are therefore reserved to allow for the possibility of future adoption of those extensions:

abstract  enum        int        short
boolean   export      interface  static
byte      extends     long       super
char      final       native     synchronized
class     float       package    throws
const     goto        private    transient
debugger  implements  protected  volatile
double    import      public

6.5.1.5. Functions

Functions are objects in ECMAScript. Functions like any other objects can be stored in variables, objects and arrays, can be passed as arguments to other functions and can be returned by functions. Functions, like any other objects may have properties. Essential specific feature of functions is that they can be invoked.

In the application text, the most common way to define a function is:

function sum(arg1, arg2) { // a function which takes two parameters
    return arg1 + arg2;    // and returns their sum
}

6.5.2. Syntax highlighting

Script window text has syntax highlighting. Its colors are:

Statement type color text example
Arbitrary functions purple image1
XILab functions blue image2
Positive numbers green image3
Negative numbers red image4
Comments grey image5
The rest of the text black image6

During the script execution the background of line with the last executed command is changed to dark gray with update rate of once in every 20 ms.

6.5.3. Additional XILab functions

This image shows XILab functions which are available from scripts, aside from standard built-in language functions.

image6

  • log(string text [, int loglevel]) – save text to the XILab log
  • msleep(int ms) - delay script execution
  • new_axis(int serial_number) - create new axis object
  • new_file(string filename) - create new file object
  • new_calibration(int A, int Microstep) - create calibration structure to pass to calibrated functions
  • get_next_serial(int serial) - get next serial out of an ordered list of opened controller serials
  • command_wait_for_stop(int refresh_period) - wait until controller stops moving
  • and all libximc library functions (see Programming guide)

Also, all constant values from the communication protocol are defined and can be used in scripts. Usage example.

6.5.3.1. XILab log

Logging is done by calling log(string text [, int loglevel] ) function. This function adds the text line to the XILab log. If the second loglevel parameter is passed the message receives the appropriate logging level and is displayed in corresponding color.

Loglevel Type
1 Error
2 Warning
3 Info

Example:

var x = 5;
log("x = " + x);

Function usage example

Note: It is not recommended to invoke functions that interact with XILab user interface (i.e. logging function) with a frequency of more than once in 20 ms.

6.5.3.2. Script execution delay

Script is paused by calling the msleep(int ms) function, which suspends script execution for ms milliseconds.

Example:

msleep(200);

Function usage example.

6.5.3.3. New axis object creation

XILab multi-axis interface provides the ability to manage controllers via scripts. The difference from the single-axis case is that you should specify the controller which receives the command. An “axis” object is introduced to abstract this concept. It has methods which match the libximc library function names. Controllers are identified by their serial numbers.

Example:

var x = new_axis(123);
x.command_move(50);

In this example first line of the script creates an axis-type object with the variable name “x”, which tries to use controller with the serial number “123”. If this controller is not connected, then the script will return an error and terminate. The second line of the script sends a “move to position 50” command to this controller.

Function usage example.

6.5.3.4. New file object creation

XILab scripts can read from and write to files. To do this you need to create a “file” object, passing desired filename in its constructor. File object has the following functions:

return_type Function_name Description
bool open() Opens the file. File is opened in read-write mode if possible, in read-only mode otherwise.
void close() Closes the file.
Number size() Returns file size in bytes.
bool seek(Number pos) Sets current position in file to pos bytes [1].
bool resize(Number size) Resizes the file to size bytes. If size is less than current file size, then the file is truncated, if it is greater than current file size, then the file is padded with zero bytes.
bool remove() Removes the file.
String read(Number maxsize) Reads up to maxsize bytes from the file and returns result as a string. Data is read in utf-8 Unicode encoding.
Number write(String s, Number maxsize) Writes up to maxsize btyes to the file from the string. Data is written in utf-8 unicode encoding, end-of-line character should be set by user. Returns amount of written bytes or -1 if an error occurred.

All file functions which return bool type, return “true” on success and “false” on failure.

Use “/” symbol as path separator, this works on all systems (Windows/Linux/Mac).

Example:

var winf = new_file("C:/file.txt"); // An example of file name and path on Windows
var linf = new_file("/home/user/Desktop/file.txt"); // An example of file name and path on Linux
var macf = new_file("/Users/macuser/file.txt"); // An example of file name and path on Mac

var f = winf; // Pick a file name
if (f.open()) { // Try to open the file
  f.write( "some text" ); // If successful, then write desired data to the file
  f.close(); // Close the file
} else { // If file open failed for some reason
  log( "Failed opening file" ); // Log an error
}

Function usage example.

6.5.3.5. Creation of calibration structure

new_calibration(double A, int Microstep) function takes as a parameter a floating point number A, which sets the ratio of user units to motor steps, and microstep division mode, which was either read earlier from MicrostepMode field of get_engine_settings() return type, or set by a MICROSTEP_MODE_ constant. This function returns calibration_t structure, which should be passed to calibrated get_/set* functions to get or set values in user units. The following two forms are functionally equivalent:

// create calibration: type 1
var calb = new_calibration(c1, c2);
// create calibration: type 2
var calb = new Object();
calb.A = c1;
calb.MicrostepMode = c2;

Function usage example.

6.5.3.6. Get next serial

get_next_serial(int serial) function takes as a parameter an integer number and returns the smallest serial from a sorted list of opened controller serials which is strictly greater than the parameter. If there are no such serials a zero is returned. This function is a convenient shortcut for automatic creation of “axis” type objects without hardcoded serial numbers.

Example:

var first_serial = get_next_serial(0);
var x = new_axis(first_serial);
var y = new_axis(get_next_serial(first_serial));

In this example in the first line we obtain a serial, in the second line an axis-type object is created, in the third line we get the next serial and create an axis for it.

Function usage example.

6.5.3.7. Wait for stop

The command_wait_for_stop(int refresh period) script function waits until the controller stops movement, that is, until the MVCMD_RUNNING bit in the MvCmdSts member of the structure returned by the get_status() function becomes unset. command_wait_for_stop script function uses command_wait_for_stop libximc function and takes as a paramater an integer denoting time delay in milliseconds between successive queries of controller state.

This function is also present as a method of an “axis”-type object.

Function usage example.

6.5.3.8. libximc library functions

Libximc library functions with “get*” prefix read settings from the controller and return the corresponding settings structure. Libximc library functions with “set*” prefix take as a parameter a settings data structure and write these settings to the controller. There are two ways to set data structure contents:

  1. call the corresponding get-function and modify required fields
// set settings: type 1
var m = get_move_settings();
m.Speed = 100;
set_move_settings(m);

2. create an Object and set all of its properties that are present as members of the data structure (case-sensitive).

// set settings: type 2
var m = new Object;
m.Speed = 100;
m.uSpeed = 0;
m.Accel = 300;
m.Decel = 500;
m.AntiplaySpeed = 10;
m.uAntiplaySpeed = 0;
set_move_settings(m);

Please note, that in the first case controller receives an additional command (sent by the get-function before the set-). In the second case one should initialize all object properties corresponding to structure members. Any missing property will be initialized with zero. Any property that does not match a structure member name will be ignored. Any property with non-matching type will be typecast according to EcmaScript rules. All data structures are described in Communication protocol specification chapter of the manual.

Function usage example.

6.5.4. Examples

This section contains examples of typical tasks which can be easily automated by XILab scripts.

6.5.4.1. Bit mask example script

/*
* Bit mask example script
*
* Description of the script:
*  This script clearly shows how to work with bit masks.
*  This script or part of it may be needed when working with any of our other commands that use bit masks. For example, the  «set_home_settings» command
*
* To run the script, upload it to the XILab software
*/

var a = new_axis(get_next_serial(0)); // take first found axis
var gets = a.get_status(); // read status once and reuse it

var gpio = gets.GPIOFlags;
var left = STATE_LEFT_EDGE;
var right = STATE_RIGHT_EDGE;
var mask = left | right;
var result = gpio & mask;
log( to_binary(left) + " = left limit switch flag" );
log( to_binary(right) + " = right limit switch flag" );
log( to_binary(mask) + " = OR operation on flags gives the mask" );
log( to_binary(gpio) + " = gpio state" );
log( to_binary(result) + " = AND operation on state and mask gives result" );
if ( result ) {
  log("At least one limit switch is on");
} else {
  log("Both limit switches are off");
}

// Binary representation function
function to_binary(i)
{
  bits = 32;
  x = i >>> 0; // coerce to unsigned in case we need to print negative ints
  str = x.toString(2); // the binary representation string
  return (repeat("0", bits) + str).slice (-bits); // pad with zeroes and return
}

// String repeat function
function repeat(str, times)
{
  var result="";
  var pattern=str;
  while (times > 0) {
    if (times&1) {
      result+=pattern;
    }
    times>>=1;
    pattern+=pattern;
  }
  return result;
}

6.5.4.2. A script which scans and writes data to the file

/*
* A script which scans and writes data to the file
*
* Description of the script:
*  This script scans and writes the data to a .csv file.
*  The script can be useful if you are using the system to scan an area and/or capture frames
*
* To run the script, upload it to the XILab software
*/

var start = 0; // Starting coordinate in steps
var step = 10; // Shift amount in steps
var end = 100; // Ending coordinate in steps

var speed = 300; // maximum movement speed in steps / second
var accel = 100; // acceleration value in steps / second^2
var decel = 100; // deceleration value in steps / second^2
var delay = 100;

var m = get_move_settings(); // read movement settings from the controller
m.Speed = speed; // set movement speed
m.Accel = accel; // set acceleration
m.Decel = decel; // set deceleration
set_move_settings(m); // write movement settings into the controller

var f = new_file("C:/a.csv"); // Choose a file name and path
f.open(); // Open a file
f.seek( 0 ); // Seek to the beginning of the file

command_move(start); // Move to the starting position
command_wait_for_stop(delay); // Wait until controller stops moving

while (get_status().CurPosition < end) {
  f.write( get_status().CurPosition + "," + get_chart_data().Pot + "," + Date.now() + "\n" ); // Get current position, potentiometer value and date and write them to file
  command_movr(step); // Move to the next position
  command_wait_for_stop(delay); // Wait until controller stops moving
}
f.close(); // Close the file

move_and_sleep.csv

  • a sample file for use with the above example

6.5.4.3. Multi axis cyclic movement script

/*
* Multi axis cyclic movement script
*
* Description of the script:
*  Does cyclic movement between two border points with set values of acceleration,
*  deceleration and top speed, for all axes found. The script is similar to the "Cyclic"
*  button in XILab
*
* To run the script, upload it to the XILab software
*/

var axes = [];
var number_of_axes = 0;
var last_serial = 0;

while (serial = get_next_serial(last_serial))   // Get next serial number and repeat for each axes
{
  axes[number_of_axes] = new_axis(serial);
  log("Found axis " + number_of_axes + " with serial number " + serial);
  number_of_axes++;
  last_serial = serial;
}

for (var i = 0; i < number_of_axes; i++)
{
  axis_configure(axes[i]);
}

while (1)
{
  for (var i = 0; i < number_of_axes; i++)
  {
    go_first_border(axes[i]);
    go_second_border(axes[i]);
  }

  msleep(100);
}

function axis_configure(axis)
{
  var speed = 1000;   // Maximum movement speed in steps / second
  var accel = 2000;   // Acceleration value in steps / second^2
  var decel = 5000;   // Deceleration value in steps / second^2

  axis.command_stop(); // send STOP command (does immediate stop)
  axis.command_zero(); // send ZERO command (sets current position and encoder value to zero)
  var m = axis.get_move_settings(); // read movement settings from the controller
  m.Speed = speed; // set movement speed
  m.Accel = accel; // set acceleration
  m.Decel = decel; // set deceleration
  axis.set_move_settings(m); // write movement settings into the controller
}

function go_first_border(axis)
{
  var first_border = 0; // first border coordinate in steps
  var GETS = axis.get_status();

  if (!(GETS.MvCmdSts & MVCMD_RUNNING) && (GETS.CurPosition != first_border))
  {
    axis.command_move(first_border);  // move towards one border
  }
}

function go_second_border(axis)
{
  var second_border = 25000; // second border coordinate in steps
  var GETS = axis.get_status();

  if (!(GETS.MvCmdSts & MVCMD_RUNNING) && (GETS.CurPosition != second_border))
  {
    axis.command_move(second_border);   // move towards another border
  }
}

6.5.4.4. Single axis cyclic movement script

/*
* Single axis cyclic movement script
*
* Description of the script:
*  Does cyclic movement between two border points with set values of acceleration,
*  deceleration and top speed. The script is similar to the "Cyclic" button in XILab
*
* To run the script, upload it to the XILab software
*/

var first_border = -10; // first border coordinate in mm
var second_border = 10; // second border coordinate in mm
var mm_per_step = 0.005; // steps to distance translation coefficient
var delay = 100; // delay in milliseconds
var calb = new_calibration(mm_per_step, get_engine_settings().MicrostepMode); // create calibration structure
command_stop(); // send STOP command (does immediate stop)
command_zero(); // send ZERO command (sets current position and encoder value to zero)
while (1) { // infinite loop
  command_move_calb(first_border, calb); // move towards one border
  command_wait_for_stop(delay); // wait until controller stops moving
  command_move_calb(second_border, calb); // move towards another border
  command_wait_for_stop(delay); // wait until controller stops moving
}

6.5.4.5. Homing test script

/*
* Homing test script
*
* Description of the script:
*  This script tests homing function by repeatedly moving to a random position,
*  doing quick stop and then homing, for all axes found. The script is similar to the GO
*  Home button in XILab
*
* To run the script, upload it to the XILab software
*/

var axes = [];
var number_of_axes = 0;
var last_serial = 0;
while (serial = get_next_serial(last_serial)) // get next serial number and repeat for each axes.
{
    axes[number_of_axes] = new_axis(serial);
   log("Found axis " + number_of_axes + " with serial number " + serial);
   number_of_axes++;
   last_serial = serial;
}

while (1) { // infinite loop
    for (var i = 0; i < number_of_axes; i++)
   {
        homing_test(axes[i]);
    }
}

function homing_test(axis)
{
    var shift_low = 0; // minimum shift distance in steps
   var shift_high = 10000; // maximum shift distance in steps
   var speed_low = 100; // minimum movement speed in steps / second
   var speed_high = 5000; // maximum movement speed in steps / second
   var time_low = 1; // minimum wait time in seconds
   var time_high = 10; // maximum wait time in seconds

    axis.command_home(); // send HOME command (find home position)
    axis.command_wait_for_stop(100); // wait until controller stops moving
    var m = axis.get_move_settings(); // read movement settings from the controller
    m.Speed = rnd(speed_low, speed_high); // set random speed from a range of speeds between "speed_low" and "speed_high"
    axis.set_move_settings(m); // write movement settings into the controller
    var shift = rnd(shift_low, shift_high); // pick random shift value from a range of distances between "shift_low" and "shift_high"
    if (Math.random() < 0.5) { // pick random direction
       shift = -shift;
    }
    axis.command_movr(shift); // send MOVR command (does a relative shift)
    msleep( rnd(time_low*1000, time_high*1000) ); // pause for a random time from a range between "time_low" and "time_high"
    axis.command_stop(); // send STOP command (does immediate stop)
}

function rnd(min,max) { // "rnd" is a helper function which uses Math.random() and returns a uniformly distributed integer random value between "min" and "max"
 var r = Math.random()*(max-min)+min;
 return Math.round(r);
}

6.5.4.6. List axis serials script

/*
* List axis serials script
*
* Description of the script:
*  An example of a script that searches for all the serial numbers of controllers
*  and outputs them to the log.
*
* To run the script, upload it to the XILab software
*/

var i = 0; // Declare loop iteration variable
var serial = 0; // Declare serial number variable
var axes = Array(); // Declare axes array
while (true) { // The loop
 serial = get_next_serial(serial); // Get next serial
 if (serial == 0) // If there are no more controllers then...
     break; // ...break out of the loop
 var a = new Object(); // Create an object
 a.serial = serial; // Assign serial number to its "serial" property
 a.handle = new_axis(serial); // Assign new axis object to its "handle" property
 axes[i] = a; // Add it to the array
 i++; // Increment counter
}
for (var k=0; k < axes.length; k++) { // Iterate through array elements
  log ( "Axis with S/N " + axes[k].serial + " is in position " + axes[k].handle.get_status().CurPosition ); // For each element print saved axis serial and call a get_status() function
}

6.5.4.7. Move and wait script

/*
* Move and wait script
*
* Description of the script:
*  The script reads the next coordinate and the delay time from the csv file,
*  after which it moves to the specified coordinate with a subsequent delay,
*  and so on until the end of reading the entire file.
*     The script can be useful if you are using the system to scan an area and/or capture frames
* To run the script, upload it to the XILab software
*/

var axis = new_axis(get_next_serial(0)); // Use first available controller
var x; // A helper variable, represents coordinate
var ms; // A helper variable, represents wait time in milliseconds
var f = new_file("./move_and_sleep.csv"); // Choose a file name and path; this script uses a file from examples in the installation directory
f.open(); // Open a file
while ( str = f.read(4096) ) { // Read file contents string by string, assuming each string is less than 4 KiB long
  var ar = str.split(","); // Split the string into substrings with comma as a separator; the result is an array of strings
  x = ar[0]; // Variable assignment
  ms = ar[1]; // Variable assignment
  log( "Moving to coordinate " + x ); // Log the event
  axis.command_move(x); // Move to the position
  axis.command_wait_for_stop(100); // Wait until the movement is complete
  log( "Waiting for " + ms + " ms" ); // Log the event
  msleep(ms); // Wait for the specified amount of time
}
log ( "The end." );
f.close(); // Close the file

6.5.4.8. Random shift script

/*
* Random shift script
*
* Description of the script:
*  This script does shifts on random offset from a specified range of distances
*  with a random speed from a chosen range of speeds.

* To run the script, upload it to the XILab software
*/

var axes = [];
var number_of_axes = 0;
var last_serial = 0;
while (serial = get_next_serial(last_serial)) // get next serial number and repeat for each axes.
{
   axes[number_of_axes] = new_axis(serial);
   log("Found axis " + number_of_axes + " with serial number " + serial);
   number_of_axes++;
    last_serial = serial;
}

while (1) { // infinite loop
   for (var i = 0; i < number_of_axes; i++)
   {
       go_to_random_shift(axes[i]);
    }
}

function go_to_random_shift(axis)
{
   var shift_low = 0; // minimum shift distance in steps
   var shift_high = 10000; // maximum shift distance in steps
   var speed_low = 100; // minimum movement speed in steps / second
   var speed_high = 5000; // maximum movement speed in steps / second

   var m = axis.get_move_settings(); // read movement settings from the controller
   m.Speed = rnd(speed_low, speed_high); // set random speed from a range of speeds between "speed_low" and "speed_high"
   axis.set_move_settings(m); // write movement settings into the controller
   var shift = rnd(shift_low, shift_high); // pick random shift value from a range of distances between "shift_low" and "shift_high"
   if (Math.random() < 0.5) { // pick random direction
       shift = -shift;
   }
   axis.command_movr(shift); // send MOVR command (does a relative shift)
    axis.command_wait_for_stop(100); // wait until controller stops moving
}

function rnd(min,max) { // "rnd" is a helper function which uses Math.random() and returns a uniformly distributed integer random value between "min" and "max"
  var r = Math.random()*(max-min)+min;
  return Math.round(r);
}

6.5.4.9. Set zero scrip

/*
* Set zero script
*
* Description of the script:
*  This script changes "standoff" setting (found on "Home position" page in the XILab "Settings") so that the current position becomes the home position.
*  The script is very convenient for calibrating and configuring new stages, as well as for changing the zero position
*
* How to use:
*  - manually move your positioner to a desired position
*  - launch this script and wait for completion
*  As a result your positioner will return to the starting position and all subsequent calls to "homing" function will bring it there.
*
* Note: homing settings are saved into RAM and will be lost when controller is powered down. If you wish to save these settings to non-volatile memory you should either pick "Save settings to flash" on the XILab main Settings page or call "command_save_settings()" at the end of the script.
*
* To run the script, upload it to the XILab software
*/

var axes = [];
var number_of_axes = 0;
var last_serial = 0;
while (serial = get_next_serial(last_serial)) // get next serial number and repeat for each axes.
{
    axes[number_of_axes] = new_axis(serial);
   log("Found axis " + number_of_axes + " with serial number " + serial);
   number_of_axes++;
   last_serial = serial;
}

for (var i = 0; i < number_of_axes; i++)
{
   set_zero(axes[i]);
}

function set_zero(axis)
{
    axis.command_stop(); // send STOP command (does immediate stop)

   var h = axis.get_home_settings(); // read homing settings from the controller
   h.HomeDelta = 0; // set "HomeDelta" parameter in "home_position" structure to 0
   h.uHomeDelta = 0; // set "uHomeDelta" parameter in "home_position" structure to 0
   var saved_fast = h.FastHome; // save "FastHome" parameter from "home_position" structure to a variable
   var saved_ufast = h.uFastHome; // save "uFastHome" parameter from "home_position" structure to a variable
   if (h.HomeFlags & HOME_MV_SEC_EN != 0) // if homing settings have two homing phases turned on
   {
        h.FastHome = 100; // set "FastHome" parameter in "home_position" structure (first movement speed) to 100 steps/s: this is required to avoid slip at the end of the first phase
       h.uFastHome = 0; // set "uFastHome" parameter in "home_position" structure to 0
    }
    axis.set_home_settings(h); // write homing settings into the controller

    var old_pos = axis.get_status().CurPosition; // save whole step part of the initial position into a variable
    var old_upos = axis.get_status().uCurPosition; // save microstep part of the initial position into a variable
    axis.command_home(); // send HOME command (find home position)
    do { msleep(100); } while (axis.get_status().MvCmdSts == (MVCMD_HOME | MVCMD_RUNNING)); // query controller state every 100 ms while movement state is "homing command is being executed"
    if (axis.get_status().MvCmdSts != MVCMD_HOME)  // if current state is not "homing completed successfully" (MVCMD_RUNNING unset, MVCMD_ERROR unset, last command MVCMD_HOME) then homing was interrupted
    {
        h.FastHome = saved_fast; // set "FastHome" parameter in "home_position" structure to a saved value
       h.uFastHome = saved_ufast; // set "uFastHome" parameter in "home_position" structure to a saved value
       axis.set_home_settings(h); // write movement settings into the controller (this restores the initial settings)
       throw "Script aborted: homing failed."; // throw an exception and terminate
    }

    var new_pos = axis.get_status().CurPosition; // read whole part of new position into "new_pos" variable
    var new_upos = axis.get_status().uCurPosition; // read microstep part of new position into "new_upos" variable
    h.HomeDelta = old_pos-new_pos; // set "HomeDelta" parameter in "home_position" structure to this value
    h.uHomeDelta = old_upos-new_upos; // set "uHomeDelta" parameter in "home_position" structure to this value
    h.FastHome = saved_fast; // set "FastHome" parameter in "home_position" structure to a saved value
    h.uFastHome = saved_ufast; // set "uFastHome" parameter in "home_position" structure to a saved value
    axis.set_home_settings(h); // write movement settings into the controller
    axis.command_move(old_pos, old_upos); // move to initial position
    do { msleep(100); } while (axis.get_status().MvCmdSts == (MVCMD_MOVE | MVCMD_RUNNING)); // query controller state every 100 ms while movement state is "movement command is being executed"
    if (axis.get_status().MvCmdSts != MVCMD_MOVE)  // if current state is not "movements completed successfully" (MVCMD_RUNNING unset, MVCMD_ERROR unset, last command MVCMD_MOVE) then movement was interrupted
    {
        throw "Script aborted: return to position failed."; // throw an exception and terminate
    }
    axis.command_zero(); // send ZERO command (sets current position and encoder value to zero)
}

log("Done."); // log success

6.5.4.10. Autotester script

/*
* Autotester script
*
* Description of the script:
*  The script tests the controller with a stage using a set of tests.
*
* Note: This is a rather difficult script to learn, since it uses a large number of commands and structures.
*
* To run the script, upload it to the XILab software
*/

View the full code

6.5.4.11. Border crossing test

/*
* Border crossing test
*
* Description of the script:
*  The script checks the correct operation of the connected external limit switch
*
* How to connect wires?
*  You must connect the limit switch to the DSub-15 connector (pins 8 and 9 on the controller connector).
*
* Note: This is a rather difficult script to learn, since it uses a large number of commands and structures.
*
* To run the script, upload it to the XILab software
*/

const MVCMD_ERROR = 0x40;
const MVCMD_RUNNING = 0x80;

var axis = new_axis(get_next_serial(0));
var m = axis.get_extio_settings();
var s = axis.get_status();

var count_error = 0;
var count_good = 0;

function BorderOff()
{
  m.EXTIOSetupFlags = 0x01;
  m.EXTIOModeFlags = 0x10;

  axis.set_extio_settings(m);
}

function BorderOn()
{
  m.EXTIOSetupFlags = 0x01;
  m.EXTIOModeFlags = 0x00;

  axis.set_extio_settings(m);
}

function BorderCycle()
{
  BorderOn();
  msleep(50);

  BorderOff();
  msleep(100);
}

log("You have to connect the common",2);
log("input/output pin on the backplane connector to",2);
log("the 2nd limit switch pin on the stage connector", 2);
log("Also its recommended to load the profile for your stage", 2);

log(">>> Start testing", 3);

while (1)
{
  axis.command_left();
  msleep(200);
  BorderOn();
  msleep(200);
  s = axis.get_status();

  if (s.MvCmdSts & MVCMD_RUNNING)
  {
    count_error++;

    log(">>> ALARM ! Crossing through the limit switch !" ,1);
  }
  else
  {
    count_good++;

    if (!(count_good % 50))
      log(">>> " + count_good + " cycles were done correct, " + count_error + " cycles were done incorrect", 3);
  }

  BorderOff();
}

6.5.4.12. Closed loop tuning test

/*
* Closed loop tuning test
*
* Description of the script:
*  The script checks the parameters of a closed loop
*
* Note: This is a rather difficult script to learn, since it uses a large number of commands and structures.
*
* To run the script, upload it to the XILab software
*/

var global_axis;

global_axis = new_axis(get_next_serial(0));
global_axis.command_stop();

const DEBUG = 1;
const MICROSTEPS = 256;
const SKIP_ENCODER_COUNT = 7;
const STORE_COUNT_MICROSTEPS = 19;
const TRUST_INDEX = 15;     // Always TRUST_INDEX < STORE_COUNT_MICROSTEPS

/*
* Save and overwrite settings
*/
var SFBS = global_axis.get_feedback_settings(); // Save information about encoder (IPS)
SFBS.FeedbackType = FEEDBACK_NONE;              // Overwrite feedback type, because in profile feedback is encoder

var SENG = global_axis.get_engine_settings();   // Save information about engine (nominal current, steps per revolution)

var SENT = global_axis.get_entype_settings();   // Save information about engine type

var SEDS = global_axis.get_edges_settings();    // Save information about edges

/*
* Clear FRAM for synchronization
* real full step with full step of firmware
*/
log("Clearing FRAM", 1);
global_axis.command_clear_fram();
msleep(4000);

/*
* Restore controller settings
*/
global_axis.set_feedback_settings(SFBS);
msleep(100);

global_axis.set_engine_settings(SENG);
msleep(100);

global_axis.set_entype_settings(SENT);
msleep(100);

global_axis.set_edges_settings(SEDS);
msleep(100);

/*
* Prepare and apply move settings
*/
var SMOV = global_axis.get_move_settings();
SMOV.Speed = 0;
SMOV.uSpeed = 16;
global_axis.set_move_settings(SMOV);
msleep(100);

/*
* Going to the full step and waiting 3 seconds for equilibration
*/
global_axis.command_move(0, 0);
msleep(3000);

/*
* Arrays for measurements and structure for GPOS
*/
var MicroStepsToRight = [];
var MicroStepsToLeft = [];
var EncToRight = [];
var EncToLeft = [];
var GPOS;

/*
* Start moving
*/
global_axis.command_right();

/*
* Skipping a some first counts for the stable experiment
*/
for (var i = 0; i < SKIP_ENCODER_COUNT; i++)
{
  GPOS = global_axis.get_position();
  var EncPos = GPOS.EncPosition;

  while (EncPos == GPOS.EncPosition)
  {
    msleep(40);
    GPOS = global_axis.get_position();
  }

  EncPos = GPOS.EncPosition;
}

/*
* Start measurements
*/
for (var i = 0; i < STORE_COUNT_MICROSTEPS; i++)
{
  GPOS = global_axis.get_position();
  var EncPos = GPOS.EncPosition;

  while (EncPos == GPOS.EncPosition)
  {
    msleep(40);
    GPOS = global_axis.get_position();
  }

  EncPos = GPOS.EncPosition;

  MicroStepsToRight[i] = GPOS.Position * MICROSTEPS + GPOS.uPosition;
  EncToRight[i] = GPOS.EncPosition;
}

/*
* Stop moving
*/
global_axis.command_stop();

/*
*  Start moving and measurements
*/
global_axis.command_left();

for (var i = 0; i < STORE_COUNT_MICROSTEPS; i++)
{
  GPOS = global_axis.get_position();
  var EncPos = GPOS.EncPosition;

  while (EncPos == GPOS.EncPosition)
  {
    msleep(40);
    GPOS = global_axis.get_position();
  }

  EncPos = GPOS.EncPosition;

  MicroStepsToLeft[STORE_COUNT_MICROSTEPS - 1 - i] = GPOS.Position * MICROSTEPS + GPOS.uPosition;
  EncToLeft[STORE_COUNT_MICROSTEPS - 1 - i] = GPOS.EncPosition;
}

/*
* Stop moving
*/
global_axis.command_stop();

/*
* Check all values
*/
for (var i = 0; i < STORE_COUNT_MICROSTEPS; i++)
{
  var diffMicrosteps = MicroStepsToRight[i] - MicroStepsToLeft[i];
  var diffConts = EncToRight[i] - EncToLeft[i];

  if (DEBUG)
  {
    log(MicroStepsToRight[i] + " - " + MicroStepsToLeft[i] + " = " + diffMicrosteps + " microstep(s)\t" +
      EncToRight[i] + " - " + EncToLeft[i] + " = " + diffConts + " count(s)", 3);
  }

  if (diffConts != 1)
  {
    log("Script error! Try again", 1);
  }
}

var RightB = (MicroStepsToRight[TRUST_INDEX] * EncToRight[0] - MicroStepsToRight[0] * EncToRight[TRUST_INDEX]) / (EncToRight[0] - EncToRight[TRUST_INDEX]);
var LeftB = (MicroStepsToLeft[TRUST_INDEX] * EncToLeft[0] - MicroStepsToLeft[0] * EncToLeft[TRUST_INDEX]) / (EncToLeft[0] - EncToLeft[TRUST_INDEX]);

log("Right counts show B = " + RightB, 2);
log("Left counts show B = " + LeftB, 2);
log("Aver B = " + ((RightB + LeftB) / 2), 3);

6.5.4.13. Discrete motion script

/*
* Discrete motion script
*
* Description of the script:
*  The script opens two axes by serial numbers. Moves along the X axis to a certain coordinate. Then it begins to shift discretely along the Y axis, with a programmable pause after each offset.
*  The script can be useful if you are using the system to scan an area and/or capture frames
*
* Warning: enter the serial numbers of your axes!
*
* Note: This is a rather difficult script to learn, since it uses a large number of commands and structures.
*
* To run the script, upload it to the XILab software
*/

// Enter the serial numbers of your axes.
serial_number_x = 14889;
serial_number_y = 14888;

var x = new_axis(serial_number_x);
var y = new_axis(serial_number_y);

// Installing the source data
var x_target_coordinate = 5000; // first border coordinate
var delay = 100; // delay in milliseconds

var y_first_border = 0; // first border coordinate
var y_second_border = 5000; // second border coordinate
var y_step = 100
var y_direct = 1

// Calibration and positioning of the axes to their original positions.
x.command_stop(); // send STOP command (does immediate stop)
x.command_zero(); // send ZERO command (sets current position and encoder value to zero)
y.command_stop(); // send STOP command (does immediate stop)
y.command_zero(); // send ZERO command (sets current position and encoder value to zero)

x.command_move(x_target_coordinate); // move to wards one border
x.command_wait_for_stop(10); // wait until controller stops moving
y.command_move(y_first_border); // move towards one border
y.command_wait_for_stop(10); // wait until controller stops moving

// Movement in discrete samples along one axis from the end to the end
// with a delay after each movement.
while (1) { // infinite loop

// Choosing the direction of travel
if (y.get_position() >= y_second_border)
{
  y_direct = -1
}
if (y.get_status().CurPosition <= y_first_border)
{
  y_direct = 1
}

// Movement in a given direction
y.command_movr(y_step*y_direct); // move towards another border
y.command_wait_for_stop(10); // wait until controller stops moving
msleep(delay);
}

6.5.4.14. Exponential position change in user units script

/*
* Exponential position change in user units script
*
* Description of the script:
*  The script performs discrete control of movement according to a certain law of motion. The amplitude and the law of displacement are given. A correction speed is used to maintain the positioning accuracy.
*
* Note: This is a rather difficult script to learn, since it uses a large number of commands and structures.
*
* To run the script, upload it to the XILab software
*/

// Main characteristics
var time_discre = 10; // Discreteness of movement control(ms)
var end_err = 0.01; // The accuracy of reaching the final coordinate of the movement.

var full_move = 6; // Total movement in mm

// If you change the equation of motion, you will need to change the equation for the correction velocity, since this change is not linear.
var K = 0.4;
var Glob_err = 0;

// Advanced setting.
var mm_per_step = 0.00125; // Distance in gr for 1 completed step.
var calb = new_calibration(mm_per_step, get_engine_settings().MicrostepMode); // create calibration structure

// Setting the starting position.
command_stop(); // send STOP command (does immediate stop)
command_wait_for_stop(10); // wait until controller stops moving
command_zero(); // send ZERO command (sets current position and encoder value to zero)


log("Start:");
// Setting 0 speeds and accelerations.
zero_movesettings();

//
go_position(full_move, time_discre)


// Function for calculating the set speed and acceleration
function set_movesettings(time, corr_speed)
{
  // Speed, Accel, Decel setting.
  var m = get_move_settings_calb(calb); // read movement settings from the controller

  // The equation of speed is equal to the derivative of the equation of motion.
  m.Speed =  K*Math.exp(K*time/1000 )+ corr_speed;

  set_move_settings_calb(m, calb); // write movement settings into the controller

log("Speed = " +m.Speed);
log("corr_speed = " +corr_speed);
}

// Set the initial parameters of motion
function zero_movesettings()
{
  var m = get_move_settings_calb(calb); // read movement settings from the controller
  m.Speed = 0.1; // set movement speed

  set_move_settings_calb(m, calb); // write movement settings into the controller
}

// A function of calculating target coordinates from time
function current_target_coordinate(time)
{
  // The equation of motion. The time is set in milliseconds. The position at the initial time is 0.
  return (Math.exp(K*time/1000) - 1);
}

// The calculation of the correction speed
function speed_corr(err_pos)
{
  Glob_err = Glob_err + err_pos*0.35;
  return  Glob_err;
}

// The main moving
function go_position(full_time, time_discre)
{
  Glob_err = 0;
  var end_position = full_move;

  // Setting the movement to the desired coordinate.
  command_move_calb(end_position, calb);

  // Pause before starting to move, to turn on the power button.
  msleep(300);
  var mas = 1;
  var basetime = new Date();
  var curr_time = new Date();
  var err_pos = 0;
  var pos = 0;
  var pos1 = 0;
  var i = time_discre;
  do {
    // If you do not need position feedback, you can instead speed_corr(err_pos) write 0
    set_movesettings(i+1, speed_corr(err_pos));

    // Waiting for the end of a discrete time interval
    do {
      curr_time = new Date - basetime;
      msleep(1);
    }
    while ((curr_time) < i); //

    // Reading the actual and calculating the planned coordinate if used.
    pos =  get_position_calb(calb).Position;
    pos1 =  current_target_coordinate(i);

    // Calculation of the position error.
    err_pos =  (pos1 -  pos);

    log("time = " + i);
    log("err_pos = " + err_pos);

    i = i + time_discre
  }
  while (Math.abs(pos - end_position) > end_err); // Completion when the end of the movement is reached with the specified accuracy.
}

6.5.4.15. For calb step script

/*
* For calb step script
*
* Description of the script:
*  In the script, the user units are configured, after which there is a departure to the leftmost position and then a certain number of shifts occur until the right position is reached. Each position is recorded in a .csv file.
*
* Note: This is a rather difficult script to learn, since it uses a large number of commands and structures.
*
* To run the script, upload it to the XILab software
*/

command_home(); // send HOME command (find home position)
command_wait_for_stop(100);
command_zero();
command_wait_for_stop(100);

// Setting the value to convert to user unit
var mm_per_step = 0.00125; // steps to distance translation coefficient
var calb = new_calibration(mm_per_step, get_engine_settings().MicrostepMode); // create calibration structure

// Setting boundaries and movement step
// Boundaries can be set manually or taken from limit constraints
var edge = get_edges_settings_calb(calb);
var first_border = edge.LeftBorder; //0;
var second_board = edge.RightBorder;//23;
var shift = 5;//step move;
var delay = 2000;// The delay of movement

var f = new_file("file.csv"); // Choose a file name and path
f.open(); // Open a file
f.resize(0);
f.seek( 0 ); // Seek to the beginning of the file

command_move_calb(first_border, calb); // Move to the starting position
command_wait_for_stop(delay); // Wait until controller stops moving
var i = 1;
var time = 0;
var step = (second_board - first_border)/shift;
f.write(0+ ","  +  get_status().CurPosition + "," +  get_status().uCurPosition+ "," + "\n" ); // Get current position, potentiometer value and date and write them to file
do {
  time = i*delay;
  command_movr_calb(shift, calb); // Move to the next position
  command_wait_for_stop(delay); // Wait until controller stops moving
  f.write(time + ","  +  get_position_calb(calb).Position + "," +  get_position_calb(calb).EncPosition+ "," + "\n" ); // Get current position, potentiometer value and date and write them to file
  i = i+1;
} while (  get_position_calb(calb).Position+shift < second_board )
f.close(); // Close the file

6.5.4.16. Step script

/*
* Step script
*
* Description of the script:
*  In the script, there is a departure to the leftmost position and then a certain number of shifts occur until the right position is reached. Each position is recorded in a .csv file.
*
* Note: The script is similar to the "for_calb_step" script, only in this script the offset occurs at the step mode
*
* To run the script, upload it to the XILab software
*/

command_home(); // send HOME command (find home position)
command_wait_for_stop(100);
command_zero();
command_wait_for_stop(100);
var edge = get_edges_settings();
var first_border = edge.LeftBorder;
var second_board = edge.RightBorder;
var count = 10;
var f = new_file("E:/a.csv"); // Choose a file name and path
f.open(); // Open a file
f.seek( 0 ); // Seek to the beginning of the file

var delay = 2000;
command_move(first_border); // Move to the starting position
command_wait_for_stop(delay); // Wait until controller stops moving
var i = 1;
var time = 0;
var shift = 6;
var step = (second_board - first_border)/shift;
f.write(0+ ","  +  get_status().CurPosition + "," +  get_status().uCurPosition+ "," + "\n" ); // Get current position, potentiometer value and date and write them to file
do {
  time = i*delay;
  command_movr(step, 0); // Move to the next position
  command_wait_for_stop(delay); // Wait until controller stops moving
  f.write(time + ","  +  get_status().CurPosition + "," +  get_status().uCurPosition+ "," + "\n" ); // Get current position, potentiometer value and date and write them to file
  i = i+1;
} while (i < shift )
f.close(); // Close the file

6.5.4.17. Homing test with extio

/*
* Homing test with extio
*
* Description of the script:
*  The script starts calibration when a signal is received from a general purpose digital input/output (extio)
*
* How to connect wires?
*  You must connect to the HDB-26 connector (pin 25 on the controller).
*
* Note: This is a rather difficult script to learn, since it uses a large number of commands and structures.
*
* To run the script, upload it to the XILab software
*/

const MVCMD_ERROR = 0x40;
const MVCMD_RUNNING = 0x80;

var axis = new_axis(get_next_serial(0));
var m = axis.get_extio_settings();
var s = axis.get_status();

var count_error = 0;
var count_good = 0;

function BorderOff()
{
  m.EXTIOSetupFlags = 0x01;
  m.EXTIOModeFlags = 0x10;

  axis.set_extio_settings(m);
}

function BorderOn()
{
  m.EXTIOSetupFlags = 0x01;
  m.EXTIOModeFlags = 0x00;

  axis.set_extio_settings(m);
}

function BorderCycle()
{
  BorderOn();
  msleep(50);

  BorderOff();
  msleep(2500);
}

log(">>> Start testing", 3);

while (1)
{
  axis.command_home();
  msleep(1500);

  BorderCycle();
  BorderCycle();

  command_wait_for_stop(100);

  s = axis.get_status();

  if (s.MvCmdSts & MVCMD_ERROR)
  {
    count_error++;

    log(">>> Alarm! Homing broken", 1);
  }
  else
  {
    count_good++;

    if (!(count_good % 50))
      log(">>> " + count_good + " cycles were done correct, " + count_error + " cycles were done incorrect", 3);
  }
}

6.5.4.18. Motion by sin function

/*
*  Motion by sin function
*
* Description of the script:
*  A script for moving with a change in speed according to the trigonometric law.
*  The script can be useful for precise positioning of a laser or motorized mirror
*
* Note: This is a rather difficult script to learn, since it uses a large number of commands and structures.
*
* To run the script, upload it to the XILab software
*/

var delay = 100;

/* Definition of delta and initial phase*/
var df = 0.05;
var f = 0;

/* Definition of package */
var GETS = new Object();

// Initial installations
var move_set = get_move_settings();
var speed = 3000;
var amplitude = 1000;
var nomber = 100;
var time = 1000;
var pos = 0;
var Pi = 3.1415;
df = Pi/nomber;

command_zero();

var pos_read = new Object();
while (1)
{
    pos_read = get_position();

    // Movement to a point with an increase in the velocity amplitude
    for (i = 1; i <= nomber-1; i++)
    {
      f = df*i;

      move_set.Speed = speed * Math.sin(f);
      pos =  amplitude*i /nomber;

      set_move_settings(move_set);
      command_move(pos);
      while (Math.abs(pos_read.Position - pos)>move_set.Speed/10)
      {
        pos_read = get_position();
      }

    }

    // Movement to a point with a decrease in the velocity amplitude
    for (i = nomber-1; i >= 1; i--)
    {
      f = df*i;

      move_set.Speed = speed * Math.sin(f);
      pos =  amplitude*i /nomber;

      set_move_settings(move_set);
      command_move(pos);
      while (Math.abs(pos_read.Position - pos)>move_set.Speed/10)
      {
        pos_read = get_position();
      }

    }

  msleep(1000);

}

6.5.4.19. Move EXTIO calb script

/*
* Move EXTIO calb script
*
* Description of the script:
*  The script moves to one of the 2 specified points, depending on the state of the EXTIO input. The movement is carried out in user units.
*
* Note: This is a rather difficult script to learn, since it uses a large number of commands and structures.
*
* To run the script, upload it to the XILab software
*/

// Main characteristics
var time_discre = 10; // Discreteness of movement control(ms)
var nomspeed = 5;
var end_err = 0.015;

var low_position = 0; // Move to position for low EXTIO
var high_position = 180; // Move to position for high EXTIO

// Advanced setting.
var gr_per_step = 0.015; // Distance in gr for 1 completed step.
var calb = new_calibration(gr_per_step, get_engine_settings().MicrostepMode); // create calibration structure

// Setting the starting position.
command_stop(); // send STOP command (does immediate stop)
command_wait_for_stop(10); // wait until controller stops moving
command_home();
command_zero(); // send ZERO command (sets current position and encoder value to zero)


log("Start:");
// Setting 0 speeds and accelerations.
movesettings();

extiosettings();
//
go_position(time_discre)

function extiosettings()
{
  var extsettings = get_extio_settings();
  extsettings.EXTIOSetupFlags = 0x00;
  extsettings.EXTIOModeFlags = 0x00;
  set_extio_settings(extsettings);
}

// Set the initial parameters of motion
function movesettings()
{
  var m = get_move_settings_calb(calb); // read movement settings from the controller
  m.Speed = nomspeed; // set movement speed

  set_move_settings_calb(m, calb); // write movement settings into the controller
}


// The main moving
function go_position(time_discre)
{
  var oldstate = 0;
  var maskstate = 32;

  // Setting the movement to the desired coordinate.
  command_move_calb(low_position, calb);

  // Pause before starting to move, to turn on the power button.
  msleep(300);

  while(1) {

  //
  var status = get_status_calb(calb);
  if ((status.GPIOFlags & maskstate) != oldstate)
  {
    log(status.GPIOFlags);
    if (oldstate)
      command_move_calb(high_position, calb);
    else
      command_move_calb(low_position, calb);

    oldstate = status.GPIOFlags & maskstate;
  }
  // Waiting for the end of a discrete time interval
  msleep(time_discre);
  }
}

6.5.4.20. Probabilistic tests

/*
* Probabilistic tests
*
* Description of the script:
*  The script runs a set of repeatable tests a certain number of times and is expected to fail.
*
* Note: This is a rather difficult script to learn, since it uses a large number of commands and structures.
*
* To run the script, upload it to the XILab software
*/

View the full code

6.5.4.21. Several shifts with calibration script

/*
* Several shifts with calibration script
*
* Description of the script:
*  This program makes shifts given number of times to the specified distance, and stands the appointed time after every shift. First it goes left, then it returns back to the origin and repeats all movements to right.
*
* Note: This is a rather difficult script to learn, since it uses a large number of commands and structures.
*
* To run the script, upload it to the XILab software
*/

const LEFT = -1;
const RIGHT = 1;

var axes = [];
var number_of_axes = 0;
var last_serial = 0;
while (serial = get_next_serial(last_serial)) // get next serial number and repeat for each axes.
{
    axes[number_of_axes] = new_axis(serial);
    log("Found axis " + number_of_axes + " with serial number " + serial);
    number_of_axes++;
    last_serial = serial;
}

// Start the main function for all avaliable axes
for (var i = 0; i < number_of_axes; i++)
{
    main(axes[i]);
}


function main(axis)
{
    axis.command_move(0,0); // Go back to the origin.
    msleep(500);

/* Creating and filling the calibration structure for specifying distances in um */
    var calibration = new Object;
    calibration.A = 5; // 1 step correspond to 5 um for 8MT50-100BS1
    calibration.MicrostepMode = axis.get_engine_settings().MicrostepMode; // Get MicrostepMode from controller settings
/*******************************************************/

/* Main cycle */

    var N = 10; // Number of shifts
    var stand_time  = 3000; // Stand time in ms
    var shift = 10; // Distance of shift in um

    MakeShifts(axis, LEFT,   shift, N, stand_time, calibration); // Make 10 shifts to the left
    MakeShifts(axis, RIGHT, shift, N, stand_time, calibration); // Make 10 shifts to the right
    MakeShifts(axis, RIGHT, shift, N, stand_time, calibration); // Make 10 shifts to the right again
    MakeShifts(axis, LEFT,   shift, N, stand_time, calibration); // Make 10 shifts to the left
}

function MakeShifts(axis, Direction, ShiftDistance, ShiftsQuantity, StandTime, Calibration)
{
/**
    This function makes shifts which number is specified by ShiftQuantity and length is specified by ShiftDistance. After every shift it stands StandTime miliseconds. Calibration parameter is a structure for convertation between steps and micrometers.
*/
    for (var i = 0; i < ShiftsQuantity; i++)
    {
        axis.command_movr_calb(Direction*ShiftDistance, Calibration);
        axis.command_wait_for_stop(100);
        msleep(StandTime);
    }
}

6.5.4.22. Steps loss test

/*
* Steps loss test
*
* Description of the script:
*  The script was written to check for skipping steps
*  It can be useful for diagnosing problematic stages
*
* Note: This is a rather difficult script to learn, since it uses a large number of commands and structures.
*
* To run the script, upload it to the XILab software
*/

function abs(x)
{
    return ((x > 0) ? x : -x);
}

/*
* Set home settings
*/
var SHOM = get_home_settings()
SHOM.FastHome = 500;
SHOM.uFastHome = 0;
SHOM.SlowHome = 20;
SHOM.uSlowHome = 0;
SHOM.HomeDelta = 300;
SHOM.uHomeDelta = 0;
SHOM.HomeFlags = HOME_STOP_FIRST_LIM;
set_home_settings(SHOM);

/*
* Check for encoder
*/
var encoder = 1
command_zero()
var first = get_status().EncPosition
command_movr(100)
command_wait_for_stop(300)
var second = get_status().EncPosition
if(abs(second - first) < 2)
{
  encoder = 0
  log("It seems like here are no encoder", 2)
}

command_home();
command_wait_for_stop(300);
command_zero();
msleep(200);
// Store old move settings
var MOV = get_move_settings();

// Set fast speed and accel\decel
var MOV2 =get_move_settings();
MOV2.Speed = MOV.Speed * 2;
MOV2.Accel = MOV.Accel * 2;
MOV2.Decel = MOV.Decel * 2;

for(var i=0; i < 1; i++) // Set default settings first
{
  set_move_settings(MOV2);

  // Move long...
  command_move(20000);
  command_wait_for_stop(300);

  // Set prev settings back
  set_move_settings(MOV);

  // Move back
  command_move(0);
  command_wait_for_stop(300);
}

if (encoder > 0)
{
  var lost = get_status().EncPosition
  if (abs(lost) > 1)
  {
    log("Lost " + lost + " pulses", 1)
  }
  else
  {
    log("All is OK");
  }
}
else
{
  log("Do final homing...")
  command_home()
  command_wait_for_stop(300)
  var  lost = get_status().CurPosition
  if (abs(lost) > 2)
  {
    log("Lost " + lost + " steps", 1)
  }
  else
  {
    log("All is OK");
  }
}

6.5.4.23. Sync test script

/*
* Sync test script
*
* Description of the script:
*  The script is written to demonstrate the work of synchronization, and also checks its operability
*
* For test you must short special pins on the controller. Pin 5 (sync in) and pin 6 (sync out). See https://doc.xisupport.com/en/8smc5-usb/8SMCn-USB/Technical_specification/Appearance_and_connectors/One_axis_system.html
*
* Note: This is a rather difficult script to learn, since it uses a large number of commands and structures.
*
* To run the script, upload it to the XILab software
*/

const dX = 4.5;
const dot_num = 5;
const micro2mili = 1000;

var ASIA = [];

for (var i = 0; i < dot_num; i++)
  ASIA[i] = new Object();

var calb = new_calibration(1, MICROSTEP_MODE_FRAC_256);

function abs(x)
{
  return (x > 0) ? x : -x;
}

function set_default()
{
  // SSNI settings
  var SSNI = get_sync_in_settings_calb(calb);
  SSNI.SyncInFlags = SYNCIN_ENABLED | SYNCIN_GOTOPOSITION;
  set_sync_in_settings_calb(SSNI, calb);

  // SSNO settings
  var SSNO = get_sync_out_settings(calb);
  SSNO.SyncOutFlags = SYNCOUT_ENABLED;
  SSNO.Accuracy = 0.5;
  set_sync_out_settings(SSNO, calb);

  // SMOV settings
  var SMOV = get_move_settings_calb(calb);
  SMOV.Speed = 1000;
  SMOV.Accel = 500;
  SMOV.Decel = 1000;
  SMOV.AntiplaySpeed = 50;
  set_move_settings_calb(SMOV, calb);

  // SENG settings
  var SENG = get_engine_settings();
  SENG.NomSpeed = 5000;
  SENG.EngineFlags = ENGINE_ACCEL_ON | ENGINE_LIMIT_VOLT | ENGINE_LIMIT_CURR;
  SENG.Antiplay = 50;
  SENG.MicrostepMode = MICROSTEP_MODE_FRAC_256;
  SENG.StepsPerRev = 200;
  set_engine_settings(SENG);
}

function send_all_asia()
{
  for (var i = 0; i < dot_num; i++)
    command_add_sync_in_action_calb(ASIA[i], calb);
}

function check_all_asia()
{
  var GETS;

  for (var i = 0; i < dot_num; i++)
  {
    log("> Checking movement ASIA[" + i + "]", 3);
    msleep(ASIA[i].Time / micro2mili);
    GETS = get_status_calb(calb);
    if (abs(GETS.CurPosition - ASIA[i].Position) < dX)
      log(">>> OK! GETS.CurSpeed = " + GETS.CurSpeed, 3);
    else
      log(">>> Error! GETS.CurPosition = " + GETS.CurPosition + ", ASIA[" + i + "].Position = " + ASIA[i].Position, 1);
    }
}

function test1()
{
  ASIA[0].Position = 22.5;
  ASIA[0].Time = 300000;

  ASIA[1].Position = 45.0;
  ASIA[1].Time = 300000;

  ASIA[2].Position = 32.5;
  ASIA[2].Time =300000;

  ASIA[3].Position = 10;
  ASIA[3].Time = 300000;

  ASIA[4].Position = -11.5;
  ASIA[4].Time = 300000;
}

function test2()
{
  ASIA[0].Position = -22.5;
  ASIA[0].Time = 300000;

  ASIA[1].Position = -45.0;
  ASIA[1].Time = 300000;

  ASIA[2].Position = -32.5;
  ASIA[2].Time =300000;

  ASIA[3].Position = -10;
  ASIA[3].Time = 300000;

  ASIA[4].Position = 11.5;
  ASIA[4].Time = 300000;
}

function test3()
{
  ASIA[0].Position = -6;
  ASIA[0].Time = 300000;

  ASIA[1].Position = 6;
  ASIA[1].Time = 300000;

  ASIA[2].Position = -6;
  ASIA[2].Time =300000;

  ASIA[3].Position = 6;
  ASIA[3].Time = 300000;

  ASIA[4].Position = -6;
  ASIA[4].Time = 300000;
}

command_zero();
set_default();
log(">>> Function test1() started", 3)
test1();
send_all_asia();
check_all_asia();
msleep(500);

command_zero();
set_default();
log(">>> Function test2() started", 3)
test2();
send_all_asia();
check_all_asia();
msleep(500);

command_zero();
set_default();
log(">>> Function test3() started", 3)
test3();
send_all_asia();
check_all_asia();
msleep(500);

6.5.4.24. Sync bug test script

/*
* Sync bug test script
*
* Description of the script:
*  This script does synchronization test to find sync bug in firmware 3.9.9, 3.8.7, 3.9.10.
*  This test only for hardware from ver. 2.2.0 to ver. 2.2.4.
*  To begin the test, the first what you need to do is connect synchronization pin 15 to pin 16 on CN1 jack.
*  The scripts automatically set all necessary settings for test, and automatically beginning the test.
*  As a result you will see a log message with current position of motor and text OK! (green text) or ERROR! (red text).
*
* Note: This is a rather difficult script to learn, since it uses a large number of commands and structures.
*
* To run the script, upload it to the XILab software
*/

var axes = [];
var number_of_axes = 0;
var last_serial = 0;

while (serial = get_next_serial(last_serial)) // get next serial number and repeat for each axes.
{
  axes[number_of_axes] = new_axis(serial);
  number_of_axes++;
  last_serial = serial;
  log("Found axis " + number_of_axes + " with serial number " + serial);
}

// SSNI settings
var SSNI = get_sync_in_settings;
SSNI.SyncInFlags = SYNCIN_ENABLED | SYNCIN_GOTOPOSITION; //set flags for synchronization in for enabled and absolute position
SSNI.ClutterTime = 4;// set sync in Clutter Time
SSNI.Position = 0;// set sync in absolute position
SSNI.Speed = 500;// set sync in speed
set_sync_in_settings(SSNI);// set synchronization in settings

// GSNO settings
var GSNO = get_sync_out_settings;
GSNO.SyncOutFlags = SYNCOUT_ENABLED | SYNCOUT_ONPERIOD;  // set flags for synchronization out for enabled out and period
GSNO.SyncOutPeriod = 200;// set sync out period
GSNO.SyncOutPulseSteps = 2000;// set sync out Pusle width
set_sync_out_settings(GSNO);  // set synchronization out settings

for (i = 0; i < 10; i++)  // testing cycle
{
  GETS = get_status();// get information about device
  command_movr(201, 0);  // shifting position for 201 steps
  command_wait_for_stop(100); // Wait until the movement is complete

  if (GETS.CurPosition != 0)// get device current position and compare it with 0
  {
    log(">>> Error! GETS.CurPosition = " + GETS.CurPosition, 1);// log ERROR, bug is exist
  }
  else
  {
    log(">>> OK! GETS.CurPosition = " + GETS.CurPosition, 3); // log OK, bug does not exist
  }
}
[1]Seeking beyond the end of a file: If the position is beyond the end of a file, then seek() shall not immediately extend the file. If a write is performed at this position, then the file shall be extended. The content of the file between the previous end of file and the newly written data is UNDEFINED and varies between platforms and file systems.