添加了imu等设备数据推送功能

This commit is contained in:
root 2025-08-06 09:52:45 +08:00
parent 2a6084eb04
commit b33e72f36e
3 changed files with 425 additions and 10 deletions

View File

@ -1034,6 +1034,82 @@ def handle_stop_video(data=None):
logger.error(f'停止视频流失败: {e}')
emit('video_status', {'status': 'error', 'message': f'停止失败: {str(e)}'})
@socketio.on('start_imu_streaming')
def handle_start_imu_streaming(data=None):
"""启动IMU头部姿态数据推流"""
try:
if device_manager:
result = device_manager.start_imu_streaming()
if result:
emit('imu_status', {'status': 'success', 'message': 'IMU头部姿态数据推流已启动'})
logger.info('IMU头部姿态数据推流已启动')
else:
emit('imu_status', {'status': 'error', 'message': 'IMU头部姿态数据推流启动失败'})
logger.error('IMU头部姿态数据推流启动失败')
else:
emit('imu_status', {'status': 'error', 'message': '设备管理器未初始化'})
logger.error('设备管理器未初始化')
except Exception as e:
logger.error(f'启动IMU数据推流失败: {e}')
emit('imu_status', {'status': 'error', 'message': f'启动失败: {str(e)}'})
@socketio.on('stop_imu_streaming')
def handle_stop_imu_streaming(data=None):
"""停止IMU头部姿态数据推流"""
try:
if device_manager:
result = device_manager.stop_imu_streaming()
if result:
emit('imu_status', {'status': 'success', 'message': 'IMU头部姿态数据推流已停止'})
logger.info('IMU头部姿态数据推流已停止')
else:
emit('imu_status', {'status': 'error', 'message': 'IMU头部姿态数据推流停止失败'})
logger.error('IMU头部姿态数据推流停止失败')
else:
emit('imu_status', {'status': 'error', 'message': '设备管理器未初始化'})
logger.error('设备管理器未初始化')
except Exception as e:
logger.error(f'停止IMU数据推流失败: {e}')
emit('imu_status', {'status': 'error', 'message': f'停止失败: {str(e)}'})
@socketio.on('start_pressure_streaming')
def handle_start_pressure_streaming(data=None):
"""启动压力传感器足部压力数据推流"""
try:
if device_manager:
result = device_manager.start_pressure_streaming()
if result:
emit('pressure_status', {'status': 'success', 'message': '压力传感器足部压力数据推流已启动'})
logger.info('压力传感器足部压力数据推流已启动')
else:
emit('pressure_status', {'status': 'error', 'message': '压力传感器足部压力数据推流启动失败'})
logger.error('压力传感器足部压力数据推流启动失败')
else:
emit('pressure_status', {'status': 'error', 'message': '设备管理器未初始化'})
logger.error('设备管理器未初始化')
except Exception as e:
logger.error(f'启动压力传感器数据推流失败: {e}')
emit('pressure_status', {'status': 'error', 'message': f'启动失败: {str(e)}'})
@socketio.on('stop_pressure_streaming')
def handle_stop_pressure_streaming(data=None):
"""停止压力传感器足部压力数据推流"""
try:
if device_manager:
result = device_manager.stop_pressure_streaming()
if result:
emit('pressure_status', {'status': 'success', 'message': '压力传感器足部压力数据推流已停止'})
logger.info('压力传感器足部压力数据推流已停止')
else:
emit('pressure_status', {'status': 'error', 'message': '压力传感器足部压力数据推流停止失败'})
logger.error('压力传感器足部压力数据推流停止失败')
else:
emit('pressure_status', {'status': 'error', 'message': '设备管理器未初始化'})
logger.error('设备管理器未初始化')
except Exception as e:
logger.error(f'停止压力传感器数据推流失败: {e}')
emit('pressure_status', {'status': 'error', 'message': f'停止失败: {str(e)}'})
# 重复的事件处理器已删除,使用前面定义的版本
if __name__ == '__main__':

View File

