Writing a new backend / Agnosticity

Howdy!

New backend continued…

I’m a bit confused about this. I assume that everything must mean (1) the new backend class for PLR, and (2) the external module it imports to connect to and control the robot.

I am adding the new backend to PLR, and I now realize just now that it could live in the external module if you preferred it that way. I’d like the backend to live in PLR of course.

I confirm that the the robot firmware (and all other resources) can be running on a remote machine, and the backend+module can connect to them.

This means that the new backend+module do not rely on any OS-specific stuff, and should be multi-platform. Testing this could take a while, I’ll have to borrow a PC and a Mac.

I’m not savvy at all when it comes to python packaging. I’ll be asking for review in the future.

Just a comment on that: the line is a bit blurry with Klipper.

Its micro-controller firmware is very slim, and most of the computation is done by a “host” python module running on a regular computer (usually an RPi).

Hmm… from what I gather so far, a new backend wouldn’t cause a protocol to not run on a certain computer (because protocols are meant to be agnostic, correct?).

It could happen however that a protocol fails to run on a certain backend, is this what you want to avoid?

Deck-agnosticity?

I’m still pondering a bit about this.

Decks are specific to a certain robot’s physical deck, which can be separate from the definition of the backend; Q1: correct? Q2: Could I use the Hamilton/OT decks on a different backend with the current version of PLR?

I imagine that it should be possible, as long as the robot has an equivalent physical deck (with the exact same dimensions and coordinate origin). This could come in handy as I have been considering 3D-printing OT’s deck and putting it into the robot (as the Pipette Jockey has done) for compatibility.

A similar thing could be done for the Hamilton deck, but I have not looked for its schematics yet.


Cheers :slight_smile:

Hey, sorry for my late reply.

I agree the backend should live in PLR. This way, it will be documented and maintained for you. The external module can remain an external module, but definitely feel free to (temporarily) put it in PLR if that’s easier for you.

The external module, as a dependency of PLR, would have to be OS-agnostic as well.

The goal is for people to be able to use your robot with any operating system.

Great! This solves the OS-agnosticity requirement.

If you are using a websocket/HTTP/etc., you can assume it works on any OS.

Additionally, if you write unit tests that cover the entire process (from LH to sending commands to a machine), I will make sure to double check it for you.

Correct.

What I meant was when people share a protocol written on a Windows machine, it should also run on a Linux machine, for example. New backends could in theory violate this principle, if they use OS-specific APIs. That is what I want to avoid.

We prefer avoid this, of course, but I understand there may be some instances where a protocol uses hardware specific functionality so this cannot always be possible.

Yes.

You probably could, but I doubt that’s very useful. A current example is the STAR backend for Hamiltons both working with the STARDeck and STARLetDeck (different sizes of what is essentially the same robot).

I have spoken too soon. Go for it!

Great start! Over time, do you think we could merge this into PLR so they appear on the PLR docs website?

1 Like

Awesome, everything is looking good then. :slight_smile:

Sure! I’d be glad to help accelerate others’ learning process.

If you have any important recommendations so far, please leave a comment.

As always, thanks a lot!

Hello again, sorry that it took me so long to come back to this. :slight_smile:

I bring a few questions about deck development that might be tricky.

Issues

Tube racks and tubes

I just realise that there will be a slight issue between pipettin and PLR, which I maybe can summarize by saying that PLR has no “tube spots”.

While well plates are straightforward to bridge, tube racks seem to be a hybrid between TipRacks (with its tip spots) and Plates.

I was tempted to reuse the Plate code but came to the conclusion that it is over my head.

Petri dishes and colonies

I really wouldn’t know how to bridge this to PLR.

Questions

  1. Are you planning to support tube racks in the future? Are there any important limitations?
    • I get the feeling that tubes were not in the scope when developing PLR, is that right?
    • Would a TubeRack be compatible with other robots controlled with PLR?
  2. How would you write a TubeRack resource for PLR?
    • I’m particularly lost when thinking how/if to reouse “create equally spaced”, “itemized resource”, or “Plate”. Maybe I should do something else entirely.
  3. How would the TubeRack play with the “A1:B2” syntax for selection when tubes may be missing in the range?
    • Can tips be selected in this way?
  4. Any ideas around bridging petri dishes to a PLR object? (e.g. for spot growth assays).
    • I’d say this is more similar to a well plate at least.

I’m sorry I don’t have more specific / better questions at the moment. I’d need to get to the PLR innards for that, and I don’t have the time for it at the moment.

Overall, I’d hope for some advice on what to write to support tube racks and petri dishes, in a way that it could be useful to others eventually.

Best :slight_smile:
Nico

Welcome back!

Yes, tube racks would be very easy to add and are definitely within the scope. The custom resources tutorial actually describes how to do this :slight_smile: But happy to make this a part of PLR in some form. It is automatically compatible with other robots.

I think we can throw an IndexError if a tube is missing. This is best done by overriding the __getitem__ of ItemizedResource.

The main thing is we don’t really have a nice way of supporting circular resources yet. This can&should be added for sure. In the meantime, it’s super easy to do this by assuming the petri dish is a square.

Thanks for the link! I should have checked the docs, hehe…

If you happen to be interested in looking at my code so far, this is it: pylabrobot/resources/pipettin/tube_racks.py · 419ef31ad7dd4e3cb2d949a45e8a556d6c7e8533 · Open Lab Automata / Forks / pylabrobot · GitLab

