变频器集成以及增加点动控制(0209)
This commit is contained in:
97
core/pd_system.py
Normal file
97
core/pd_system.py
Normal file
@ -0,0 +1,97 @@
|
||||
import sys
|
||||
import os
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
import threading
|
||||
import time
|
||||
import queue
|
||||
from core.system_state import SystemState,FeedStatus
|
||||
from hardware.relay import RelayController
|
||||
from hardware.inverter import InverterController
|
||||
from hardware.transmitter import TransmitterController
|
||||
from config.ini_manager import ini_manager
|
||||
from hardware.upper_plc import OmronFinsPollingService
|
||||
from vision.visual_callback_dq import VisualCallback
|
||||
from opc.opcua_client_feed import OpcuaClientFeed
|
||||
from busisness.blls import ArtifactBll,PDRecordBll
|
||||
from busisness.models import ArtifactInfoModel,PDRecordModel
|
||||
|
||||
|
||||
class FeedingControlSystem:
|
||||
def __init__(self):
|
||||
print('FeedingControlSystem初始化')
|
||||
self.pd_record_bll=PDRecordBll()
|
||||
|
||||
|
||||
def send_pd_data(self):
|
||||
"""
|
||||
发送PD数据到OPC队列
|
||||
"""
|
||||
# 构建PD数据
|
||||
_cur_mould='SHR2B1-13'
|
||||
'F块L1块需要设置重量'
|
||||
_weight=0
|
||||
_pdrecords = self.pd_record_bll.get_last_pds(_cur_mould)
|
||||
if _pdrecords:
|
||||
_pdrecord=_pdrecords[0]
|
||||
if _pdrecord.TaskID:
|
||||
if _pdrecord.BlockNumber=='F':
|
||||
print(f'{_pdrecord.MouldCode} F块,不发送派单数据')
|
||||
print(f'{_pdrecord.MouldCode} F块,不发送派单数据')
|
||||
print(f'{_pdrecord.MouldCode} F块,不发送派单数据')
|
||||
return True
|
||||
_fact_volumn=self.get_fact_volumn(_pdrecord.MouldCode,_pdrecord.BlockNumber,_weight)
|
||||
if _fact_volumn>0:
|
||||
_pdrecord.FBetonVolume=_fact_volumn
|
||||
print(f'{_pdrecord.MouldCode}-{_pdrecord.BlockNumber} 实际派单方量:{_fact_volumn},{_fact_volumn},{_fact_volumn}')
|
||||
print(f'{_pdrecord.MouldCode}-{_pdrecord.BlockNumber} 实际派单方量:{_fact_volumn},{_fact_volumn},{_fact_volumn}')
|
||||
print(f'{_pdrecord.MouldCode}-{_pdrecord.BlockNumber} 实际派单方量:{_fact_volumn},{_fact_volumn},{_fact_volumn}')
|
||||
# self.state._pd_data=_pdrecord
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
print(f'{_pdrecord.MouldCode} 未获取到数据-(等待扫码)')
|
||||
return False
|
||||
else:
|
||||
print(f'接口数据异常')
|
||||
return False
|
||||
|
||||
def get_fact_volumn(self,mould_code:str,block_number:str='',_weight:float=0) -> float:
|
||||
"""获取实际派单发量"""
|
||||
_now_volumn=0
|
||||
_pd_volumn=0
|
||||
|
||||
print(f'get_fact_volumn当前重量:{_weight}')
|
||||
_now_volumn=_weight/2500
|
||||
if not block_number and '-' in mould_code:
|
||||
block_number = mould_code.split('-')[0][-2:]
|
||||
if block_number=='B1':
|
||||
_pd_volumn=1.9
|
||||
if _weight>750:
|
||||
#留0.3
|
||||
_pd_volumn=_pd_volumn-_now_volumn+0.3
|
||||
if _pd_volumn<1:
|
||||
_pd_volumn=1
|
||||
|
||||
if block_number in ['B2','B3']:
|
||||
_pd_volumn=1.9
|
||||
elif block_number=='L1':
|
||||
_pd_volumn=2.0
|
||||
elif block_number=='L2':
|
||||
#多F块后面剩下的,大约500,那下完F后多的就可以减去
|
||||
_pd_volumn=2
|
||||
# if _weight>1300:
|
||||
_pd_volumn=_pd_volumn-_now_volumn+0.5
|
||||
if _pd_volumn>2.1:
|
||||
_pd_volumn=2.1
|
||||
elif _pd_volumn<0.8:
|
||||
_pd_volumn=0.8
|
||||
|
||||
return round(_pd_volumn,1)
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
system = FeedingControlSystem()
|
||||
|
||||
system.send_pd_data()
|
||||
@ -3,7 +3,7 @@ import threading
|
||||
from enum import IntEnum
|
||||
|
||||
class SystemState(QObject):
|
||||
"""状态中以_开头的属性会发送信号通知,不需要的不要加_开头"""
|
||||
"""状态中以_开头的属性会发送到OPC通知,不需要的不要加_开头"""
|
||||
state_updated=Signal(str,object)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
288
core/system copy.py
Normal file
288
core/system copy.py
Normal file
@ -0,0 +1,288 @@
|
||||
# core/system.py
|
||||
import threading
|
||||
import time
|
||||
import cv2
|
||||
from core.state import SystemState
|
||||
from hardware.relay import RelayController
|
||||
from hardware.inverter import InverterController
|
||||
from hardware.transmitter import TransmitterController
|
||||
from hardware.RFID.rfid_service import rfid_service
|
||||
from vision.camera import DualCameraController
|
||||
from vision.detector import VisionDetector
|
||||
from feeding.controller import FeedingController
|
||||
from service.mould_service import app_web_service
|
||||
from config.settings import app_set_config
|
||||
|
||||
|
||||
class FeedingControlSystem:
|
||||
def __init__(self):
|
||||
self.state = SystemState()
|
||||
|
||||
# 初始化硬件控制器
|
||||
self.relay_controller = RelayController(
|
||||
host=app_set_config.relay_host,
|
||||
port=app_set_config.relay_port
|
||||
)
|
||||
|
||||
self.inverter_controller = InverterController(self.relay_controller)
|
||||
self.transmitter_controller = TransmitterController(self.relay_controller)
|
||||
|
||||
# 初始化视觉系统
|
||||
self.camera_controller = DualCameraController(app_set_config.camera_configs)
|
||||
|
||||
self.vision_detector = VisionDetector()
|
||||
|
||||
# 初始化RFID控制器
|
||||
self.rfid_controller = rfid_service(
|
||||
host=app_set_config.rfid_host,
|
||||
port=app_set_config.rfid_port
|
||||
)
|
||||
# 初始化下料控制器
|
||||
self.feeding_controller = FeedingController(
|
||||
self.relay_controller,
|
||||
self.inverter_controller,
|
||||
self.transmitter_controller,
|
||||
self.vision_detector,
|
||||
self.camera_controller,
|
||||
self.rfid_controller,
|
||||
self.state
|
||||
)
|
||||
|
||||
# 线程管理
|
||||
self.monitor_thread = None
|
||||
self.visual_control_thread = None
|
||||
self.alignment_check_thread = None
|
||||
self.lower_feeding_thread = None
|
||||
self.led_thread = None
|
||||
|
||||
def initialize(self):
|
||||
"""初始化系统"""
|
||||
print("初始化控制系统...")
|
||||
|
||||
# self.check_device_connectivity()
|
||||
|
||||
# self.camera_controller.start_cameras()
|
||||
# if not app_set_config.debug_feeding:
|
||||
# 启动系统监控(要料,破拱)线程
|
||||
self.start_monitoring()
|
||||
|
||||
# 启动视觉控制(角度、溢出)线程
|
||||
# self.start_visual_control()
|
||||
|
||||
# 启动对齐检查线程
|
||||
self.start_alignment_check()
|
||||
|
||||
# 启动下料线程
|
||||
self.start_lower_feeding()
|
||||
#LED屏
|
||||
# self.start_led()
|
||||
|
||||
print("控制系统初始化完成")
|
||||
|
||||
def start_monitoring(self):
|
||||
"""启动系统监控"""
|
||||
print('振动和要料监控线程启动')
|
||||
self.monitor_thread = threading.Thread(
|
||||
target=self._monitor_loop,
|
||||
daemon=True,
|
||||
name='monitor'
|
||||
)
|
||||
self.monitor_thread.start()
|
||||
|
||||
def _monitor_loop(self):
|
||||
"""监控循环"""
|
||||
while self.state.running:
|
||||
try:
|
||||
# self.feeding_controller.check_upper_material_request()
|
||||
self.feeding_controller.check_arch_blocking()
|
||||
time.sleep(1)
|
||||
except Exception as e:
|
||||
print(f"监控线程错误: {e}")
|
||||
|
||||
def start_visual_control(self):
|
||||
"""启动视觉控制"""
|
||||
print('视觉控制线程启动')
|
||||
self.visual_control_thread = threading.Thread(
|
||||
target=self._visual_control_loop,
|
||||
daemon=True,
|
||||
name='visual_control'
|
||||
)
|
||||
self.visual_control_thread.start()
|
||||
|
||||
def _visual_control_loop(self):
|
||||
"""视觉控制循环"""
|
||||
while self.state.running:
|
||||
try:
|
||||
# print('visual_control')
|
||||
current_frame = self.camera_controller.get_single_latest_frame()
|
||||
if current_frame is not None:
|
||||
# 执行视觉控制逻辑
|
||||
self.feeding_controller.visual_control(current_frame)
|
||||
time.sleep(app_set_config.visual_check_interval)
|
||||
except Exception as e:
|
||||
print(f"视觉控制循环错误: {e}")
|
||||
time.sleep(app_set_config.visual_check_interval)
|
||||
|
||||
def start_alignment_check(self):
|
||||
"""启动对齐检查"""
|
||||
print('对齐检查线程启动')
|
||||
self.alignment_check_thread = threading.Thread(
|
||||
target=self._alignment_check_loop,
|
||||
daemon=True,
|
||||
name='align_check'
|
||||
)
|
||||
self.alignment_check_thread.start()
|
||||
|
||||
def _alignment_check_loop(self):
|
||||
"""对齐检查循环"""
|
||||
loc_align_status=False
|
||||
loc_before_status=None
|
||||
while self.state.running:
|
||||
try:
|
||||
if self.state.lower_feeding_stage == 4: # 等待对齐阶段
|
||||
current_frame = self.camera_controller.get_single_latest_frame()
|
||||
if current_frame is not None:
|
||||
self.state.vehicle_aligned = self.alignment_check_status()
|
||||
if self.state.vehicle_aligned:
|
||||
# loc_count+=1
|
||||
print("检测到模具车对齐")
|
||||
else:
|
||||
print("模具车未对齐")
|
||||
# time.sleep(app_set_config.alignment_check_interval)
|
||||
# loc_align_status=self.alignment_check_status()
|
||||
# if loc_align_status and not loc_before_status:
|
||||
# print("模具车由未对齐到对齐")
|
||||
# self.state.vehicle_aligned=True
|
||||
# elif not loc_align_status and loc_before_status:
|
||||
# print("模具车由对齐到未对齐")
|
||||
# self.state.vehicle_aligned=False
|
||||
|
||||
# if loc_before_status!=loc_align_status:
|
||||
# loc_before_status=loc_align_status
|
||||
|
||||
except Exception as e:
|
||||
print(f"对齐检查循环错误: {e}")
|
||||
finally:
|
||||
time.sleep(app_set_config.alignment_check_interval)
|
||||
|
||||
|
||||
def alignment_check_status(self)->bool:
|
||||
"""对齐检查循环"""
|
||||
loc_aligned=False
|
||||
loc_count=0
|
||||
for i in range(4):
|
||||
try:
|
||||
current_frame = self.camera_controller.get_single_latest_frame()
|
||||
if current_frame is not None:
|
||||
loc_aligned = self.vision_detector.detect_vehicle_alignment(current_frame)
|
||||
if loc_aligned:
|
||||
loc_count+=1
|
||||
print("检测到模具车对齐")
|
||||
else:
|
||||
loc_count=0
|
||||
print("模具车未对齐")
|
||||
time.sleep(app_set_config.alignment_check_interval)
|
||||
except Exception as e:
|
||||
print(f"对齐检查循环错误: {e}")
|
||||
time.sleep(app_set_config.alignment_check_interval)
|
||||
|
||||
if loc_count>=3:
|
||||
loc_aligned=True
|
||||
else:
|
||||
loc_aligned=False
|
||||
return loc_aligned
|
||||
|
||||
def start_lower_feeding(self):
|
||||
"""启动下料流程"""
|
||||
self.lower_feeding_thread = threading.Thread(
|
||||
target=self._start_lower_feeding,
|
||||
name="Feeding",
|
||||
daemon=True
|
||||
)
|
||||
self.lower_feeding_thread.start()
|
||||
|
||||
def _start_lower_feeding(self):
|
||||
"""启动下料流程"""
|
||||
while self.state.running:
|
||||
self.feeding_controller.start_feeding()
|
||||
time.sleep(app_set_config.lower_feeding_interval)
|
||||
|
||||
def start_led(self):
|
||||
"""启动LED流程"""
|
||||
self.led_thread = threading.Thread(
|
||||
target=self._start_led,
|
||||
name="LED",
|
||||
daemon=True
|
||||
)
|
||||
self.led_thread.start()
|
||||
|
||||
def _start_led(self):
|
||||
"""启动LED流程"""
|
||||
while self.state.running:
|
||||
led_info = app_web_service.get_pouring_led()
|
||||
if led_info:
|
||||
if self.state.current_artifact.MouldCode==led_info.MouldCode:
|
||||
led_info.RingTypeCode=self.state.current_artifact.RingTypeCode
|
||||
led_info.UpperWeight=self.state._upper_weight
|
||||
led_info.LowerWeight=self.state._lower_weight
|
||||
led_info.VibrationFrequency=self.state._mould_frequency
|
||||
|
||||
#发送到LED屏
|
||||
|
||||
time.sleep(app_set_config.led_interval)
|
||||
|
||||
def check_device_connectivity(self) -> bool:
|
||||
"""检查关键设备连接状态"""
|
||||
try:
|
||||
# 检查网络继电器连接
|
||||
test_response = self.relay_controller.send_command(self.relay_controller.read_status_command)
|
||||
if not test_response:
|
||||
print("网络继电器连接失败")
|
||||
return False
|
||||
|
||||
# 检查变频器连接
|
||||
if not self.relay_controller.modbus_client.connect():
|
||||
print("无法连接到网络继电器Modbus服务")
|
||||
return False
|
||||
|
||||
# 尝试读取变频器一个寄存器(测试连接)
|
||||
# test_result = self.relay_controller.modbus_client.read_holding_registers(
|
||||
# address=0x00,
|
||||
# count=1,
|
||||
# slave=self.inverter_controller.config['slave_id']
|
||||
# )
|
||||
|
||||
# if isinstance(test_result, Exception):
|
||||
# print("变频器连接测试失败")
|
||||
# return False
|
||||
|
||||
# 检查下料斗变送器连接
|
||||
test_weight = self.transmitter_controller.read_data(2)
|
||||
if test_weight is None:
|
||||
print("下料斗变送器连接失败")
|
||||
return False
|
||||
|
||||
self.relay_controller.modbus_client.close()
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"设备连接检查失败: {e}")
|
||||
return False
|
||||
|
||||
def stop(self):
|
||||
"""停止系统"""
|
||||
print("停止控制系统...")
|
||||
self.state.running = False
|
||||
|
||||
# 等待线程结束
|
||||
if self.monitor_thread:
|
||||
self.monitor_thread.join()
|
||||
if self.visual_control_thread:
|
||||
self.visual_control_thread.join()
|
||||
if self.alignment_check_thread:
|
||||
self.alignment_check_thread.join()
|
||||
if self.lower_feeding_thread:
|
||||
self.lower_feeding_thread.join()
|
||||
|
||||
# 释放摄像头资源
|
||||
self.camera_controller.release()
|
||||
print("控制系统已停止")
|
||||
501
core/system.py
501
core/system.py
@ -1,54 +1,53 @@
|
||||
# core/system.py
|
||||
import sys
|
||||
import os
|
||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
import threading
|
||||
import time
|
||||
import cv2
|
||||
from core.state import SystemState
|
||||
import queue
|
||||
from core.system_state import SystemState,FeedStatus
|
||||
from hardware.relay import RelayController
|
||||
from hardware.inverter import InverterController
|
||||
from hardware.transmitter import TransmitterController
|
||||
from hardware.RFID.rfid_service import rfid_service
|
||||
from vision.camera import DualCameraController
|
||||
from vision.detector import VisionDetector
|
||||
from feeding.controller import FeedingController
|
||||
from service.mould_service import app_web_service
|
||||
from config.settings import app_set_config
|
||||
from config.ini_manager import ini_manager
|
||||
from hardware.upper_plc import OmronFinsPollingService
|
||||
from vision.visual_callback_dq import VisualCallback
|
||||
from opc.opcua_client_feed import OpcuaClientFeed
|
||||
from busisness.blls import ArtifactBll,PDRecordBll
|
||||
from busisness.models import ArtifactInfoModel,PDRecordModel
|
||||
|
||||
|
||||
class FeedingControlSystem:
|
||||
def __init__(self):
|
||||
print('FeedingControlSystem初始化')
|
||||
self.state = SystemState()
|
||||
|
||||
# 初始化硬件控制器
|
||||
self.relay_controller = RelayController(
|
||||
host=app_set_config.relay_host,
|
||||
port=app_set_config.relay_port
|
||||
host=ini_manager.relay_host,
|
||||
port=ini_manager.relay_port
|
||||
)
|
||||
|
||||
self.inverter_controller = InverterController(self.relay_controller)
|
||||
|
||||
self.inverter_controller = InverterController()
|
||||
self.transmitter_controller = TransmitterController(self.relay_controller)
|
||||
#小屏修改过屏幕
|
||||
self.vf_auto_mode=True
|
||||
# 初始化 OPC UA 客户端
|
||||
self.opcua_client_feed = OpcuaClientFeed()
|
||||
|
||||
# 初始化 RFID 控制器
|
||||
# self.rfid_controller = rfid_service(
|
||||
# host=app_set_config.rfid_host,
|
||||
# port=app_set_config.rfid_port
|
||||
# )
|
||||
|
||||
# 初始化视觉系统
|
||||
self.camera_controller = DualCameraController(app_set_config.camera_configs)
|
||||
|
||||
self.vision_detector = VisionDetector()
|
||||
|
||||
# 初始化RFID控制器
|
||||
self.rfid_controller = rfid_service(
|
||||
host=app_set_config.rfid_host,
|
||||
port=app_set_config.rfid_port
|
||||
)
|
||||
# self.plc_service = OmronFinsPollingService(ini_manager.upper_plc_ip, ini_manager.upper_plc_port)
|
||||
|
||||
# 初始化下料控制器
|
||||
self.feeding_controller = FeedingController(
|
||||
self.relay_controller,
|
||||
self.inverter_controller,
|
||||
self.transmitter_controller,
|
||||
self.vision_detector,
|
||||
self.camera_controller,
|
||||
self.rfid_controller,
|
||||
self.state
|
||||
)
|
||||
|
||||
self.feeding_controller = VisualCallback(self.state)
|
||||
|
||||
# 初始化 OPC 队列监听线程
|
||||
self.opc_queue_thread = None
|
||||
|
||||
# 线程管理
|
||||
self.monitor_thread = None
|
||||
@ -60,26 +59,243 @@ class FeedingControlSystem:
|
||||
def initialize(self):
|
||||
"""初始化系统"""
|
||||
print("初始化控制系统...")
|
||||
|
||||
|
||||
# self.check_device_connectivity()
|
||||
|
||||
# self.camera_controller.start_cameras()
|
||||
# if not app_set_config.debug_feeding:
|
||||
# 启动系统监控(要料,破拱)线程
|
||||
self.start_monitoring()
|
||||
|
||||
# 启动视觉控制(角度、溢出)线程
|
||||
# self.start_visual_control()
|
||||
|
||||
# 启动对齐检查线程
|
||||
self.start_alignment_check()
|
||||
|
||||
# self.start_monitoring()
|
||||
# 启动下料线程
|
||||
self.start_lower_feeding()
|
||||
#LED屏
|
||||
# self.start_led()
|
||||
# self.start_lower_feeding()
|
||||
# 启动OPC队列处理线程
|
||||
# self.opcua_client_feed.start()
|
||||
|
||||
# self.start_opc_queue_thread()
|
||||
|
||||
#启用API线程
|
||||
self.start_api_thread()
|
||||
|
||||
self.start_vf_thread()
|
||||
# self.feeding_controller.get_current_mould()
|
||||
# self.feeding_controller._cur_mould_model.MouldCode='SHR2L1-5'
|
||||
# self.feeding_controller.send_pd_data()
|
||||
#启用派单线程
|
||||
# self.start_pd_thread()
|
||||
print("控制系统初始化完成")
|
||||
|
||||
def start_opc_queue_thread(self):
|
||||
"""启动OPC队列处理线程"""
|
||||
print('启动OPC队列处理线程')
|
||||
self.opc_queue_thread = threading.Thread(
|
||||
target=self._process_opc_queue,
|
||||
daemon=True,
|
||||
name='opc_queue_processor'
|
||||
)
|
||||
self.opc_queue_thread.start()
|
||||
|
||||
def start_api_thread(self):
|
||||
"""启动PD线程"""
|
||||
# print('启动API处理线程,从API获取未浇筑数据')
|
||||
self.api_thread = threading.Thread(
|
||||
target=self._process_api_db,
|
||||
daemon=True,
|
||||
name='api_thread'
|
||||
)
|
||||
self.api_thread.start()
|
||||
|
||||
def start_vf_thread(self):
|
||||
"""启动变频器控制线程"""
|
||||
# print('启动API处理线程,从API获取未浇筑数据')
|
||||
self.vf_thread = threading.Thread(
|
||||
target=self._process_vf,
|
||||
daemon=True,
|
||||
name='vf_thread'
|
||||
)
|
||||
self.vf_thread.start()
|
||||
|
||||
def _process_vf(self):
|
||||
_begin_time=None
|
||||
_wait_times=300
|
||||
_start_wait_seconds=None
|
||||
while self.state.running:
|
||||
try:
|
||||
# if self.feeding_controller._is_finish_ratio>=0.6:
|
||||
# self.inverter_controller.set_frequency(230)
|
||||
# else:
|
||||
# self.inverter_controller.set_frequency(220)
|
||||
|
||||
if self.state.vf_status in [1,2]:
|
||||
if _begin_time is None :
|
||||
print("----浇筑即将启动-----")
|
||||
if _start_wait_seconds is None:
|
||||
#记录盖板对齐时间
|
||||
_start_wait_seconds=time.time()
|
||||
if self.feeding_controller._is_finish_ratio>=0.02:
|
||||
_elasped_time=time.time()-_start_wait_seconds
|
||||
if _elasped_time<10:
|
||||
time.sleep(10-_elasped_time)
|
||||
self.inverter_controller.control('start',230)
|
||||
print("----振捣已经启动-----")
|
||||
_begin_time=time.time()
|
||||
self.state._mould_frequency=230
|
||||
self.state._mould_vibrate_status=True
|
||||
if self.state.vf_status==2:
|
||||
print("----振捣270s-----")
|
||||
_wait_time=270
|
||||
else:
|
||||
print("----振捣300秒-----")
|
||||
_wait_time=300
|
||||
else:
|
||||
print("----下料重量小于46KG,暂时不振捣-----")
|
||||
# else:
|
||||
elif self.state.vf_status==3 and _begin_time is not None:
|
||||
if time.time()-_begin_time>=_wait_time:
|
||||
if self.vf_auto_mode:
|
||||
self.inverter_controller.control('stop')
|
||||
self.state._mould_vibrate_status=False
|
||||
_begin_time=None
|
||||
_start_wait_seconds=None
|
||||
except Exception as e:
|
||||
print(f"处理变频器数据时发生错误: {e}")
|
||||
time.sleep(2)
|
||||
|
||||
|
||||
def _process_api_db(self):
|
||||
from service.mould_service import app_web_service
|
||||
"""处理API队列中的数据"""
|
||||
# 初始化三个列表用于跟踪ArtifactActionID
|
||||
processed_artifact_actions = [] # 已处理的ArtifactActionID列表
|
||||
processed_artifact_ids = [] # 已处理的ArtifactActionID列表
|
||||
processed_pd_records = [] # 已插入PDRecord表的ArtifactActionID列表
|
||||
processed_pd_ids=[]
|
||||
_model_task=None
|
||||
artifact_bll=ArtifactBll()
|
||||
pdrecord_bll=PDRecordBll()
|
||||
print('启动API处理线程,从API获取未浇筑数据')
|
||||
while self.state.running:
|
||||
try:
|
||||
not_poured = app_web_service.get_not_pour_artifacts()
|
||||
if not_poured:
|
||||
for item in reversed(not_poured):
|
||||
|
||||
if item.MouldCode is None or item.MouldCode == '':
|
||||
continue
|
||||
|
||||
_is_artifactid=True
|
||||
# 检查MouldCode是否已处理
|
||||
if item.MouldCode in processed_artifact_actions:
|
||||
#print(f"待浇筑:MouldCode {item.MouldCode} 已处理,跳过")
|
||||
#处理过了。判断是否更新
|
||||
if item.ArtifactID is None or item.ArtifactID == '':
|
||||
_is_artifactid=False
|
||||
if item.ArtifactID in processed_artifact_ids:
|
||||
# print(f"待浇筑:ArtifactID {item.ArtifactID} 已处理,跳过")
|
||||
_is_artifactid=False
|
||||
if _is_artifactid:
|
||||
_model_data = ArtifactInfoModel(**item.__dict__)
|
||||
_ret=artifact_bll.save_artifact_task(_model_data)
|
||||
if _ret > 0:
|
||||
# 标记为已处理
|
||||
processed_artifact_actions.append(item.MouldCode)
|
||||
if len(processed_artifact_actions) > 4:
|
||||
processed_artifact_actions.pop(0)
|
||||
if item.ArtifactID:
|
||||
processed_artifact_ids.append(item.ArtifactID)
|
||||
if len(processed_artifact_ids) > 4:
|
||||
processed_artifact_ids.pop(0)
|
||||
# 限制最多保存3条记录,删除最旧的
|
||||
|
||||
#print(f"待浇筑:已处理MouldCode {item.MouldCode} ArtifactID {item.ArtifactID}")
|
||||
|
||||
if item.MouldCode in processed_pd_records:
|
||||
#print(f"派单:MouldCode {item.MouldCode} 已处理,跳过")
|
||||
if item.ArtifactID is None or item.ArtifactID == '':
|
||||
continue
|
||||
if item.ArtifactID in processed_pd_ids:
|
||||
#print(f"待浇筑:ArtifactID {item.ArtifactID} 已处理,跳过")
|
||||
continue
|
||||
|
||||
_pd_record_data=None
|
||||
if item.ArtifactID:
|
||||
if item.BetonTaskID is not None and item.BetonTaskID != '':
|
||||
#获取taskid
|
||||
if _model_task is None or item.BetonTaskID != _model_task.TaskID:
|
||||
_model_task = app_web_service.get_task_info(item.BetonTaskID)
|
||||
if _model_task is None:
|
||||
print(f"异常:BetonTaskID {item.BetonTaskID} 不存在,跳过")
|
||||
continue
|
||||
|
||||
_pd_record_data = PDRecordModel(
|
||||
ArtifactID=item.ArtifactID,
|
||||
ArtifactActionID=item.ArtifactActionID,
|
||||
TaskID=_model_task.TaskID,
|
||||
ProjectName=_model_task.ProjectName,
|
||||
ProduceMixID=_model_task.ProduceMixID,
|
||||
BetonGrade=_model_task.BetonGrade,
|
||||
BetonVolume=item.BetonVolume,
|
||||
MouldCode=item.MouldCode,
|
||||
SkeletonID=item.SkeletonID,
|
||||
RingTypeCode=item.RingTypeCode,
|
||||
SizeSpecification=item.SizeSpecification,
|
||||
BuriedDepth=item.BuriedDepth,
|
||||
BlockNumber=item.BlockNumber,
|
||||
PlannedVolume=_model_task.PlannedVolume
|
||||
)
|
||||
else:
|
||||
_pd_record_data = PDRecordModel(
|
||||
MouldCode=item.MouldCode
|
||||
)
|
||||
|
||||
if _pd_record_data is None:
|
||||
continue
|
||||
_ret=pdrecord_bll.save_PD_record(_pd_record_data)
|
||||
if _ret > 0:
|
||||
# 标记为已处理
|
||||
processed_pd_records.append(item.MouldCode)
|
||||
# 限制最多保存3条记录,删除最旧的
|
||||
if len(processed_pd_records) > 4:
|
||||
processed_pd_records.pop(0)
|
||||
if item.ArtifactID:
|
||||
processed_pd_ids.append(item.ArtifactID)
|
||||
if len(processed_pd_ids) > 4:
|
||||
processed_pd_ids.pop(0)
|
||||
|
||||
#print(f"派单:已处理MouldCode {item.MouldCode} ArtifactID {item.ArtifactID}")
|
||||
except Exception as e:
|
||||
print(f"处理MouldCode {item.MouldCode} 时发生错误: {e}")
|
||||
|
||||
time.sleep(5)
|
||||
|
||||
def _process_opc_queue(self):
|
||||
"""处理OPC队列中的数据"""
|
||||
while self.state.running:
|
||||
try:
|
||||
# 从队列中获取数据,设置超时以允许线程退出
|
||||
item = self.state.opc_queue.get(timeout=1)
|
||||
if item:
|
||||
public_name, value = item
|
||||
# 这里可以添加实际的OPC处理逻辑
|
||||
print(f"Processing OPC update: {public_name} = {value}")
|
||||
self.opcua_client_feed.write_value_by_name(public_name, value)
|
||||
# 标记任务完成
|
||||
self.state.opc_queue.task_done()
|
||||
except queue.Empty:
|
||||
# 队列为空,继续循环
|
||||
continue
|
||||
except Exception as e:
|
||||
print(f"OPC队列处理错误: {e}")
|
||||
|
||||
def angle_visual_callback(self, current_angle, overflow_detected, mould_aligned):
|
||||
"""角度视觉回调"""
|
||||
self.feeding_controller.angle_visual_callback(current_angle, overflow_detected, mould_aligned)
|
||||
|
||||
def diff_visual_callback(self, current_diff,current_area):
|
||||
"""差异视觉回调"""
|
||||
self.feeding_controller.diff_visual_callback(current_diff,current_area)
|
||||
|
||||
def shutdown(self):
|
||||
"""关闭系统"""
|
||||
self.feeding_controller.shutdown()
|
||||
self.stop()
|
||||
|
||||
|
||||
def start_monitoring(self):
|
||||
"""启动系统监控"""
|
||||
@ -101,99 +317,6 @@ class FeedingControlSystem:
|
||||
except Exception as e:
|
||||
print(f"监控线程错误: {e}")
|
||||
|
||||
def start_visual_control(self):
|
||||
"""启动视觉控制"""
|
||||
print('视觉控制线程启动')
|
||||
self.visual_control_thread = threading.Thread(
|
||||
target=self._visual_control_loop,
|
||||
daemon=True,
|
||||
name='visual_control'
|
||||
)
|
||||
self.visual_control_thread.start()
|
||||
|
||||
def _visual_control_loop(self):
|
||||
"""视觉控制循环"""
|
||||
while self.state.running:
|
||||
try:
|
||||
# print('visual_control')
|
||||
current_frame = self.camera_controller.get_single_latest_frame()
|
||||
if current_frame is not None:
|
||||
# 执行视觉控制逻辑
|
||||
self.feeding_controller.visual_control(current_frame)
|
||||
time.sleep(app_set_config.visual_check_interval)
|
||||
except Exception as e:
|
||||
print(f"视觉控制循环错误: {e}")
|
||||
time.sleep(app_set_config.visual_check_interval)
|
||||
|
||||
def start_alignment_check(self):
|
||||
"""启动对齐检查"""
|
||||
print('对齐检查线程启动')
|
||||
self.alignment_check_thread = threading.Thread(
|
||||
target=self._alignment_check_loop,
|
||||
daemon=True,
|
||||
name='align_check'
|
||||
)
|
||||
self.alignment_check_thread.start()
|
||||
|
||||
def _alignment_check_loop(self):
|
||||
"""对齐检查循环"""
|
||||
loc_align_status=False
|
||||
loc_before_status=None
|
||||
while self.state.running:
|
||||
try:
|
||||
if self.state.lower_feeding_stage == 4: # 等待对齐阶段
|
||||
current_frame = self.camera_controller.get_single_latest_frame()
|
||||
if current_frame is not None:
|
||||
self.state.vehicle_aligned = self.alignment_check_status()
|
||||
if self.state.vehicle_aligned:
|
||||
# loc_count+=1
|
||||
print("检测到模具车对齐")
|
||||
else:
|
||||
print("模具车未对齐")
|
||||
# time.sleep(app_set_config.alignment_check_interval)
|
||||
# loc_align_status=self.alignment_check_status()
|
||||
# if loc_align_status and not loc_before_status:
|
||||
# print("模具车由未对齐到对齐")
|
||||
# self.state.vehicle_aligned=True
|
||||
# elif not loc_align_status and loc_before_status:
|
||||
# print("模具车由对齐到未对齐")
|
||||
# self.state.vehicle_aligned=False
|
||||
|
||||
# if loc_before_status!=loc_align_status:
|
||||
# loc_before_status=loc_align_status
|
||||
|
||||
except Exception as e:
|
||||
print(f"对齐检查循环错误: {e}")
|
||||
finally:
|
||||
time.sleep(app_set_config.alignment_check_interval)
|
||||
|
||||
|
||||
def alignment_check_status(self)->bool:
|
||||
"""对齐检查循环"""
|
||||
loc_aligned=False
|
||||
loc_count=0
|
||||
for i in range(4):
|
||||
try:
|
||||
current_frame = self.camera_controller.get_single_latest_frame()
|
||||
if current_frame is not None:
|
||||
loc_aligned = self.vision_detector.detect_vehicle_alignment(current_frame)
|
||||
if loc_aligned:
|
||||
loc_count+=1
|
||||
print("检测到模具车对齐")
|
||||
else:
|
||||
loc_count=0
|
||||
print("模具车未对齐")
|
||||
time.sleep(app_set_config.alignment_check_interval)
|
||||
except Exception as e:
|
||||
print(f"对齐检查循环错误: {e}")
|
||||
time.sleep(app_set_config.alignment_check_interval)
|
||||
|
||||
if loc_count>=3:
|
||||
loc_aligned=True
|
||||
else:
|
||||
loc_aligned=False
|
||||
return loc_aligned
|
||||
|
||||
def start_lower_feeding(self):
|
||||
"""启动下料流程"""
|
||||
self.lower_feeding_thread = threading.Thread(
|
||||
@ -209,32 +332,6 @@ class FeedingControlSystem:
|
||||
self.feeding_controller.start_feeding()
|
||||
time.sleep(app_set_config.lower_feeding_interval)
|
||||
|
||||
|
||||
|
||||
def start_led(self):
|
||||
"""启动LED流程"""
|
||||
self.led_thread = threading.Thread(
|
||||
target=self._start_led,
|
||||
name="LED",
|
||||
daemon=True
|
||||
)
|
||||
self.led_thread.start()
|
||||
|
||||
def _start_led(self):
|
||||
"""启动LED流程"""
|
||||
while self.state.running:
|
||||
led_info = app_web_service.get_pouring_led()
|
||||
if led_info:
|
||||
if self.state.current_artifact.MouldCode==led_info.MouldCode:
|
||||
led_info.RingTypeCode=self.state.current_artifact.RingTypeCode
|
||||
led_info.UpperWeight=self.state._upper_weight
|
||||
led_info.LowerWeight=self.state._lower_weight
|
||||
led_info.VibrationFrequency=self.state._mould_frequency
|
||||
|
||||
#发送到LED屏
|
||||
|
||||
time.sleep(app_set_config.led_interval)
|
||||
|
||||
def check_device_connectivity(self) -> bool:
|
||||
"""检查关键设备连接状态"""
|
||||
try:
|
||||
@ -272,6 +369,59 @@ class FeedingControlSystem:
|
||||
print(f"设备连接检查失败: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def start_pd_thread(self):
|
||||
"""启动PD线程"""
|
||||
print('启动派单处理线程,从API获取未浇筑数据')
|
||||
self.pd_jbl_thread = threading.Thread(
|
||||
target=self._process_pd_jbl,
|
||||
daemon=True,
|
||||
name='pd_jbl_thread'
|
||||
)
|
||||
self.pd_jbl_thread.start()
|
||||
|
||||
def _process_pd_jbl(self):
|
||||
# pass
|
||||
#根据当前浇筑块进行最近一块的派单
|
||||
_isFinish=False
|
||||
_start_time=None
|
||||
while self.state.running:
|
||||
#增加生产阶段检测,
|
||||
if self.state._feed_status==FeedStatus.FCheckGB:
|
||||
if not _isFinish:
|
||||
if _start_time is None:
|
||||
_start_time=time.time()
|
||||
_isSuccess=self.feeding_controller.send_pd_data()
|
||||
if _isSuccess:
|
||||
_isFinish=True
|
||||
if time.time()-_start_time>60:
|
||||
print('派单超时,人工介入')
|
||||
_isFinish=True
|
||||
elif self.state._feed_status==FeedStatus.FFinished:
|
||||
_start_time=None
|
||||
_isFinish=False
|
||||
time.sleep(5)
|
||||
|
||||
@property
|
||||
def _is_finish(self):
|
||||
"""检查系统是否运行"""
|
||||
return self.feeding_controller._is_finish
|
||||
|
||||
@property
|
||||
def _is_finish_ratio(self):
|
||||
"""检查系统是否运行"""
|
||||
return self.feeding_controller._is_finish_ratio
|
||||
|
||||
@property
|
||||
def vibrate_status(self):
|
||||
"""检查系统是否运行"""
|
||||
return self.state._mould_vibrate_status
|
||||
|
||||
def set_vf_mode(self,is_auto=False):
|
||||
"""设置变频器为自动模式"""
|
||||
self.vf_auto_mode=is_auto
|
||||
|
||||
|
||||
def stop(self):
|
||||
"""停止系统"""
|
||||
print("停止控制系统...")
|
||||
@ -286,7 +436,22 @@ class FeedingControlSystem:
|
||||
self.alignment_check_thread.join()
|
||||
if self.lower_feeding_thread:
|
||||
self.lower_feeding_thread.join()
|
||||
|
||||
if self.opc_queue_thread:
|
||||
self.opc_queue_thread.join()
|
||||
if self.vf_thread:
|
||||
self.vf_thread.join()
|
||||
if self.api_thread:
|
||||
self.api_thread.join()
|
||||
# 释放摄像头资源
|
||||
self.camera_controller.release()
|
||||
# self.camera_controller.release()
|
||||
print("控制系统已停止")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
system = FeedingControlSystem()
|
||||
system.initialize()
|
||||
time.sleep(2)
|
||||
system.state._upper_weight=1000
|
||||
|
||||
while True:
|
||||
time.sleep(1)
|
||||
|
||||
178
core/system_state.py
Normal file
178
core/system_state.py
Normal file
@ -0,0 +1,178 @@
|
||||
import threading
|
||||
from enum import IntEnum
|
||||
import queue
|
||||
import json
|
||||
from dataclasses import asdict
|
||||
from busisness.blls import ArtifactBll,PDRecordBll
|
||||
|
||||
class SystemState:
|
||||
"""系统状态类,存在变化的参数及标志"""
|
||||
"""系统状态中以_开头的属性会发送到OPC通知,不需要的不要加_开头"""
|
||||
# state_updated=Signal(str,object)
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
#
|
||||
self.watched_props = []
|
||||
self.lock = threading.RLock()
|
||||
self.opc_queue = queue.Queue()
|
||||
# 系统运行状态
|
||||
self.running = True
|
||||
|
||||
# 上料斗控制相关
|
||||
self._upper_door_position = Upper_Door_Position.Default # default(在搅拌楼下接料), over_lower(在下料斗上方), returning(返回中)
|
||||
# 是否破拱
|
||||
self._upper_is_arch_=False
|
||||
self._upper_door_closed=True
|
||||
self._upper_weight=0
|
||||
self._upper_volume=0.0
|
||||
#下料比例变频
|
||||
self.vf_frequencys=[{'radio':0,'fre':230},{'radio':0.3,'fre':230},{'radio':0.6,'fre':230}]
|
||||
#使用
|
||||
self._mould_frequency=230
|
||||
self._mould_vibrate_status=False #True振动中False未振动
|
||||
#记录模具开始振动的时间
|
||||
self.mould_vibrate_time=0
|
||||
|
||||
#下料斗状态想着
|
||||
self.lower_feeding_stage = 0 # 0:未下料, 1:第一阶段, 2:第二阶段, 3:第三阶段, 4:等待模具车对齐
|
||||
self._lower_is_arch_=False
|
||||
self._lower_weight=0
|
||||
self._lower_angle=0.0
|
||||
|
||||
#模具车状态
|
||||
self._mould_weight=0
|
||||
|
||||
|
||||
self.lower_feeding_cycle = 0 # 下料斗下料循环次数
|
||||
self.upper_feeding_count = 0 # 上料斗已下料次数
|
||||
self.upper_feeding_max = 2 #上料斗最大下料次数
|
||||
|
||||
# 重量相关
|
||||
self.last_upper_weight = 0
|
||||
self.last_lower_weight = 0
|
||||
self.last_weight_time = 0
|
||||
#需要下料的总重量
|
||||
self._mould_need_weight=0
|
||||
#完成下料的总重量
|
||||
self._mould_finish_weight=0
|
||||
|
||||
self.initial_upper_weight=0
|
||||
self.initial_lower_weight=0
|
||||
|
||||
|
||||
# 错误计数
|
||||
self.upper_weight_error_count = 0
|
||||
self.lower_weight_error_count = 0
|
||||
|
||||
# 视觉系统状态
|
||||
self.angle_control_mode = "normal" # 角度控制模式: normal, reducing, maintaining, recovery
|
||||
self.overflow_detected = "0" # 堆料检测
|
||||
self.current_finish_status=False # 当前是否完成浇筑满
|
||||
self.door_opening_large = False # 夹角
|
||||
self.vehicle_aligned = False # 模具车是否对齐
|
||||
self.last_angle = None # 上次检测角度
|
||||
|
||||
#当前RFID的内容格式为 模块编号,分块号,尺寸规格,方量
|
||||
self.rfid_current=None
|
||||
|
||||
#当前生产的管片
|
||||
self.current_artifact=None
|
||||
#当前生产状态
|
||||
self._feed_status=FeedStatus.FNone
|
||||
#每方重量
|
||||
self.density=2416.4
|
||||
self.bll_artifact=ArtifactBll()
|
||||
self.bll_pdrecord=PDRecordBll()
|
||||
#记录正在生产code模具编号,status:2正生产3完成生成,weight:完成重量
|
||||
self._db_status={'code':'','status':1,'weight':0}
|
||||
#派单数据发送到OPC
|
||||
self._pd_data=''
|
||||
|
||||
#变频器相关
|
||||
#是否启动变频器0未1普通块启动2F块启动 3结束
|
||||
self.vf_status=0
|
||||
self.watched_props = [k for k in self.__dict__ if k.startswith('_')]
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
super().__setattr__(name, value)
|
||||
if name in self.watched_props:
|
||||
with self.lock:
|
||||
public_name = name.lstrip('_')
|
||||
try:
|
||||
if public_name.startswith('db'):
|
||||
self.save_db(public_name,value) #有影响的话改成异步
|
||||
else:
|
||||
if public_name=="pd_data":
|
||||
#更新派单表
|
||||
if hasattr(value,'MouldCode'):
|
||||
self.bll_pdrecord.start_pd(value.MouldCode,value.FBetonVolume)
|
||||
_opc_pd={
|
||||
"ArtifactID":value.ArtifactID,
|
||||
"TaskID":value.TaskID,
|
||||
"ProduceMixID":value.ProduceMixID,
|
||||
"BetonVolume":value.FBetonVolume,
|
||||
"PlannedVolume":value.PlannedVolume
|
||||
}
|
||||
self.opc_queue.put_nowait((public_name, json.dumps(_opc_pd)))
|
||||
else:
|
||||
self.opc_queue.put_nowait((public_name, value))
|
||||
except queue.Full:
|
||||
# 队列已满,记录异常但不中断程序
|
||||
print(f"OPC queue is full, skipping update for {public_name}")
|
||||
except Exception as e:
|
||||
# 捕获其他异常
|
||||
print(f"Unexpected error putting to OPC queue: {e}")
|
||||
|
||||
# self.state_updated.emit(public_name, value)
|
||||
|
||||
def save_db(self,public_name,val):
|
||||
if not val:
|
||||
return
|
||||
if public_name=="db_status":
|
||||
_code=val['code']
|
||||
if _code:
|
||||
_status=val['status']
|
||||
if _status==3:
|
||||
#完成生产
|
||||
self.bll_artifact.finish_produce(_code,val['weight'])
|
||||
elif _status==2:
|
||||
#开始生产
|
||||
self.bll_artifact.start_produce(_code)
|
||||
|
||||
|
||||
class FeedStatus(IntEnum):
|
||||
#初始值
|
||||
FNone = 0
|
||||
# 检查模车(模车到位)
|
||||
FCheckGB = 1
|
||||
#RFID检测或匹配
|
||||
FRFID=2,
|
||||
# 下料1(下料斗到模具车)
|
||||
FFeed1=5
|
||||
#下料2(上--》下)
|
||||
FFeed2 = 6
|
||||
# 下料3(下--》模)
|
||||
FFeed3 = 7
|
||||
# 下料4(上--》下)
|
||||
FFeed4 = 8
|
||||
#下料5(下-》模)
|
||||
FFeed5 = 9
|
||||
#完成(管片生产完成)
|
||||
FFinished = 11
|
||||
|
||||
class Upper_Door_Position(IntEnum):
|
||||
# default(在搅拌楼下接料), over_lower(在下料斗上方), returning(返回中)
|
||||
Default = 0
|
||||
Over_Lower = 1
|
||||
Returning = 2
|
||||
|
||||
|
||||
class Upper_PLC_Status(IntEnum):
|
||||
# 即将振捣室
|
||||
PLC_ZDS_Ready = 4
|
||||
#到达振捣室
|
||||
PLC_ZDS_Finish = 5
|
||||
#即将搅拌楼
|
||||
PLC_JBL_Ready = 64
|
||||
#到达搅拌楼
|
||||
PLC_JBL_Finish = 66
|
||||
Reference in New Issue
Block a user