PLR Dev Roadmap 2025 - Q1 & Q2

Hi everyone,

I’d like to propose a biannual “PLR roadmap” discussion where we share our plans and ideas for the next six months.

This is an open invitation to all skill levels—whether you actively develop, contribute ideas, or simply want to see certain features implemented. Here’s how you can participate:

  1. Share what you plan to work on.
  2. Share what you’d love to see developed by the community.

The goal is to align efforts, improve feature development, and collaborate more effectively to make progress together.

Let me start! :blush:

By the end of Q2 2025, I plan to work on and/or would love to see progress on the following open-source PLR development projects:

  1. create real ContainerRacks
    …currently PLR does not have a TubeRack, PetriDishRack, TroughRack that enables assignment of individual Tube, PetriDish or Trough instances to specific positions on said rack.
    The only way this is currently possible is via assignment of Tube or Trough to entire TubeCarrier or TroughCarrier instances.
    But physically, racks exist for both and can be placed into the position of an SLAS-standard-sized plate_holder/plate_site.

  2. help create stable versioning
    …for PLR to enable proper app development for endusers we must have stable PLR versions → stable versions enable containerisation → simplifies specialised apps and their deployment → simplifiea end user experience.

  3. advertise → more users → more dev → more utility for everyone

  4. create NestedTipRackStack
    …up to 4x your tip throughput (without mid-run restacking)

  5. write a lot more documentation
    …most common PLR feedback I’ve received: wish for more documentation to accelerate entrance into the PLR ecosystem.

  6. start the PLR Protocol Library
    …one subfolder in PLR:main listing protocols users have freely added, organised by application (?) (possibility of automatic one-click conversion to other liquid handlers? :eyes: ).

  7. create ChannelHeadAdapter (structure: Resource > ChannelHeadAdapter > Tip)
    …most channels/pipettes can pick up a lot more than just tips; PLR should enable the use of all adapters if they fulfil pickup requirements; generating this resource subclass aims to start this enablement process.

  8. make Tip a ChannelHeadAdapter
    Tip is currently not a resource; should standardise and giving tips additional (currently not captured) attributes: e.g. tip_conductive?.

  9. look into CO-RE tools like the grippers → make ChannelHeadAdapter
    …one example of a non-Tip ChannelHeadAdapter

  10. implement default firmware error handling
    …currently PLR is sending commands to a machine, the machine responds to PLR… PLR doesn’t respond back - very one-sided conversation :smiling_face_with_tear:
    After some conversations with @rickwierenga, I propose decorator-based callback functions: e.g. add …

@handle_error(error_types=["no_liquid_detected"], 
  how={0:"repeat_from_well_bottom",
1: "wait_for_user_input"}
  apply_to_channels="all")
await lh.aspirate(source_wells, lld_mode=pressure, vols=[5]*num_channels)

…to enable automatic repeating of any aspiration that failed because the machine erroneously failed to (e.g.) detect a liquid in one of the source_wells.
i.e. PLR uses decorators to dynamically respond to machine responses with pre-defined actions.

  1. standardisation of frontend-backend-physical_definition relationship for machines
    …some machines currently have 2 frontends (?) while other machines like the liquid handlers have a simple, easy and effective structure of frontend(backend=backend_instance, physical_definition=resource_instance).
    Defined as…

    • frontend - what users interact with in a Python script
    • backend - controls the machines functionalities (e.g. heating/cooling/shaking/aspirating/moving resources/…)
    • physical_definition - defines the physical world 3D shape of the machine (including child location(s)/rails/deck_positions/…)
      I would find it a lot more intuitive if this simple structure is applied to all machines (e.g. temperature controllers, shakers, tilter, …).
      This would also simplify the use of these machines as simple plate_holders: e.g. a shaker that is bolted into the deck, used in one automated Protocol (aP) but not another → when not used it doesn’t require a programmatic connection but can be usefully integrated into the aP as plate_holder.
  2. New Machine integrations:

    • new plate washers
    • first mechanic arm integration (maybe with specified inverse kinematics control :eyes: )

Looking forward to hearing your thoughts and contributions, and am very happy for others to beat me to implementing any of this or working together on any of these projects! :sweat_smile:

Of course, there is no obligation to implement (or even stick) to such a roadmap, and plenty of ideas will naturally evolve due to the open-source nature of the project which a roadmap or list of ideas cannot capture a priori.
So please feel free to continue adding new ideas outside the scope of what we write down here.

2 Likes
  1. Share what you plan to work on.

I’d like to work on better Opentrons (OT2) integration. I think there are some ways to do it well and reliably, but I think it takes a slightly different route than what is currently in PLR.

  1. Share what you’d love to see developed by the community.

I really like the http server bits of PLR, and would like to see that + machine integrations be a thing. For example, if I combine a liquid handler and a centrifuge, I want a way to address both at once over an http server (combining them both as a kind of workcell). These workcells would be easier to reproduce than single machines, and software could be written against them as a unit.

    • first mechanic arm integration (maybe with specified inverse kinematics control :eyes: )

