Software/Zaber Console/Python

From ZaberWiki
Jump to navigation Jump to search

The Zaber Console Script Editor can be used to send a list of commands to Zaber devices in order to automate a task. You can also make a script decide which actions to perform and repeat a list of actions several times. This page describes how to write scripts in Python. Zaber console also supports common Microsoft.NET languages like C#, Visual Basic.NET, and Javascript.NET, but those are described on the scripting page.

Please note that scripting in Zaber Console is not recommended for new development; please consider using the Zaber Motion Library instead.

Scripting for non-programmers

Even if you're not a programmer, you can use scripts that someone else has already written. Several sample scripts are included with the Zaber Console. More sample scripts can be found below. Scripts are usually not difficult to decipher even for non-programmers. If you can find a script that does something close to what you want, you can often modify it to do exactly what you want, simply by changing the numbers or combining parts of other scripts.

If you can't convince one of these scripts to do exactly what you need, we are pleased to offer custom software development services. Simply let us know what you want to do, no matter how trivial or complex, and we'll be happy to give you an estimate. Contact us for more information.

Running existing scripts

Many sample scripts are included with the Zaber Console. Scripts can be executed either by clicking on the "Run" button next to the desired script in the Scripts tab, or by opening a script with the Script Editor and selecting "Run Script" from the Run menu.

Binary vs. ASCII mode

Scripts either send commands in Binary protocol or ASCII protocol. For example, move absolute can either be Conversation.Request(Command.MoveAbsolute, 10000) (Binary protocol) or Conversation.Request("move abs 10000") (ASCII protocol). The devices default communication protocol depends on the series it belongs to. X-Series devices default to ASCII, T-Series and A-Series devices default to Binary. See more information on each of these protocols in the (ASCII protocol manual and the Binary protocol manual).

Basic script syntax

When viewing and modifying the sample scripts, the following descriptions of some common script syntax should help you understand what's going on. Note that Python scripts don't use templates, so you don't need the #template() declaration.

conversation.Request(Command.XXXXX,DDDDD) (Binary mode)
conversation.Request("XXXXX DDDDD") (ASCII mode)
This sends a request to the selected device and waits for a response. XXXXX should be replaced with the name of a command, and DDDDD should be replaced with command data. Some common binary commands are Home, MoveAbsolute, MoveRelative, MoveAtConstantSpeed, Stop, and ReturnSetting. The ASCII equivalents are home, move abs, move rel, move vel, stop, and get.
conversation.Send(Command.XXXXX,DDDDD) (Binary mode)
conversation.Send("XXXXX DDDDD") (ASCII mode)
This sends a request to the selected device without waiting for a response. That means that the script execution will proceed immediately without waiting for the device to respond, and when the device does respond, its response will be ignored by the script. XXXXX should be replaced with the name of a command, and DDDDD should be replaced with command data.
You can see a complete list of available commands for any device in the Zaber Console. Select the device from the device list and look at the commands tab. Any command in the list can be used in place of XXXXX above. In binary mode, simply remove the spaces from the command name shown. The rest of the commands appear in the Settings tab. For any read-only setting in binary mode, just add "Return" to the start of the name (e.g., ReturnFirmwareVersion). For the other settings in binary mode, add "Set" to the start of the name to set the value. In ASCII mode, just add "get " or "set " before the command name. You can always look in the log window to see what command is being sent when you click on a button.
sleep(DDDDD)
This causes the script execution to pause for a number of milliseconds specified by DDDDD.
print "SSSSSS"
This prints a line of text SSSSSS to the output tab.

Sample Scripts

