Synchronous Axes Movement (Lockstep)

This example shows how to perform synchronous movement (lockstep) of two axes. Examples assumes one device with two axes. Typical usage of lockstep is parallel gantry mechanism. Further technical information can be found in the following article:

https://www.zaber.com/technical-articles/driving-parallel-axes-with-lockstep-movement

Goal is to perform movement to initial position of 50 mm and then move for 3 second at slow speed. The second axis must have constant offset of 20 mm to the first axis all the time. See the picture.

Synchronous Axes Movement

Program will initially retrieve lockstep information from the device. If the lockstep is not enabled program performs procedure to activate it. Procedure first homes both axes and then set axis 2 to designated offset of 20 mm. Then lockstep is enabled upon axis 1 and 2. From that point on both axes will move synchronously.

# retrieve lockstep info
info = lockstep.info()
# if lockstep is not enabled execute following procedure before movement
if not info.is_enabled:
    # home both axes
    axis1.home()
    axis2.home()

    # set axis2 to offset of 20 mm
    offset_position = int(20 * 1000 / DEVICE_MICROSTEP_SIZE_MICROMETERS)
    axis2.move_abs(offset_position)

    # enable lockstep
    lockstep.enable(axis1=AXIS_1_NUMBER, axis2=AXIS_2_NUMBER)

Procedure of enabling lockstep serves solely to demonstrate functionality of library. Proper lockstep setup involves mechanical mounting. Instruction from article referenced at top of the page should be followed. In your actual automation program if lockstep is not enabled program should most likely exit with error.

Program continues with movement execution using lockstep object. First homing is performed following by movement to initial position of 50 mm. Then lockstep.move_vel(velocity) starts movement at specific speed. Program waits 3 second and stops movement using lockstep.stop(). At the end homing is performed to return device to default position.

# home lockstep
lockstep.home()

# move to initial distance of 50 mm
initial_position = int(50 * 1000 / DEVICE_MICROSTEP_SIZE_MICROMETERS)
lockstep.move_abs(initial_position)

# start moving at velocity of 5 mm/s
velocity = int(5 * 1000 / DEVICE_MICROSTEP_SIZE_MICROMETERS * DEVICE_TIME)
lockstep.move_vel(velocity)
# wait 3 seconds
time.sleep(3)
# stop movement
lockstep.stop()

# home lockstep
lockstep.home()

Once the lockstep is enabled device will always move axes synchronously. All commands performing movement of just one axis will fail. This includes also commands sent from other software as Zaber Console. In order to move both axes lockstep object must be used.

Lockstep can be turned off by calling lockstep.disable(). Disabling lockstep makes axes move independently again. Doing so when axes are mechanically tied may result in damaging devices and other equipment.

# uncomment following line to disable the lockstep at the end
# lockstep.disable()

Please change the port in the code to appropriate port on you computer (e.g. COM3). Note that when the program is running, no other program can access the computer port.

# choose appropriate port on your computer (currently COM5)
SERIAL_PORT = "COM5"

Example is using mathematical conversion between device specific microsteps and millimeters. Correct conversion results depend on right value of constant:

# device specific value used to convert distance to microsteps
DEVICE_MICROSTEP_SIZE_MICROMETERS = 0.15625  # micrometers

Please set appropriate values depending on what device is used. Values can be found in devices’ datasheets as “Microstep Size (Default Resolution)”.

More details on lockstep can be found in the following document: https://www.zaber.com/wiki/Manuals/ASCII_Protocol_Manual#lockstep

Example code (Download):

import time
from zaber.serial import AsciiSerial, AsciiDevice

# device specific value used to convert distance to microsteps
DEVICE_MICROSTEP_SIZE_MICROMETERS = 0.15625  # micrometers
# zaber specific value used to convert time
DEVICE_TIME = 1.6384

# choose appropriate port on your computer (currently COM5)
SERIAL_PORT = "COM5"

# assuming the device has number 1
DEVICE_NUMBER = 1

# lockstep will be activated upon axes 1 and 2
AXIS_1_NUMBER = 1
AXIS_2_NUMBER = 2


def main():
    # choose appropriate port on your computer (currently COM5)
    port = AsciiSerial(SERIAL_PORT)

    # assuming designated device has number 1
    device = AsciiDevice(port, DEVICE_NUMBER)

    # creating manipulation objects for axes
    axis1 = device.axis(AXIS_1_NUMBER)
    axis2 = device.axis(AXIS_2_NUMBER)

    # creating manipulation object for lockstep
    lockstep = device.lockstep()

    # retrieve lockstep info
    info = lockstep.info()
    # if lockstep is not enabled execute following procedure before movement
    if not info.is_enabled:
        # home both axes
        axis1.home()
        axis2.home()

        # set axis2 to offset of 20 mm
        offset_position = int(20 * 1000 / DEVICE_MICROSTEP_SIZE_MICROMETERS)
        axis2.move_abs(offset_position)

        # enable lockstep
        lockstep.enable(axis1=AXIS_1_NUMBER, axis2=AXIS_2_NUMBER)

    # at this point lockstep is always enabled and axes move synchronously
    # from this point all movements must be performed using "lockstep" object

    # home lockstep
    lockstep.home()

    # move to initial distance of 50 mm
    initial_position = int(50 * 1000 / DEVICE_MICROSTEP_SIZE_MICROMETERS)
    lockstep.move_abs(initial_position)

    # start moving at velocity of 5 mm/s
    velocity = int(5 * 1000 / DEVICE_MICROSTEP_SIZE_MICROMETERS * DEVICE_TIME)
    lockstep.move_vel(velocity)
    # wait 3 seconds
    time.sleep(3)
    # stop movement
    lockstep.stop()

    # home lockstep
    lockstep.home()

    # uncomment following line to disable the lockstep at the end
    # lockstep.disable()


# run main function on program start
if __name__ == '__main__':
    main()