Skip to content

Air liha backend#981

Draft
Robert-Keyser-Calico wants to merge 12 commits intoPyLabRobot:mainfrom
Robert-Keyser-Calico:air-liha-backend
Draft

Air liha backend#981
Robert-Keyser-Calico wants to merge 12 commits intoPyLabRobot:mainfrom
Robert-Keyser-Calico:air-liha-backend

Conversation

@Robert-Keyser-Calico
Copy link
Copy Markdown
Contributor

This pull request adds comprehensive support for the Tecan Air LiHa (ZaapMotion) hardware variant to the pylabrobot project. It introduces a new backend subclass, updates liquid class mappings, and provides detailed documentation and tooling for reverse engineering and testing. The changes are organized into implementation planning, technical investigation, new utilities for USB protocol decoding, and a demo script for a related bulk dispenser instrument.

Air LiHa Support Implementation:

  • Added a detailed implementation plan for supporting Air LiHa via a new AirEVOBackend subclass, outlining architectural decisions, required overrides, ZaapMotion configuration, and test coverage. This ensures clean separation from the existing syringe-based backend and minimizes risk to current users.
  • Documented the technical investigation into Air LiHa, including reverse engineering of ZaapMotion initialization, motor configuration, plunger conversion factors, per-operation command patterns, and liquid class data extraction from EVOware XML files.

Developer Tooling and Utilities:

  • Added decode_usb_capture.py, a utility script for decoding Tecan EVO USB captures from Wireshark, which assists in analyzing and validating firmware-level communication during development and troubleshooting.

Demo and Testing:

  • Added demo_multidrop.py, a demo script showcasing usage of the Multidrop Combi bulk dispenser, including plate configuration, dispensing, and error handling, to aid both development and user onboarding for related instruments.

These changes collectively provide a robust foundation for Air LiHa support, facilitate future hardware integrations, and improve developer productivity with new reverse engineering tools.

Robert-Keyser-Calico and others added 12 commits March 27, 2026 14:12
The Air LiHa uses ZaapMotion BLDC motor controllers for air displacement
pipetting. After power cycle, these controllers boot into bootloader mode
and require motor configuration (PID gains, current limits, encoder setup)
before Z-axis homing can succeed. This was reverse-engineered from USB
captures of EVOware's initialization sequence.

Changes:
- New AirEVOBackend subclass with ZaapMotion boot exit and motor config
- Air LiHa plunger conversion factors (106.4 steps/uL, 213 speed factor)
- ZaapMotion force mode (SFR/SFP/SDP) wrapping around plunger operations
- ZaapDiTi liquid class entries for Water and DMSO with DiTi 50uL tips
- Hardware test scripts and investigation documentation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The ZaapMotion SDO config command must be sent right before PIA
(matching EVOware's sequence). Also add logging and post-failure
diagnostics to the init test script.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Move init-skip logic into AirEVOBackend.setup() (_is_initialized,
  _setup_quick, _setup_full) with fast 1s buffer drain
- Fix labware_library.py: use TecanPlate for Eppendorf plate (required
  by aspirate/dispense), correct tip length to 58.1mm (measured),
  set tip_type to AIRDITI, fix TipSpot import
- Z-coordinate issue identified: tip pickup Z is ~100mm too high.
  Root cause is _liha_positions adding carrier offset + tip_length
  to z_start values that are already absolute Tecan coordinates
  (0=top, z_range=deck). Needs coordinate transform fix.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix pick_up_tips to use tip rack z_start directly instead of
  broken _liha_positions Z calculation (coordinate system mismatch)
- Fix Y-spacing (ys) in aspirate/dispense: use plate item_dy (well pitch)
  instead of well size (was 54 instead of 90, causing invalid operand)
- Add jog_liha.py interactive teaching tool for X/Y/Z positions
- Add tips_off.py emergency tip removal script
- Add temporary X offset (+60 = 6mm) for tip pickup alignment
- Aspirate Z still needs calibration (z_start too high)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
16 tests covering all Air LiHa-specific logic with mocked USB:

- ConversionFactorTests: verify 106.4 steps/uL and 213 speed factor
  are used in airgap calculations (not syringe 3/6)
- ForceModeSFRTests: verify SFR/SFP/SDP commands sent to all 8 tips
  for force_on and force_off
- InitSkipTests: verify REE0 parsing for init-skip logic
  (@ = OK, A = init failed, G = not init, Y = tip not fetched)
- ZaapMotionConfigTests: verify 33-command config sequence,
  RCS skip logic, safety module SPN/SPS3
- PickUpTipsAirTests: verify tip pickup uses Air LiHa conversion
  factors (SEP=14910, PPR=1064)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Mirror of v1b1 firmware features for the legacy architecture:
- Wrap raw send_command calls (REE, PIA, PIB, BMX, BMA, PPA, SDT) in typed EVOArm/LiHa methods
- Add new firmware commands: RPP, RVZ, RTS, PAZ for plunger/Z/tip queries
- Create inline ZaapMotion class replacing raw T2{tip} string commands
- Implement mixing (_perform_mix) and blow-out (_perform_blow_out) with Air LiHa force mode overrides
- Add request_tip_presence() via RTS firmware command
- Add post-grip plate verification, configurable RoMa park position
- Update tests for new firmware wrapper call patterns

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

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix mypy errors: add type annotations for z_aspirate list, type: ignore
  for mock method assignments, use mock_send variable for mock attribute access
- Fix ruff import sorting in air_evo_tests.py
- Fix item_dy access on Optional[Resource] with None check
- Add STEPS_PER_UL/SPEED_FACTOR constants to EVOBackend base class
- Update _typos.toml: exclude OCR'd manual text and USB capture logs,
  whitelist Tecan firmware command abbreviations (ALO, SOM, SHS, etc.)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Files kept locally but removed from repo:
- keyser-testing/Tecan Manuals/ (PDFs + OCR text extractions)
- keyser-testing/evoware-usb-capture-*/ (pcap, trace logs)
- keyser-testing/evoware-pktmon-capture-*/ (etl, decoded logs)
- keyser-testing/*.pdf (ZaapMotion docs)

Also:
- Add these paths to .gitignore
- Fix ruff import sorting in air_evo_backend.py

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (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.

1 participant