Qmix SDK  20180626
The software libraries for integration of all CETONI devices.
Pump Library
Slider_Pump_API_color.jpg

Introduction

General

This pump library defines a common pump control interface for a range of different pump types such as e.g. syringe pumps, dilutors, peristaltic pumps, or diaphragm pumps.

In general a pump consists of an actuator (like a linear drive for a syringe pump, a servo drive for a peristaltic pump or a simple DC/EC drive for a diaphragm pump) and a container for the transport of the fluid (like a syringe for a syringe pump/dilutor, a tube for a peristaltic pump or a pump head for the diaphragm pump). With some pumps like syringe pumps and peristaltic pumps the container is exchangeable by the application engineer or even by the user of the laboratory device. That means a user may mount different kind of syringes on a syringe pump or may use different tube sizes on a peristaltic pump. With other pumps (i.e. diaphragm pumps) the container and the actuator are fixed to each other and build up one single unit. The pump parameters (e.g. volume, flow or pressure) may be limited by the actuator and/or by the container.

Actuator limits

On a syringe pump the flow is limited by the speed of the actuator (the velocity of the linear drive) and the volume is limited by the length/maximum position of the linear drive. On a peristaltic pump or diaphragm pump the volume is not limited by the actuator but the maximum flow is limited by the actuator speed - the maximum rotation speed of the peristaltic pump drive or the speed of the DC/EC diaphragm pump drive.

Container limits

Container limits are only important for devices where it is possible to change the container. On every change of the container the calculation of the flow and volume values changes and therefore the parameters maximum volume and maximum flow may also change. That means each container has its own container limits. The maximum volume of a syringe pump is limited by the stroke of the syringe piston and the inner syringe diameter. The maximum flow is limited by the inner diameter of the syringe. The tube dimensions do not limit the maximum volume of a peristaltic pump but the maximum flow is limited by the inner diameter of the tube.


Including

The way how you include the library functions in your own windows program, depends on the compiler and on the programming language you use. In order to access the pump API, you have to include the library labbCAN_Pump_API.dll to your programming environment. You have to copy this file to the working directory of your system or to the application directory that contains your application EXE file. Use the calling convention LCP_CALL for this library. This convention is managing how the parameters are put on the stack and who is responsible to clean the stack after the function execution.

The interface of the library, constant definitions and declarations of the library functions, is defined in the header file interface/labbCAN_Pump_API.h


Initialization

Step 1 - Retrieve device handle

To work with a pump, you need a valid device handle. A device handle is simply an opaque pointer to the internal device object created by the labbCAN environment. So the first thing you need do to is obtaining a valid device handle.

You can get a valid pump handle with the functions LCP_LookupPumpByName() or LCP_GetPumpHandle():

dev_hdl PumpHandle;
Result = LCP_LookupPumpByName("Nemesys1_Pump", &PumpHandle);
dev_hdl PumpHandle2;
Result = LCP_GetPumpHandle(1, &PumpHandle2);
Note
You can get the pump names from the device configuration files (see Device Configuration Files)

Step 2 - Enable devices

If you have valid device handle, you can start to bring your devices into a properly enabled and initialized state. To do this, you need to:

  1. clear all faults (LCP_ClearFault())
  2. enable all pump drives (LCP_Enable())
  3. execute a reference move (if required) to find the device homing positions (LCP_SyringePumpCalibrate()) or restore the previously saved drive position counter via LCP_RestoreDrivePosCnt()

Examples

The following example code snippet shows a valid valid pump initialization procedure:

