修正了页面重复关闭硬件资源,的问题。
This commit is contained in:
parent
26b6bc3e0a
commit
4ab2211cd8
591699
backend/Log/OrbbecSDK.log.1.txt
Normal file
591699
backend/Log/OrbbecSDK.log.1.txt
Normal file
File diff suppressed because it is too large
Load Diff
@ -204,7 +204,6 @@ class BaseDevice(ABC):
|
||||
if old_status != is_connected:
|
||||
self._notify_status_change(is_connected)
|
||||
|
||||
|
||||
def emit_data(self, event: str, data: Any, namespace: Optional[str] = None):
|
||||
"""
|
||||
发送数据到前端
|
||||
|
@ -900,30 +900,118 @@ class CameraManager(BaseDevice):
|
||||
try:
|
||||
if not self.cap:
|
||||
# 如果相机实例不存在,尝试重新创建
|
||||
self.logger.info("相机实例不存在,尝试重新创建-----------------")
|
||||
return self._attempt_device_reconnection()
|
||||
|
||||
if not self.cap.isOpened():
|
||||
# 相机未打开,尝试重连
|
||||
self.logger.info("相机未打开,尝试重新连接-----------------")
|
||||
return self._attempt_device_reconnection()
|
||||
|
||||
# 尝试读取一帧来验证连接
|
||||
# 多层次验证相机连接状态
|
||||
try:
|
||||
ret, frame = self.cap.read()
|
||||
if ret and frame is not None:
|
||||
# 立即释放帧内存
|
||||
del frame
|
||||
# 第一步:使用grab()方法快速清除所有缓存帧
|
||||
self.logger.debug("快速清除相机缓存帧...")
|
||||
try:
|
||||
# grab()方法只获取帧但不解码,速度更快
|
||||
# 连续grab多次以清空内部缓冲区
|
||||
for _ in range(15): # 增加清除次数,确保缓存完全清空
|
||||
if not self.cap.grab():
|
||||
break # 如果grab失败,说明没有更多缓存帧
|
||||
except Exception as e:
|
||||
self.logger.debug(f"清除缓存帧时出现异常: {e}")
|
||||
|
||||
# 第二步:严格的连续帧检测
|
||||
failed_count = 0
|
||||
total_frames = 15 # 增加检测帧数
|
||||
consecutive_failures = 0 # 连续失败计数
|
||||
|
||||
for i in range(total_frames):
|
||||
try:
|
||||
ret, frame = self.cap.read()
|
||||
if ret and frame is not None:
|
||||
# 验证帧数据的有效性
|
||||
if self._validate_frame_data(frame):
|
||||
del frame
|
||||
consecutive_failures = 0 # 重置连续失败计数
|
||||
else:
|
||||
failed_count += 1
|
||||
consecutive_failures += 1
|
||||
del frame
|
||||
else:
|
||||
failed_count += 1
|
||||
consecutive_failures += 1
|
||||
|
||||
# 如果连续3帧失败,立即判定为断开
|
||||
if consecutive_failures >= 3:
|
||||
self.logger.warning(f"相机连接检测失败:连续{consecutive_failures}帧失败")
|
||||
return False
|
||||
|
||||
# 如果总失败帧数超过30%,判定为断开
|
||||
if failed_count > total_frames * 0.3:
|
||||
self.logger.warning(f"相机连接检测失败:{failed_count}/{i+1}帧读取失败,超过30%阈值")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
failed_count += 1
|
||||
consecutive_failures += 1
|
||||
self.logger.debug(f"读取第{i+1}帧时异常: {e}")
|
||||
|
||||
# 连续异常也判定为断开
|
||||
if consecutive_failures >= 3:
|
||||
self.logger.warning(f"相机连接检测异常:连续{consecutive_failures}帧异常")
|
||||
return False
|
||||
|
||||
# 短暂延时,避免过快读取
|
||||
time.sleep(0.005) # 减少延时提高检测速度
|
||||
|
||||
# 第三步:最终判断
|
||||
success_rate = (total_frames - failed_count) / total_frames
|
||||
if success_rate >= 0.7: # 成功率需要达到70%
|
||||
self.logger.info(f"相机连接检测成功:{total_frames-failed_count}/{total_frames}帧读取成功,成功率{success_rate:.1%}")
|
||||
return True
|
||||
else:
|
||||
# 读取失败,可能设备已断开
|
||||
return self._attempt_device_reconnection()
|
||||
except Exception:
|
||||
# 读取异常,尝试重连
|
||||
return self._attempt_device_reconnection()
|
||||
self.logger.warning(f"相机连接检测失败:成功率{success_rate:.1%}低于70%阈值")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
self.logger.warning(f"相机连接检测过程中发生异常: {e}")
|
||||
return False
|
||||
except Exception as e:
|
||||
self.logger.debug(f"检查相机硬件连接时发生异常: {e}")
|
||||
return False
|
||||
|
||||
def _validate_frame_data(self, frame) -> bool:
|
||||
"""
|
||||
验证帧数据的有效性
|
||||
|
||||
Args:
|
||||
frame: 要验证的帧数据
|
||||
|
||||
Returns:
|
||||
bool: 帧数据是否有效
|
||||
"""
|
||||
try:
|
||||
if frame is None:
|
||||
return False
|
||||
|
||||
# 检查帧尺寸
|
||||
if frame.shape[0] < 10 or frame.shape[1] < 10:
|
||||
return False
|
||||
|
||||
# 检查帧数据是否全为零(可能是无效帧)
|
||||
if np.all(frame == 0):
|
||||
return False
|
||||
|
||||
# 检查帧数据的方差(全黑或全白帧可能是无效的)
|
||||
if np.var(frame) < 1.0:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def _attempt_device_reconnection(self) -> bool:
|
||||
"""
|
||||
尝试重新连接相机设备
|
||||
@ -1011,65 +1099,6 @@ class CameraManager(BaseDevice):
|
||||
except Exception as e:
|
||||
self.logger.error(f"清理相机资源时发生错误: {e}")
|
||||
|
||||
def _save_frame_to_cache(self, frame, frame_type='camera'):
|
||||
"""保存帧到全局缓存"""
|
||||
try:
|
||||
with self.frame_cache_lock:
|
||||
current_time = time.time()
|
||||
|
||||
# 清理过期帧
|
||||
self._cleanup_expired_frames()
|
||||
|
||||
# 如果缓存已满,移除最旧的帧
|
||||
if frame_type in self.global_frame_cache and len(self.global_frame_cache[frame_type]) >= self.max_cache_size:
|
||||
oldest_key = min(self.global_frame_cache[frame_type].keys())
|
||||
del self.global_frame_cache[frame_type][oldest_key]
|
||||
|
||||
# 初始化帧类型缓存
|
||||
if frame_type not in self.global_frame_cache:
|
||||
self.global_frame_cache[frame_type] = {}
|
||||
|
||||
# 保存帧(深拷贝避免引用问题)
|
||||
frame_data = {
|
||||
'frame': frame.copy(),
|
||||
'timestamp': current_time,
|
||||
'frame_id': len(self.global_frame_cache[frame_type])
|
||||
}
|
||||
|
||||
self.global_frame_cache[frame_type][current_time] = frame_data
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'保存帧到缓存失败: {e}')
|
||||
|
||||
def _get_latest_frame_from_cache(self, frame_type='camera'):
|
||||
"""从队列获取最新帧"""
|
||||
try:
|
||||
if self.frame_queue.empty():
|
||||
self.logger.debug('帧队列为空')
|
||||
return None, None
|
||||
|
||||
# 获取队列中的所有帧,保留最新的一个
|
||||
frames = []
|
||||
while not self.frame_queue.empty():
|
||||
try:
|
||||
frames.append(self.frame_queue.get_nowait())
|
||||
except queue.Empty:
|
||||
break
|
||||
|
||||
if not frames:
|
||||
return None, None
|
||||
|
||||
# 获取最新帧(最后一个)
|
||||
latest_frame = frames[-1]
|
||||
|
||||
# 将最新帧重新放回队列
|
||||
try:
|
||||
self.frame_queue.put_nowait(latest_frame)
|
||||
except queue.Full:
|
||||
pass # 队列满时忽略
|
||||
|
||||
return latest_frame['frame'].copy(), latest_frame['timestamp']
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f'从队列获取帧失败: {e}')
|
||||
return None, None
|
||||
|
@ -141,6 +141,11 @@ class DeviceCoordinator:
|
||||
# 并行初始化设备
|
||||
futures = []
|
||||
|
||||
# FemtoBolt深度相机
|
||||
if self.device_configs.get('femtobolt', {}).get('enabled', False):
|
||||
future = self.executor.submit(self._init_femtobolt)
|
||||
futures.append(('femtobolt', future))
|
||||
|
||||
# 普通相机
|
||||
if self.device_configs.get('camera', {}).get('enabled', False):
|
||||
future = self.executor.submit(self._init_camera)
|
||||
@ -156,10 +161,7 @@ class DeviceCoordinator:
|
||||
future = self.executor.submit(self._init_pressure)
|
||||
futures.append(('pressure', future))
|
||||
|
||||
# FemtoBolt深度相机
|
||||
if self.device_configs.get('femtobolt', {}).get('enabled', False):
|
||||
future = self.executor.submit(self._init_femtobolt)
|
||||
futures.append(('femtobolt', future))
|
||||
|
||||
|
||||
# 等待所有设备初始化完成
|
||||
success_count = 0
|
||||
@ -422,6 +424,10 @@ class DeviceCoordinator:
|
||||
success_count = 0
|
||||
for device_name, device in self.devices.items():
|
||||
try:
|
||||
# 对深度相机(femtobolt)和普通相机(camera)直接调用初始化和启动推流
|
||||
if device_name in ['femtobolt', 'camera']:
|
||||
continue
|
||||
|
||||
if hasattr(device, '_start_connection_monitor'):
|
||||
device._start_connection_monitor()
|
||||
success_count += 1
|
||||
@ -429,7 +435,7 @@ class DeviceCoordinator:
|
||||
else:
|
||||
self.logger.warning(f"{device_name}设备不支持连接监控")
|
||||
except Exception as e:
|
||||
self.logger.error(f"启动{device_name}设备连接监控失败: {e}")
|
||||
self.logger.error(f"启动{device_name}设备失败: {e}")
|
||||
|
||||
self.logger.info(f"设备连接监控启动完成,成功: {success_count}/{len(self.devices)}")
|
||||
return success_count > 0
|
||||
@ -452,6 +458,21 @@ class DeviceCoordinator:
|
||||
success_count = 0
|
||||
for device_name, device in self.devices.items():
|
||||
try:
|
||||
# 对深度相机(femtobolt)和普通相机(camera)直接调用停止推流
|
||||
if device_name in ['femtobolt', 'camera']:
|
||||
self.logger.info(f"停止{device_name}设备推流")
|
||||
|
||||
# # 调用设备的cleanup方法清理资源,停止推流
|
||||
# if hasattr(device, 'cleanup'):
|
||||
# if device.cleanup():
|
||||
# success_count += 1
|
||||
# self.logger.info(f"{device_name}设备推流已停止")
|
||||
# else:
|
||||
# self.logger.warning(f"{device_name}设备推流停止失败")
|
||||
# else:
|
||||
# self.logger.warning(f"{device_name}设备不支持推流停止")
|
||||
continue
|
||||
|
||||
if hasattr(device, '_stop_connection_monitor'):
|
||||
device._stop_connection_monitor()
|
||||
success_count += 1
|
||||
@ -459,7 +480,7 @@ class DeviceCoordinator:
|
||||
else:
|
||||
self.logger.warning(f"{device_name}设备不支持连接监控")
|
||||
except Exception as e:
|
||||
self.logger.error(f"停止{device_name}设备连接监控失败: {e}")
|
||||
self.logger.error(f"停止{device_name}设备失败: {e}")
|
||||
|
||||
self.logger.info(f"设备连接监控停止完成,成功: {success_count}/{len(self.devices)}")
|
||||
return True
|
||||
|
@ -589,10 +589,6 @@ class FemtoBoltManager(BaseDevice):
|
||||
self.logger.warning("FemtoBolt流已在运行")
|
||||
return True
|
||||
|
||||
if not self.is_connected:
|
||||
if not self.initialize():
|
||||
return False
|
||||
|
||||
try:
|
||||
self.is_streaming = True
|
||||
self.streaming_thread = threading.Thread(
|
||||
@ -620,8 +616,14 @@ class FemtoBoltManager(BaseDevice):
|
||||
try:
|
||||
self.is_streaming = False
|
||||
|
||||
# 等待流线程自然结束
|
||||
if self.streaming_thread and self.streaming_thread.is_alive():
|
||||
self.streaming_thread.join(timeout=5.0)
|
||||
self.logger.info("等待FemtoBolt流线程结束...")
|
||||
self.streaming_thread.join(timeout=3.0)
|
||||
if self.streaming_thread.is_alive():
|
||||
self.logger.warning("FemtoBolt流线程未能在超时时间内结束")
|
||||
else:
|
||||
self.logger.info("FemtoBolt流工作线程结束")
|
||||
|
||||
self.logger.info("FemtoBolt流已停止")
|
||||
return True
|
||||
@ -791,11 +793,26 @@ class FemtoBoltManager(BaseDevice):
|
||||
"""
|
||||
try:
|
||||
if self.device_handle:
|
||||
# 先停止Pipeline以释放设备资源
|
||||
if hasattr(self, 'pipeline') and self.pipeline:
|
||||
try:
|
||||
self.logger.info("正在停止FemtoBolt Pipeline...")
|
||||
self.pipeline.stop()
|
||||
self.logger.info("FemtoBolt Pipeline已停止")
|
||||
# 等待Pipeline完全释放资源
|
||||
time.sleep(0.5)
|
||||
except Exception as e:
|
||||
self.logger.warning(f"停止Pipeline时出现警告: {e}")
|
||||
finally:
|
||||
self.pipeline = None
|
||||
|
||||
# 尝试停止设备(如果有stop方法)
|
||||
if hasattr(self.device_handle, 'stop'):
|
||||
try:
|
||||
self.device_handle.stop()
|
||||
self.logger.info("FemtoBolt设备已停止")
|
||||
# 等待设备完全停止
|
||||
time.sleep(0.3)
|
||||
except Exception as e:
|
||||
self.logger.warning(f"停止FemtoBolt设备时出现警告: {e}")
|
||||
|
||||
@ -804,6 +821,8 @@ class FemtoBoltManager(BaseDevice):
|
||||
try:
|
||||
self.device_handle.close()
|
||||
self.logger.info("FemtoBolt设备连接已关闭")
|
||||
# 等待设备连接完全关闭
|
||||
time.sleep(0.2)
|
||||
except Exception as e:
|
||||
self.logger.warning(f"关闭FemtoBolt设备时出现警告: {e}")
|
||||
|
||||
@ -811,6 +830,10 @@ class FemtoBoltManager(BaseDevice):
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"清理FemtoBolt设备失败: {e}")
|
||||
finally:
|
||||
# 确保所有相关属性都被重置
|
||||
self.pipeline = None
|
||||
self.device_handle = None
|
||||
|
||||
def disconnect(self):
|
||||
"""
|
||||
@ -870,31 +893,16 @@ class FemtoBoltManager(BaseDevice):
|
||||
self.logger.error(f"重新加载FemtoBolt配置失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def check_hardware_connection(self) -> bool:
|
||||
"""
|
||||
检查FemtoBolt设备硬件连接状态
|
||||
|
||||
相机连接检测太复杂,忽略连接检测
|
||||
Returns:
|
||||
bool: 设备是否物理连接
|
||||
bool: 相机是否连接
|
||||
"""
|
||||
try:
|
||||
if not self.sdk_initialized or not self.device_handle:
|
||||
return False
|
||||
return self.is_connected
|
||||
|
||||
|
||||
# 尝试获取设备状态来验证连接
|
||||
if hasattr(self.femtobolt, 'device_get_capture'):
|
||||
try:
|
||||
# 尝试获取一帧数据来验证设备连接
|
||||
capture = self.femtobolt.device_get_capture(self.device_handle, timeout_in_ms=1000)
|
||||
if capture:
|
||||
self.femtobolt.capture_release(capture)
|
||||
return True
|
||||
except Exception:
|
||||
pass
|
||||
return False
|
||||
except Exception as e:
|
||||
self.logger.debug(f"检查FemtoBolt硬件连接时发生异常: {e}")
|
||||
return False
|
||||
|
||||
def cleanup(self):
|
||||
"""
|
||||
@ -902,7 +910,7 @@ class FemtoBoltManager(BaseDevice):
|
||||
"""
|
||||
try:
|
||||
# 清理监控线程
|
||||
self._cleanup_monitoring()
|
||||
# self._cleanup_monitoring()
|
||||
|
||||
self.stop_streaming()
|
||||
self._cleanup_device()
|
||||
|
@ -62,6 +62,10 @@ class FPMS_DEVICE_INFO(ctypes.Structure):
|
||||
class RealPressureDevice:
|
||||
"""真实SMiTSense压力传感器设备"""
|
||||
|
||||
# 类级别的USB初始化状态跟踪
|
||||
_usb_initialized = False
|
||||
_usb_init_lock = threading.Lock()
|
||||
|
||||
def __init__(self, dll_path=None):
|
||||
"""
|
||||
初始化SMiTSense压力传感器
|
||||
@ -139,9 +143,16 @@ class RealPressureDevice:
|
||||
def _initialize_device(self):
|
||||
"""初始化设备连接"""
|
||||
try:
|
||||
# 初始化USB连接
|
||||
if self.dll.fpms_usb_init_wrap(0) != 0:
|
||||
raise RuntimeError("初始化失败")
|
||||
# 使用类级别锁确保USB子系统只初始化一次
|
||||
with RealPressureDevice._usb_init_lock:
|
||||
if not RealPressureDevice._usb_initialized:
|
||||
# 初始化USB连接
|
||||
if self.dll.fpms_usb_init_wrap(0) != 0:
|
||||
raise RuntimeError("USB子系统初始化失败")
|
||||
RealPressureDevice._usb_initialized = True
|
||||
logger.info("USB子系统初始化成功")
|
||||
else:
|
||||
logger.info("USB子系统已初始化,跳过重复初始化")
|
||||
|
||||
# 获取设备列表
|
||||
count = ctypes.c_int()
|
||||
@ -433,12 +444,21 @@ class RealPressureDevice:
|
||||
try:
|
||||
if self.is_connected and self.dll and self.device_handle:
|
||||
self.dll.fpms_usb_close_wrap(self.device_handle.value)
|
||||
# 重置设备句柄
|
||||
self.device_handle = None
|
||||
# 设置连接状态为断开
|
||||
self.is_connected = False
|
||||
logger.info('SMiTSense压力传感器连接已关闭')
|
||||
except Exception as e:
|
||||
logger.error(f'关闭压力传感器连接异常: {e}')
|
||||
|
||||
@classmethod
|
||||
def reset_usb_state(cls):
|
||||
"""重置USB初始化状态(用于设备完全断开后的重新初始化)"""
|
||||
with cls._usb_init_lock:
|
||||
cls._usb_initialized = False
|
||||
logger.info("USB子系统状态已重置")
|
||||
|
||||
def __del__(self):
|
||||
"""析构函数,确保资源清理"""
|
||||
self.close()
|
||||
@ -522,7 +542,8 @@ class PressureManager(BaseDevice):
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"压力板初始化失败: {e}")
|
||||
self.is_connected = False
|
||||
# 使用set_connected方法停止连接监控线程
|
||||
self.set_connected(False)
|
||||
self.device = None
|
||||
return False
|
||||
|
||||
@ -590,9 +611,6 @@ class PressureManager(BaseDevice):
|
||||
try:
|
||||
while self.is_streaming:
|
||||
try:
|
||||
|
||||
# 读数成功,重置失败计数
|
||||
self.is_connected = True
|
||||
# 从设备读取数据
|
||||
pressure_data = None
|
||||
if self.device:
|
||||
@ -603,6 +621,10 @@ class PressureManager(BaseDevice):
|
||||
time.sleep(self.reconnect_delay)
|
||||
continue
|
||||
|
||||
# 读数成功,立即更新心跳和连接状态
|
||||
self.is_connected = True
|
||||
self.update_heartbeat()
|
||||
|
||||
foot_pressure = pressure_data['foot_pressure']
|
||||
# 获取各区域压力值
|
||||
left_front = foot_pressure['left_front']
|
||||
@ -647,9 +669,6 @@ class PressureManager(BaseDevice):
|
||||
'timestamp': pressure_data['timestamp']
|
||||
}
|
||||
|
||||
# 更新心跳时间,防止连接监控线程判定为超时
|
||||
self.update_heartbeat()
|
||||
|
||||
# 更新统计信息
|
||||
self.packet_count += 1
|
||||
self.last_data_time = time.time()
|
||||
@ -784,16 +803,16 @@ class PressureManager(BaseDevice):
|
||||
"""
|
||||
try:
|
||||
if not self.device:
|
||||
# 如果设备实例不存在,尝试重新创建
|
||||
# 如果设备实例不存在,返回False表示硬件未连接
|
||||
return self._attempt_device_reconnection()
|
||||
|
||||
# 对于真实设备,检查DLL和设备句柄状态
|
||||
if hasattr(self.device, 'dll') and hasattr(self.device, 'device_handle'):
|
||||
if not self.device.dll or not self.device.device_handle:
|
||||
# DLL或句柄无效,尝试重连
|
||||
# DLL或句柄无效,返回False表示硬件未连接
|
||||
return self._attempt_device_reconnection()
|
||||
|
||||
# 直接检查设备句柄的有效性,不依赖is_connected状态避免循环依赖
|
||||
# 直接检查设备句柄的有效性
|
||||
try:
|
||||
# 检查设备句柄是否有效
|
||||
if not self.device.device_handle or not hasattr(self.device.device_handle, 'value'):
|
||||
@ -803,12 +822,25 @@ class PressureManager(BaseDevice):
|
||||
if self.device.device_handle.value == 0:
|
||||
return self._attempt_device_reconnection()
|
||||
|
||||
# 尝试简单的设备状态检查,而不是完整的数据读取
|
||||
# 尝试实际的设备通信来验证硬件连接
|
||||
# 使用DLL函数检查设备列表,验证设备是否真实存在
|
||||
count = ctypes.c_int()
|
||||
devs = (FPMS_DEVICE_INFO * 10)()
|
||||
r = self.device.dll.fpms_usb_get_device_list_wrap(devs, 10, ctypes.byref(count))
|
||||
|
||||
# 如果获取设备列表失败或设备数量为0,说明硬件已断开
|
||||
if r != 0 or count.value == 0:
|
||||
self.logger.debug(f"设备列表检查失败: r={r}, count={count.value}")
|
||||
return self._attempt_device_reconnection()
|
||||
|
||||
# 设备列表正常,硬件连接正常
|
||||
return True
|
||||
except Exception:
|
||||
|
||||
except Exception as e:
|
||||
self.logger.debug(f"硬件连接检查异常: {e}")
|
||||
return self._attempt_device_reconnection()
|
||||
|
||||
# 对于模拟设备,总是返回True
|
||||
# 对于Mock设备,直接返回True
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
@ -834,19 +866,18 @@ class PressureManager(BaseDevice):
|
||||
|
||||
self.device = None
|
||||
|
||||
# 重置USB状态,为重新插入的设备做准备
|
||||
RealPressureDevice.reset_usb_state()
|
||||
|
||||
# 根据设备类型重新创建设备实例
|
||||
if self.device_type == 'real':
|
||||
self.device = RealPressureDevice()
|
||||
else:
|
||||
self.device = MockPressureDevice()
|
||||
self.device = RealPressureDevice()
|
||||
|
||||
# 检查新设备是否连接成功
|
||||
if hasattr(self.device, 'is_connected') and self.device.is_connected:
|
||||
self._notify_status_change(True)
|
||||
# 重连成功后,确保数据流正在运行
|
||||
if not self.is_streaming:
|
||||
self.logger.info("重连成功,启动压力数据流")
|
||||
self.start_streaming()
|
||||
self.logger.info("重连成功,启动压力数据流")
|
||||
self.start_streaming()
|
||||
|
||||
return True
|
||||
else:
|
||||
|
@ -296,6 +296,7 @@ class RecordingManager:
|
||||
|
||||
# 设置录制参数
|
||||
self.current_session_id = session_id
|
||||
# self.logger.info(f'检测sessionID................: {self.current_session_id}')
|
||||
self.current_patient_id = patient_id
|
||||
self.screen_region = tuple(screen_location) # [x, y, w, h] -> (x, y, w, h)
|
||||
self.camera_region = tuple(camera_location) # [x, y, w, h] -> (x, y, w, h)
|
||||
|
@ -16,7 +16,7 @@ max_backups = 7
|
||||
|
||||
[CAMERA]
|
||||
enabled = True
|
||||
device_index = 0
|
||||
device_index = 3
|
||||
width = 1280
|
||||
height = 720
|
||||
fps = 30
|
||||
@ -41,7 +41,6 @@ imu_device_type = ble
|
||||
imu_port = COM9
|
||||
imu_mac_address = ef:3c:1a:0a:fe:02
|
||||
imu_baudrate = 9600
|
||||
|
||||
pressure_enabled = True
|
||||
pressure_device_type = real
|
||||
pressure_use_mock = False
|
||||
|
Binary file not shown.
1
backend/dll/femtobolt/k4aviewer.err
Normal file
1
backend/dll/femtobolt/k4aviewer.err
Normal file
@ -0,0 +1 @@
|
||||
Glfw error [65544]: WGL: Failed to make context current
|
@ -1029,13 +1029,13 @@ class AppServer:
|
||||
except Exception as duration_error:
|
||||
self.logger.error(f'更新会话持续时间失败: {duration_error}')
|
||||
|
||||
# 停止设备连接监控
|
||||
if self.device_coordinator:
|
||||
try:
|
||||
self.device_coordinator.stop_all_connection_monitor()
|
||||
self.logger.info('检测停止,设备连接监控已停止')
|
||||
except Exception as monitor_error:
|
||||
self.logger.error(f'停止设备连接监控失败: {monitor_error}')
|
||||
# # 停止设备连接监控
|
||||
# if self.device_coordinator:
|
||||
# try:
|
||||
# self.device_coordinator.stop_all_connection_monitor()
|
||||
# self.logger.info('检测停止,设备连接监控已停止')
|
||||
# except Exception as monitor_error:
|
||||
# self.logger.error(f'停止设备连接监控失败: {monitor_error}')
|
||||
|
||||
success = self.db_manager.update_session_status(session_id, 'completed')
|
||||
if success:
|
||||
|
@ -522,31 +522,7 @@
|
||||
|
||||
</el-form-item>
|
||||
|
||||
<div class="cameraFormTitle">头部IMU</div>
|
||||
<el-form-item label="IMU串口号">
|
||||
<el-select v-model="cameraForm.imu.port" placeholder="请选择">
|
||||
<el-option label="COM1" value="COM1" />
|
||||
<el-option label="COM2" value="COM2" />
|
||||
<el-option label="COM3" value="COM3" />
|
||||
<el-option label="COM4" value="COM4" />
|
||||
<el-option label="COM5" value="COM5" />
|
||||
<el-option label="COM6" value="COM6" />
|
||||
<el-option label="COM7" value="COM7" />
|
||||
<el-option label="COM8" value="COM8" />
|
||||
<el-option label="COM9" value="COM9" />
|
||||
<el-option label="COM10" value="COM10" />
|
||||
<el-option label="COM11" value="COM11" />
|
||||
<el-option label="COM12" value="COM12" />
|
||||
<el-option label="COM13" value="COM13" />
|
||||
<el-option label="COM14" value="COM14" />
|
||||
<el-option label="COM15" value="COM15" />
|
||||
<el-option label="COM16" value="COM16" />
|
||||
<el-option label="COM17" value="COM17" />
|
||||
<el-option label="COM18" value="COM18" />
|
||||
<el-option label="COM19" value="COM19" />
|
||||
<el-option label="COM20" value="COM20" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
</el-form>
|
||||
</div>
|
||||
|
||||
@ -786,6 +762,7 @@ const isRunning = ref(false);
|
||||
const timerId = ref(null);
|
||||
const blinkState = ref(false);
|
||||
const formattedTime = computed(() => {
|
||||
|
||||
const mins = Math.floor(seconds.value / 60);
|
||||
const secs = seconds.value % 60;
|
||||
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
|
||||
@ -812,7 +789,7 @@ const startTimer = () => {
|
||||
seconds.value = Math.round(elapsed / 1000);
|
||||
|
||||
// 检测时长超过10分钟(600秒)自动停止检测
|
||||
if (seconds.value >= 60) {
|
||||
if (seconds.value >= 600) {
|
||||
console.log('⏰ 检测时长超过10分钟,自动停止检测');
|
||||
ElMessage.warning('检测时长已达到10分钟,自动停止检测');
|
||||
stopRecord()
|
||||
@ -1004,8 +981,7 @@ function connectWebSocket() {
|
||||
socket.on('disconnect', (reason) => {
|
||||
console.log('⚠️ 主连接断开:', reason)
|
||||
isConnected.value = false
|
||||
stopDeviceDataPush()
|
||||
// 如果正在录像,停止录像
|
||||
|
||||
if (isRecording.value) {
|
||||
stopRecording()
|
||||
isStart.value = false
|
||||
@ -1139,24 +1115,11 @@ function startDeviceDataPush() {
|
||||
}
|
||||
}
|
||||
|
||||
// 停止设备数据推送
|
||||
function stopDeviceDataPush() {
|
||||
if (devicesSocket && devicesSocket.connected) {
|
||||
console.log('🛑 发送停止设备数据推送请求...')
|
||||
devicesSocket.emit('stop_push_data')
|
||||
} else {
|
||||
console.warn('⚠️ 设备Socket未连接,无法停止设备数据推送')
|
||||
}
|
||||
}
|
||||
|
||||
// 断开WebSocket连接函数
|
||||
function disconnectWebSocket() {
|
||||
if (socket && socket.connected) {
|
||||
console.log('正在主动断开WebSocket连接...')
|
||||
|
||||
// 停止设备数据推送
|
||||
stopDeviceDataPush()
|
||||
|
||||
// 断开主连接
|
||||
socket.disconnect()
|
||||
socket = null
|
||||
@ -1672,10 +1635,6 @@ async function startDetection() {
|
||||
try {
|
||||
console.log('🚀 正在开始检测...')
|
||||
|
||||
// 验证患者信息
|
||||
if (!patientInfo.value || !patientInfo.value.id) {
|
||||
throw new Error('缺少患者信息,无法开始检测')
|
||||
}
|
||||
// 调用后端API开始检测
|
||||
const response = await fetch(`${BACKEND_URL}/api/detection/start`, {
|
||||
method: 'POST',
|
||||
@ -1683,7 +1642,7 @@ async function startDetection() {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
patient_id: patientInfo.value.id,
|
||||
patient_id: route.params.id,
|
||||
// 可以添加其他检测参数
|
||||
creator_id: creatorId.value,
|
||||
})
|
||||
@ -1754,7 +1713,7 @@ const loadPatientInfo = async () => {
|
||||
const result = await response.json()
|
||||
if (result.success) {
|
||||
patientInfo.value = { ...result.data, sessionId: null }
|
||||
startDetection()
|
||||
|
||||
console.log('患者信息加载成功:', patientInfo.value)
|
||||
} else {
|
||||
throw new Error(result.message)
|
||||
@ -1778,7 +1737,7 @@ const handleBeforeUnload = (event) => {
|
||||
}
|
||||
|
||||
// 停止检测
|
||||
stopDetection()
|
||||
// stopDetection()
|
||||
// 断开WebSocket连接
|
||||
disconnectWebSocket()
|
||||
|
||||
@ -1929,17 +1888,22 @@ const getDevicesInit = async () => {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
if (authStore.currentUser) {
|
||||
console.log(authStore.currentUser)
|
||||
creatorId.value = authStore.currentUser.id
|
||||
}
|
||||
|
||||
// 加载患者信息
|
||||
loadPatientInfo()
|
||||
// 启动检测
|
||||
startDetection()
|
||||
// 页面加载时自动连接WebSocket
|
||||
connectWebSocket()
|
||||
|
||||
// 监听页面关闭或刷新事件
|
||||
window.addEventListener('beforeunload', handleBeforeUnload)
|
||||
if (authStore.currentUser) {
|
||||
console.log(authStore.currentUser)
|
||||
creatorId.value = authStore.currentUser.id
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
@ -1955,10 +1919,13 @@ onUnmounted(() => {
|
||||
stopRecord()
|
||||
}
|
||||
|
||||
stopDetection()
|
||||
// 页面关闭时断开WebSocket连接
|
||||
// stopDetection()
|
||||
// 页面关闭时断开WebSocket连接
|
||||
disconnectWebSocket()
|
||||
|
||||
|
||||
|
||||
|
||||
// 清理图表资源
|
||||
if (tiltCharts) {
|
||||
try {
|
||||
@ -1992,6 +1959,7 @@ onUnmounted(() => {
|
||||
const startRecord = async () => { // 开始录屏
|
||||
try {
|
||||
console.log('🚀 正在开始录屏...')
|
||||
startTimer()
|
||||
// 验证患者信息
|
||||
if (!patientInfo.value || !patientInfo.value.sessionId) {
|
||||
throw new Error('缺少患者信息,无法开始录屏')
|
||||
|
Loading…
Reference in New Issue
Block a user