How to control the LSPone via Python and Matlab ?

How to control the LSPone via Python and Matlab ?

Syringe pumps serve as indispensable tools for accurately delivering liquid volumes. Among these, the LSPone stands out in the world of laboratory automation for its exceptional performance and versatility.

In this blog post, we’ll explore how to control the LSPone syringe pump using Python and Matlab. From understanding its capabilities to providing simple step-by-step instructions for setting up communication interfaces and controlling the pump, this post aims to empower researchers of all levels. Whether you’re working on pump control for the very first time or seeking advanced techniques, this guide will empower you in mastering your LSPone syringe pump.

TABLE OF CONTENTS

Why Choose the LSPone Laboratory Syringe Pump ?

The LSPone Laboratory Syringe Pump from Advanced Microfluidics SA is an innovative solution for high-precision dosing in microfluidic research combining high-precision pumping with a low-volume rotary valve. Coupled with the LSPoneQuick software, it can aspirate or dispense liquids, control the flow rate and automate fluid handling.

The LSPone stands out for its exceptional dosing accuracy and near-pulseless flow, catering to diverse liquid handling needs ranging from milliliters to nanoliters. Its zero dead volume selection valve facilitates efficient management of multiple fluids with minimal carryover, while the user-friendly interface ensures effortless operation making the LSPone a perfect choice for laboratory experiments.

Key advantages of the LSPone include its exceptional dead, internal, and carryover volumes that further underscore its superiority. With no dead volume, a carryover volume limited to 1.5 μL and an internal volume of only 4 μL reduced by the small channel diameter of 0.5 mm, this syringe pump offers unmatched precision and control allowing fast liquid switches.

Moreover, the LSPone’s optimized flow paths, which not only limit contamination but also maximize cleanability, ensure impeccable biochemical compatibility. Its high dilution ratio, facilitated by minimal carryover volume, ensures maximal dilution with the diluent, while its unique valve design expels air from the syringe and valve immediately allowing for bubble-free priming.

What Do you Need to Communicate with the LSPone ?

To communicate with the LSPone laboratory syringe pump you will need a few key components:

  • An LSPone laboratory syringe pump with a syringe of your choice,
  • A mini-USB/USB cable or a DB9 connector (RS-232 or RS-485 can be implemented within it) allowing for serial communication and enabling data transfer between the syringe pump and the computer,
  • A Serial Port: The computer must have an available serial port or a USB-to-serial adapter to connect the cable
  • The LSPoneQuick software or a programming platform (Matlab or Python Environment with the PySerial package that encapsulates access to the serial port),
  • A basic understanding of the LSPone command set detailed in the pump’s user manual.

How to Set Up the Communication Port ?

Before you can start controlling your LSPone pump, it’s essential to configure the communication port. Follow these steps to establish a connection 🔧:

  • Connect the mini-USB/USB cable or DB9 connector to the serial port on the rear of the pump and the corresponding port on the computer.
  • Turn on the pump.
  • Identify the serial port name assigned to the connection on your computer (e.g., COM4 for Windows or /dev/ttyUSB0 for Linux). You can typically find this information in the device manager or by using terminal coammands.
  • Ensure that the serial port settings match the specifications of your syringe pump:
    • 1 start bit,
    • 8 data bits,
    • Parity: none,
    • 1 stop bit,
    • a baud rate of 9600 bits/s.
  • Test the connection by sending a simple command, such as querying the pump status.

The LSPone Command Set

The LSPone offers an array of commands for external control, categorized into distinct types for precise manipulation. These include control directives, initialization prompts, valve adjustments, plunger movements, setting configurations, and comprehensive reporting functionalities. Each command, excluding queries and special directives starting with “?” or “!”, necessitates the appended marker [R] for execution.

Notably, once a command is initiated, the system does not accept new commands except for interruptions or report requests. Additionally, the system promptly responds to command inputs and notifies of errors in case of invalid entries within the command sequence.

The LSPone Command Set used to control the LSPone syringe pump is summarized in the table below. More commands are detailed in the pump’s user manual.

