Adding a liquidhandler callback

Hi,

I have a simple backend (implementing aspirate(), dispense() etc) and want to implement a pause() function (*).

It looks like a lot has changed since last time I looked a few months ago, when there was an entry in liquidhandler.py that said:

 ALLOWED_CALLBACKS = {
    "aspirate",
    "aspirate96",
    "dispense",
    "dispense96",
    "drop_tips",
    "drop_tips96",
    "move_resource",
    "pick_up_tips",
    "pick_up_tips96",
  }

How do I go about this in the current version? What is the best stable version to download?
Is there a registration mechanism for these functions now and is this documented somewhere?

Thanks,
w

(*) the pause is needed when the robot runs out of tips and user needs to insert a full tip plate.

i removed callbacks since they weren’t useful in PR 535 Remove callback support from LiquidHandler by rickwierenga · Pull Request #535 · PyLabRobot/pylabrobot · GitHub

this is in anticipation of more useful error handling: error handling: option 3 (PoC) by rickwierenga ¡ Pull Request #542 ¡ PyLabRobot/pylabrobot ¡ GitHub. i am still figuring out the optimal API for this feature

this should be doable with a nice error handling mechanism (and could probably be a default error handler we provide in PLR)

Thanks. I have not kept up with changes really in recent months - which of the changes require refactoring of the backends as well?

I implemented a Pause() in my backend and liquidhandler.py, but that is now in the old version. I have pegged that version as otherwise I end up debugging/rewriting my own stuff as well as PLR with every PLR change and life’s too short.

How is the ‘core API’ defined now, I had a quick peek but I don’t see ‘ALLOWED_CALLBACKS’ anymore. Ie. do I need to register or specify a Pause function in the current code somewhere, and where is that done now?

Sadly, the weekend’s just arrived - have a good one!

PS Should add - the pause literally stops the machine and passes on a message to display to the user, and they have to click ‘ok’. It is not an error, in that I tell the machine to pause, the machine does not tell me what’s wrong.

I generate a list of commands in advance (as a file) and do not get interactive feedback - hence error handling might not apply here.

i don’t really understand what you are asking

if you are asking about how to implement a pause in the script, there are numerous ways to do that. The easiest would be to have an input call in your protocol. I don’t see how that is necessarily connected to PLR.

Regarding syncing changes, that is a choice when using open source software: do you contribute back and stay up to date with the main branch, or do you work on a diverging branch? up to the individual to decide

1 Like

In my case, Pause() is a command and part of the accessible API, just like Aspirate(), Dispense(), DropTips() etc.

I have an asynchronous case where I produce a file with instructions, so it is literally a line in that file, and I need to produce it by calling the API function.

The old version pre-declared the API of accessible functions through ALLOWED_CALLBACKS I think? Is that still the case, and if so, where is that API (pre)defined?

Just doing the thought experiment of switching robots - this pause command should be robot agnostic ideally, but your suggestion of ‘implementing it in a script’ is not?

Cheers,
w

for asynchronous waiting, you can just use await asyncio.sleep (or input for user input).

it should not be a backend method. backend methods are (aim to be) the minimal set of atomic commands (exposing all functionality of a machine at a level where they can’t be split further)

if you have a program that writes “pause” lines to a file, you can do so from ‘user-space’

you mean it had a list of methods in a list of strings? that no longer exists

it wasn’t complete, and didn’t serve that purpose

you can look in the docs or use

[name for name, obj in inspect.getmembers(LiquidHandler, predicate=inspect.isfunction)]

pause is not a robot command. in fact i would say it’s the absence of commands.

since the plr api is interactive (send a command, it executes) (as opposed to queueing then dong all), just stop sending commands

the robot will stop doing work

→ a “pause” command should not be part of the api

why? it’s just python code at that point

1 Like

Hmm, I’m afraid I disagree there. It is a robot command in this case unfortunately, and present in its API - it sends the head to a specified location (home, out of the way) so that the user can reach in and exchange a plate, eg. an empty tip plate; it displays a user-supplied message (like, “change tip plate”). I agree that this is not in the ‘atomic’ set of other robots which can communicate in real time.

Keep in mind this is one asynchronous - pylabrobot writes an instructions file, the file is run independently so any on-the-fly ‘sleep’ or wait action in real time won’t work. The command ‘pause’ needs to be issued as a line in the instructions list, which is run sequentially on this SPT DC1 robot. Can’t do it another way…

A way to register new and add to these atomic functions would be nice. That would allow for user-supplied ones alongside ‘core’ atomic functions. Can that be abstracted out? It would also allow for implementing higher level ‘shortcuts’ as well for specific applications, in the longer run, in a regimented way? (‘plugins’, eg., for a concentration-response dispense across n wells action - it fosters reusability).

why not send the commands directly for execution (interactively) instead of writing to an intermediary file?

for backend specific functionality (since pause is not an atomic command, it will not be a frontend method), you can just call lh.backend.whatever() (this is a very common pattern, for example to get hamilton specific functionality on a star)

but why not just to a simple pcap and figure out how the robot sends/receives commands so you’re able to actually program it in python?

1 Like

why not send the commands directly for execution (interactively) instead of writing to an intermediary file?

We literally have no way to do so currently. SPT Labtech ships software with the DC1 dispenser, which can import a file containing a list of commands (there are actually two file formats, and at least one of them will change following our feedback).

We have asked whether there is a more direct way and it seems that would involve a C# API. Unfortunately, life is too short to frustrate myself with C# alongside python.

for backend specific functionality (since pause is not an atomic command, it will not be a frontend method), you can just call lh.backend.whatever()

OK - that’s what I ended up doing, but since I used an earlier version the CALLBACK requirement made me worry that I was missing something essential. Good to hear that has been simplified.

Thanks
w

as long as the computer can communicate to the machine, you are able to replicate this yourself. It’s just data over a wire. You can analyze this with wireshark and figure out how to send it from python.

It has not been simplified, this has literally been possible since day 1 of PLR, but nice to hear it works for you.

this is what i did for the STAR and many many other machines. It’s a little more work up front, but definitely worth it for us. You can develop and iterate so much faster when you can use the machine interactively, you can literally have a notebook open and just develop a protocol step by step. Short iteration time (seconds) vs having to run whole scripts

1 Like

plus humanidity’s solution “treasure box” (i.e. Python ecosystem) available interactively :slight_smile:

from ipywidgets for slider-accelerated parameter identification to real-time computer vision feedback of what is on your deck… there are no limitations in Python

2 Likes

Thanks. I take all these points, but as mentioned earlier - not an option.

We’re users right now and experimentalists need this to work right now, ie. we do not have time to reinvent low-level interfaces we already pay the vendor for.

And yes, a vendor should provide these ideally, but in practice it is often proprietary information, plus potentially not well documented.

Ideally, vendors would agree on a shared interface/API for robot communication : say, a standardised ingestion of eg. JSON input; an outline format definition; and set of atomic functions, but we are far from that. PLR provides a placeholder for that but it is born from necessity.

1 Like