This tutorial section will walk you through a series of scripts where each script adds a new feature. We include a separate version of each script for binary and ASCII modes. Follow these steps to run one of the scripts:

  1. Read the beginning of the script to see what language and mode it's written in.
  2. Use the mouse to select the script. Make sure you don't select anything else before or after the script.
  3. Type Ctrl-C to copy the script to the clipboard.
  4. Run the Zaber Console or switch back to it if it's already running.
  5. Most scripts assume the Zaber devices are turned on and the port is already open, so click the Open button if you need to. Make sure that you are running a binary mode script if your devices are running in binary mode, or an ASCII mode script if your devices are running in ASCII mode. After you open the port, you should see a list of devices that includes more than just "All Devices".
  6. Click on the scripts tab.
  7. Click on the Script Editor... button.
    If this is the first time you've opened the script editor, it will prompt you for a folder to hold your scripts. You should create a new folder somewhere and select that. Creating a folder called Zaber Scripts under My Documents is a good choice.
  8. In the Script Editor window, click on the Language menu and click the language that the script is written in.
  9. From the File menu, choose New.
  10. Click in the main field and type Ctrl-V to paste the script.
  11. Some scripts need you to select a device number, click on the drop down to see a list of device numbers.
  12. Click the Run Script button.

If you want to keep the script to run again another time, click the File menu and choose Save Script As.... Then type a file name for the script in your scripts folder. Be sure to end the name with the right extension: ".py" for Python. Once you've saved it, it will appear in the list on the Scripts tab of Zaber Console.

A list of commands

The simplest script you can write is just a list of commands with no logic. The script makes a request, waits for the response, and then makes the next request until it gets to the end of the list. The ASCII command scripts use PollUntilIdle() to wait until the device has finished moving.

This script makes the selected device take 5 steps backwards, and then extend back to where it started. Open the port before running this script. The device has to start at least 50000 microsteps away from the home position, so if you receive the RelativePositionInvalid error or BADDATA error, just extend the device before running the script.

# A list of binary commands sample - Python
conversation.Request(Command.MoveRelative, -10000)
conversation.Request(Command.MoveRelative, -10000)
conversation.Request(Command.MoveRelative, -10000)
conversation.Request(Command.MoveRelative, -10000)
conversation.Request(Command.MoveRelative, -10000)
conversation.Request(Command.MoveRelative, 50000)
# A list of ASCII commands sample - Python
conversation.Request("move rel -10000")
conversation.PollUntilIdle()
conversation.Request("move rel -10000")
conversation.PollUntilIdle()
conversation.Request("move rel -10000")
conversation.PollUntilIdle()
conversation.Request("move rel -10000")
conversation.PollUntilIdle()
conversation.Request("move rel -10000")
conversation.PollUntilIdle()
conversation.Request("move rel 50000")
conversation.PollUntilIdle()


Looping

You can repeat commands using a loop structure like for or while. This example shows how to use for to replace the five MoveRelative -10000 commands in the previous sample. We also introduce variables with the move_count and distance variables.

# Looping sample in binary mode - Python
move_count = 5
distance = 10000
for i in range(move_count):
    conversation.Request(Command.MoveRelative, -distance)
conversation.Request(Command.MoveRelative, move_count*distance)
# Looping sample in ASCII mode - Python
move_count = 5
distance = 10000
for i in range(move_count):
    conversation.Request("move rel", -distance)
    conversation.PollUntilIdle()
conversation.Request("move rel", move_count*distance)
conversation.PollUntilIdle()

Input and output

You can display messages to the user and ask them for input using the standard Python methods. This sample asks the user how many moves to make and how big each move should be.

# Input and output sample in binary mode - Python
move_count = input("How many moves would you like to make?")

distance = input("How many microsteps would you like in each move?")
for i in range(move_count):
    conversation.Request(Command.MoveRelative, -distance)
conversation.Request(Command.MoveRelative, move_count*distance)


# Input and output sample in ASCII mode - Python
move_count = input("How many moves would you like to make?")

distance = input("How many microsteps would you like in each move?")
for i in range(move_count):
    conversation.Request("move rel", -distance)
    conversation.PollUntilIdle()
conversation.Request("move rel", move_count*distance)
conversation.PollUntilIdle()

Response Data

Most commands return some kind of data, and your scripts can use that data. In this sample, we check that there is room for the movement before starting. This sample also introduces conditional logic using the if statement.

# Response data sample in binary mode - Python
import sys

# First check the current position and display it
current_position = conversation.Request(Command.ReturnCurrentPosition).Data
print "Current position is %d microsteps." % current_position

