Lab Equipment Automation Package
Project description
Control.lab.ly
Lab Equipment Automation Package
Description
User-friendly package that enables flexible automation an reconfigurable setups for high-throughput experimentation and machine learning.
Package Structure
- Analyse
- Compound
- Control
- Make
- Measure
- Move
- Transfer
- View
Device support
- Make
- Multi-channel LED array [Arduino]
- Multi-channel spin-coater [Arduino]
- Peltier device [Arduino]
- Measure
- (Keithley) 2450 Source Measure Unit (SMU) Instrument
- (PiezoRobotics) Dynamic Mechanical Analyser (DMA)
- Precision mass balance [Arduino]
- Move
- (Creality) Ender-3
- (Dobot) M1 Pro
- (Dobot) MG400
- Primitiv [Arduino]
- Transfer
- (Dobot) Gripper attachments
- (Sartorius) rLINE® dispensing modules
- (TriContinent) C Series syringe pumps
- Peristaltic pump and syringe system [Arduino]
- View
- (FLIR) AX8 thermal imaging camera - full functionality in development
- Web cameras [General]
Installation
Control.lab.ly can be found on PyPI and can be installed easily with pip install
.
$ pip install control-lab-ly
Basic Usage
Simple start-up guide for basic usage of the package.
Import desired class
from controllably.Move.Cartesian import Ender
mover = Ender(...)
mover.safeMoveTo((x,y,z))
More details for each class / module / package can be explored by using the help
function.
help(controllably.Move) # help on package
help(Ender) # help on class
help(mover) # help on instance/object
Alternatively, you can use the native pydoc
documentation generator.
$ python -m pydoc controllably.Move
Tip: when using Interactive Python (IPython) (e.g. Jupyter notebooks), add a exclamation mark (
!
) in front of the shell command
>>> !python -m pydoc controllably.Move
>>> !python -m pydoc -b # Generates a static HTML site to browse package documentation
For basic usage, this is all you need to know. Check the documentation for more details on each respective class.
Advanced Usage
For more advanced uses, Control.lab.ly provides a host of tools to streamline the development of lab equipment automation.
0. Import package
The convention is to import Control-lab-ly as lab
.
import controllably as lab
Contents
- Projects
- Setups
- Decks
- Safety measures
- Plugins
1. Creating a new project
Create a /configs
folder in the base folder of your project repository to store all configuration related files from which the package will read from.
This only has to be done once when you first set up the project folder.
lab.create_configs()
A different address may be used by different machines for the same device. To manage the different addresses used by different machines, you first need your machine's unique identifier.
# Get your machine's ID
print(lab.Helper.get_node())
A template of registry.yaml
has also been added to the folder to hold the machine-specific addresses of your connected devices (i.e. COM ports).
Populate the YAML file in the format shown below.
### registry.yaml ###
'012345678901234': # insert your machine's 15-digit ID here (from the above step)
cam_index: # camera index of the connected imaging devices
__cam_01__: 1 # keep the leading and trailing double underscores
__cam_02__: 0
port: # addresses of serial COM ports
__device_01__: COM3 # keep the leading and trailing double underscores
__device_02__: COM16
To find the COM port address(es) of the device(s) that is/are currently connected to your machine, use:
lab.Helper.get_ports()
2. Creating a new setup
Create a new folder for the configuration files of your new setup. If you had skipped the previous step of creating a project, calling lab.create_setup()
will also generate the required file structure. However, be sure to populate your machine ID and device addresses in the registry.yaml
file.
lab.create_setup(setup_name = "_Setup01_")
# replace "_Setup01_" with the desired name for your setup
This creates a /_Setup01_
folder that holds the configuration files for the setup, which includes config.yaml
and layout.json
.
2.1 config.yaml
Configuration and calibration values for your devices is stored in config.yaml
.
Each configuration starts with the name
of your device, then its module
, class
, and settings
.
_Device01_: # name of simple device (user-defined)
module: _module_name_01_ # device module
class: _submodule_1A_._class_1A_ # device class
settings:
port: __device_01__ # port addresses defined in registry.yaml
_setting_A_: {'tuple': [300,0,200]} # use keys to define the type of iterable
_setting_B_: {'array': [[0,1,0],[-1,0,0]]} # only tuple and np.array supported
Compound
devices are similarly configured. The configuration values for its component devices are defined under the component_config
setting. The structure of the configuration values for the component devices are similar to that shown above, except indented to fall under the indentation of the component_config
setting.
_Device02_: # name of 'Compound' device (user-defined)
module: Compound
class: _submodule_2A_._class_2A_
settings:
_setting_C_: 1 # other settings for your 'Compound' device
component_config: # nest component configuration settings here
_Component01_: # name of component
module: _module_name_03_
class: _submodule_3A_._class_3A_
settings:
ip_address: '192.0.0.1' # IP addresses do not vary between machines
_Component02_:
module: _module_name_04_
class: _submodule_4A_._class_4A_
settings:
_setting_D_: 2 # settings for your component device
Lastly, you can define shortcuts to quickly access components of Compound
devices.
SHORTCUTS:
_Nickname1_: '_Device02_._Component01_'
_Nickname2_: '_Device02_._Component02_'
2.2 layout.json
Layout configuration of your physical workspace (Deck
) will be stored in layout.json
. This package uses the same Labware files as those provided by Opentrons, which can be found here, and custom Labware files can be created here. Labware files are JSON files that specifies the external and internal dimensions of a Labware block/object.
Optional: if your setup does not involve moving objects around in a pre-defined workspace, a layout configuration may not be required.
{
"reference_points":{
"1": ["_x01_","_y01_","_z01_"],
"2": ["_x02_","_y02_","_z02_"]
},
"slots":{
"1": {
"name": "_Labware01_",
"exclusion_height": -1,
"filepath": "_repo_/.../_Labware01_.json"
},
"2": {
"name": "_Labware02_",
"exclusion_height": 0,
"filepath": "_repo_/.../_Labware02_.json"
},
"3": {
"name": "_Labware03_",
"exclusion_height": 10,
"filepath": "_repo_/.../_Labware03_.json"
}
}
}
In reference_points
, the bottom-left coordinates of each slot in the workspace are defined. Slots are positions where Labware blocks may be placed.
In slots
, the name of each slot and the file reference for Labware block that occupies that slot are defined. The filepath starts with the repository's base folder name.
The exclusion_height
is the height (in mm) above the dimensions of the Labware block to steer clear from when performing move actions. Defaults to -1 (i.e. do not avoid).
(Note: only applies to final coordinates (i.e. destination). Does not guarantee collision avoidance when using point-to-point move actions. Use safeMoveTo()
instead.)
2.3 Load setup
The initialisation of the setup occurs during the import setup
from within configs/_Setup01_
.
# Add repository folder to sys.path
from pathlib import Path
import sys
REPO = '_repo_'
# replace "_repo_" with your base directory for the project
ROOT = str(Path().absolute()).split(REPO)[0]
sys.path.append(f'{ROOT}{REPO}')
# Import the initialised setup
from configs._Setup01_ import setup
this = setup
this._Device01_
this._Nickname2_
With this
, you can access all the devices that you have defined in configs.yaml
.
3. Managing a deck
Optional: if your setup does not involve moving objects around in a pre-defined workspace, a Deck
may not be required.
3.1 Loading a deck
To load the Deck
from the layout file, use the loadDeck()
function.
from configs._Setup01_ import LAYOUT_FILE
this._Device02_.loadDeck(LAYOUT_FILE)
deck = this._Device02.deck
3.2 Loading a Labware
To load the Labware
into the Deck
, use the load_labware()
method.
deck.load_labware(...)
4. Setting up safety measures
You can optionally set the safety policy for session. This has to be done before importing any of the classes.
lab.set_safety('high') # Pauses for input before every move action
lab.set_safety('low') # Waits for countdown before every move action
# Import other classes from control-lab-ly only after setting the safety policy
5. Using plugins
User-defined plugins can be integrated into Control.lab.ly without making additions or modifications to the package itself. All classes and functions can be found in lab.modules
.
print(lab.modules)
# view the entire package (only those that have been imported during the session)
lab.modules.Make.Something.Good.myClass
# this expression returns the registered class
5.1 Directly registering a Class or Function
You can import the class and register the object using the Factory.register()
function.
from my_module import myClass
lab.Factory.register(myClass, "Make.Something.Good")
5.2 Registering a Python module
Alternatively, you can automatically register all Classes and Functions in a Python module just by importing it.
Declare a __where__
global variable to indicate where to register the module.
### my_module.py ###
__where__ = "Make.Something.Good" # Where to register this module to
# ==========
def myClass: # Main body of code goes here
...
# ==========
from controllably import include_this_module # Registers only the Classes and Functions
include_this_module() # defined above in this .py file
At the end of the .py file, import and call the include_this_module()
function.
Dependencies
- Dash (>=2.7.1)
- Impedance (>=1.4.1)
- Imutils (>=0.5.4)
- Matplotlib (>=3.3.4)
- Nest-asyncio (>=1.5.1)
- Numpy (>=1.19.5)
- Opencv-python (>=4.5.4.58)
- Pandas (>=1.2.4)
- Plotly (>=5.3.1)
- PyModbusTCP (>=0.2.0)
- Pyserial (>=3.5)
- PySimpleGUI (>=4.60.4)
- PyVISA (>=1.12.0)
- PyYAML (>=6.0)
- Scipy (>=1.6.2)
Contributors
@kylejeanlewis
@mat-fox
@Quijanove
@AniketChitre
How to Contribute
Issues and feature requests are welcome!
License
This project is distributed under the MIT License.
Change Log
Unreleased
Items under development
1.1.0
- Integration for orbital shaker [QInstruments]
- Integration for pH meter probe [Sentron]
- Integration for force sensor
Version 1.0.1
Bug fixes and minor feature enhancements. First released 08 May 2023.
Added
LiquidMover
- Added
LiquidMover.touchTip()
method to touch the pipette tip against the walls of the vessel to remove excess liquid on the outside of the tip (#62) - Added option to indicate the position of the first available pipette tip in
LiquidMover
(#61)
- Added
- Added adaptive GUI controls for
Liquid
objects (#70) - Added option to indicate which digital IO channel to use with Dobot attachments (#53)
Changed
MassBalance
- Updated to the use
pd.concat()
instead ofpd.DataFrame.append()
, which is going ot be deprecated (#63) - Fixed endless loop for when
MassBalance
tries tozero()
while recording data (#60)
- Updated to the use
- Changed the
Image
class and methods into functions within a module (#54) - Fixed the tool offset of pipette when pipette tip is attached, and accounts for the length of pipette that enters the pipette tip (#64)
- Changed to using more precise time interval measurements by moving from
time.time()
totime.perf_counter()
(#68) - Fixed discrepancy in aspirate and dispense speed for
Sartorius
(#73) and let speed return to a global default value (#72) - Updated documentation
Version 1.0.0
Major overhaul in package structure. Standardisation of methods and consolidation of common methods. First released 12 Apr 2023.
Added
- Usage of Abstract Base Classes (ABCs) to define a base class with abstract methods that needs to be implemented through sub-classing (#31)
- Usage of Protocols to provide an interface between different classes of objects (#30)
- Usage of Dataclasses to store complex data
- Usage of decorators to modify methods
- Introduced different functions to parse the program docstring and find program parameters
Changed
- Standardised methods and consolidated common methods
- Added type hints (#28)
- Moved Dobot attachments from Mover to Transfer.Substrate
- Split GUI Panels into individual files
- Split Dobot arms into individual files
- Split functions/methods in
misc.py
into individual files. - Changed
_flags
to a public attributeflags
- Update documentation (#27, #28, #29)
Removed
- Unnecessary commented-out blocks of code
Version 0.0.x
(0.0.4.x) Introduced control for Peltier device and TriContinent Series C syringe pumps. First released 10 Mar 2023.
(0.0.3.x) Minor changes to movement robot safety and pipette control. Introduced control for LED array. First released 08 Mar 2023.
(0.0.2.x) Updates in setting up configuration files. First released 24 Feb 2023.
(0.0.1.x) First release of Control.lab.ly distributed on 23 Feb 2023.
(0.0.0.x) Pre-release packaging checks
Added
0.0.4
- Added control for
Peltier
(#23)- set and get temperatures
- hold temperatures for desired duration
- checks if target temperature has been reached by checking power level lower than a threshold or time passed over a predefined duration, once the temperature is within tolerance
- ability to record temperatures and timestamps
- Added control for
TriContinent
andTriContinentEnsemble
(#25)- single actions such as
empty
,fill
,initialise
, move actions, set speeds and valves, and wait - compound actions such as
aspirate
,dispense
, andprime
- single actions such as
0.0.3
- Added safety measures for movement actions (#24)
- In
Deck
, added exclusion zones when reading thelayout.json
file and new methodis_excluded()
to check if target coordinate is within the exclusion zone - In
Mover
, updateisFeasible()
method to check if target coordinates violates the deck's exclusion zone - New function
set_safety()
defines safety modes when starting a new session to pause for input (in "high" safety setting) and to wait for safety countdown (in "low" safety setting)
- In
Make.Light.LEDArray
for controlling LEDs in the photo-reactor, as well as timing the LED "on" durations (#35)
0.0.2.2
- Added import of
CompoundSetup
class
0.0.2
Deck.at()
method for directly referencing slots using either index numbers or names- New
CompoundSetup
class for common methods ofCompound
devices - New
load_deck()
function to loadDeck
after initialisation
0.0.1
- Make
- Multi-channel spin-coater [Arduino]
- Measure
- (Keithley) 2450 Source Measure Unit (SMU) Instrument
- (PiezoRobotics) Dynamic Mechanical Analyser (DMA)
- Precision mass balance [Arduino]
- Move
- (Creality) Ender-3
- (Dobot) M1 Pro
- (Dobot) MG400
- Primitiv [Arduino]
- Transfer
- (Sartorius) rLINE® dispensing modules
- Peristaltic pump and syringe system [Arduino]
- View
- (FLIR) AX8 thermal imaging camera - full functionality in development
- Web cameras [General]
- misc
- Helper class for most common actions
- create_configs: make new directory for configuration files
- create_setup: make new directory for specific setup-related files
- load_setup: initialise setup on import during runtime
Changed
0.0.4
- Update documentation
0.0.3.1
- Update documentation
0.0.3
Sartorius
- made the blowout/home optional for the dispense method upon emptying the pipette
- Update documentation
0.0.2.1
- Changed template files for
lab.create_setup()
0.0.2
- Update documentation
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for control_lab_ly-1.0.1-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | dbb3ab34b5c1e366d5090b78b8037e8bab3ec9375aac417a797220ef1ff0b549 |
|
MD5 | ebe91e4eea24d72e3be751d46db1b732 |
|
BLAKE2b-256 | a39b140010886acb913d29b99026b4c5099812b370e8d49db7c289078807b1f7 |