From 421daf8d40cce933d861af50fa49d7a8acc695f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20S=C3=A1nchez-Gallego?= Date: Thu, 7 Nov 2024 07:24:41 +0000 Subject: [PATCH 1/2] Change async_readout default to False in observe_tile --- CHANGELOG.md | 7 +++++++ src/gort/gort.py | 3 ++- src/gort/observer.py | 2 +- src/gort/overwatcher/observer.py | 1 + 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7c900f..60db6a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## Next version + +### 🔥 Breaking change + +* `GortObserver.observe_tile` now default to `async_readout=False`. This will block until the exposure is done, which is a more natural behaviour for an external user that is not trying to over-optimise things. The code that uses `observe_tile` in GORT (`Gort.observe()` and `ObserverOverwatcher.observe_loop_task()`) have been updated to explicitly use `async_readout=True`. + + ## 1.0.2 - November 6, 2024 ### 🚀 New diff --git a/src/gort/gort.py b/src/gort/gort.py index 3794129..224b353 100644 --- a/src/gort/gort.py +++ b/src/gort/gort.py @@ -710,9 +710,10 @@ async def observe( for ipos, dpos in enumerate(tile.dither_positions): is_last = ipos == len(tile.dither_positions) - 1 - result, _ = await self.observe_tile( + result, _ = await self.observer.observe_tile( tile=tile, dither_position=dpos, + async_readout=True, keep_guiding=not is_last, skip_slew_when_acquired=True, run_cleanup=False, diff --git a/src/gort/observer.py b/src/gort/observer.py index 5921071..fe40f8a 100644 --- a/src/gort/observer.py +++ b/src/gort/observer.py @@ -260,7 +260,7 @@ async def observe_tile( dither_position: int | None = None, exposure_time: float = 900.0, n_exposures: int = 1, - async_readout: bool = True, + async_readout: bool = False, keep_guiding: bool = False, skip_slew_when_acquired: bool = True, guide_tolerance: float = 1.0, diff --git a/src/gort/overwatcher/observer.py b/src/gort/overwatcher/observer.py index c0e1321..85dfd9f 100644 --- a/src/gort/overwatcher/observer.py +++ b/src/gort/overwatcher/observer.py @@ -223,6 +223,7 @@ async def observe_loop_task(self): result, _ = await observer.observe_tile( tile=tile, dither_position=dpos, + async_readout=True, keep_guiding=True, skip_slew_when_acquired=True, run_cleanup=False, From 5996f29a49a5fad0fb6300c95094c20e6397f4db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20S=C3=A1nchez-Gallego?= Date: Thu, 7 Nov 2024 07:31:26 +0000 Subject: [PATCH 2/2] Add sleep in cleanup when reading out exposure to prevent bug in lvmscp --- CHANGELOG.md | 4 ++++ src/gort/recipes/operations.py | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60db6a1..d9f6cd8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ * `GortObserver.observe_tile` now default to `async_readout=False`. This will block until the exposure is done, which is a more natural behaviour for an external user that is not trying to over-optimise things. The code that uses `observe_tile` in GORT (`Gort.observe()` and `ObserverOverwatcher.observe_loop_task()`) have been updated to explicitly use `async_readout=True`. +### 🔧 Fixed + +* Temporary fix in the cleanup recipe for a bug in `lvmscp` caused by a quick reset after reading out a pending exposure. + ## 1.0.2 - November 6, 2024 diff --git a/src/gort/recipes/operations.py b/src/gort/recipes/operations.py index f5965fd..38ca80b 100644 --- a/src/gort/recipes/operations.py +++ b/src/gort/recipes/operations.py @@ -218,6 +218,7 @@ async def recipe(self, readout: bool = True, turn_lamps_off: bool = True): await self.gort.guiders.stop() if not (await self.gort.specs.are_idle()): + extra_sleep: float = 0 cotasks = [] for spec in self.gort.specs.values(): @@ -227,6 +228,7 @@ async def recipe(self, readout: bool = True, turn_lamps_off: bool = True): if await spec.is_reading(): self.gort.log.warning(f"{spec.name} is reading. Waiting.") cotasks.append(self._wait_until_spec_is_idle(spec)) + extra_sleep = 10 elif await spec.is_exposing(): self.gort.log.warning(f"{spec.name} is exposing. Aborting.") cotasks.append(spec.abort()) @@ -239,9 +241,17 @@ async def recipe(self, readout: bool = True, turn_lamps_off: bool = True): self.gort.log.warning(f"{msg} Reading it.") cotasks.append(spec.actor.commands.read()) cotasks.append(self._wait_until_spec_is_idle(spec)) + extra_sleep = 10 try: await asyncio.gather(*cotasks) + + # HACK: lvmscp says the controller is idle before it actually + # writes the image to disk. If we reset too fast (as we are going + # to do just after this) that will crash the exposures. + # I'll fix that in lvmscp (promise) but for now we add a sleep here + # to allows the images to post-process and write before resetting. + await asyncio.sleep(extra_sleep) except Exception as ee: self.gort.log.error(f"Error during cleanup: {ee}") self.gort.log.warning("Resetting the spectrographs.")