I have a lite6 robotic arm from ufactory which is really good - got inverse kinematics built in and a python API and everything. You can get it for $3500. It’s pretty cheap because it is direct from the chinese company that builds em, and they have built them for years (usually larger arms for industrial applications). However, the biogripper is $2100 so I haven’t bought it yet. Good option for a mechanic arm integration.

3 Likes

great ideas!

it seems important to integrate more serious readout machines:

  • finish integration of cytation5-family LED imagers
  • begin fw-level integration of imagexpress laser imagers and cytoflex flow cytometers

we’re lacking any type of logistics solution between liquid handlers / clusters of instruments:

  • a robot arm materially better than the hamilton iSWAP, not hobbiest-grade, but also available for <$10k

it is most obvious we need:

  • one open-source example method with instrument integrations like cytomat & centrifuge

Rick has a great summary of what’s on our mind below:

2 Likes

thank you Camillo for taking the lead on this. Upon reading this I agree that more planned & organized development, rather than schizo ad-hoc development of the past, can be an accelerant for PLR.

All of your suggestions are excellent. For me, I particularly want to focus (and can take the lead on?):

  • versioning
  • more documentation
    • every major resource subclass should have a doc page. right now, few do.
    • dedicated cookbook with quick ‘how-to’s’
    • full protocol examples
  • error handling, either as proposed by Camillo or a similar method

Other priorities for me are:

  • re-implement tip racks: currently the “rack” is redefined for every tip type, even though the physical rack object is the same.
  • improve cytation5 integration drastically (filters, lenses). will soon be testing in production protocol
    • we recently acquired 2 cytation1’s, the firmware looks identical at first glance
  • finish currently wip machine integrations
    • ml prep
    • a4s plate sealer
    • inheco odtc
  • new machines:
    • cytoflex flow machine
    • image express
  • maintenance scripts
    • i didn’t believe in the past, but multiple reliable people say it’s actually useful
    • our machines have stochastic errors, curious if this fixes
  • io layer for CI (will explain in a post soon)
  • higher level methods like serial dilute and aliquot
  • robot arms if it comes up

Last week, I was able to create a protocol where every plate/resource/operation was already defined. It took less than an hour to write & water test this protocol with copilot. Since most of our protocols are fundamentally easy to express, writing code (one medium expression) should also be trivial.

I suggest creating a new thread on the forum for every individual action-point to be discussed in more detail. We already have threads for some topics. Let’s keep this thread to what Camillo proposed:

  • what you want to do
  • what you want to see
2 Likes

A quick comment.

It would also be great to have a look at the EVO backend. It has not been updated for a while and last time i check it could not run.
We would like to do the updates our selvs but with the little time i have i cant keep up with the updates to PLR and dont know where to start. Can we make a EVO backends development plan?

2 Likes

what specifically is broken? the tests still pass

I don’t have access to an EVO right now…

We are currently fixing the problems with the EVO we have. I think the main challenge is that the code has fallen behind the rest of PLR and that we are using fixed tips that probably changes some of the settings on the instrument.

Sorry if the previous message sounded snarky (specially when i have not answered before now).

1 Like

for a while i had a tecan dev branch (GitHub - PyLabRobot/pylabrobot at tecan-dev-branch) this was >1y ago, but has some new unmerged changes like PnP module. It got messed up when i rewrote git history. I will see if I can merge this into PLR soon, it should be a little bit more up to date than the current code. (Although tests still pass, so the stuff that was working before should still work. If not, we need better tests.) fwiw, we also had fixed tips on the evo that was used to develop the backend initially.