@ -778,22 +778,106 @@ class DeviceManager:
logger.error(f'录制FemtoBolt帧失败: {e}')
def set_socketio(self, socketio):
"""设置WebSocket连接用于推流"""
"""设置WebSocket连接"""
self.socketio = socketio
def start_imu_streaming(self):
"""启动IMU头部姿态数据推流"""
try:
if self.imu_streaming:
logger.warning('IMU数据推流已在运行')
return True
if not self.imu_device:
logger.error('IMU设备未初始化')
return False
self.imu_streaming = True
self.imu_thread = threading.Thread(target=self._imu_streaming_thread, daemon=True)
self.imu_thread.start()
logger.info('IMU头部姿态数据推流已启动')
return True
except Exception as e:
logger.error(f'启动IMU数据推流失败: {e}')
self.imu_streaming = False
return False
def stop_imu_streaming(self):
"""停止IMU头部姿态数据推流"""
try:
if not self.imu_streaming:
logger.warning('IMU数据推流未运行')
return True
self.imu_streaming = False
if self.imu_thread and self.imu_thread.is_alive():
self.imu_thread.join(timeout=2)
logger.info('IMU头部姿态数据推流已停止')
return True
except Exception as e:
logger.error(f'停止IMU数据推流失败: {e}')
return False
def start_pressure_streaming(self):
"""启动压力传感器足部压力数据推流"""
try:
if self.pressure_streaming:
logger.warning('压力传感器数据推流已在运行')
return True
if not self.pressure_device:
logger.error('压力传感器设备未初始化')
return False
self.pressure_streaming = True
self.pressure_thread = threading.Thread(target=self._pressure_streaming_thread, daemon=True)
self.pressure_thread.start()
logger.info('压力传感器足部压力数据推流已启动')
return True
except Exception as e:
logger.error(f'启动压力传感器数据推流失败: {e}')
self.pressure_streaming = False
return False
def stop_pressure_streaming(self):
"""停止压力传感器足部压力数据推流"""
try:
if not self.pressure_streaming:
logger.warning('压力传感器数据推流未运行')
return True
self.pressure_streaming = False
if self.pressure_thread and self.pressure_thread.is_alive():
self.pressure_thread.join(timeout=2)
logger.info('压力传感器足部压力数据推流已停止')
return True
except Exception as e:
logger.error(f'停止压力传感器数据推流失败: {e}')
return False
def start_streaming(self) -> Dict[str, bool]:
"""启动视频推流
"""启动所有设备推流
Returns:
Dict: 推流启动状态
{
'camera_streaming': bool,
'femtobolt_streaming': bool
'femtobolt_streaming': bool,
'imu_streaming': bool,
'pressure_streaming': bool
}
"""
result = {
'camera_streaming': False,
'femtobolt_streaming': False
'femtobolt_streaming': False,
'imu_streaming': False,
'pressure_streaming': False
}
try:
@ -824,13 +908,23 @@ class DeviceManager:
result['femtobolt_streaming'] = True
logger.debug('FemtoBolt深度相机推流已启动')
# 启动IMU头部姿态数据推流
if self.device_status['imu'] and not self.imu_streaming:
result['imu_streaming'] = self.start_imu_streaming()
logger.debug('IMU头部姿态数据推流已启动')
# 启动压力传感器足部压力数据推流
if self.device_status['pressure'] and not self.pressure_streaming:
result['pressure_streaming'] = self.start_pressure_streaming()
logger.debug('压力传感器足部压力数据推流已启动')
except Exception as e:
logger.warning(f'启动推流失败: {e}')
return result
def stop_streaming(self) -> bool:
"""停止所有视频推流
"""停止所有设备推流
Returns:
bool: 停止操作是否成功
@ -853,6 +947,16 @@ class DeviceManager:
self.femtobolt_streaming_thread.join(timeout=2)
logger.debug('FemtoBolt深度相机推流已停止')
# 停止IMU头部姿态数据推流
if self.imu_streaming:
self.stop_imu_streaming()
logger.debug('IMU头部姿态数据推流已停止')
# 停止压力传感器足部压力数据推流
if self.pressure_streaming:
self.stop_pressure_streaming()
logger.debug('压力传感器足部压力数据推流已停止')
return True
except Exception as e:
@ -1008,6 +1112,110 @@ class DeviceManager:
logger.debug(f'FemtoBolt推流线程异常: {e}')
finally:
self.femtobolt_streaming = False
def _imu_streaming_thread(self):
"""IMU头部姿态数据推流线程"""
logger.info('IMU头部姿态数据推流线程已启动')
try:
while self.imu_streaming and self.socketio:
try:
# 从IMU设备读取数据
imu_data = self.imu_device.read_data()
if imu_data:
# 计算头部姿态角度(欧拉角)
# 这里使用简化的计算方法,实际应用中可能需要更复杂的姿态解算
accel = imu_data['accel']
gyro = imu_data['gyro']
# 计算俯仰角和横滚角(基于加速度计)
import math
pitch = math.atan2(accel['x'], math.sqrt(accel['y']**2 + accel['z']**2)) * 180 / math.pi
roll = math.atan2(accel['y'], math.sqrt(accel['x']**2 + accel['z']**2)) * 180 / math.pi
# 偏航角需要磁力计数据,这里使用陀螺仪积分(简化处理)
yaw = gyro['z'] * 0.1 # 简化的偏航角计算
# 构建头部姿态数据
head_pose_data = {
'roll': roll,
'pitch': pitch,
'yaw': yaw,
'acceleration': accel,
'gyroscope': gyro,
'temperature': imu_data.get('temperature', 25),
'timestamp': imu_data['timestamp']
}
# 通过WebSocket发送头部姿态数据
self.socketio.emit('imu_data', {
'head_pose': head_pose_data,
'timestamp': datetime.now().isoformat()
})
# 控制数据发送频率10Hz
time.sleep(0.1)
except Exception as e:
logger.error(f'IMU数据推流异常: {e}')
time.sleep(0.1)
except Exception as e:
logger.error(f'IMU推流线程异常: {e}')
finally:
logger.info('IMU头部姿态数据推流线程已结束')
def _pressure_streaming_thread(self):
"""压力传感器足部压力数据推流线程"""
logger.info('压力传感器足部压力数据推流线程已启动')
try:
while self.pressure_streaming and self.socketio:
try:
# 从压力传感器设备读取数据
pressure_data = self.pressure_device.read_data()
if pressure_data:
# 计算平衡相关指标
left_pressure = pressure_data['left_foot']
right_pressure = pressure_data['right_foot']
total_pressure = left_pressure + right_pressure
# 计算平衡比例(左脚压力占总压力的比例)
balance_ratio = left_pressure / total_pressure if total_pressure > 0 else 0.5
# 计算压力中心偏移
pressure_center_offset = (balance_ratio - 0.5) * 100 # 转换为百分比
# 构建足部压力数据
foot_pressure_data = {
'left_foot_pressure': left_pressure,
'right_foot_pressure': right_pressure,
'total_pressure': total_pressure,
'balance_ratio': balance_ratio,
'pressure_center_offset': pressure_center_offset,
'balance_status': 'balanced' if abs(pressure_center_offset) < 10 else 'unbalanced',
'timestamp': pressure_data['timestamp']
}
# 通过WebSocket发送足部压力数据
self.socketio.emit('pressure_data', {
'foot_pressure': foot_pressure_data,
'timestamp': datetime.now().isoformat()
})
# 控制数据发送频率20Hz
time.sleep(0.05)
except Exception as e:
logger.error(f'压力传感器数据推流异常: {e}')
time.sleep(0.1)
except Exception as e:
logger.error(f'压力传感器推流线程异常: {e}')
finally:
logger.info('压力传感器足部压力数据推流线程已结束')
def start_recording(self, session_id: str, patient_id: str) -> Dict[str, Any]:
"""启动同步录制