# Ask user for instructions
move_count = input("How many moves would you like to make?")
distance = input("How many microsteps would you like in each move?")
total_distance = move_count * distance

# Check that there is room for the requested moves
if total_distance > current_position:
    # complain to user
    print "Not enough room for that."

    # skip the rest of the script
    sys.exit(0)

# Loop through all the requested moves
new_position = current_position
for _ in range(move_count):
    conversation.Request(Command.MoveRelative, -distance)

# Return to starting position
conversation.Request(Command.MoveRelative, move_count*distance)


# Response data sample in ASCII mode - Python
import sys

# First check the current position and display it
current_position = conversation.Request("get pos").Data
print "Current position is %d microsteps." % current_position

# Ask user for instructions
move_count = input("How many moves would you like to make?")
distance = input("How many microsteps would you like in each move?")
total_distance = move_count * distance

# Check that there is room for the requested moves
if total_distance > current_position:
    # complain to user
    print "Not enough room for that."

    # skip the rest of the script
    sys.exit(0)

# Loop through all the requested moves
new_position = current_position
for _ in range(move_count):
    conversation.Request("move rel", -distance)
    conversation.PollUntilIdle()

# Return to starting position
conversation.Request("move rel", move_count*distance)
conversation.PollUntilIdle()

Response Data: Analog/Digital Inputs

Most commands return some kind of data, and your scripts can use that data. When reading a digital input we would want to return an integer (boolean), but we want a floating point when reading an analog input because we would want to know precisely what the voltage reading is. This example shows how to read the response of a digital input as an integer and the response of an analog input as a floating point, and then print them.

Please note, digital and analog inputs are only available on the MCB1, and MCB2 series controllers.

# Response data from digital and analog inputs sample in ASCII - Python

# Read analog input 1 and convert the response to a floating point value
analog_data = float(conversation.Request("io get ai 1").TextData)
# Output the voltage reading [V]
print analog_data

# Read digital input 1 as an integer value
digital_data = conversation.Request("io get di 1").Data 
print digital_data

Helper methods

Once your scripts get this big, you can often make them more readable by taking repeated code and moving it into separate helper functions. In this sample, we create a helper function that displays a message and asks the user to enter a number. We also create a helper function for making a move and displaying the new position.

# Helper methods sample in binary mode - Python
import sys

def ask_number(question):
    line = raw_input(question)
    return int(line)

def move_and_display(distance):
    new_position = conversation.Request(Command.MoveRelative, distance).Data
    print "New position is %d microsteps." % new_position

# First check the current position and display it
current_position = conversation.Request(Command.ReturnCurrentPosition).Data
print "Current position is %d microsteps." % current_position

# Ask user for instructions
move_count = ask_number("How many moves would you like to make?")
distance = ask_number("How many microsteps would you like in each move?")
total_distance = move_count * distance

# Check that there is room for the requested moves
if total_distance > current_position:
    # complain to user
    print "Not enough room for that."

    # skip the rest of the script
    sys.exit(0)

# Loop through all the requested moves
new_position = current_position
for _ in range(move_count):
    move_and_display(-distance)

# Return to starting position
move_and_display(move_count*distance)


# Helper methods sample in ASCII mode - Python
import sys

def ask_number(question):
    line = raw_input(question)
    return int(line)

def move_and_display(distance):
    conversation.Request("move rel", distance)
    conversation.PollUntilIdle()
    new_position = conversation.Request("get pos").Data
    print "New position is %d microsteps." % new_position

# First check the current position and display it
current_position = conversation.Request("get pos").Data
print "Current position is %d microsteps." % current_position

# Ask user for instructions
move_count = ask_number("How many moves would you like to make?")
distance = ask_number("How many microsteps would you like in each move?")
total_distance = move_count * distance

# Check that there is room for the requested moves
if total_distance > current_position:
    # complain to user
    print "Not enough room for that."

    # skip the rest of the script
    sys.exit(0)

# Loop through all the requested moves
new_position = current_position
for _ in range(move_count):
    move_and_display(-distance)

