Non-blocking (simultaneous) axis movement
Movement methods in the library are by default blocking, meaning the method calls return (end) when the issued movement is finished by the device. As a result, by default they only move one axis at a time. In some cases moving multiple axes simultaneously is desirable. For example, simultaneously moving two axes may shorten the movement time.
One option is to use language concurrency mechanisms, such as threads, to manage simultaneous movements. The library also includes an option for simultaneous movement without threads, shown in the following example:
# from zaber_motion.ascii import Connection
# from zaber_motion import Units
axis1 = device.get_axis(1)
axis2 = device.get_axis(2)
axis1.move_absolute(3, Units.LENGTH_CENTIMETRES, wait_until_idle=False)
axis2.move_absolute(3, Units.LENGTH_CENTIMETRES, wait_until_idle=False)
axis1.wait_until_idle()
axis2.wait_until_idle()
var axis1 = device.GetAxis(1);
var axis2 = device.GetAxis(2);
axis1.MoveAbsolute(3, Units.Length_Centimetres, waitUntilIdle: false);
axis2.MoveAbsolute(3, Units.Length_Centimetres, waitUntilIdle: false);
axis1.WaitUntilIdle();
axis2.WaitUntilIdle();
// The JavaScript API does not have synchronous movement methods.
// Consult the next section for an example of asynchronous movement in JavaScript.
// import zaber.motion.ascii.Axis;
// import zaber.motion.ascii.Connection;
// import zaber.motion.ascii.Device;
// import zaber.motion.Units;
Axis axis1 = device.getAxis(1);
Axis axis2 = device.getAxis(2);
axis1.moveAbsolute(3, Units.LENGTH_CENTIMETRES, false);
axis2.moveAbsolute(3, Units.LENGTH_CENTIMETRES, false);
axis1.waitUntilIdle();
axis2.waitUntilIdle();
% import zaber.motion.ascii.Connection;
% import zaber.motion.Units;
axis1 = device.getAxis(1);
axis2 = device.getAxis(2);
axis1.moveAbsolute(3, Units.LENGTH_CENTIMETRES, false);
axis2.moveAbsolute(3, Units.LENGTH_CENTIMETRES, false);
axis1.waitUntilIdle();
axis2.waitUntilIdle();
Axis axis1 = device.getAxis(1);
Axis axis2 = device.getAxis(2);
axis1.moveAbsolute(3, Units::LENGTH_CENTIMETRES, false);
axis2.moveAbsolute(3, Units::LENGTH_CENTIMETRES, false);
axis1.waitUntilIdle();
axis2.waitUntilIdle();
In the example above, movement commands are issued to two axes of one device.
An optional third @arg waitUntilIdle
argument of the @method MoveAbsolute
method is set to false.
This argument value causes the method to return immediately after issuing the move command to the device.
As a result, neither movement is blocking so both axes move simultaneously.
You may still want to wait for both movements to complete though, which can be done using consecutive calls of the @method WaitUntilIdle
method for each of the axes.
Asynchronous operations
For languages which allow asynchronous operations, an alternative approach may be taken:
# import asyncio
# from zaber_motion.ascii import Connection
# from zaber_motion import Units
axis1_coroutine = axis1.move_absolute_async(3, Units.LENGTH_CENTIMETRES)
axis2_coroutine = axis2.move_absolute_async(3, Units.LENGTH_CENTIMETRES)
move_coroutine = asyncio.gather(axis1_coroutine, axis2_coroutine)
loop = asyncio.get_event_loop()
loop.run_until_complete(move_coroutine)
var taskAxis1 = axis1.MoveAbsoluteAsync(3, Units.Length_Centimetres);
var taskAxis2 = axis2.MoveAbsoluteAsync(3, Units.Length_Centimetres);
Task.WaitAll(taskAxis1, taskAxis2);
// const { ascii: { Connection }, Length } = require('@zaber/motion');
const promiseAxis1 = axis1.moveAbsolute(3, Length.cm);
const promiseAxis2 = axis2.moveAbsolute(3, Length.cm);
await Promise.all([promiseAxis1, promiseAxis2]);
// import java.util.concurrent.CompletableFuture;
// import java.util.concurrent.ExecutionException;
// import zaber.motion.ascii.Axis;
// import zaber.motion.ascii.Connection;
// import zaber.motion.ascii.Device;
// import zaber.motion.Units;
// add the following to the main() function:
CompletableFuture<Void> futureAxis1 = axis1.moveAbsoluteAsync(3, Units.LENGTH_CENTIMETRES);
CompletableFuture<Void> futureAxis2 = axis2.moveAbsoluteAsync(3, Units.LENGTH_CENTIMETRES);
try {
CompletableFuture.allOf(futureAxis1, futureAxis2).get();
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
% No alternative approach can be taken using the current MATLAB library.
// No alternative approach can be taken using the current C++ library.
In the example above, move commands are issued as coroutines
.
Both coroutines are joined by asyncio.gather
into a single coroutine which is executed on asyncio
event loop.
In the example above, move commands are issued as pending Tasks
.
The program then waits until both Tasks complete.
In the example above, the second move command is issued without awaiting the first command promise. The program awaits both promises together.
In the example above, move commands are issued as CompletableFutures
.
The program then waits until both CompletableFutures complete.
Note that the device can only handle a certain amount of asynchronous parallel requests.
When the device cannot process the issued requests in time or due to lack of space in receive buffers,
the requests start timing out with @class RequestTimeoutException
.