Basic Example (Hello Zaber)

The following complete example demonstrates the basic usage of the library. Running the program will make your Zaber device move.

Before running the code, replace the placeholder port name with the name of your port (for example COM2). If you are uncertain about the name, see our guide to finding the right port.

Python
C#
C++
JavaScript
MATLAB
Java
Swift
Octave
MATLAB (legacy)
from zaber_motion import Units
from zaber_motion.ascii import Connection

with Connection.open_serial_port("COM3") as connection:
    connection.enable_alerts()

    device_list = connection.detect_devices()
    print("Found {} devices".format(len(device_list)))

    device = device_list[0]

    axis = device.get_axis(1)
    if not axis.is_homed():
      axis.home()

    # Move to 10mm
    axis.move_absolute(10, Units.LENGTH_MILLIMETRES)

    # Move by an additional 5mm
    axis.move_relative(5, Units.LENGTH_MILLIMETRES)
using System;
using Zaber.Motion;
using Zaber.Motion.Ascii;

namespace csharp
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var connection = Connection.OpenSerialPort("COM3")) {
                connection.EnableAlerts();

                var deviceList = connection.DetectDevices();
                Console.WriteLine($"Found {deviceList.Length} devices.");

                var device = deviceList[0];

                var axis = device.GetAxis(1);
                if (!axis.IsHomed())
                {
                    axis.Home();
                }

                // Move to 10mm
                axis.MoveAbsolute(10, Units.Length_Millimetres);

                // Move by an additional 5mm
                axis.MoveRelative(5, Units.Length_Millimetres);
            }
        }
    }
}
const { Length, ascii: { Connection } } = require('@zaber/motion');

async function main() {
  const connection = await Connection.openSerialPort('COM3');
  try {
    await connection.enableAlerts();

    const deviceList = await connection.detectDevices();
    console.log(`Found ${deviceList.length} devices.`);

    const device = deviceList[0];

    const axis = device.getAxis(1);
    if (!await axis.isHomed()) {
      await axis.home();
    }

    // Move to 10mm
    await axis.moveAbsolute(10, Length.mm);

    // Move by an additional 5mm
    await axis.moveRelative(5, Length.mm);
  } finally {
    // close the port to allow Node.js to exit
    await connection.close();
  }
}

main();
#include <iostream>
#include <vector>
#include <exception>
#include <zaber/motion/ascii.h>

using namespace zaber::motion;
using namespace zaber::motion::ascii;

int main() {
    try {
        Connection connection = Connection::openSerialPort("COM3");
        connection.enableAlerts();

        std::vector<Device> deviceList = connection.detectDevices();
        std::cout << "Found " << deviceList.size() << " devices" << std::endl;

        Device device = deviceList[0];

        Axis axis = device.getAxis(1);
        if (!axis.isHomed()) {
            axis.home();
        }

        // Move to 10mm
        axis.moveAbsolute(10, Units::LENGTH_MILLIMETRES);

        // Move by an additional 5mm
        axis.moveRelative(5, Units::LENGTH_MILLIMETRES);

        return 0;
    } catch (const std::exception& e) {
        // Print the error before crashing the program.
        std::cerr << e.what() << std::endl;
        throw;
    }
}
package com.someone.example;

import zaber.motion.Units;
import zaber.motion.ascii.Axis;
import zaber.motion.ascii.Connection;
import zaber.motion.ascii.Device;

/**
 * Example Java Zaber application
 */
public class App
{
    public static void main(String[] args)
    {
        try (Connection connection = Connection.openSerialPort("COM3")) {
            connection.enableAlerts();

            Device[] deviceList = connection.detectDevices();
            System.out.println(String.format("Found %d devices.", deviceList.length));

            Device device = deviceList[0];

            Axis axis = device.getAxis(1);
            if (!axis.isHomed()) {
                axis.home();
            }

            // Move to 10mm
            axis.moveAbsolute(10, Units.LENGTH_MILLIMETRES);
            // Move by an additional 5mm
            axis.moveRelative(5, Units.LENGTH_MILLIMETRES);
        }
    }
}
import zaber.motion.ascii.Connection;
import zaber.motion.Units;