View File

@ -542,6 +542,38 @@ function connectWebSocket() {
console.error('❌ Socket错误:', error)
})
// IMU
socket.on('imu_status', (data) => {
console.log('📡 IMU状态:', data)
if (data.status === 'success') {
ElMessage.success(data.message)
} else {
ElMessage.error(data.message)
}
})
// IMU姿
socket.on('imu_data', (data) => {
console.log('🎯 IMU头部姿态数据:', data)
handleIMUData(data)
})
//
socket.on('pressure_status', (data) => {
console.log('📡 压力传感器状态:', data)
if (data.status === 'success') {
ElMessage.success(data.message)
} else {
ElMessage.error(data.message)
}
})
//
socket.on('pressure_data', (data) => {
console.log('👣 压力传感器足部压力数据:', data)
handlePressureData(data)
})
} catch (error) {
console.error('💥 连接异常:', error.message)
isConnected.value = false
@ -602,11 +634,6 @@ function stopRtsp() {
}
}
//
function displayFrame(base64Image) {
if (base64Image && base64Image.length > 0) {
@ -631,6 +658,110 @@ function hideVideo() {
depthCameraImgSrc.value = ''
}
// IMU姿
function handleIMUData(data) {
try {
if (data && data.euler_angles) {
// 姿
console.log('🎯 更新IMU头部姿态数据:', data.euler_angles)
//
//
//
// updateHeadPoseChart(data.euler_angles)
}
} catch (error) {
console.error('❌ 处理IMU数据失败:', error)
}
}
//
function handlePressureData(data) {
try {
if (data && data.pressure_data) {
//
console.log('👣 更新压力传感器数据:', data.pressure_data)
//
//
//
// updatePressureChart(data.pressure_data)
}
} catch (error) {
console.error('❌ 处理压力传感器数据失败:', error)
}
}
// IMU姿
function startIMUStreaming() {
if (socket && socket.connected) {
console.log('🚀 发送start_imu_streaming事件')
socket.emit('start_imu_streaming', {}, (ack) => {
if (ack) {
console.log('✅ start_imu_streaming事件已确认:', ack)
} else {
console.log('⚠️ start_imu_streaming事件无确认响应')
}
})
} else {
console.error('❌ WebSocket未连接无法启动IMU数据推流')
ElMessage.error('WebSocket未连接无法启动IMU数据推流')
}
}
// IMU姿
function stopIMUStreaming() {
if (socket && socket.connected) {
console.log('🛑 发送stop_imu_streaming事件')
socket.emit('stop_imu_streaming', {}, (ack) => {
if (ack) {
console.log('✅ stop_imu_streaming事件已确认:', ack)
} else {
console.log('⚠️ stop_imu_streaming事件无确认响应')
}
})
} else {
console.error('❌ WebSocket未连接无法停止IMU数据推流')
ElMessage.error('WebSocket未连接无法停止IMU数据推流')
}
}
//
function startPressureStreaming() {
if (socket && socket.connected) {
console.log('🚀 发送start_pressure_streaming事件')
socket.emit('start_pressure_streaming', {}, (ack) => {
if (ack) {
console.log('✅ start_pressure_streaming事件已确认:', ack)
} else {
console.log('⚠️ start_pressure_streaming事件无确认响应')
}
})
} else {
console.error('❌ WebSocket未连接无法启动压力传感器数据推流')
ElMessage.error('WebSocket未连接无法启动压力传感器数据推流')
}
}
//
function stopPressureStreaming() {
if (socket && socket.connected) {
console.log('🛑 发送stop_pressure_streaming事件')
socket.emit('stop_pressure_streaming', {}, (ack) => {
if (ack) {
console.log('✅ stop_pressure_streaming事件已确认:', ack)
} else {
console.log('⚠️ stop_pressure_streaming事件无确认响应')
}
})
} else {
console.error('❌ WebSocket未连接无法停止压力传感器数据推流')
ElMessage.error('WebSocket未连接无法停止压力传感器数据推流')
}
}
// /
function handleStartStopRecording() {
if (!isConnected.value) {