pylabrobot.centrifuge.highres.microspin_backend.MicroSpinBackend.wait_for_spindle_stopped#

async MicroSpinBackend.wait_for_spindle_stopped(*, timeout: float | None = 1800.0, poll_interval: float = 60.0) Dict[str, str]#

Block until the firmware confirms the rotor is fully stopped.

The MicroSpin firmware queues status behind any active motion and only answers once the rotor has spun down, so a single status is sufficient as a “we are stopped” gate. This method issues status repeatedly with a short per-call timeout until one returns successfully (the rotor stopped) – or until the overall timeout budget expires.

Retrying matters in practice because long decels can take well over a poll interval (a worst-case observed spin was spin 1000 100 10 5 taking >17 min to spin down on the slow-decel curve). With a single long timeout, you have to either pick a value that’s too short and raise spuriously, or one that’s so long it would mask a genuine hang forever. Polling gives you both bounded latency and tolerant patience.

Parameters:
  • timeout (float | None) – Total time budget in seconds. None means “wait indefinitely” (only do this if you’re sure the device isn’t stuck – see the low-G hang warning in spin()). Defaults to DEFAULT_SPINDLE_STOP_TIMEOUT (30 min).

  • poll_interval (float) – Per-status call timeout in seconds. Each individual status call may legitimately time out (because the rotor is still moving); the loop catches those and tries again. Defaults to DEFAULT_SPINDLE_POLL_INTERVAL (60 s).

Returns:

The parsed status report ({key – value} dict) from the first status call that succeeds.

Raises:
  • asyncio.TimeoutError – If the overall timeout expires before any status call returns successfully.

  • MicroSpinError – If a status call returns ERROR! (this is not retried – an ERROR! from status means the device itself thinks something is wrong, not that motion is still in progress).

Return type:

Dict[str, str]