connection = Connection.openSerialPort('COM3');
try
    connection.enableAlerts();

    deviceList = connection.detectDevices();
    fprintf('Found %d devices.\n', deviceList.length);

    device = deviceList(1);

    axis = device.getAxis(1);
    if ~axis.isHomed()
        axis.home();
    end

    % Move to 10mm
    axis.moveAbsolute(10, Units.LENGTH_MILLIMETRES);
    % Move by an additional 5mm
    axis.moveRelative(5, Units.LENGTH_MILLIMETRES);

    connection.close();
catch exception
    connection.close();
    rethrow(exception);
end
javaaddpath("motion-library-jar-with-dependencies.jar");

CONNECTION_CLASS = "zaber.motion.ascii.Connection";
LENGTH_MILLIMETRES = java_get("zaber.motion.Units", "LENGTH_MILLIMETRES");

connection = javaMethod("openSerialPort", CONNECTION_CLASS, "COM3");
try
    connection.enableAlerts();

    deviceList = connection.detectDevices();
    fprintf("Found %d devices.\n", length(deviceList));

    device = deviceList(1);

    axis = device.getAxis(1);
    if (!axis.isHomed())
        axis.home();
    endif

    % Move to 10mm
    axis.moveAbsolute(10, LENGTH_MILLIMETRES);
    % Move by an additional 5mm
    axis.moveRelative(5, LENGTH_MILLIMETRES);

    connection.close();
catch exception
    connection.close();
    rethrow(exception);
end
import ZaberMotion
import ZaberMotionAscii
import ZaberMotionExceptions

do {
    let connection = try await Connection.openSerialPort(
        portName: "/dev/tty.usbserial-A4017DXH"
    )
    try await connection.enableAlerts()

    let deviceList = try await connection.detectDevices()
    print("Found \(deviceList.count) devices.")

    let device = deviceList[0]
    let axis = try device.getAxis(axisNumber: 1)

    if !(try await axis.isHomed()) {
        try await axis.home()
    }

    // Move to 10mm
    try await axis.moveAbsolute(position: 10, unit: Units.Length.mm)
    // Move by additional 5mm
    try await axis.moveRelative(position: 10, unit: Units.Length.mm)
} catch let e as MotionLibException {
    print(e.toString())
} catch {
    print("Error: \(error)")
}
import zaber.motion.ascii.Connection;
import zaber.motion.Units;

connection = Connection.openSerialPort('COM3');
try
    connection.enableAlerts();

    deviceList = connection.detectDevices();
    fprintf('Found %d devices.\n', length(deviceList));

    device = deviceList(1);

    axis = device.getAxis(1);
    if ~axis.isHomed()
        axis.home();
    end

    % Move to 10mm
    axis.moveAbsolute(10, Units.LengthMillimetres);
    % Move by an additional 5mm
    axis.moveRelative(5, Units.LengthMillimetres);

    connection.close();
catch exception
    connection.close();
    rethrow(exception);
end
LabView

Detailed Explanation

The following section provides detailed explanation of the example code along with some additional information about Zaber devices.

Opening a Connection

Python
C#
C++
JavaScript
MATLAB
Java
Swift
Octave
MATLAB (legacy)
with Connection.open_serial_port("COM3") as connection:
    connection.enable_alerts()
    # ...
using (var connection = Connection.OpenSerialPort("COM3")) {
    connection.EnableAlerts();
    // ...
}
const connection = await Connection.openSerialPort('COM3');
try {
  await connection.enableAlerts();
  // ...
connection = Connection.openSerialPort('COM3');
try
    connection.enableAlerts();
    % ...
    connection.close();
catch exception
    connection.close();
    rethrow(exception);
end
} finally {
  // close the port to allow Node.js to exit
  await connection.close();
}
try (Connection connection = Connection.openSerialPort("COM3")) {
    connection.enableAlerts();
    // ...
}
connection = Connection.openSerialPort('COM3');
try
    connection.enableAlerts();
    % ...
    connection.close();
catch exception
    connection.close();
    rethrow(exception);
end
connection = javaMethod("openSerialPort", CONNECTION_CLASS, "COM3");
try
    connection.enableAlerts();
    % ...
    connection.close();
catch exception
    connection.close();
    rethrow(exception);
end
Connection connection = Connection::openSerialPort("COM3");
connection.enableAlerts();
let connection = try await Connection.openSerialPort(
    portName: "/dev/tty.usbserial-A4017DXH"
)
try await connection.enableAlerts()
// ...
LabView

The first step towards communicating with the device is opening a connection. In the example we create a connection by opening a serial port but the library supports other ways such as TCP. If you encounter a problem at this step, head to the Troubleshooting section below.

The code also demonstrates use of a try-catch statement to ensure that the serial port closes in case of an exception.

Calling the enableAlerts method allows devices to communicate back without preceding requests. This allows more timely detection of the end of movement when using ZML. If you are planning to implement your own low-level communication (e.g. using Arduino), alert handling may increase the complexity of your implementation. Additionally, some of Zaber's legacy software may not be able to handle alerts. In such cases, you can omit this line or later set comm.alert setting back to 0.

Detecting devices

Calling the detectDevices method searches the connection for all the present devices and performs their identification.

Python
C#
C++
JavaScript
MATLAB
Java
Swift
Octave
MATLAB (legacy)
device_list = connection.detect_devices()
print("Found {} devices".format(len(device_list)))
var deviceList = connection.DetectDevices();
Console.WriteLine($"Found {deviceList.Length} devices.");
const deviceList = await connection.detectDevices();
console.log(`Found ${deviceList.length} devices.`);
Device[] deviceList = connection.detectDevices();
System.out.println(String.format("Found %d devices.", deviceList.length));
deviceList = connection.detectDevices();
fprintf('Found %d devices.\n', deviceList.length);
deviceList = connection.detectDevices();
fprintf('Found %d devices.\n', length(deviceList));
deviceList = connection.detectDevices();
fprintf("Found %d devices.\n", length(deviceList));
std::vector<Device> deviceList = connection.detectDevices();
std::cout << "Found " << deviceList.size() << " devices" << std::endl;
let deviceList = try await connection.detectDevices()
print("Found \(deviceList.count) devices.")
LabView

During the identification, the library connects to the internet to retrieve information about Zaber devices. No personal or identifying information is exchanged with Zaber servers. The library stores all the information in the operating system cache folder to later allow for offline use. For more information about the behaviour see Device Database.

Homing the Device

After detecting the devices, we pick the first device from the list and make sure it's homed.

Python
C#
C++
JavaScript
MATLAB
Java
Swift
Octave
MATLAB (legacy)
device = device_list[0]

axis = device.get_axis(1)
if not axis.is_homed():
  axis.home()
var device = deviceList[0];

var axis = device.GetAxis(1);
if (!axis.IsHomed())
{
    axis.Home();
}
const device = deviceList[0];

const axis = device.getAxis(1);
if (!await axis.isHomed()) {
  await axis.home();
}
Device device = deviceList[0];

Axis axis = device.getAxis(1);
if (!axis.isHomed()) {
    axis.home();
}
device = deviceList(1);

axis = device.getAxis(1);
if ~axis.isHomed()
    axis.home();
end
device = deviceList(1);

axis = device.getAxis(1);
if ~axis.isHomed()
    axis.home();
end
device = deviceList(1);

axis = device.getAxis(1);
if (!axis.isHomed())
    axis.home();
