771 lines
37 KiB
Python
771 lines
37 KiB
Python
from yc_SCANNER.prod.tw.com.yctools.util.hw.barCodeReader import abfactory
|
||
from yc_SCANNER.prod.tw.com.yctools.util.hw.barCodeReader import CINO_S680
|
||
import copy
|
||
import sys
|
||
import threading
|
||
from datetime import datetime, timedelta
|
||
import time
|
||
from PyQt5.QtGui import QImage, QPixmap, QColor
|
||
from PyQt5.QtWidgets import QFileDialog, QApplication, QTableWidgetItem, QHeaderView, QLabel
|
||
import cv2
|
||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||
from PyQt5.QtCore import QThread, pyqtSignal, QObject, QTimer
|
||
|
||
from Screwdriver_Detection_Window import Ui_Screwdriver_Detection_Window
|
||
from Camera import Camera
|
||
from ScrewDrive import ScrewDrive
|
||
from Modbus import Modbus
|
||
from Screwdriver_Database import DB_MainWindow
|
||
from Motor import Motor
|
||
from Lock import Lock
|
||
import logging
|
||
from Myini import Myini
|
||
from Screwdriver_Detection_EngineerMode import Screwdriver_Detection_EngineerMode
|
||
from Screwdriver_EngineerMode_LogIn import Screwdriver_EngineerMode_LogIn
|
||
|
||
import gc
|
||
import yaml
|
||
from PLC.IOcardQthread import IOcard
|
||
import tkinter as tk
|
||
from tkinter import filedialog
|
||
from tkinter import messagebox
|
||
import os
|
||
import configparser
|
||
|
||
|
||
|
||
class Screwdriver_Detection(QtWidgets.QMainWindow, Ui_Screwdriver_Detection_Window):
|
||
def __init__(self):
|
||
QtWidgets.QMainWindow.__init__(self) # 創建主界面對象
|
||
print('Screwdriver_Detection0509')
|
||
self.setupUi(self)
|
||
self.pushButton_Load_Recipe.setStyleSheet(
|
||
'background-color: #4CAF50; border: 1px solid #dcdfe6; padding: 10px; border-radius: 20px;') #green
|
||
self.pushButton_Recipe_End.setStyleSheet(
|
||
'background-color: #FF5555; border: 1px solid #dcdfe6; padding: 10px; border-radius: 20px;') #red
|
||
|
||
self.timer = QTimer(self)
|
||
|
||
# set logging file
|
||
self.iniLogging()
|
||
self.dev_logger.info('Program(Screwdriver_Detection) Start')
|
||
lock = Lock(dev_logger=self.dev_logger)
|
||
self.MYINI = Myini()
|
||
|
||
self.label_Image.setScaledContents(True)
|
||
|
||
# self.motor = Motor()
|
||
# if self.motor.Motor_isOpen:
|
||
# self.motor.MotorInit()
|
||
# self.motor_idle_timer = QTimer(self)#設定IO卡閒置重新連線計時器
|
||
# self.motor_idle_timer.start(60000)#設定馬達閒置重平台移進去時間間隔為60秒
|
||
# # self.serialPort = SerialPort()
|
||
# self.modbus = Modbus(self.dev_logger)
|
||
# if self.modbus.Modbus_isOpen:
|
||
# self.modbus_reconnect_timer = QTimer(self) # 設定IO卡閒置重新連線計時器
|
||
# self.modbus_reconnect_timer.start(60000) # 設定IO卡閒置重新連線計時器啟用時間間隔為60秒
|
||
|
||
# self.Identity = ['alpha', 'beta']
|
||
|
||
self.IOCardThread = IOcard(SERVER_HOST='192.168.0.150', SERVER_PORT=502, dev_logger=self.dev_logger)
|
||
self.IOCardConnect()
|
||
|
||
if self.IOCardThread.connect:
|
||
self.motor_idle_timer = QTimer(self) # 設定IO卡閒置重新連線計時器
|
||
self.motor_idle_timer.start(75000)#設定馬達閒置重平台移進去時間間隔為60秒
|
||
|
||
self.camera = Camera()
|
||
if self.camera.Camera_isOpen:
|
||
self.camera.start()
|
||
|
||
self.dbwindow = DB_MainWindow()
|
||
|
||
self.login_window = Screwdriver_EngineerMode_LogIn(self.MYINI)
|
||
self.engineer_mode_window = Screwdriver_Detection_EngineerMode(self.IOCardThread, self.MYINI, self.camera)
|
||
|
||
self.iniGuiEvent()
|
||
|
||
self.screwdrives = list()
|
||
for i, k in enumerate(self.MYINI.Identity_CodeName):
|
||
sd = ScrewDrive(r".\model", self.dev_logger, k, myIni=self.MYINI)
|
||
sd.report.connect(self.NG_Report)
|
||
sd.status.connect(self.statusChange)
|
||
self.screwdrives.append(sd)
|
||
|
||
self.countdown_seconds = 0
|
||
self.is_Timeup = False
|
||
self.NG_Count = 0
|
||
self.Start24_Count = 0
|
||
self.real_detect_amount = 0
|
||
self.passdetect_amount = 0 #合格數量
|
||
self.comboBox_recipe.addItems([recipe for recipe in self.MYINI.recipes])
|
||
self.comboBox_recipe.setVisible(False)
|
||
self.pushButton_TakeImage.setVisible(False)
|
||
self.pushButton_24Hours.setVisible(False)
|
||
|
||
# self.exposure_time_tuple = (23000, 25000, 27000, 29000, 31000, 36000)
|
||
# self.exposure_time_tuple = (18000, 20000, 22000, 24000, 26000, 28000)
|
||
# self.exposure_time_tuple = (33000, 35000, 37000, 39000, 41000, 36000)#5張AI 1張AOI
|
||
self.exposure_time_tuple_AI = (33000, 35000, 37000, 39000, 41000)
|
||
self.exposure_time_tuple_AOI = (32000, 34000, 36000, 38000, 40000)
|
||
|
||
# self.dbwindow.awm_key = 'M11-2303001'
|
||
|
||
self.IOCardThread.openYellowLight_closeDetctLight()
|
||
|
||
self.pushButton_TakeImage.setEnabled(False)
|
||
self.load_translations()
|
||
|
||
self.engineer_mode_window.Recipe_Change_Signal.connect(self.Recipe_Change)
|
||
# self.Recipe_Change()
|
||
|
||
self.aoi_op_lead_time_start = datetime.now()
|
||
self.aoi_op_lead_time_end = datetime.now()
|
||
def debugBar(self, msg):
|
||
self.statusBar().showMessage(str(msg), 5000)
|
||
|
||
def IOCardConnect(self):
|
||
self.IOCardThread.IOCard_connect()
|
||
if self.IOCardThread.connect:
|
||
self.debugBar('IOCard Connection!!!')
|
||
self.IOCardThread.open()
|
||
self.IOCardThread.start()
|
||
# self.IOCardThread.rawdataINPUT.connect(self.showInput)
|
||
else:
|
||
self.debugBar('IOCard Disconnection!!!')
|
||
|
||
def iniGuiEvent(self):
|
||
self.pushButton_Start.clicked.connect(self.Start)
|
||
self.pushButton_Reset.clicked.connect(self.Operate_stop)
|
||
self.pushButton_24Hours.clicked.connect(self.Start24_Thread)
|
||
self.timer.timeout.connect(self.updateCountdown)
|
||
self.pushButton_TakeImage.clicked.connect(self.take_trainning_image)
|
||
# self.modbus_reconnect_timer.timeout.connect(self.modbus_reconnect)
|
||
# self.motor_idle_timer.timeout.connect(self.motor_idle)
|
||
self.pushButton_Load_Recipe.clicked.connect(self.Load_recipe)
|
||
self.pushButton_ReDetect.clicked.connect(self.Redetect)
|
||
self.pushButton_Recipe_End.clicked.connect(self.Recipe_end)
|
||
# self.engineer_mode_window.comboBox_recipe.currentIndexChanged.connect(self.Recipe_Change)
|
||
self.login_window.pushButton_login.clicked.connect(self.Open_engineer_mode_Window)
|
||
self.pushButton_engineer_mode.clicked.connect(self.Open_login_Window)
|
||
self.engineer_mode_window.pushButton_TakeImage.clicked.connect(self.take_trainning_image)
|
||
self.engineer_mode_window.pushButton_24Hours.clicked.connect(self.Start24_Thread)
|
||
|
||
def Open_login_Window(self):
|
||
self.login_window.show()
|
||
|
||
def Open_engineer_mode_Window(self):
|
||
if self.login_window.logIn() == True:
|
||
self.engineer_mode_window.show()
|
||
self.login_window.close()
|
||
|
||
self.engineer_mode_window.checkBox_language_zh.clicked.connect(lambda: self.language_change('zh'))
|
||
self.engineer_mode_window.checkBox_language_en.clicked.connect(lambda: self.language_change('en'))
|
||
self.engineer_mode_window.checkBox_language_pt.clicked.connect(lambda: self.language_change('pt'))
|
||
self.engineer_mode_window.checkBox_language_tv.clicked.connect(lambda: self.language_change('tv'))
|
||
def load_translations(self):
|
||
file_path = './i18n_language/translations.yaml'
|
||
with open(file_path, 'r', encoding='utf-8') as file:
|
||
self.translations = yaml.safe_load(file)
|
||
def language_change(self, lang):
|
||
_translate = QtCore.QCoreApplication.translate
|
||
self.engineer_mode_window.label.setText(_translate("Screwdriver_Detection_EngineerMode_Window", self.translations.get(lang, {}).get('mode', "")))
|
||
|
||
self.pushButton_Start.setText(_translate("Screwdriver_Detection_Window", self.translations.get(lang, {}).get('pushButton_Start_Text', "")))
|
||
self.pushButton_Reset.setText(_translate("Screwdriver_Detection_Window", self.translations.get(lang, {}).get('pushButton_Reset_Text', "")))
|
||
self.pushButton_ReDetect.setText(_translate("Screwdriver_Detection_Window", self.translations.get(lang, {}).get('pushButton_ReDetect_Text', "")))
|
||
self.pushButton_Load_Recipe.setText(_translate("Screwdriver_Detection_Window", self.translations.get(lang, {}).get('pushButton_Load_Recipe_Text', "")))
|
||
self.pushButton_Recipe_End.setText(_translate("Screwdriver_Detection_Window", self.translations.get(lang, {}).get('pushButton_Recipe_End_Text', "")))
|
||
self.pushButton_engineer_mode.setText(_translate("Screwdriver_Detection_Window", self.translations.get(lang, {}).get('pushButton_engineer_mode_Text', "")))
|
||
|
||
self.label_workNumber.setText(_translate("Screwdriver_Detection_Window", self.translations.get(lang, {}).get('label_workNumber_Text', "")))
|
||
self.label_workAmount.setText(_translate("Screwdriver_Detection_Window", self.translations.get(lang, {}).get('label_workAmount_Text', "")))
|
||
self.label_partNumber.setText(_translate("Screwdriver_Detection_Window", self.translations.get(lang, {}).get('label_partNumber_Text', "")))
|
||
self.label_partName.setText(_translate("Screwdriver_Detection_Window", self.translations.get(lang, {}).get('label_partName_Text', "")))
|
||
self.label_workAmountReal.setText(_translate("Screwdriver_Detection_Window", self.translations.get(lang, {}).get('label_workAmountReal_Text', "")))
|
||
self.label_NGAmount.setText(_translate("Screwdriver_Detection_Window", self.translations.get(lang, {}).get('label_NGAmount_Text', "")))
|
||
self.label_passAmount.setText(_translate("Screwdriver_Detection_Window", self.translations.get(lang, {}).get('label_passAmount_Text', "")))
|
||
|
||
|
||
def Recipe_Change(self):
|
||
self.pushButton_Recipe_End.setEnabled(False)
|
||
self.pushButton_Load_Recipe.setEnabled(False)
|
||
self.pushButton_Start.setEnabled(False)
|
||
self.pushButton_ReDetect.setEnabled(False)
|
||
self.pushButton_24Hours.setEnabled(False)
|
||
self.pushButton_Reset.setEnabled(False)
|
||
self.pushButton_TakeImage.setEnabled(False)
|
||
try:
|
||
self.camera.Recipe_Change(self.engineer_mode_window.comboBox_recipe.currentText())
|
||
|
||
if self.engineer_mode_window.comboBox_recipe.currentText() == 'Milwaukee':
|
||
self.recipe_model = 'Milwaukee'
|
||
|
||
elif self.engineer_mode_window.comboBox_recipe.currentText() == 'KleinTool':
|
||
self.awm_Key_for_Recipe = 'M11-2303002'
|
||
self.dbwindow.awm_key = 'M11-2303002'
|
||
|
||
self.dev_logger.info(f'Recipe_Change {self.MYINI.recipe} --> {self.engineer_mode_window.comboBox_recipe.currentText()}')
|
||
self.MYINI.recipe_change(self.engineer_mode_window.comboBox_recipe.currentText())
|
||
threading.Thread(target=self.screwdrives_Object_Rebuild, args=()).start()
|
||
except Exception as e:
|
||
self.dev_logger.error(
|
||
f'Recipe_Change {self.MYINI.recipe} --> {self.engineer_mode_window.comboBox_recipe.currentText()}\n{e}')
|
||
def screwdrives_Object_Rebuild(self):
|
||
print('screwdrives_Object_Rebuild start')
|
||
self.screwdrives.clear()
|
||
gc.collect()
|
||
# print(f'self.MYINI.Identity_CodeName = {self.MYINI.Identity_CodeName}')
|
||
for i, k in enumerate(self.MYINI.Identity_CodeName):
|
||
# print(f'Identity_CodeName = {k}')
|
||
sd = ScrewDrive(r".\model", self.dev_logger, k, myIni=self.MYINI)
|
||
sd.report.connect(self.NG_Report)
|
||
sd.status.connect(self.statusChange)
|
||
self.screwdrives.append(sd)
|
||
print(f'screwdrives_Object_Rebuild_len(self.screwdrives) = {len(self.screwdrives)}')
|
||
self.pushButton_Recipe_End.setEnabled(True)
|
||
# self.pushButton_Load_Recipe.setEnabled(True)
|
||
self.pushButton_Start.setEnabled(True)
|
||
self.pushButton_ReDetect.setEnabled(True)
|
||
self.pushButton_24Hours.setEnabled(True)
|
||
self.pushButton_Reset.setEnabled(True)
|
||
self.pushButton_TakeImage.setEnabled(True)
|
||
self.comboBox_recipe.setEnabled(True)
|
||
|
||
def Redetect(self):
|
||
self.dbwindow.database_isOpen = False
|
||
self.dbwindow.isfirstchk = False
|
||
self.pushButton_Start.click()
|
||
self.real_detect_amount -= 1
|
||
|
||
def Load_recipe(self):
|
||
try:
|
||
br = abfactory()
|
||
br.process = CINO_S680
|
||
br.setup_baudrate('COM5', '9600')
|
||
br.turn_on_machine()
|
||
readData = br.readData()
|
||
self.dbwindow.awm_key = readData
|
||
self.awm_Key_for_Recipe = readData
|
||
print(f'br.readDate() = {self.dbwindow.awm_key}')
|
||
except Exception as e: #沒有接掃碼器 跳meesengeBox
|
||
# ------------------------------測試工單 20250117---------------------------
|
||
# self.dbwindow.awm_key = 'M11-2303001'
|
||
# self.awm_Key_for_Recipe = 'M11-2303001'
|
||
# ------------------------------KleinTool----------------------------------
|
||
self.dbwindow.awm_key = 'M11-24062691'
|
||
self.awm_Key_for_Recipe = 'M11-24062691'
|
||
# ------------------------------KleinToolblack----------------------------------
|
||
# self.dbwindow.awm_key = 'M11-24113803'
|
||
# self.awm_Key_for_Recipe = 'M11-24113803'
|
||
print(f'barcodereader error --- {e}')
|
||
|
||
try:
|
||
read_datas = self.dbwindow.get_aoi_op_master_datas(self.dbwindow.awm_key)
|
||
|
||
read_datas_weightname = self.dbwindow.get_aoi_recipe_master_datas(read_datas['part_no'])
|
||
|
||
self.recipe_model = self.get_tool_name_from_ini(read_datas_weightname['para1'].split('.')[0])
|
||
|
||
self.engineer_mode_window.comboBox_recipe.setCurrentText(self.recipe_model)
|
||
# self.Recipe_Change()
|
||
|
||
self.show_aoi_op_master_datas_on_UI(read_datas)
|
||
|
||
self.pushButton_Load_Recipe.setEnabled(False)
|
||
self.pushButton_Start.setEnabled(True)
|
||
self.pushButton_ReDetect.setEnabled(True)
|
||
self.pushButton_Recipe_End.setEnabled(True)
|
||
self.pushButton_Recipe_End.setStyleSheet(
|
||
'background-color: #4CAF50; border: 1px solid #dcdfe6; padding: 10px; border-radius: 20px;') # green
|
||
self.pushButton_Load_Recipe.setStyleSheet(
|
||
'background-color: #FF5555; border: 1px solid #dcdfe6; padding: 10px; border-radius: 20px;') # red
|
||
|
||
time.sleep(1)
|
||
|
||
self.aoi_op_lead_time_start = datetime.now()
|
||
print(f'aoi_op_lead_time_start = {self.aoi_op_lead_time_start}')
|
||
except Exception as e:
|
||
self.dev_logger.error(f'Load_recipe\n{e}')
|
||
self.showerror('工單讀取錯誤')
|
||
|
||
# 定義函式,讀取INI檔並查找對應工具名稱
|
||
def get_tool_name_from_ini(self, tool_id, ini_file='ScrewDrive.ini'):
|
||
config = configparser.ConfigParser()
|
||
config.read(ini_file)
|
||
|
||
# 迭代RECIPE_Model下的所有項目,查找對應的ID
|
||
for tool_name, id in config['RECIPE_Model'].items():
|
||
if id == tool_id:
|
||
# 將工具名稱的首字母變成大寫
|
||
if tool_name == 'milwaukee':
|
||
tool_name = 'Milwaukee'
|
||
elif tool_name == 'kleintool':
|
||
tool_name = 'KleinTool'
|
||
elif tool_name == 'kleintoolblack':
|
||
tool_name = 'KleinToolblack'
|
||
return tool_name
|
||
return 'Milwaukee'
|
||
def show_aoi_op_master_datas_on_UI(self, datas):
|
||
# print(datas)
|
||
self.label_ForRecipe_Change.setText(datas['awm_key'])
|
||
self.label_prod_qty.setText(str(datas['prod_qty']))
|
||
self.label_part_no.setText(datas['part_no'])
|
||
self.label_item_name.setText(datas['part_name'])
|
||
|
||
def Recipe_end(self):
|
||
self.screwdrives.clear()
|
||
gc.collect()
|
||
self.pushButton_Recipe_End.setEnabled(False)
|
||
self.pushButton_Start.setEnabled(False)
|
||
self.pushButton_ReDetect.setEnabled(False)
|
||
self.pushButton_Load_Recipe.setEnabled(True)
|
||
self.pushButton_Load_Recipe.setStyleSheet(
|
||
'background-color: #4CAF50; border: 1px solid #dcdfe6; padding: 10px; border-radius: 20px;') # green
|
||
self.pushButton_Recipe_End.setStyleSheet(
|
||
'background-color: #FF5555; border: 1px solid #dcdfe6; padding: 10px; border-radius: 20px;') # red
|
||
self.real_detect_amount = 0
|
||
self.NG_Count = 0
|
||
self.Start24_Count = 0
|
||
|
||
def motor_idle(self):
|
||
if self.IOCardThread.connect and self.pushButton_Start.accessibleName() == 'Start':
|
||
self.IOCardThread.motor_idle_time += 1
|
||
print('++++++++++1')
|
||
if self.IOCardThread.motor_idle_time == 2:
|
||
# self.motor_idle_timer.stop()
|
||
self.pushButton_Start.setText('System Idle')
|
||
self.pushButton_Start.setAccessibleName('System Idle')
|
||
self.IOCardThread.motor_idle_time = 0
|
||
self.moveMotorIn()
|
||
print('Idle state start')
|
||
|
||
def modbus_reconnect(self):
|
||
self.modbus.modbus_reconnect_time += 1#1分鐘進來1次
|
||
# print(f'閒置{self.modbus.modbus_reconnect_time}秒')
|
||
if self.modbus.modbus_reconnect_time == 60 or self.modbus.Modbus_isOpen == False:#閒置1小時 或 重連失敗時 重新連線
|
||
# print(f'重新連線了')
|
||
self.modbus.close_connection()
|
||
self.modbus.CloseModbus = True
|
||
time.sleep(3)
|
||
self.modbus = Modbus(dev_logger=self.dev_logger)
|
||
self.dev_logger.info('modbus_reconnect')
|
||
|
||
def iniLogging(self):
|
||
logging_FileName = time.strftime('%Y%m%d')
|
||
|
||
self.dev_logger: logging.Logger = logging.getLogger(name='dev')
|
||
self.dev_logger.setLevel(logging.DEBUG)
|
||
|
||
handler: logging.StreamHandler = logging.StreamHandler()
|
||
formatter: logging.Formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(filename)s - %(funcName)s - %(message)s')
|
||
handler.setFormatter(formatter)
|
||
self.dev_logger.addHandler(handler)
|
||
|
||
file_handler: logging.FileHandler = logging.FileHandler(rf'.\Logging\{logging_FileName}_dev.log', mode='a')
|
||
file_handler.setFormatter(formatter)
|
||
self.dev_logger.addHandler(file_handler)
|
||
|
||
def closeEvent(self, event):
|
||
print('window close')
|
||
self.dev_logger.info('window closing')
|
||
self.is_Timeup = False
|
||
self.moveMotorIn()
|
||
time.sleep(0.3)
|
||
self.IOCardThread.closeAll()
|
||
self.dev_logger.info('window closed')
|
||
QApplication.closeAllWindows()
|
||
|
||
def Operate_stop(self):
|
||
time.sleep(0.3)
|
||
# self.motor.Yellow()
|
||
self.IOCardThread.openYellowLight_closeDetctLight()
|
||
|
||
def DetectNG(self):
|
||
time.sleep(0.3)
|
||
# self.motor.Red()
|
||
self.IOCardThread.openRedLight_closeDetctLight()
|
||
if self.engineer_mode_window.checkBox_buzzerOn.isChecked() == True:
|
||
time.sleep(0.5)
|
||
# self.motor.Buzzer()
|
||
self.IOCardThread.detectEndNG()
|
||
|
||
def DetectOK(self):
|
||
time.sleep(0.3)
|
||
# self.motor.Green()
|
||
self.IOCardThread.openYellowLight_closeDetctLight()
|
||
|
||
def moveMotorOut(self):
|
||
print('moveMotorForward')
|
||
self.IOCardThread.updataDisSpeed(310, 400)#出來
|
||
def moveMotorIn(self):
|
||
print('moveMotorBackward')
|
||
self.IOCardThread.updataDisSpeed(-310, 400)#進去
|
||
def AI_Light(self):
|
||
self.IOCardThread.detectStart_1()
|
||
|
||
def AI_Light_Kleintools(self):
|
||
self.modbus.com1_on()
|
||
self.modbus.com2andcom3_on()
|
||
def AOI_Light(self):
|
||
self.IOCardThread.detectStart_2()
|
||
|
||
def updateCountdown(self):
|
||
hours, remainder = divmod(self.countdown_seconds, 3600)
|
||
minutes, seconds = divmod(remainder, 60)
|
||
|
||
time_str = f'{hours} H {minutes} M {seconds} S'
|
||
self.pushButton_24Hours.setText(time_str)
|
||
|
||
self.countdown_seconds -= 1
|
||
if self.countdown_seconds % 3600 == 0:
|
||
print('self.countdown_seconds % 3600 == 0:')
|
||
if self.countdown_seconds < 0:
|
||
self.timer.stop()
|
||
self.is_Timeup = False
|
||
self.pushButton_24Hours.setText('倒數結束')
|
||
def take_trainning_image(self):
|
||
try:
|
||
if os.path.exists(f'{self.engineer_mode_window.takeImage_file_route}') == True:
|
||
print(self.engineer_mode_window.takeImage_file_route)
|
||
self.Time_for_Record_ForSaveKleinTool = time.strftime('%Y%m%d_%H%M%S')
|
||
threading.Thread(target=self.take_trainning_image_Thread, args=()).start()
|
||
else:
|
||
self.engineer_mode_window.takeImage_file_route = ''
|
||
self.showerror('取像路徑錯誤')
|
||
|
||
except:
|
||
self.engineer_mode_window.takeImage_file_route = ''
|
||
self.showerror('取像路徑錯誤')
|
||
|
||
def showerror(self, hintMessage):
|
||
root = tk.Tk()
|
||
root.withdraw()
|
||
messagebox.showerror(title='error', message=hintMessage)
|
||
|
||
def take_trainning_image_Thread(self):
|
||
# self.move()
|
||
self.moveMotorIn()
|
||
self.AI_Light()
|
||
# self.AI_Light_Kleintools()
|
||
time.sleep(1.5)
|
||
self.engineer_mode_window.label_OK.setText('Taking Image')
|
||
self.engineer_mode_window.label_OK.setStyleSheet(
|
||
'background-color: #272727; color: white; border-radius: 5px; padding: 10px; font-size: 36px;')
|
||
|
||
for exp_time in self.exposure_time_tuple_AI:
|
||
threading.Thread(target=self.camera.SetExposureTime, args=(float(exp_time),)).start()
|
||
time.sleep(0.4)
|
||
|
||
self.inputimage = copy.deepcopy(self.camera.Image_RealTime)
|
||
self.Result = cv2.flip(copy.deepcopy(self.inputimage), 1)
|
||
cv2.imwrite(f'{self.engineer_mode_window.takeImage_file_route}/AI/{self.Time_for_Record_ForSaveKleinTool}_AI_{exp_time}.png',
|
||
cv2.cvtColor(self.Result, cv2.COLOR_BGR2GRAY))
|
||
|
||
self.AOI_Light()
|
||
time.sleep(0.15)
|
||
for exp_time in self.exposure_time_tuple_AOI:
|
||
threading.Thread(target=self.camera.SetExposureTime, args=(float(exp_time),)).start()
|
||
time.sleep(0.4)
|
||
|
||
self.inputimage = copy.deepcopy(self.camera.Image_RealTime)
|
||
self.Result = cv2.flip(copy.deepcopy(self.inputimage), 1)
|
||
cv2.imwrite(f'{self.engineer_mode_window.takeImage_file_route}/AOI/{self.Time_for_Record_ForSaveKleinTool}_AOI_{exp_time}.png',
|
||
cv2.cvtColor(self.Result, cv2.COLOR_BGR2GRAY))
|
||
|
||
self.After_CameraGrab()
|
||
self.engineer_mode_window.label_OK.setText('Finish')
|
||
self.engineer_mode_window.label_OK.setStyleSheet(
|
||
'background-color: #4CAF50; color: white; border-radius: 5px; padding: 10px; font-size: 36px;')
|
||
|
||
def Start24_Thread(self):
|
||
if self.is_Timeup == False:
|
||
self.NG_Count = 0
|
||
self.Start24_Count = 0
|
||
self.pushButton_Start.setEnabled(False)
|
||
self.countdown_seconds = 24 * 60 * 60 # 設定倒數秒數,這裡是 24 小時的秒數
|
||
self.timer.start(1000) # 設定定時器每秒觸發一次
|
||
self.is_Timeup = True
|
||
threading.Thread(target=self.Start24, args=()).start()
|
||
else:
|
||
self.is_Timeup = False
|
||
self.timer.stop()
|
||
self.pushButton_Start.setEnabled(True)
|
||
|
||
def Start24(self):
|
||
# now = datetime.now()
|
||
# later = now + timedelta(hours=24)
|
||
while self.is_Timeup:
|
||
# self.move()
|
||
self.moveMotorIn()
|
||
while not self.IOCardThread.MOTORSTATE[1]:
|
||
time.sleep(0.01)
|
||
self.AI_Light()
|
||
time.sleep(1)
|
||
self.label_OK.setText('calculating')
|
||
self.dbwindow.reset_data(self.awm_Key_for_Recipe)
|
||
self.dbwindow.creat_Serial_Number()
|
||
self.dbwindow.aoi_start = datetime.now()
|
||
self.starttime_ALLTIME = time.time()
|
||
# print(f' ------------------------------------TimeStart --> {time.time()} ------------------------------------')
|
||
self.All_AIPass = True
|
||
self.All_Report_count = 0
|
||
self.inputimage = copy.deepcopy(self.camera.Image_RealTime)
|
||
threading.Thread(target=self.camera.SetExposureTime, args=(self.MYINI.Camera_Setting['exposuretime_aoi'],)).start()
|
||
self.Result = cv2.flip(copy.deepcopy(self.inputimage), 1)
|
||
for sd in self.screwdrives:
|
||
sd.Result = self.Result
|
||
sd.image_AI = cv2.cvtColor(self.Result, cv2.COLOR_BGR2GRAY)
|
||
sd.Main(1, self.dbwindow.aoi_start)
|
||
# self.screwdrive.Result = self.Result
|
||
# self.screwdrive.image_AI = cv2.cvtColor(self.Result, cv2.COLOR_BGR2GRAY)
|
||
# self.screwdrive.Main(1, self.dbwindow.aoi_start)
|
||
starttime = time.time()
|
||
# self.camera.SetExposureTime(float(100000))
|
||
self.AOI_Light()
|
||
time.sleep(0.25)
|
||
# cv2.imwrite(f'./AI.png', self.screwdrive.image_AI)
|
||
for sd in self.screwdrives:
|
||
sd.image_AOI = cv2.cvtColor(cv2.flip(copy.deepcopy(self.camera.Image_RealTime), 1), cv2.COLOR_BGR2GRAY)
|
||
sd.AOIimage_ISREADY = True
|
||
# self.screwdrive.image_AOI = cv2.cvtColor(cv2.flip(copy.deepcopy(self.camera.Image_RealTime), 1),
|
||
# cv2.COLOR_BGR2GRAY)
|
||
# self.screwdrive.AOIimage_ISREADY = True
|
||
# cv2.imwrite(f'./AOI.png', self.screwdrive.image_AOI)
|
||
print(f'!!拍攝AOI影像 : {time.time() - starttime}')
|
||
self.After_CameraGrab()
|
||
# threading.Thread(target=self.After_CameraGrab, args=()).start()
|
||
|
||
time.sleep(6)
|
||
|
||
def Start(self):
|
||
# if self.awm_Key_for_Recipe == 'M11-2303001' and self.dbwindow.awm_key == 'M11-2303001':
|
||
# print(self.awm_Key_for_Recipe)
|
||
|
||
if self.recipe_model == 'Milwaukee':
|
||
threading.Thread(target=self.Start_Thread_Milwaukee, args=()).start()
|
||
# -------------------學長之前寫的測試工單-------------------------
|
||
# if self.awm_Key_for_Recipe == 'M11-2303002':
|
||
# threading.Thread(target=self.Start_Thread_KleinTools_Gray, args=()).start()
|
||
# -------------------20250117修改-------------------------
|
||
if self.recipe_model == 'KleinTool' or self.recipe_model == 'KleinToolblack':
|
||
threading.Thread(target=self.Start_Thread_KleinTools_Gray, args=()).start()
|
||
self.real_detect_amount += 1
|
||
def Start_Thread_Milwaukee(self):
|
||
if self.pushButton_Start.text() == 'System Idle':
|
||
# self.motor_idle_timer.start(5000)
|
||
self.moveMotorOut()
|
||
self.pushButton_Start.setText('Start')
|
||
self.pushButton_Start.setAccessibleName('Start')
|
||
|
||
print('Motor idle over')
|
||
else:
|
||
self.label_OK.setText('calculating')
|
||
self.pushButton_Start.setEnabled(False)
|
||
self.pushButton_ReDetect.setEnabled(False)
|
||
# self.move()
|
||
self.moveMotorIn()
|
||
time.sleep(0.1)
|
||
while not self.IOCardThread.MOTORSTATE[1]:
|
||
time.sleep(0.1)
|
||
# print(f'self.IOCardThread.MOTORSTATE = {self.IOCardThread.MOTORSTATE}')
|
||
self.AI_Light()
|
||
time.sleep(0.6)
|
||
self.dbwindow.reset_data(self.awm_Key_for_Recipe)
|
||
self.dbwindow.creat_Serial_Number()
|
||
self.dbwindow.aoi_start = datetime.now()
|
||
self.starttime_ALLTIME = time.time()
|
||
# print(f' ------------------------------------TimeStart --> {time.time()} ------------------------------------')
|
||
self.All_AIPass = True
|
||
self.All_Report_count = 0
|
||
self.inputimage = copy.deepcopy(self.camera.Image_RealTime)
|
||
threading.Thread(target=self.camera.SetExposureTime, args=(self.MYINI.Camera_Setting['exposuretime_aoi'],)).start()
|
||
self.Result = cv2.flip(copy.deepcopy(self.inputimage), 1)
|
||
for sd in self.screwdrives:
|
||
sd.Result = self.Result
|
||
sd.image_AI = cv2.cvtColor(self.Result, cv2.COLOR_BGR2GRAY)
|
||
sd.Main(1, self.dbwindow.aoi_start)
|
||
# self.screwdrive.Result = self.Result
|
||
# self.screwdrive.image_AI = cv2.cvtColor(self.Result, cv2.COLOR_BGR2GRAY)
|
||
# self.screwdrive.Main(1, self.dbwindow.aoi_start)
|
||
starttime = time.time()
|
||
# self.camera.SetExposureTime(float(100000))
|
||
self.AOI_Light()
|
||
time.sleep(0.15)
|
||
# cv2.imwrite(f'./AI.png', self.screwdrive.image_AI)
|
||
for sd in self.screwdrives:
|
||
sd.image_AOI = cv2.cvtColor(cv2.flip(copy.deepcopy(self.camera.Image_RealTime), 1), cv2.COLOR_BGR2GRAY)
|
||
sd.AOIimage_ISREADY = True
|
||
# self.screwdrive.image_AOI = cv2.cvtColor(cv2.flip(copy.deepcopy(self.camera.Image_RealTime), 1),
|
||
# cv2.COLOR_BGR2GRAY)
|
||
# self.screwdrive.AOIimage_ISREADY = True
|
||
# cv2.imwrite(f'./AOI.png', self.screwdrive.image_AOI)
|
||
print(f'!!拍攝AOI影像 : {time.time() - starttime}')
|
||
self.After_CameraGrab()
|
||
# threading.Thread(target=self.After_CameraGrab, args=()).start()
|
||
def Start_Thread_KleinTools_Gray(self):
|
||
if self.pushButton_Start.text() == 'System Idle':
|
||
# self.motor_idle_timer.start(5000)
|
||
self.moveMotorOut()
|
||
self.pushButton_Start.setText('Start')
|
||
self.pushButton_Start.setAccessibleName('Start')
|
||
print("KleinTools_Gray_start")
|
||
print('Motor idle over')
|
||
else:
|
||
print("KleinTools_Gray_start")
|
||
self.label_OK.setText('calculating')
|
||
self.pushButton_Start.setEnabled(False)
|
||
self.pushButton_ReDetect.setEnabled(False)
|
||
# self.move()
|
||
self.moveMotorIn()
|
||
threading.Thread(target=self.camera.SetExposureTime, args=(self.MYINI.Camera_Setting['exposuretime_aoi'],)).start()
|
||
time.sleep(0.1)
|
||
while not self.IOCardThread.MOTORSTATE[1]:
|
||
time.sleep(0.1)
|
||
# print(f'self.IOCardThread.MOTORSTATE = {self.IOCardThread.MOTORSTATE}')
|
||
self.AOI_Light()
|
||
time.sleep(0.6)
|
||
self.dbwindow.reset_data(self.awm_Key_for_Recipe)
|
||
self.dbwindow.creat_Serial_Number()
|
||
self.dbwindow.aoi_start = datetime.now()
|
||
self.starttime_ALLTIME = time.time()
|
||
# print(f' ------------------------------------TimeStart --> {time.time()} ------------------------------------')
|
||
self.All_AIPass = True
|
||
self.All_Report_count = 0
|
||
self.inputimage = copy.deepcopy(self.camera.Image_RealTime)
|
||
self.Result = cv2.flip(copy.deepcopy(self.inputimage), 1)
|
||
|
||
for sd in self.screwdrives:
|
||
sd.Result = self.Result
|
||
sd.image_AI = cv2.cvtColor(self.Result, cv2.COLOR_BGR2GRAY)
|
||
# cv2.imwrite(f'./AI.png', sd.image_AI)
|
||
sd.Main(1, self.dbwindow.aoi_start)
|
||
# self.screwdrive.Result = self.Result
|
||
# self.screwdrive.image_AI = cv2.cvtColor(self.Result, cv2.COLOR_BGR2GRAY)
|
||
# self.screwdrive.Main(1, self.dbwindow.aoi_start)
|
||
starttime = time.time()
|
||
# self.camera.SetExposureTime(float(100000))
|
||
time.sleep(0.15)
|
||
# cv2.imwrite(f'./AI.png', self.screwdrive.image_AI)
|
||
for sd in self.screwdrives:
|
||
# sd.image_AOI = cv2.cvtColor(cv2.flip(copy.deepcopy(self.camera.Image_RealTime), 1), cv2.COLOR_BGR2GRAY)
|
||
sd.image_AOI = copy.deepcopy(cv2.cvtColor(self.Result, cv2.COLOR_BGR2GRAY))
|
||
# cv2.imwrite(f'./AOI.png', sd.image_AOI)
|
||
sd.AOIimage_ISREADY = True
|
||
# self.screwdrive.image_AOI = cv2.cvtColor(cv2.flip(copy.deepcopy(self.camera.Image_RealTime), 1),
|
||
# cv2.COLOR_BGR2GRAY)
|
||
# self.screwdrive.AOIimage_ISREADY = True
|
||
# cv2.imwrite(f'./AOI.png', self.screwdrive.image_AOI)
|
||
print(f'!!拍攝AOI影像 : {time.time() - starttime}')
|
||
self.After_CameraGrab()
|
||
# threading.Thread(target=self.After_CameraGrab, args=()).start()
|
||
|
||
def After_CameraGrab(self):
|
||
# self.move()
|
||
self.moveMotorOut()
|
||
time.sleep(0.2)
|
||
|
||
self.camera.SetExposureTime(self.MYINI.Camera_Setting['exposuretime_ai'])
|
||
|
||
# if self.modbus.com1_Status:
|
||
# self.modbus.com1_off()
|
||
# self.modbus.com1_Status = not self.modbus.com1_Status
|
||
def statusChange(self, statusNow):
|
||
# if self.All_AIPass or self.checkBox_saveImage.isChecked():
|
||
# output_file_name = f'{self.camera.cam.ExposureTime.GetValue()}.png'
|
||
# output_file_path = fr"D:\ScrewdriverFile\ScrewdriverImage\0922\{output_file_name}"
|
||
# cv2.imwrite(output_file_path, self.inputimage)
|
||
if statusNow:
|
||
start = time.time()
|
||
self.imageLable_Show(self.label_Image, cv2.rotate(self.Result, cv2.ROTATE_90_CLOCKWISE))
|
||
end = time.time()
|
||
print(f'!!顯示影像 : {end - start:.8f}')
|
||
self.dbwindow.aoi_end = datetime.now()
|
||
print(f'!!ALLTIME : {time.time() - self.starttime_ALLTIME}')
|
||
starttime = time.time()
|
||
if self.All_Report_count == len(self.MYINI.Class_Name_All) * len(self.MYINI.Identity_CodeName):
|
||
# print(f'QQQQQQ:{self.aoi_op_lead_time_end} - {self.aoi_op_lead_time_start}')
|
||
self.aoi_op_lead_time_end = self.dbwindow.aoi_end
|
||
# print(f'QQQQQQ:{self.aoi_op_lead_time_end} - {self.aoi_op_lead_time_start}')
|
||
self.dbwindow.aoi_op_lead_time = str((self.aoi_op_lead_time_end - self.aoi_op_lead_time_start).total_seconds())
|
||
# print(f'{self.dbwindow.aoi_op_lead_time} = {self.aoi_op_lead_time_end} - {self.aoi_op_lead_time_start}')
|
||
self.aoi_op_lead_time_start = self.aoi_op_lead_time_end
|
||
|
||
self.dbwindow.write_data()
|
||
self.dbwindow.database_isOpen = True
|
||
|
||
time.sleep(0.5)
|
||
self.pushButton_Start.setEnabled(True)
|
||
self.pushButton_ReDetect.setEnabled(True)
|
||
endtime = time.time()
|
||
print(f'!!上傳資料庫 : {endtime - starttime}')
|
||
print(f'********************結束********************')
|
||
|
||
|
||
def NG_Report(self, is_OK, confidence, Index):
|
||
try:
|
||
self.All_Report(is_OK, confidence, Index)
|
||
# self.imageLable_Show(self.label_image_Result, self.Result)
|
||
|
||
if is_OK == 0:#AI False
|
||
self.All_AIPass = False
|
||
except Exception as e:
|
||
self.dev_logger.error(e)
|
||
|
||
def All_Report(self, is_OK, confidence, Index):
|
||
if not (is_OK in [1]):
|
||
if self.dbwindow.ng_bits_index == '':
|
||
self.dbwindow.ng_bits_index = self.All_Report_count + 1
|
||
else:
|
||
self.dbwindow.ng_bits_index = f'{self.dbwindow.ng_bits_index},{self.All_Report_count + 1}'
|
||
|
||
self.All_Report_count += 1
|
||
|
||
if self.All_Report_count == len(self.MYINI.Class_Name_All) * len(self.MYINI.Identity_CodeName):
|
||
self.Start24_Count += 1
|
||
if self.dbwindow.ng_bits_index == '':
|
||
self.dbwindow.pass_or_failure = True
|
||
self.DetectOK()
|
||
self.label_OK.setText('OK')
|
||
self.label_OK.setStyleSheet(
|
||
'background-color: #4CAF50; color: white; border-radius: 5px; padding: 10px; font-size: 36px;')
|
||
self.passdetect_amount += 1 #合格數量+1
|
||
self.label_passdetect_amount.setText(f'{self.passdetect_amount}')
|
||
|
||
elif len([x for x in self.screwdrives[0].NG_Image_Information.values() if 'slotted' in x]) > 12 and len(
|
||
[x for x in self.screwdrives[0].NG_Image_Information.values() if 'vacancy' in x]) > 12:
|
||
self.dbwindow.ng_bits_index = ''
|
||
self.dbwindow.pass_or_failure = True
|
||
self.DetectNG()
|
||
self.label_OK.setText('不計數')
|
||
self.label_OK.setStyleSheet(
|
||
'background-color: #4CAF50; color: white; border-radius: 5px; padding: 10px; font-size: 36px;')
|
||
else:
|
||
self.NG_Count += 1
|
||
try:
|
||
ng_bits_index_amount = len(self.dbwindow.ng_bits_index.split(","))
|
||
self.label_OK.setText(f'NG {ng_bits_index_amount}')
|
||
except Exception as e:
|
||
self.label_OK.setText(f'NG 1')
|
||
print(e)
|
||
self.label_OK.setStyleSheet(
|
||
'background-color: #FF5555; color: white; border-radius: 5px; padding: 10px; font-size: 36px;')
|
||
self.DetectNG()
|
||
self.lineEdit_NG_Count.setText(f'NG : {self.NG_Count} / {self.Start24_Count}')
|
||
|
||
self.label_detect_amount.setText(f'{self.real_detect_amount}')
|
||
# else:
|
||
# formatted_time = datetime.now().strftime('%Y%m%d_%H%M%S')
|
||
# cv2.imwrite(f'./Defect AI Image/{formatted_time}.png', self.Result)
|
||
def imageLable_Show(self, image_label, Show_image):
|
||
Show_image = cv2.cvtColor(Show_image, cv2.COLOR_BGR2RGB) # 圖像存儲使用8-8-8 24位RGB格式
|
||
rows, cols, channels = Show_image.shape # 獲取圖片長寬
|
||
QImg = QImage(Show_image.data, cols, rows, cols*channels, QImage.Format_RGB888)
|
||
pixmap = QPixmap.fromImage(QImg)
|
||
image_label.setPixmap(pixmap)
|
||
|
||
if __name__ == '__main__':
|
||
app = QApplication(sys.argv) # 固定的,PyQt5程式都需要QApplication對象。sys.argv是命令列參數清單,確保程式可以按兩下運行
|
||
MyWindow = Screwdriver_Detection() # 初始化
|
||
MyWindow.show() # 將視窗控制項顯示在螢幕上
|
||
sys.exit(app.exec_()) # 程式運行,sys.exit方法確保程式完整退出 |