There’s some stuff over there, but I’m still a bit lost around the need for a “tube spot” feature.

It makes more sense to have tube spots and tubes in a tube rack object, mirroring what has been implemented in the TipRack class.

I may be able to learn a bit more in today’s meeting. See you soon!

1 Like

Code is looking really good so far!

Regarding spots, it depends on whether the tubes are moved in and out of the rack during normal operation. To compare:

  • For plates, the Wells are direct children of the Plate because they are an integral part of it.
  • For tip racks, the tip spots are direct children. Each tip spot may or may not have a tip at any time (Tips aren’t Resources though).
  • For carriers, there are CarrierSites which may or may not contain a Plate as a child resource. This is to enable code like lh.move_resource(plate, carrier[0]). Without the ‘virtual’ CarrierSite resource, it would be impossible to simultaneously specify the target location of a move and update the resource tree.

Let’s discuss this afternoon!

Hi again!

I saw that you pushed tip racks and petri dishes just a few days ago. That’s great! ^.^

I’ll be using those soon if they are ready. But first I bring two questions about interpreting coordinates.

Pickup(resource=TipSpot(name=tips_01_tipspot_0_0, location=(007.200, 068.300, -83.500), size_x=9.0, size_y=9.0, size_z=0, category=tip_spot),
       offset=None,
       tip=HamiltonTip(HIGH_VOLUME, has_filter=True, maximal_volume=1065, fitting_depth=8, total_tip_length=95.1, pickup_method=OUT_OF_RACK))
  • What is the topmost coordinate of the tip given that information?
  • Is there a reference document or a general pattern for this kind of question?

Sorry if I missed the docs for this. I’ve not had luck interpreting the sources either.

My memory is blurred. Did we in the end?

They will be, yes. Either with a human or robot gripper. :grin:

I see. In our data model we went for wellspots, and set “removable=False” somewhere instead.

Best!

Nico

The location (007.200, 068.300, -83.500) is the location of the tip spot wrt the tip rack it is in. A tip spot is a location in a tip rack, with or without a Tip.

Check out the new resources guide: Resources Introduction — PyLabRobot documentation If anything is missing, please ask or create a PR!

I’m not sure we did.
Currently, we have TipRacks and TipCarriers, both added after the call.The benefit of tip carriers is moving tubes in and out, the benefit of a tip rack is nicer 2d-indexing. I think I am going to change the TubeCarrier subclass to override indexing behavior soon. Is this a priority for you?

Hmm ok.

Thanksfor the link. I did not find what I was looking for so I’ll change my question to this one: how can the topmost Z coordinate of a particular tip be calculated from the information in the Pickup operation and Tip?

If the tip has a length, and I know the height of the surface on which the tip stands (the tipspot), I’m then missing a coordinate for the place on the tip which meets that surface. Correct?

Let me illustrate:

image

For hamliton tips, I think the tip spot is already the top, but I have not verified this.

I’m actually not sure if we store the height you pointed at. There is a fitting depth parameter, but I think that refers to how deep the channel goes into the tip, as it is only 8mm for standard hamilton tips.

Hmm I see… I’m now looking at OT’s labware and they seem to do the same thing:

image

This is not an issue, but I’d like to know for sure what each coordinate is. I would like to see the robot just work with decks from other projects (e.g. Science Jubilee, nopentrons, etc.) and not crash into them.

Would it be possible to confirm that the Z coordiante of the spot is the top of the tip? and that the fitting_depth should be applied as an offset below that point?

Also just to be sure, I’d need to check that resource.get_absolute_position returns a coordiante relative to the coordinate origin of the robot, and that origin is at the top left (as in digital images), and not bottom left (as in CNCs).

image

Sorry for the late response.

The Z-coordinate of the tip spots is actually the bottom of the tip when placed in the tip rack.

tip_spot_a1 = tip_rack.get_item("A1").get_absolute_location() + tip_rack.get_item("A1").center()
await lh.backend.move_channel_x(0, tip_spot_a1.x)
await lh.backend.move_channel_y(0, tip_spot_a1.y)
 
ttl = tip_rack.get_item("A1").get_tip().total_tip_length
await lh.backend.move_channel_z(0, tip_spot_a1.z + ttl)

await lh.backend.move_channel_z(0, tip_spot_a1.z + ttl - tip_rack.get_item("A1").get_tip().fitting_depth)

Easy to adjust this if something else is more sensible.

The origin 0,0,0 is the left (x) front (y) bottom (z). If you use a different coordinate space in your robot software, then you’d just need to transpose the coordinates from PLR-space on the backend. This is what happens on the Tecan.

This information is key, thanks! It’s also a good fit for the development docs.

Is this standard practice I can read about somewhere? Are there other conventions like this one that I may come across? (e.g. wells, tubes, or other resources).

This is critical for me because I’m using this information from PLR to decide which coordinates the robot will move to, with almost no intelligence downstream.

The same applies to the origin.

Due to early work with frontend developers, our robot operates with the origin on the left (x) back (y) and bottom (z), as in images or writing. Unfortunately this is not something that will change soon.

Thanks a lot Rick, the information really helps. :slight_smile:

I’ll be back with more questions soon!

I have been talking to @CamilloMoschner about creating a doc page for each (significant) PLR resource type. I will prioritize that. Please keep asking questions in the meantime.

y_plr = y_you,max - y_you right?

1 Like

Yes exactly. :slight_smile:

That would be great. Thanks!

I’ll try to get back to working on this soon.

1 Like