I’m late to the party (how come it’s May '25 already?) but I’ll throw this in here:

One of the things that bugs me is setting up plates. These are hardcoded, which is a bad idea : a new code release for every new plate, and they are not centrally stored in any way. Nor can they be searched, or same plates be used across machines easily (you need to know where they are defined), etc.

I am very much wedded to Django, so what I would do is -

  • set up a generic PlateBase concrete base class (data model) which covers all the basic info (nx,ny-layout, size, height, origin, wellbottomshape, has-a-lid, whatever)

  • derive any instrument-specific XxxPlate implementation from this (containing, say, additional special Hamilton parameters or functionality, as required by that particular machine)

  • Store all plates in a database (export/import from JSON format dump)

  • have a filter_plates() routine that allows finding a (list of) matching plates by name, any parameter etc. Resulting objects would be cast back to their relevant XxxPlate derived type, but generic PLR routines would take any PlateBase type generically.

I use this concept routinely in my Django apps, instantiating objects from a database, as required, on the fly. Django further offers the option to create web interfaces to manage that. I’ll admit it is daunting, but I find its data model approach really versatile and powerful.

Hth
W

2 Likes

good news, we can do a lot of this already!

in what way are they hardcoded? we provide functions that initialize a Plate instance for asymptotically all plate definitions from every manufacturer. This information is fixed so it makes sense to hard-code it. But you can also create your own instances of Plate quite easily.

@CamilloMoschner created a very nice video tutorial on this:

Plates are just modeled using an instance of Plate. You are free to instantiate/modify them at runtime in whatever way makes sense for you.

We’re working on improving the documentation to make them searchable.

They can, with the exception of Tecan (for now). Tecan has some attributes z_travel, z_start, z_dispense, z_max for which we have to find out what they actually mean. With EVO development starting back up (thanks to @VilhelmKM and I think soon others), I think we can solve this in the near future.

If you think about it, physically plates can be used between machines. If you had a very good model of the physical plate, it would have all information necessary for any robot to make it work. There is no immeasurable “magic” attribute that a certain robot would need. So, we can have one class Plate ‘to rule them all’.

This exists:

We already support (de)serializing json: docs

We don’t have a fancy filter method yet for resources. You can, however, call resource.get_all_children() to get a list of all children in a resource’s subtree. (.children is direct children). Then, with python list comprehensions you can easily say

[c.name.startswith("prefix_") for c in r.get_all_children()]

or

[w.bottom_type == WellBottomType.FLAT for w in r.get_all_children() if isinstance(w, Well)]
2 Likes

I do not disagree with any of that Rick, but it misses the point: hardcoding plate information is not great as it a) requires contributors to be python programmers with access to a repository, superuser permissions, and time on their hands etc, and b) requires others to update their code in order to use new (other people’s) plates - which makes it harder on you to have a stable release for a while.

If such definitions would be in a database, or separate file, you can start thinking about crowdsourcing such info, or ask vendors if they can supply it in a certain format, independently of any ongoing coding work.

Cheers,
w

Hi @willem,

Can you please elaborate on what you mean by “hardcoded”?

To your points:

plate information […] a) requires contributors to be python programmers with access to a repository

Q1: Yes, PyLabRobot is a Python library; what is your suggestion as an alternative and why is an alternative needed?

superuser permissions

Q2: Why does one require superuser permissions to execute Python files?

b) requires others to update their code in order to use new (other people’s) plates - which makes it harder on you to have a stable release for a while

Yes, in order to use new plate definitions one has to pull these new definitions from the repository, whether the definitions are stored in a classic database or .py files doesn’t really change this?

But there are plenty of ways to use new definitions faster:
e.g. just send them to each other like

from pylabrobot.resources.plate import Plate
from pylabrobot.resources.utils import create_ordered_items_2d
from pylabrobot.resources.well import (
  CrossSectionType,
  Well,
  WellBottomType,
)
def Cor_Axy_24_wellplate_10mL_Vb(name: str, with_lid: bool = False) -> Plate:
  """
  Corning cat. no.: P-DW-10ML-24-C-S
  - manufacturer_link: https://ecatalog.corning.com/life-sciences/b2b/UK/en/
    Genomics-&-Molecular-Biology/Automation-Consumables/Deep-Well-Plate/
    Axygen%C2%AE-Deep-Well-and-Assay-Plates/p/P-DW-10ML-24-C
  - brand: Axygen
  - distributor: (Fisher Scientific, 12557837)
  - material: Polypropylene
  - sterile: yes
  - autoclavable: yes
  """
  return Plate(
    name=name,
    size_x=127.76,
    size_y=85.48,
    size_z=44.24,
    lid=None,
    model="Cor_Axy_24_wellplate_10mL_Vb",
    ordered_items=create_ordered_items_2d(
      Well,
      num_items_x=6,
      num_items_y=4,
      dx=9.8,
      dy=7.2,
      dz=1.2,
      item_dx=18,
      item_dy=18,
      size_x=17.0,
      size_y=17.0,
      size_z=42,
      bottom_type=WellBottomType.V,
      material_z_thickness=1.0,
      cross_section_type=CrossSectionType.RECTANGLE,
    ),
  )

Now you can place this definition into any script that you want, instantly :slight_smile:


I wonder:
Q3: Are you suggesting a website-based database with users contributing resource information straight into the database without a pull request into the database?
Q3.a: Do you see the issue with the requirement of being a GitHub user?

Q3.b: How would we validate contributions in that case?

One important aspect of the PLR Resource Library is that we aim to cross-validate all resources added to it.
Jumping the pull request stage sounds like it might make the cross-validation before addition to the Resource Library harder (and misses version-control?).


As @rickwierenga mentioned, we have been working on a repository-hosted text-based database for a while.
There is no major obstacle with building such a database. The general issue we found is simply resource naming conventions, resulting limited namespace, missing manufacturer information, and oftentimes that users misunderstand the difference between a supplier and the original manufacturer, all resources must be stored by the manufacturer’s

Q4: I suggest we have a separate thread to discuss this database and what you think would be useful for it?
We can share all the information about our current approach there without deviating this threads purpose further.

1 Like

made a new thread to continue this discussion: High level pylabrobot resource library (PLR-RL) discussion