# Return to starting position
move_and_display(move_count*distance)


Scripting for programmers

Programmers should review all the information provided in the non-programmers section above as that information applies to you as well. In addition, this section will cover more advanced scripting details. You might also be interested in the Zaber Console source code, as well as writing your own plug ins for Zaber Console.

Running existing scripts

There are three ways to run a script, only two of which were covered in the "for non-programmers" section above:

  1. Click the "Run" button next to it in the Zaber Console scripts tab
  2. Open the script in the Script Editor and select "Run Script" from the Run menu.
  3. Use the Script Runner command line application from a command prompt or within a batch file.

The first two options are the easiest since they can be done from within the Zaber Console. The third is only necessary if you want to execute multiple scripts in sequence or execute scripts from a batch file without having to open the Zaber Console application. Script Runner is a different application from the Zaber Console and is only included with the Windows installer, not the Click Once version.

Add the Zaber Console directory to your Windows path.

  1. Open System Properties (Win+Pause)
  2. Switch to the Advanced tab
  3. Click Environment Variables
  4. Select PATH in the System variables section
  5. Click Edit
  6. Add a semicolon to the end of the list and then add Zaber Console's path.
    For example, pretend the path is already this: C:\Program Files\MSOffice
    If you installed in the default location, you would change it to this: C:\Program Files\MSOffice;C:\Program Files\Zaber Technologies\Zaber Console 1.2.X
  7. Click OK. Click OK.

Then open a command prompt or create a batch file and use the following command line syntax:

ScriptRunner [Options] script_name to run a specified script where script_name is the filename of a script to run. The file extension tells ScriptRunner what language to use (e.g, .cs files are run using the C# compiler).
ScriptRunner /showports to display a list of available ports
ScriptRunner /help to display the help file
Options:
/p port_name optional port to open (COM1, COM2, etc) prior to script execution
/m mode optional mode to open the serial port in: 'b' for binary or 'a' for ASCII. The default is binary.
/b baud_rate optional open the serial port with the requested baud rate. This defaults to 9600 in binary mode and 115200 in ASCII mode.
/d device_number optional device number to use for the default conversation object
/a axis_number optional axis number to use for the default conversation object with a multi-axis device in ASCII mode
/f folder_name optional search for scripts and templates in the given folder
/log optional flag to log all requests and responses to the console

Command Line Examples:

ScriptRunner sample.cs run the sample.cs script
ScriptRunner /p COM1 sample.cs open COM1, then run the sample.cs script
ScriptRunner /p COM1 /d 1 sample.cs open conversation to device 1 on COM 1, then run the sample.cs script
ScriptRunner /showports displays a list of available com ports
ScriptRunner /help displays a help screen

Example batch file:

@echo off
scriptrunner /port com1 "All - stop.cs"
pause


Note that some scripts may not require opening the COM port or selecting a device prior to running the script. A script itself can open the COM port and select devices. Therefore it is good practice to specify setup requirements in comments at the top of your scripts.

The script runner will look for template files in a folder called Templates. It will also look in parent folders for the Templates folder.

Templates

Python scripts do not need templates, so don't add a template declaration.

Script Syntax

The language menu in the script editor shows all .NET languages installed on your computer. By default, you should see C#, Visual Basic, JavaScript, and Python. Python works differently from the other languages, which are described on the scripting page.

There are several sample scripts included with the Zaber Console. It's a good idea to open each of them in Script Editor to gain a better understanding of script syntax. There are three different ways to communicate with Zaber devices in your scripts; you can issue instructions at the "port" level, the "device" level or the "conversation" level.

Objects and Classes

There are some predefined objects for communicating with the selected device or port at different levels.

Predefined Object Class
port_facade ZaberPortFacade
port_facade.Port IZaberPort
conversation Conversation
conversation.Device ZaberDevice

These predefined objects are explained in more detail below:

port_facade
A predefined object implementing the ZaberPortFacade class for the selected port. Use a ZaberPortFacade to get to all the objects representing the Zaber devices connected to your serial port. You can use the GetConversation(deviceNumber) or GetDevice(deviceNumber) methods to get the conversation or device object for one of your devices. For more details on all classes and features of the library, read the rest of this section or see the library help file in the Help menu of the Zaber Console script editor.
port_facade.Port
Use this to talk directly to the selected port as follows:
# Python sample script communicating to the "port" using the 
# IZaberPort.Send method in binary mode.
# You must open a port before running the script.
my_port = port_facade.Port;
my_port.Send(1, Command.Home, 0);
sleep(3000);
my_port.Send(1, Command.MoveAbsolute, 100000); 
# Python sample script communicating to the "port" using the 
# IZaberPort.Send method in ASCII mode.
# you must open a port before running the script
my_port = port_facade.Port;
my_port.Send("/1 home");
sleep(3000);
my_port.Send("/1 move abs 100000");
conversation
A predefined object implementing the Conversation class for the selected device. This allows conversation level communications with the currently selected device in Script Editor or Script Runner. (In Script Runner, the selected device would be specified by the command-line parameters.) Communication at the conversation level is synchronous. On sending a request to a device, the execution of your script will wait until the device responds. The response data is accessible by your script. In binary mode, the movement commands don't respond until the movement is finished, and they return the final position as their data value. In ASCII mode, the movement commands respond immediately, so your script has to use PollUntilIdle() to wait for the movement to finish and then get the position from a separate request.
# Python sample of conversation object in binary mode
my_response = conversation.Request(Command.MoveRelative, 20000)
my_position = my_response.Data
print "Current position is %d" % my_position

my_response = conversation.Request(Command.MoveRelative, -10000)
my_position = my_response.Data
print "Current position is %d" % my_position
# Python sample of conversation object in ASCII mode
conversation.Request("move rel", 20000)
conversation.PollUntilIdle()
my_response = conversation.Request("get pos")
my_position = my_response.Data
print "Current position is %d" % my_position

conversation.Request("move rel", -10000)
conversation.PollUntilIdle()
my_response = conversation.Request("get pos")
my_position = my_response.Data
print "Current position is %d" % my_position
conversation.Device
A predefined object implementing the ZaberDevice class for the selected device. This allows device level communications with the currently selected device in Script Editor or Script Runner. (In Script Runner, the selected device would be specified by the command-line parameters.) Communication at the device level is asynchronous. On sending a request to a device, the execution of your script will continue immediately without waiting for a response, and the response data is not accessible by the script. This isn't as useful in ASCII mode, because all ASCII commands respond immediately.
# Python sample script communicating to the current device using the Send method
# you must open a port before running the script
conversation.Device.Send(Command.Home)
sleep(3000)
conversation.Device.Send(Command.MoveAbsolute, 100000)

Methods, Functions, and Statements

port_facade.Port.Send
Sends an instruction to the selected port (does not wait for a response). See the port_facade.Port example above.
port_facade.GetDevice
Gets a ZaberDevice object with the requested device number. See the description of ZaberDevice above.
# Python sample script selecting a specific device using the GetDevice method
# you must open a port before running the script
my_device = port_facade.GetDevice(1)
my_device.Send(Command.Home, 0)
port_facade.GetConversation
Gets a Conversation object with the requested device number. See the description of Conversation above.
# Python sample script selecting a specific conversation using the GetConversation method
# you must open a port before running the script
my_conversation = port_facade.GetConversation(1)
my_conversation.Request(Command.Home)
port_facade.Open
You can open a port from within Zaber Console before running your script or you can specify the port as a command line option when using Script Runner, but sometimes it's preferable to open the port directly from within your script (for example if your script is always run on the same COM port).
# Python sample script opening a port
# Does nothing if port is already open
if not port_facade.IsOpen:          # make sure port is not already open
    port_facade.Open("COM1")        # Open COM1
    sleep(1000)                     # Wait for all devices to reply.

    # your code here

    port_facade.Close()             # Close COM1
conversation.Request
Sends a request to a device synchronously (script waits for a response before continuing).
conversation.Device.Send
Sends a request to a device asynchronously (script continues immediately).
print
Standard Python statement to write a line to the output.
print "Hello World"
input(message)
standard Python function for reading input text from user and parsing it as a number or other data type
num = input("Enter a number: ")
print 5 * num
# If you enter 10, this will print 50
raw_input(message)
standard Python function for reading input text from user
text = raw_input("Enter a number: ")
print 5 * text
# If you enter 10, this will print 1010101010
sleep
waits a specified number of milliseconds
sleep(1000)

Error handling

Communicating over the serial port to Zaber devices sometimes has problems, so you may want to add error handling to your scripts. If you have no error handling, then a communication problem will stop the script and pop up an error message. The devices will finish whatever moves they were executing and then stop. Adding error handling can let your script recover from problems and keep going.

The simplest technique is to avoid communication problems in the first place. The most common cause of problems on T-Series devices is sending commands to two devices at the same time. If they try to respond at the same time, they will occasionally interrupt each other and garble the responses. To avoid this, don't send requests to device zero, and wait for each device to finish its command before sending a request to the next device.

Another simple technique is to write your script so it just restarts when an error occurs. Here's a simple example:

# Python example of simple error handling with a restart strategy
from Zaber import ConversationException

while not is_canceled:
    conversation = port_facade.GetConversation(0)
    conversation.Timeout = 5000
    try:
        while not is_canceled:
            conversation.Request(Command.MoveAbsolute, 0)
            conversation.Request(Command.MoveRelative, 10000)
            conversation.Request(Command.MoveRelative, -7000)
            conversation.Request(Command.MoveRelative, 5000)
    except ConversationException as ex:
        print "Exception: %s" % ex.Message

Note that it starts with an absolute move so that wherever the error occurs in the sequence, it can safely restart.

The next option is to automatically retry any commands that are interrupted by an error. That will usually just make the device send the response again, and the script can continue. The automatic retry feature is smart enough to know which commands are not safe to retry, and it will just report the error for those. One example is the MoveRelative command, so if you want to use the automatic retry feature, all your movements should be absolute. The automatic retry feature is only supported for binary mode, but it's much easier to avoid response collisions in ASCII mode, because all commands respond immediately. Here's a simple example:

# Python example of simple error handling with a retry strategy
# Don't automatically reopen port if Renumber is detected.
# Sometimes a packet collision looks like a Renumber response.
port_facade.IsInvalidateEnabled = False

conversation = port_facade.GetConversation(0)
conversation.RetryCount = 10
while not is_canceled:
    conversation.Request(Command.MoveAbsolute, 0)
    conversation.Request(Command.MoveAbsolute, 10000)
    conversation.Request(Command.MoveAbsolute, 3000)
    conversation.Request(Command.MoveAbsolute, 8000)

Note that all the relative moves have been changed to absolute moves.


More Sample Scripts

Simultaneous moves

Here are some example scripts that show how to move two devices at the same time. There are versions for binary and ASCII mode, as well as an example for multi-axis devices.

# Python sample that demonstrates moving two devices simultaneously
# in binary mode.

# Get conversations for the two devices you want to move.
c1 = port_facade.GetConversation(1)
c2 = port_facade.GetConversation(2)

# Start a topic to wait for the response
topic = c1.StartTopic()
# Send the command using Device.Send() instead of Request()
# Note the topic.MessageId parameter to coordinate request and response
c1.Device.Send(Command.Home, 0, topic.MessageId)

# While c1 is homing, also request c2 to home. This one just uses
# Request() because we want to wait until it finishes.
c2.Request(Command.Home)

# We know c2 has finished homing, so now wait until c1 finishes.
topic.Wait()

# We'll ask c1 to execute a long move, while c2 wiggles back and forth
# with several small moves.
topic = c1.StartTopic()
c1.Device.Send(Command.MoveAbsolute, 100000, topic.MessageId)
while not topic.IsComplete:
	c2.Request(Command.MoveAbsolute, 10000)
	c2.Request(Command.MoveAbsolute, 0)

# We know it's already complete. This just checks for error responses.
topic.Validate()

c1.Request(Command.MoveAbsolute, 0)


# Python sample that demonstrates moving two devices simultaneously
# in ASCII mode.

# Get conversations for the two devices you want to move.
c1 = port_facade.GetConversation(1)
c2 = port_facade.GetConversation(2)

c1.Request("home")
# While c1 is homing, also request c2 to home.
c2.Request("home")
# Wait for both to finish moving. It doesn't matter which
# finishes first, this will check both.
c1.PollUntilIdle()
c2.PollUntilIdle()

# We'll ask c1 to execute a long move, while c2 wiggles back and forth
# with several small moves.
c1.Request("move abs 100000")

# The response to any command includes the IsIdle flag.
while not c1.Request("get pos").IsIdle:
       c2.Request("move abs 10000")
       c2.PollUntilIdle()
       c2.Request("move abs 0")
       c2.PollUntilIdle()

c1.Request("move abs 0")
c1.PollUntilIdle()
# Python sample that demonstrates moving two axes simultaneously
# on a multi-axis device.

# Get conversations for the device you want to use, as well as
# the two axes you want to move.
both = port_facade.GetConversation(1)
axis1 = port_facade.GetConversation(1, 1)
axis2 = port_facade.GetConversation(1, 2)

# When you want both axes to do the same thing, you can send it to the
# conversation for the whole device.
both.Request("home")
# Wait for both to finish moving.
both.PollUntilIdle()

# We'll ask axis 1 to execute a long move, while axis 2 wiggles back and forth
# with several small moves.
axis1.Request("move abs 100000")

# The response to any command includes the IsIdle flag.
while not axis1.Request("get pos").IsIdle:
       axis2.Request("move abs 10000")
       axis2.PollUntilIdle()
       axis2.Request("move abs 0")
       axis2.PollUntilIdle()

axis1.Request("move abs 0")
axis1.PollUntilIdle()

Suppress the Stop command when canceled

Sometimes, you don't want to send a Stop command when you cancel a running script. To do that, you can replace the default cancel() function. This example also shows how to make the sleep() function notice that the script has been canceled before the thread gets aborted.

# Python example to show how to suppress the Stop command when the
# script is canceled.
def cancel():
    global is_canceled
    is_canceled = True

def sleep(milliseconds):
    # Script thread waits 1 second after calling cancel() before
    # aborting, so break up the sleep into 500ms chunks and
    # check is_canceled.
    while milliseconds > 0 and not is_canceled:
        chunk = min(500, milliseconds)
        System.Threading.Thread.Sleep(chunk)
        milliseconds -= chunk

while not is_canceled:
    print "Hello, World!"
    sleep(2000)

Units of Measure

The device and conversation classes will handle unit of measure conversion for you. The simplest technique is to declare a measurement variable that holds a single unit, and then multiply that by the actual value you want, so 50mm becomes 50*mm. Units of measure are supported in both ASCII mode and binary mode. See the ZaberDevice class in the help file for more support of units of measure.

# Unit of measure sample in Binary mode - Python
mm = Measurement(1, UnitOfMeasure.Millimeter)
position = conversation.Request(Command.ReturnCurrentPosition).Measurement
print "Starting position is %s." % position

for _ in range(5):
    conversation.RequestInUnits(Command.MoveRelative, 10*mm)

position = conversation.Request(Command.ReturnCurrentPosition).Measurement
print "Retracted position is %s." % position

conversation.RequestInUnits(Command.MoveRelative, -50*mm)

Note that in ASCII mode, unit of measure is only defined for each axis and not the device itself. Using units of measure on a device conversation will result in an exception.

# Unit of measure sample in ASCII mode - Python
mm = Measurement(1, UnitOfMeasure.Millimeter)
position = conversation.Axes[0].Request("get pos").Measurement
print "Starting position is %s." % position

for _ in range(5):
    conversation.Axes[0].RequestInUnits("move rel", 10*mm)
    conversation.Axes[0].PollUntilIdle()

position = conversation.Axes[0].Request("get pos").Measurement
print "Retracted position is %s." % position

conversation.Axes[0].RequestInUnits("move rel", -50*mm)
conversation.Axes[0].PollUntilIdle()