Skip to content

Commit 1636440

Browse files
committed
stop cytation ftdi if camera setup fails
1 parent 0e2896d commit 1636440

File tree

1 file changed

+114
-103
lines changed

1 file changed

+114
-103
lines changed

pylabrobot/plate_reading/biotek_backend.py

Lines changed: 114 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -155,115 +155,126 @@ async def setup(self, use_cam: bool = False) -> None:
155155
self._shaking_task: Optional[asyncio.Task] = None
156156

157157
if use_cam:
158-
if not USE_PYSPIN:
159-
raise RuntimeError(
160-
"PySpin is not installed. Please follow the imaging setup instructions. "
161-
f"Import error: {_PYSPIN_IMPORT_ERROR}"
162-
)
163-
if self.imaging_config is None:
164-
raise RuntimeError("Imaging configuration is not set.")
165-
166-
logger.debug("[cytation5] setting up camera")
167-
168-
# -- Retrieve singleton reference to system object (Spinnaker) --
169-
self.spinnaker_system = PySpin.System.GetInstance()
170-
version = self.spinnaker_system.GetLibraryVersion()
171-
logger.debug(
172-
"[cytation5] Library version: %d.%d.%d.%d",
173-
version.major,
174-
version.minor,
175-
version.type,
176-
version.build,
158+
try:
159+
await self._set_up_camera()
160+
except:
161+
# if setting up the camera fails, we have to close the ftdi connection
162+
# so that the user can try calling setup() again.
163+
# if we don't close the ftdi connection here, it will be open until the
164+
# python kernel is restarted.
165+
await self.stop()
166+
raise
167+
168+
async def _set_up_camera(self) -> None:
169+
if not USE_PYSPIN:
170+
raise RuntimeError(
171+
"PySpin is not installed. Please follow the imaging setup instructions. "
172+
f"Import error: {_PYSPIN_IMPORT_ERROR}"
177173
)
174+
if self.imaging_config is None:
175+
raise RuntimeError("Imaging configuration is not set.")
176+
177+
logger.debug("[cytation5] setting up camera")
178+
179+
# -- Retrieve singleton reference to system object (Spinnaker) --
180+
self.spinnaker_system = PySpin.System.GetInstance()
181+
version = self.spinnaker_system.GetLibraryVersion()
182+
logger.debug(
183+
"[cytation5] Library version: %d.%d.%d.%d",
184+
version.major,
185+
version.minor,
186+
version.type,
187+
version.build,
188+
)
178189

179-
# -- Get the camera by serial number, or the first. --
180-
cam_list = self.spinnaker_system.GetCameras()
181-
num_cameras = cam_list.GetSize()
182-
logger.debug("[cytation5] number of cameras detected: %d", num_cameras)
183-
184-
for cam in cam_list:
185-
info = self._get_device_info(cam)
186-
serial_number = info["DeviceSerialNumber"]
187-
logger.debug("[cytation5] camera detected: %s", serial_number)
188-
189-
if (
190-
self.imaging_config.camera_serial_number is not None
191-
and serial_number == self.imaging_config.camera_serial_number
192-
):
193-
self.cam = cam
194-
logger.info("[cytation5] using camera with serial number %s", serial_number)
195-
break
196-
else: # if no specific camera was found by serial number so use the first one
197-
if num_cameras > 0:
198-
self.cam = cam_list.GetByIndex(0)
199-
logger.info(
200-
"[cytation5] using first camera with serial number %s", info["DeviceSerialNumber"]
201-
)
202-
else:
203-
logger.error("[cytation5] no cameras found")
204-
self.cam = None
205-
cam_list.Clear()
190+
# -- Get the camera by serial number, or the first. --
191+
cam_list = self.spinnaker_system.GetCameras()
192+
num_cameras = cam_list.GetSize()
193+
logger.debug("[cytation5] number of cameras detected: %d", num_cameras)
206194

207-
if self.cam is None:
208-
raise RuntimeError(
209-
"No camera found. Make sure the camera is connected and the serial " "number is correct."
210-
)
195+
for cam in cam_list:
196+
info = self._get_device_info(cam)
197+
serial_number = info["DeviceSerialNumber"]
198+
logger.debug("[cytation5] camera detected: %s", serial_number)
211199

212-
# -- Initialize camera --
213-
for _ in range(10):
214-
try:
215-
self.cam.Init() # SpinnakerException: Spinnaker: Could not read the XML URL [-1010]
216-
break
217-
except: # noqa
218-
pass
219-
else:
220-
raise RuntimeError(
221-
"Failed to initialize camera. Make sure the camera is connected and the "
222-
"Spinnaker SDK is installed correctly."
200+
if (
201+
self.imaging_config.camera_serial_number is not None
202+
and serial_number == self.imaging_config.camera_serial_number
203+
):
204+
self.cam = cam
205+
logger.info("[cytation5] using camera with serial number %s", serial_number)
206+
break
207+
else: # if no specific camera was found by serial number so use the first one
208+
if num_cameras > 0:
209+
self.cam = cam_list.GetByIndex(0)
210+
logger.info(
211+
"[cytation5] using first camera with serial number %s", info["DeviceSerialNumber"]
223212
)
224-
nodemap = self.cam.GetNodeMap()
213+
else:
214+
logger.error("[cytation5] no cameras found")
215+
self.cam = None
216+
cam_list.Clear()
225217

226-
# -- Configure trigger to be software --
227-
# This is needed for longer exposure times (otherwise 23ms is the maximum)
228-
# 1. Set trigger selector to frame start
229-
ptr_trigger_selector = PySpin.CEnumerationPtr(nodemap.GetNode("TriggerSelector"))
230-
if not PySpin.IsReadable(ptr_trigger_selector) or not PySpin.IsWritable(ptr_trigger_selector):
231-
raise RuntimeError(
232-
"unable to configure TriggerSelector " "(can't read or write TriggerSelector)"
233-
)
234-
ptr_frame_start = PySpin.CEnumEntryPtr(ptr_trigger_selector.GetEntryByName("FrameStart"))
235-
if not PySpin.IsReadable(ptr_frame_start):
236-
raise RuntimeError("unable to configure TriggerSelector (can't read FrameStart)")
237-
ptr_trigger_selector.SetIntValue(int(ptr_frame_start.GetNumericValue()))
238-
239-
# 2. Set trigger source to software
240-
ptr_trigger_source = PySpin.CEnumerationPtr(nodemap.GetNode("TriggerSource"))
241-
if not PySpin.IsReadable(ptr_trigger_source) or not PySpin.IsWritable(ptr_trigger_source):
242-
raise RuntimeError("unable to configure TriggerSource (can't read or write TriggerSource)")
243-
ptr_inference_ready = PySpin.CEnumEntryPtr(ptr_trigger_source.GetEntryByName("Software"))
244-
if not PySpin.IsReadable(ptr_inference_ready):
245-
raise RuntimeError("unable to configure TriggerSource (can't read Software)")
246-
ptr_trigger_source.SetIntValue(int(ptr_inference_ready.GetNumericValue()))
247-
248-
# 3. Set trigger mode to on
249-
ptr_trigger_mode = PySpin.CEnumerationPtr(nodemap.GetNode("TriggerMode"))
250-
if not PySpin.IsReadable(ptr_trigger_mode) or not PySpin.IsWritable(ptr_trigger_mode):
251-
raise RuntimeError("unable to configure TriggerMode (can't read or write TriggerMode)")
252-
ptr_trigger_on = PySpin.CEnumEntryPtr(ptr_trigger_mode.GetEntryByName("On"))
253-
if not PySpin.IsReadable(ptr_trigger_on):
254-
raise RuntimeError("unable to query TriggerMode On")
255-
ptr_trigger_mode.SetIntValue(int(ptr_trigger_on.GetNumericValue()))
256-
257-
# "NOTE: Blackfly and Flea3 GEV cameras need 1 second delay after trigger mode is turned on"
258-
await asyncio.sleep(1)
259-
260-
# -- Load filter information --
261-
if self._filters is None:
262-
await self._load_filters()
263-
264-
# -- Load objective information --
265-
if self._objectives is None:
266-
await self._load_objectives()
218+
if self.cam is None:
219+
raise RuntimeError(
220+
"No camera found. Make sure the camera is connected and the serial " "number is correct."
221+
)
222+
223+
# -- Initialize camera --
224+
for _ in range(10):
225+
try:
226+
self.cam.Init() # SpinnakerException: Spinnaker: Could not read the XML URL [-1010]
227+
break
228+
except: # noqa
229+
pass
230+
else:
231+
raise RuntimeError(
232+
"Failed to initialize camera. Make sure the camera is connected and the "
233+
"Spinnaker SDK is installed correctly."
234+
)
235+
nodemap = self.cam.GetNodeMap()
236+
237+
# -- Configure trigger to be software --
238+
# This is needed for longer exposure times (otherwise 23ms is the maximum)
239+
# 1. Set trigger selector to frame start
240+
ptr_trigger_selector = PySpin.CEnumerationPtr(nodemap.GetNode("TriggerSelector"))
241+
if not PySpin.IsReadable(ptr_trigger_selector) or not PySpin.IsWritable(ptr_trigger_selector):
242+
raise RuntimeError(
243+
"unable to configure TriggerSelector " "(can't read or write TriggerSelector)"
244+
)
245+
ptr_frame_start = PySpin.CEnumEntryPtr(ptr_trigger_selector.GetEntryByName("FrameStart"))
246+
if not PySpin.IsReadable(ptr_frame_start):
247+
raise RuntimeError("unable to configure TriggerSelector (can't read FrameStart)")
248+
ptr_trigger_selector.SetIntValue(int(ptr_frame_start.GetNumericValue()))
249+
250+
# 2. Set trigger source to software
251+
ptr_trigger_source = PySpin.CEnumerationPtr(nodemap.GetNode("TriggerSource"))
252+
if not PySpin.IsReadable(ptr_trigger_source) or not PySpin.IsWritable(ptr_trigger_source):
253+
raise RuntimeError("unable to configure TriggerSource (can't read or write TriggerSource)")
254+
ptr_inference_ready = PySpin.CEnumEntryPtr(ptr_trigger_source.GetEntryByName("Software"))
255+
if not PySpin.IsReadable(ptr_inference_ready):
256+
raise RuntimeError("unable to configure TriggerSource (can't read Software)")
257+
ptr_trigger_source.SetIntValue(int(ptr_inference_ready.GetNumericValue()))
258+
259+
# 3. Set trigger mode to on
260+
ptr_trigger_mode = PySpin.CEnumerationPtr(nodemap.GetNode("TriggerMode"))
261+
if not PySpin.IsReadable(ptr_trigger_mode) or not PySpin.IsWritable(ptr_trigger_mode):
262+
raise RuntimeError("unable to configure TriggerMode (can't read or write TriggerMode)")
263+
ptr_trigger_on = PySpin.CEnumEntryPtr(ptr_trigger_mode.GetEntryByName("On"))
264+
if not PySpin.IsReadable(ptr_trigger_on):
265+
raise RuntimeError("unable to query TriggerMode On")
266+
ptr_trigger_mode.SetIntValue(int(ptr_trigger_on.GetNumericValue()))
267+
268+
# "NOTE: Blackfly and Flea3 GEV cameras need 1 second delay after trigger mode is turned on"
269+
await asyncio.sleep(1)
270+
271+
# -- Load filter information --
272+
if self._filters is None:
273+
await self._load_filters()
274+
275+
# -- Load objective information --
276+
if self._objectives is None:
277+
await self._load_objectives()
267278

268279
@property
269280
def version(self) -> str:

0 commit comments

Comments
 (0)