Skip to content

Upgrade Agilent VSpin and Access2 protocol drivers - #1227

Open
rickwierenga wants to merge 3 commits into
mainfrom
vspin-access2-upgrade
Open

Upgrade Agilent VSpin and Access2 protocol drivers#1227
rickwierenga wants to merge 3 commits into
mainfrom
vspin-access2-upgrade

Conversation

@rickwierenga

Copy link
Copy Markdown
Member

Summary

This PR substantially upgrades PyLabRobot's Agilent VSpin centrifuge and Access2 loader support
using complete protocol and sequencing knowledge from the vspin-cockpit project.

The existing PLR APIs and FTDI transports are retained, while opaque wire captures are replaced
with named protocol operations, typed status decoding, explicit trajectory calculations, bounded
polling, and safer state-confirmed workflows.

Thanks

Special thanks to Reed Kelso for generously sharing his work on the Agilent VSpin and Access2 in the
vspin-cockpit repository and allowing us to adapt the
relevant logic for PyLabRobot.

The reference implementation was pinned during development to
2e6ff6b9327cb66f7889d76cdefefc2a5b5652b2.

A durable acknowledgement is also included in the package-local VSpin README.

VSpin changes

  • Added structured NMC command construction and typed response decoding.
  • Replaced delimiter-based reads with fixed-length reads derived from each module's active status
    mask.
  • Added checksum validation and command/response context to protocol errors.
  • Ported baud probing, network reset, sequential address assignment, module identification,
    topology validation, and final 57,600-baud setup.
  • Added bounded, status-driven homing and retained the resulting home position.
  • Added shortest-path bucket positioning with:
    • motion-complete confirmation;
    • encoder-position tolerance;
    • servo fault detection;
    • motor-off failure handling;
    • one-revolution alignment recovery.
  • Reworked spin calculations around explicit RCF/RPM, velocity, acceleration, ramp-time, and
    encoder-distance conversions.
  • Preserved independent acceleration and deceleration fractions.
  • Confirmed deceleration using both MOVE_DONE and zero measured velocity.
  • Removed the unexplained post-spin reset/re-home loop.
  • Added an explicit safe spin-abort operation.
  • Rejects signed 32-bit position overflow before sending servo motion.
  • Teardown now closes FTDI without resetting the NMC network.

Access2 changes

  • Added a typed, transport-independent Access2 command/status codec.
  • Uses PLR's binary Reader and Writer helpers throughout.
  • Preserves the existing FTDI constructor and transport behavior.
  • Added strict FTDI framing, CRC validation, response-ID matching, bounded frame sizes, and
    partial-read handling.
  • Added firmware and hardware version queries.
  • Added short and full status decoding, including:
    • initialized and homed state;
    • emergency-stop state;
    • motor-power faults;
    • optical sensor state;
    • per-axis status and positions.
  • Distinguishes absolute single-axis moves from controller-stored teachpoint moves.
  • Added bounded, status-confirmed homing and motion polling.
  • Added readable load and unload sequences with physical VSpin interlocks.
  • PLR resource state changes only after the corresponding physical operation succeeds.
  • Added idempotent absolute gripper open/close operations while retaining private relative grip
    adjustments.

TCP Access2 support is intentionally deferred. A future implementation can use
pylabrobot.io.Socket without changing the existing FTDI path.

Compatibility

The principal PLR interfaces remain intact:

  • VSpin.spin(g, duration, acceleration, deceleration)
  • go_to_bucket1() and go_to_bucket2()
  • VSpin door, bucket-lock, status, and calibration operations
  • Access2.load() and Access2.unload()
  • Existing FTDI-based construction

Internal helpers and protocol names were refactored repository-wide without deprecation aliases.

@TheBirdAttack

Copy link
Copy Markdown

What would speak against making a Windows-specific exception for VSpin and allowing it to
use the existing COM port/VCP path?

On Windows, the VSpin can appear as a normal virtual COM port. If PyLabRobot could use that directly, users would not have to replace the FTDI driver with libusbK via Zadig. That would also make it much easier to switch back to the original Agilent software, since the manufacturer tools should still be able to find the device through the standard driver path.

I know, this is mainly an operational concern, still we Windows users already suffer enough through Microslop, why make us perform driver archaeology before spinning a plate? ;)

This would also align well with PyLabRobot’s existing IO model, since pylabrobot.io.Serial already supports explicit COM ports and could be used as an optional transport without changing the current FTDI backend.

Something like:

VSpin(name="vspin", device_id="FTDI_SERIAL")  # unchanged default FTDI path
VSpin(name="vspin", serial_port="COM7")       # optional VCP path

@TheBirdAttack

Copy link
Copy Markdown

I tested the PR on our older V11 VSpin centrifuge (both on Windows and via WSL2/libftdi). I am not entirely sure if this is a general compatibility issue with older firmware/hardware, or if our specific unit is just showing its age and acting up, but I observed two potential issues:

Baud rate upgrade seems to fail: The centrifuge initializes reliably at 19200 baud, but communication times out once the PR switches to 57600 baud. Interestingly, when I locally forced the runtime baud rate to stay at 19200, all operations completed successfully over libftdi.

Checksum errors during startup: The unmodified PR fails early during NMC module discovery. I suspect this is due to stale or misaligned response bytes (e.g., response 02fb0000). A small local patch seemed to get around this by setting RTS/DTR before NMC initialization, waiting briefly after a hard reset, and adding a short resync scan to catch those stale bytes.

Potential Idea / Workaround:
Assuming our device isn't just faulty and this behavior might affect other older units as well, a minimally invasive fix could be adding a compatibility knob. We could keep the 57600 baud switch as the default for newer models, but allow opting out of the post-init baud upgrade (keeping it at 19200). If you think it makes sense, incorporating the small startup resync step might also make the initial module discovery a bit more robust for quirky hardware like ours.

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.

2 participants