1 //============================================================================
2 // INCLUDES
3 //============================================================================
6 
7 //===========================================================================
8 // STATIC DATA
9 //===========================================================================
10 static dev_hdl hPump1; ///< stores pump handle
11 
12 //===========================================================================
13 // Pump initialisation
14 //===========================================================================
15 TErrCode InitPump(void)
16 {
17  TErrCode Result;
18  long Retval;
19 
20  // Get a pump handle for the pump that is registered with the name
21  // Nemesys1_Pump
22  hPump1 = LCP_LookupPumpByName("Nemesys1_Pump");
23  if (hPump1 <= 0)
24  {
25  // handle error properly here
26  return -ERR_NOENT;
27  }
28 
29  // Now we check if the pump is in a fault state. We need to clear the fault
30  // state first, before we can enable the pump drive
31  Retval = LCP_IsInFaultState(hPump1);
32  if (1 == Retval)
33  {
34  Result = LCP_ClearFault(hPump1);
35  if (Result != ERR_NOERR)
36  {
37  // handle error properly here
38  return Result;
39  }
40  }
41 
42  // Now we enable the pump drive. Enabling the pump means, power
43  // will be applied to power stage of the pump drive units.
44  Result = LCP_Enable(hPump1);
45  if (Result != ERR_NOERR)
46  {
47  // handle error properly here
48  return Result;
49  }
50 
51  int SavedPositionCounterValue = 0;
52  //
53  // load saved position counter value from file here
54  // ...
55 
56  // Now we restore the previously saved position counter value of the pumps
57  // drive units
58  Result = LCP_RestoreDrivePosCnt(hPump1, SavedPositionCounterValue);
59  if (Result != ERR_NOERR)
60  {
61  // handle error properly here
62  return Result;
63  }
64 
65  // Now we setup volume and flow SI units - or we restore the values saved
66  // to file previously. We would like to use milliliters as volume unit and
67  // milliliters / second as flow unit
68  LCP_SetVolumeUnit(hPump1, MILLI, LITRES);
70 
71  // Now we configure the syringe parameters of the syringe that is currently
72  // mounted on our syringe pump device - we use a syringe with 2 mm innder
73  // diameter and 60 mm piston stroke.
74  Result = LCP_SetSyringeParam(hPump1, 2, 60);
75  if (Result != ERR_NOERR)
76  {
77  // handle error properly here
78  return Result;
79  }
80 
81  // now the pump is properly initialized and we can start dosing
82  return Result;
83 }
LCP_Func long LCP_CALL LCP_SetVolumeUnit(dev_hdl hPump, int Prefix, int VolumeUnit)
This function sets the default volume unit.
labbCAN Pump Application Programming Interface
#define ERR_NOENT
No such entity.
Definition: err_codes.h:104
LCP_Func long LCP_CALL LCP_SetFlowUnit(dev_hdl hPump, int Prefix, int VolumeUnit, int TimeUnit)
Sets the flow unit for a certain pump.
#define PER_SECOND
PER_SECOND.
Definition: labbCAN_MotionControl_API.h:210
LCP_Func long LCP_CALL LCP_SetSyringeParam(dev_hdl hPump, double InnerDiameter_mm, double MaxPistonStroke_mm)
Set syringe parameters.
int32_t TErrCode
Error code type.
Definition: err_codes.h:50
LCP_Func long LCP_CALL LCP_ClearFault(dev_hdl hPump)
Clear fault condition.
long long dev_hdl
generic device handle
Definition: labbCAN_Bus_API.h:359
LCP_Func long LCP_CALL LCP_RestoreDrivePosCnt(dev_hdl hPump, long PosCntValue)
Restore internal hardware position counter value of pump drive.
#define ERR_NOERR
No error.
Definition: err_codes.h:102
#define LITRES
LITRES.
Definition: labbCAN_Pump_API.h:242
LCP_Func long LCP_CALL LCP_IsInFaultState(dev_hdl hPump)
Check if pump is in a fault state.
#define MILLI
MILLI.
Definition: labbCAN_MotionControl_API.h:223
LCP_Func long LCP_CALL LCP_LookupPumpByName(const char *pPumpName, dev_hdl *PumpHandle)
Lookup for a pump device by its name.
LCP_Func long LCP_CALL LCP_Enable(dev_hdl hPump)
Set axis into enabled state.
labbCAN Bus Application Programming Interface

Reference

See the Pump API Initialisation module and the Pump Configuration module for a detailed reference of all pump initialization and configuration functions.


Dosing

For almost all dosing tasks the functions from the Pump Control module and from the Pump Status module are required. Using the pump API you can choose from a number of different dosing modes:

  • LCP_Aspirate() for the aspiration of a certain volume with a certain flow
  • LCP_Dispense() for dispension of a certain volume
  • LCP_PumpVolume() for aspiration or dispension depending on the sign of the flow rate parameter (negativ = aspiration, positive = dispension)
  • LCP_SetFillLevel() aspirates or dispenses until a certain syringe fill level is reached
  • LCP_GenerateFlow() generates a constant flow - dosing continues until it gets stopped manually or until pusher reached one of its limits.
