1228
This commit is contained in:
@ -58,6 +58,22 @@ class ArtifactBll:
|
|||||||
"OptTime": datetime.now(),
|
"OptTime": datetime.now(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def insert_artifact_bycode(self,model: dict) -> bool:
|
||||||
|
|
||||||
|
"""根据模具编号插入管片任务"""
|
||||||
|
if self.dal.exists_by_module_code(model["MouldCode"]):
|
||||||
|
return False
|
||||||
|
return self.dal.insert_artifact({
|
||||||
|
"MouldCode": model["MouldCode"],
|
||||||
|
"SizeSpecification": model["SizeSpecification"],
|
||||||
|
"BlockNumber": model["BlockNumber"],
|
||||||
|
"BetonVolume": model["BetonVolume"],
|
||||||
|
"PStatus":1,
|
||||||
|
"Status": 2,
|
||||||
|
"Source": 2,
|
||||||
|
"OptTime": datetime.now(),
|
||||||
|
})
|
||||||
|
|
||||||
def get_artifacting_task(self) -> ArtifactInfoModel:
|
def get_artifacting_task(self) -> ArtifactInfoModel:
|
||||||
"""获取正在进行的管片任务数据"""
|
"""获取正在进行的管片任务数据"""
|
||||||
loc_item= self.dal.get_top_artifact(1,"ID desc","Status=2")
|
loc_item= self.dal.get_top_artifact(1,"ID desc","Status=2")
|
||||||
|
|||||||
@ -16,7 +16,7 @@ class BaseDal:
|
|||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
"""初始化数据访问层,创建数据库连接"""
|
"""初始化数据访问层,创建数据库连接"""
|
||||||
# 假设数据库文件在db目录下
|
# 假设数据库文件在db目录下
|
||||||
self.db_dao = SQLiteHandler.get_instance("db/three.db", max_readers=50, busy_timeout=4000)
|
self.db_dao = SQLiteHandler.get_instance("../db/three.db", max_readers=50, busy_timeout=4000)
|
||||||
|
|
||||||
class ArtifactDal(BaseDal):
|
class ArtifactDal(BaseDal):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -98,6 +98,21 @@ class ArtifactDal(BaseDal):
|
|||||||
print(f"根据ID获取构件任务失败: {e}")
|
print(f"根据ID获取构件任务失败: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def exists_by_module_code(self, module_code: str) -> bool:
|
||||||
|
"""根据模具编号获取构件任务"""
|
||||||
|
try:
|
||||||
|
sql = "SELECT count(1) FROM ArtifactTask WHERE MouldCode = ? and OptTime>?"
|
||||||
|
results = self.db_dao.execute_read(sql, (module_code,datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)))
|
||||||
|
|
||||||
|
rows = list(results)
|
||||||
|
if rows[0][0] == 1:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"根据ID获取构件任务失败: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
def get_by_id(self, artifact_id: int) -> Optional[ArtifactInfoModel]:
|
def get_by_id(self, artifact_id: int) -> Optional[ArtifactInfoModel]:
|
||||||
"""根据构件ID获取构件任务"""
|
"""根据构件ID获取构件任务"""
|
||||||
try:
|
try:
|
||||||
|
|||||||
BIN
db/three.db
BIN
db/three.db
Binary file not shown.
BIN
db/three.db-shm
Normal file
BIN
db/three.db-shm
Normal file
Binary file not shown.
BIN
db/three.db-wal
Normal file
BIN
db/three.db-wal
Normal file
Binary file not shown.
BIN
doc/浇筑系统对接接口文档-20251223.doc
Normal file
BIN
doc/浇筑系统对接接口文档-20251223.doc
Normal file
Binary file not shown.
@ -384,7 +384,7 @@ class rfid_service:
|
|||||||
接收线程的主循环,用于接收RFID推送的数据
|
接收线程的主循环,用于接收RFID推送的数据
|
||||||
"""
|
"""
|
||||||
while self._thread_signal:
|
while self._thread_signal:
|
||||||
self._pause_receive=False
|
# self._pause_receive=False
|
||||||
if self._pause_receive:
|
if self._pause_receive:
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
continue
|
continue
|
||||||
@ -409,11 +409,11 @@ class rfid_service:
|
|||||||
|
|
||||||
received_data += chunk
|
received_data += chunk
|
||||||
remaining_bytes -= len(chunk)
|
remaining_bytes -= len(chunk)
|
||||||
print(f"[数据接收] 已接收 {len(received_data)}/{self._buffer_length} 字节")
|
# print(f"[数据接收] 已接收 {len(received_data)}/{self._buffer_length} 字节")
|
||||||
|
|
||||||
# 只有接收到完整的数据才算成功
|
# 只有接收到完整的数据才算成功
|
||||||
if remaining_bytes == 0:
|
if remaining_bytes == 0:
|
||||||
print(f"[数据接收] 成功接收完整数据包 ({self._buffer_length} 字节)")
|
# print(f"[数据接收] 成功接收完整数据包 ({self._buffer_length} 字节)")
|
||||||
data = received_data # 保存完整的数据包
|
data = received_data # 保存完整的数据包
|
||||||
self._error_count=0
|
self._error_count=0
|
||||||
else:
|
else:
|
||||||
@ -443,13 +443,13 @@ class rfid_service:
|
|||||||
|
|
||||||
if data:
|
if data:
|
||||||
loc_str = command_hex.parse_user_data_hex(data)
|
loc_str = command_hex.parse_user_data_hex(data)
|
||||||
raw_data = binascii.hexlify(data).decode()
|
# raw_data = binascii.hexlify(data).decode()
|
||||||
print(f"收到RFID推送数据: {raw_data}")
|
# print(f"收到RFID推送数据: {raw_data}")
|
||||||
|
|
||||||
# 保存到文件
|
# 保存到文件
|
||||||
with open('rfid_data.log', 'a') as f:
|
# with open('rfid_data.log', 'a') as f:
|
||||||
timestamp = datetime.now().strftime('%H:%M:%S.%f')[:-3]
|
# timestamp = datetime.now().strftime('%H:%M:%S.%f')[:-3]
|
||||||
f.write(f"[{timestamp}] 解析数据: {loc_str}, 原始数据: {raw_data}\n")
|
# f.write(f"[{timestamp}] 解析数据: {loc_str}, 原始数据: {raw_data}\n")
|
||||||
|
|
||||||
if loc_str:
|
if loc_str:
|
||||||
# 将数据添加到缓冲区
|
# 将数据添加到缓冲区
|
||||||
@ -514,6 +514,7 @@ class rfid_service:
|
|||||||
"""
|
"""
|
||||||
停止接收RFID推送的数据
|
停止接收RFID推送的数据
|
||||||
"""
|
"""
|
||||||
|
print('RFID 线程停止')
|
||||||
self._thread_signal = False
|
self._thread_signal = False
|
||||||
if self._receive_thread:
|
if self._receive_thread:
|
||||||
self._receive_thread.join(timeout=2.0)
|
self._receive_thread.join(timeout=2.0)
|
||||||
|
|||||||
@ -73,7 +73,7 @@ class RelayController:
|
|||||||
sock.connect((self.host, self.port))
|
sock.connect((self.host, self.port))
|
||||||
sock.send(byte_data)
|
sock.send(byte_data)
|
||||||
response = sock.recv(1024)
|
response = sock.recv(1024)
|
||||||
print(f"收到继电器响应: {binascii.hexlify(response)}")
|
# print(f"收到继电器响应: {binascii.hexlify(response)}")
|
||||||
return response
|
return response
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"继电器通信错误: {e}")
|
print(f"继电器通信错误: {e}")
|
||||||
@ -97,7 +97,7 @@ class RelayController:
|
|||||||
def control(self, device, action):
|
def control(self, device, action):
|
||||||
"""控制继电器"""
|
"""控制继电器"""
|
||||||
if device in self.relay_commands and action in self.relay_commands[device]:
|
if device in self.relay_commands and action in self.relay_commands[device]:
|
||||||
print(f"发送控制继电器命令 {device} {action}")
|
# print(f"发送控制继电器命令 {device} {action}")
|
||||||
self.send_command(self.relay_commands[device][action])
|
self.send_command(self.relay_commands[device][action])
|
||||||
else:
|
else:
|
||||||
print(f"无效设备或动作: {device}, {action}")
|
print(f"无效设备或动作: {device}, {action}")
|
||||||
@ -110,6 +110,13 @@ class RelayController:
|
|||||||
# 异步5秒后关闭
|
# 异步5秒后关闭
|
||||||
threading.Thread(target=self._close_upper_s, daemon=True,name="close_upper_s").start()
|
threading.Thread(target=self._close_upper_s, daemon=True,name="close_upper_s").start()
|
||||||
|
|
||||||
|
def control_upper_close_after(self):
|
||||||
|
"""控制上料斗关在几秒后"""
|
||||||
|
# 关闭上料斗出砼门
|
||||||
|
self.control(self.DOOR_UPPER_OPEN, 'close')
|
||||||
|
# 异步5秒后关闭
|
||||||
|
threading.Thread(target=self._close_upper_after_s, daemon=True,name="close_upper_after_s").start()
|
||||||
|
|
||||||
def control_upper_close_sync(self,duration=5):
|
def control_upper_close_sync(self,duration=5):
|
||||||
self.control(self.DOOR_UPPER_OPEN, 'close')
|
self.control(self.DOOR_UPPER_OPEN, 'close')
|
||||||
self.control(self.DOOR_UPPER_CLOSE, 'open')
|
self.control(self.DOOR_UPPER_CLOSE, 'open')
|
||||||
@ -224,6 +231,24 @@ class RelayController:
|
|||||||
self.control(self.DOOR_UPPER_CLOSE, 'close')
|
self.control(self.DOOR_UPPER_CLOSE, 'close')
|
||||||
print("上料斗关闭完成")
|
print("上料斗关闭完成")
|
||||||
|
|
||||||
|
def _close_upper_after_s(self):
|
||||||
|
"""
|
||||||
|
异步5秒后关闭上料斗20秒
|
||||||
|
"""
|
||||||
|
|
||||||
|
# time.sleep(5)
|
||||||
|
self.control_arch_upper_open_sync(5)
|
||||||
|
self.control(self.DOOR_UPPER_CLOSE, 'open')
|
||||||
|
time.sleep(1)
|
||||||
|
self.control(self.DOOR_UPPER_CLOSE, 'close')
|
||||||
|
self.control_arch_upper_open_sync(5)
|
||||||
|
self.control_arch_upper_open_sync(5)
|
||||||
|
self.control_arch_upper_open_async(8)
|
||||||
|
self.control(self.DOOR_UPPER_CLOSE, 'open')
|
||||||
|
time.sleep(20)
|
||||||
|
self.control(self.DOOR_UPPER_CLOSE, 'close')
|
||||||
|
print("上料斗关闭完成")
|
||||||
|
|
||||||
def _close_lower_5s(self):
|
def _close_lower_5s(self):
|
||||||
time.sleep(6)
|
time.sleep(6)
|
||||||
self.control(self.DOOR_LOWER_CLOSE, 'close')
|
self.control(self.DOOR_LOWER_CLOSE, 'close')
|
||||||
@ -238,19 +263,40 @@ class RelayController:
|
|||||||
self.control(self.BREAK_ARCH_LOWER, 'open')
|
self.control(self.BREAK_ARCH_LOWER, 'open')
|
||||||
# 异步5秒后关闭
|
# 异步5秒后关闭
|
||||||
threading.Thread(target=self._close_break_arch_lower, daemon=True,name="_close_break_arch_lower").start()
|
threading.Thread(target=self._close_break_arch_lower, daemon=True,name="_close_break_arch_lower").start()
|
||||||
|
|
||||||
|
def control_arch_lower_open_sync(self,duration):
|
||||||
|
"""控制下料斗振动"""
|
||||||
|
self.control(self.BREAK_ARCH_LOWER, 'open')
|
||||||
|
# 异步5秒后关闭
|
||||||
|
time.sleep(duration)
|
||||||
|
self.control(self.BREAK_ARCH_LOWER, 'close')
|
||||||
|
|
||||||
|
def control_arch_upper_open_sync(self,duration):
|
||||||
|
"""控制下料斗振动"""
|
||||||
|
self.control(self.BREAK_ARCH_UPPER, 'open')
|
||||||
|
# 异步5秒后关闭
|
||||||
|
time.sleep(duration)
|
||||||
|
self.control(self.BREAK_ARCH_UPPER, 'close')
|
||||||
|
|
||||||
def _close_break_arch_lower(self):
|
def _close_break_arch_lower(self):
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
self.control(self.BREAK_ARCH_LOWER, 'close')
|
self.control(self.BREAK_ARCH_LOWER, 'close')
|
||||||
|
|
||||||
|
|
||||||
def control_arch_upper_open(self):
|
def control_arch_upper_open_async(self,delay_seconds: float = 15):
|
||||||
"""控制上料斗关"""
|
"""异步控制上料斗振动
|
||||||
|
|
||||||
|
Args:
|
||||||
|
delay_seconds: 延迟关闭时间(秒),默认15秒
|
||||||
|
"""
|
||||||
# 关闭下料斗出砼门
|
# 关闭下料斗出砼门
|
||||||
self.control(self.BREAK_ARCH_UPPER, 'open')
|
self.control(self.BREAK_ARCH_UPPER, 'open')
|
||||||
# 异步5秒后关闭
|
# 异步5秒后关闭
|
||||||
threading.Thread(target=self._close_break_arch_upper, daemon=True,name="_close_break_arch_upper").start()
|
threading.Thread(target=lambda d: self._close_break_arch_upper(delay_seconds),args=(delay_seconds,), daemon=True, name="_close_break_arch_upper").start()
|
||||||
def _close_break_arch_upper(self):
|
|
||||||
time.sleep(3)
|
def _close_break_arch_upper(self, delay_seconds: float = 15):
|
||||||
|
time.sleep(delay_seconds)
|
||||||
|
print(f"上料斗振动关闭完成,延迟{delay_seconds}秒")
|
||||||
self.control(self.BREAK_ARCH_UPPER, 'close')
|
self.control(self.BREAK_ARCH_UPPER, 'close')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -80,7 +80,7 @@ class TransmitterController:
|
|||||||
self.relay_controller.modbus_client.close()
|
self.relay_controller.modbus_client.close()
|
||||||
|
|
||||||
# 直接读取 变送器返回的数据并解析
|
# 直接读取 变送器返回的数据并解析
|
||||||
def read_data_normal(self, transmitter_id):
|
def read_data_sub(self, transmitter_id):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Args: transmitter_id 为1 表示上料斗, 为2 表示下料斗
|
Args: transmitter_id 为1 表示上料斗, 为2 表示下料斗
|
||||||
@ -90,7 +90,7 @@ class TransmitterController:
|
|||||||
BUFFER_SIZE= 1024
|
BUFFER_SIZE= 1024
|
||||||
IP = None
|
IP = None
|
||||||
PORT = None
|
PORT = None
|
||||||
weight = 0
|
weight = None
|
||||||
if transmitter_id == 1:
|
if transmitter_id == 1:
|
||||||
# 上料斗变送器的信息:
|
# 上料斗变送器的信息:
|
||||||
IP = ini_manager.upper_transmitter_ip
|
IP = ini_manager.upper_transmitter_ip
|
||||||
@ -102,7 +102,7 @@ class TransmitterController:
|
|||||||
|
|
||||||
if not IP or not PORT:
|
if not IP or not PORT:
|
||||||
print(f"未配置变送器 {transmitter_id} 的IP或PORT")
|
print(f"未配置变送器 {transmitter_id} 的IP或PORT")
|
||||||
return 0
|
return None
|
||||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||||
try:
|
try:
|
||||||
s.settimeout(TIMEOUT)
|
s.settimeout(TIMEOUT)
|
||||||
@ -134,7 +134,7 @@ class TransmitterController:
|
|||||||
# 成功返回重量(int),失败返回None
|
# 成功返回重量(int),失败返回None
|
||||||
return weight
|
return weight
|
||||||
|
|
||||||
def read_data(self, transmitter_id):
|
def read_data_sub_test(self, transmitter_id):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
测试用:模拟读取变送器数据mock
|
测试用:模拟读取变送器数据mock
|
||||||
@ -267,3 +267,15 @@ class TransmitterController:
|
|||||||
# print(f"数据解析失败:{e},原始数据包:{packet_data}")
|
# print(f"数据解析失败:{e},原始数据包:{packet_data}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def read_data(self,transmitter_id):
|
||||||
|
"""获取重量函数:根据变送器ID获取当前重量,三次"""
|
||||||
|
max_try_times=5
|
||||||
|
try_times=0
|
||||||
|
while try_times<max_try_times:
|
||||||
|
weight=self.read_data_sub(transmitter_id)
|
||||||
|
if weight is not None:
|
||||||
|
return weight
|
||||||
|
try_times+=1
|
||||||
|
print(f'-----获取重量异常-------------- transmitter_id: {transmitter_id}')
|
||||||
|
print(f'-----获取重量异常-------------- transmitter_id: {transmitter_id}')
|
||||||
|
return None
|
||||||
31
test_dal_debug.py
Normal file
31
test_dal_debug.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
from busisness.dals import ArtifactDal
|
||||||
|
|
||||||
|
# 测试 exists_by_module_code 方法
|
||||||
|
dal = ArtifactDal()
|
||||||
|
|
||||||
|
# 测试1: 不存在的模具编号
|
||||||
|
print("=== 测试1: 不存在的模具编号 ===")
|
||||||
|
result = dal.exists_by_module_code("不存在的模具编号")
|
||||||
|
print(f"结果: {result}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# 测试2: 存在的模具编号(如果有数据的话)
|
||||||
|
print("=== 测试2: 存在的模具编号 ===")
|
||||||
|
result = dal.exists_by_module_code("TEST001")
|
||||||
|
print(f"结果: {result}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# 测试3: 直接查询数据库验证
|
||||||
|
print("=== 测试3: 直接SQL查询验证 ===")
|
||||||
|
db_dao = dal.db_dao
|
||||||
|
sql = "SELECT count(1) as cnt FROM ArtifactTask WHERE MouldCode = ?"
|
||||||
|
results = db_dao.execute_read(sql, ("不存在的模具编号",))
|
||||||
|
print(f"查询结果类型: {type(results)}")
|
||||||
|
print(f"查询结果: {results}")
|
||||||
|
rows = list(results)
|
||||||
|
print(f"rows: {rows}")
|
||||||
|
if rows:
|
||||||
|
print(f"rows[0]: {rows[0]}")
|
||||||
|
print(f"rows[0][0]: {rows[0][0]}")
|
||||||
|
else:
|
||||||
|
print("rows为空列表")
|
||||||
@ -1,16 +1,10 @@
|
|||||||
# main.py
|
# main.py
|
||||||
import time
|
import time
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from config.settings import app_set_config
|
|
||||||
from core.system import FeedingControlSystem
|
|
||||||
from hardware import relay
|
from hardware import relay
|
||||||
from hardware.relay import RelayController
|
from hardware.relay import RelayController
|
||||||
from hardware.transmitter import TransmitterController
|
from hardware.transmitter import TransmitterController
|
||||||
import threading
|
|
||||||
import time
|
import time
|
||||||
import cv2
|
|
||||||
import os
|
|
||||||
from core.state import FeedStatus
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|||||||
@ -6,25 +6,55 @@ import os
|
|||||||
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
import time
|
import time
|
||||||
from hardware.RFID.rfid_service import rfid_service
|
from hardware.RFID.rfid_service import rfid_service
|
||||||
|
from busisness.blls import ArtifactBll
|
||||||
|
from busisness.models import ArtifactInfoModel
|
||||||
|
|
||||||
|
|
||||||
|
rfid=None
|
||||||
def test_data_callback(status,raw_data):
|
rfid_before_mould=''
|
||||||
|
artifact_bll=ArtifactBll()
|
||||||
|
def test_data_callback(status,data):
|
||||||
"""
|
"""
|
||||||
测试用的数据接收回调函数
|
测试用的数据接收回调函数
|
||||||
"""
|
"""
|
||||||
if status:
|
global rfid_before_mould
|
||||||
print(f"[回调] 收到RFID数据: {raw_data}")
|
try:
|
||||||
|
if status==1:
|
||||||
|
#成功读取到RFID标签
|
||||||
|
#检查标识是否符号要求
|
||||||
|
if data:
|
||||||
|
loc_array=data.strip(',').split(',')
|
||||||
|
if len(loc_array)==4:
|
||||||
|
if rfid_before_mould!=loc_array[0]:
|
||||||
|
model={
|
||||||
|
'MouldCode':loc_array[0],
|
||||||
|
'BlockNumber':loc_array[1],
|
||||||
|
'SizeSpecification':loc_array[2],
|
||||||
|
'BetonVolume':loc_array[3]
|
||||||
|
}
|
||||||
|
artifact_bll.insert_artifact_bycode(model)
|
||||||
|
rfid_before_mould=loc_array[0]
|
||||||
|
print(f"RFID-生产模具车号:{loc_array[0]}")
|
||||||
else:
|
else:
|
||||||
print(f"[回调] 读取RFID数据为空或失败")
|
print(f"RFID-重复生产模具车号:{loc_array[0]}")
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("RFID标签格式错误")
|
||||||
|
print(f"成功读取到RFID标签:{data}")
|
||||||
|
else:
|
||||||
|
self.rfid_flag_succ=False
|
||||||
|
print("读取RFID标签失败")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"RFID回调处理异常: {e}")
|
||||||
|
|
||||||
|
|
||||||
def test_rfid_functions():
|
def test_rfid_functions():
|
||||||
"""
|
"""
|
||||||
测试RFIDHardware的主要功能
|
测试RFIDHardware的主要功能
|
||||||
"""
|
"""
|
||||||
|
global rfid
|
||||||
# 初始化RFID控制器
|
# 初始化RFID控制器
|
||||||
rfid = rfid_service(host='192.168.250.77', port=6000)
|
rfid = rfid_service(host='192.168.250.67', port=6000)
|
||||||
|
|
||||||
# print("=== RFID硬件测试开始 ===")
|
# print("=== RFID硬件测试开始 ===")
|
||||||
|
|
||||||
@ -97,20 +127,37 @@ def test_rfid_functions():
|
|||||||
# rfid._data_buffer.append('THR B1-12,B1,6600 * 1500,1.900')
|
# rfid._data_buffer.append('THR B1-12,B1,6600 * 1500,1.900')
|
||||||
# rfid._process_collected_data()
|
# rfid._process_collected_data()
|
||||||
rfid.start_receiver(callback=test_data_callback)
|
rfid.start_receiver(callback=test_data_callback)
|
||||||
|
while True:
|
||||||
|
rfid._pause_receive = False
|
||||||
|
time.sleep(10)
|
||||||
|
|
||||||
|
|
||||||
# print("接收线程已启动,等待接收数据...")
|
# print("接收线程已启动,等待接收数据...")
|
||||||
# 等待5秒模拟接收过程1111111111111
|
# 等待5秒模拟接收过程1111111111111
|
||||||
time.sleep(60*60)
|
time.sleep(60*60)
|
||||||
finally:
|
finally:
|
||||||
# 确保停止接收线程
|
# 确保停止接收线程
|
||||||
# rfid.stop_receiver()
|
rfid.stop_receiver()
|
||||||
|
|
||||||
print("\n=== RFID硬件测试结束 ===")
|
# print("\n=== RFID硬件测试结束 ===")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
try:
|
try:
|
||||||
|
# model={
|
||||||
|
# 'ArtifactID':0,
|
||||||
|
# 'MouldCode':'SHR2B1-4',
|
||||||
|
# 'BlockNumber':'B2',
|
||||||
|
# 'SizeSpecification':'6600*1500',
|
||||||
|
# 'BetonVolume':1.910
|
||||||
|
# }
|
||||||
|
# artifact_bll.insert_artifact_bycode(model)
|
||||||
test_rfid_functions()
|
test_rfid_functions()
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
if rfid is not None:
|
||||||
|
rfid.stop_receiver()
|
||||||
print("\n测试被用户中断")
|
print("\n测试被用户中断")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
if rfid is not None:
|
||||||
|
rfid.stop_receiver()
|
||||||
print(f"测试过程中发生错误: {e}")
|
print(f"测试过程中发生错误: {e}")
|
||||||
120
vision/muju_cls/main.py
Normal file
120
vision/muju_cls/main.py
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
import os
|
||||||
|
import cv2
|
||||||
|
from rknnlite.api import RKNNLite
|
||||||
|
|
||||||
|
# classify_single_image, StableClassJudge, CLASS_NAMES 已在 muju_cls_rknn 中定义
|
||||||
|
from muju_cls_rknn import classify_single_image, StableClassJudge, CLASS_NAMES
|
||||||
|
|
||||||
|
|
||||||
|
def run_stable_classification_loop(
|
||||||
|
model_path,
|
||||||
|
roi_file,
|
||||||
|
image_source,
|
||||||
|
stable_frames=3,
|
||||||
|
display_scale=0.5, # 显示缩放比例(0.5 = 显示为原来 50%)
|
||||||
|
show_window=False # 是否显示窗口
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
image_source: cv2.VideoCapture 对象
|
||||||
|
"""
|
||||||
|
|
||||||
|
judge = StableClassJudge(
|
||||||
|
stable_frames=stable_frames,
|
||||||
|
ignore_class=2 # 忽略“有遮挡”类别参与稳定判断
|
||||||
|
)
|
||||||
|
|
||||||
|
cap = image_source
|
||||||
|
if not hasattr(cap, "read"):
|
||||||
|
raise TypeError("image_source 必须是 cv2.VideoCapture 实例")
|
||||||
|
|
||||||
|
# 可选:创建可缩放窗口
|
||||||
|
if show_window:
|
||||||
|
cv2.namedWindow("RTSP Stream - Press 'q' to quit", cv2.WINDOW_NORMAL)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
ret, frame = cap.read()
|
||||||
|
if not ret:
|
||||||
|
print("无法读取视频帧(可能是流断开或结束)")
|
||||||
|
break
|
||||||
|
|
||||||
|
# 上下左右翻转
|
||||||
|
frame = cv2.flip(frame, -1)
|
||||||
|
|
||||||
|
# ---------------------------
|
||||||
|
# 单帧推理
|
||||||
|
# ---------------------------
|
||||||
|
result = classify_single_image(frame, model_path, roi_file)
|
||||||
|
|
||||||
|
class_id = result["class_id"]
|
||||||
|
class_name = result["class"]
|
||||||
|
score = result["score"]
|
||||||
|
|
||||||
|
print(f"[FRAME] {class_name} | conf={score:.3f}")
|
||||||
|
|
||||||
|
# ---------------------------
|
||||||
|
# 稳定判断
|
||||||
|
# ---------------------------
|
||||||
|
stable_class_id = judge.update(class_id)
|
||||||
|
|
||||||
|
if stable_class_id is not None:
|
||||||
|
print(f"\n稳定输出: {CLASS_NAMES[stable_class_id]}\n")
|
||||||
|
|
||||||
|
# ---------------------------
|
||||||
|
# 显示画面(缩小窗口)
|
||||||
|
# ---------------------------
|
||||||
|
if show_window:
|
||||||
|
h, w = frame.shape[:2]
|
||||||
|
display_frame = cv2.resize(
|
||||||
|
frame,
|
||||||
|
(int(w * display_scale), int(h * display_scale)),
|
||||||
|
interpolation=cv2.INTER_AREA
|
||||||
|
)
|
||||||
|
|
||||||
|
cv2.imshow("RTSP Stream - Press 'q' to quit", display_frame)
|
||||||
|
|
||||||
|
if cv2.waitKey(1) & 0xFF == ord('q'):
|
||||||
|
break
|
||||||
|
|
||||||
|
cap.release()
|
||||||
|
cv2.destroyAllWindows()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# ---------------------------
|
||||||
|
# 配置参数
|
||||||
|
# ---------------------------
|
||||||
|
MODEL_PATH = "muju_cls.rknn"
|
||||||
|
ROI_FILE = "./roi_coordinates/muju_roi.txt"
|
||||||
|
RTSP_URL = "rtsp://admin:XJ123456@192.168.250.61:554/streaming/channels/101"
|
||||||
|
|
||||||
|
STABLE_FRAMES = 3
|
||||||
|
DISPLAY_SCALE = 0.5 # 显示窗口缩放比例
|
||||||
|
SHOW_WINDOW = False # 部署时改成 False,测试的时候打开
|
||||||
|
|
||||||
|
# ---------------------------
|
||||||
|
# 打开 RTSP 视频流
|
||||||
|
# ---------------------------
|
||||||
|
print(f"正在连接 RTSP 流: {RTSP_URL}")
|
||||||
|
cap = cv2.VideoCapture(RTSP_URL)
|
||||||
|
|
||||||
|
# 降低 RTSP 延迟(部分摄像头支持)
|
||||||
|
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
|
||||||
|
|
||||||
|
if not cap.isOpened():
|
||||||
|
print("无法打开 RTSP 流,请检查网络、账号密码或 URL")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
print("RTSP 流连接成功,开始推理...")
|
||||||
|
|
||||||
|
# ---------------------------
|
||||||
|
# 启动稳定分类循环三帧稳定判断
|
||||||
|
# ---------------------------
|
||||||
|
run_stable_classification_loop(
|
||||||
|
model_path=MODEL_PATH,
|
||||||
|
roi_file=ROI_FILE,
|
||||||
|
image_source=cap,
|
||||||
|
stable_frames=STABLE_FRAMES,
|
||||||
|
display_scale=DISPLAY_SCALE,
|
||||||
|
show_window=SHOW_WINDOW
|
||||||
|
)
|
||||||
|
|
||||||
BIN
vision/muju_cls/muju_cls - 副本.rknn
Normal file
BIN
vision/muju_cls/muju_cls - 副本.rknn
Normal file
Binary file not shown.
BIN
vision/muju_cls/muju_cls.rknn
Normal file
BIN
vision/muju_cls/muju_cls.rknn
Normal file
Binary file not shown.
282
vision/muju_cls/muju_cls_rknn.py
Normal file
282
vision/muju_cls/muju_cls_rknn.py
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
import os
|
||||||
|
import cv2
|
||||||
|
import numpy as np
|
||||||
|
from rknnlite.api import RKNNLite
|
||||||
|
|
||||||
|
from collections import deque
|
||||||
|
|
||||||
|
class StableClassJudge:
|
||||||
|
"""
|
||||||
|
连续三帧稳定判决器:
|
||||||
|
- class0 / class1 连续 3 帧 -> 输出
|
||||||
|
- class2 -> 清空计数,重新统计
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, stable_frames=3, ignore_class=2):
|
||||||
|
self.stable_frames = stable_frames
|
||||||
|
self.ignore_class = ignore_class
|
||||||
|
self.buffer = deque(maxlen=stable_frames)
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.buffer.clear()
|
||||||
|
|
||||||
|
def update(self, class_id):
|
||||||
|
"""
|
||||||
|
输入单帧分类结果
|
||||||
|
返回:
|
||||||
|
- None:尚未稳定
|
||||||
|
- class_id:稳定输出结果
|
||||||
|
"""
|
||||||
|
|
||||||
|
# 遇到 class2,直接清空重新计数
|
||||||
|
if class_id == self.ignore_class:
|
||||||
|
self.reset()
|
||||||
|
return None
|
||||||
|
|
||||||
|
self.buffer.append(class_id)
|
||||||
|
|
||||||
|
# 缓冲未满
|
||||||
|
if len(self.buffer) < self.stable_frames:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# 三帧完全一致
|
||||||
|
if len(set(self.buffer)) == 1:
|
||||||
|
stable_class = self.buffer[0]
|
||||||
|
self.reset() # 输出一次后重新计数(防止重复触发)
|
||||||
|
return stable_class
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
# ---------------------------
|
||||||
|
# 三分类映射,模具车1是小的,模具车2是大的
|
||||||
|
# ---------------------------
|
||||||
|
CLASS_NAMES = {
|
||||||
|
0: "模具车1",
|
||||||
|
1: "模具车2",
|
||||||
|
2: "有遮挡"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---------------------------
|
||||||
|
# RKNN 全局实例(只加载一次)
|
||||||
|
# ---------------------------
|
||||||
|
_global_rknn = None
|
||||||
|
|
||||||
|
|
||||||
|
def init_rknn_model(model_path):
|
||||||
|
global _global_rknn
|
||||||
|
if _global_rknn is not None:
|
||||||
|
return _global_rknn
|
||||||
|
|
||||||
|
rknn = RKNNLite(verbose=False)
|
||||||
|
ret = rknn.load_rknn(model_path)
|
||||||
|
if ret != 0:
|
||||||
|
raise RuntimeError(f"Load RKNN failed: {ret}")
|
||||||
|
|
||||||
|
ret = rknn.init_runtime(core_mask=RKNNLite.NPU_CORE_0)
|
||||||
|
if ret != 0:
|
||||||
|
raise RuntimeError(f"Init runtime failed: {ret}")
|
||||||
|
|
||||||
|
_global_rknn = rknn
|
||||||
|
print(f"[INFO] RKNN 模型加载成功: {model_path}")
|
||||||
|
return rknn
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------
|
||||||
|
# 预处理
|
||||||
|
# ---------------------------
|
||||||
|
def letterbox(image, new_size=640, color=(114, 114, 114)):
|
||||||
|
h, w = image.shape[:2]
|
||||||
|
scale = min(new_size / h, new_size / w)
|
||||||
|
nh, nw = int(h * scale), int(w * scale)
|
||||||
|
resized = cv2.resize(image, (nw, nh))
|
||||||
|
new_img = np.full((new_size, new_size, 3), color, dtype=np.uint8)
|
||||||
|
top = (new_size - nh) // 2
|
||||||
|
left = (new_size - nw) // 2
|
||||||
|
new_img[top:top + nh, left:left + nw] = resized
|
||||||
|
return new_img
|
||||||
|
|
||||||
|
|
||||||
|
def resize_stretch(image, size=640):
|
||||||
|
return cv2.resize(image, (size, size))
|
||||||
|
|
||||||
|
|
||||||
|
def preprocess_image_for_rknn(
|
||||||
|
img,
|
||||||
|
size=640,
|
||||||
|
resize_mode="stretch",
|
||||||
|
to_rgb=True,
|
||||||
|
normalize=False,
|
||||||
|
layout="NHWC"
|
||||||
|
):
|
||||||
|
if resize_mode == "letterbox":
|
||||||
|
img_box = letterbox(img, new_size=size)
|
||||||
|
else:
|
||||||
|
img_box = resize_stretch(img, size=size)
|
||||||
|
|
||||||
|
if to_rgb:
|
||||||
|
img_box = cv2.cvtColor(img_box, cv2.COLOR_BGR2RGB)
|
||||||
|
|
||||||
|
img_f = img_box.astype(np.float32)
|
||||||
|
|
||||||
|
if normalize:
|
||||||
|
img_f /= 255.0
|
||||||
|
|
||||||
|
if layout == "NHWC":
|
||||||
|
out = np.expand_dims(img_f, axis=0)
|
||||||
|
else:
|
||||||
|
out = np.expand_dims(np.transpose(img_f, (2, 0, 1)), axis=0)
|
||||||
|
|
||||||
|
return np.ascontiguousarray(out)
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------
|
||||||
|
# 单次 RKNN 推理(三分类)
|
||||||
|
# ---------------------------
|
||||||
|
def rknn_classify_preprocessed(input_tensor, model_path):
|
||||||
|
rknn = init_rknn_model(model_path)
|
||||||
|
|
||||||
|
input_tensor = np.ascontiguousarray(input_tensor.astype(np.float32))
|
||||||
|
outs = rknn.inference([input_tensor])
|
||||||
|
|
||||||
|
pred = outs[0].reshape(-1).astype(float) # shape = (3,)
|
||||||
|
class_id = int(np.argmax(pred))
|
||||||
|
|
||||||
|
return class_id, pred
|
||||||
|
|
||||||
|
# ---------------------------
|
||||||
|
# ROI
|
||||||
|
# ---------------------------
|
||||||
|
def load_single_roi(txt_path):
|
||||||
|
if not os.path.exists(txt_path):
|
||||||
|
raise RuntimeError(f"ROI 文件不存在: {txt_path}")
|
||||||
|
|
||||||
|
with open(txt_path) as f:
|
||||||
|
for line in f:
|
||||||
|
s = line.strip()
|
||||||
|
if not s:
|
||||||
|
continue
|
||||||
|
x, y, w, h = map(int, s.split(','))
|
||||||
|
return (x, y, w, h)
|
||||||
|
|
||||||
|
raise RuntimeError("ROI 文件为空")
|
||||||
|
|
||||||
|
|
||||||
|
def crop_and_return_roi(img, roi):
|
||||||
|
x, y, w, h = roi
|
||||||
|
h_img, w_img = img.shape[:2]
|
||||||
|
|
||||||
|
if x < 0 or y < 0 or x + w > w_img or y + h > h_img:
|
||||||
|
raise RuntimeError(f"ROI 超出图像范围: {roi}")
|
||||||
|
|
||||||
|
return img[y:y + h, x:x + w]
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------
|
||||||
|
# 单张图片推理(三分类)
|
||||||
|
# ---------------------------
|
||||||
|
def classify_single_image(
|
||||||
|
frame,
|
||||||
|
model_path,
|
||||||
|
roi_file,
|
||||||
|
size=640,
|
||||||
|
resize_mode="stretch",
|
||||||
|
to_rgb=True,
|
||||||
|
normalize=False,
|
||||||
|
layout="NHWC"
|
||||||
|
):
|
||||||
|
if frame is None:
|
||||||
|
raise FileNotFoundError("输入帧为空")
|
||||||
|
|
||||||
|
roi = load_single_roi(roi_file)
|
||||||
|
roi_img = crop_and_return_roi(frame, roi)
|
||||||
|
|
||||||
|
input_tensor = preprocess_image_for_rknn(
|
||||||
|
roi_img,
|
||||||
|
size=size,
|
||||||
|
resize_mode=resize_mode,
|
||||||
|
to_rgb=to_rgb,
|
||||||
|
normalize=normalize,
|
||||||
|
layout=layout
|
||||||
|
)
|
||||||
|
|
||||||
|
class_id, probs = rknn_classify_preprocessed(input_tensor, model_path)
|
||||||
|
class_name = CLASS_NAMES.get(class_id, f"未知类别({class_id})")
|
||||||
|
|
||||||
|
return {
|
||||||
|
"class_id": class_id,
|
||||||
|
"class": class_name,
|
||||||
|
"score": round(float(probs[class_id]), 4),
|
||||||
|
"raw": probs.tolist()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------
|
||||||
|
# 示例调用
|
||||||
|
# ---------------------------
|
||||||
|
if __name__ == "__main__":
|
||||||
|
model_path = "muju_cls.rknn"
|
||||||
|
roi_file = "./roi_coordinates/muju_roi.txt"
|
||||||
|
image_path = "./test_image/test.png"
|
||||||
|
|
||||||
|
frame = cv2.imread(image_path)
|
||||||
|
if frame is None:
|
||||||
|
raise FileNotFoundError(f"无法读取图片: {image_path}")
|
||||||
|
|
||||||
|
result = classify_single_image(frame, model_path, roi_file)
|
||||||
|
print("[RESULT]", result)
|
||||||
|
|
||||||
|
# ---------------------------
|
||||||
|
# 示例判断逻辑
|
||||||
|
'''
|
||||||
|
import cv2
|
||||||
|
from muju_cls_rknn import classify_single_image,StableClassJudge,CLASS_NAMES
|
||||||
|
|
||||||
|
def run_stable_classification_loop(
|
||||||
|
model_path,
|
||||||
|
roi_file,
|
||||||
|
image_source,
|
||||||
|
stable_frames=3
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
image_source:
|
||||||
|
- cv2.VideoCapture
|
||||||
|
"""
|
||||||
|
judge = StableClassJudge(
|
||||||
|
stable_frames=stable_frames,
|
||||||
|
ignore_class=2 # 有遮挡
|
||||||
|
)
|
||||||
|
|
||||||
|
cap = image_source
|
||||||
|
if not hasattr(cap, "read"):
|
||||||
|
raise TypeError("image_source 必须是 cv2.VideoCapture")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
ret, frame = cap.read()
|
||||||
|
# 上下左右翻转
|
||||||
|
frame = cv2.flip(frame, -1)
|
||||||
|
|
||||||
|
if not ret:
|
||||||
|
print("读取帧失败,退出")
|
||||||
|
break
|
||||||
|
|
||||||
|
result = classify_single_image(frame, model_path, roi_file)
|
||||||
|
|
||||||
|
class_id = result["class_id"]
|
||||||
|
class_name = result["class"]
|
||||||
|
score = result["score"]
|
||||||
|
|
||||||
|
print(f"[FRAME] {class_name} conf={score}")
|
||||||
|
|
||||||
|
stable = judge.update(class_id)
|
||||||
|
|
||||||
|
if stable is not None:
|
||||||
|
print(f"\n稳定输出: {CLASS_NAMES[stable]} \n")
|
||||||
|
|
||||||
|
if cv2.waitKey(1) & 0xFF == ord('q'):
|
||||||
|
break
|
||||||
|
|
||||||
|
cap.release()
|
||||||
|
cv2.destroyAllWindows()
|
||||||
|
'''
|
||||||
|
# ---------------------------
|
||||||
87
vision/muju_cls/muju_utils.py
Normal file
87
vision/muju_cls/muju_utils.py
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
import os
|
||||||
|
import cv2
|
||||||
|
from rknnlite.api import RKNNLite
|
||||||
|
import time
|
||||||
|
|
||||||
|
# classify_single_image, StableClassJudge, CLASS_NAMES 已在 muju_cls_rknn 中定义
|
||||||
|
from .muju_cls_rknn import classify_single_image, StableClassJudge, CLASS_NAMES
|
||||||
|
|
||||||
|
# 获取当前文件所在目录的绝对路径
|
||||||
|
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
def run_stable_classification_loop():
|
||||||
|
"""
|
||||||
|
image_source: cv2.VideoCapture 对象
|
||||||
|
"""
|
||||||
|
_ret=None
|
||||||
|
# 使用相对于当前文件的绝对路径
|
||||||
|
model_path = os.path.join(current_dir, "muju_cls.rknn")
|
||||||
|
roi_file = os.path.join(current_dir, "roi_coordinates", "muju_roi.txt")
|
||||||
|
RTSP_URL = "rtsp://admin:XJ123456@192.168.250.61:554/streaming/channels/101"
|
||||||
|
stable_frames=3
|
||||||
|
print(f"正在连接 RTSP 流: {RTSP_URL}")
|
||||||
|
cap =None
|
||||||
|
try:
|
||||||
|
cap = cv2.VideoCapture(RTSP_URL)
|
||||||
|
# 降低 RTSP 延迟(部分摄像头支持)
|
||||||
|
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
|
||||||
|
|
||||||
|
if not cap.isOpened():
|
||||||
|
print("无法打开 RTSP 流,请检查网络、账号密码或 URL")
|
||||||
|
return None
|
||||||
|
|
||||||
|
print("RTSP 流连接成功,开始推理...")
|
||||||
|
|
||||||
|
judge = StableClassJudge(
|
||||||
|
stable_frames=stable_frames,
|
||||||
|
ignore_class=2 # 忽略“有遮挡”类别参与稳定判断
|
||||||
|
)
|
||||||
|
|
||||||
|
if not hasattr(cap, "read"):
|
||||||
|
raise TypeError("image_source 必须是 cv2.VideoCapture 实例")
|
||||||
|
_max_count=10
|
||||||
|
while True:
|
||||||
|
_max_count=_max_count-1
|
||||||
|
|
||||||
|
ret, frame = cap.read()
|
||||||
|
if not ret:
|
||||||
|
print("无法读取视频帧(可能是流断开或结束)")
|
||||||
|
continue
|
||||||
|
# 上下左右翻转
|
||||||
|
frame = cv2.flip(frame, -1)
|
||||||
|
|
||||||
|
# ---------------------------
|
||||||
|
# 单帧推理
|
||||||
|
# ---------------------------
|
||||||
|
result = classify_single_image(frame, model_path, roi_file)
|
||||||
|
|
||||||
|
class_id = result["class_id"]
|
||||||
|
class_name = result["class"]
|
||||||
|
score = result["score"]
|
||||||
|
|
||||||
|
print(f"[FRAME] {class_name} | conf={score:.3f}")
|
||||||
|
|
||||||
|
# ---------------------------
|
||||||
|
# 稳定判断
|
||||||
|
# ---------------------------
|
||||||
|
stable_class_id = judge.update(class_id)
|
||||||
|
|
||||||
|
if stable_class_id is not None:
|
||||||
|
_ret=CLASS_NAMES[stable_class_id]
|
||||||
|
if _ret is None:
|
||||||
|
print("-------当前类别为:为空,继续等待稳定------")
|
||||||
|
continue
|
||||||
|
if _ret=="模具车1" or _ret=="模具车2":
|
||||||
|
break
|
||||||
|
print(f"当前类别为:{_ret},继续等待稳定...")
|
||||||
|
else:
|
||||||
|
print("当前类别为:为空,继续等待稳定...")
|
||||||
|
|
||||||
|
time.sleep(0.1)
|
||||||
|
finally:
|
||||||
|
if cap is not None:
|
||||||
|
cap.release()
|
||||||
|
return _ret
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
1
vision/muju_cls/roi_coordinates/muju_roi.txt
Normal file
1
vision/muju_cls/roi_coordinates/muju_roi.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
2,880,385,200
|
||||||
BIN
vision/muju_cls/test.png
Normal file
BIN
vision/muju_cls/test.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.9 MiB |
1
vision/roi_coordinates/muju_roi.txt
Normal file
1
vision/roi_coordinates/muju_roi.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
2,880,385,200
|
||||||
@ -6,7 +6,9 @@ from hardware.transmitter import TransmitterController
|
|||||||
import time
|
import time
|
||||||
import threading
|
import threading
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import logging
|
||||||
from hardware.upper_plc import OmronFinsPollingService
|
from hardware.upper_plc import OmronFinsPollingService
|
||||||
|
from vision.muju_cls.muju_utils import run_stable_classification_loop
|
||||||
|
|
||||||
class VisualCallback:
|
class VisualCallback:
|
||||||
# 类变量,用于存储实例引用,实现单例检测
|
# 类变量,用于存储实例引用,实现单例检测
|
||||||
@ -26,19 +28,10 @@ class VisualCallback:
|
|||||||
if hasattr(self, '_initialized') and self._initialized:
|
if hasattr(self, '_initialized') and self._initialized:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.angle_mode = "normal"
|
|
||||||
self.relay_controller = RelayController()
|
self.relay_controller = RelayController()
|
||||||
self.transmitter_controller = TransmitterController(self.relay_controller)
|
self.transmitter_controller = TransmitterController(self.relay_controller)
|
||||||
self.init_weight = 100
|
|
||||||
self.mould_finish_weight = 0
|
|
||||||
self.mould_need_weight = 100
|
|
||||||
self.finish_count = 0
|
|
||||||
self.overflow = False
|
|
||||||
self.is_start_visual=False
|
|
||||||
|
|
||||||
# 线程安全的参数传递
|
# 线程安全的参数传递
|
||||||
self._current_angle = None
|
|
||||||
self._overflow_detected = None
|
|
||||||
self._new_data_available = threading.Event()
|
self._new_data_available = threading.Event()
|
||||||
self._is_processing = threading.Lock()
|
self._is_processing = threading.Lock()
|
||||||
self._stop_event = threading.Event()
|
self._stop_event = threading.Event()
|
||||||
@ -47,10 +40,22 @@ class VisualCallback:
|
|||||||
self._door_control_lock = threading.Lock()
|
self._door_control_lock = threading.Lock()
|
||||||
# 记录当前控制门的线程名称,用于调试
|
# 记录当前控制门的线程名称,用于调试
|
||||||
self._current_controlling_thread = None
|
self._current_controlling_thread = None
|
||||||
# 新增标志位:指示safe_control_lower_close是否正在执行
|
#是否启动后的第一个模具
|
||||||
self._is_safe_closing = False
|
self._is_first_module=True
|
||||||
|
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
|
||||||
|
#完成多少,忽略未浇筑满
|
||||||
|
self._max_ignore_radio=0.5
|
||||||
|
|
||||||
self._is_feed_start=True
|
# self.plc_data=5
|
||||||
|
self.plc_service = OmronFinsPollingService("192.168.250.233")
|
||||||
|
self.plc_service.register_data_callback(self.on_plc_update)
|
||||||
|
# self.plc_service.register_status_callback(self.on_status_change)
|
||||||
|
self.plc_service.start_polling(interval=2.0)
|
||||||
|
|
||||||
# 创建并启动单个持续运行的线程
|
# 创建并启动单个持续运行的线程
|
||||||
self.callback_thread = threading.Thread(
|
self.callback_thread = threading.Thread(
|
||||||
@ -59,30 +64,66 @@ class VisualCallback:
|
|||||||
)
|
)
|
||||||
self.callback_thread.start()
|
self.callback_thread.start()
|
||||||
|
|
||||||
|
|
||||||
self.feed_thread = threading.Thread(
|
self.feed_thread = threading.Thread(
|
||||||
target=self._run_feed,
|
target=self._run_feed,
|
||||||
daemon=True
|
daemon=True
|
||||||
)
|
)
|
||||||
self.feed_thread.start()
|
self.feed_thread.start()
|
||||||
|
|
||||||
|
"""启动系统监控"""
|
||||||
|
self.monitor_thread = threading.Thread(
|
||||||
|
target=self._monitor_loop,
|
||||||
|
daemon=True,
|
||||||
|
name='monitor'
|
||||||
|
)
|
||||||
|
self.monitor_thread.start()
|
||||||
|
|
||||||
|
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._before_finish_time=None
|
||||||
|
#进入未浇筑满状态标志位
|
||||||
self._is_before_finish=False
|
self._is_before_finish=False
|
||||||
|
#是否浇筑满标志位
|
||||||
self._is_finish=False
|
self._is_finish=False
|
||||||
# self._is_finish_ratio=0
|
#浇筑完成比例(重量)
|
||||||
#是否震荡关闭平面(设想90%后关闭几秒,让液面平整)
|
self._is_finish_ratio=0
|
||||||
# self._is_zd_close=False
|
|
||||||
|
#下料阶段,汇总时用枚举
|
||||||
|
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_overflow_state = False
|
self._last_overflow_state = False
|
||||||
self._last_control_time = 0
|
self._last_control_time = 0
|
||||||
self._initialized = True
|
self._initialized = True
|
||||||
self.plc_data=None
|
self.plc_data=None
|
||||||
# self.plc_data=5
|
|
||||||
self.plc_service = OmronFinsPollingService("192.168.250.233")
|
|
||||||
self.plc_service.register_data_callback(self.on_plc_update)
|
|
||||||
# self.plc_service.register_status_callback(self.on_status_change)
|
|
||||||
self.plc_service.start_polling(interval=2.0)
|
|
||||||
|
|
||||||
def angle_visual_callback(self, current_angle, overflow_detected):
|
def angle_visual_callback(self, current_angle, overflow_detected):
|
||||||
"""
|
"""
|
||||||
@ -111,8 +152,67 @@ class VisualCallback:
|
|||||||
# 释放处理锁
|
# 释放处理锁
|
||||||
self._is_processing.release()
|
self._is_processing.release()
|
||||||
|
|
||||||
|
def _monitor_loop(self):
|
||||||
|
"""监控循环"""
|
||||||
|
while not self._is_finish:
|
||||||
|
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:
|
||||||
|
# 检查重量变化是否过慢
|
||||||
|
if (abs(_arch_weight - self._last_arch_one_weight) < 200) and \
|
||||||
|
(current_time - self._last_arch_time) >= 2:
|
||||||
|
print('---------------------第一阶段振动5秒-----------------')
|
||||||
|
self.relay_controller.control_arch_lower_open_sync(5)
|
||||||
|
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:
|
||||||
|
# 检查重量变化是否过慢
|
||||||
|
# if (abs(_arch_weight - self._last_arch_two_weight) < 50) and \
|
||||||
|
# (current_time - self._last_arch_time) >= 2:
|
||||||
|
# self.relay_controller.control_arch_upper_open_sync(3)
|
||||||
|
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:
|
||||||
|
# 检查重量变化是否过慢
|
||||||
|
|
||||||
|
if (abs(_arch_weight - self._last_arch_three_weight) < 100) and \
|
||||||
|
(current_time - self._last_arch_time) >= 2:
|
||||||
|
print('---------------------第三阶段振动5秒-----------------')
|
||||||
|
self.relay_controller.control_arch_lower_open_sync(3)
|
||||||
|
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:
|
||||||
|
# 检查重量变化是否过慢
|
||||||
|
# if (abs(_arch_weight - self._last_arch_four_weight) < 200) and \
|
||||||
|
# (current_time - self._last_arch_time) > 2:
|
||||||
|
# self.relay_controller.control_arch_upper_open_sync(5)
|
||||||
|
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:
|
||||||
|
_min_arch_weight=20
|
||||||
|
if self._is_finish_ratio<self._max_angle_radio:
|
||||||
|
_min_arch_weight=50
|
||||||
|
if (abs(_arch_weight - self._last_arch_five_weight) < _min_arch_weight) and \
|
||||||
|
(current_time - self._last_arch_time) >= 2:
|
||||||
|
print('---------------------第五阶段振动5秒-----------------')
|
||||||
|
self.relay_controller.control_arch_lower_open_sync(5)
|
||||||
|
self._last_arch_five_weight = _arch_weight
|
||||||
|
# 更新最后读取时间
|
||||||
|
self._last_arch_time = current_time
|
||||||
|
time.sleep(2)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"监控线程错误: {e}")
|
||||||
|
|
||||||
def _run_thread_loop(self):
|
def _run_thread_loop(self):
|
||||||
"""
|
"""
|
||||||
|
接受视觉回调数据
|
||||||
线程主循环,持续运行
|
线程主循环,持续运行
|
||||||
等待新数据,然后调用处理方法
|
等待新数据,然后调用处理方法
|
||||||
"""
|
"""
|
||||||
@ -138,14 +238,25 @@ class VisualCallback:
|
|||||||
while True:
|
while True:
|
||||||
print("------------已启动----------------")
|
print("------------已启动----------------")
|
||||||
if self._is_feed_start:
|
if self._is_feed_start:
|
||||||
if self.plc_data==5:
|
|
||||||
self.run_feed()
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
print("-----------上料斗未就位----------------")
|
|
||||||
print("-----------上料斗未就位----------------")
|
|
||||||
|
|
||||||
time.sleep(0.5)
|
# if self.plc_data==5:
|
||||||
|
#_is_finish_ratio完成 比例,根据重量过滤一下
|
||||||
|
if self._overflow_detected=='未堆料':
|
||||||
|
if self._is_first_module:
|
||||||
|
print('------------进入第一块111111-------------')
|
||||||
|
self._is_first_module=False
|
||||||
|
self.run_feed_all()
|
||||||
|
break
|
||||||
|
elif self._is_finish and self._is_finish_ratio>=0.7:
|
||||||
|
print('-----------进入连续块111111-----------')
|
||||||
|
# self.init_val()
|
||||||
|
# self.run_feed_all()
|
||||||
|
|
||||||
|
# else:
|
||||||
|
# print("-----------上料斗未就位----------------")
|
||||||
|
# print("---------3--上料斗未就位----------------")
|
||||||
|
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
def safe_control_lower_close(self,duration=3):
|
def safe_control_lower_close(self,duration=3):
|
||||||
"""线程安全的下料斗关闭方法"""
|
"""线程安全的下料斗关闭方法"""
|
||||||
@ -167,153 +278,293 @@ class VisualCallback:
|
|||||||
# 无论成功失败,都要重置标志位
|
# 无论成功失败,都要重置标志位
|
||||||
self._is_safe_closing = False
|
self._is_safe_closing = False
|
||||||
|
|
||||||
def run_feed(self):
|
def close_lower_door_visual(self):
|
||||||
"""第一阶段下料:下料斗向模具车下料(低速)"""
|
"""关闭下料斗门"""
|
||||||
print("--------------------开始下料--------------------")
|
|
||||||
loc_relay=self.relay_controller
|
|
||||||
loc_mitter=self.transmitter_controller
|
|
||||||
|
|
||||||
initial_lower_weight=loc_mitter.read_data(2)
|
|
||||||
initial_upper_weight=loc_mitter.read_data(1)
|
|
||||||
first_finish_weight=0
|
|
||||||
# need_total_weight=1.91*2416
|
|
||||||
start_time=None
|
|
||||||
self.is_start_visual=True
|
|
||||||
|
|
||||||
if initial_lower_weight>100:
|
|
||||||
#下料斗的料全部下完
|
|
||||||
while not self._is_finish:
|
|
||||||
loc_mitter.is_start_lower=True
|
|
||||||
current_weight = loc_mitter.read_data(2)
|
|
||||||
first_finish_weight=initial_lower_weight-current_weight
|
|
||||||
if current_weight<500:
|
|
||||||
# 破拱控制
|
|
||||||
if start_time is None or time.time()-start_time>5:
|
|
||||||
start_time=time.time()
|
|
||||||
loc_relay.control_arch_lower_open()
|
|
||||||
|
|
||||||
if current_weight<250:
|
|
||||||
start_time=None
|
|
||||||
self.is_start_visual=False
|
self.is_start_visual=False
|
||||||
loc_mitter.is_start_lower=False
|
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
self.safe_control_lower_close()
|
self.safe_control_lower_close()
|
||||||
break
|
|
||||||
print(f'------------已下料: {first_finish_weight}kg-------------')
|
|
||||||
time.sleep(1)
|
|
||||||
|
|
||||||
# _current_lower_weight=loc_mitter.read_data(2)
|
def _visual_close(self):
|
||||||
# first_finish_weight=initial_lower_weight-_current_lower_weight
|
self.is_start_visual=False
|
||||||
|
self._is_finish=True
|
||||||
|
self._is_feed_stage=0
|
||||||
|
print(f'--------进入关闭-----------')
|
||||||
|
self.safe_control_lower_close(3)
|
||||||
|
print(f'--------关闭完成-----------')
|
||||||
|
#记录重量
|
||||||
|
_current_weight=self.transmitter_controller.read_data(2)
|
||||||
|
if _current_weight is not None:
|
||||||
|
self._finish_weight= self._finish_weight+(self._inital_finish_lweight-_current_weight)
|
||||||
|
with open('weight.txt', 'a') as f:
|
||||||
|
timestamp = datetime.now().strftime("%H:%M:%S")
|
||||||
|
f.write(f"{timestamp} - {self._finish_weight}\n")
|
||||||
|
|
||||||
|
|
||||||
|
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.run_feed_f()
|
||||||
|
elif _is_f=='模具车2':
|
||||||
|
self._is_small_f=False
|
||||||
|
self.run_feed()
|
||||||
|
print('-------------其他模具---------------')
|
||||||
|
|
||||||
|
if self._is_small_f is None:
|
||||||
|
print('-----------未判断出模具类型--------------')
|
||||||
|
return
|
||||||
|
|
||||||
|
def run_feed_f(self):
|
||||||
|
"""第一阶段下料:下料斗向模具车下料(低速)"""
|
||||||
|
print("--------------------开始下料(F块)--------------------")
|
||||||
|
# loc_relay=self.relay_controller
|
||||||
|
loc_mitter=self.transmitter_controller
|
||||||
|
max_weight_none=5
|
||||||
|
cur_weight_none=0
|
||||||
|
initial_lower_weight=loc_mitter.read_data(2)
|
||||||
|
if initial_lower_weight is None:
|
||||||
|
print("-----f上料斗重量异常-----")
|
||||||
|
return
|
||||||
|
first_finish_weight=0
|
||||||
|
self._finish_weight=first_finish_weight
|
||||||
|
self._inital_finish_lweight=initial_lower_weight
|
||||||
|
need_total_weight=0.54*2416
|
||||||
|
if initial_lower_weight>100:
|
||||||
|
if not self._is_finish:
|
||||||
|
self.is_start_visual=True
|
||||||
|
initial_lower_weight=loc_mitter.read_data(2)
|
||||||
|
if initial_lower_weight is None:
|
||||||
|
print("-----f上料斗重量异常2-----")
|
||||||
|
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:
|
||||||
|
#如果重量连续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
|
||||||
|
print(f'------------已下料比例: {self._is_finish_ratio}-------------')
|
||||||
|
if self._is_finish_ratio>self._max_f_angle_ratio:
|
||||||
|
#关5秒
|
||||||
|
#大于0.7后不再检测了,直接交给视觉控制夹脚
|
||||||
|
# print(f'------------已下料比例: {self._is_finish_ratio}-------------')
|
||||||
|
break
|
||||||
|
|
||||||
|
# print(f'------------已下料: {first_finish_weight+second_finish_weight}kg-------------')
|
||||||
|
time.sleep(1)
|
||||||
# initial_lower_weight=_current_lower_weight
|
# initial_lower_weight=_current_lower_weight
|
||||||
# print(f'------------已下料: {first_finish_weight}kg-------------')
|
print(f'------------已下料(F): {first_finish_weight}kg-------------')
|
||||||
# print(f'------------已下料: {first_finish_weight}kg-------------')
|
print(f'------------已下料(F): {first_finish_weight}kg-------------')
|
||||||
|
|
||||||
|
print(f'------------已完成-------------')
|
||||||
|
|
||||||
|
|
||||||
|
def run_feed(self):
|
||||||
|
"""第一阶段下料:下料斗向模具车下料(低速)"""
|
||||||
|
print("--------------------开始下料(普通块)--------------------")
|
||||||
|
loc_relay=self.relay_controller
|
||||||
|
loc_mitter=self.transmitter_controller
|
||||||
|
max_weight_none=5
|
||||||
|
cur_weight_none=0
|
||||||
|
|
||||||
|
initial_lower_weight=loc_mitter.read_data(2)
|
||||||
|
# initial_upper_weight=loc_mitter.read_data(1)
|
||||||
|
if initial_lower_weight is None:
|
||||||
|
print("---------------下料斗重量异常----------------")
|
||||||
|
return
|
||||||
|
first_finish_weight=0
|
||||||
|
need_total_weight=1.91*2416
|
||||||
|
# start_time=None
|
||||||
|
self.is_start_visual=True
|
||||||
|
if initial_lower_weight>100:
|
||||||
|
#下料斗的料全部下完
|
||||||
|
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
|
||||||
|
if current_weight<250 and current_weight>0:
|
||||||
|
self.close_lower_door_visual()
|
||||||
|
break
|
||||||
|
time.sleep(1)
|
||||||
|
_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!=5:
|
||||||
|
print('------------上料斗未就位----------------')
|
||||||
|
print('------------上料斗未就位----------------')
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
if self.plc_data==5:
|
if self.plc_data==5:
|
||||||
print(f'------------上料斗向下料斗转移(留3000KG)-------------')
|
print(f'------------上料斗向下料斗转移(留3000KG)-------------')
|
||||||
#打开上料斗出砼门,开5就,开三分之一下
|
#打开上料斗出砼门,开5就,开三分之一下
|
||||||
|
|
||||||
loc_relay.control_upper_open_sync(6)
|
loc_relay.control_upper_open_sync(6)
|
||||||
|
self._is_feed_stage=2
|
||||||
loc_time_count=1
|
loc_time_count=1
|
||||||
upper_open_time=time.time()
|
upper_open_time=time.time()
|
||||||
|
|
||||||
while not self._is_finish:
|
while not self._is_finish:
|
||||||
loc_mitter.is_start_upper=True
|
|
||||||
current_upper_weight = loc_mitter.read_data(1)
|
current_upper_weight = loc_mitter.read_data(1)
|
||||||
if current_upper_weight<3000:
|
if current_upper_weight is None:
|
||||||
|
cur_weight_none+=1
|
||||||
|
if cur_weight_none>max_weight_none:
|
||||||
|
#如果重量连续5次为None,认为上料斗未就位,跳出循环
|
||||||
|
print('------------第一次上到下,上料斗重量异常----------------')
|
||||||
|
print('------------第一次上到下,上料斗重量异常----------------')
|
||||||
|
loc_relay.control_upper_close_sync(5+loc_time_count)
|
||||||
|
return
|
||||||
|
continue
|
||||||
|
cur_weight_none=0
|
||||||
|
if current_upper_weight<3000 and current_upper_weight>0:
|
||||||
#关5秒,loc_time_count多关一秒
|
#关5秒,loc_time_count多关一秒
|
||||||
loc_relay.control_upper_close_sync(4+loc_time_count)
|
loc_relay.control_upper_close_sync(5+loc_time_count)
|
||||||
loc_mitter.is_start_upper=False
|
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
if time.time()-upper_open_time>5:
|
if time.time()-upper_open_time>5:
|
||||||
upper_open_time=time.time()
|
if loc_time_count<6:
|
||||||
loc_relay.control_upper_open_sync(0.5)
|
|
||||||
loc_time_count=loc_time_count+0.5
|
|
||||||
else:
|
|
||||||
time.sleep(0.5)
|
|
||||||
# time.sleep(0.4)
|
|
||||||
|
|
||||||
self.is_start_visual=True
|
|
||||||
loc_mitter.is_start_lower=False
|
|
||||||
loc_mitter.test_lower_weight=2000
|
|
||||||
initial_lower_weight=loc_mitter.read_data(2)
|
|
||||||
|
|
||||||
while not self._is_finish:
|
|
||||||
loc_mitter.is_start_lower=True
|
|
||||||
current_weight = loc_mitter.read_data(2)
|
|
||||||
second_finish_weight=initial_lower_weight-current_weight
|
|
||||||
if current_weight<500:
|
|
||||||
#关5秒
|
|
||||||
if start_time is None or time.time()-start_time>5:
|
|
||||||
start_time=time.time()
|
|
||||||
loc_relay.control_arch_lower_open()
|
|
||||||
if current_weight<250:
|
|
||||||
start_time=None
|
|
||||||
self.is_start_visual=False
|
|
||||||
loc_mitter.is_start_lower=False
|
|
||||||
time.sleep(0.5)
|
|
||||||
self.safe_control_lower_close()
|
|
||||||
break
|
|
||||||
print(f'------------已下料: {first_finish_weight+second_finish_weight}kg-------------')
|
|
||||||
time.sleep(1)
|
|
||||||
# _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-------------')
|
|
||||||
if self.plc_data==5:
|
|
||||||
#第二次上料斗向下料斗转移
|
|
||||||
loc_relay.control_upper_open_sync(6)
|
|
||||||
loc_time_count=1
|
|
||||||
upper_open_time=time.time()
|
|
||||||
loc_mitter.is_start_upper=False
|
|
||||||
loc_mitter.test_upper_weight=3000
|
|
||||||
#第二次到下料斗还需要的量
|
|
||||||
#loc_left_need_weight=need_total_weight-first_finish_weight
|
|
||||||
initial_upper_weight=loc_mitter.read_data(1)
|
|
||||||
start_time=None
|
|
||||||
while not self._is_finish:
|
|
||||||
# print(f'------------上料斗向下料斗转移22222-------------')
|
|
||||||
loc_mitter.is_start_upper=True
|
|
||||||
current_upper_weight = loc_mitter.read_data(1)
|
|
||||||
if current_upper_weight<500:
|
|
||||||
#关5秒,loc_time_count多关一秒
|
|
||||||
if start_time is None or time.time()-start_time>4:
|
|
||||||
start_time=time.time()
|
|
||||||
loc_relay.control_arch_upper_open()
|
|
||||||
if current_upper_weight<100:
|
|
||||||
start_time=None
|
|
||||||
loc_relay.control_upper_close_sync(4+loc_time_count)
|
|
||||||
loc_mitter.is_start_upper=False
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
if time.time()-upper_open_time>3:
|
|
||||||
upper_open_time=time.time()
|
upper_open_time=time.time()
|
||||||
loc_relay.control_upper_open_sync(0.8)
|
loc_relay.control_upper_open_sync(0.8)
|
||||||
loc_time_count=loc_time_count+0.8
|
loc_time_count=loc_time_count+0.8
|
||||||
else:
|
else:
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
|
else:
|
||||||
|
loc_relay.control_upper_close_sync(6+loc_time_count)
|
||||||
|
|
||||||
|
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
|
||||||
|
# second_finish_weight=initial_lower_weight-current_weight
|
||||||
|
if current_weight<250:
|
||||||
|
self.close_lower_door_visual()
|
||||||
|
break
|
||||||
|
# print(f'------------已下料: {first_finish_weight+second_finish_weight}kg-------------')
|
||||||
|
time.sleep(1)
|
||||||
|
_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-------------')
|
||||||
|
|
||||||
|
self._is_feed_stage=0
|
||||||
|
if self.plc_data==5:
|
||||||
|
#第二次上料斗向下料斗转移
|
||||||
|
loc_relay.control_upper_open_sync(11)
|
||||||
|
loc_time_count=1
|
||||||
|
upper_open_time=time.time()
|
||||||
|
#第二次到下料斗还需要的量
|
||||||
|
#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('------------第二次上到下,上料斗重量异常----------------')
|
||||||
|
loc_relay.control_upper_close_sync(15)
|
||||||
|
break
|
||||||
|
continue
|
||||||
|
cur_weight_none=0
|
||||||
|
if current_upper_weight<400 and current_upper_weight>0:
|
||||||
|
loc_relay.control_arch_upper_open()
|
||||||
|
loc_relay.control_upper_open_sync(5)
|
||||||
|
# start_time=None
|
||||||
|
#5秒后关闭
|
||||||
|
loc_relay.control_upper_close_after()#control_upper_close_sync(8+loc_time_count)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if time.time()-upper_open_time>2:
|
||||||
|
# if loc_time_count<6:
|
||||||
|
upper_open_time=time.time()
|
||||||
|
loc_relay.control_upper_open_sync(1)
|
||||||
|
loc_time_count=loc_time_count+1
|
||||||
|
else:
|
||||||
|
time.sleep(0.5)
|
||||||
|
else:
|
||||||
|
loc_relay.control_upper_close_sync(15)
|
||||||
# time.sleep(0.4)
|
# time.sleep(0.4)
|
||||||
|
|
||||||
#第二次下料斗转移到模具车
|
#第三次下料斗转移到模具车
|
||||||
if not self._is_finish:
|
if not self._is_finish:
|
||||||
self.is_start_visual=True
|
self.is_start_visual=True
|
||||||
# loc_mitter.is_start_lower=False
|
initial_lower_weight=loc_mitter.read_data(2)
|
||||||
# loc_mitter.test_lower_weight=2000
|
self._finish_weight=first_finish_weight
|
||||||
# initial_lower_weight=loc_mitter.read_data(2)
|
self._inital_finish_lweight=initial_lower_weight
|
||||||
|
if initial_lower_weight is None:
|
||||||
# while not self._is_finish:
|
print("-------下料斗重量异常(第三次下到模具车)---------")
|
||||||
# loc_mitter.is_start_lower=True
|
return
|
||||||
# current_weight = loc_mitter.read_data(2)
|
self._is_feed_stage=5
|
||||||
# second_finish_weight=initial_lower_weight-current_weight
|
while not self._is_finish:
|
||||||
# # self._is_finish_ratio=(second_finish_weight+first_finish_weight)/need_total_weight
|
current_weight = loc_mitter.read_data(2)
|
||||||
# # print(f'------------已下料比例: {self._is_finish_ratio}-------------')
|
if current_weight is None:
|
||||||
|
cur_weight_none+=1
|
||||||
# if current_weight<500:
|
if cur_weight_none>max_weight_none:
|
||||||
# #关5秒
|
#重量异常退出
|
||||||
# if start_time is None or time.time()-start_time>5:
|
print('------------第三次下到模具车,下料斗重量异常----------------')
|
||||||
# start_time=time.time()
|
self.close_lower_door_visual()
|
||||||
# loc_relay.control_arch_lower_open()
|
return
|
||||||
|
continue
|
||||||
|
cur_weight_none=0
|
||||||
|
second_finish_weight=initial_lower_weight-current_weight
|
||||||
|
self._is_finish_ratio=(second_finish_weight+first_finish_weight)/need_total_weight
|
||||||
|
print(f'------------已下料比例: {self._is_finish_ratio}-------------')
|
||||||
|
if self._is_finish_ratio>self._max_angle_radio:
|
||||||
|
#关5秒
|
||||||
|
# print(f'------------已下料比例: {self._is_finish_ratio}-------------')
|
||||||
|
break
|
||||||
|
|
||||||
# print(f'------------已下料: {first_finish_weight+second_finish_weight}kg-------------')
|
# print(f'------------已下料: {first_finish_weight+second_finish_weight}kg-------------')
|
||||||
# time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
# _current_lower_weight=loc_mitter.read_data(2)
|
# _current_lower_weight=loc_mitter.read_data(2)
|
||||||
# first_finish_weight=first_finish_weight+initial_lower_weight-_current_lower_weight
|
# first_finish_weight=first_finish_weight+initial_lower_weight-_current_lower_weight
|
||||||
@ -354,41 +605,53 @@ class VisualCallback:
|
|||||||
# time.sleep(3)
|
# time.sleep(3)
|
||||||
else:
|
else:
|
||||||
if overflow_detected=='浇筑满':
|
if overflow_detected=='浇筑满':
|
||||||
self.is_start_visual=False
|
self._visual_close()
|
||||||
self._is_finish=True
|
return
|
||||||
self.safe_control_lower_close(3)
|
# print(f'--------已关闭已关闭-----------')
|
||||||
elif overflow_detected=="大堆料":
|
elif overflow_detected=="大堆料":
|
||||||
print(f'--------未浇筑满,大堆料,不开关-----------')
|
print(f'--------未浇筑满,大堆料-----------')
|
||||||
else:
|
self._pulse_control('open',0.3)
|
||||||
self._pulse_control('open',0.5)
|
|
||||||
time.sleep(0.3)
|
time.sleep(0.3)
|
||||||
self._pulse_control('close',0.6)
|
self._pulse_control('close',0.4)
|
||||||
time.sleep(2)
|
|
||||||
|
time.sleep(1)
|
||||||
self._is_before_finish=True
|
self._is_before_finish=True
|
||||||
|
else:
|
||||||
|
# self._pulse_control('open',0.5)
|
||||||
|
# time.sleep(0.3)
|
||||||
|
# self._pulse_control('close',0.6)
|
||||||
|
self._pulse_control('open',0.6)
|
||||||
|
time.sleep(0.3)
|
||||||
|
self._pulse_control('close',0.7)
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
|
self._is_before_finish=True
|
||||||
|
if self._is_finish_ratio<=self._max_ignore_radio:
|
||||||
|
#如果重量未达到最大忽略角度,需要跳出
|
||||||
|
self._is_before_finish=False
|
||||||
return
|
return
|
||||||
elif overflow_detected == "浇筑满":
|
elif overflow_detected == "浇筑满":
|
||||||
self.is_start_visual=False
|
self._visual_close()
|
||||||
self._is_finish=True
|
|
||||||
self.safe_control_lower_close(3)
|
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
self._before_finish_time=None
|
self._before_finish_time=None
|
||||||
# if self._is_finish_ratio>=0.8:
|
if self._is_finish_ratio>=self._max_angle_radio or (self._is_finish_ratio>self._max_f_angle_ratio and self._is_small_f):
|
||||||
# if overflow_detected == "大堆料":
|
if overflow_detected == "大堆料":
|
||||||
# TARGET_ANGLE = 10.0 # 大堆料时控制在15度左右
|
TARGET_ANGLE = 5.0 # 大堆料时控制在15度左右
|
||||||
# elif overflow_detected == "小堆料":
|
elif overflow_detected == "小堆料":
|
||||||
# TARGET_ANGLE = 20.0 # 小堆料时控制在35度左右
|
TARGET_ANGLE = 15.0 # 小堆料时控制在35度左右
|
||||||
# else:
|
else:
|
||||||
# TARGET_ANGLE = 25.0 # 未溢料时开到最大56度
|
TARGET_ANGLE = 25.0 # 未溢料时开到最大56度
|
||||||
# if self._is_finish_ratio>=0.9 and not self._is_zd_close:
|
else:
|
||||||
# #关闭10秒,直接关闭,不等待
|
if self._is_feed_stage==1 or self._is_feed_stage==3:
|
||||||
# print('-----------------达到90% 关闭--------------------')
|
#根据溢料状态动态调整目标角度
|
||||||
# self._is_zd_close=True
|
if overflow_detected == "大堆料":
|
||||||
# self.safe_control_lower_close()
|
TARGET_ANGLE = 15.0 # 大堆料时控制在15度左右
|
||||||
# time.sleep(10)
|
elif overflow_detected == "小堆料":
|
||||||
# return
|
TARGET_ANGLE = 45.0 # 小堆料时控制在35度左右
|
||||||
|
else:
|
||||||
# else:
|
TARGET_ANGLE = 55.0 # 未溢料时开到最大56度
|
||||||
|
else:
|
||||||
#根据溢料状态动态调整目标角度
|
#根据溢料状态动态调整目标角度
|
||||||
if overflow_detected == "大堆料":
|
if overflow_detected == "大堆料":
|
||||||
TARGET_ANGLE = 15.0 # 大堆料时控制在15度左右
|
TARGET_ANGLE = 15.0 # 大堆料时控制在15度左右
|
||||||
@ -401,7 +664,7 @@ class VisualCallback:
|
|||||||
TARGET_ANGLE = max(5.0, min(56.0, TARGET_ANGLE))
|
TARGET_ANGLE = max(5.0, min(56.0, TARGET_ANGLE))
|
||||||
|
|
||||||
# PID控制参数
|
# PID控制参数
|
||||||
KP = 0.15 # 比例系数
|
KP = 0.2 # 比例系数
|
||||||
KI = 0 # 积分系数
|
KI = 0 # 积分系数
|
||||||
KD = 0 # 微分系数
|
KD = 0 # 微分系数
|
||||||
# KP = 0.15 # 比例系数
|
# KP = 0.15 # 比例系数
|
||||||
@ -618,6 +881,12 @@ class VisualCallback:
|
|||||||
if self.callback_thread.is_alive():
|
if self.callback_thread.is_alive():
|
||||||
self.callback_thread.join(timeout=1.0)
|
self.callback_thread.join(timeout=1.0)
|
||||||
|
|
||||||
|
if self.feed_thread.is_alive():
|
||||||
|
self.feed_thread.join(timeout=1.0)
|
||||||
|
|
||||||
|
if self.monitor_thread.is_alive():
|
||||||
|
self.monitor_thread.join(timeout=1.0)
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
"""析构函数,确保线程安全关闭"""
|
"""析构函数,确保线程安全关闭"""
|
||||||
self.shutdown()
|
self.shutdown()
|
||||||
|
|||||||
1018
vision/visual_callback_dq.py
Normal file
1018
vision/visual_callback_dq.py
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user