Skip to content

v1b1 changes#1000

Draft
rickwierenga wants to merge 79 commits into
mainfrom
v1b1
Draft

v1b1 changes#1000
rickwierenga wants to merge 79 commits into
mainfrom
v1b1

Conversation

@rickwierenga
Copy link
Copy Markdown
Member

@rickwierenga rickwierenga commented Apr 18, 2026

rickwierenga and others added 30 commits March 23, 2026 12:42
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
y: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Notebook autoreload creates new class objects, breaking isinstance
checks on backend params (silently falling back to defaults). BackendParams
uses a metaclass with __instancecheck__ that falls back to qualname+module
comparison, which stays stable across reloads.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- DeviceBackend -> Driver (with backward-compat alias)
- Device._backend -> Device._driver, param backend -> driver
- New CapabilityBackend ABC for capability-specific backend interfaces
- All 15 abstract capability backends now extend CapabilityBackend
- Concrete backends extend both their capability backend and Driver
- Serialization key "backend" -> "driver" (deserialize accepts both)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Every monolithic backend that extended both a CapabilityBackend and Driver
is now split into:
- Driver: owns I/O, connection lifecycle, device-level ops
- CapabilityBackend: protocol translation, encodes capability calls into
  driver commands

Devices split: HepaFan, BioShake, Pico, Opentrons TempModule, Hamilton
HeaterShaker, Hamilton TiltModule, Keyence BarcodeScanner, XPeel, SCILA,
MettlerToledo, A4S, VSpin/Access2, CLARIOstar, SpectraMax 384+/M5.