Note
All dosing functions are non blocking. That means each function returns Immediately after the dosing process has been started and you need to poll the LCP_IsPumping() function to detect if dosing has been finished.

With the status functions you can always query the actual state of the pumps you are working with:

Each pump drive tracks the actual position value (volume value) by an internal position counter. If the pumps are switched off, the actual value of the position counter gets lost and is initialized to zero at next start. So right after power on, you don't know anything about the actual position of the pump drive units. For pumps like peristaltic pumps this does not matter but for pumps like syringe pumps this is very important because the position defines the actual fill level.

To properly initialize the internal position counter you either need to execute a reference move via LCP_SyringePumpCalibrate() or you need to restore a previously saved position counter value via LCP_RestoreDrivePosCnt(). Because a safe reference move is possible only if there is now syringe mounted on the device, the recommended way is using LCP_RestoreDrivePosCnt(). That means, right before you shut down your system, you need to query the actual position counter value of each pump via LCP_GetDrivePosCnt(). Then you need to store this value into a file. The next time you start up your devices, you load the saved position values, and write it back into the devices vial LCP_RestoreDrivePosCnt().

Warning
If you manually change the position of the pusher of you syringe pump while it is switched of, the saved position counter value ist not valid anymore and you need to execute a calibration move via LCP_SyringePumpCalibrate().

Examples

The following example code snippet shows how to empty a syringe completely and then aspirate a certain volume with a certain flow rate.

1 //============================================================================
2 // INCLUDES
3 //============================================================================
6 
7 //===========================================================================
8 // STATIC DATA
9 //===========================================================================
10 static dev_hdl hPump1; ///< stores pump handle
11 
12 //===========================================================================
13 // Pump dosage
14 //===========================================================================
15 TErrCode PumpDosageExample(void)
16 {
17  TErrCode Result;
18  long Retval;
19 
20  // First we completely empty the syringe (fill level 0) with the maximum
21  // flow rate
22  double MaximumFlow;
23  Result = LCP_GetFlowRateMax(hNemesys1, &MaximumFlow);
24  Result = LCP_SetFillLevel(hPump1, 0, MaximumFlow);
25  if (Result != ERR_NOERR)
26  {
27  // handle error properly here
28  return Result;
29  }
30 
31 
32  Sleep(100); // Give pump some time to start dosage
33 
34  // The loop continues until pump finished dosage
35  do
36  {
37  Retval = LCP_IsPumping(hPump1);
38  if (Result != ERR_NOERR)
39  {
40  // handle error properly here
41  return Result;
42  }
43  Sleep(50); // do not take all processor time with this loop
44  }
45  while (Retval > 0);
46 
47  // now we aspirate 0.1 ml with a flow rate of 0.004 ml/s
48  Result = LCP_Aspirate(hPump1, 0.1, 0.004);
49  if (Result != ERR_NOERR)
50  {
51  // handle error properly here
52  return Result;
53  }
54 
55  return ERR_NOERR;
56 }
LCP_Func long LCP_CALL LCP_SetFillLevel(dev_hdl hPump, double Level, double Flow)
Pumps fluid with the given flow rate until the requested fill level is reached.
LCP_Func long LCP_CALL LCP_Aspirate(dev_hdl hPump, double Volume, double Flow)
Aspirate a certain volume with a certain flow rate.
labbCAN Pump Application Programming Interface
int32_t TErrCode
Error code type.
Definition: err_codes.h:50
long long dev_hdl
generic device handle
Definition: labbCAN_Bus_API.h:359
LCP_Func long LCP_CALL LCP_IsPumping(dev_hdl hPump)
Check if device is currently stopped or dosing.
#define ERR_NOERR
No error.
Definition: err_codes.h:102
LCP_Func long LCP_CALL LCP_GetFlowRateMax(dev_hdl hPump, double *FlowRateMax)
Get maximum flow rate that is realizable with current dosing unit configuration.
labbCAN Bus Application Programming Interface

Reference

See the Pump Control module and the Pump Status module for a detailed reference of all pump dosing and status functions.


Programming Interface - API

See the labbCAN Pump API module for a detailed reference of the pump library application programming interface