Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions docs/api/pylabrobot.agilent.rst
Original file line number Diff line number Diff line change
Expand Up @@ -140,3 +140,22 @@ VSpin

.. autoclass:: pylabrobot.agilent.vspin.VSpinCentrifugeBackend.SpinParams
:members:


PlateLoc
--------

.. currentmodule:: pylabrobot.agilent.plateloc

.. autosummary::
:toctree: _autosummary
:nosignatures:
:recursive:

PlateLoc
PlateLocSealer
PlateLocSealerBackend
PlateLocDriver
PlateLocSerialProfile
PlateLocStatus
PlateLocError
6 changes: 5 additions & 1 deletion docs/user_guide/01_material-handling/sealers/sealers.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@
## Installation

```bash
pip install pylabrobot[serial]
pip install "pylabrobot[serial]"
```

In automated wet lab workflows, **microplate sealers** are essential for preserving sample integrity.
They prevent **evaporation**, **cross-contamination**, and **spillage**, especially during heating, shaking, storage, or robotic transport.

PyLabRobot supports integration with various sealer machines, allowing you to programmatically seal plates as part of your automation workflows.

Supported serial sealers include:

- Agilent PlateLoc through `pylabrobot.agilent.PlateLoc`

---

## Types of Sealers
Expand Down
1 change: 1 addition & 0 deletions docs/user_guide/agilent/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
:maxdepth: 1

biotek/index
plateloc/hello-world
vspin/hello-world
```
157 changes: 157 additions & 0 deletions docs/user_guide/agilent/plateloc/hello-world.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "plateloc-intro",
"source": "# Agilent PlateLoc\n\nThe Agilent PlateLoc is controlled through PLR's `Sealer` capability with a direct RS-232 serial driver. It does not require Agilent ActiveX, VWorks, or vendor server software. Install the optional serial dependency before connecting:\n\n```bash\npip install \"pylabrobot[serial]\"\n```",
"metadata": {}
},
{
"cell_type": "code",
"id": "plateloc-import",
"source": "from pylabrobot.agilent import PlateLoc\n\nplateloc = PlateLoc(name=\"plateloc\", port=\"COM6\")",
"metadata": {},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"id": "plateloc-setup",
"source": "await plateloc.setup()",
"metadata": {},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"id": "plateloc-set-temp",
"source": "await plateloc.sealer.set_sealing_temperature(175)",
"metadata": {},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"id": "plateloc-set-time",
"source": "await plateloc.sealer.set_sealing_time(0.5)",
"metadata": {},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"id": "plateloc-status-first",
"source": "status = await plateloc.sealer.request_status()",
"metadata": {},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"id": "plateloc-sealer-intro",
"source": "The device also exposes the standard sealer capability:",
"metadata": {}
},
{
"cell_type": "code",
"id": "plateloc-seal",
"source": "await plateloc.sealer.seal(temperature=175, duration=1.5)",
"metadata": {},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"id": "plateloc-open",
"source": "await plateloc.sealer.open()",
"metadata": {},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"id": "plateloc-close",
"source": "await plateloc.sealer.close()",
"metadata": {},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"id": "plateloc-sealer-notes",
"source": "`sealer.open()` and `sealer.close()` move the stage and wait for the default stage-settle delay. `sealer.seal()` starts a sealing cycle after writing the requested temperature and time.\n\nThe PlateLoc sealer capability also exposes independent setpoint and status helpers:",
"metadata": {}
},
{
"cell_type": "code",
"id": "plateloc-set-temp-160",
"source": "await plateloc.sealer.set_sealing_temperature(160)",
"metadata": {},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"id": "plateloc-set-time-1",
"source": "await plateloc.sealer.set_sealing_time(1.0)",
"metadata": {},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"id": "plateloc-status-print",
"source": "status = await plateloc.sealer.request_status()\nprint(status.target_temperature, status.sealing_time, status.cycle_complete)",
"metadata": {},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"id": "plateloc-status-notes",
"source": "`request_status()` returns the best-known PLR state plus a live cycle-complete query. The direct serial protocol decoded here does not expose actual block temperature or actual stored time reads, so PLR reports the last successfully written target temperature and sealing time.",
"metadata": {}
},
{
"cell_type": "code",
"id": "plateloc-stop",
"source": "await plateloc.stop()",
"metadata": {},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"id": "plateloc-protocol",
"source": "## Serial command profile\n\nThe decoded direct protocol uses `19200 8N1` and carriage-return-terminated ASCII frames with two-letter command codes plus payloads. Temperature and time payloads use the firmware's fractional setpoint convention: the digits after the decimal point are the integer controller value.\n\n| Operation | Frame |\n|---|---|\n| Set sealing temperature | `ST 0.{temperature_celsius:03d}\\r` |\n| Set sealing time | `SS 0.{seconds_x10:02d}\\r` |\n| Start cycle | `GO 00\\r` |\n| Stop cycle | `AC 00\\r` |\n| Move stage out | `SO 00\\r` |\n| Move stage in | `SI 00\\r` |\n| Apply seal | `AS 00\\r` |\n| Clear error | `CL 00\\r` |\n| Check cycle complete | `CC 00\\r` |\n\nFor example, `set_sealing_temperature(175)` writes `ST 0.175\\r`, `set_sealing_temperature(30)` writes `ST 0.030\\r`, `set_sealing_time(0.5)` writes `SS 0.05\\r`, and `set_sealing_time(1.2)` writes `SS 0.12\\r`.\n\nNegative acknowledgements are parsed as `<code>NK(message)` and raised as `PlateLocError`. Some valid firmware commands reply with single-carriage-return acknowledgements such as `SOAK\\r`. The cycle-complete command returns `True` for `CCAK\\r` and `False` for `CCNK\\r`.\n\nYou can still override serial settings and timing with `PlateLocSerialProfile` while keeping the same PLR frontend:",
"metadata": {}
},
{
"cell_type": "code",
"id": "plateloc-profile",
"source": "from pylabrobot.agilent import PlateLoc, PlateLocSerialProfile\n\nprofile = PlateLocSerialProfile(\n baudrate=19200,\n stage_move_delay=6,\n)\n\nplateloc = PlateLoc(name=\"plateloc\", port=\"COM6\", profile=profile)",
"metadata": {},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"id": "plateloc-troubleshooting",
"source": "## Troubleshooting\n\nThe PlateLoc RS-232 connector is not VGA and is not USB TTL. Use a USB-to-RS-232 adapter plus the correct DB9 cable for the instrument. If the port opens but every command times out, verify the PlateLoc is powered, the rear serial cable is seated, and the cable wiring matches the instrument requirement. Some setups require a null-modem DB9 adapter rather than a straight-through cable.",
"metadata": {}
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"name": "python",
"version": "3.11.0"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
9 changes: 9 additions & 0 deletions pylabrobot/agilent/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,13 @@
SynergyH1,
SynergyH1Backend,
)
from .plateloc import (
PlateLoc,
PlateLocDriver,
PlateLocError,
PlateLocSealer,
PlateLocSealerBackend,
PlateLocSerialProfile,
PlateLocStatus,
)
from .vspin import Access2, Access2Driver, VSpin, VSpinCentrifugeBackend, VSpinDriver
9 changes: 9 additions & 0 deletions pylabrobot/agilent/plateloc/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from .plateloc import (
PlateLoc,
PlateLocDriver,
PlateLocError,
PlateLocSealer,
PlateLocSealerBackend,
PlateLocSerialProfile,
PlateLocStatus,
)
Loading