Package: control-lab-ly
Control.lab.lyLab Equipment Automation PackageDescriptionUser-friendly package that enables flexible automation an reconfigurable setups for high-throughput experimentation and machine learning.Package StructureCompoundControlMakeMeasureMoveTransferViewDevice supportMake(QInstruments) BioShake Orbital Shaker(Arduino-based devices)Multi-channel LED arrayMulti-channel spin-coaterPeltier deviceMeasure(Keithley)SMU 2450 Source Measure Unit InstrumentDAQ 6510 Data Acquisition and Multimeter System(PiezoRobotics) Dynamic Mechanical Analyser (DMA)(Sentron) SI series pH meters(Arduino-based device)Precision mass balanceLoad cellMove(Creality) Ender-3(Dobot)M1 ProMG400(Arduino-based device) gantry robot running on GRBLTransfer(Dobot) Gripper attachments(Sartorius) rLINE® dispensing modules(TriContinent) C Series syringe pumps(Arduino-based device) Peristaltic pump and syringe systemView(FLIR) AX8 thermal imaging camera(General) Web camerasInstallationControl.lab.ly can be found on PyPI and can be easily installed withpip install.$pipinstallcontrol-lab-lyBasic UsageSimple start-up guide for basic usage of the package.Import desired classfromcontrollably.Move.CartesianimportEndermover=Ender(...)mover.safeMoveTo((x,y,z))View documentationUse the built-in guide to read the documentation for the package.fromcontrollablyimportguide_meguide_me()Alternatively, details for each class / module / package can be explored by using thehelpfunction.help(Ender)For basic usage, this is all you need to know. Check the documentation for more details on each class and function.Advanced UsageFor more advanced uses, Control.lab.ly provides a host of tools to streamline the development of lab equipment automation. This includes setting up configuration files and adding plugin drivers.Import packageimportcontrollablyaslabOptionally, you can set the safety policy for the session. This feature allows the user to prevent collisions before each movement is made. The safety policy has to be assigned before importing any of theMoverobjects.lab.set_safety('high')# Notifies; Pauses for input before every move actionlab.set_safety('low')# Notifies; Waits for countdown before every move actionlab.set_safety(None)# Carries out movement actions without delay# Import control-lab-ly classes only after setting the safety policyContentsSetupsDecksAddressesPlugins1. Creating a new setupCreate a/configs/MySetupfolder that holds the configuration files for the setup, which includesconfig.yamlandlayout.json.lab.create_setup(setup_name="MySetup")1.1config.yamlThis file stores the configuration and calibration values for your devices.MyDevice:# device namemodule:Move# top-level categoryclass:Cartesian.Ender# device classsettings:port:COM1# serial port addresssetting_A:{'tuple':[300,0,200]}# use keys to define the type of iterablesetting_B:{'array':[[0,1,0],[-1,0,0]]}# only tuple and np.array supportedEach device configuration starts with the device name, then the following parameters:module: top-level category (such as Make, Measure, Move,Transfer, View)class: point to specific subclass using dot notationsettings: various initialisation settingsSee theguidefor more details on these parametersCompound devices are similarly configured.MyCompoundDevice:# compound device namemodule:Compoundclass:LiquidMover.LiquidMoverSetupsettings:# settings for your compound devicesetting_C:Truecomponent_config:# nest component configuration settings hereMyFirstDevice:# component device namemodule:Transferclass:Liquid.SyringeAssemblysettings:# settings for your component deviceport:COM22setting_D:2MySecondDevice:# component device namemodule:Moverclass:Jointed.Dobot.M1Prosettings:# settings for your compound deviceip_address:'192.0.0.1'The configuration values for the component devices are nested under thecomponent_configsetting of the compound device.Lastly, you can define shortcuts (or nicknames) to quickly access the components of compound devices.SHORTCUTS:First:'MyCompoundDevice.MyFirstDevice'Second:'MyCompoundDevice.MySecondDevice'A different serial port address or camera index may be used by different machines for the same device.SeeSection 3to find out how to manage the different addresses used by different machines.1.2layout.jsonThis file stores the layout configuration of your physical workspace, also known as aDeck.SeeSection 2on how to load this information into the setup.Optional: if your setup does not involve moving objects around in a pre-defined workspace,  a layout configuration may not be requiredThis package uses the same Labware files as those provided byOpentrons, which can be foundhere, and custom Labware files can be createdhere. Labware files are JSON files that specifies the external and internal dimensions of a Labware block / object.{"reference_points":{"1":[11.1,22.2,33.3],"2":[44.4,55.5,66.6],"3":[77.7,88.8,99.9]},"slots":{"1":{"name":"MyLabware01","exclusion_height":-1,"filepath":"MyREPO/.../MyLabware01.json"},"2":{"name":"MyLabware02","exclusion_height":0,"filepath":"MyREPO/.../MyLabware02.json"},"3":{"name":"MyLabware03","exclusion_height":10,"filepath":"MyREPO/.../MyLabware03.json"}}}Inreference_points, the bottom-left coordinates of each slot on the deck are defined. Slots are positions where Labware blocks may be placed.Inslots, thenameof the Labware and thefilepathto the JSON file containing Labware details are defined. The filepath starts with the name of the repository's base folder.Theexclusion_heightis the height (in mm) above the dimensions of the Labware block to steer clear from when performing movement actions. Values less than 0 means the Labware is not avoided.(Note: Labware avoidance only applies to final coordinates (i.e. destination). Does not guarantee collision avoidance when using point-to-point move actions. UsesafeMoveTo()instead.)1.3 Load setupThe initialisation of the setup occurs when importingsetupfromconfigs.MySetup. Withsetup, you can access all the devices that you have defined inSection 1.1.### main.py #### Add repository folder to sys.pathfrompathlibimportPathimportsysREPO='MyREPO'ROOT=str(Path().absolute()).split(REPO)[0]sys.path.append(f'{ROOT}{REPO}')# Import the initialised setupfromconfigs.MySetupimportsetupsetup.MyDevicesetup.First2. Managing a deckOptional: if your setup does not involve moving items around in a pre-defined workspace,  aDeckmay not be required2.1 Loading a deckTo load aDeckfrom the layout file, use theloadDeck()function of aMoverobject (or its subclasses).fromconfigs.MySetupimportsetup,LAYOUT_FILEsetup.Mover.loadDeck(LAYOUT_FILE)LAYOUT_FILEcontains the details that has been defined inlayout.json(seeSection 1.2)2.2 Loading a LabwareTo load aLabwareonto the deck, use theloadLabware()method of theDeckobject.setup.Mover.deck.loadLabware(...)This package uses the same Labware files as those provided byOpentrons, which can be foundhere, and custom Labware files can be createdhere. Labware files are JSON files that specifies the external and internal dimensions of a Labware block / object.3. Managing project addressesA/configsfolder will have been created in the base folder of your project repository to store all configuration related files from which the package will read from, inSection 1. A template ofregistry.yamlhas also been added to the/configsfolder to manage the machine-specific addresses of your connected devices (e.g. serial port and camera index).### registry.yaml ###'012345678901234':# insert your machine's 15-digit ID herecam_index:# camera index of the connected imaging devices__cam_01__:1# keep the leading and trailing double underscores__cam_02__:0port:# addresses of serial ports__MyDevice__:COM1# keep the leading and trailing double underscores__MyFirstDevice__:COM22Use theHelper.get_node()function to get the 15-digit unique identifier of your machineUse theHelper.get_port()function to get the serial port addresses of your connect deviceslab.Helper.get_node()# Get your machine's ID (15-digit)lab.Helper.get_ports()# Get the port addresses of connected devicesAfterwards, change the value for the serial port address in theconfig.yamlfile to match the registry.### config.yaml ###MyDevice:module:Moveclass:Cartesian.Endersettings:port:__MyDevice__# serial port address4. Using pluginsOptional: if drivers for your hardware components are already included, plugins may not be requiredUser-defined plugins can be easily written and integrated into Control.lab.ly. All available classes and functions can be found inlab.modules.lab.guide_me()# Use guide to view imported objectslab.modules.at.Make.Something.Good.MyClass# Access the class4.1 Registering a Class or FunctionYou can import the class and register the object using theFactory.register()function.frommy_moduleimportMyClasslab.Factory.register(MyClass,"Make.Something.Good")4.2 Registering a Python moduleAlternatively, 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 moduleAt the end of the .py file, import and call  theinclude_this_module()function### my_module.py ###__where__="Make.Something.Good"# Where to register this module todefMyClass:# Main body of code goes here...defmy_function:...fromcontrollablyimportinclude_this_module# Registers only the Classes and Functionsinclude_this_module()# defined above in this .py fileThe Classes and Functions in the module will be registered when you import the module.### main.py ###frommy_moduleimportMyClass,my_functionDependenciesMarkdown (>=3.3.4)numpy (>=1.19.5)opencv-python (>=4.5.4.58)pandas (>=1.2.4)pyModbusTCP (>=0.2.0)pyserial (>=3.5)PySimpleGUI (>=4.60.5)PyVISA (>=1.12.0)PyVISA-py (>=0.7)PyYAML (>=6.0)tkhtmlview (>=0.2.0)Contributors@kylejeanlewis@mat-fox@Quijanove@AniketChitreHow to ContributeIssuesand feature requests are welcome!LicenseThis project is distributed under theMIT License.Change LogVersion 1.3.0Feature enhancements, bug fixes and patches. First released 19 Feb 2024.Addedadded check for poor physical connection withPiezoRoboticsDeviceKeithleyadded new subclasses ofKeithleyDevice:DAQ6510andSMU2450added way to read and save model name ofKeithleyDeviceadded new Keithley program for DAQ to scan multiple channelsnew methodsclearErrors(),setDisplay(),setFunction()Changedchanged the way travel times are calculated forMovertools, so that they reflect the actual physical travel times more accuratelychanged ability to delay initialisation of TriContinent pumps until it is in a more convenient locationfixed few bugs withSentronProbetoolRemovedremoved old archived filesVersion 1.2.0Feature enhancements, bug fixes and patches. First released 22 Aug 2023.AddedForceClampSetupclassLoadCellclassBalanceclass (subclass ofLoadCell)ChangedupdateLEDArrayto delay timing loop by 0.1sfix bug with initialisingPiezoRoboticsDeviceupdategetTemperature()across multiple classes to standardise outputMoverclassspeed-related attributes and propertiesadd method to calculate travel time based on target speed, acceleration and decelerationmodify how speeds and max speeds interact withmove()andsafeMoveTo()CartesianclasssetSpeed()andsetSpeedFraction()get max speed settings from device upon connectingchange calculation of movement wait times using device speed and accelerationPrimitivclasschange the class name toGrblandPrimitivas a subclass name to retain compatibilityoverloadmoveTo()and_query()methods to use jogging modemodify the sequence of commands to halt movementimplementgetAcceleration(),getCoordinates(),getMaxSpeed()clear errors and setting feed rate upon establishing connectionEnderclasschange the class name toMarlinandEnderas a subclass name to retain compatibilityadded method to immediately stop movementimplementgetAcceleration(),getCoordinates(),getMaxSpeed()separate methods forsetSpeed()(absolute speed in mm/s) andsetSpeedFraction()(proportional speed to max speed)Dobotclassaddedstop()methodFlirAX8classaddedinvertPalette()methodadded data parsing methods_decode_from_modbus()and_encode_to_modbus()KeithleyDevice()classaddedip_addresspropertyadded options for_read()methodaddedreadline()methodimplementdisconnect()methodfix bug with Keithley programs usingdevice.run()instead ofdevice.start()RemovedThermalclassremoved dependency onimutilspackageVersions 1.1.2 & 1.1.1Bug fixes and patches. First released 12 Jul 2023.AddedimportDeviceclasses in init files to view documentationadded library for GRBL status and error codesaddupdate_root_direcctory()function to HelperChangedfix bug with adding new rows into Dataframesusereset_input_buffer()instead offlushInput()forpyserial.Serialobjectsprint the actual string sent to Serial devicesupdate methods inDeck,Labware, andWellto camelCaseupdateDeck.isExcluded()to apply strict inequalities when determining out-of-range coordinatesupdateLiquidMoverto insert a portion of tip into rack before ejectingupdateSpinnerfix bug with sending commandsadded_query()methodpass verbosity to individual spinnersverbosity ofMeasureobjects pass through to devicesupdatePiezoRoboticsDeviceinitialize upon connectionraise errors when encountering themupdateMovermodifysetFlag()to print kwargs instead of raising error if assigned values are not booleanusesafe_height(if defined) instead of z-coordinate of home insafeMoveTo()addedgetSettings()methodupdateGantryclassread multiple flines in_query()check that commands end with newline before sending to devicefix bug with changing speedsupdateEnderaddedgetTemperature(),holdTemperature(),isAtTemperature()methodsmodifiedsetTemperature()to use Marlin code to wait for temperatureupdatePrimitivclassaddgetStatus()andstop()methodsadd_get_settings()methodfix bug inM1Pro.setHandedness()updateSartoriusclasstip_inset_mmnow an instance attribute with initialisation parameterssettip_onflag to False when performingeject()Version 1.1.0Bug fixes and feature enhancements. First released 15 Jun 2023.AddedForceSensor- DIY force sensor (#55)BioShake- orbital shaker from QInstruments (#56)SentronProbe- pH meter probe from Sentron (#75)Makeraddedexecute()abstract method and implemented in subclassesGUIGuide- documentation guideMakerPanel- daptive GUI controls forMakerobjects (#87)ChangedM1Profix issue with changing handedness (#86)PeltierrenamegetTemperatures()togetTemperature()renameisReady()toisAtTemperature()renameset_pointtoset_temperatureEnderrenameset_pointtoset_temperatureTriContinentrenamestep_limittolimitsRefactor and reorganizeGUIcodeRefactor code inhelperandfactoryUpdated documentationRemovedAnalysesub-package removedControl.Schedulesub-package removedUnnecessary commented-out blocks of codeVersion 1.0.1Bug fixes and minor feature enhancements. First released 08 May 2023.AddedLiquidMoverAddedLiquidMover.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 inLiquidMover(#61)Added adaptive GUI controls forLiquidobjects (#70)Added option to indicate which digital IO channel to use with Dobot attachments (#53)ChangedMassBalanceUpdated to the usepd.concat()instead ofpd.DataFrame.append(), which is going ot be deprecated (#63)Fixed endless loop for whenMassBalancetries tozero()while recording data (#60)Changed theImageclass 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 fromtime.time()totime.perf_counter()(#68)Fixed discrepancy in aspirate and dispense speed forSartorius(#73) and let speed return to a global default value (#72)Updated documentationVersion 1.0.0Major overhaul in package structure. Standardisation of methods and consolidation of common methods. First released 12 Apr 2023.AddedUsage 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 dataUsage of decorators to modify methodsIntroduced different functions to parse the program docstring and find program parametersChangedStandardised methods and consolidated common methodsAdded type hints (#28)Moved Dobot attachments from Mover to Transfer.SubstrateSplit GUI Panels into individual filesSplit Dobot arms into individual filesSplit functions/methods inmisc.pyinto individual files.Changed_flagsto a public attributeflagsUpdate documentation (#27, #28, #29)RemovedUnnecessary commented-out blocks of codeVersion 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 ofControl.lab.lydistributed on 23 Feb 2023.(0.0.0.x) Pre-release packaging checksAdded0.0.4Added control forPeltier(#23)set and get temperatureshold temperatures for desired durationchecks 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 toleranceability to record temperatures and timestampsAdded control forTriContinentandTriContinentEnsemble(#25)single actions such asempty,fill,initialise, move actions, set speeds and valves, and waitcompound actions such asaspirate,dispense, andprime0.0.3Added safety measures for movement actions (#24)InDeck, added exclusion zones when reading thelayout.jsonfile and new methodis_excluded()to check if target coordinate is within the exclusion zoneInMover, updateisFeasible()method to check if target coordinates violates the deck's exclusion zoneNew functionset_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)Make.Light.LEDArrayfor controlling LEDs in the photo-reactor, as well as timing the LED "on" durations (#35)0.0.2.2Added import ofCompoundSetupclass0.0.2Deck.at()method for directly referencing slots using either index numbers or namesNewCompoundSetupclass for common methods ofCompounddevicesNewload_deck()function to loadDeckafter initialisation0.0.1MakeMulti-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) MG400Primitiv [Arduino]Transfer(Sartorius) rLINE® dispensing modulesPeristaltic pump and syringe system [Arduino]View(FLIR) AX8 thermal imaging camera - full functionality in developmentWeb cameras [General]miscHelper class for most common actionscreate_configs: make new directory for configuration filescreate_setup: make new directory for specific setup-related filesload_setup: initialise setup on import during runtimeChanged0.0.4Update documentation0.0.3.1Update documentation0.0.3Sartoriusmade the blowout/home optional for the dispense method upon emptying the pipetteUpdate documentation0.0.2.1Changed template files forlab.create_setup()0.0.2Update documentation