Files
Feeding_control_system/vision/visual_callback_dq.py
2026-04-07 09:51:38 +08:00

1494 lines
70 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from pickle import FALSE
from re import S
from cv2.gapi import ov
from config.settings import app_set_config
from core.relay_feed import RelayFeedController
from hardware.relay import RelayController
from hardware.transmitter import TransmitterController
import time
import threading
from datetime import datetime
import logging
import queue
from hardware.upper_plc import OmronFinsPollingService
from vision.muju_cls.muju_utils import run_stable_classification_loop
from vision.camera_picture import save_camera_picture
from busisness.blls import ArtifactBll,PDRecordBll
from busisness.models import ArtifactInfoModel,PDRecordModel
from service.mould_service import app_web_service
from core.system_state import SystemState,FeedStatus,Upper_Door_Position,PD_StatusEnum
from core.core_utils import CoreUtils
from dataclasses import asdict
import json
import math
class VisualCallback:
# 类变量,用于存储实例引用,实现单例检测
_instance = None
_lock = threading.Lock()
# def __new__(cls,*args, **kwargs):
# """检测实例是否存在,实现单例模式"""
# with cls._lock:
# if cls._instance is None:
# cls._instance = super().__new__(cls)
# return cls._instance
def __init__(self,
relay_controller:RelayController,
transmitter_controller:TransmitterController,
state:SystemState=None):
"""初始化视觉回调处理器"""
# 避免重复初始化
if hasattr(self, '_initialized') and self._initialized:
return
self.relay_controller = relay_controller
self.transmitter_controller = transmitter_controller
self.relay_feed=RelayFeedController(relay_controller,state)
self.pd_record_bll=PDRecordBll()
self.state=state
# 线程安全的参数传递
self._new_data_available = threading.Event()
self._is_processing = threading.Lock()
#diff参数
self._is_processing_diff = threading.Lock()
self._new_data_diff = threading.Event()
self._current_diff=0
self._current_diff_area=[]
self._is_diff_save=False
self._stop_event = threading.Event()
# 添加下料斗门控制锁,防止两个线程同时控制
self._door_control_lock = threading.Lock()
# 记录当前控制门的线程名称,用于调试
self._current_controlling_thread = None
#是否启动后的第一个模具
self._is_first_module=True
#上一次派单方量
self.prev_pd_volume=0.0
self.init_val()
# self._setup_logging_2()
#F块完成重量的70%控制夹脚F块多于这个比例就没有记录了注意
self._max_f_angle_ratio=0.7
#完成多少,调整角度比例 多于0.8就没记录了(注意)
self._max_angle_radio=0.8
#重量大于95%停留时间2秒其他的1秒
self._weight_ratio_955=0.955
#完成多少,忽略未浇筑满
self._max_ignore_radio=0.8
self._mould_accept_aligned=None
self._mould_before_aligned=False
#模具开始浇筑时间
self._time_mould_begin=''
#模具结束浇筑时间
self._time_mould_end=''
#记录当前模具信息model
self._cur_mould_model=None
self.plc_valid_data=[5,37]
self.plc_valid_data_jbl=[66,98]
# self.db_queue=queue.Queue()
# 获取视觉数据线程angle_visual_callback推送的数据并进行处理注意处理视觉进行夹角控制
self.callback_thread = None
self.diff_thread = None
def init_val(self):
#初始化值
"""初始化视觉回调处理器"""
self.angle_mode = "normal"
self.overflow = False
self.is_start_visual=False
# 线程安全的参数传递
self._current_angle = None
self._overflow_detected = None
# 新增标志位指示safe_control_lower_close是否正在执行
self._is_safe_closing = False
self._is_feed_start=True
#未浇筑满时间,用于确定是否进入未浇筑满
self._before_finish_time=None
#进入未浇筑满状态标志位
self._is_before_finish=False
#是否浇筑满标志位
self._is_finish=False
#用于保存diff标志位
# self._is_diff_save=False
#用于判断当前判断是否对齐(diff)
self._is_diff_unaligned=False
self._diff_f_val=0
self._diff_f_area=[]
#浇筑完成比例(重量)
self._is_finish_ratio=0
#下料阶段,汇总时用枚举
self._is_feed_stage=0
#振动相关参数
self._last_arch_one_weight=0
self._last_arch_two_weight=0
self._last_arch_three_weight=0
self._last_arch_four_weight=0
self._last_arch_five_weight=0
self._last_arch_time=0
#是否为F块
self._is_small_f=None
#采集数据用,下料重量=之前下的重量+最后一阶段(下-->模具车)重量差
#记录最后一次下料斗到模具车前的重量
self._finish_weight=0
#记录最后一次下料斗到车初始重量
self._inital_finish_lweight=0
#记录视觉停止下料时的重量(计算后面加了多少)
self._last_lower_weight=0
#每片开始下料斗的重量
self._init_lower_weight=0
# 初始化控制间隔和堆料状态跟踪属性
self._last_overflow_state = False
self._last_control_time = 0
self._is_running=True
self._is_stop_one_seconds=False
self._initialized = True
self.plc_data=None
self._mould_need_weight=0
#点动等级
self._point_speed_grade=0
self._point_weight=0
def start_visual_thread(self)->bool:
"""浇筑状态回调线程"""
self.callback_thread = threading.Thread(
target=self._run_thread_loop,
daemon=True
)
self.callback_thread.start()
#diff线程值传递后处理
self.diff_thread = threading.Thread(
target=self._diff_temp,
daemon=True
)
self.diff_thread.start()
return True
def angle_visual_callback(self, current_angle, overflow_detected, mould_aligned):
"""
视觉控制主逻辑,供外部推送数据
使用单个持续运行的线程,通过参数设置传递数据
如果线程正在处理数据,则丢弃此次推送
"""
#print(f"{datetime.now().strftime('%H:%M:%S.%f')[:-3]} 收到推送数据")
# 尝试获取处理锁,若失败则说明正在处理,丢弃数据
if not self._is_processing.acquire(blocking=False):
print("回调线程仍在执行,丢弃此次推送数据")
return
try:
# 更新参数
if overflow_detected is not None:
# print(f"{datetime.now().strftime('%H:%M:%S.%f')[:-3]} 收到溢料:{overflow_detected}")
self._overflow_detected = overflow_detected
if current_angle is not None:
#print(f"{datetime.now().strftime('%H:%M:%S.%f')[:-3]} 收到角度:{current_angle}")
self._current_angle = current_angle
if mould_aligned is not None:
#print(f"{datetime.now().strftime('%H:%M:%S.%f')[:-3]} 收到对齐:{mould_aligned}")
self._mould_accept_aligned=mould_aligned
# 通知线程有新数据可用
self._new_data_available.set()
finally:
# 释放处理锁
self._is_processing.release()
def diff_visual_callback(self, current_diff,current_area):
"""
视觉模型diff回调
"""
#print(f"{datetime.now().strftime('%H:%M:%S.%f')[:-3]} 收到推送数据")
# 尝试获取处理锁,若失败则说明正在处理,丢弃数据
if not self._is_processing_diff.acquire(blocking=False):
print("222回调线程仍在执行丢弃此次推送数据")
return
try:
# 更新参数
if current_diff is not None:
# print(f"{datetime.now().strftime('%H:%M:%S.%f')[:-3]} 收到diff:{current_diff}")
self._current_diff = current_diff
self._diff_f_val=current_diff
if current_area is not None:
# print(f"{datetime.now().strftime('%H:%M:%S.%f')[:-3]} 收到area:{current_area}")
self._current_diff_area = current_area
self._diff_f_area = current_area
# 通知线程有新数据可用
self._new_data_diff.set()
finally:
# 释放处理锁
self._is_processing_diff.release()
def _diff_temp(self):
"""
接受视觉回调数据
线程主循环,持续运行
等待新数据,然后调用处理方法
"""
_temp_diff_count=0
_temp_area_count=0
_temp_diff_str2=''
_temp_area_str2=''
while not self._stop_event.is_set():
# print('-----等待diff 数据------')
# 等待新数据可用
self._new_data_diff.wait()
# 重置事件
self._new_data_diff.clear()
#_is_diff_save是否完成此片
if self._is_diff_save:
# print('-----进入diff 数据------')
#完成了此片,然后是对齐状态
if not self._is_diff_unaligned:
# 处理数据
# print('-----进入对齐数据------')
if self._current_diff is not None and self._current_diff_area is not None:
_timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
if _temp_diff_count<=10 and self._current_diff!=0:
_temp_diff_str=f"diff , {_timestamp} , {self._current_diff}\n"
_temp_diff_count+=1
with open('weight.txt', 'a') as f:
f.write(_temp_diff_str+'\n')
# print('-----保存成功(diff 数据)------')
if _temp_area_count<=10 and self._current_diff_area!=[]:
_temp_area_str=f"area , {_timestamp} , {str(self._current_diff_area)}\n"
_temp_area_count+=1
with open('weight.txt', 'a') as f:
f.write(_temp_area_str+'\n')
# print('-----保存成功(area 数据)------')
if _temp_diff_count>=10 and _temp_area_count>=10:
self._is_diff_save=False
time.sleep(1)
continue
# else:
#变成了未对齐,拉起盖板后,重新计数
# if _temp_diff_count>=10 and _temp_area_count>=10:
# _temp_diff_count=0
# _temp_area_count=0
# self._is_diff_save=False
# _temp_diff_str=''
# _temp_area_str=''
self._current_diff=0
self._current_diff_area=[]
_temp_diff_count=0
_temp_area_count=0
_temp_diff_str=''
_temp_area_str=''
time.sleep(1)
def _arch_loop(self):
"""破拱线程"""
while self._is_running:
if self._is_finish:
time.sleep(2)
continue
try:
current_time = time.time()
# 检查下料斗破拱(只有在下料过程中才检查)
if self._is_feed_stage==1: # 下料斗--》模具车
_arch_weight = self.transmitter_controller.read_data(2)
if _arch_weight is not None and _arch_weight>0:
# 检查重量变化是否过慢
_weight_changed=abs(_arch_weight - self._last_arch_one_weight)
#_last_arch_one_weight默认为0一开始就进入振动
print(f'---------------第一阶段,重量变化:{_weight_changed}------------------')
if (_weight_changed< 200) and \
(current_time - self._last_arch_time) >= 2:
self._last_arch_time = current_time
print('---------------------第一阶段振动3秒小于200KG-----------------')
if self._current_angle>25:
self.relay_feed.control_arch_lower_open_sync(3)
self._last_arch_one_weight = _arch_weight
continue
self._last_arch_one_weight = _arch_weight
elif self._is_feed_stage==2: #上料斗到下料斗,料多,谨慎振动
_arch_weight = self.transmitter_controller.read_data(1)
if _arch_weight is not None and _arch_weight>0:
# 检查重量变化是否过慢
_weight_changed=abs(_arch_weight - self._last_arch_two_weight)
print(f'---------------第二阶段,重量变化:{_weight_changed}------------------')
if (_weight_changed < 100) and \
(current_time - self._last_arch_time) >= 2:
self._last_arch_time = current_time
#print('---------------------第二阶段振动3秒-----------------')
# self.relay_feed.control_arch_upper_open_sync(3)
self._last_arch_two_weight = _arch_weight
continue
self._last_arch_two_weight = _arch_weight
elif self._is_feed_stage==3: #第二次下料斗-》模具车
_arch_weight = self.transmitter_controller.read_data(2)
if _arch_weight is not None and _arch_weight>0:
#刚开始不需要振动,料太多
if self._last_arch_three_weight>0:
_weight_changed=abs(_arch_weight - self._last_arch_three_weight)
# 检查重量变化是否过慢
print(f'---------------第三阶段,重量变化:{_weight_changed}------------------')
if (_weight_changed < 100) and \
(current_time - self._last_arch_time) >= 2:
self._last_arch_time = current_time
print('---------------------第三阶段振动3秒(小于100KG-----------------')
if self._current_angle>25:
self.relay_feed.control_arch_lower_open_sync(3)
self._last_arch_three_weight = _arch_weight
continue
self._last_arch_three_weight = _arch_weight
elif self._is_feed_stage==4: #上料斗--》下料斗
_arch_weight = self.transmitter_controller.read_data(1)
if _arch_weight is not None and _arch_weight>0:
# 检查重量变化是否过慢
_weight_changed=abs(_arch_weight - self._last_arch_four_weight)
print(f'---------------第二阶段,重量变化:{_weight_changed}------------------')
if (_weight_changed < 200) and \
(current_time - self._last_arch_time) > 2:
self._last_arch_time = current_time
print('---------------------第四阶段振动5秒-----------------')
#重量不准,暂时不振动
# self.relay_feed.control_arch_upper_open_sync(5)
self._last_arch_four_weight = _arch_weight
continue
self._last_arch_four_weight = _arch_weight
elif self._is_feed_stage==5: #下料斗->模具车
_arch_weight = self.transmitter_controller.read_data(2)
if _arch_weight is not None and _arch_weight>0:
if self._last_arch_five_weight>0:
_weight_changed=abs(_arch_weight - self._last_arch_five_weight)
print(f'---------------第五阶段,重量变化:{_weight_changed}------------------')
_min_arch_weight=20
if self._is_finish_ratio<self._max_angle_radio:
_min_arch_weight=50
if (_weight_changed < _min_arch_weight) and \
(current_time - self._last_arch_time) >= 2:
self._last_arch_time = current_time
print(f'---------------------第五阶段振动3秒(小于{_min_arch_weight}kg)-----------------')
if self._current_angle>25:
self.relay_feed.control_arch_lower_open_sync(3)
self._last_arch_five_weight = _arch_weight
continue
self._last_arch_five_weight = _arch_weight
# 更新最后读取时间
self._last_arch_time = current_time
time.sleep(2)
except Exception as e:
print(f"监控线程错误: {e}")
def _aligned_get_times(self,flag):
"""
获取对齐,1为对齐0为未对齐
"""
_current_times=time.time()
_temp_aligned_count=0
if flag==1:
while time.time()-_current_times<=2:
# print(f'-------------{self._mould_accept_aligned}-----------------')
if self._mould_accept_aligned=='盖板对齐':
_temp_aligned_count=_temp_aligned_count+1
else:
_temp_aligned_count=0
if _temp_aligned_count>0:
print(f'-------------{datetime.now().strftime("%H:%M:%S")} 盖板对齐,次数:{_temp_aligned_count}-----------------')
time.sleep(0.2)
self._mould_accept_aligned=''
if _temp_aligned_count>=8:
return True
else:
return False
elif flag==2:
while time.time()-_current_times<=5:
if self._mould_accept_aligned=='盖板未对齐':
_temp_aligned_count=_temp_aligned_count+1
else:
_temp_aligned_count=0
if _temp_aligned_count>0:
print(f'-------------{datetime.now().strftime("%H:%M:%S")} 盖板未对齐,次数:{_temp_aligned_count}-----------------')
time.sleep(0.2)
self._mould_accept_aligned=''
if _temp_aligned_count>=20:
self._is_diff_unaligned=True
return True
else:
self._is_diff_unaligned=False
return False
def _no_aligned_diff(self):
"""
diff 未对齐检测
"""
_current_times=time.time()
_temp_aligned_count=0
while time.time()-_current_times<=1:
# print(f'-------------{self._mould_accept_aligned}-----------------')
if self._mould_accept_aligned=='盖板未对齐':
_temp_aligned_count=_temp_aligned_count+1
else:
_temp_aligned_count=0
# print(f'-------------{datetime.now().strftime("%H:%M:%S")} 盖板对齐,次数:{_temp_aligned_count}-----------------')
time.sleep(0.2)
if _temp_aligned_count>=3:
return True
else:
return False
def _run_thread_loop(self):
"""
接受视觉回调数据
线程主循环,持续运行
等待新数据,然后调用处理方法
"""
while not self._stop_event.is_set():
# 等待新数据可用
self._new_data_available.wait()
# 重置事件
self._new_data_available.clear()
# 获取当前参数(使用临时变量避免被其他线程修改)
current_angle = self._current_angle
overflow_detected = self._overflow_detected
self._is_feed_start=True
if self.is_start_visual:
# 处理数据
self._process_angle_callback(current_angle, overflow_detected)
time.sleep(0.1)
def _run_feed(self):
_is_api_request=True
while self.state.running:
# print("------------已启动----------------")
if self._is_feed_start:
# if self.plc_data==5:
#_is_finish_ratio完成 比例,根据重量过滤一下
if self._is_first_module and self._overflow_detected=='未堆料':
#第一次打开 ,未堆料,检测对齐
if _is_api_request:
self.get_current_mould()
_is_api_request=False
_is_aligned=self._aligned_get_times(1)
if _is_aligned:
_is_api_request=True
if self.state.pd_status==PD_StatusEnum.PD_Ready:
self.state.pd_status=PD_StatusEnum.PD_TimeOut
print('------------启动程序后,进入第一块-------------')
self._is_first_module=False
self._mould_before_aligned=True
if self._cur_mould_model:
self.state.current_mould=self._cur_mould_model
self.state.current_block_number=CoreUtils.get_number_by_mould_code(self._cur_mould_model.MouldCode)
self.state._db_mould_status={
'mould_code':self._cur_mould_model.MouldCode,
'status':2,
'weight':0,
}
else:
self.state.current_mould=None
self.state.current_block_number=''
_current_weight=self.transmitter_controller.read_data(2)
if _current_weight:
self._init_lower_weight=_current_weight
else:
print('------------获取上料斗重量失败-------------')
return
self.state._feed_status=FeedStatus.FCheckGB
# if not self.state.current_block_number=='F':
# self.state.pd_status=PD_StatusEnum.PD_Ready
# self.is_start_visual=True
self.run_feed_all()
elif self._is_finish and self._is_finish_ratio>=0.7:
#后续流程--》检查到未对齐,--》后又对齐+未堆料
#print('------------------进入连续块检测------------------')
if self._mould_before_aligned:
#未对齐,检测对齐
_is_not_aligned=self._aligned_get_times(2)
if _is_not_aligned:
#标志位
self._mould_before_aligned=False
print('------------连续盖板未对齐完成,进入派单标志-------------')
self.state.pd_status=PD_StatusEnum.PD_Ready
#print('------------连续盖板未对齐-------------')
else:
if _is_api_request:
self.get_current_mould()
_is_api_request=False
_is_aligned=self._aligned_get_times(1)
if _is_aligned and self._overflow_detected=='未堆料':
print('------------进入连续生产-------------')
self._mould_before_aligned=True
_is_api_request=True
if self.state.pd_status==PD_StatusEnum.PD_Ready:
self.state.pd_status=PD_StatusEnum.PD_TimeOut
if self._cur_mould_model:
self.state.current_mould=self._cur_mould_model
self.state.current_block_number=CoreUtils.get_number_by_mould_code(self._cur_mould_model.MouldCode)
self.state._db_mould_status={
'mould_code':self._cur_mould_model.MouldCode,
'status':2,
'weight':0,
}
else:
self.state.current_mould=None
self.state.current_block_number=''
_current_weight=self.transmitter_controller.read_data(2)
if not _current_weight:
print('------------获取上料斗重量失败-------------')
return
# print('-----------进入连续块111111-----------')
# self.is_start_visual=True
if self._last_lower_weight>0:
with open('weight.txt', 'a') as f:
f.write(f"补料:{self._last_lower_weight-_current_weight}\n\n"+"="*32)
self.init_val()
self._init_lower_weight=_current_weight
self.state._feed_status=FeedStatus.FCheckGB
# if not self.state.current_block_number=='F':
#这里需要判断状态是否发送完成,如果没发送完成,应该报警(时间太长),
# self.state.pd_status=PD_StatusEnum.PD_Ready
self.run_feed_all()
# else:
# print("-----------上料斗未就位----------------")
# print("---------3--上料斗未就位----------------")
time.sleep(0.2)
def safe_control_lower_close(self,duration=3):
"""线程安全的下料斗关闭方法"""
thread_name = threading.current_thread().name
# print(f"[{thread_name}] 尝试关闭下料斗...")
# 设置标志位,指示正在执行安全关闭操作
self._is_safe_closing = True
try:
with self._door_control_lock:
self._current_controlling_thread = thread_name
print(f"关闭下料斗{duration}")
self.relay_controller.control(self.relay_controller.DOOR_LOWER_OPEN, 'close')
self.relay_controller.control(self.relay_controller.DOOR_LOWER_CLOSE, 'open')
time.sleep(duration)
self.relay_controller.control(self.relay_controller.DOOR_LOWER_CLOSE, 'close')
self._current_controlling_thread = None
#print(f"[{thread_name}] 释放下料斗控制权")
finally:
# 无论成功失败,都要重置标志位
self._is_safe_closing = False
def close_lower_door_visual(self):
"""关闭下料斗门"""
self.is_start_visual=False
#休眠让视觉先结束
time.sleep(0.5)
self.safe_control_lower_close()
def _visual_close(self):
self.is_start_visual=False
self._is_finish=True
self.state.vf_status=3
self.state._feed_status=FeedStatus.FFinished
self._is_feed_stage=0
print(f'--------进入关闭(浇筑满)-----------')
self.safe_control_lower_close(3)
print(f'--------浇筑完成-----------')
if self._cur_mould_model:
self.state._db_mould_status={
'mould_code':self._cur_mould_model.MouldCode,
'status':3,
'weight':self.state._mould_finish_weight,
}
# try:
# self.db_queue.put_nowait({
# "f":self._is_small_f,
# "Status": 3
# })
# except queue.Full:
# print("数据库队列已满,无法添加数据")
#记录重量
_current_weight=self.transmitter_controller.read_data(2)
if _current_weight is not None:
self._last_lower_weight=_current_weight
self._finish_weight= self._finish_weight+(self._inital_finish_lweight-_current_weight)
with open('weight.txt', 'a') as f:
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
if self._is_small_f:
if self._cur_mould_model:
f.write(f"{self._time_mould_begin},{timestamp},{self._cur_mould_model.MouldCode},F,{self._finish_weight}\n")
else:
f.write(f"{self._time_mould_begin},{timestamp},F,{self._finish_weight}\n")
else:
if self._cur_mould_model:
f.write(f"{self._time_mould_begin},{timestamp},{self._cur_mould_model.MouldCode},B,{self._finish_weight}\n")
else:
f.write(f"{self._time_mould_begin},{timestamp},B,{self._finish_weight}\n")
#开启保存diff
self._is_diff_save=True
#保存图片
save_camera_picture()
def run_feed_all(self):
"""
全流程下料:包括判断模具类型
"""
_is_f= run_stable_classification_loop()
print(f'------------已判断出模具类型: {_is_f}-------------')
if _is_f is not None:
if _is_f=='模具车1':
self._is_small_f=True
print('-------------F块模具--------------')
# print('-------------F块模具--------------')
# print('-------------F块模具--------------')
# self.send_pd_data()
self.run_feed_f()
elif _is_f=='模具车2':
self._is_small_f=False
print('-------------B-L模具---------------')
# self.send_pd_data()
self.run_feed()
if self._is_small_f is None:
print('-----------未判断出模具类型--------------')
return
def run_feed_f(self):
"""第一阶段下料:下料斗向模具车下料(低速)"""
print("--------------------开始下料F块--------------------")
self._time_mould_begin=datetime.now().strftime("%Y-%m-%d %H:%M:%S")
loc_mitter=self.transmitter_controller
max_weight_none=5
cur_weight_none=0
initial_lower_weight=self._init_lower_weight
first_finish_weight=0
self._finish_weight=first_finish_weight
self._inital_finish_lweight=initial_lower_weight
self._mould_need_weight=0.54*2416
need_total_weight=self._mould_need_weight
if initial_lower_weight>100:
if not self._is_finish:
self.state._feed_status=FeedStatus.FFeed5
self.state.vf_status=2
self.is_start_visual=True
self._is_feed_stage=5
while not self._is_finish:
current_weight = loc_mitter.read_data(2)
if current_weight is None:
cur_weight_none+=1
if cur_weight_none>max_weight_none:
#如果重量连续5次为None认为下料斗未就位跳出循环
print('------------f下到模具车,下料斗重量异常----------------')
print('------------f下到模具车,下料斗重量异常----------------')
self.close_lower_door_visual()
return
#视觉处理关闭,异常的话重量没有生效
continue
cur_weight_none=0
first_finish_weight=initial_lower_weight-current_weight
self._is_finish_ratio=(first_finish_weight)/need_total_weight
self.state._mould_finish_weight=first_finish_weight
self.state._mould_finish_ratio=self._is_finish_ratio
print(f'------------已下料比例: {self._is_finish_ratio}-------------')
# if self._is_finish_ratio>=1:
#关5秒
#大于0.7后不再检测了,直接交给视觉控制夹脚
# print(f'------------已下料比例: {self._is_finish_ratio}-------------')
# break
# print(f'------------已下料: {first_finish_weight+second_finish_weight}kg-------------')
time.sleep(0.5)
# initial_lower_weight=_current_lower_weight
print(f'------------已下料F: {first_finish_weight}kg-------------')
print(f'------------已下料F: {first_finish_weight}kg-------------')
# print(f'------------已完成-------------')
def run_feed(self):
"""第一阶段下料:下料斗向模具车下料(低速)"""
print("--------------------开始下料(普通块)--------------------")
self._time_mould_begin=datetime.now().strftime("%Y-%m-%d %H:%M:%S")
loc_relay=self.relay_feed
loc_mitter=self.transmitter_controller
max_weight_none=5
cur_weight_none=0
initial_lower_weight=self._init_lower_weight
# initial_upper_weight=loc_mitter.read_data(1)
first_finish_weight=0
self._mould_need_weight=1.91*2416
need_total_weight=self._mould_need_weight
if self._is_finish:
return
# start_time=None
self.state._feed_status=FeedStatus.FFeed1
self.state.vf_status=1
if initial_lower_weight>100:
self.is_start_visual=True
#下料斗的料全部下完
self._is_feed_stage=1
while not self._is_finish:
current_weight = loc_mitter.read_data(2)
if current_weight is None:
cur_weight_none+=1
if cur_weight_none>max_weight_none:
print("-----------下料斗重量异常(第一次下到模具车)--------------")
self.close_lower_door_visual()
return
continue
cur_weight_none=0
self.state._mould_finish_weight=initial_lower_weight-current_weight
self._is_finish_ratio= self.state._mould_finish_weight/need_total_weight
self.state._mould_finish_ratio=self._is_finish_ratio
print(f'------------已下料比例: {self._is_finish_ratio}-------------')
if current_weight<250 and current_weight>0:
# if current_weight>100:
#100,上面粘贴的,振动一下
# loc_relay.control_arch_lower_open_async(5)
self.close_lower_door_visual()
break
time.sleep(1)
self.is_start_visual=False
_current_lower_weight=loc_mitter.read_data(2)
if _current_lower_weight is None:
print("-------下料斗重量异常---------")
return
first_finish_weight=initial_lower_weight-_current_lower_weight
# initial_lower_weight=_current_lower_weight
print(f'------------已下料(第一次): {first_finish_weight}kg-------------')
print(f'------------已下料(第一次): {first_finish_weight}kg-------------')
self._is_feed_stage=0
while self.plc_data not in self.plc_valid_data:
#print('------------上料斗未就位----------------')
# print('------------上料斗未就位----------------')
time.sleep(1)
if self._is_finish:
return
if self.plc_data in self.plc_valid_data:
print(f'------------上料斗就位(上料斗往下料斗阶段)-------------')
#打开上料斗出砼门开5就开三分之一下
loc_relay.control_upper_open_sync(6)
self._is_feed_stage=2
loc_time_count=1
upper_open_time=time.time()
self.state._upper_door_closed=1
while not self._is_finish:
current_upper_weight = loc_mitter.read_data(1)
if current_upper_weight is None:
cur_weight_none+=1
if cur_weight_none>max_weight_none:
#如果重量连续5次为None认为上料斗未就位跳出循环
print('------------第一次上到下,上料斗重量异常----------------')
print('------------第一次上到下,上料斗重量异常----------------')
self.state._upper_door_closed=0
loc_relay.control_upper_close_sync(5+loc_time_count)
return
continue
cur_weight_none=0
_two_lower_weight=loc_mitter.read_data(2)
if _two_lower_weight is None:
_two_lower_weight=0
if (current_upper_weight<3200 and current_upper_weight>0) or _two_lower_weight>3200:
#关5秒,loc_time_count多关一秒
self.state._upper_door_closed=0
loc_relay.control_upper_close_sync(5+loc_time_count)
break
else:
if time.time()-upper_open_time>=4:
if loc_time_count<6:
upper_open_time=time.time()
loc_relay.control_upper_open_sync(0.8)
loc_time_count=loc_time_count+0.8
else:
time.sleep(0.5)
else:
loc_relay.control_upper_close_sync(6+loc_time_count)
self.state._upper_door_closed=0
if self._is_finish:
return
self.is_start_visual=True
initial_lower_weight=loc_mitter.read_data(2)
if initial_lower_weight is None:
print("-------下料斗重量异常(第二次下料到模具车)---------")
return
self._is_feed_stage=3
while not self._is_finish:
current_weight = loc_mitter.read_data(2)
if current_weight is None:
cur_weight_none+=1
if cur_weight_none>max_weight_none:
print("-------下料斗重量异常(第二次下料到模具车)---------")
self.close_lower_door_visual()
return
continue
cur_weight_none=0
self.state._mould_finish_weight=first_finish_weight+initial_lower_weight-current_weight
self._is_finish_ratio=self.state._mould_finish_weight/need_total_weight
self.state._mould_finish_ratio=self._is_finish_ratio
if current_weight<250:
# if current_weight>100:
#100,上面粘贴的,振动一下
# loc_relay.control_arch_lower_open_async(5)
self.close_lower_door_visual()
break
# print(f'------------已下料: {first_finish_weight+second_finish_weight}kg-------------')
time.sleep(0.5)
self.is_start_visual=False
_current_lower_weight=loc_mitter.read_data(2)
if _current_lower_weight is None:
print("-------下料斗重量异常(第二次下到模)---------")
return
first_finish_weight=first_finish_weight+initial_lower_weight-_current_lower_weight
print(f'------------已下料(第二次): {first_finish_weight}kg-------------')
print(f'------------已下料(第二次): {first_finish_weight}kg-------------')
if self._is_finish:
return
self._is_feed_stage=0
if self.plc_data in self.plc_valid_data:
self.state._upper_door_closed=2
#第二次上料斗向下料斗转移
loc_relay.control_upper_open_sync(12)
loc_time_count=1
upper_open_time=time.time()
upper_open_time_2=None
#第二次到下料斗还需要的量
#loc_left_need_weight=need_total_weight-first_finish_weight
#initial_upper_weight=loc_mitter.read_data(1)
#start_time=None
self._is_feed_stage=4
while not self._is_finish:
# print(f'------------上料斗向下料斗转移22222-------------')
current_upper_weight = loc_mitter.read_data(1)
if current_upper_weight is None:
cur_weight_none+=1
if cur_weight_none>max_weight_none:
#如果重量连续5次为None认为上料斗未就位跳出循环
print('------------第二次上到下,上料斗重量异常----------------')
print('------------第二次上到下,上料斗重量异常----------------')
self.state._upper_door_closed=0
loc_relay.control_upper_close_sync(15)
return
continue
cur_weight_none=0
if (current_upper_weight<600 and current_upper_weight>0) or upper_open_time_2 is not None:
if upper_open_time_2 is None:
upper_open_time_2=time.time()
if current_upper_weight<400 or time.time()-upper_open_time_2>5:
loc_relay.control_arch_upper_open_async(5)
# loc_relay.control_arch_upper_open()
loc_relay.control_upper_open_sync(5)
self.state._upper_door_closed=2
# start_time=None
#5秒后关闭
loc_relay.control_upper_close_after()#control_upper_close_sync(8+loc_time_count)
break
time.sleep(0.5)
else:
if time.time()-upper_open_time>=1:
# if loc_time_count<6:
upper_open_time=time.time()
loc_relay.control_upper_open_sync(1.2)
loc_time_count=loc_time_count+1
else:
time.sleep(0.5)
else:
loc_relay.control_upper_close_sync(15)
self.state._upper_door_closed=0
# time.sleep(0.4)
#第三次下料斗转移到模具车
if not self._is_finish:
self.is_start_visual=True
initial_lower_weight=loc_mitter.read_data(2)
self._finish_weight=first_finish_weight
self._inital_finish_lweight=initial_lower_weight
if initial_lower_weight is None:
print("-------下料斗重量异常(第三次下到模具车)---------")
return
self._is_feed_stage=5
while not self._is_finish:
current_weight = loc_mitter.read_data(2)
if current_weight is None:
cur_weight_none+=1
if cur_weight_none>max_weight_none:
#重量异常退出
print('------------第三次下到模具车,下料斗重量异常----------------')
self.close_lower_door_visual()
return
continue
cur_weight_none=0
second_finish_weight=initial_lower_weight-current_weight
self.state._mould_finish_weight=second_finish_weight+first_finish_weight
self._is_finish_ratio=self.state._mould_finish_weight/need_total_weight
self.state._mould_finish_ratio=self._is_finish_ratio
print(f'------------已下料比例: {self._is_finish_ratio}-------------')
# if self._is_finish_ratio>=1:
#关5秒
# print(f'------------已下料比例: {self._is_finish_ratio}-------------')
# break
# print(f'------------已下料: {first_finish_weight+second_finish_weight}kg-------------')
time.sleep(0.5)
# _current_lower_weight=loc_mitter.read_data(2)
# first_finish_weight=first_finish_weight+initial_lower_weight-_current_lower_weight
# print(f'------------已下料: {first_finish_weight}kg-------------')
# print(f'------------已下料: {first_finish_weight}kg-------------')
# print(f'------------已完成-------------')
def _process_angle_callback(self, current_angle, overflow_detected):
"""
实时精细控制 - 基于PID思想无固定间隔
"""
try:
# 记录控制时间戳(用于微分计算,而非限制)
current_time = time.time()
# 确保所有PID相关属性都被正确初始化
if not hasattr(self, '_last_control_time'):
self._last_control_time = current_time
if not hasattr(self, '_last_error'):
self._last_error = 0
if not hasattr(self, '_error_integral'):
self._error_integral = 0
# print(f"{self.angle_mode}")
self.overflow = overflow_detected in ["大堆料", "小堆料"]
if current_angle is None:
return
print(f"{datetime.now().strftime('%H:%M:%S.%f')[:-3]} 角度11: {current_angle:.2f}°,{overflow_detected},diff_f_val:{self._diff_f_val},diff_f_area:{self._diff_f_area}")
if self._is_small_f:
if self._is_finish_ratio>=1.02:
print('重量达到最大比例,浇筑满关闭')
self._visual_close()
return
elif self._is_finish_ratio>=0.9:
if (self._diff_f_val>=427 and self._diff_f_val<=450):
print('------------diff到达浇筑满-------------')
self._visual_close()
return
elif (len(self._diff_f_area)>0 and self._diff_f_area[-1]>=33400 and self._diff_f_area[-1]<=34500):
print('------------area到达浇筑满-------------')
self._visual_close()
return
else:
if self._is_finish_ratio>=1.01:
print('重量达到最大比例,浇筑满关闭')
self._visual_close()
return
elif self._is_finish_ratio>=0.93:
if (self._diff_f_val>=460 and self._diff_f_val<=510):
print('------------diff到达浇筑满-------------')
self._visual_close()
return
if (len(self._diff_f_area)>0 and self._diff_f_area[-1]>=38200 and self._diff_f_area[-1]<=41000):
print('------------area到达浇筑满-------------')
self._visual_close()
return
if overflow_detected == "未浇筑满" or self._is_before_finish:
if self._before_finish_time is None:
self._before_finish_time=current_time
self.safe_control_lower_close(1)
print('-----------------关闭(未浇筑满)--------------------')
# time.sleep(3)
else:
if not self._is_stop_one_seconds:
#根据角度来计算还需要多久完全关闭
if current_angle>=20:
self.safe_control_lower_close(2)
elif current_angle>=10 and current_angle<20:
self.safe_control_lower_close(1)
elif current_angle>=6 and current_angle<10:
self.safe_control_lower_close(0.5)
self._is_stop_one_seconds=True
elif current_angle>7:
#点动状态下如果关闭后角度大于7度关紧
self.safe_control_lower_close(0.2)
_open_time=0.3
_sleep_time=0.3
_close_time=0.5
if overflow_detected=='浇筑满':
if self._is_small_f:
self._visual_close()
return
else:
if self._diff_f_val>=410 and self._diff_f_val<450:
#排除这个范围的关闭
print(f'浇筑满状态diff_f_val:{self._diff_f_val},不关闭')
_open_time=0.5
_sleep_time=0.3
_close_time=0.7
else:
self._visual_close()
return
# print(f'--------已关闭已关闭-----------')
elif overflow_detected=="大堆料":
print(f'--------未浇筑满,大堆料-----------')
elif overflow_detected=="小堆料":
print(f'--------未浇筑满,小堆料-----------')
_open_time=0.5
_sleep_time=0.3
_close_time=0.7
else:
if self._is_small_f:
_open_time=0.6
_sleep_time=0.3
_close_time=0.8
else:
if self._is_finish_ratio<0.9:
_open_time=1
_sleep_time=0.3
_close_time=1.2
#之前慢的参数
# _open_time=0.8
# _sleep_time=0.3
# _close_time=1
elif self._is_finish_ratio<0.95 and self._is_finish_ratio>=0.9:
if self._point_weight>=10:
_open_time=0.7
_sleep_time=0.3
_close_time=0.9
else:
#之前慢的参数
# _open_time=0.8
# _sleep_time=0.3
# _close_time=1
_open_time=0.9
_sleep_time=0.3
_close_time=1.1
else:
_open_time=0.6
_sleep_time=0.3
_close_time=0.8
if self._point_speed_grade==1:
if _open_time>0.6:
_open_time=0.6
_sleep_time=0.3
_close_time=0.8
elif self._point_speed_grade==2:
if _open_time>0.5:
_open_time=0.5
_sleep_time=0.3
_close_time=0.7
elif self._point_speed_grade==3:
if _open_time>0.4:
_open_time=0.4
_sleep_time=0.3
_close_time=0.6
elif self._point_speed_grade==4:
if _open_time>0.3:
_open_time=0.3
_sleep_time=0.3
_close_time=0.5
_last_finish_ratio=self._is_finish_ratio
print(f'--------比例开始:{_last_finish_ratio}-----------')
self._pulse_control('open',_open_time)
time.sleep(_sleep_time)
self._pulse_control('close',_close_time)
print(f'--------比例结束:{self._is_finish_ratio}-----------')
self._point_weight=(self._is_finish_ratio-_last_finish_ratio)*self._mould_need_weight
print(f'--------流速:{self._point_weight}-----------')
if self._is_small_f:
time.sleep(2.5)
else:
# if self._is_finish_ratio>= 0.93:
# time.sleep(2)
# print('--------重量已到95.5%需要2秒休息-----------')
# else:
time.sleep(1)
#下得过快需要2秒休息
if self._point_weight>=65:
time.sleep(5)
self._point_speed_grade=4
elif self._point_weight>=50 and self._point_weight<65:
time.sleep(4)
self._point_speed_grade=3
elif self._point_weight>=35 and self._point_weight<50:
time.sleep(3)
self._point_speed_grade=2
elif self._point_weight>=25 and self._point_weight<35:
time.sleep(2)
self._point_speed_grade=1
elif self._point_weight>=15 and self._point_weight<25:
time.sleep(1)
self._point_speed_grade=0
else:
self._point_speed_grade=0
self._is_before_finish=True
if self._is_finish_ratio<=self._max_ignore_radio:
#如果重量未达到最大忽略角度,需要跳出
self._is_before_finish=False
return
elif overflow_detected == "浇筑满":
self._visual_close()
return
else:
self._before_finish_time=None
#2160KG
if self._is_finish_ratio>=0.85 and not self._is_small_f:
if overflow_detected == "大堆料":
TARGET_ANGLE = 5.0 # 大堆料时控制在15度左右
elif overflow_detected == "小堆料":
TARGET_ANGLE = 15.0 # 小堆料时控制在35度左右
else:
TARGET_ANGLE = 35.0 # 12.25由25--》35
elif (self._is_finish_ratio>0.7 and self._is_small_f):
if overflow_detected == "大堆料":
TARGET_ANGLE = 5.0 # 大堆料时控制在15度左右
elif overflow_detected == "小堆料":
TARGET_ANGLE = 15.0 # 小堆料时控制在35度左右
else:
TARGET_ANGLE = 35.0 # 12.25由25--》35
else:
if self._is_feed_stage==1 or self._is_feed_stage==3:
#根据溢料状态动态调整目标角度
if overflow_detected == "大堆料":
if not self.state._mould_vibrate_status:
TARGET_ANGLE = 15.0 # 临时控制变频器堆料时很小
else:
TARGET_ANGLE = 35.0 # 大堆料时控制在15度左右
elif overflow_detected == "小堆料":
TARGET_ANGLE = 55.0 # 小堆料时控制在35度左右
else:
TARGET_ANGLE = 55.0 # 未溢料时开到最大56度
else:
if self._is_small_f:
#根据溢料状态动态调整目标角度
if overflow_detected == "大堆料":
TARGET_ANGLE = 15.0 # 大堆料时控制在15度左右
elif overflow_detected == "小堆料":
TARGET_ANGLE = 25.0 # 小堆料时控制在35度左右
else:
TARGET_ANGLE = 45.0 # 未溢料时开到最大56度
else:
#根据溢料状态动态调整目标角度
if overflow_detected == "大堆料":
TARGET_ANGLE = 15.0 # 大堆料时控制在15度左右
elif overflow_detected == "小堆料":
TARGET_ANGLE = 55.0 # 小堆料时控制在35度左右
else:
TARGET_ANGLE = 55.0 # 未溢料时开到最大56度
# 确保目标角度在硬件范围内5-56度
TARGET_ANGLE = max(5.0, min(56.0, TARGET_ANGLE))
# PID控制参数
KP = 0.2 # 比例系数
KI = 0 # 积分系数
KD = 0 # 微分系数
# KP = 0.15 # 比例系数
# KI = 0.008 # 积分系数
# KD = 0.08 # 微分系数
# if TARGET_ANGLE <= 25.0:
# KP, KI, KD = 0.18, 0.008, 0.08 # 小角度,强控制
# elif TARGET_ANGLE <= 40.0:
# KP, KI, KD = 0.15, 0.01, 0.06 # 中角度
# else:
# KP, KI, KD = 0.12, 0.012, 0.04 # 大角度,温和控制
# 计算误差
error = current_angle - TARGET_ANGLE
dt = current_time - self._last_control_time
# 积分项(抗饱和)
self._error_integral += error * dt
self._error_integral = max(min(self._error_integral, 50), -50) # 积分限幅
# 微分项
error_derivative = (error - self._last_error) / dt if dt > 0 else 0
# PID输出
pid_output = (KP * error + KI * self._error_integral + KD * error_derivative)
#print(f"📊 PID计算: 误差={error:.2f}°, 积分={self._error_integral:.2f}, "
# f"微分={error_derivative:.2f}, 输出={pid_output:.2f}")
# 更新历史值
self._last_error = error
self._last_control_time = current_time
# 状态机 + PID控制
if self.angle_mode == "normal":
self._normal_mode_advanced(current_angle, pid_output,TARGET_ANGLE)
elif self.angle_mode == "reducing":
self._reducing_mode_advanced(current_angle, pid_output, TARGET_ANGLE)
elif self.angle_mode == "maintaining":
self._maintaining_mode_advanced(current_angle, pid_output, TARGET_ANGLE)
except Exception as e:
print("处理视觉回调时发生异常: ")
print("处理视觉回调时发生异常: ")
print("处理视觉回调时发生异常: ")
print(f"处理视觉回调时发生异常: {e}")
def _normal_mode_advanced(self, current_angle, pid_output,target_angle):
"""高级正常模式控制"""
if self.overflow:
self.angle_mode = "reducing"
print("检测到溢料,切换到减小模式")
return
# 🎯 修复1: 添加强制控制机制
# 基于PID输出的智能控制
control_threshold = 2 # 从2.0减小到0.5,提高灵敏度
if abs(pid_output) > control_threshold:
if pid_output > 0:
# 需要减小角度(关门)
pulse_time = min(0.3, pid_output * 0.1)
self._pulse_control("close", pulse_time)
print(f"正常模式: 角度偏高{pid_output:.1f},关门{pulse_time:.2f}")
else:
# 需要增大角度(开门)
pulse_time = min(0.3, abs(pid_output) * 0.1)
self._pulse_control("open", pulse_time)
print(f"正常模式: 角度偏低{abs(pid_output):.1f},开门{pulse_time:.2f}")
else:
# 在死区内,保持静止
error = current_angle - target_angle
abs_error = abs(error)
# 强制控制如果误差超过5度强制控制
if abs_error > 5:
if error > 0: # 当前角度 > 目标角度,需要关门
pulse_time=0.1 # 根据误差计算脉冲时间
self._pulse_control("close", pulse_time)
#print(f"🚨 强制关门: 误差{abs_error:.1f}°过大,脉冲{pulse_time:.3f}s")
else: # 当前角度 < 目标角度,需要开门
pulse_time =0.1
self._pulse_control("open", pulse_time)
#print(f"🚨 强制开门: 误差{abs_error:.1f}°过大,脉冲{pulse_time:.3f}s")
return
else:
self._stop_door()
print(f"正常模式: 角度在目标范围内,保持静止")
def _reducing_mode_advanced(self, current_angle, pid_output, target_angle):
"""高级减小模式控制"""
if not self.overflow:
if current_angle <= target_angle + 5.0:
self.angle_mode = "normal"
print("溢料消除且角度合适,返回正常模式")
else:
# 缓慢恢复
self._pulse_control("close", 0.1)
return
# 有溢料,积极减小角度
if current_angle > target_angle:
# 使用PID输出计算控制量
pulse_time = min(0.5, max(0.1, pid_output * 0.15))
self._pulse_control("close", pulse_time)
# print(f"减小模式: 积极关门{pulse_time:.2f}秒PID输出:{pid_output:.1f}")
else:
self.angle_mode = "maintaining"
print("角度已达标,进入维持模式")
def _maintaining_mode_advanced(self, current_angle, pid_output, target_angle):
"""高级维持模式控制"""
if not self.overflow:
self.angle_mode = "normal"
print("溢料消除,返回正常模式")
return
# 精确维持控制
dead_zone = 1.5 # 更小的死区
if abs(pid_output) > dead_zone:
pulse_time = min(0.2, abs(pid_output) * 0.05) # 更精细的控制
if pid_output > 0:
self._pulse_control("close", pulse_time)
print(f"维持模式: 微调关门{pulse_time:.2f}")
else:
self._pulse_control("open", pulse_time)
print(f"维持模式: 微调开门{pulse_time:.2f}")
else:
self._stop_door()
print("维持模式: 角度精确控制中")
def _pulse_control(self, action, duration):
"""统一的脉冲控制方法"""
# 检查是否正在执行safe_control_lower_close如果是则跳过relay操作
if self._is_safe_closing:
thread_name = threading.current_thread().name
print(f"[{thread_name}] safe_control_lower_close正在执行跳过脉冲控制 {action}")
return
if duration <= 0:
return
thread_name = threading.current_thread().name
#print(f"[{thread_name}] 尝试脉冲控制 {action},时长 {duration:.2f}秒...")
with self._door_control_lock:
self._current_controlling_thread = thread_name
# print(f"[{thread_name}] 获得下料斗控制权,执行脉冲控制")
if action == "open":
self.relay_controller.control(self.relay_controller.DOOR_LOWER_CLOSE, 'close')
self.relay_controller.control(self.relay_controller.DOOR_LOWER_OPEN, 'open')
time.sleep(duration)
self.relay_controller.control(self.relay_controller.DOOR_LOWER_OPEN, 'close')
print(f"[{thread_name}] 开门脉冲: {duration:.2f}")
else: # close
self.relay_controller.control(self.relay_controller.DOOR_LOWER_OPEN, 'close')
self.relay_controller.control(self.relay_controller.DOOR_LOWER_CLOSE, 'open')
time.sleep(duration)
self.relay_controller.control(self.relay_controller.DOOR_LOWER_CLOSE, 'close')
print(f"[{thread_name}] 关门脉冲: {duration:.2f}")
self._current_controlling_thread = None
#print(f"[{thread_name}] 释放下料斗控制权")
def _stop_door(self):
"""停止门运动"""
# 检查是否正在执行safe_control_lower_close如果是则跳过relay操作
if self._is_safe_closing:
thread_name = threading.current_thread().name
print(f"[{thread_name}] safe_control_lower_close正在执行跳过停止门运动操作")
return
thread_name = threading.current_thread().name
#print(f"[{thread_name}] 尝试停止门运动...")
with self._door_control_lock:
self._current_controlling_thread = thread_name
#print(f"[{thread_name}] 获得下料斗控制权,执行停止操作")
self.relay_controller.control(self.relay_controller.DOOR_LOWER_OPEN, 'close')
self.relay_controller.control(self.relay_controller.DOOR_LOWER_CLOSE, 'close')
self._current_controlling_thread = None
#print(f"[{thread_name}] 释放下料斗控制权")
def _open_door(self, duration=0.5):
"""打开门"""
self._pulse_control("open", 0.3)
def _close_door(self, duration=0.5):
"""关闭门"""
self._pulse_control("close", 1)
def on_plc_update(self,data: int, binary: str):
#4即将振捣室5振捣室 64即将搅拌楼 66到达搅拌楼
# print(f"[数据回调] 数值: 0x{data:02X} | 十进制: {data:3d} | 二进制: {binary}")
self.plc_data=data
if self.plc_data in self.plc_valid_data:
if self.state._upper_door_position!=Upper_Door_Position.ZDS:
self.state._upper_door_position=Upper_Door_Position.ZDS
self.relay_controller.control(self.relay_controller.UPPER_TO_ZD, 'close')
elif self.plc_data in self.plc_valid_data_jbl:
if self.state._upper_door_position!=Upper_Door_Position.JBL:
self.state._upper_door_position=Upper_Door_Position.JBL
self.relay_controller.control(self.relay_controller.UPPER_TO_JBL, 'close')
else:
if self.state._upper_door_position!=Upper_Door_Position.Returning:
self.state._upper_door_position=Upper_Door_Position.Returning
# @classmethod
# def instance_exists(cls):
"""检测实例是否存在"""
# return cls._instance is not None
def shutdown(self):
"""关闭线程,清理资源"""
# 设置停止事件
self._stop_event.set()
# 唤醒线程以便它能检测到停止事件
self._new_data_available.set()
self._is_running=False
self._is_finish=True
self.is_start_visual=False
# #关闭下料斗
# self.safe_control_lower_close()
# 等待线程结束
if self.callback_thread and self.callback_thread.is_alive():
self.callback_thread.join(timeout=1.0)
if self.diff_thread and self.diff_thread.is_alive():
self.diff_thread.join(timeout=1.0)
def get_current_mould(self):
"""获取当前要浇筑的管片"""
# if self.state.pd_status==PD_StatusEnum.PD_Ready:
# self.state.pd_status=PD_StatusEnum.PD_TimeOut
_not_poured=app_web_service.get_not_pour_artifacts()
if _not_poured is not None and len(_not_poured)>=1:
_cur_poured_model=_not_poured[-1]
if _cur_poured_model.MouldCode:
self._cur_mould_model=_cur_poured_model
# self.state.current_mould=_cur_poured_model
# self.state.current_block_number=CoreUtils.get_number_by_mould_code(_cur_poured_model.MouldCode)
print(f'当前要浇筑的管片 {json.dumps(asdict(_cur_poured_model), ensure_ascii=False)}')
else:
self._cur_mould_model=None
# self.state.current_mould=None
# self.state.current_block_number=''
print('当前没有未浇筑的管片')
def __del__(self):
"""析构函数,确保线程安全关闭"""
self.shutdown()
# 创建默认实例
# visual_callback_instance = VisualCallback()
# 兼容层,保持原来的函数调用方式可用
# def angle_visual_callback(current_angle, overflow_detected):
# """
# 兼容旧版本的函数调用方式
# 将调用转发到默认实例的angle_visual_callback方法
# """
# visual_callback_instance.angle_visual_callback(current_angle, overflow_detected)