CommandOperandOperand DescriptionCommand Description
RN/AExecute command string
XN/ANo trailing [R]Re-execute last executed command string
G<n>0-600000 = Loop foreverRepeat command sequence
gN/AMax loop depth = 10Mark the start of a repeat sequence
M<n>0-86400000MillisecondsDelay command execution
HN/ANo trailing [R]Halt command
@POWEROFFN/AShut down the pump
Z<n> or Y<n>(void) or 0-3(void) or 0 = high force, 1 = normal force, 2 = medium force, 3 = low forceInitialize the plunger drive and home the valve
O<n>1-max nb of valve positions (4, 6, 8, 10 or 12)Counter-clockwise plug movement (valve seen from above)Move to valve port
I<n>1-max nb of valve positions (4, 6, 8, 10 or 12)Clockwise plug movement (valve seen from above)Move to valve port
B<n>1-max nb of valve positions (4, 6, 8, 10 or 12)Shortest plug movement (clockwise direction preferred)Move to valve port
A<n>0-3000 with N=0
0-24000 with N=1
Absolute position
P<n>0-3000 with N=0
0-24000 with N=1
Relative Pickup
D<n>0-3000 with N=0
0-24000 with N=1
Relative Dispense
V<n>1-1600Peak speed (pulses/sec)Set peak speed
N<n>0-1<0> = microstep of 0.01 mm resolution
<1> = microstep of 0.00125 mm resolution
Scaling of dispense/pickup. Motor always driven in microstep mode

Some report commands are presented in the table below while the detailed set of report commands can be found in the pump’s user manual. These commands do not need a trailing [R] character.

CommandDescription
QCurrent status
?Absolute plunger position
?2Maximal speed
?4Actual plunger position
?6Valve position
?26Pump address

Examples of Commands

 
  • /1Z2R<CR>: Initialize the plunger drive with medium force and home the valve.
  • /1V250R<CR>: Set the peak speed to 250 pulses/sec.
  • /1I4P500M2000I8D500R<CR>: Move clockwise to valve port 4, trigger a pick-up move of 500 steps, delay the next command execution by 2 seconds, move clockwise to valve port 8 and execute a 500-step dispense.
  • /1I2P1000B9gM1000D200G5R<CR>: Move clockwise to valve port 2, trigger a pick-up move of 1000 steps, move to valve port 9 with the shortest path then repeat the following 5 times: delay the command execution by 1 second before executing a 200-step dispense.
🚨 It is important to mention that the length of the command block is limited to 512 characters due to buffer size limitations.

How to Control the LSPone Pump Using the LSPoneQuick Software ?

The LSPoneQuick software presents a user-friendly graphical interface designed for easy and efficient navigation. With its macro recording feature, users can create custom automated sequences step-by-step, easily revisiting and modifying them as needed.  The software’s simple design allows quick access to the LSPone’s features which simplifies the handling of the pump tasks.

To connect the pump to the software, follow the instructions in the “Auto” mode on the opening screen or switch to “Manual” mode and select a specific serial port. Once connected, the pump is automatically initialized and the home tab of the software is displayed. 

The software has three distinct tabs as can be seen in the screenshot below: the home tab, the macro recording tab and the settings tab.

A screenshot of the LSPoneQuick software's home tab

From the home tab, you can reinitialize the pump, stop it, choose the resolution of your displacement, choose the volume you want to pickup or dispense, set the syringe speed, select the valve port, etc.

In the macro recording tab, you can see the command listing in which all the actions performed in the home tab are automatically saved, which allows one to control the pumping program, repeat it and save it for future applications.

From the settings tab, you can input the communication port, the valve module and the syringe volume.

More details about the LSPoneQuick software can be found in the software’s user guide.

How to Control the LSPone Pump Using Python ?

The LSPone can also be controlled remotely via programming platforms such as Python or Matlab which can give you more flexibility and convenience, especially if you want to run continuously complex pumping programs with loops, pauses, and varying flow rates. Programming platforms are also of specific interest when different devices are used at the same time as they enable the automation of sequences involving all the devices.

In this section, Python code snippets showing how to open the serial port, write and send control command strings to the pump and write a pumping program to the LSPone will be presented. We’ll walk through code snippets that demonstrate how to perform common tasks such as moving to a specified valve port, picking up and dispensing liquids, etc. These examples will provide a hands-on understanding of Python-based control of the LSPone syringe pump.

First, we will be utilizing the AMF Tools Python Library, purpose-built for controlling AMF products such as the LSPone. Additionally, we’ll demonstrate how to create a custom Python library dedicated to the LSPone’s commands.

AMF Tools Python Library

Advanced Microfluidics (AMF) has introduced a python library dedicated to control their instruments including the RVM, SPM and LSPone. To install and utilize the AMFTools package, one can execute the following command in the Python console:

				
					pip install AMFTools
				
			

The library provides a structured set of commands used to interact with AMF devices. These commands encompass essential operations ranging from setting up connections to executing precise movements and adjustments. These are grouped as follows:

  • General Methods: such as establishing and terminating connections, sending commands, and receiving responses from the device.
  • Set Functions: functions dedicated to configuring various parameters of the AMF device, including address, syringe size, answer mode, port number, speed, acceleration, and more.
  • Get functions: functions that facilitate retrieving information about the device’s status, configuration, firmware version, valve position, plunger position, and other relevant parameters.
  • Global Action Functions: including actions such as checking valve and pump status, moving the valve to the target port, resetting the device, and powering it off.
  • Pump Action Functions: Specifically targeting pump-related operations, this category includes functions for absolute and relative positioning, volume control, pickup, and dispensing actions.

For further details regarding the comprehensive list of functions, along with their respective explanations, please refer to the AMF Tools page on the Python Package Index.

Below is a practical code snippet example demonstrating how to use the AMF Tools Python Library to construct a pumping program that replicates the actions shown in the video (LSPone-Laboratory syringe pump from the Advanced Microfluidics SA youtube page): initialisation (priming/air purge) of an LSPone syringe pump with an integrated distribution valve featuring 6 ports, each usable as input or output.

				
					'''
----------------------------------------------------------------------------
Initialisation (priming/air purge) of an LSPone syringe pump with an integrated distribution valve with 6 ports each usable as input or output
----------------------------------------------------------------------------
'''
# Import the required module or class
from amfTools import AMF

#--------------------------------------#
# Establish a connection with the pump #
#--------------------------------------#

# Specify the serial port, the baud rate and the number of valve ports
serial_port = 'COM4' # change this according to your COM port
baud_rate   = 9600
valve_ports = 6  # adjust the number of valve ports to the number you have

# Initialize the LSPone, create an instance of the AMFDevice class
LSPone = AMF(serial_port, baud_rate, valve_ports)

# Connect to the device
connected = LSPone.connect()

# Check if the connection is successful and print the appropriate message
if connected:
    print("Connection successful!")
else:
    print("Failed to connect.")

# Home the device, ensuring it is in a known state
LSPone.home()

#-----------------------------#
# Start the priming procedure #
#-----------------------------#

# Liquid picked-up from port 2 then expelled in port 6 used as an output. Pickup and dispense repeated a second time. Air totally removed after first priming. Same procedure applied for inputs 3, 4 and 5 for a bubble-free priming.

# Define the ports to be used as inputs in this pumping program
ports = [2, 3, 4, 5]

# Iterate through each port in the list
for port in ports:
    # Perform pumping action twice for each port
    for _ in range(2):
        # Move to the specified input port with the shortest path
        LSPone.valveShortestPath(port) 
        # Pickup 100 µL of the liquid knowing that the syringe size is 500 µL
        LSPone.pumpPickupVolume(100,500)
        # Move to port 6 with the shortest path
        LSPone.valveShortestPath(6)
        # Dispense the previously picked-up volume
        LSPone.pumpDispenseVolume(100,500)
				
			

How to Communicate with the LSPone Using the Pyserial Library ?

In this part, we explore how to communicate with the LSPone pump, using the PySerial library used to access and control serial ports, providing a convenient interface for sending and receiving data to and from serial devices.

The provided code snippet demonstrates how to send commands to the LSPone pump, with several examples provided (the ones presented just above) including initializing the pump, setting parameters such as peak speed, and executing complex sequences of actions. Each command is sent using the `send_command` method function.

				
					'''
--------------------------------------------------
Writing/Reading Single Commands to/from the LSPone
--------------------------------------------------
'''
import serial
import time

class AMF:
    
    # Initializing the object and establishing a serial connection with the corresponding data format 
    def __init__(self, COM):   
        self.COM = COM
        self.ser = serial.Serial(COM, baudrate=9600, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS)

    # Send a command to the device
    def send_command(self, command, with_trailing_R=True):
        # Wait for any previous response to clear 
        time.sleep(0.05)
        self.ser.read_all()
        
        command_str = f'/1{command}'
        # Append 'R' to the command if specified
        if with_trailing_R:
            command_str += 'R'
        # Append '\r' (carriage return) to the command
        command_str += '\r' 
        # Write the command to the serial port
        self.ser.write(command_str.encode())
        time.sleep(0.05)

#------------------------------------------------#
# To execute a command with a trailing 'R':      #
# send_command("command")                        #
#                                                #
# To execute a command without a trailing 'R':   #
# send_command("command", with_trailing_R=False) #
#------------------------------------------------#

    # Get a response from the device
    def get_response(self):
        response = self.ser.readline().decode().strip()
        return response

#----------------------------------------------#
# Examples on how to send commands to the pump #
#----------------------------------------------#

# Initialize the pump (12 port valve) with the specified COM port
LSPone = AMF('COM4')

# Initialize the plunger drive with medium force and home the valve
LSPone.send_command('Z2')

# Set the peak speed to 250 pulses/sec
LSPone.send_command('V250')

# Move clockwise to valve port 4, trigger a pick-up move of 500 steps, delay the next command execution by 2 seconds, move clockwise to valve port 8 and execute the 500-step dispense
LSPone.send_command('I4P500M2000I8D500')

# Move clockwise to valve port 2, trigger a pick-up move of 1000 steps, move to valve port 9 with the shortest path then repeat the following 5 times: delay the command execution by 1 second before executing a 200-step dispense
LSPone.send_command('I2P1000B9gM1000D200G5')

