feat: 新增急停信号

This commit is contained in:
zhu-mengmeng 2025-06-30 11:19:07 +08:00
parent 6d60e77743
commit 92905294aa
6 changed files with 288 additions and 39 deletions

View File

@ -49,8 +49,8 @@
"default_framerate": 30
},
"modbus": {
"host": "localhost",
"port": "5020"
"host": "192.168.2.88",
"port": "502"
},
"serial": {
"keyboard": {

Binary file not shown.

View File

@ -16,6 +16,6 @@ client.write_registers(address=3, values=[0])
# client.write_registers(address=13, values=[1])
result = client.read_holding_registers(address=3, count=1)
result = client.read_holding_registers(address=109, count=1)
print(result.registers[0],"123===")
client.close()

View File

@ -77,7 +77,7 @@ class ModbusMonitor(QObject):
def _initialize_registers(self):
"""初始化要监控的寄存器列表"""
# 默认监控的寄存器地址
register_addresses = [5, 6, 11, 13, 20, 21, 22, 23, 24, 30] # 添加寄存器30用于电力监控
register_addresses = [5, 6, 11, 13, 20, 21, 22, 23, 24, 25, 30]
for address in register_addresses:
self.registers[address] = RegisterValue(address)

View File

@ -243,4 +243,23 @@ class NGHandler(RegisterHandler):
#如果有回调函数,则调用
if self.callback:
self.callback(value)
self.callback(value)
class EmergencyStopHandler(RegisterHandler):
"""寄存器D25处理器处理急停信号"""
def __init__(self, callback=None):
super().__init__()
self.callback = callback
self.status_map = {
0: "正常",
1: "急停触发"
}
def handle_change(self, value):
status = self.status_map.get(value, f"未知状态({value})")
logging.info(f"急停信号: {status}")
# 如果有回调函数,则调用
if self.callback and value == 1:
self.callback(value, "监听到急停信号")

View File

@ -19,7 +19,8 @@ from utils.register_handlers import (
Error2Handler,
Error3Handler,
UnloadingLevelHandler,
UnloadingPositionHandler
UnloadingPositionHandler,
EmergencyStopHandler
)
from utils.electricity_monitor import ElectricityHandler
# 导入PySide6
@ -53,6 +54,7 @@ class MainWindow(MainWindowUI):
unloading_feedback_signal = Signal(str, str) # 参数status_type, desc
unloading_level_ui_signal = Signal(int) # 用于在主线程中更新下料层数UI
unloading_position_ui_signal = Signal(int) # 用于在主线程中更新下料位置UI
emergency_stop_signal = Signal(int, str) # 用于在主线程中处理急停信号
def __init__(self, user_id=None, user_name=None, corp_name=None, corp_id=None):
"""初始化主窗口"""
@ -75,12 +77,7 @@ class MainWindow(MainWindowUI):
self._loading_info = None # 存储上料对话框的信息
self._is_loading_active = False # 标识上料任务是否正在进行
# 连接信号到槽
self.loading_feedback_signal.connect(self._handle_loading_feedback_ui)
self.unloading_feedback_signal.connect(self._handle_unloading_feedback_ui)
# 连接新增的信号
self.unloading_level_ui_signal.connect(self.handle_unloading_level_ui)
self.unloading_position_ui_signal.connect(self.handle_unloading_position_ui)
# 信号的连接在connect_signals方法中统一处理不在这里连接
# 称重相关变量
self._current_weight = None # 当前称重值(千克)
@ -109,17 +106,12 @@ class MainWindow(MainWindowUI):
self.output_form_layout = QFormLayout()
self.output_content_layout.addLayout(self.output_form_layout)
# 只有在相机启用时创建相机显示组件
if self.camera_enabled:
# 创建相机显示组件并添加到上料区
self.camera_display = CameraDisplayWidget()
self.material_content_layout.addWidget(self.camera_display)
else:
# 在上料区添加占位标签
self.material_placeholder = QLabel("相机功能已禁用")
self.material_placeholder.setAlignment(Qt.AlignCenter)
self.material_placeholder.setStyleSheet("color: #888888; background-color: #f0f0f0;")
self.material_content_layout.addWidget(self.material_placeholder)
# 创建相机显示组件和占位标签
self.camera_display = None
self.material_placeholder = None
# 初始化上料区显示
self.init_camera_display()
# 为下料区添加占位标签,确保它保持为空
self.output_placeholder = QWidget()
@ -266,6 +258,19 @@ class MainWindow(MainWindowUI):
# 连接报表按钮点击事件
self.report_button.clicked.connect(self.on_report)
# 连接加载反馈信号
self.loading_feedback_signal.connect(self._handle_loading_feedback_ui)
# 连接下料反馈信号
self.unloading_feedback_signal.connect(self._handle_unloading_feedback_ui)
# 连接下料层数和位置UI更新信号
self.unloading_level_ui_signal.connect(self.handle_unloading_level_ui)
self.unloading_position_ui_signal.connect(self.handle_unloading_position_ui)
# 连接急停信号
self.emergency_stop_signal.connect(self._handle_emergency_stop_ui)
def update_inspection_columns(self):
"""更新检验列配置 - 使用检验配置管理器获取启用的列数和标题"""
@ -300,12 +305,25 @@ class MainWindow(MainWindowUI):
# 加载未完成的检验数据
self._safe_load_data()
# 只有在相机启用时处理相机显示
if self.camera_enabled and hasattr(self, 'camera_display'):
# 如果相机已连接,直接开始显示相机画面
if self.camera_display.camera_manager.isOpen:
if not self.camera_display.camera_manager.isGrabbing:
self.camera_display.start_display()
# 处理相机显示
if self.camera_enabled and self.camera_display:
from widgets.camera_manager import CameraManager
camera_manager = CameraManager.get_instance()
# 检查相机是否已打开
if camera_manager.isOpen:
# 更新UI显示相机画面
self.update_camera_ui(True)
# 如果相机未在采集,则开始采集
if not camera_manager.isGrabbing:
# 使用内部方法启动相机显示
QTimer.singleShot(100, self._start_camera_display)
logging.info("主页面显示:启动相机显示")
else:
# 如果相机未打开,尝试重新初始化
QTimer.singleShot(100, self.initialize_camera)
logging.info("主页面显示:尝试初始化相机")
# 加载托盘号列表
self.load_pallet_codes()
@ -660,8 +678,13 @@ class MainWindow(MainWindowUI):
"""处理相机状态变化"""
if is_connected:
logging.info("相机已连接并显示")
self.update_camera_ui(True)
else:
logging.warning(f"相机显示问题: {message}")
# 更新占位符文本
if self.material_placeholder:
self.material_placeholder.setText(f"相机错误: {message}" if message else "相机未连接")
self.update_camera_ui(False)
def handle_camera_connection(self, is_connected, message):
"""处理相机连接状态变化"""
@ -695,10 +718,20 @@ class MainWindow(MainWindowUI):
logging.info("停止Modbus监控")
self.modbus_monitor.stop()
# 只有在相机启用时处理相机关闭
if self.camera_enabled and hasattr(self, 'camera_display'):
# 处理相机关闭
if self.camera_enabled and self.camera_display:
# 停止相机显示
self.camera_display.stop_display()
# 关闭相机设备
try:
from widgets.camera_manager import CameraManager
camera_manager = CameraManager.get_instance()
if camera_manager.isOpen:
camera_manager.close_device()
logging.info("相机设备已关闭")
except Exception as e:
logging.error(f"关闭相机设备失败: {str(e)}")
# 停止串口监听
self.serial_manager.stop_keyboard_listener()
@ -1637,6 +1670,9 @@ class MainWindow(MainWindowUI):
monitor.register_handler(23, Error2Handler(self.machine_handlers.handle_error_2))
monitor.register_handler(24, Error3Handler(self.machine_handlers.handle_error_3))
# 注册急停信号处理器
monitor.register_handler(25, EmergencyStopHandler(self.handle_emergency_stop))
# 注册下料层数和位置处理器
monitor.register_handler(4, UnloadingLevelHandler(self.handle_unloading_level))
monitor.register_handler(5, UnloadingPositionHandler(self.handle_unloading_position))
@ -2188,8 +2224,7 @@ class MainWindow(MainWindowUI):
# 如果有故障,显示提示
if error_code in (2, 3):
QMessageBox.warning(self, "机器人视觉报警", f"机器人视觉报警: {detailed_desc}")
# error_1 属于上料故障
self.show_operation_status("异常", "", detailed_desc)
# 移除在下料区域显示异常信息的代码
@Slot(int, str)
@ -2204,9 +2239,8 @@ class MainWindow(MainWindowUI):
self._update_error_status()
# 如果有故障,显示提示
if error_code > 0:
# error_2 属于下料故障
self.show_operation_status("异常", "", detailed_desc)
# 移除在下料区域显示异常信息的代码
@Slot(int, str)
def handle_error_3(self, error_code, error_desc):
"""拆码垛报警"""
@ -2224,11 +2258,11 @@ class MainWindow(MainWindowUI):
QMessageBox.warning(self, "异常", f"异常: {detailed_desc}")
modbus.write_register_until_success(client, 2, 0)
modbus.close_client(client)
self.show_operation_status("异常", "", detailed_desc)
# 移除在下料区域显示异常信息的代码
elif error_code == 2:
QMessageBox.warning(self, "异常", f"异常: {detailed_desc}")
modbus.write_register_until_success(client, 3, 0)
modbus.close_client(client)
modbus.close_client(client)
@Slot(int)
def handle_unloading_level(self, level):
"""处理下料层数信息来自Modbus"""
@ -2661,4 +2695,200 @@ class MainWindow(MainWindowUI):
dialog.exec_()
except Exception as e:
logging.error(f"打开报表对话框失败: {str(e)}")
QMessageBox.warning(self, "错误", f"打开报表对话框失败: {str(e)}")
QMessageBox.warning(self, "错误", f"打开报表对话框失败: {str(e)}")
def init_camera_display(self):
"""初始化相机显示区域"""
try:
# 清理之前的组件(如果有)
if self.camera_display:
self.material_content_layout.removeWidget(self.camera_display)
self.camera_display.deleteLater()
self.camera_display = None
if self.material_placeholder:
self.material_content_layout.removeWidget(self.material_placeholder)
self.material_placeholder.deleteLater()
self.material_placeholder = None
# 清空布局中的所有项目
while self.material_content_layout.count():
item = self.material_content_layout.takeAt(0)
if item.widget():
item.widget().deleteLater()
# 创建占位标签
self.material_placeholder = QLabel("相机初始化中..." if self.camera_enabled else "相机功能已禁用")
self.material_placeholder.setAlignment(Qt.AlignCenter)
self.material_placeholder.setStyleSheet("color: #888888; background-color: #f0f0f0;")
self.material_content_layout.addWidget(self.material_placeholder)
# 创建相机显示组件
self.camera_display = CameraDisplayWidget()
self.camera_display.signal_camera_status.connect(self.handle_camera_status)
# 先隐藏相机组件,直到确认相机可用
self.material_content_layout.addWidget(self.camera_display)
self.camera_display.hide()
# 如果相机功能已启用,尝试初始化相机
if self.camera_enabled:
# 启动相机初始化过程
QTimer.singleShot(500, self.initialize_camera)
logging.info("相机初始化已安排")
else:
logging.info("相机功能已禁用,不进行初始化")
self.material_placeholder.show()
self.camera_display.hide()
except Exception as e:
logging.error(f"初始化相机显示区域失败: {str(e)}")
def initialize_camera(self):
"""初始化相机并显示画面"""
try:
if not self.camera_enabled:
return
logging.info("开始初始化相机...")
# 获取相机管理器实例
from widgets.camera_manager import CameraManager
camera_manager = CameraManager.get_instance()
# 枚举设备
devices = camera_manager.enum_devices()
if not devices or len(devices) == 0:
self.material_placeholder.setText("未检测到相机设备")
logging.warning("未检测到相机设备")
return
# 打开第一个相机设备
device_index = 0
success = camera_manager.open_device(device_index)
if success:
logging.info(f"相机已成功打开,设备索引: {device_index}")
# 更新UI
self.update_camera_ui(True)
# 立即开始显示相机画面
QTimer.singleShot(100, lambda: self._start_camera_display())
else:
self.material_placeholder.setText("相机打开失败")
logging.error("相机打开失败")
except Exception as e:
self.material_placeholder.setText("相机初始化错误")
logging.error(f"初始化相机失败: {str(e)}")
def _start_camera_display(self):
"""开始显示相机画面(内部方法)"""
try:
if self.camera_display and self.camera_enabled:
# 确保相机组件可见
self.camera_display.setVisible(True)
self.camera_display.raise_()
# 开始显示
success = self.camera_display.start_display()
if success:
# 确保占位符隐藏
if self.material_placeholder:
self.material_placeholder.setVisible(False)
logging.info("相机显示已成功启动")
else:
# 如果启动失败,显示占位符
if self.material_placeholder:
self.material_placeholder.setText("相机显示启动失败")
self.material_placeholder.setVisible(True)
logging.error("相机显示启动失败")
except Exception as e:
logging.error(f"启动相机显示失败: {str(e)}")
def update_camera_ui(self, is_camera_ready):
"""更新相机UI显示
Args:
is_camera_ready: 相机是否准备就绪
"""
try:
if is_camera_ready and self.camera_enabled:
# 显示相机画面,隐藏占位符
if self.camera_display:
self.camera_display.setVisible(True)
self.camera_display.raise_() # 确保相机组件在最上层
if self.material_placeholder:
self.material_placeholder.setVisible(False)
logging.info("相机UI已更新显示相机画面")
else:
# 隐藏相机画面,显示占位符
if self.camera_display:
self.camera_display.setVisible(False)
if self.material_placeholder:
self.material_placeholder.setVisible(True)
self.material_placeholder.raise_() # 确保占位符在最上层
if not self.camera_enabled:
self.material_placeholder.setText("相机功能已禁用")
elif not is_camera_ready:
self.material_placeholder.setText("相机未就绪")
logging.info(f"相机UI已更新显示占位符 (相机启用={self.camera_enabled}, 相机就绪={is_camera_ready})")
except Exception as e:
logging.error(f"更新相机UI失败: {str(e)}")
def handle_camera_status(self, is_connected, message):
"""处理相机状态变化"""
if is_connected:
logging.info("相机已连接并显示")
self.update_camera_ui(True)
else:
logging.warning(f"相机显示问题: {message}")
# 更新占位符文本
if self.material_placeholder:
self.material_placeholder.setText(f"相机错误: {message}" if message else "相机未连接")
self.update_camera_ui(False)
@Slot(int, str)
def handle_emergency_stop(self, value, desc):
"""处理急停信号"""
logging.info(f"[处理] 急停信号: {desc}")
# 保存一个急停状态变量
self.emergency_stop = value
# 当急停信号为1时重置D2和D3寄存器
if value == 1:
try:
modbus = ModbusUtils()
client = modbus.get_client()
# 重置D2和D3寄存器
modbus.write_register_until_success(client, 2, 0)
modbus.write_register_until_success(client, 3, 0)
# 通过信号在主线程中处理UI更新
self.emergency_stop_signal.emit(value, desc)
modbus.close_client(client)
except Exception as e:
logging.error(f"处理急停信号失败: {str(e)}")
else:
# 急停信号解除,在主线程中恢复错误状态显示
self.emergency_stop_signal.emit(value, desc)
def _handle_emergency_stop_ui(self, value, desc):
"""在主线程中处理急停信号UI更新"""
try:
if value == 1:
# 显示警告对话框
QMessageBox.warning(self, "急停警告", "监听到急停信号")
# 更新错误状态标签
self.error_status_label.setText("故障: 急停")
self.error_status_label.setToolTip("急停按钮被触发")
self.error_status_label.setStyleSheet("color: red; font-weight: bold;")
else:
# 急停信号解除,恢复错误状态显示
self._update_error_status()
except Exception as e:
logging.error(f"处理急停UI更新失败: {str(e)}")