Fix jog queue blocking waiting to put new commands.

This commit is contained in:
Julian Stirling 2026-02-13 16:20:20 +00:00
parent f1d974c922
commit 728880e49d
2 changed files with 36 additions and 2 deletions

View file

@ -70,6 +70,25 @@ class JogStopCommand(JogCommand):
"""A command to stop a jog move."""
class JogQueue(queue.Queue[JogCommand]):
"""A class queue for JogCommands. This always returns the most recent command."""
def __init__(self) -> None:
"""Set up a queue with a max size of 1."""
super().__init__(maxsize=1)
def put(
self, item: JogCommand, block: bool = False, timeout: Optional[float] = None
) -> None:
"""Put the next command into the queue, bumping anything already there."""
try:
# First remove existing item if present
self.get_nowait()
except queue.Empty:
pass
super().put(item, block=block, timeout=timeout)
class BaseStage(lt.Thing):
"""A base stage class for OpenFlexure translation stages.
@ -97,7 +116,7 @@ class BaseStage(lt.Thing):
super().__init__(thing_server_interface)
self._hardware_lock = threading.RLock()
self._jog_lock = threading.Lock()
self._jog_queue: queue.Queue[JogCommand] = queue.Queue[JogCommand](maxsize=1)
self._jog_queue = JogQueue()
self._jog_thread: Optional[threading.Thread] = None
self._hardware_position = dict.fromkeys(self._axis_names, 0)
@ -310,7 +329,7 @@ class BaseStage(lt.Thing):
# Check the background thread is running, and restart it if not.
if self._jog_thread is None or not self._jog_thread.is_alive():
self.logger.info("Starting background thread for jog commands")
self._jog_queue = queue.Queue[JogCommand](maxsize=1)
self._jog_queue = JogQueue()
self._jog_thread = threading.Thread(
target=self._jog_loop, args=(command,)
)

View file

@ -12,6 +12,7 @@ from labthings_fastapi.testing import create_thing_without_server
from openflexure_microscope_server.things.camera.simulation import SimulatedCamera
from openflexure_microscope_server.things.stage import (
BaseStage,
JogMoveCommand,
RedefinedBaseMovementError,
)
from openflexure_microscope_server.things.stage.dummy import DummyStage
@ -300,3 +301,17 @@ def test_thing_description_equivalence(dummy_stage, mocker):
assert sanga_actions == dummy_actions == base_actions
assert sanga_properties == dummy_properties == base_properties
def test_get_jog_from_queue_most_recent(dummy_stage):
"""Test that the jog queue gives the most recent Jog Command."""
# Try to stack 4 moves in the queue, only 1 should be queued.
for i in range(4):
dummy_stage._jog_queue.put(JogMoveCommand([i, i, i]))
command = dummy_stage._get_from_jog_queue(0.001)
assert isinstance(command, JogMoveCommand)
# Should be the last one queued
assert command.displacement == [3, 3, 3]
# Nothing else is queued
assert dummy_stage._get_from_jog_queue(0.001) is None