# Verify the valve port position
LSPone.send_command('?6', with_trailing_R=False)
LSPone.get_response()



				
			

How to Control the LSPone Pump Using Matlab ?

In this section, a Matlab code snippet will be presented, showing how to open the serial port, write and send control command strings to the pump. For that, a quick start adapter class is defined, dedicated to the LSPone’s commands.

We’ll walk through codelines that demonstrate how to perform common tasks such as moving to a specified valve port, picking up and dispensing liquids, etc.

				
					classdef LSPone
    properties
        COM
        ser
    end
    
    methods
        % Initializing the object and establishing a serial connection
        function obj = LSPone(COM)
            obj.COM = COM;
            obj.ser = serialport(obj.COM, 9600, 'Parity', 'none', 'StopBits', 1, 'DataBits', 8);
        end
        
        % Closing the serial connection and deleting the object
        function delete(obj)
            delete(obj.ser);
            obj.ser = [];
        end
        
        % Sending a command to the device
        function send_command(obj, command, with_trailing_R)
            % make with_trailing_R true by default
            if nargin < 3
                with_trailing_R = true;
            end
            % Wait for any previous responses to clear
            pause(0.01); 
            flushinput(obj.ser);
            % Append R to the command if specified
            command_str = ['/1', command];
            if with_trailing_R
                command_str = [command_str, 'R'];
            end
            % Append carriage return (13 in ASCII)
            command_str = [command_str, char(13)];
            % Write the command to the serial port
            write(obj.ser, command_str, "uint8");
            pause(0.01); % Wait to ensure the command is processed
        end

        % Reading and returning the response from the device
        function response = get_response(obj)
            response = read(obj.ser, obj.ser.NumBytesAvailable, "char");
        end

        % Initializing the plunger with a specified plunger force
        function initialize_plunger(obj, force_level)
            % Make 0 the default value
            if nargin < 2
                force_level = 0;
            end
            if ~any(force_level == [' ', 0, 1, 2, 3])
                error('Force level must be void, 0, 1, 2, or 3.');
            end
            command = ['Z', num2str(force_level)];
            obj.send_command(command); % Execute the command
        end
        
        % Move to the specified valve port via the shortest path
        function move_shortest(obj, port)
            obj.send_command(['B', num2str(port)]);
        end
        
        % Move clockwise to the specified port
        function move_clockwise(obj, port)
            obj.send_command(['I', num2str(port)]);
        end
        
        % Move counter-clockwise to the specified port
        function move_counterclockwise(obj, port)
            obj.send_command(['O', num2str(port)]);
        end
        
        % Move the plunger for relative pickup
        function relative_pickup(obj, position)
            obj.send_command(['P', num2str(position)]);
        end
        
        % Move the plunger for relative dispensing
        function relative_dispense(obj, position)
            obj.send_command(['D', num2str(position)]);
        end
        
        % Set the peak speed for plunger movement
        function set_peak_speed(obj, speed)
            if speed < 0 || speed > 1600
                error('Speed must be a positive integer smaller than 1600.');
            end
            obj.send_command(['V', num2str(speed)]);
        end
        
        % Get the valve position
        function valve_position = get_valve_position(obj)
            obj.send_command('?6',false);
            valve_position = obj.get_response();
        end
    end
end

%----------------------------------------------------------------%
% Examples on how to use the defined class to control the LSPone %
%----------------------------------------------------------------%

% Connect the pump
% pump = LSPone('COM4');

% Initialize the plunger drive with medium force and home the valve 
% pump.initialize_plunger(2);

% Move to port 4 with shortest path
% pump.move_shortest(4);

% Trigger a pick-up move of 1000 steps
% pump.relative_pickup(1000);

% Verify the valve port position
% pump.get_valve_position();

% Execute a 400-step dispense
% pump.relative_dispense(400);

% Move clockwise to valve port 2, trigger a pick-up move of 1000 steps, move to valve port 9 with the shortest path then repeat the following 5 times: delay the command execution by 1 second before executing a 200-step dispense
% pump.send_command('I2P1000B9gM1000D200G5');

% Disconnect and delete device
% delete(pump);
				
			

Conclusion

In this blog post, we’ve introduced the LSPone laboratory syringe pump and explored the basics of its external control via two programming platforms, Python and Matlab, using the LSPone communication command set.  We hope this post serves as a valuable guide for researchers and engineers seeking to employ the LSPone laboratory syringe pump in their microfluidics research and experiments.

Stay tuned for more insights, tutorials, and practical applications in our future posts. Until then, happy pumping and coding 💻!

📧 If you have any questions or feedback, please feel free to contact us at contact@darwin-microfluidics.com.