Update Docker configuration, enhance error handling, and improve logging
- Added health check to the camera management API service in docker-compose.yml for better container reliability. - Updated installation scripts in Dockerfile to check for existing dependencies before installation, improving efficiency. - Enhanced error handling in the USDAVisionSystem class to allow partial operation if some components fail to start, preventing immediate shutdown. - Improved logging throughout the application, including more detailed error messages and critical error handling in the main loop. - Refactored WebSocketManager and CameraMonitor classes to use debug logging for connection events, reducing log noise.
This commit is contained in:
@@ -90,8 +90,20 @@ class CameraStreamer:
|
||||
"""Start streaming preview frames"""
|
||||
with self._lock:
|
||||
if self.streaming:
|
||||
self.logger.warning("Streaming already active")
|
||||
return True
|
||||
self.logger.warning("Streaming already active - checking if thread is alive")
|
||||
# Check if thread is actually running
|
||||
if self._streaming_thread and self._streaming_thread.is_alive():
|
||||
self.logger.info("Streaming thread is alive, returning success")
|
||||
return True
|
||||
else:
|
||||
# Thread died but flag wasn't reset - clean up and restart
|
||||
self.logger.warning("Streaming flag set but thread is dead - cleaning up and restarting")
|
||||
self.streaming = False
|
||||
if self.hCamera is not None:
|
||||
try:
|
||||
self._cleanup_camera()
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error cleaning up stale camera handle: {e}")
|
||||
|
||||
try:
|
||||
# Initialize camera for streaming
|
||||
@@ -249,6 +261,15 @@ class CameraStreamer:
|
||||
try:
|
||||
self.logger.info(f"Initializing camera for streaming: {self.camera_config.name}")
|
||||
|
||||
# Safety check: ensure no stale camera handle exists
|
||||
if self.hCamera is not None and not self._using_shared_camera:
|
||||
self.logger.warning("Stale camera handle detected during initialization - cleaning up first")
|
||||
try:
|
||||
mvsdk.CameraUnInit(self.hCamera)
|
||||
except Exception as e:
|
||||
self.logger.warning(f"Error cleaning up stale handle: {e}")
|
||||
self.hCamera = None
|
||||
|
||||
# Check if recorder is active and has camera open - if so, share it
|
||||
if self.recorder and self.recorder.hCamera and self.recorder.recording:
|
||||
self.logger.info("Recorder is active with camera open - will share recorder's camera connection")
|
||||
@@ -423,11 +444,41 @@ class CameraStreamer:
|
||||
time.sleep(STREAMING_LOOP_SLEEP) # Just wait, recorder populates queues
|
||||
continue
|
||||
|
||||
# Safety check: ensure camera handle is valid before use
|
||||
if self.hCamera is None:
|
||||
self.logger.error("Camera handle is None in streaming loop - stopping")
|
||||
break
|
||||
|
||||
# Capture frame with timeout
|
||||
pRawData, FrameHead = mvsdk.CameraGetImageBuffer(self.hCamera, CAMERA_GET_BUFFER_TIMEOUT)
|
||||
try:
|
||||
pRawData, FrameHead = mvsdk.CameraGetImageBuffer(self.hCamera, CAMERA_GET_BUFFER_TIMEOUT)
|
||||
except mvsdk.CameraException as e:
|
||||
if e.error_code == mvsdk.CAMERA_STATUS_TIME_OUT:
|
||||
continue # Timeout is normal, continue
|
||||
else:
|
||||
self.logger.error(f"CameraGetImageBuffer failed: {e.message} (error_code: {e.error_code})")
|
||||
# If camera is invalid, break to prevent segfault
|
||||
if e.error_code in [mvsdk.CAMERA_STATUS_INVALID_HANDLE, mvsdk.CAMERA_STATUS_INVALID_PARAM]:
|
||||
self.logger.error("Invalid camera handle detected - stopping streaming loop")
|
||||
break
|
||||
time.sleep(BRIEF_PAUSE_SLEEP)
|
||||
continue
|
||||
|
||||
# Process frame
|
||||
mvsdk.CameraImageProcess(self.hCamera, pRawData, self.frame_buffer, FrameHead)
|
||||
try:
|
||||
mvsdk.CameraImageProcess(self.hCamera, pRawData, self.frame_buffer, FrameHead)
|
||||
except mvsdk.CameraException as e:
|
||||
self.logger.error(f"CameraImageProcess failed: {e.message} (error_code: {e.error_code})")
|
||||
# Release buffer before continuing
|
||||
try:
|
||||
mvsdk.CameraReleaseImageBuffer(self.hCamera, pRawData)
|
||||
except:
|
||||
pass
|
||||
if e.error_code in [mvsdk.CAMERA_STATUS_INVALID_HANDLE, mvsdk.CAMERA_STATUS_INVALID_PARAM]:
|
||||
self.logger.error("Invalid camera handle in image process - stopping streaming loop")
|
||||
break
|
||||
time.sleep(BRIEF_PAUSE_SLEEP)
|
||||
continue
|
||||
|
||||
# Convert to OpenCV format
|
||||
frame = self._convert_frame_to_opencv(FrameHead)
|
||||
@@ -477,7 +528,14 @@ class CameraStreamer:
|
||||
pass
|
||||
|
||||
# Release buffer
|
||||
mvsdk.CameraReleaseImageBuffer(self.hCamera, pRawData)
|
||||
try:
|
||||
mvsdk.CameraReleaseImageBuffer(self.hCamera, pRawData)
|
||||
except mvsdk.CameraException as e:
|
||||
self.logger.error(f"CameraReleaseImageBuffer failed: {e.message} (error_code: {e.error_code})")
|
||||
# If handle is invalid, break to prevent further issues
|
||||
if e.error_code in [mvsdk.CAMERA_STATUS_INVALID_HANDLE, mvsdk.CAMERA_STATUS_INVALID_PARAM]:
|
||||
self.logger.error("Invalid camera handle when releasing buffer - stopping streaming loop")
|
||||
break
|
||||
|
||||
# Control frame rate
|
||||
time.sleep(1.0 / self.preview_fps)
|
||||
@@ -491,6 +549,15 @@ class CameraStreamer:
|
||||
self.logger.error(f"Fatal error in streaming loop: {e}")
|
||||
finally:
|
||||
self.logger.info("Streaming loop ended")
|
||||
# Reset streaming flag when loop ends
|
||||
with self._lock:
|
||||
self.streaming = False
|
||||
# Cleanup camera resources if not already done
|
||||
if self.hCamera is not None and not self._using_shared_camera:
|
||||
try:
|
||||
self._cleanup_camera()
|
||||
except Exception as cleanup_e:
|
||||
self.logger.error(f"Error during cleanup after loop ended: {cleanup_e}")
|
||||
|
||||
def _convert_frame_to_opencv(self, FrameHead) -> Optional[np.ndarray]:
|
||||
"""Convert camera frame to OpenCV format"""
|
||||
|
||||
Reference in New Issue
Block a user