endif
Device device = deviceList[0];

Axis axis = device.getAxis(1);
if (!axis.isHomed()) {
    axis.home();
}
let device = deviceList[0]
let axis = try device.getAxis(axisNumber: 1)

if !(try await axis.isHomed()) {
    try await axis.home()
}
LabView

Homing a device moves it so that it finds a reference position. A reference position is necessary in order to perform accurate absolute position movements. The device retains the reference position until it's powered off, so repeated homing is unnecessary as long as power is maintained.

Note that homing is performed using the axis object rather than the device object. Some devices have multiple axes, so the Axis class allows control of a specific axis on the device. Axes are indexed from 1. Therefore the code above homes the first axis of the device.

Moving the Device

Once homed, we can start moving the device by calling moveAbsolute and moveRelative methods.

Python
C#
C++
JavaScript
MATLAB
Java
Swift
Octave
MATLAB (legacy)
# Move to 10mm
axis.move_absolute(10, Units.LENGTH_MILLIMETRES)

# Move by an additional 5mm
axis.move_relative(5, Units.LENGTH_MILLIMETRES)
// Move to 10mm
axis.MoveAbsolute(10, Units.Length_Millimetres);

// Move by an additional 5mm
axis.MoveRelative(5, Units.Length_Millimetres);
// Move to 10mm
await axis.moveAbsolute(10, Length.mm);

// Move by an additional 5mm
await axis.moveRelative(5, Length.mm);
// Move to 10mm
axis.moveAbsolute(10, Units.LENGTH_MILLIMETRES);
// Move by an additional 5mm
axis.moveRelative(5, Units.LENGTH_MILLIMETRES);
% Move to 10mm
axis.moveAbsolute(10, Units.LENGTH_MILLIMETRES);
% Move by an additional 5mm
axis.moveRelative(5, Units.LENGTH_MILLIMETRES);
% Move to 10mm
axis.moveAbsolute(10, Units.LengthMillimetres);
% Move by an additional 5mm
axis.moveRelative(5, Units.LengthMillimetres);
% Move to 10mm
axis.moveAbsolute(10, LENGTH_MILLIMETRES);
% Move by an additional 5mm
axis.moveRelative(5, LENGTH_MILLIMETRES);
// Move to 10mm
axis.moveAbsolute(10, Units::LENGTH_MILLIMETRES);

// Move by an additional 5mm
axis.moveRelative(5, Units::LENGTH_MILLIMETRES);
// Move to 10mm
try await axis.moveAbsolute(position: 10, unit: Units.Length.mm)
// Move by additional 5mm
try await axis.moveRelative(position: 10, unit: Units.Length.mm)
LabView

At a low level, the devices operate in native units related to their drive type, such as microsteps for a stepper driver or encoder counts for a direct drive device. The library allows you to specify real-world units like millimetres, and handles the conversion to the specific native units. Use native units directly by omitting the second argument in the move methods, or by specifying the units to be native. To read more about native units refer, to the ASCII Protocol manual.

The above movements will execute one after the other, with the program waiting for the movement to finish before continuing. This behaviour can be controlled by including a third argument in the move method, with a boolean false indicating that the method should not wait.

If you have a rotary device use Units.AngleDegrees in the code above.

Troubleshooting

Connection Failed Exception

Ensure that you have specified the correct serial port name. Check also that other applications, such as Zaber Console, do not have the port open by either selecting Close or exiting the application. Using the Zaber Launcher application does not cause a conflict over the serial port.

No Device Found Exception

Check that the device is connected correctly and powered on. Also ensure that you have specified the correct serial port name. You can use the Zaber Launcher application to verify communication with the devices.

Device Address Conflict Exception

If you encounter DeviceAddressConflictException , open the port in the Zaber Launcher application which will automatically reassign unique addresses to your devices.

Project Download

Additionally, we provide a download link to a complete project for each programming language.