Also: CapabilityBackend gains _on_setup/_on_stop hooks, Capability._on_setup
calls backend._on_setup, updated creating-capabilities.md, updated all
legacy wrappers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Recording backends and chatterbox backends are now pure CapabilityBackends.
Test devices use a _NullDriver for the Device lifecycle.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Test capabilities directly via cap._on_setup() instead of wrapping
in a fake Device.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix import sorting across 10+ files (ruff format --fix)
- Fix MolecularDevices legacy backend: reference renamed class, update test mocks to patch at correct level (Driver/Protocol instead of legacy wrapper)
- Fix Pico legacy tests: split Driver/MicroscopyBackend usage to match new architecture
- Fix Opentrons temp module: add base-type annotations for if/else branches
- Fix Liconic: use _on_setup/_on_stop (CapabilityBackend API)
- Fix Azenta A4S: type: ignore[safe-super] for abstract Driver methods
- Fix Pico backend: self._snap_images() instead of self._driver._snap_images()

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move shaker/tc capabilities into base class with has_shaking,
has_temperature, supports_active_cooling flags. Add resource
definitions for BioShake3000, BioShake3000Elm, BioShake3000ElmDWP,
and BioShakeQ1 from spec sheets.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…nds (#957)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract autoload firmware protocol into a standalone class that takes a
driver reference and operates on track numbers instead of Carrier objects.
The legacy STARBackend and new STAR device can both wire into this class.
Includes 36 tests covering all command types.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PlateReader now delegates reads through AbsorbanceCapability,
LuminescenceCapability, and FluorescenceCapability via adapter backends
that wrap the legacy PlateReaderBackend. Extracted _DictBackendParams
into pylabrobot/legacy/_backend_params.py for reuse across legacy
adapters.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move autoload, cover, x-arm, wash station, and ~44 generic driver
infrastructure methods (firmware queries, EEPROM, area reservation,
configuration) into the new STARDriver architecture. Legacy backend
methods now delegate to new classes or have deprecation docstrings.

- STARAutoload: autoload module control (carrier loading, barcode, LEDs)
- STARCover: front cover lock/unlock/enable/disable
- STARXArm: left/right X-arm positioning (parameterized by side)
- STARWashStation: dual-chamber wash station drain/fill/init
- STARDriver: generic instrument operations directly on driver
- STARChatterboxDriver: updated with all subsystems
- STAR device only exposes capabilities (PIP, Head96, iSWAP)
- Subsystems live on the driver, accessed via star._driver
- 114 tests across all subsystems
- Right X-arm and wash station are conditional on hardware config
- X-arm methods use mm (PLR standard), not 0.1mm firmware units
- Fixed pre-existing assertion bugs in release_occupied_area and
  set_instrument_configuration

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
These methods send a command to hardware and wait for a response,
so request_ better reflects the I/O semantics. Covers PreciseFlex,
capability interfaces (temperature, humidity), and all vendor backends
(Azenta, Agilent, BMG, Byonoy, Hamilton, INHECO, Liconic, Molecular
Devices, Opentrons, Qinstruments, Thermo Fisher). Legacy public APIs
keep get_ names unchanged; only internal delegations are updated.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move 14 multi-channel PIP operations to STARPIPBackend: channel
positioning (Y/Z), initialization, spread, z-safety, foil piercing.
Parameters use mm (PLR standard) with internal 0.1mm conversion.

Key changes:
- pierce_foil and step_off_foil on STARPIPBackend with explicit deck param
- iSWAP-parked checks on Y-movement methods
- Channel min Y spacing queried from firmware in driver setup()
- Right X-arm conditional on right_x_drive_large
- Wash station conditional on wash_station_*_installed
- Legacy backend aliases (left_x_arm, iswap) for PIPBackend compat
- Fixed pierce_foil one_by_one bug (z vs z+distance_from_bottom)
- Fixed _ensure_can_reach_position dead fallback (is None vs not)
- Architecture doc updated

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two new dispensing capabilities under bulk_dispensers/:
- SyringeDispensing: dispense(plate, volumes={col: vol}), prime(plate, volume)
- PeristalticDispensing: dispense(plate, volumes={col: vol}), prime(), purge()

Both use BackendParams for device-specific parameters.
Also adds BackendParams to PlateWashingCapability.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- EL406Driver: FTDI I/O, batch management, device-level ops, queries
- EL406PlateWashingBackend: manifold ops (wash, aspirate, dispense, prime)
- EL406ShakingBackend: shake/soak
- EL406SyringeDispensingBackend: syringe dispense/prime
- EL406PeristalticDispensingBackend: peristaltic dispense/prime/purge

Legacy code is thin wrappers delegating to new backends. All 385 tests pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…tecture

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move plate washer docs from 00_liquid-handling/plate-washing/ to
agilent/biotek/el406/ and heater-shaker docs from
01_material-handling/heating_shaking/ to qinstruments/bioshake/.
Add Manufacturers toctree section with manufacturer-level indexes.
Include migration guide at repo root for future device migrations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move device docs from legacy category dirs (00_liquid-handling/,
01_material-handling/, 02_analytical/) to manufacturer-based layout
mirroring the codebase. Add Manufacturers toctree section and API
reference RST files for all manufacturers with autosummary directives
and autoclass for nested BackendParams. Add Sphinx cross-references
for BackendParams in notebook markdown cells.

Devices migrated: EL406, BioShake, Mettler Toledo WXS205SDU,
Azenta a4S, Azenta XPeel, Liconic STX, Inheco ThermoShake,
Inheco CPAC, Inheco SCILA, Inheco Incubator Shaker, Inheco ODTC,
Thermo Fisher Multidrop Combi.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
vcjdeboer and others added 8 commits April 10, 2026 17:18
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Rick Wierenga <rick_wierenga@icloud.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Rick Wierenga <rick_wierenga@icloud.com>
Each of the 4 drawers is now a LoadingTray keyed by drawer_id in
`scila.drawers`. Command sequences (PrepareForInput/OpenDoor,
PrepareForOutput/CloseDoor) and drawer_id validation move from the
driver into SCILADrawerLoadingTrayBackend. Re-add CO2-flow warning
suppression (log + continue) that had been lost in the rewrite.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…re (#989)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Hazlam Shamin <69739427+hazlamshamin@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…imbus

Deck is now passed into the driver at __init__ time (not through setup), so
the driver can construct backends with deck as a required arg. PIP/Head96
capabilities also take deck required on __init__. Legacy STARBackend still
receives deck via set_deck (legacy flow) and forwards it to the already-built
STARDriver.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rickwierenga rickwierenga force-pushed the v1b1 branch 2 times, most recently from feee0ba to 162dd2c Compare April 23, 2026 17:30
rickwierenga and others added 2 commits April 23, 2026 10:30
Makes gripper_length and gripper_z_offset required on PreciseFlexArmBackend
(no sensible backend-level defaults — they depend on the mounted gripper)
and moves the per-model defaults (162 mm length, 0 mm z offset) to the
PreciseFlex400 Device wrapper so users can override them when installing
a non-stock gripper.

Also renames PF400Params.z_tool_offset to gripper_z_offset for naming
consistency with the user-facing parameter.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Rick Wierenga <rick_wierenga@icloud.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread pylabrobot/hamilton/liquid_handlers/star/pip_channel.py Outdated
BioCam and others added 10 commits April 27, 2026 13:49
PIPChannel.request_firmware_version and STARDriver.request_firmware_version
now parse the RF response through parse_star_firmware_version_date and
return a datetime.date, matching what STARHead96Backend already did.
ztouch_probe_z_height uses version.year < 2022 directly instead of
regex re-parsing the raw string.

Drop the chatterbox-None fallback from STARHead96Backend.request_firmware_version:
chatterbox paths should explicitly override the method (or accept the
ValueError) rather than silently advertising a fabricated date.

Legacy STARBackend.request_pip_channel_version keeps its str return type
by inlining the raw RF query — the new PIPChannel method now returns
datetime so direct delegation would have broken the legacy contract.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Move the read-window from a backend/device-construction parameter to a
per-call argument on BarcodeScanner.scan(read_time=...). Backends for
scanners without a configurable window (chatterbox, Keyence) accept and
ignore.
scan() / scan_barcode() now return None when the read window elapses
with no successful decode. Reserved for the "nothing seen" case;
hardware faults still raise BarcodeScannerError. Liconic propagates the
Optional through read_barcode_inline / scan_barcode.
…0-100, PF400 park override

- GripperLocation → CartesianPose; add JointPose=Dict[int,float] alias
- PreciseFlexGripperLocation → PreciseFlexCartesianPose; PFAxis → Axis
- Cart.rail field → rail_position; consistent rail_position kwarg naming
- Percentage params suffixed _pct (speed_pct, acceleration_pct, finger_speed_pct, etc.)
  with 0-100 ValueError validation across set_profile_*, set_motion_profile_values,
  set_monitor_speed (lower bound relaxed from 1 to 0), and _set_grasp_data
- park() consolidates the firmware "movetosafe" call (move_to_safe removed)
- New PreciseFlex400Backend overrides park() with explicit joint pose
  {BASE:170, SHOULDER:0, ELBOW:180, WRIST:-180}; PreciseFlex400 device wires it up
- Legacy shim updated to delegate to renamed new-module API; legacy public API preserved
The method returns a CartesianPose (location + rotation), so 'location'
was a misnomer. Renamed across the ABC, the Arm wrapper, and all
backends (xArm6, Hamilton STAR/iSwap/core, Brooks PreciseFlex, legacy
adapters), plus user-guide notebooks/markdown.
…convention so 0°=+X (#1034)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Rick Wierenga <rick_wierenga@icloud.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…hy refactor (#1044)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
rickwierenga added a commit to c-reiter/pylabrobot that referenced this pull request May 19, 2026
Hold off on the agilent/ subpackage split (and its deprecation shims) until
the broader machine-interface architecture lands (see PyLabRobot#1000). This PR now
only adds the new HighRes MicroSpin files; existing VSpin imports are
unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
rickwierenga and others added 5 commits May 19, 2026 14:27
…1b1 refactor

Surfaced by a firmware-level audit of v1b1 vs main; restores effective parity for
defaults and call surfaces without changing the new Device/Driver/Capability
architecture.

- iSWAP: MoveToLocationParams.minimum_traverse_height 360.0 → 280.0 to match
  main's _iswap_traversal_height; move_gripper(width=None) picks 91/132 mm by
  firmware vintage.
- 96-head: slave-timeout polling (_is_slave_timeout / _wait_for_idle) wraps
  aspirate96/dispense96; read_timeout=max(300, driver.read_timeout) restored;
  _check_96_position_legal envelope check at pickup/drop/asp/disp; drop-z 216.4
  sanity warn.
- CoRe: reject negative y/z; range checks for grip_strength, y_gripping_speed,
  z_speed, z_press_on_distance, acceleration_index; back/front_y ordering +
  left_arm_min_y assertions in core_grippers(); add core_read_barcode (C0 ZB)
  and CoreGripper.check_resource_exists_at_location_center.
- X-arm: restore x_arm_request_firmware_version (X0 RF) and
  experimental_x_arm_move (X0 XP).
- Probing: real probe_liquid_heights / probe_liquid_volumes / empty_tips on
  STARDriver (were NotImplementedError stubs); aspirate(probe_liquid_height=True)
  now works.
- PIP: PIPChannel.move_x / move_x_relative / move_y_relative /
  move_tool_z_relative; STARPIPBackend.request_tadm_status batch query;
  get_channel_spacings; or → is None traversal-height fallback semantics.
- Setup: skip_pip / skip_iswap / skip_core96_head / skip_autoload kwargs;
  num_channels from RT count (kp fallback); _channels_minimum_y_spacing
  pre-fill restored to [9.0] * 8.
- Top-level: set_minimum_channel_traversal_height /
  set_minimum_iswap_traversal_height setters + iswap_minimum_traversal_height
  context manager on _HamiltonSTAR; deprecated set_minimum_traversal_height
  shim raises with migration message.
- Autoload: set_barcode_type legacy 7-bool shim restored as deprecation.
- Errors: tighten skip condition to (error_code == 0 AND trace_information == 0)
  so master-side trace-only faults aren't silently dropped; fw_parsing date
  regexes re-anchored with \b.
- Misc: dedup DEFAULT_TIP_FITTING_DEPTH; y_drive_mm_per_increment typo
  0.046302082 → 0.046302083.

All 117 existing STAR tests pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…lidate_tip_inventory from legacy

Byte-equivalent move into the v1b1 PIP capability. STAR-specific z kwargs
(minimum_traverse_height_at_beginning_of_a_command, z_position_at_end_of_a_command)
are now passed via pick_up_backend_params / drop_backend_params instead of being
named kwargs on pick_up_tips / drop_tips. Legacy use_channels default
(list(range(num_channels_available))) preserved verbatim in consolidate.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
When the SCILA is operated without an external gas mixer, drawer open/close
emits a non-fatal CO2-flow warning. Until now this was always swallowed-and-
logged via an unconditional substring match. The new flag (default True) makes
the swallow deliberate: with no mixer connected, the warning is expected and
silenced; with a mixer connected, the warning is surfaced via logger.warning
so a real CO2 problem isn't hidden.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The legacy stubs forwarded to pylabrobot.brooks, but the new brooks API
has diverged enough (renamed poses/axes, *_pct units, new access types)
that the forwarders are brittle. Drop the forwarders and keep a verbatim
copy of main's pylabrobot/arms/precise_flex/ under
pylabrobot/legacy/arms/precise_flex/, with only the
pylabrobot.arms.* -> pylabrobot.legacy.arms.* import path rewritten.
The new pylabrobot/brooks/ implementation is unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants