init commit
This commit is contained in:
518
code/aio.py
Normal file
518
code/aio.py
Normal file
@ -0,0 +1,518 @@
|
||||
import json
|
||||
import threading
|
||||
import time
|
||||
|
||||
import ui.login_window as login_window
|
||||
import ui.reset_window as reset_window
|
||||
import ui.main_window as main_window
|
||||
from PySide6 import QtWidgets
|
||||
from PySide6.QtCore import Qt, QThread, Signal, QObject
|
||||
import sys
|
||||
import re
|
||||
import pymysql
|
||||
import hashlib
|
||||
import datetime
|
||||
import common.clibs as clibs
|
||||
import common.openapi as openapi
|
||||
from PySide6.QtWidgets import QMessageBox
|
||||
from PySide6.QtGui import QColor, QTextCursor, QTextCharFormat, QDoubleValidator
|
||||
from analysis import brake, current, wavelogger, iso
|
||||
|
||||
|
||||
class MultiWindows:
|
||||
login_window = None
|
||||
reset_window = None
|
||||
main_window = None
|
||||
|
||||
|
||||
class ConnDB(QObject):
|
||||
completed = Signal(tuple)
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def do_conn(self, action):
|
||||
conn, cursor = None, None
|
||||
try:
|
||||
conn = pymysql.connect(host='10.2.20.216', user='root', password='Rokae_123457', port=13306, charset='utf8', connect_timeout=clibs.INTERVAL*10)
|
||||
cursor = conn.cursor()
|
||||
except Exception:
|
||||
...
|
||||
finally:
|
||||
self.completed.emit((conn, cursor))
|
||||
|
||||
|
||||
class RunProg(QObject):
|
||||
completed = Signal(tuple)
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def program(self, action): # 0: prog 1: idx
|
||||
prog, idx, network = action
|
||||
if idx in range(7):
|
||||
run = prog.processing
|
||||
elif idx == -1:
|
||||
run = prog.net_conn
|
||||
elif idx == -99:
|
||||
run = prog
|
||||
|
||||
try:
|
||||
run()
|
||||
self.completed.emit((True, prog, "", idx, network)) # 运行是否成功/返回值/报错信息/idx
|
||||
except Exception as err:
|
||||
self.completed.emit((False, None, err, idx, network)) # 运行是否成功/返回值/报错信息/idx
|
||||
|
||||
|
||||
class ThreadIt(QObject):
|
||||
completed = Signal(tuple)
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def run_program(self, action):
|
||||
try:
|
||||
res = action[0](*action[1])
|
||||
self.completed.emit((True, res, "")) # 运行是否成功/返回值/报错信息
|
||||
except Exception as err:
|
||||
self.completed.emit((False, "", err))
|
||||
|
||||
|
||||
class LoginWindow(login_window.Ui_Form):
|
||||
action = Signal(int)
|
||||
|
||||
def __init__(self):
|
||||
super(LoginWindow, self).__init__()
|
||||
self.setupUi(self)
|
||||
self.le_username.setFocus()
|
||||
self.conn, self.cursor = None, None
|
||||
if not clibs.status["mysql"]:
|
||||
self.setup_DB()
|
||||
|
||||
def get_user_infos(self, results):
|
||||
self.conn, self.cursor = results
|
||||
if self.conn is None and self.cursor is None:
|
||||
QMessageBox.critical(self, "网络错误", "无法连接至服务器数据库,稍后再试......")
|
||||
try:
|
||||
MultiWindows.reset_window.close()
|
||||
except Exception:
|
||||
...
|
||||
finally:
|
||||
self.close()
|
||||
else:
|
||||
self.cursor.execute("SET autocommit = 1;")
|
||||
clibs.status["mysql"] = 1
|
||||
|
||||
def setup_DB(self):
|
||||
self.t = QThread(self)
|
||||
self.conn_db = ConnDB()
|
||||
self.conn_db.moveToThread(self.t)
|
||||
self.conn_db.completed.connect(self.get_user_infos)
|
||||
self.action.connect(self.conn_db.do_conn)
|
||||
self.t.start()
|
||||
self.action.emit(1)
|
||||
|
||||
def user_login(self):
|
||||
username = self.le_username.text()
|
||||
password = self.le_password.text()
|
||||
md = hashlib.md5(password.encode())
|
||||
password = md.hexdigest()
|
||||
|
||||
self.cursor.execute("use user_info;")
|
||||
self.cursor.execute("select * from UserInfo;")
|
||||
user_infos = self.cursor.fetchall()
|
||||
for user_info in user_infos:
|
||||
if user_info[0] == username and user_info[1] == password and user_info[2] == 0:
|
||||
MultiWindows.main_window = MainWindow(self.conn, self.cursor, username)
|
||||
MultiWindows.main_window.show()
|
||||
self.close()
|
||||
else:
|
||||
t = datetime.datetime.now().strftime("%H:%M:%S")
|
||||
self.label_hint.setText(f"[{t}] 用户名或密码错误,或用户已登录......")
|
||||
self.label_hint.setStyleSheet("color: red;")
|
||||
|
||||
def reset_password(self):
|
||||
MultiWindows.reset_window = ResetWindow(self, self.conn, self.cursor)
|
||||
MultiWindows.reset_window.show()
|
||||
self.setVisible(False)
|
||||
|
||||
|
||||
class ResetWindow(reset_window.Ui_Form):
|
||||
def __init__(self, login_window, conn, cursor):
|
||||
super(ResetWindow, self).__init__()
|
||||
self.setupUi(self)
|
||||
self.le_username.setFocus()
|
||||
self.login_window = login_window
|
||||
self.conn = conn
|
||||
self.cursor = cursor
|
||||
|
||||
def reset_password(self):
|
||||
username = self.le_username.text()
|
||||
old_password = self.le_old_password.text()
|
||||
md = hashlib.md5(old_password.encode())
|
||||
password = md.hexdigest()
|
||||
new_password_1 = self.le_new_password_1.text()
|
||||
new_password_2 = self.le_new_password_2.text()
|
||||
|
||||
self.cursor.execute("use user_info;")
|
||||
self.cursor.execute("select * from UserInfo;")
|
||||
user_infos = self.cursor.fetchall()
|
||||
|
||||
for user_info in user_infos:
|
||||
if user_info[0] == username and user_info[1] == password and user_info[2] == 0:
|
||||
break
|
||||
else:
|
||||
t = datetime.datetime.now().strftime("%H:%M:%S")
|
||||
self.label_hint.setText(f"[{t}] 用户名或密码错误,或用户已登录......")
|
||||
self.label_hint.setStyleSheet("color: red;")
|
||||
return
|
||||
|
||||
if new_password_1 != new_password_2 or len(new_password_1) < 8:
|
||||
t = datetime.datetime.now().strftime("%H:%M:%S")
|
||||
self.label_hint.setText(f"[{t}] 两次输入的新密码不匹配,或长度小于8位......")
|
||||
self.label_hint.setStyleSheet("color: red;")
|
||||
else:
|
||||
md = hashlib.md5(new_password_1.encode())
|
||||
password = md.hexdigest()
|
||||
self.cursor.execute(f"UPDATE UserInfo SET password = '{password}' WHERE username = '{username}'")
|
||||
self.close()
|
||||
|
||||
def reset_cancel(self):
|
||||
self.login_window.setVisible(True)
|
||||
self.close()
|
||||
|
||||
def closeEvent(self, event):
|
||||
self.login_window.setVisible(True)
|
||||
self.close()
|
||||
|
||||
|
||||
class MainWindow(main_window.Ui_MainWindow):
|
||||
action = Signal(tuple)
|
||||
|
||||
def __init__(self, conn, cursor, username):
|
||||
super(MainWindow, self).__init__()
|
||||
self.setupUi(self)
|
||||
self.conn = conn
|
||||
self.cursor = cursor
|
||||
self.username = username
|
||||
self.predoes()
|
||||
# self.t = threading.Thread(target=self.state_detection)
|
||||
# self.t.daemon = True
|
||||
# self.t.start()
|
||||
|
||||
def predoes(self):
|
||||
# ========================= db int =========================
|
||||
t = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
|
||||
self.cursor.execute(f"UPDATE UserInfo SET online = 1 WHERE username = '{self.username}';")
|
||||
self.cursor.execute(f"CREATE DATABASE IF NOT EXISTS {self.username};")
|
||||
self.cursor.execute(f"use {self.username};")
|
||||
self.cursor.execute(f"CREATE TABLE {t}_log (id INT AUTO_INCREMENT PRIMARY KEY, timestamp TIMESTAMP NOT NULL default CURRENT_TIMESTAMP, level ENUM('DEBUG', 'INFO', 'WARNING', 'ERROR'), module VARCHAR(255) NOT NULL, content TEXT);")
|
||||
self.cursor.execute(f"INSERT INTO {t}_log (module, level, content) VALUES (%s, %s, %s)", ("aio", "info", "testing"))
|
||||
self.cursor.execute("SHOW TABLES;")
|
||||
tables = [x[0] for x in self.cursor.fetchall()]
|
||||
if len(tables) > clibs.MAX_LOG_NUMBER:
|
||||
for table in sorted(tables)[:-10]:
|
||||
self.cursor.execute(f"DROP TABLE {table};")
|
||||
|
||||
# ========================= clibs =========================
|
||||
clibs.cursor = self.cursor
|
||||
clibs.tb_name = f"{t}_log"
|
||||
|
||||
# ========================= clibs =========================
|
||||
# validator = QDoubleValidator(bottom=300, decimals=2)
|
||||
# self.le_durable_interval.setValidator(validator)
|
||||
|
||||
# ========================= styleSheet =========================
|
||||
tws = [self.tw_funcs, self.tw_docs]
|
||||
for tw in tws:
|
||||
tw.setStyleSheet("""
|
||||
QTabBar::tab:selected {
|
||||
background: #0078D4;
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
}
|
||||
QTabBar::tab:!selected {
|
||||
background: #F0F0F0;
|
||||
color: #333;
|
||||
}
|
||||
QTabWidget::pane {
|
||||
border: 1px solid #CCCCCC;
|
||||
}
|
||||
""")
|
||||
|
||||
# ============================↓↓↓debug↓↓↓============================
|
||||
# print(f"self.cb_data_func.currentIndex() = {self.cb_data_func.currentIndex()}")
|
||||
|
||||
def run_program_thread(self, prog, idx, prog_done, network):
|
||||
self.tw_docs.setCurrentIndex(0)
|
||||
# self.pte_output.clear()
|
||||
if idx != -99:
|
||||
prog.output.connect(self.w2t)
|
||||
self.t = QThread(self)
|
||||
self.run = RunProg()
|
||||
self.run.moveToThread(self.t)
|
||||
self.run.completed.connect(prog_done)
|
||||
self.action.connect(self.run.program)
|
||||
self.t.start()
|
||||
self.action.emit((prog, idx, network))
|
||||
|
||||
def w2t(self, msg, color="black"):
|
||||
self.pte_output.appendHtml(f"<span style='color:{color};'>{msg}</span>")
|
||||
cursor = self.pte_output.textCursor()
|
||||
cursor.movePosition(QTextCursor.End)
|
||||
self.pte_output.setTextCursor(cursor)
|
||||
self.pte_output.ensureCursorVisible()
|
||||
self.update()
|
||||
|
||||
def prog_start(self):
|
||||
def prog_done(results):
|
||||
flag, result, error, idx, network = results
|
||||
clibs.running[idx] = 0
|
||||
# if flag is False:
|
||||
# self.w2t(f"{clibs.functions[idx]}运行失败:{error}", "red")
|
||||
# elif flag is True:
|
||||
# ...
|
||||
|
||||
if sum(clibs.running) > 0:
|
||||
if sum(clibs.running) == 1:
|
||||
QMessageBox.critical(self, "运行中", f"{clibs.functions[clibs.running.index(1)]}正在执行中,不可同时运行两个处理/测试程序!")
|
||||
return
|
||||
else:
|
||||
self.w2t(f"clibs.running = {clibs.running}", "red")
|
||||
self.w2t(f"clibs.functions = {clibs.functions}", "red")
|
||||
QMessageBox.critical(self, "严重错误", "理论上不允许同时运行两个处理程序,需要检查!")
|
||||
return
|
||||
|
||||
if self.tw_funcs.currentIndex() == 0 and self.cb_data_func.currentIndex() == 0:
|
||||
self.run_program_thread(brake.BrakeDataProcess(self.le_data_path.text()), 0, prog_done, None)
|
||||
elif self.tw_funcs.currentIndex() == 0 and self.cb_data_func.currentIndex() == 1:
|
||||
self.run_program_thread(current.CurrentDataProcess(self.le_data_path.text(), self.cb_data_current.currentText()), 1, prog_done, None)
|
||||
elif self.tw_funcs.currentIndex() == 0 and self.cb_data_func.currentIndex() == 2:
|
||||
self.run_program_thread(iso.IsoDataProcess(self.le_data_path.text()), 2, prog_done, None)
|
||||
elif self.tw_funcs.currentIndex() == 0 and self.cb_data_func.currentIndex() == 3:
|
||||
self.run_program_thread(wavelogger.WaveloggerDataProcess(self.le_data_path.text()), 3, prog_done, None)
|
||||
elif self.tw_funcs.currentIndex() == 1 and self.cb_unit_func.currentIndex() == 0:
|
||||
self.w2t(f"{clibs.functions[4]}功能待开发.....", "red")
|
||||
elif self.tw_funcs.currentIndex() == 1 and self.cb_unit_func.currentIndex() == 1:
|
||||
self.w2t(f"{clibs.functions[5]}功能待开发.....", "red")
|
||||
elif self.tw_funcs.currentIndex() == 2:
|
||||
self.w2t(f"{clibs.functions[6]}功能待开发.....", "red")
|
||||
|
||||
def prog_stop(self):
|
||||
QMessageBox.warning(self, "停止运行", "运行过程中不建议停止运行,可能会损坏文件,如果确实需要停止运行,可以直接关闭窗口!")
|
||||
|
||||
def prog_reset(self):
|
||||
self.pte_output.clear()
|
||||
|
||||
def file_browser(self):
|
||||
idx_dict = {0: self.le_data_path, 1: self.le_unit_path, 2: self.le_durable_path}
|
||||
dir_path = QtWidgets.QFileDialog.getExistingDirectory()
|
||||
tab_index = self.tw_funcs.currentIndex()
|
||||
if dir_path:
|
||||
idx_dict[tab_index].setText(dir_path)
|
||||
|
||||
def curve_draw(self):
|
||||
...
|
||||
|
||||
def durable_cb_change(self):
|
||||
...
|
||||
|
||||
def pre_page(self):
|
||||
...
|
||||
|
||||
def realtime_page(self):
|
||||
...
|
||||
|
||||
def next_page(self):
|
||||
...
|
||||
|
||||
def load_sql(self):
|
||||
...
|
||||
|
||||
def search_keyword(self):
|
||||
...
|
||||
|
||||
def prog_done_conn(self, results):
|
||||
flag, result, error, idx, network = results
|
||||
if flag is False:
|
||||
self.w2t(f"{network.upper()}连接失败", "red")
|
||||
elif flag is True:
|
||||
clibs.status[network] = 1
|
||||
if network == "hmi":
|
||||
self.btn_hmi_conn.setText("断开")
|
||||
clibs.c_hr = result
|
||||
elif network == "md":
|
||||
self.btn_md_conn.setText("断开")
|
||||
clibs.c_md = result
|
||||
elif network == "ec":
|
||||
self.btn_ec_conn.setText("断开")
|
||||
clibs.c_ec = result
|
||||
|
||||
def prog_done_disconn(self, results):
|
||||
flag, result, error, idx, network = results
|
||||
if flag is False:
|
||||
self.w2t(f"{network.upper()}断开连接失败", "red")
|
||||
elif flag is True:
|
||||
clibs.status[network] = 0
|
||||
if network == "hmi":
|
||||
self.btn_hmi_conn.setText("连接")
|
||||
clibs.c_hr = result
|
||||
elif network == "md":
|
||||
self.btn_md_conn.setText("连接")
|
||||
clibs.c_md = result
|
||||
elif network == "ec":
|
||||
self.btn_ec_conn.setText("连接")
|
||||
clibs.c_ec = result
|
||||
|
||||
def hmi_conn(self):
|
||||
if self.btn_hmi_conn.text() == "连接":
|
||||
clibs.ip_addr = self.le_hmi_ip.text().strip()
|
||||
ip_pattern = re.compile(r"(([1-9]?\d|1\d\d|2[0-4]\d|25[0-5])\.){3}([1-9]?\d|1\d\d|2[0-4]\d|25[0-5])")
|
||||
if not ip_pattern.fullmatch(clibs.ip_addr):
|
||||
self.w2t(f"{clibs.ip_addr} 不是一个有效的 IP 地址", "red")
|
||||
return
|
||||
self.run_program_thread(openapi.HmiRequest(clibs.ip_addr, clibs.socket_port, clibs.xService_port), -1, self.prog_done_conn, "hmi")
|
||||
elif self.btn_hmi_conn.text() == "断开":
|
||||
self.run_program_thread(clibs.c_hr.close, -99, self.prog_done_disconn, "hmi")
|
||||
|
||||
def md_conn(self):
|
||||
if clibs.status["hmi"] == 0:
|
||||
QMessageBox.warning(self, "告警", "打开Modbus连接之前,需要先打开HMI连接!")
|
||||
return
|
||||
|
||||
if self.btn_md_conn.text() == "连接":
|
||||
clibs.modbus_port = self.le_md_port.text().strip()
|
||||
self.run_program_thread(openapi.ModbusRequest(clibs.ip_addr, clibs.modbus_port), -1, self.prog_done_conn, "md")
|
||||
elif self.btn_md_conn.text() == "断开":
|
||||
self.run_program_thread(clibs.c_md.close, -99, self.prog_done_disconn, "md")
|
||||
|
||||
def ec_conn(self):
|
||||
if clibs.status["hmi"] == 0:
|
||||
QMessageBox.warning(self, "告警", "打开外部通信连接之前,需要先打开HMI连接!")
|
||||
return
|
||||
|
||||
if self.btn_ec_conn.text() == "连接":
|
||||
clibs.external_port = self.le_ec_port.text().strip()
|
||||
self.run_program_thread(openapi.ExternalCommunication(clibs.ip_addr, clibs.external_port), -1, self.prog_done_conn, "ec")
|
||||
elif self.btn_ec_conn.text() == "断开":
|
||||
self.run_program_thread(clibs.c_ec.close, -99, self.prog_done_disconn, "ec")
|
||||
|
||||
def hmi_page(self):
|
||||
self.sw_network.setCurrentIndex(0)
|
||||
|
||||
def md_page(self):
|
||||
self.sw_network.setCurrentIndex(1)
|
||||
|
||||
def ec_page(self):
|
||||
self.sw_network.setCurrentIndex(2)
|
||||
|
||||
def hmi_send(self):
|
||||
def prog_done(results):
|
||||
...
|
||||
|
||||
def hmi_send_thread():
|
||||
if clibs.status["hmi"] == 0:
|
||||
QMessageBox.critical(self, "错误", "使用该功能之前,需要先打开HMI连接!")
|
||||
return
|
||||
|
||||
cmd = self.pte_hmi_send.toPlainText()
|
||||
req = json.dumps(json.loads(cmd), separators=(",", ":"))
|
||||
print(f"type of cmd = {type(cmd)}")
|
||||
print(f"type of req = {type(req)}")
|
||||
if "id" in req: # 老协议
|
||||
print(f"wrong req = {req}")
|
||||
msg_id = json.loads(req)["id"]
|
||||
clibs.c_hr.c.send(clibs.c_hr.package(req))
|
||||
print(f"msg_id ={msg_id}")
|
||||
clibs.logger("INFO", "aio", f"hmi: [send] 老协议请求发送成功 {req}")
|
||||
records = clibs.c_hr.get_from_id(msg_id, "done")
|
||||
print(f"req = {req}")
|
||||
print(f"records = {records}")
|
||||
self.pte_him_recv.clear()
|
||||
self.pte_him_recv.appendPlainText(records)
|
||||
else: # 新协议
|
||||
clibs.c_hr.c_xs.send(clibs.c_hr.package_xs(json.loads(cmd)))
|
||||
data = ""
|
||||
time.sleep(clibs.INTERVAL/5)
|
||||
_ = clibs.c_hr.c_xs.recv(1024)
|
||||
while len(_) == 1024:
|
||||
data += _
|
||||
_ = clibs.c_hr.c_xs.recv(1024)
|
||||
|
||||
print(f"data = {data}")
|
||||
self.pte_him_recv.clear()
|
||||
self.pte_him_recv.appendPlainText(data.decode())
|
||||
self.run_program_thread(hmi_send_thread, -99, prog_done, None)
|
||||
|
||||
def md_send(self):
|
||||
...
|
||||
|
||||
def ec_send(self):
|
||||
...
|
||||
|
||||
def hmi_cb_change(self):
|
||||
cmd = self.cb_hmi_cmd.currentText()
|
||||
self.pte_hmi_send.clear()
|
||||
self.pte_him_recv.clear()
|
||||
with open(f"{clibs.PREFIX}/files/protocols/hmi/{cmd}.json", mode="r", encoding="utf-8") as f_hmi:
|
||||
t = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f")
|
||||
hmi_dict = json.load(f_hmi)
|
||||
if "id" in hmi_dict.keys():
|
||||
hmi_dict["id"] = f"{cmd}-{t}"
|
||||
|
||||
self.pte_hmi_send.appendPlainText(json.dumps(hmi_dict, indent=2, separators=(",", ":")))
|
||||
|
||||
def md_cb_change(self):
|
||||
...
|
||||
|
||||
def ec_cb_change(self):
|
||||
...
|
||||
|
||||
def check_interval(self):
|
||||
try:
|
||||
interval = float(self.le_durable_interval.text())
|
||||
interval = 300 if interval < 300 else int(interval)
|
||||
except Exception:
|
||||
interval = 300
|
||||
self.le_durable_interval.setText(str(interval))
|
||||
|
||||
def state_detection(self):
|
||||
while True:
|
||||
time.sleep(clibs.INTERVAL)
|
||||
if clibs.status["hmi"] == 0 and self.btn_hmi_conn.text() == "断开":
|
||||
self.btn_hmi_conn.setText("连接")
|
||||
elif clibs.status["hmi"] == 1 and self.btn_hmi_conn.text() == "连接":
|
||||
self.btn_hmi_conn.setText("断开")
|
||||
|
||||
def closeEvent(self, event):
|
||||
idx = -1 if clibs.running.count(1) == 0 else clibs.running.index(1)
|
||||
info_text = "当前无程序正在运行,可放心退出!" if idx == -1 else f"当前正在运行{clibs.functions[idx]},确认退出?"
|
||||
reply = QMessageBox.question(self, "退出", info_text)
|
||||
if reply == QMessageBox.Yes:
|
||||
try:
|
||||
self.cursor.execute(f"use user_info;")
|
||||
self.cursor.execute(f"UPDATE UserInfo SET online = 0 WHERE username = '{self.username}'")
|
||||
self.cursor.close()
|
||||
self.conn.close()
|
||||
finally:
|
||||
clibs.lock.release()
|
||||
|
||||
if clibs.status["md"] == 1:
|
||||
self.run_program_thread(clibs.c_md.close, -99, self.prog_done_disconn, "md")
|
||||
if clibs.status["ec"] == 1:
|
||||
self.run_program_thread(clibs.c_ec.close, -99, self.prog_done_disconn, "ec")
|
||||
if clibs.status["hmi"] == 1:
|
||||
self.run_program_thread(clibs.c_hr.close, -99, self.prog_done_disconn, "hmi")
|
||||
|
||||
self.close()
|
||||
event.accept()
|
||||
else:
|
||||
event.ignore()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
window = LoginWindow()
|
||||
window.show()
|
||||
sys.exit(app.exec())
|
||||
|
218
code/analysis/brake.py
Normal file
218
code/analysis/brake.py
Normal file
@ -0,0 +1,218 @@
|
||||
import json
|
||||
import os.path
|
||||
import time
|
||||
import pandas
|
||||
from PySide6.QtCore import Signal, QThread
|
||||
import openpyxl
|
||||
import re
|
||||
from common import clibs
|
||||
|
||||
|
||||
class BrakeDataProcess(QThread):
|
||||
output = Signal(str, str)
|
||||
|
||||
def __init__(self, dir_path, /):
|
||||
super().__init__()
|
||||
self.dir_path = dir_path
|
||||
self.idx = 0
|
||||
|
||||
def logger(self, level, module, content, color="black", error="", flag="both"):
|
||||
clibs.logger(level, module, content, color, flag, signal=self.output)
|
||||
if level.upper() == "ERROR":
|
||||
raise Exception(f"{error} | {content}")
|
||||
|
||||
def check_files(self, rawdata_dirs, result_files):
|
||||
msg_wrong = "需要有四个文件和若干个数据文件夹,可参考如下确认:<br>"
|
||||
msg_wrong += "- reach33/66/100_XXXXXXX.xlsx<br>- *.cfg<br>"
|
||||
msg_wrong += "- reach33_load33_speed33<br>- reach33_load33_speed66<br>...<br>- reach100_load100_speed66<br>- reach100_load100_speed100<br>"
|
||||
|
||||
if len(result_files) != 4 or len(rawdata_dirs) == 0:
|
||||
self.logger("ERROR", "brake-check_files", msg_wrong, "red", "InitFileError")
|
||||
|
||||
config_file, reach33_file, reach66_file, reach100_file = None, None, None, None
|
||||
for result_file in result_files:
|
||||
filename = result_file.split("/")[-1]
|
||||
if re.match(".*\\.cfg", filename):
|
||||
config_file = result_file
|
||||
elif filename.startswith("reach33_") and filename.endswith(".xlsx"):
|
||||
reach33_file = result_file
|
||||
elif filename.startswith("reach66_") and filename.endswith(".xlsx"):
|
||||
reach66_file = result_file
|
||||
elif filename.startswith("reach100_") and filename.endswith(".xlsx"):
|
||||
reach100_file = result_file
|
||||
else:
|
||||
if not (config_file and reach33_file and reach66_file and reach100_file):
|
||||
self.logger("ERROR", "brake-check_files", msg_wrong, "red", "InitFileError")
|
||||
|
||||
reach_s = ['reach33', 'reach66', 'reach100']
|
||||
load_s = ['load33', 'load66', 'load100']
|
||||
speed_s = ['speed33', 'speed66', 'speed100']
|
||||
prefix = []
|
||||
for rawdata_dir in rawdata_dirs:
|
||||
components = rawdata_dir.split("/")[-1].split('_') # reach_load_speed
|
||||
prefix.append(components[0])
|
||||
if components[0] not in reach_s or components[1] not in load_s or components[2] not in speed_s:
|
||||
msg = f"报错信息:数据目录 {rawdata_dir} 命名不合规,请参考如下形式<br>"
|
||||
msg += "命名规则:reachAA_loadBB_speedCC,AA/BB/CC 指的是臂展/负载/速度的比例<br>"
|
||||
msg += "规则解释:reach66_load100_speed33,表示 66% 臂展,100% 负载以及 33% 速度情况下的测试结果文件夹<br>"
|
||||
self.logger("ERROR", "brake-check_files", msg, "red", "WrongDataFolder")
|
||||
|
||||
_, rawdata_files = clibs.traversal_files(rawdata_dir, self.output)
|
||||
if len(rawdata_files) != 3:
|
||||
msg = f"数据目录 {rawdata_dir} 下数据文件个数错误,每个数据目录下有且只能有三个以 .data 为后缀的数据文件"
|
||||
self.logger("ERROR", "brake-check_files", msg, "red", "WrongDataFile")
|
||||
|
||||
for rawdata_file in rawdata_files:
|
||||
if not rawdata_file.endswith(".data"):
|
||||
msg = f"数据文件 {rawdata_file} 后缀错误,每个数据目录下有且只能有三个以 .data 为后缀的数据文件"
|
||||
self.logger("ERROR", "brake-check_files", msg, "red", "WrongDataFile")
|
||||
|
||||
result_files = []
|
||||
for _ in [reach33_file, reach66_file, reach100_file]:
|
||||
if _.split("/")[-1].split("_")[0] in set(prefix):
|
||||
result_files.append(_)
|
||||
|
||||
self.logger("INFO", "brake-check_files", "数据目录合规性检查结束,未发现问题......", "green")
|
||||
return config_file, result_files
|
||||
|
||||
def get_configs(self, config_file):
|
||||
try:
|
||||
with open(config_file, mode="r", encoding="utf-8") as f_config:
|
||||
configs = json.load(f_config)
|
||||
|
||||
p_dir = config_file.split('/')[-2]
|
||||
if not re.match("^[jJ][123]$", p_dir):
|
||||
self.logger("ERROR", "brake-get_configs-1", "被处理的根文件夹命名必须是 [Jj][123] 的格式", "red", "DirNameError")
|
||||
|
||||
axis = int(p_dir[-1]) # 要处理的轴
|
||||
rrs = [abs(_) for _ in configs["TRANSMISSION"]["REDUCTION_RATIO_NUMERATOR"]] # 减速比,rr for reduction ratio
|
||||
avs = configs["MOTION"]["JOINT_MAX_SPEED"]
|
||||
rr = rrs[axis-1]
|
||||
av = avs[axis-1]
|
||||
return av, rr
|
||||
except Exception as Err:
|
||||
self.logger("ERROR", "brake-get_configs-2", f"无法打开 {config_file},或者使用了错误的机型配置文件,需检查<br>{Err}", "red", "OpenFileError")
|
||||
|
||||
def now_doing_msg(self, docs, flag):
|
||||
now = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
|
||||
file_type = 'file' if os.path.isfile(docs) else 'dir'
|
||||
if flag == 'start' and file_type == 'dir':
|
||||
self.logger("INFO", "brake-now_doing_msg", f"[{now}] 正在处理目录 {docs} 中的数据......")
|
||||
elif flag == 'start' and file_type == 'file':
|
||||
self.logger("INFO", "brake-now_doing_msg", f"[{now}] 正在处理文件 {docs} 中的数据......")
|
||||
elif flag == 'done' and file_type == 'dir':
|
||||
self.logger("INFO", "brake-now_doing_msg", f"[{now}] 目录 {docs} 数据文件已处理完毕")
|
||||
elif flag == 'done' and file_type == 'file':
|
||||
self.logger("INFO", "brake-now_doing_msg", f"[{now}] 文件 {docs} 数据已处理完毕")
|
||||
|
||||
@staticmethod
|
||||
def data2result(df, ws_result, row_start, row_end):
|
||||
data = []
|
||||
for row in range(row_start, row_end):
|
||||
data.append(df.iloc[row, 0])
|
||||
data.append(df.iloc[row, 1])
|
||||
data.append(df.iloc[row, 2])
|
||||
|
||||
i = 0
|
||||
row_max = 1000 if row_end - row_start < 1000 else row_end - row_start + 100
|
||||
for row in range(2, row_max):
|
||||
try:
|
||||
ws_result.cell(row=row, column=1).value = data[i]
|
||||
ws_result.cell(row=row, column=2).value = data[i + 1]
|
||||
ws_result.cell(row=row, column=3).value = data[i + 2]
|
||||
i += 3
|
||||
except Exception:
|
||||
ws_result.cell(row=row, column=1).value = None
|
||||
ws_result.cell(row=row, column=2).value = None
|
||||
ws_result.cell(row=row, column=3).value = None
|
||||
|
||||
def get_row_range(self, data_file, df, conditions, av, rr):
|
||||
row_start, row_end = 0, 0
|
||||
ratio = float(conditions[2].removeprefix('speed')) / 100
|
||||
av_max = av * ratio
|
||||
threshold = 0.95
|
||||
|
||||
for row in range(df.index[-1] - 1, -1, -10):
|
||||
if df.iloc[row, 2] != 0:
|
||||
row_start = row - 20 if row - 20 > 0 else 0 # 急停前找 20 个点
|
||||
break
|
||||
else:
|
||||
self.logger("ERROR", "brake-get_row_range", f"数据文件 {data_file} 采集的数据中没有 ESTOP 为非 0 的情况,需要确认", "red", "StartNotFoundError")
|
||||
|
||||
for row in range(row_start, df.index[-1] - 1, 10):
|
||||
speed_row = df.iloc[row, 0] * clibs.RADIAN * rr * 60 / 360
|
||||
if abs(speed_row) < 1:
|
||||
row_end = row + 100 if row + 100 <= df.index[-1] - 1 else df.index[-1] - 1
|
||||
break
|
||||
else:
|
||||
self.logger("ERROR", "brake-get_row_range", f"数据文件 {data_file} 最后的速度未降为零", "red", "SpeedNotZeroError")
|
||||
|
||||
av_estop = abs(df.iloc[row_start - 20:row_start, 0].abs().mean() * clibs.RADIAN)
|
||||
if abs(av_estop / av_max) < threshold:
|
||||
filename = data_file.split("/")[-1]
|
||||
msg = f"[av_estop: {av_estop:.2f} | shouldbe: {av_max:.2f}] 数据文件 {filename} 触发 ESTOP 时未采集到指定百分比的最大速度,需要检查"
|
||||
self.logger("WARNING", "brake-get_row_range", msg, "#8A2BE2")
|
||||
|
||||
return row_start, row_end
|
||||
|
||||
@staticmethod
|
||||
def get_shtname(conditions, count):
|
||||
# 33%负载_33%速度_1 - reach/load/speed
|
||||
load = conditions[1].removeprefix('load')
|
||||
speed = conditions[2].removeprefix('speed')
|
||||
result_sheet_name = f"{load}%负载_{speed}%速度_{count}"
|
||||
|
||||
return result_sheet_name
|
||||
|
||||
def single_file_process(self, data_file, wb, count, av, rr):
|
||||
df = pandas.read_csv(data_file, sep='\t')
|
||||
conditions = data_file.split("/")[-2].split("_") # reach/load/speed
|
||||
shtname = self.get_shtname(conditions, count)
|
||||
ws = wb[shtname]
|
||||
|
||||
row_start, row_end = self.get_row_range(data_file, df, conditions, av, rr)
|
||||
self.data2result(df, ws, row_start, row_end)
|
||||
|
||||
def data_process(self, result_file, rawdata_dirs, av, rr):
|
||||
filename = result_file.split("/")[-1]
|
||||
self.logger("INFO", "brake-data_process", f"正在打开文件 {filename},这可能需要一些时间......", "blue")
|
||||
try:
|
||||
wb = openpyxl.load_workbook(result_file)
|
||||
except Exception as Err:
|
||||
self.logger("ERROR", "brake-data_process", f"{filename}文件打开失败,可能是文件已损坏,确认后重新执行!<br>{Err}", "red", "CannotOpenFile")
|
||||
|
||||
prefix = filename.split('_')[0]
|
||||
for rawdata_dir in rawdata_dirs:
|
||||
if rawdata_dir.split("/")[-1].split('_')[0] == prefix:
|
||||
self.now_doing_msg(rawdata_dir, 'start')
|
||||
_, data_files = clibs.traversal_files(rawdata_dir, self.output)
|
||||
for idx in range(3):
|
||||
self.single_file_process(data_files[idx], wb, idx+1, av, rr)
|
||||
# threads = [
|
||||
# threading.Thread(target=self.single_file_process, args=(data_files[0], wb, 1, av, rr)),
|
||||
# threading.Thread(target=self.single_file_process, args=(data_files[1], wb, 2, av, rr)),
|
||||
# threading.Thread(target=self.single_file_process, args=(data_files[2], wb, 3, av, rr))
|
||||
# ]
|
||||
# [t.start() for t in threads]
|
||||
# [t.join() for t in threads]
|
||||
self.now_doing_msg(rawdata_dir, 'done')
|
||||
|
||||
self.logger("INFO", "brake-data_process", f"正在保存文件 {filename},这可能需要一些时间......<br>", "blue")
|
||||
wb.save(result_file)
|
||||
wb.close()
|
||||
|
||||
def processing(self):
|
||||
time_start = time.time()
|
||||
clibs.running[self.idx] = 1
|
||||
|
||||
rawdata_dirs, result_files = clibs.traversal_files(self.dir_path, self.output)
|
||||
config_file, result_files = self.check_files(rawdata_dirs, result_files)
|
||||
av, rr = self.get_configs(config_file)
|
||||
|
||||
for result_file in result_files:
|
||||
self.data_process(result_file, rawdata_dirs, av, rr)
|
||||
|
||||
self.logger("INFO", "brake-processing", "-"*60 + "<br>全部处理完毕<br>", "purple")
|
||||
time_total = time.time() - time_start
|
||||
msg = f"处理时间:{time_total // 3600:02.0f} h {time_total % 3600 // 60:02.0f} m {time_total % 60:02.0f} s"
|
||||
self.logger("INFO", "brake-processing", msg)
|
427
code/analysis/current.py
Normal file
427
code/analysis/current.py
Normal file
@ -0,0 +1,427 @@
|
||||
import json
|
||||
import openpyxl
|
||||
import pandas
|
||||
import re
|
||||
import csv
|
||||
from PySide6.QtCore import Signal, QThread
|
||||
import time
|
||||
from common import clibs
|
||||
|
||||
|
||||
class CurrentDataProcess(QThread):
|
||||
output = Signal(str, str)
|
||||
|
||||
def __init__(self, dir_path, proc, /):
|
||||
super().__init__()
|
||||
self.dir_path = dir_path
|
||||
self.proc = proc
|
||||
self.idx = 1
|
||||
|
||||
def logger(self, level, module, content, color="black", error="", flag="both"):
|
||||
clibs.logger(level, module, content, color, flag, signal=self.output)
|
||||
if level.upper() == "ERROR":
|
||||
raise Exception(f"{error} | {content}")
|
||||
|
||||
def initialization(self):
|
||||
_, data_files = clibs.traversal_files(self.dir_path, self.output)
|
||||
count, config_file = 0, None
|
||||
for data_file in data_files:
|
||||
filename = data_file.split("/")[-1]
|
||||
if re.match(".*\\.cfg", filename):
|
||||
config_file = data_file
|
||||
count += 1
|
||||
elif filename == "T_电机电流.xlsx":
|
||||
count += 1
|
||||
else:
|
||||
if not re.match("^j[1-7].*\\.data$", filename):
|
||||
msg = f"不合规 {data_file}<br>"
|
||||
msg += "所有数据文件必须以 j[1-7]_ 开头,以 .data 结尾,比如j1_abcdef.data,请检查整改后重新运行"
|
||||
self.logger("ERROR", "current-initialization", msg, "red", "FilenameIllegal")
|
||||
|
||||
if count != 2:
|
||||
msg = "需要有一个机型配置文件\"*.cfg\",以及一个数据处理文件\"T_电机电流.xlsx\"表格,请检查整改后重新运行"
|
||||
self.logger("ERROR", "current-initialization", msg, "red", "FilenameIllegal")
|
||||
|
||||
return data_files, config_file
|
||||
|
||||
def current_max(self, data_files, rts):
|
||||
self.logger("INFO", "current-current_max", f"正在处理最大转矩值逻辑......")
|
||||
current = {1: [], 2: [], 3: [], 4: [], 5: [], 6: []}
|
||||
for data_file in data_files:
|
||||
if data_file.endswith(".data"):
|
||||
df = pandas.read_csv(data_file, sep="\t")
|
||||
else:
|
||||
continue
|
||||
|
||||
self.logger("INFO", "current-current_max", f"正在处理 {data_file} ...")
|
||||
cols = len(df.columns)
|
||||
axis = int(data_file.split("/")[-1].split("_")[0].removeprefix("j"))
|
||||
rt = rts[axis-1]
|
||||
self.logger("INFO", "current-current_max", f"最大列数为 {cols},{axis} 轴的额定转矩为 {rt}")
|
||||
|
||||
col = df.columns.values[clibs.c_servo_trq-1] # 获取 "device_servo_trq_feedback"
|
||||
c_max = df[col].abs().max()
|
||||
|
||||
scale = 1000
|
||||
_ = abs(c_max/scale*rt)
|
||||
current[axis].append(_)
|
||||
self.logger("INFO", "current-current_max", f"{data_file}: {_:.2f}")
|
||||
self.logger("INFO", "current-current_max", f"获取到的列名为 {col},最大转矩为 {_}")
|
||||
|
||||
with open(data_file, "a+") as f_data:
|
||||
csv_writer = csv.writer(f_data, delimiter="\t")
|
||||
csv_writer.writerow([""] * (cols-1) + [_])
|
||||
|
||||
for axis, cur in current.items():
|
||||
if not cur:
|
||||
continue
|
||||
else:
|
||||
_ = ""
|
||||
for value in cur:
|
||||
_ += f"{value:.4f} "
|
||||
self.logger("INFO", "current-current_max", f"{axis}轴最大转矩数据:{_}")
|
||||
|
||||
self.logger("INFO", "current-current_max", f"获取最大转矩值结束 current_max = {current}")
|
||||
self.logger("INFO", "current-current_max", f"最大转矩数据处理完毕......")
|
||||
return current
|
||||
|
||||
def current_avg(self, data_files, rts):
|
||||
self.logger("INFO", "current-current_avg", f"正在处理平均转矩值逻辑......")
|
||||
current = {1: [], 2: [], 3: [], 4: [], 5: [], 6: []}
|
||||
for data_file in data_files:
|
||||
if data_file.endswith(".data"):
|
||||
df = pandas.read_csv(data_file, sep="\t")
|
||||
else:
|
||||
continue
|
||||
|
||||
self.logger("INFO", "current-current_avg", f"正在处理 {data_file} ...")
|
||||
cols = len(df.columns)
|
||||
axis = int(data_file.split("/")[-1].split("_")[0].removeprefix("j"))
|
||||
rt = rts[axis-1]
|
||||
self.logger("INFO", "current-current_avg", f"最大列数为 {cols},{axis} 轴的额定转矩为 {rt}")
|
||||
|
||||
col = df.columns.values[clibs.c_servo_trq-1]
|
||||
c_std = df[col].std()
|
||||
c_avg = df[col].mean()
|
||||
|
||||
scale = 1000
|
||||
_ = (abs(c_avg)+c_std*3)/scale*rt
|
||||
current[axis].append(_)
|
||||
self.logger("INFO", "current-current_avg", f"{data_file}: {_:.2f}")
|
||||
self.logger("INFO", "current-current_avg", f"获取到的列名为 {col},平均转矩为 {_}")
|
||||
|
||||
with open(data_file, "a+") as f_data:
|
||||
csv_writer = csv.writer(f_data, delimiter="\t")
|
||||
csv_writer.writerow([""] * (cols-1) + [_])
|
||||
|
||||
for axis, cur in current.items():
|
||||
if not cur:
|
||||
continue
|
||||
else:
|
||||
_ = ""
|
||||
for value in cur:
|
||||
_ += f"{value:.4f} "
|
||||
self.logger("INFO", "current-current_avg", f"{axis}轴平均转矩数据:{_}")
|
||||
|
||||
self.logger("INFO", "current-current_avg", f"获取平均转矩值结束 current_avg = {current}", flag="cursor")
|
||||
self.logger("INFO", "current-current_avg", f"平均转矩数据处理完毕......")
|
||||
return current
|
||||
|
||||
def current_cycle(self, data_files, rrs, rts, params):
|
||||
result, hold, single, scenario, dur_time = None, [], [], [], 0
|
||||
for data_file in data_files:
|
||||
filename = data_file.split("/")[-1]
|
||||
if filename == "T_电机电流.xlsx":
|
||||
result = data_file
|
||||
elif re.match("j[1-7]_hold_.*\\.data", filename):
|
||||
hold.append(data_file)
|
||||
elif re.match("j[1-7]_s_.*\\.data", filename):
|
||||
scenario.append(data_file)
|
||||
dur_time = float(filename.split("_")[3])
|
||||
elif re.match("j[1-7]_.*\\.data", filename):
|
||||
single.append(data_file)
|
||||
|
||||
clibs.stop, filename = True, result.split("/")[-1]
|
||||
self.logger("INFO", "current-current_cycle", f"正在打开文件 {filename},这可能需要一些时间......", "blue")
|
||||
try:
|
||||
wb = openpyxl.load_workbook(result)
|
||||
except Exception as Err:
|
||||
self.logger("ERROR", "current-current_cycle", f"{filename}文件打开失败,可能是文件已损坏,确认后重新执行!<br>{Err}", "red", "CannotOpenFile")
|
||||
|
||||
ws = wb["统计"]
|
||||
for idx in range(len(params)-1):
|
||||
row = idx + 2
|
||||
for col in range(2, 8):
|
||||
ws.cell(row=row, column=col).value = params[idx][col-2]
|
||||
ws.cell(row=1, column=1).value = params[-1]
|
||||
|
||||
if hold:
|
||||
avg = self.current_avg(hold, rts)
|
||||
for axis, cur_value in avg.items():
|
||||
sht_name = f"J{axis}"
|
||||
wb[sht_name]["P4"].value = float(cur_value[0])
|
||||
|
||||
if dur_time == 0:
|
||||
self.p_single(wb, single, rrs)
|
||||
else:
|
||||
self.p_scenario(wb, scenario, rrs, dur_time)
|
||||
|
||||
self.logger("INFO", "current-current_cycle", f"正在保存文件 {filename},这可能需要一些时间......", "blue")
|
||||
wb.save(result)
|
||||
wb.close()
|
||||
|
||||
def find_point(self, data_file, df, flag, row_s, row_e, threshold, step, end_point, skip_scale, axis, seq):
|
||||
if flag == "lt":
|
||||
while row_e > end_point:
|
||||
speed_avg = df.iloc[row_s:row_e].abs().mean()
|
||||
if speed_avg < threshold:
|
||||
row_e -= step
|
||||
row_s -= step
|
||||
continue
|
||||
else:
|
||||
# one more time,如果连续两次 200 个点的平均值都大于 threshold,说明已经到了临界点了(其实也不一定,只不过相对遇到一次就判定临界点更安全一点点)
|
||||
# 从实际数据看,这开逻辑很小概率能触发到
|
||||
speed_avg = df.iloc[row_s-end_point*skip_scale:row_e-end_point*skip_scale].abs().mean()
|
||||
if speed_avg < threshold:
|
||||
self.logger("WARNING", "current-find_point", f"【lt】{axis} 轴第 {seq} 次查找数据可能有异常,row_s = {row_s}, row_e = {row_e}!", "purple")
|
||||
return row_s, row_e
|
||||
else:
|
||||
self.logger("ERROR", "current-find_point", f"{data_file} 数据有误,需要检查,无法找到第 {seq} 个有效点......", "red", "AnchorNotFound")
|
||||
elif flag == "gt":
|
||||
while row_e > end_point:
|
||||
speed_avg = df.iloc[row_s:row_e].abs().mean()
|
||||
# if axis == 1 and seq == 1:
|
||||
# insert_logdb("DEBUG", "current", f"【gt】{axis} 轴,speed_avg = {speed_avg},row_s = {row_s}, row_e = {row_e}!")
|
||||
if speed_avg > threshold:
|
||||
row_e -= step
|
||||
row_s -= step
|
||||
continue
|
||||
else:
|
||||
# one more time,如果连续两次 200 个点的平均值都小于 threshold,说明已经到了临界点了(其实也不一定,只不过相对遇到一次就判定临界点更安全一点点)
|
||||
# 从实际数据看,这开逻辑很小概率能触发到
|
||||
speed_avg = df.iloc[row_s-end_point*skip_scale:row_e-end_point*skip_scale].abs().mean()
|
||||
if speed_avg > threshold:
|
||||
self.logger("WARNING", "current-find_point", f"【gt】{axis} 轴第 {seq} 次查找数据可能有异常,row_s = {row_s}, row_e = {row_e}!", "purple")
|
||||
return row_s, row_e
|
||||
else:
|
||||
self.logger("ERROR", "current-find_point", f"{data_file} 数据有误,需要检查,无法找到第 {seq} 个有效点......", "red", "AnchorNotFound")
|
||||
|
||||
def get_row_number(self, threshold, flag, df, row_s, row_e, axis):
|
||||
count_1, count_2 = 0, 0
|
||||
if flag == "start" or flag == "end":
|
||||
for number in df.iloc[row_s:row_e].abs():
|
||||
count_2 += 1
|
||||
if number > threshold:
|
||||
count_1 += 1
|
||||
if count_1 == 10:
|
||||
return row_s + count_2 - 10
|
||||
else:
|
||||
count_1 = 0
|
||||
elif flag == "middle":
|
||||
for number in df.iloc[row_s:row_e].abs():
|
||||
count_2 += 1
|
||||
if number < threshold: # 唯一的区别
|
||||
count_1 += 1
|
||||
if count_1 == 10:
|
||||
return row_s + count_2 - 10
|
||||
else:
|
||||
count_1 = 0
|
||||
|
||||
places = {"start": "起点", "middle": "中间点", "end": "终点"} # 因为是终点数据,所以可能有异常
|
||||
self.logger("WARNING", "current-get_row_number", f"{axis} 轴获取{places[flag]}数据 {row_e} 可能有异常,需关注!", "purple")
|
||||
return row_e
|
||||
|
||||
def p_single(self, wb, single, rrs):
|
||||
# 1. 先找到第一个速度为零的点,数据从后往前找,一开始就是零的情况不予考虑
|
||||
# 2. 记录第一个点的位置,继续向前查找第二个速度为零的点,同理,一开始为零的点不予考虑
|
||||
# 3. 记录第二个点的位置,并将其中的数据拷贝至对应位置
|
||||
for data_file in single:
|
||||
axis = int(data_file.split("/")[-1].split("_")[0].removeprefix("j"))
|
||||
sht_name = f"J{axis}"
|
||||
ws = wb[sht_name]
|
||||
pandas.set_option("display.precision", 2)
|
||||
df_origin = pandas.read_csv(data_file, sep="\t")
|
||||
rr = rrs[axis-1]
|
||||
addition = 180 / 3.1415926 * 60 / 360 * rr
|
||||
|
||||
col_names = list(df_origin.columns)
|
||||
df = df_origin[col_names[clibs.c_joint_vel-1]].multiply(addition)
|
||||
|
||||
step = 50 # 步进值
|
||||
end_point = 200 # 有效数值的数目
|
||||
threshold = 5 # 200个点的平均阈值线
|
||||
skip_scale = 2
|
||||
row_start, row_middle, row_end = 0, 0, 0
|
||||
row_e = df.index[-1]
|
||||
row_s = row_e - end_point
|
||||
speed_avg = df.iloc[row_s:row_e].abs().mean()
|
||||
if speed_avg < threshold:
|
||||
# 第一次过滤:消除速度为零的数据,找到速度即将大于零的上升临界点
|
||||
row_s, row_e = self.find_point(data_file, df, "lt", row_s, row_e, threshold, step, end_point, skip_scale, axis, "pre-1")
|
||||
row_e -= end_point*skip_scale
|
||||
row_s -= end_point*skip_scale
|
||||
# 第二次过滤:消除速度大于零的数据,找到速度即将趋近于零的下降临界点
|
||||
row_s, row_e = self.find_point(data_file, df, "gt", row_s, row_e, threshold, step, end_point, skip_scale, axis, "pre-2")
|
||||
row_e -= end_point*skip_scale
|
||||
row_s -= end_point*skip_scale
|
||||
# 第三次过滤:消除速度为零的数据,找到速度即将大于零的上升临界点
|
||||
row_s, row_e = self.find_point(data_file, df, "lt", row_s, row_e, threshold, step, end_point, skip_scale, axis, "pre-3")
|
||||
row_e -= end_point*skip_scale
|
||||
row_s -= end_point*skip_scale
|
||||
# 正式第一次采集:消除速度大于零的数据,找到速度即将趋近于零的下降临界点
|
||||
row_s, row_e = self.find_point(data_file, df, "gt", row_s, row_e, threshold, step, end_point, skip_scale, axis, 1)
|
||||
row_end = self.get_row_number(threshold, "end", df, row_s, row_e, axis)
|
||||
row_e -= end_point*skip_scale
|
||||
row_s -= end_point*skip_scale
|
||||
# 正式第二次采集:消除速度为零的数据,找到速度即将大于零的上升临界点
|
||||
row_s, row_e = self.find_point(data_file, df, "lt", row_s, row_e, threshold, step, end_point, skip_scale, axis, 2)
|
||||
row_middle = self.get_row_number(threshold, "middle", df, row_s, row_e, axis)
|
||||
row_e -= end_point*skip_scale
|
||||
row_s -= end_point*skip_scale
|
||||
# 正式第三次采集:消除速度大于零的数据,找到速度即将趋近于零的下降临界点
|
||||
row_s, row_e = self.find_point(data_file, df, "gt", row_s, row_e, threshold, step, end_point, skip_scale, axis, 3)
|
||||
row_start = self.get_row_number(threshold, "start", df, row_s, row_e, axis)
|
||||
elif speed_avg > threshold:
|
||||
# 第一次过滤:消除速度大于零的数据,找到速度即将趋近于零的下降临界点
|
||||
row_s, row_e = self.find_point(data_file, df, "gt", row_s, row_e, threshold, step, end_point, skip_scale, axis, "pre-1")
|
||||
row_e -= end_point*skip_scale
|
||||
row_s -= end_point*skip_scale
|
||||
# 第二次过滤:消除速度为零的数据,找到速度即将大于零的上升临界点
|
||||
row_s, row_e = self.find_point(data_file, df, "lt", row_s, row_e, threshold, step, end_point, skip_scale, axis, "pre-2")
|
||||
row_e -= end_point*skip_scale
|
||||
row_s -= end_point*skip_scale
|
||||
# 第一次正式采集:消除速度大于零的数据,找到速度即将趋近于零的下降临界点
|
||||
row_s, row_e = self.find_point(data_file, df, "gt", row_s, row_e, threshold, step, end_point, skip_scale, axis, 1)
|
||||
row_end = self.get_row_number(threshold, "end", df, row_s, row_e, axis)
|
||||
row_e -= end_point*skip_scale
|
||||
row_s -= end_point*skip_scale
|
||||
# 第二次正式采集:消除速度为零的数据,找到速度即将大于零的上升临界点
|
||||
row_s, row_e = self.find_point(data_file, df, "lt", row_s, row_e, threshold, step, end_point, skip_scale, axis, 2)
|
||||
row_middle = self.get_row_number(threshold, "middle", df, row_s, row_e, axis)
|
||||
row_e -= end_point*skip_scale
|
||||
row_s -= end_point*skip_scale
|
||||
# 第三次正式采集:消除速度大于零的数据,找到速度即将趋近于零的下降临界点
|
||||
row_s, row_e = self.find_point(data_file, df, "gt", row_s, row_e, threshold, step, end_point, skip_scale, axis, 3)
|
||||
row_start = self.get_row_number(threshold, "start", df, row_s, row_e, axis)
|
||||
|
||||
self.logger("INFO", "current", f"{axis} 轴起点:{row_start}")
|
||||
self.logger("INFO", "current", f"{axis} 轴中间点:{row_middle}")
|
||||
self.logger("INFO", "current", f"{axis} 轴终点:{row_end}")
|
||||
self.logger("INFO", "current", f"{axis} 轴数据非零段点数:{row_middle-row_start+1}")
|
||||
self.logger("INFO", "current", f"{axis} 轴数据为零段点数:{row_end-row_middle+1}")
|
||||
if abs(row_end+row_start-2*row_middle) > 1000:
|
||||
self.logger("WARNING", "current", f"{axis} 轴数据占空比异常!", "purple")
|
||||
|
||||
data, first_c, second_c, third_c, fourth_c = [], clibs.c_joint_vel-1, clibs.c_servo_trq-1, clibs.c_sensor_trq-1, clibs.c_estimate_trans_trq-1
|
||||
for row in range(row_start, row_end+1):
|
||||
data.append(df_origin.iloc[row, first_c])
|
||||
data.append(df_origin.iloc[row, second_c])
|
||||
data.append(df_origin.iloc[row, third_c])
|
||||
data.append(df_origin.iloc[row, fourth_c])
|
||||
|
||||
i = 0
|
||||
for row in ws.iter_rows(min_row=2, min_col=2, max_row=150000, max_col=5):
|
||||
for cell in row:
|
||||
try:
|
||||
if i % 4 == 0:
|
||||
ws.cell((i//4)+2, 1).value = float(((i//4)+1)/1000)
|
||||
_ = f"{data[i]:.2f}"
|
||||
cell.value = float(_)
|
||||
i += 1
|
||||
except Exception:
|
||||
if i % 4 == 0:
|
||||
ws.cell((i//4)+2, 1).value = None
|
||||
cell.value = None
|
||||
i += 1
|
||||
|
||||
def p_scenario(self, wb, scenario, rrs, dur_time):
|
||||
self.logger("INFO", "current", f"本次处理的是电机电流场景数据,场景运动周期为 {dur_time}s", "blue")
|
||||
for data_file in scenario:
|
||||
cycle = 0.001
|
||||
axis = int(data_file.split("/")[-1].split("_")[0].removeprefix("j"))
|
||||
sht_name = f"J{axis}"
|
||||
ws = wb[sht_name]
|
||||
pandas.set_option("display.precision", 2)
|
||||
df_origin = pandas.read_csv(data_file, sep="\t")
|
||||
rr = rrs[axis-1]
|
||||
addition = 180 / 3.1415926 * 60 / 360 * rr
|
||||
|
||||
col_names = list(df_origin.columns)
|
||||
df = df_origin[col_names[clibs.c_joint_vel-1]].multiply(addition)
|
||||
|
||||
row_start = 3000
|
||||
row_end = row_start + int(dur_time/cycle)
|
||||
if row_end > df.index[-1]:
|
||||
self.logger("ERROR", "current-p_scenario", f"位置超限:{data_file} 共有 {df.index[-1]} 条数据,无法取到第 {row_end} 条数据,需要确认场景周期时间...", "blue", "DataOverLimit")
|
||||
|
||||
data, first_c, second_c, third_c, fourth_c = [], clibs.c_joint_vel-1, clibs.c_servo_trq-1, clibs.c_sensor_trq-1, clibs.c_estimate_trans_trq-1
|
||||
for row in range(row_start, row_end+1):
|
||||
data.append(df_origin.iloc[row, first_c])
|
||||
data.append(df_origin.iloc[row, second_c])
|
||||
data.append(df_origin.iloc[row, third_c])
|
||||
data.append(df_origin.iloc[row, fourth_c])
|
||||
|
||||
i = 0
|
||||
for row in ws.iter_rows(min_row=2, min_col=2, max_row=250000, max_col=5):
|
||||
for cell in row:
|
||||
try:
|
||||
if i % 4 == 0:
|
||||
ws.cell((i//4)+2, 1).value = float(((i//4)+1)/1000)
|
||||
_ = f"{data[i]:.2f}"
|
||||
cell.value = float(_)
|
||||
i += 1
|
||||
except Exception:
|
||||
cell.value = None
|
||||
if i % 4 == 0:
|
||||
ws.cell((i//4)+2, 1).value = None
|
||||
i += 1
|
||||
|
||||
def get_configs(self, config_file):
|
||||
try:
|
||||
if re.match("^[NXEC]B.*", config_file.split("/")[-1]):
|
||||
robot_type = "工业"
|
||||
else:
|
||||
robot_type = "协作"
|
||||
|
||||
with open(config_file, mode="r", encoding="utf-8") as f_config:
|
||||
configs = json.load(f_config)
|
||||
|
||||
version = configs["VERSION"]
|
||||
sc = [0.001, 0.001, 0.001, 0.001, 0.001, 0.001] # 采样周期,sc for sample cycle
|
||||
r_rrs = configs["TRANSMISSION"]["REDUCTION_RATIO_NUMERATOR"] # 减速比,rr for reduction ratio
|
||||
m_avs = configs["MOTION"]["JOINT_MAX_SPEED"]
|
||||
m_stall_ts = configs["MOTOR"]["STALL_TORQUE"] # 电机堵转转矩
|
||||
m_rts = configs["MOTOR"]["RATED_TORQUE"] # 电机额定转矩rt for rated torque
|
||||
m_max_ts = configs["MOTOR"]["PEAK_TORQUE"] # 电机峰值转矩
|
||||
m_r_rpms = configs["MOTOR"]["RATED_SPEED"] # 电机额定转速
|
||||
m_max_rpms = configs["MOTOR"]["MAX_SPEED"] # 电机最大转速
|
||||
r_max_sst = configs["TRANSMISSION"]["MAX_TORQUE_FOR_START_AND_STOP"] # 减速器最大启停转矩,sst for start and stop torque
|
||||
r_max_t = configs["TRANSMISSION"]["MAX_PEAK_TORQUE"] # 减速器瞬时最大转矩
|
||||
r_avg_t = configs["TRANSMISSION"]["MAX_AVERAGE_TORQUE"] # 减速器平均负载转矩允许最大值
|
||||
|
||||
self.logger("INFO", "current", f"get_configs: 机型文件版本 {config_file}_{version}")
|
||||
self.logger("INFO", "current", f"get_configs: 减速比 {r_rrs}")
|
||||
self.logger("INFO", "current", f"get_configs: 额定转矩 {m_rts}")
|
||||
self.logger("INFO", "current", f"get_configs: 最大角速度 {m_avs}")
|
||||
return sc, r_rrs, m_avs, m_stall_ts, m_rts, m_max_ts, m_r_rpms, m_max_rpms, r_max_sst, r_max_t, r_avg_t, robot_type
|
||||
except Exception as Err:
|
||||
self.logger("ERROR", "current", f"get_config: 无法打开 {config_file},或获取配置文件参数错误 {Err}", "red", "OpenFileError")
|
||||
|
||||
def processing(self):
|
||||
time_start = time.time()
|
||||
clibs.running[self.idx] = 1
|
||||
|
||||
data_files, config_file = self.initialization()
|
||||
params = self.get_configs(config_file)
|
||||
rts, rrs = params[4], params[1]
|
||||
if self.proc == "最大值":
|
||||
self.current_max(data_files, rts)
|
||||
elif self.proc == "平均值":
|
||||
self.current_avg(data_files, rts)
|
||||
elif self.proc == "周期":
|
||||
self.current_cycle(data_files, rrs, rts, params)
|
||||
|
||||
self.logger("INFO", "current-processing", "-"*60 + "<br>全部处理完毕<br>", "purple")
|
||||
time_total = time.time() - time_start
|
||||
msg = f"数据处理时间:{time_total // 3600:02.0f} h {time_total % 3600 // 60:02.0f} m {time_total % 60:02.0f} s\n"
|
||||
self.logger("INFO", "current-processing", msg)
|
213
code/analysis/iso.py
Normal file
213
code/analysis/iso.py
Normal file
@ -0,0 +1,213 @@
|
||||
import pdfplumber
|
||||
import openpyxl
|
||||
import os
|
||||
import time
|
||||
from PySide6.QtCore import Signal, QThread
|
||||
from common import clibs
|
||||
|
||||
|
||||
class IsoDataProcess(QThread):
|
||||
output = Signal(str, str)
|
||||
|
||||
def __init__(self, dir_path, /):
|
||||
super().__init__()
|
||||
self.dir_path = dir_path
|
||||
self.idx = 2
|
||||
|
||||
def logger(self, level, module, content, color="black", error="", flag="both"):
|
||||
clibs.logger(level, module, content, color, flag, signal=self.output)
|
||||
if level.upper() == "ERROR":
|
||||
raise Exception(f"{error} | {content}")
|
||||
|
||||
def p_iso(self, file, p_files, ws, tmpfile):
|
||||
p_files.append(file)
|
||||
|
||||
pdf = pdfplumber.open(file)
|
||||
with open(tmpfile, mode="w", encoding="utf-8") as fb:
|
||||
for page in pdf.pages:
|
||||
fb.write(page.extract_text())
|
||||
with open(tmpfile, mode="r", encoding="utf-8") as fb:
|
||||
lines = fb.readlines()
|
||||
lines = [line for line in lines if not line.startswith("Page ")]
|
||||
for line in lines:
|
||||
if line.strip() == "Pose Accuracy and Repeatability":
|
||||
index = lines.index(line)
|
||||
ws.cell(row=3, column=7).value = float(lines[index+4].split()[1])
|
||||
ws.cell(row=4, column=7).value = float(lines[index+5].split()[1])
|
||||
ws.cell(row=5, column=7).value = float(lines[index+6].split()[1])
|
||||
ws.cell(row=6, column=7).value = float(lines[index+7].split()[1])
|
||||
ws.cell(row=7, column=7).value = float(lines[index+8].split()[1])
|
||||
|
||||
ws.cell(row=8, column=7).value = float(lines[index+4].split()[2])
|
||||
ws.cell(row=9, column=7).value = float(lines[index+5].split()[2])
|
||||
ws.cell(row=10, column=7).value = float(lines[index+6].split()[2])
|
||||
ws.cell(row=11, column=7).value = float(lines[index+7].split()[2])
|
||||
ws.cell(row=12, column=7).value = float(lines[index+8].split()[2])
|
||||
elif line.strip() == "Pose Accuracy Variation":
|
||||
index = lines.index(line)
|
||||
ws.cell(row=13, column=7).value = float(lines[index+4].split()[1])
|
||||
ws.cell(row=14, column=7).value = float(lines[index+5].split()[1])
|
||||
ws.cell(row=15, column=7).value = float(lines[index+6].split()[1])
|
||||
elif line.strip() == "Distance Accuracy":
|
||||
index = lines.index(line)
|
||||
ws.cell(row=16, column=7).value = float(lines[index + 4].split()[1])
|
||||
ws.cell(row=17, column=7).value = float(lines[index + 4].split()[2])
|
||||
elif line.strip() == "Stabilisation Time and Overshoot":
|
||||
index = lines.index(line)
|
||||
ws.cell(row=18, column=7).value = float(lines[index + 7].split()[3])
|
||||
ws.cell(row=19, column=7).value = float(lines[index + 7].split()[2])
|
||||
elif line.strip() == "Velocity Accuracy and Repeatability":
|
||||
index = lines.index(line)
|
||||
ws.cell(row=20, column=7).value = float(lines[index + 4].split()[1])
|
||||
ws.cell(row=21, column=7).value = float(lines[index + 4].split()[2])
|
||||
ws.cell(row=22, column=7).value = float(lines[index + 4].split()[3])
|
||||
elif line.strip()[:31] == "Path Accuracy and Repeatability":
|
||||
index = lines.index(line)
|
||||
ws.cell(row=29, column=7).value = float(lines[index + 4].split()[1])
|
||||
ws.cell(row=30, column=7).value = float(lines[index + 4].split()[2])
|
||||
elif line.strip() == "Corner Overshoot and Roundoff":
|
||||
index = lines.index(line)
|
||||
ws.cell(row=35, column=7).value = float(lines[index + 4].split()[1])
|
||||
ws.cell(row=36, column=7).value = float(lines[index + 4].split()[2])
|
||||
elif line.strip() == "Robot Weaving":
|
||||
index = lines.index(line)
|
||||
ws.cell(row=41, column=7).value = float(lines[index + 4].split()[2])
|
||||
ws.cell(row=42, column=7).value = float(lines[index + 4].split()[3])
|
||||
ws.cell(row=43, column=7).value = float(lines[index + 4].split()[4])
|
||||
else:
|
||||
pass
|
||||
pdf.close()
|
||||
|
||||
def p_iso_100(self, file, p_files, ws, tmpfile):
|
||||
p_files.append(file)
|
||||
|
||||
pdf = pdfplumber.open(file)
|
||||
with open(tmpfile, mode="w", encoding="utf-8") as fb:
|
||||
for page in pdf.pages:
|
||||
fb.write(page.extract_text())
|
||||
with open(tmpfile, mode="r", encoding="utf-8") as fb:
|
||||
lines = fb.readlines()
|
||||
lines = [line for line in lines if not line.startswith("Page ")]
|
||||
for line in lines:
|
||||
if line.strip() == "Velocity Accuracy and Repeatability":
|
||||
index = lines.index(line)
|
||||
ws.cell(row=26, column=7).value = float(lines[index + 4].split()[1])
|
||||
ws.cell(row=27, column=7).value = float(lines[index + 4].split()[2])
|
||||
ws.cell(row=28, column=7).value = float(lines[index + 4].split()[3])
|
||||
elif line.strip()[:31] == "Path Accuracy and Repeatability":
|
||||
index = lines.index(line)
|
||||
ws.cell(row=33, column=7).value = float(lines[index + 4].split()[1])
|
||||
ws.cell(row=34, column=7).value = float(lines[index + 4].split()[2])
|
||||
elif line.strip() == "Corner Overshoot and Roundoff":
|
||||
index = lines.index(line)
|
||||
ws.cell(row=39, column=7).value = float(lines[index + 4].split()[1])
|
||||
ws.cell(row=40, column=7).value = float(lines[index + 4].split()[2])
|
||||
elif line.strip() == "Robot Weaving":
|
||||
index = lines.index(line)
|
||||
ws.cell(row=47, column=7).value = float(lines[index + 4].split()[2])
|
||||
ws.cell(row=48, column=7).value = float(lines[index + 4].split()[3])
|
||||
ws.cell(row=49, column=7).value = float(lines[index + 4].split()[4])
|
||||
else:
|
||||
pass
|
||||
pdf.close()
|
||||
|
||||
def p_iso_1000(self, file, p_files, ws, tmpfile):
|
||||
p_files.append(file)
|
||||
|
||||
pdf = pdfplumber.open(file)
|
||||
with open(tmpfile, mode="w", encoding="utf-8") as fb:
|
||||
for page in pdf.pages:
|
||||
fb.write(page.extract_text())
|
||||
with open(tmpfile, mode="r", encoding="utf-8") as fb:
|
||||
lines = fb.readlines()
|
||||
lines = [line for line in lines if not line.startswith("Page ")]
|
||||
for line in lines:
|
||||
if line.strip() == "Velocity Accuracy and Repeatability":
|
||||
index = lines.index(line)
|
||||
ws.cell(row=23, column=7).value = float(lines[index + 4].split()[1])
|
||||
ws.cell(row=24, column=7).value = float(lines[index + 4].split()[2])
|
||||
ws.cell(row=25, column=7).value = float(lines[index + 4].split()[3])
|
||||
elif line.strip()[:31] == "Path Accuracy and Repeatability":
|
||||
index = lines.index(line)
|
||||
ws.cell(row=31, column=7).value = float(lines[index + 4].split()[1])
|
||||
ws.cell(row=32, column=7).value = float(lines[index + 4].split()[2])
|
||||
elif line.strip() == "Corner Overshoot and Roundoff":
|
||||
index = lines.index(line)
|
||||
ws.cell(row=37, column=7).value = float(lines[index + 4].split()[1])
|
||||
ws.cell(row=38, column=7).value = float(lines[index + 4].split()[2])
|
||||
elif line.strip() == "Robot Weaving":
|
||||
index = lines.index(line)
|
||||
ws.cell(row=44, column=7).value = float(lines[index + 4].split()[2])
|
||||
ws.cell(row=45, column=7).value = float(lines[index + 4].split()[3])
|
||||
ws.cell(row=46, column=7).value = float(lines[index + 4].split()[4])
|
||||
else:
|
||||
pass
|
||||
pdf.close()
|
||||
|
||||
def initialization(self):
|
||||
dirs, files = clibs.traversal_files(self.dir_path, self.output)
|
||||
if len(dirs) != 0:
|
||||
self.logger("ERROR", "iso", f"init: 工作目录下不可以有文件夹!", "red", "InitFileError")
|
||||
|
||||
for file in files:
|
||||
file = file.lower()
|
||||
if file.endswith("iso-results.xlsx"):
|
||||
pass
|
||||
elif file.endswith("iso-v1000.pdf"):
|
||||
pass
|
||||
elif file.endswith("iso-v100.pdf"):
|
||||
pass
|
||||
elif file.endswith("iso.pdf"):
|
||||
pass
|
||||
else:
|
||||
self.logger("ERROR", "iso", f"init: 工作目录下只允许有如下四个文件,不区分大小写,pdf文件最少有一个!<br>1. iso-results.xlsx<br>2. ISO.pdf<br>3. ISO-V100.pdf<br>4. ISO-V1000.pdf", "red", "InitFileError")
|
||||
|
||||
return files
|
||||
|
||||
def processing(self):
|
||||
time_start = time.time()
|
||||
clibs.running[self.idx] = 1
|
||||
|
||||
files = self.initialization()
|
||||
filename = f"{self.dir_path}/iso-results.xlsx"
|
||||
tmpfile = f"{self.dir_path}/data.txt"
|
||||
wb, ws = None, None
|
||||
try:
|
||||
wb = openpyxl.load_workbook(filename)
|
||||
ws = wb.active
|
||||
for i in range(3, 50):
|
||||
ws.cell(row=i, column=7).value = None
|
||||
except Exception as Err:
|
||||
self.logger("ERROR", "iso", f"main: 无法打开文件 {filename}<br>{Err}", "red", "FileOpenError")
|
||||
|
||||
p_files = []
|
||||
for file in files:
|
||||
if file.split("/")[-1].lower() == "iso.pdf":
|
||||
self.logger("INFO", "iso", f"正在处理{file}......")
|
||||
self.p_iso(file, p_files, ws, tmpfile)
|
||||
self.logger("INFO", "iso", f"文件{file}已处理完毕。")
|
||||
|
||||
elif file.split("/")[-1].lower() == "iso-v100.pdf":
|
||||
self.logger("INFO", "iso", f"正在处理{file}......")
|
||||
self.p_iso_100(file, p_files, ws, tmpfile)
|
||||
self.logger("INFO", "iso", f"文件{file}已处理完毕。")
|
||||
|
||||
elif file.split("/")[-1].lower() == "iso-v1000.pdf":
|
||||
self.logger("INFO", "iso", f"正在处理{file}......")
|
||||
self.p_iso_1000(file, p_files, ws, tmpfile)
|
||||
self.logger("INFO", "iso", f"文件{file}已处理完毕。")
|
||||
|
||||
else:
|
||||
pass
|
||||
wb.save(filename)
|
||||
wb.close()
|
||||
|
||||
if len(p_files) == 0:
|
||||
self.logger("ERROR", "iso", f"目录 {self.dir_path} 下没有需要处理的文件,需要确认......", "red", "FileNotFound")
|
||||
else:
|
||||
os.remove(tmpfile)
|
||||
|
||||
self.logger("INFO", "current-processing", "-" * 60 + "<br>全部处理完毕<br>", "purple")
|
||||
time_total = time.time() - time_start
|
||||
msg = f"数据处理时间:{time_total // 3600:02.0f} h {time_total % 3600 // 60:02.0f} m {time_total % 60:02.0f} s\n"
|
||||
self.logger("INFO", "current-processing", msg)
|
160
code/analysis/wavelogger.py
Normal file
160
code/analysis/wavelogger.py
Normal file
@ -0,0 +1,160 @@
|
||||
import pandas
|
||||
import csv
|
||||
import openpyxl
|
||||
import chardet
|
||||
import time
|
||||
from PySide6.QtCore import Signal, QThread
|
||||
from common import clibs
|
||||
|
||||
|
||||
class WaveloggerDataProcess(QThread):
|
||||
output = Signal(str, str)
|
||||
|
||||
def __init__(self, dir_path, /):
|
||||
super().__init__()
|
||||
self.dir_path = dir_path
|
||||
self.idx = 3
|
||||
|
||||
def logger(self, level, module, content, color="black", error="", flag="both"):
|
||||
clibs.logger(level, module, content, color, flag, signal=self.output)
|
||||
if level.upper() == "ERROR":
|
||||
raise Exception(f"{error} | {content}")
|
||||
|
||||
def find_point(self, bof, step, margin, threshold, pos, data_file, flag, df, row):
|
||||
# bof: backward or forward
|
||||
# pos: used for debug
|
||||
# flag: greater than or lower than
|
||||
row_target = None
|
||||
row_origin = len(df) - margin + 1
|
||||
if flag == "gt":
|
||||
while 0 < row < row_origin:
|
||||
value = float(df.iloc[row, 2])
|
||||
if value > threshold:
|
||||
row = row - step if bof == "backward" else row + step
|
||||
continue
|
||||
else:
|
||||
row_target = row - step if bof == "backward" else row + step
|
||||
break
|
||||
else:
|
||||
if bof == "backward":
|
||||
self.logger("ERROR", "wavelogger-find_point", f"find_point-gt: [{pos}] 在 {data_file} 中,无法正确识别数据,需要确认...", "red", "DataError")
|
||||
elif bof == "forward":
|
||||
row_target = row + margin # to end while loop in function `single_file_proc`
|
||||
elif flag == "lt":
|
||||
while 0 < row < row_origin:
|
||||
value = float(df.iloc[row, 2])
|
||||
if value < threshold:
|
||||
row = row - step if bof == "backward" else row + step
|
||||
continue
|
||||
else:
|
||||
row_target = row - step if bof == "backward" else row + step
|
||||
break
|
||||
else:
|
||||
if bof == "backward":
|
||||
self.logger("ERROR", "wavelogger-find_point", f"find_point-lt: [{pos}] 在 {data_file} 中,无法正确识别数据,需要确认...", "red", "DataError")
|
||||
elif bof == "forward":
|
||||
row_target = row + margin # to end while loop in function `single_file_proc`
|
||||
return row_target
|
||||
|
||||
def get_cycle_info(self, data_file, step, margin, threshold):
|
||||
# end -> middle: low
|
||||
# middle -> start: high
|
||||
# 1. 从最后读取数据,无论是大于1还是小于1,都舍弃,找到相反的值的起始点
|
||||
# 2. 从起始点,继续往前寻找,找到与之数值相反的中间点
|
||||
# 3. 从中间点,继续往前寻找,找到与之数值相反的结束点,至此,得到了高低数值的时间区间以及一轮的周期时间
|
||||
with open(data_file, "rb") as f:
|
||||
raw_data = f.read(1000)
|
||||
result = chardet.detect(raw_data)
|
||||
encoding = result['encoding']
|
||||
csv_reader = csv.reader(open(data_file, encoding=encoding))
|
||||
begin = int(next(csv_reader)[1])
|
||||
df = pandas.read_csv(data_file, sep=",", encoding=encoding, skip_blank_lines=False, header=begin - 1, on_bad_lines="skip")
|
||||
row = len(df) - margin
|
||||
if float(df.iloc[row, 2]) < threshold:
|
||||
row = self.find_point("backward", step, margin, threshold, "a1", data_file, "lt", df, row)
|
||||
|
||||
_row = self.find_point("backward", step, margin, threshold, "a2", data_file, "gt", df, row)
|
||||
_row = self.find_point("backward", step, margin, threshold, "a3", data_file, "lt", df, _row)
|
||||
row_end = self.find_point("backward", step, margin, threshold, "a4", data_file, "gt", df, _row)
|
||||
row_middle = self.find_point("backward", step, margin, threshold, "a5", data_file, "lt", df, row_end)
|
||||
row_start = self.find_point("backward", step, margin, threshold, "a6", data_file, "gt", df, row_middle)
|
||||
# print(f"row_end = {row_end}")
|
||||
# print(f"row_middle = {row_middle}")
|
||||
# print(f"row_start = {row_start}")
|
||||
return row_end-row_middle, row_middle-row_start, row_end-row_start, df
|
||||
|
||||
def initialization(self):
|
||||
_, data_files = clibs.traversal_files(self.dir_path, self.output)
|
||||
|
||||
for data_file in data_files:
|
||||
if not data_file.lower().endswith(".csv"):
|
||||
self.logger("ERROR", "wavelogger-initialization", f"init: {data_file} 文件后缀错误,只允许 .csv 文件,需要确认!", "red", "FileTypeError")
|
||||
|
||||
return data_files
|
||||
|
||||
def preparation(self, data_file, step, margin, threshold, wb):
|
||||
shtname = data_file.split("/")[-1].split(".")[0]
|
||||
ws = wb.create_sheet(shtname)
|
||||
low, high, cycle, df = self.get_cycle_info(data_file, step, margin, threshold)
|
||||
|
||||
return ws, df, low, high, cycle
|
||||
|
||||
def single_file_proc(self, ws, data_file, step, threshold, margin, data_length, df, cycle):
|
||||
row, row_lt, row_gt, count, count_i, data = 1, 1, 1, 1, 1, {}
|
||||
row_max = len(df) - margin
|
||||
while row < row_max:
|
||||
if count not in data.keys():
|
||||
data[count] = []
|
||||
|
||||
value = float(df.iloc[row, 2])
|
||||
if value < threshold:
|
||||
row_lt = self.find_point("forward", step, margin, threshold, "c"+str(row), data_file, "lt", df, row)
|
||||
start = int(row_gt + (row_lt - row_gt - data_length) / 2)
|
||||
end = start + data_length
|
||||
value = df.iloc[start:end, 2].astype(float).mean() + 3 * df.iloc[start:end, 2].astype(float).std()
|
||||
if value > 1:
|
||||
msg = f"\n"
|
||||
self.logger("WARNING", "wavelogger-single_file_proc", f"{data_file} 文件第 {count} 轮 第 {count_i} 个数据可能有问题,需人工手动确认,确认有问题可删除,无问题则保留", "purple")
|
||||
|
||||
data[count].append(value)
|
||||
count_i += 1
|
||||
else:
|
||||
row_gt = self.find_point("forward", step, margin, threshold, "c"+str(row), data_file, "gt", df, row)
|
||||
if row_gt - row_lt > cycle * 2:
|
||||
count += 1
|
||||
count_i = 1
|
||||
row = max(row_gt, row_lt)
|
||||
for i in range(2, 10):
|
||||
ws.cell(row=1, column=i).value = f"第{i-1}次测试"
|
||||
ws.cell(row=i, column=1).value = f"第{i-1}次精度变化"
|
||||
|
||||
for i in sorted(data.keys()):
|
||||
row, column = 2, i + 1
|
||||
for value in data[i]:
|
||||
ws.cell(row=row, column=column).value = float(value)
|
||||
row += 1
|
||||
|
||||
def execution(self, data_files):
|
||||
self.logger("INFO", "wavelogger-execution", "正在处理中......", "blue")
|
||||
wb = openpyxl.Workbook()
|
||||
step, margin, data_length, threshold = 5, 50, 50, 5
|
||||
for data_file in data_files:
|
||||
ws, df, low, high, cycle = self.preparation(data_file, step, margin, threshold, wb)
|
||||
self.single_file_proc(ws, data_file, step, threshold, margin, data_length, df, cycle)
|
||||
|
||||
wd = "/".join(data_files[0].split("/")[:-1])
|
||||
filename = wd + "/result.xlsx"
|
||||
wb.save(filename)
|
||||
wb.close()
|
||||
|
||||
def processing(self):
|
||||
time_start = time.time()
|
||||
clibs.running[self.idx] = 1
|
||||
|
||||
data_files = self.initialization()
|
||||
self.execution(data_files)
|
||||
|
||||
self.logger("INFO", "wavelogger-processing", "-" * 60 + "<br>全部处理完毕<br>", "purple")
|
||||
time_total = time.time() - time_start
|
||||
msg = f"数据处理时间:{time_total // 3600:02.0f} h {time_total % 3600 // 60:02.0f} m {time_total % 60:02.0f} s\n"
|
||||
self.logger("INFO", "wavelogger-processing", msg)
|
374
code/autotest/do_brake.py
Normal file
374
code/autotest/do_brake.py
Normal file
@ -0,0 +1,374 @@
|
||||
import time
|
||||
import os
|
||||
import paramiko
|
||||
import openpyxl
|
||||
import pandas
|
||||
import json
|
||||
from PySide6.QtCore import Signal, QThread
|
||||
from common import clibs
|
||||
|
||||
|
||||
class DoBrakeTest(QThread):
|
||||
output = Signal(str, str)
|
||||
|
||||
def __init__(self, dir_path, tool, /):
|
||||
super().__init__()
|
||||
self.dir_path = dir_path
|
||||
self.tool = tool
|
||||
self.idx = 4
|
||||
|
||||
def logger(self, level, module, content, color="black", error="", flag="both"):
|
||||
clibs.logger(level, module, content, color, flag, signal=self.output)
|
||||
if level.upper() == "ERROR":
|
||||
raise Exception(f"{error} | {content}")
|
||||
|
||||
def initialization(self, data_dirs, data_files):
|
||||
def check_files():
|
||||
msg = "初始路径下不允许有文件夹,初始路径下只能存在如下五个文件,且文件为关闭状态,确认后重新运行!<br>"
|
||||
msg += "1. configs.xlsx<br>2. reach33/reach66/reach100_xxxx.xlsx<br>3. xxxx.zip"
|
||||
if len(data_dirs) != 0 or len(data_files) != 5:
|
||||
self.logger("ERROR", "do_brake-check_files", msg, "red", "InitFileError")
|
||||
|
||||
config_file, reach33_file, reach66_file, reach100_file, prj_file, result_dirs = None, None, None, None, None, []
|
||||
for data_file in data_files:
|
||||
filename = data_file.split("/")[-1]
|
||||
if filename == "configs.xlsx":
|
||||
config_file = data_file
|
||||
elif filename.startswith("reach33_") and filename.endswith(".xlsx"):
|
||||
reach33_file = data_file
|
||||
elif filename.startswith("reach66_") and filename.endswith(".xlsx"):
|
||||
reach66_file = data_file
|
||||
elif filename.startswith("reach100_") and filename.endswith(".xlsx"):
|
||||
reach100_file = data_file
|
||||
elif filename.endswith(".zip"):
|
||||
prj_file = data_file
|
||||
else:
|
||||
self.logger("ERROR", "do_brake-check_files", msg, "red", "InitFileError")
|
||||
|
||||
if config_file and reach33_file and reach66_file and reach100_file and prj_file:
|
||||
os.mkdir(f"{self.dir_path}/j1")
|
||||
os.mkdir(f"{self.dir_path}/j2")
|
||||
os.mkdir(f"{self.dir_path}/j3")
|
||||
|
||||
load = f"load{self.tool.removeprefix('tool')}"
|
||||
for reach in ["reach33", "reach66", "reach100"]:
|
||||
for speed in ["speed33", "speed66", "speed100"]:
|
||||
dir_name = "_".join([reach, load, speed])
|
||||
result_dirs.append(dir_name)
|
||||
os.mkdir(f"{self.dir_path}/j1/{dir_name}")
|
||||
os.mkdir(f"{self.dir_path}/j2/{dir_name}")
|
||||
if reach == "reach100":
|
||||
os.mkdir(f"{self.dir_path}/j3/{dir_name}")
|
||||
|
||||
self.logger("INFO", "do_brake-check_files", "数据目录合规性检查结束,未发现问题......", "green")
|
||||
return config_file, prj_file, result_dirs
|
||||
else:
|
||||
self.logger("ERROR", "do_brake-check_files", msg, "red", "InitFileError")
|
||||
|
||||
def get_configs():
|
||||
robot_type = None
|
||||
msg_id, state = clibs.c_hr.execution("controller.get_params")
|
||||
records = clibs.c_hr.get_from_id(msg_id, state)
|
||||
for record in records:
|
||||
if "请求发送成功" not in record[0]:
|
||||
robot_type = eval(record[0])["data"]["robot_type"]
|
||||
server_file = f"/home/luoshi/bin/controller/robot_cfg/{robot_type}/{robot_type}.cfg"
|
||||
local_file = self.dir_path + f"/{robot_type}.cfg"
|
||||
clibs.c_pd.pull_file_from_server(server_file, local_file)
|
||||
|
||||
try:
|
||||
with open(local_file, mode="r", encoding="utf-8") as f_config:
|
||||
configs = json.load(f_config)
|
||||
except Exception as Err:
|
||||
self.logger("ERROR", "do_brake-get_configs", f"无法打开 {local_file}<br>{Err}", "red", "OpenFileError")
|
||||
|
||||
# 最大角速度,额定电流,减速比,额定转速
|
||||
version = configs["VERSION"]
|
||||
avs = configs["MOTION"]["JOINT_MAX_SPEED"]
|
||||
clibs.insert_logdb("INFO", "do_brake", f"get_configs: 机型文件版本 {robot_type}_{version}")
|
||||
clibs.insert_logdb("INFO", "do_brake", f"get_configs: 各关节角速度 {avs}")
|
||||
return avs
|
||||
|
||||
_config_file, _prj_file, _result_dirs = check_files()
|
||||
_avs = get_configs()
|
||||
|
||||
return _config_file, _prj_file, _result_dirs, _avs
|
||||
|
||||
def gen_result_file(self, axis, t_end, reach, load, speed, speed_max, rounds):
|
||||
d_vel, d_trq, d_stop, threshold = [], [], [], 0.95
|
||||
|
||||
start_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(t_end-12))
|
||||
end_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(t_end))
|
||||
try:
|
||||
clibs.lock.acquire(True)
|
||||
clibs.cursor.execute(f"select content from logs where time between '{start_time}' and '{end_time}' and content like '%diagnosis.result%' order by id asc")
|
||||
records = clibs.cursor.fetchall()
|
||||
finally:
|
||||
clibs.lock.release()
|
||||
|
||||
for record in records: # 保留最后12s的数据
|
||||
data = eval(record[0])["data"]
|
||||
for item in data:
|
||||
d_item = reversed(item["value"])
|
||||
if item.get("channel", None) == axis-1 and item.get("name", None) == "hw_joint_vel_feedback":
|
||||
d_vel.extend(d_item)
|
||||
elif item.get("channel", None) == axis-1 and item.get("name", None) == "device_servo_trq_feedback":
|
||||
d_trq.extend(d_item)
|
||||
elif item.get("channel", None) == 0 and item.get("name", None) == "device_safety_estop":
|
||||
d_stop.extend(d_item)
|
||||
|
||||
idx = 0
|
||||
for idx in range(len(d_stop)-10, 0, -1):
|
||||
if d_stop[idx] == 1:
|
||||
break
|
||||
|
||||
av_estop = abs(sum(d_vel[idx - 20:idx])/20 * clibs.RADIAN)
|
||||
if av_estop / speed_max < threshold:
|
||||
self.logger("WARNING", "do_brake-gen_result_file", f"[av_estop: {av_estop:.2f} | shouldbe: {speed_max:.2f}] 处理数据时,本次触发 ESTOP 时未采集到指定百分比的最大速度,即将重试!", "#8A2BE2")
|
||||
clibs.count += 1
|
||||
if clibs.count < 3:
|
||||
return "retry"
|
||||
else:
|
||||
clibs.count = 0
|
||||
self.logger("WARNING", "do_brake-gen_result_file",f"尝试三次后仍无法获取正确数据,本次数据无效,继续执行...", "red")
|
||||
|
||||
df1 = pandas.DataFrame.from_dict({"hw_joint_vel_feedback": d_vel})
|
||||
df2 = pandas.DataFrame.from_dict({"device_servo_trq_feedback": d_trq})
|
||||
df3 = pandas.DataFrame.from_dict({"device_safety_estop": d_stop})
|
||||
df = pandas.concat([df1, df2, df3], axis=1)
|
||||
filename = f"{self.dir_path}/j{axis}/reach{reach}_load{load}_speed{speed}/reach{reach}_load{load}_speed{speed}_{rounds}.data"
|
||||
df.to_csv(filename, sep="\t", index=False)
|
||||
|
||||
@staticmethod
|
||||
def change_curve_state(stat):
|
||||
if not stat:
|
||||
display_pdo_params = []
|
||||
else:
|
||||
display_pdo_params = [{"name": name, "channel": chl} for name in ["hw_joint_vel_feedback", "device_servo_trq_feedback"] for chl in range(6)]
|
||||
display_pdo_params.append({"name": "device_safety_estop", "channel": 0})
|
||||
clibs.c_hr.execution("diagnosis.open", open=stat, display_open=stat, overrun=True, turn_area=True, delay_motion=False)
|
||||
clibs.c_hr.execution("diagnosis.set_params", display_pdo_params=display_pdo_params, frequency=50, version="1.4.1")
|
||||
|
||||
def run_rl(self, config_file, prj_file, result_dirs, avs):
|
||||
count, total, speed_target = 0, 63, 0
|
||||
prj_name = ".".join(prj_file.split("/")[-1].split(".")[:-1])
|
||||
wb = openpyxl.load_workbook(config_file, read_only=True)
|
||||
ws = wb["Target"]
|
||||
write_diagnosis = float(ws.cell(row=2, column=2).value)
|
||||
get_init_speed = float(ws.cell(row=3, column=2).value)
|
||||
single_brake = str(ws.cell(row=4, column=2).value)
|
||||
pon = ws.cell(row=5, column=2).value
|
||||
io_name = ws.cell(row=6, column=2).value.upper().strip()
|
||||
wb.close()
|
||||
msg = f"基本参数配置:write_diagnosis(废弃) = {write_diagnosis}, get_init_speed = {get_init_speed}, single_brake = {single_brake}, pon = {pon}"
|
||||
self.logger("INFO", "do_brake-run_rl", msg)
|
||||
|
||||
if pon == "positive":
|
||||
clibs.c_md.write_pon(1)
|
||||
elif pon == "negative":
|
||||
clibs.c_md.write_pon(0)
|
||||
else:
|
||||
self.logger("ERROR", "do_brake-run_rl", "configs.xlsx 中 Target 页面 B5 单元格填写不正确,检查后重新运行...", "red", "DirectionError")
|
||||
|
||||
self.change_curve_state(True)
|
||||
for condition in result_dirs:
|
||||
reach = condition.split("_")[0].removeprefix("reach")
|
||||
load = condition.split("_")[1].removeprefix("load")
|
||||
speed = condition.split("_")[2].removeprefix("speed")
|
||||
|
||||
# for single condition test
|
||||
single_axis = -1
|
||||
if single_brake != "0":
|
||||
total = 3
|
||||
single_axis = int(single_brake.split("-")[0])
|
||||
if reach != single_brake.split("-")[1] or load != single_brake.split("-")[2] or speed != single_brake.split("-")[3]:
|
||||
continue
|
||||
|
||||
for axis in range(1, 4):
|
||||
# for single condition test
|
||||
if (single_axis != -1 and single_axis != axis) or (axis == 3 and reach != "100"):
|
||||
continue
|
||||
|
||||
clibs.c_md.write_axis(axis)
|
||||
self.logger("INFO", "brake-processing", "-" * 90, "purple", flag="signal")
|
||||
speed_max = 0
|
||||
for rounds in range(1, 4):
|
||||
count += 1
|
||||
_ = 3 if count % 3 == 0 else count % 3
|
||||
this_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
|
||||
prj_path = f"{prj_name}/_build/{prj_name}.prj"
|
||||
msg = f"[{this_time} | {count}/{total}] 正在执行 {axis} 轴 {condition} 的第 {_} 次制动测试..."
|
||||
self.logger("INFO", "do_brake-run_rl", msg)
|
||||
|
||||
# 1. 触发软急停,并解除,目的是让可能正在运行着的机器停下来,切手动模式并下电
|
||||
clibs.c_md.r_soft_estop(0)
|
||||
clibs.c_md.r_soft_estop(1)
|
||||
clibs.c_ec.setdo_value(io_name, "true")
|
||||
clibs.c_md.r_reset_estop()
|
||||
clibs.c_md.r_clear_alarm()
|
||||
clibs.c_md.write_act(0)
|
||||
|
||||
while count % 3 == 1:
|
||||
# 2. 修改要执行的场景
|
||||
rl_cmd = ""
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect(hostname=clibs.ip_addr, port=clibs.ssh_port, username=clibs.username, password=clibs.password)
|
||||
if pon == "positive":
|
||||
rl_cmd = f"brake_E(j{axis}_{reach}_p, j{axis}_{reach}_n, p_speed, p_tool)"
|
||||
elif pon == "negative":
|
||||
rl_cmd = f"brake_E(j{axis}_{reach}_n, j{axis}_{reach}_p, p_speed, p_tool)"
|
||||
rl_speed = f"VelSet {speed}"
|
||||
rl_tool = f"tool p_tool = {self.tool}"
|
||||
cmd = "cd /home/luoshi/bin/controller/; "
|
||||
cmd += f'sudo sed -i "/brake_E/d" projects/{prj_name}/_build/brake/main.mod; '
|
||||
cmd += f'sudo sed -i "/DONOTDELETE/i {rl_cmd}" projects/{prj_name}/_build/brake/main.mod; '
|
||||
cmd += f'sudo sed -i "/VelSet/d" projects/{prj_name}/_build/brake/main.mod; '
|
||||
cmd += f'sudo sed -i "/MoveAbsJ/i {rl_speed}" projects/{prj_name}/_build/brake/main.mod; '
|
||||
cmd += f'sudo sed -i "/tool p_tool/d" projects/{prj_name}/_build/brake/main.mod; '
|
||||
cmd += f'sudo sed -i "/VelSet/i {rl_tool}" projects/{prj_name}/_build/brake/main.mod; '
|
||||
stdin, stdout, stderr = ssh.exec_command(cmd, get_pty=True)
|
||||
stdin.write(clibs.password + "\n")
|
||||
stdout.read().decode() # 需要read一下才能正常执行
|
||||
stderr.read().decode()
|
||||
|
||||
# 3. reload工程后,pp2main,并且自动模式和上电,最后运行程序
|
||||
clibs.c_hr.execution("overview.reload", prj_path=prj_path, tasks=["brake"])
|
||||
clibs.c_hr.execution("rl_task.pp_to_main", tasks=["brake"])
|
||||
clibs.c_hr.execution("state.switch_auto")
|
||||
clibs.c_hr.execution("state.switch_motor_on")
|
||||
clibs.c_hr.execution("rl_task.set_run_params", loop_mode=True, override=1.0)
|
||||
clibs.c_hr.execution("rl_task.run", tasks=["brake"])
|
||||
t_start = time.time()
|
||||
while True:
|
||||
if clibs.c_md.read_ready_to_go() == 1:
|
||||
clibs.c_md.write_act(True)
|
||||
break
|
||||
else:
|
||||
time.sleep(1)
|
||||
if (time.time() - t_start) > 15:
|
||||
self.logger("ERROR", "do_brake-run_rl", "15s 内未收到机器人的运行信号,需要确认 RL 程序编写正确并正常执行...", "red", "ReadySignalTimeoutError")
|
||||
# 4. 找出最大速度,传递给RL程序,最后清除相关记录
|
||||
time.sleep(5) # 消除前 5s 的不稳定数据
|
||||
start_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
|
||||
time.sleep(get_init_speed) # 指定时间后获取实际【正|负】方向的最大速度,可通过configs.xlsx配置
|
||||
end_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
|
||||
clibs.c_hr.execution("rl_task.stop", tasks=["brake"])
|
||||
|
||||
# 找出最大速度
|
||||
@clibs.db_lock
|
||||
def get_speed_max():
|
||||
_speed_max = 0
|
||||
clibs.cursor.execute(f"select content from logs where time between '{start_time}' and '{end_time}' and content like '%diagnosis.result%' order by id asc")
|
||||
records = clibs.cursor.fetchall()
|
||||
for record in records:
|
||||
data = eval(record[0])["data"]
|
||||
for item in data:
|
||||
if item.get("channel", None) == axis-1 and item.get("name", None) == "hw_joint_vel_feedback":
|
||||
_ = clibs.RADIAN * sum(item["value"]) / len(item["value"])
|
||||
if pon == "positive":
|
||||
_speed_max = max(_, _speed_max)
|
||||
elif pon == "negative":
|
||||
_speed_max = min(_, _speed_max)
|
||||
return _speed_max
|
||||
|
||||
speed_max = abs(get_speed_max())
|
||||
speed_target = avs[axis-1] * float(speed) / 100
|
||||
clibs.insert_logdb("INFO", "do_brake", f"axis = {axis}, direction = {pon}, max speed = {speed_max}")
|
||||
if speed_max < speed_target*0.95 or speed_max > speed_target*1.05:
|
||||
self.logger("WARNING", "do_brake-run_rl", f"Axis: {axis}-{count} | 采集获取最大 Speed: {speed_max} | Shouldbe: {speed_target}", "indigo")
|
||||
clibs.insert_logdb("WARNING", "do_brake", f"Axis: {axis}-{count} | 采集获取最大 Speed: {speed_max} | Shouldbe: {speed_target}")
|
||||
clibs.c_md.write_speed_max(speed_max)
|
||||
|
||||
if speed_max < 10:
|
||||
clibs.c_md.r_clear_alarm()
|
||||
self.logger("WARNING", "do_brake-run_rl", f"未获取到正确的速度,即将重新获取...", "red")
|
||||
continue
|
||||
else:
|
||||
break
|
||||
|
||||
while 1:
|
||||
clibs.c_ec.setdo_value(io_name, "true")
|
||||
clibs.c_md.r_reset_estop()
|
||||
clibs.c_md.r_clear_alarm()
|
||||
clibs.c_md.write_act(0)
|
||||
# 5. 重新运行程序,发送继续运动信号,当速度达到最大值时,通过DO触发急停
|
||||
clibs.c_hr.execution("rl_task.pp_to_main", tasks=["brake"])
|
||||
clibs.c_hr.execution("state.switch_auto")
|
||||
clibs.c_hr.execution("state.switch_motor_on")
|
||||
t_start = time.time()
|
||||
while 1:
|
||||
clibs.c_md.r_clear_alarm()
|
||||
clibs.c_hr.execution("rl_task.run", tasks=["brake"])
|
||||
time.sleep(1)
|
||||
if clibs.c_md.w_program_state == 1:
|
||||
break
|
||||
else:
|
||||
time.sleep(5)
|
||||
if time.time() - t_start > 60:
|
||||
self.logger("ERROR", "do_brake-run_rl","60s 内程序未能正常执行,需检查...", "red", "RlProgramStartTimeout")
|
||||
|
||||
for i in range(16):
|
||||
if clibs.c_md.read_ready_to_go() == 1:
|
||||
clibs.c_md.write_act(1)
|
||||
break
|
||||
else:
|
||||
time.sleep(1)
|
||||
else:
|
||||
self.logger("ERROR", "do_brake-run_rl", "16s 内未收到机器人的运行信号,需要确认 RL 程序配置正确并正常执行...", "red", "ReadySignalTimeoutError")
|
||||
|
||||
def exec_brake():
|
||||
flag, start, data, record = True, time.time(), None, None
|
||||
while flag:
|
||||
time.sleep(0.05)
|
||||
if time.time() - start > 20:
|
||||
self.logger("ERROR", "do_brake-exec_brake", "20s 内未触发急停,需排查......", "red", "BrakeTimeoutError")
|
||||
|
||||
try:
|
||||
clibs.lock.acquire(True)
|
||||
clibs.cursor.execute(f"select content from logs where content like '%diagnosis.result%' order by id desc limit 1")
|
||||
record = clibs.cursor.fetchone()
|
||||
data = eval(record[0])["data"]
|
||||
finally:
|
||||
clibs.lock.release()
|
||||
|
||||
for item in data:
|
||||
if item.get("channel", None) != axis-1 or item.get("name", None) != "hw_joint_vel_feedback":
|
||||
continue
|
||||
|
||||
speed_moment = clibs.RADIAN * sum(item["value"]) / len(item["value"])
|
||||
if abs(speed_moment) > speed_max - 2:
|
||||
if (pon == "positive" and speed_moment > 0) or (pon == "negative" and speed_moment < 0):
|
||||
clibs.c_ec.setdo_value(io_name, "false")
|
||||
time.sleep(2)
|
||||
flag = False
|
||||
break
|
||||
return time.time()
|
||||
|
||||
time.sleep(11) # 排除从其他位姿到零点位姿,再到轴极限位姿的时间
|
||||
t_end = exec_brake()
|
||||
# 6. 保留数据并处理输出
|
||||
ret = self.gen_result_file(axis, t_end, reach, load, speed, speed_max, rounds)
|
||||
if ret != "retry":
|
||||
clibs.count = 0
|
||||
break
|
||||
|
||||
else:
|
||||
time.sleep(50) # why?
|
||||
self.change_curve_state(False)
|
||||
msg = f"\n{self.tool.removeprefix('tool')}%负载的制动性能测试执行完毕,如需采集其他负载,须切换负载类型,并更换其他负载,重新执行"
|
||||
self.logger("INFO", "do_brake-run_rl", msg, "green")
|
||||
|
||||
def processing(self):
|
||||
time_start = time.time()
|
||||
clibs.running[self.idx] = 1
|
||||
|
||||
data_dirs, data_files = clibs.traversal_files(self.dir_path, self.output)
|
||||
config_file, prj_file, result_dirs, avs = self.initialization(data_dirs, data_files)
|
||||
clibs.c_pd.push_prj_to_server(prj_file)
|
||||
self.run_rl(config_file, prj_file, result_dirs, avs)
|
||||
|
||||
self.logger("INFO", "brake-processing", "-"*60 + "<br>全部处理完毕<br>", "purple")
|
||||
time_total = time.time() - time_start
|
||||
msg = f"处理时间:{time_total // 3600:02.0f} h {time_total % 3600 // 60:02.0f} m {time_total % 60:02.0f} s"
|
||||
self.logger("INFO", "brake-processing", msg)
|
268
code/autotest/do_current.py
Normal file
268
code/autotest/do_current.py
Normal file
@ -0,0 +1,268 @@
|
||||
import os
|
||||
import threading
|
||||
import time
|
||||
import paramiko
|
||||
import pandas
|
||||
from PySide6.QtCore import Signal, QThread
|
||||
from common import clibs
|
||||
|
||||
|
||||
class DoBrakeTest(QThread):
|
||||
output = Signal(str, str)
|
||||
|
||||
def __init__(self, dir_path, tool, /):
|
||||
super().__init__()
|
||||
self.dir_path = dir_path
|
||||
self.tool = tool
|
||||
self.idx = 5
|
||||
|
||||
def logger(self, level, module, content, color="black", error="", flag="both"):
|
||||
clibs.logger(level, module, content, color, flag, signal=self.output)
|
||||
if level.upper() == "ERROR":
|
||||
raise Exception(f"{error} | {content}")
|
||||
|
||||
def initialization(self, data_dirs, data_files):
|
||||
def check_files():
|
||||
msg = "初始路径下不允许有文件夹,初始路径下只能存在如下两个文件,且文件为关闭状态,确认后重新运行!<br>"
|
||||
msg += "1. T_电机电流.xlsx<br>2. xxxx.zip"
|
||||
if len(data_dirs) != 0 or len(data_files) != 2:
|
||||
self.logger("ERROR", "do_current-check_files", msg, "red", "InitFileError")
|
||||
|
||||
prj_file, count = None, 0
|
||||
for data_file in data_files:
|
||||
filename = data_file.split("/")[-1]
|
||||
if filename == "T_电机电流.xlsx":
|
||||
count += 1
|
||||
elif filename.endswith(".zip"):
|
||||
count += 1
|
||||
prj_file = data_file
|
||||
else:
|
||||
self.logger("ERROR", "do_current-check_files", msg, "red", "InitFileError")
|
||||
|
||||
if count != 2:
|
||||
self.logger("ERROR", "do_current-check_files", msg, "red", "InitFileError")
|
||||
|
||||
self.logger("INFO", "do_current-check_files", "数据目录合规性检查结束,未发现问题......", "green")
|
||||
if self.tool == "tool100":
|
||||
os.mkdir(f"{self.dir_path}/single")
|
||||
os.mkdir(f"{self.dir_path}/s_1")
|
||||
os.mkdir(f"{self.dir_path}/s_2")
|
||||
os.mkdir(f"{self.dir_path}/s_3")
|
||||
elif self.tool == "inertia":
|
||||
os.mkdir(f"{self.dir_path}/inertia")
|
||||
else:
|
||||
self.logger("ERROR", "do_current-check_files", "负载选择错误,电机电流测试只能选择 tool100/inertia 规格!", "red", "LoadSelectError")
|
||||
|
||||
return prj_file
|
||||
|
||||
def get_configs():
|
||||
robot_type = None
|
||||
msg_id, state = clibs.c_hr.execution("controller.get_params")
|
||||
records = clibs.c_hr.get_from_id(msg_id, state)
|
||||
for record in records:
|
||||
if "请求发送成功" not in record[0]:
|
||||
robot_type = eval(record[0])["data"]["robot_type"]
|
||||
server_file = f"/home/luoshi/bin/controller/robot_cfg/{robot_type}/{robot_type}.cfg"
|
||||
local_file = self.dir_path + f"/{robot_type}.cfg"
|
||||
clibs.c_pd.pull_file_from_server(server_file, local_file)
|
||||
|
||||
_prj_file = check_files()
|
||||
get_configs()
|
||||
|
||||
return _prj_file
|
||||
|
||||
def single_axis_proc(self, records, number):
|
||||
text = "single" if number < 6 else "hold"
|
||||
number = number if number < 6 else number - 6
|
||||
d_vel, d_trq, d_sensor, d_trans = [], [], [], []
|
||||
for record in records:
|
||||
data = eval(record[0])["data"]
|
||||
for item in data:
|
||||
d_item = reversed(item["value"])
|
||||
if item.get("channel", None) == number and item.get("name", None) == "hw_joint_vel_feedback":
|
||||
d_vel.extend(d_item)
|
||||
elif item.get("channel", None) == number and item.get("name", None) == "device_servo_trq_feedback":
|
||||
d_trq.extend(d_item)
|
||||
elif item.get("channel", None) == number and item.get("name", None) == "hw_sensor_trq_feedback":
|
||||
d_sensor.extend(d_item)
|
||||
elif item.get("channel", None) == number and item.get("name", None) == "hw_estimate_trans_trq_res":
|
||||
d_trans.extend(d_item)
|
||||
|
||||
df1 = pandas.DataFrame.from_dict({"hw_joint_vel_feedback": d_vel})
|
||||
df2 = pandas.DataFrame.from_dict({"device_servo_trq_feedback": d_trq})
|
||||
df3 = pandas.DataFrame.from_dict({"hw_sensor_trq_feedback": d_sensor})
|
||||
df4 = pandas.DataFrame.from_dict({"hw_estimate_trans_trq_res": d_trans})
|
||||
df = pandas.concat([df1, df2, df3, df4], axis=1)
|
||||
filename = f"{self.dir_path}/single/j{number + 1}_{text}_{time.time()}.data"
|
||||
df.to_csv(filename, sep="\t", index=False)
|
||||
|
||||
def scenario_proc(self, records, number, scenario_time):
|
||||
d_vel, d_trq, d_sensor, d_trans = [[], [], [], [], [], []], [[], [], [], [], [], []], [[], [], [], [], [], []], [[], [], [], [], [], []]
|
||||
for record in records:
|
||||
data = eval(record[0])["data"]
|
||||
for item in data:
|
||||
d_item = reversed(item["value"])
|
||||
for axis in range(6):
|
||||
if item.get("channel", None) == axis and item.get("name", None) == "hw_joint_vel_feedback":
|
||||
d_vel[axis].extend(d_item)
|
||||
elif item.get("channel", None) == axis and item.get("name", None) == "device_servo_trq_feedback":
|
||||
d_trq[axis].extend(d_item)
|
||||
elif item.get("channel", None) == axis and item.get("name", None) == "hw_sensor_trq_feedback":
|
||||
d_sensor[axis].extend(d_item)
|
||||
elif item.get("channel", None) == axis and item.get("name", None) == "hw_estimate_trans_trq_res":
|
||||
d_trans[axis].extend(d_item)
|
||||
|
||||
for axis in range(6):
|
||||
df1 = pandas.DataFrame.from_dict({"hw_joint_vel_feedback": d_vel[axis]})
|
||||
df2 = pandas.DataFrame.from_dict({"device_servo_trq_feedback": d_trq[axis]})
|
||||
df3 = pandas.DataFrame.from_dict({"hw_sensor_trq_feedback": d_sensor[axis]})
|
||||
df4 = pandas.DataFrame.from_dict({"hw_estimate_trans_trq_res": d_trans[axis]})
|
||||
df = pandas.concat([df1, df2, df3, df4], axis=1)
|
||||
filename = f"{self.dir_path}/s_{number-11}/j{axis+1}_s_{number-11}_{scenario_time}_{time.time()}.data"
|
||||
df.to_csv(filename, sep="\t", index=False)
|
||||
|
||||
def gen_result_file(self, number, start_time, end_time, scenario_time):
|
||||
def get_records(s_time, e_time):
|
||||
clibs.cursor.execute(f"select content from logs where time between '{s_time}' and '{e_time}' and content like '%diagnosis.result%' order by id asc")
|
||||
_ = clibs.cursor.fetchall()
|
||||
return _
|
||||
|
||||
if number < 12:
|
||||
records = get_records(start_time, end_time)
|
||||
t = threading.Thread(target=self.single_axis_proc, args=(records, number))
|
||||
t.daemon = True
|
||||
t.start()
|
||||
elif number < 15:
|
||||
records = get_records(start_time, end_time)
|
||||
t = threading.Thread(target=self.scenario_proc, args=(records, number, scenario_time))
|
||||
t.daemon = True
|
||||
t.start()
|
||||
|
||||
@staticmethod
|
||||
def change_curve_state(stat):
|
||||
curves = ["hw_joint_vel_feedback", "device_servo_trq_feedback", "hw_sensor_trq_feedback", "hw_estimate_trans_trq_res"]
|
||||
display_pdo_params = [] if not stat else [{"name": curve, "channel": chl} for curve in curves for chl in range(6)]
|
||||
clibs.c_hr.execution("diagnosis.open", open=stat, display_open=stat, overrun=True, turn_area=True, delay_motion=False)
|
||||
clibs.c_hr.execution("diagnosis.set_params", display_pdo_params=display_pdo_params, frequency=50, version="1.4.1")
|
||||
|
||||
def run_rl(self, prj_file):
|
||||
prj_name = ".".join(prj_file.split("/")[-1].split(".")[:-1])
|
||||
c_regular = [
|
||||
"scenario(0, j1_p, j1_n, p_speed, p_tool, i_tool)",
|
||||
"scenario(0, j2_p, j2_n, p_speed, p_tool, i_tool)",
|
||||
"scenario(0, j3_p, j3_n, p_speed, p_tool, i_tool)",
|
||||
"scenario(0, j4_p, j4_n, p_speed, p_tool, i_tool)",
|
||||
"scenario(0, j5_p, j5_n, p_speed, p_tool, i_tool)",
|
||||
"scenario(0, j6_p, j6_n, p_speed, p_tool, i_tool)",
|
||||
"scenario(4, j1_hold, j1_hold, p_speed, p_tool, i_tool)",
|
||||
"scenario(4, j2_hold, j2_hold, p_speed, p_tool, i_tool)",
|
||||
"scenario(4, j3_hold, j3_hold, p_speed, p_tool, i_tool)",
|
||||
"scenario(4, j4_hold, j4_hold, p_speed, p_tool, i_tool)",
|
||||
"scenario(4, j5_hold, j5_hold, p_speed, p_tool, i_tool)",
|
||||
"scenario(4, j6_hold, j6_hold, p_speed, p_tool, i_tool)",
|
||||
"scenario(1, j6_p, j6_n, p_speed, p_tool, i_tool)",
|
||||
"scenario(2, j6_p, j6_n, p_speed, p_tool, i_tool)",
|
||||
"scenario(3, j6_p, j6_n, p_speed, p_tool, i_tool)",
|
||||
]
|
||||
c_inertia = [
|
||||
"scenario(5, j4_p_inertia, j4_n_inertia, p_speed, p_tool, i_tool)",
|
||||
"scenario(5, j5_p_inertia, j5_n_inertia, p_speed, p_tool, i_tool)",
|
||||
"scenario(5, j6_p_inertia, j6_n_inertia, p_speed, p_tool, i_tool)",
|
||||
]
|
||||
disc_regular = ["一轴", "二轴", "三轴", "四轴", "五轴", "六轴", "一轴保持", "二轴保持", "三轴保持", "四轴保持", "五轴保持", "六轴保持", "场景一", "场景二", "场景三"]
|
||||
disc_inertia = ["四轴惯量", "五轴惯量", "六轴惯量"]
|
||||
conditions, disc = [], []
|
||||
if self.tool == "tool100":
|
||||
conditions, disc = c_regular, disc_regular
|
||||
elif self.tool == "inertia":
|
||||
conditions, disc = c_inertia, disc_inertia
|
||||
|
||||
# 打开诊断曲线,触发软急停,并解除,目的是让可能正在运行着的机器停下来
|
||||
clibs.c_md.r_soft_estop(0)
|
||||
clibs.c_md.r_soft_estop(1)
|
||||
clibs.c_md.r_clear_alarm()
|
||||
|
||||
for condition in conditions:
|
||||
number = conditions.index(condition)
|
||||
self.logger("INFO", "do_current-run_rl", f"正在执行{disc[number]}测试......")
|
||||
|
||||
# 1. 将act重置为False,并修改将要执行的场景
|
||||
clibs.c_md.write_act(False)
|
||||
ssh = paramiko.SSHClient()
|
||||
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
|
||||
ssh.connect(clibs.ip_addr, clibs.ssh_port, username=clibs.username, password=clibs.password)
|
||||
cmd = "cd /home/luoshi/bin/controller/; "
|
||||
cmd += f'sudo sed -i "/scenario/d" projects/{prj_name}/_build/current/main.mod; '
|
||||
cmd += f'sudo sed -i "/DONOTDELETE/i {condition}" projects/{prj_name}/_build/current/main.mod'
|
||||
stdin, stdout, stderr = ssh.exec_command(cmd, get_pty=True)
|
||||
stdin.write(clibs.password + "\n")
|
||||
stdout.read().decode() # 需要read一下才能正常执行
|
||||
stderr.read().decode()
|
||||
|
||||
# 2. reload工程后,pp2main,并且自动模式和上电
|
||||
prj_path = f"{prj_name}/_build/{prj_name}.prj"
|
||||
clibs.c_hr.execution("overview.reload", prj_path=prj_path, tasks=["current"])
|
||||
clibs.c_hr.execution("rl_task.pp_to_main", tasks=["current"])
|
||||
clibs.c_hr.execution("state.switch_auto")
|
||||
clibs.c_hr.execution("state.switch_motor_on")
|
||||
|
||||
# 3. 开始运行程序
|
||||
clibs.c_hr.execution("rl_task.set_run_params", loop_mode=True, override=1.0)
|
||||
clibs.c_hr.execution("rl_task.run", tasks=["current"])
|
||||
t_start = time.time()
|
||||
while True:
|
||||
if clibs.c_md.read_ready_to_go() == 1:
|
||||
clibs.c_md.write_act(True)
|
||||
break
|
||||
else:
|
||||
time.sleep(1)
|
||||
if (time.time() - t_start) > 15:
|
||||
self.logger("ERROR", "do_current-run_rl", "15s 内未收到机器人的运行信号,需要确认RL程序和工具通信是否正常执行...", "red", "ReadySignalTimeoutError")
|
||||
|
||||
# 4. 执行采集
|
||||
time.sleep(10) # 消除前 10s 的不稳定数据
|
||||
self.change_curve_state(True)
|
||||
start_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
|
||||
single_time, stall_time, scenario_time = 40, 10, 0
|
||||
if number < 6: # 单轴
|
||||
time.sleep(single_time)
|
||||
elif number < 12: # 堵转
|
||||
time.sleep(stall_time)
|
||||
else: # 场景
|
||||
t_start = time.time()
|
||||
while True:
|
||||
scenario_time = float(f"{float(clibs.c_md.read_scenario_time()):.2f}")
|
||||
if float(scenario_time) != 0:
|
||||
self.logger("INFO", "do_current-run_rl", f"场景{number - 11}的周期时间:{scenario_time}")
|
||||
break
|
||||
else:
|
||||
time.sleep(1)
|
||||
if (time.time()-t_start) > 180:
|
||||
self.logger("ERROR", "do_current-run_rl", f"180s 内未收到场景{number - 11}的周期时间,需要确认RL程序和工具通信交互是否正常执行...", "red", "GetScenarioTimeError")
|
||||
time.sleep(20)
|
||||
|
||||
# 5.停止程序运行,保留数据并处理输出
|
||||
end_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
|
||||
clibs.c_hr.execution("rl_task.stop", tasks=["current"])
|
||||
time.sleep(2) # 确保数据都拿到
|
||||
self.change_curve_state(False)
|
||||
self.gen_result_file(number, start_time, end_time, scenario_time)
|
||||
else:
|
||||
if self.tool == "tool100":
|
||||
self.logger("INFO", "do_current-run_rl", "单轴和场景电机电流采集完毕,如需采集惯量负载,须切换负载类型,并更换惯量负载,重新执行", "green")
|
||||
elif self.tool == "inertia":
|
||||
self.logger("INFO", "do_current-run_rl", "惯量负载电机电流采集完毕,如需采集单轴/场景/保持电机电流,须切换负载类型,并更换偏置负载,重新执行", "green")
|
||||
|
||||
def processing(self):
|
||||
time_start = time.time()
|
||||
clibs.running[self.idx] = 1
|
||||
|
||||
data_dirs, data_files = clibs.traversal_files(self.dir_path, self.output)
|
||||
prj_file = self.initialization(data_dirs, data_files)
|
||||
clibs.c_pd.push_prj_to_server(prj_file)
|
||||
self.run_rl(prj_file)
|
||||
|
||||
self.logger("INFO", "brake-processing", "-" * 60 + "<br>全部处理完毕<br>", "purple")
|
||||
time_total = time.time() - time_start
|
||||
msg = f"处理时间:{time_total // 3600:02.0f} h {time_total % 3600 // 60:02.0f} m {time_total % 60:02.0f} s"
|
||||
self.logger("INFO", "brake-processing", msg)
|
62
code/common/clibs.py
Normal file
62
code/common/clibs.py
Normal file
@ -0,0 +1,62 @@
|
||||
import os
|
||||
import os.path
|
||||
import threading
|
||||
|
||||
|
||||
def traversal_files(dir_path, signal):
|
||||
# 功能:以列表的形式分别返回指定路径下的文件和文件夹,不包含子目录
|
||||
# 参数:路径/信号/游标/功能编号
|
||||
# 返回值:路径下的文件夹列表 路径下的文件列表
|
||||
global cursor, tb_name
|
||||
|
||||
if not os.path.exists(dir_path):
|
||||
logger("ERROR", "clibs", f"数据文件夹{dir_path}不存在,请确认后重试......", "red", signal=signal)
|
||||
else:
|
||||
dirs, files = [], []
|
||||
for item in os.scandir(dir_path):
|
||||
if item.is_dir():
|
||||
dirs.append(item.path.replace("\\", "/"))
|
||||
elif item.is_file():
|
||||
files.append(item.path.replace("\\", "/"))
|
||||
|
||||
return dirs, files
|
||||
|
||||
|
||||
def db_lock(func):
|
||||
def wrapper(*args, **kwargs):
|
||||
try:
|
||||
lock.acquire(True)
|
||||
ret = func(*args, **kwargs)
|
||||
finally:
|
||||
lock.release()
|
||||
return ret
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
@db_lock
|
||||
def logger(level, module, content, color="black", flag="both", signal=""):
|
||||
global cursor, tb_name
|
||||
if flag == "signal":
|
||||
signal.emit(content, color)
|
||||
elif flag == "cursor":
|
||||
cursor.execute(f"INSERT INTO {tb_name} (level, module, content) VALUES (%s, %s, %s)", (level, module, content))
|
||||
elif flag == "both":
|
||||
signal.emit(content, color)
|
||||
cursor.execute(f"INSERT INTO {tb_name} (level, module, content) VALUES (%s, %s, %s)", (level, module, content))
|
||||
|
||||
|
||||
# PREFIX = "assets" # for pyinstaller packaging
|
||||
PREFIX = "../assets" # for source code testing and debug
|
||||
lock = threading.Lock()
|
||||
|
||||
running = [0, 0, 0, 0, 0, 0, 0] # 制动数据/转矩数据/激光数据/精度数据/制动自动化/转矩自动化/耐久数据采集
|
||||
functions = ["制动数据处理", "转矩数据处理", "激光数据处理", "精度数据处理", "制动自动化测试", "转矩自动化测试", "耐久数据采集"]
|
||||
|
||||
log_name = ""
|
||||
ip_addr, ssh_port, socket_port, xService_port, external_port, modbus_port, upgrade_port = "", 22, 5050, 6666, 8080, 502, 4567
|
||||
username, password = "luoshi", "123456"
|
||||
INTERVAL, RADIAN, MAX_FRAME_SIZE, MAX_LOG_NUMBER = 0.5, 57.3, 1024, 10
|
||||
c_md, c_hr, c_ec, c_pd, cursor, tb_name = None, None, None, None, None, ""
|
||||
status = {"mysql": 0, "hmi": 0, "md": 0, "ec": 0}
|
||||
c_joint_vel, c_servo_trq, c_sensor_trq, c_estimate_trans_trq, c_safety_estop = 1, 2, 3, 4, 3 # 各个指标所在列
|
2577
code/common/openapi.py
Normal file
2577
code/common/openapi.py
Normal file
File diff suppressed because it is too large
Load Diff
85
code/durable/create_plot.py
Normal file
85
code/durable/create_plot.py
Normal file
@ -0,0 +1,85 @@
|
||||
import os.path
|
||||
import matplotlib.pyplot as plt
|
||||
import pandas
|
||||
from matplotlib.widgets import Slider
|
||||
from PySide6.QtCore import Signal, QThread
|
||||
from common import clibs
|
||||
|
||||
|
||||
# class DrawCurves(QThread):
|
||||
# output = Signal(str, str)
|
||||
#
|
||||
# def __init__(self, /):
|
||||
# super().__init__()
|
||||
#
|
||||
# @staticmethod
|
||||
# def logger(level, module, content, color="black", error="", flag="both", signal=output):
|
||||
# clibs.logger(level, module, content, color, flag, signal)
|
||||
# if level.upper() == "ERROR":
|
||||
# raise Exception(error)
|
||||
#
|
||||
# def initialization(self):
|
||||
# path, curves = None, None
|
||||
# try:
|
||||
# path = clibs.data_dd["path"]
|
||||
# curves = clibs.data_dd["curves"]
|
||||
# except Exception:
|
||||
# clibs.w2t("程序未开始运行,暂无数据可以展示......\n", "red")
|
||||
# return None, None
|
||||
#
|
||||
# for curve in curves:
|
||||
# if not os.path.exists(f"{path}/{curve}.csv"):
|
||||
# clibs.w2t(f"{curve}曲线数据暂未生成,稍后再试......\n", "orange")
|
||||
# return None, None
|
||||
#
|
||||
# return path, curves
|
||||
#
|
||||
#
|
||||
# def data_plot(path, curve):
|
||||
# titles = {"hw_joint_vel_feedback": "各关节最大速度曲线", "device_servo_trq_feedback": "各关节平均有效转矩曲线"}
|
||||
# ylabels = {"hw_joint_vel_feedback": "速度(rad/s)", "device_servo_trq_feedback": "转矩(Nm)"}
|
||||
#
|
||||
# fig, axes = plt.subplots(figsize=(10, 4.5), dpi=100)
|
||||
# cols = [f"{curve}_{i}" for i in range(6)]
|
||||
# cols.insert(0, "time")
|
||||
# df = pandas.read_csv(f"{path}/{curve}.csv")
|
||||
# plt.plot(df[cols[1]], label="一轴")
|
||||
# plt.plot(df[cols[2]], label="二轴")
|
||||
# plt.plot(df[cols[3]], label="三轴")
|
||||
# plt.plot(df[cols[4]], label="四轴")
|
||||
# plt.plot(df[cols[5]], label="五轴")
|
||||
# plt.plot(df[cols[6]], label="六轴")
|
||||
# axes.set_title(titles[curve])
|
||||
# axes.set_ylabel(ylabels[curve])
|
||||
# axes.legend(loc="upper right")
|
||||
#
|
||||
# slider_position = plt.axes((0.1, 0.01, 0.8, 0.05), facecolor="blue") # (left, bottom, width, height)
|
||||
# scrollbar = Slider(slider_position, 'Time', 1, int(len(df)), valstep=1)
|
||||
#
|
||||
# def update(val):
|
||||
# pos = scrollbar.val
|
||||
# axes.set_xlim([pos, pos + 10])
|
||||
# fig.canvas.draw_idle()
|
||||
#
|
||||
# scrollbar.on_changed(update)
|
||||
# fig.tight_layout(rect=(0, 0.02, 0.96, 1)) # tuple (left, bottom, right, top)
|
||||
#
|
||||
#
|
||||
# def main():
|
||||
# path, curves = initialization()
|
||||
# if not path or not curves:
|
||||
# return
|
||||
#
|
||||
# for curve in curves:
|
||||
# data_plot(path, curve)
|
||||
#
|
||||
# plt.show()
|
||||
#
|
||||
#
|
||||
# plt.rcParams['font.sans-serif'] = ['SimHei']
|
||||
# plt.rcParams['axes.unicode_minus'] = False
|
||||
# plt.rcParams['figure.dpi'] = 100
|
||||
# plt.rcParams['font.size'] = 14
|
||||
# plt.rcParams['lines.marker'] = 'o'
|
||||
# plt.rcParams["figure.autolayout"] = True
|
||||
#
|
239
code/durable/factory_test.py
Normal file
239
code/durable/factory_test.py
Normal file
@ -0,0 +1,239 @@
|
||||
import json
|
||||
import threading
|
||||
import time
|
||||
import pandas
|
||||
import numpy
|
||||
import math
|
||||
import csv
|
||||
from PySide6.QtCore import Signal, QThread
|
||||
from common import clibs
|
||||
|
||||
|
||||
class DoBrakeTest(QThread):
|
||||
output = Signal(str, str)
|
||||
|
||||
def __init__(self, dir_path, interval, proc, /):
|
||||
super().__init__()
|
||||
self.dir_path = dir_path
|
||||
self.interval = interval
|
||||
self.proc = proc
|
||||
self.idx = 6
|
||||
|
||||
def logger(self, level, module, content, color="black", error="", flag="both"):
|
||||
clibs.logger(level, module, content, color, flag, signal=self.output)
|
||||
if level.upper() == "ERROR":
|
||||
raise Exception(f"{error} | {content}")
|
||||
|
||||
def initialization(self, data_dirs, data_files):
|
||||
def check_files():
|
||||
if len(curves) == 0:
|
||||
self.logger("ERROR", "factory-check_files", "未查询到需要记录数据的曲线,至少选择一个!", "red", "CurveNameError")
|
||||
|
||||
if len(data_dirs) != 0 or len(data_files) != 1:
|
||||
self.logger("ERROR", "factory-check_files", "初始路径下不允许有文件夹,且初始路径下只能存在一个工程文件 —— *.zip,确认后重新运行!", "red", "InitFileError")
|
||||
|
||||
if not data_files[0].endswith(".zip"):
|
||||
self.logger("ERROR", "factory-check_files", f"{data_files[0]} 不是一个有效的工程文件,需确认!", "red", "ProjectFileError")
|
||||
|
||||
return data_files[0], interval
|
||||
|
||||
def get_configs():
|
||||
robot_type, records = None, None
|
||||
msg_id, state = clibs.c_hr.execution("controller.get_params")
|
||||
records = clibs.c_hr.get_from_id(msg_id, state)
|
||||
for record in records:
|
||||
if "请求发送成功" not in record[0]:
|
||||
robot_type = eval(record[0])["data"]["robot_type"]
|
||||
server_file = f"/home/luoshi/bin/controller/robot_cfg/{robot_type}/{robot_type}.cfg"
|
||||
local_file = self.dir_path + f"/{robot_type}.cfg"
|
||||
clibs.c_pd.pull_file_from_server(server_file, local_file)
|
||||
|
||||
try:
|
||||
with open(local_file, mode="r", encoding="utf-8") as f_config:
|
||||
configs = json.load(f_config)
|
||||
except Exception as Err:
|
||||
self.logger("ERROR", "factory-get_configs", f"无法打开 {local_file}<br>{Err}", "red", "OpenFileError")
|
||||
|
||||
# 最大角速度,额定电流,减速比,额定转速
|
||||
version = configs["VERSION"]
|
||||
m_avs = configs["MOTION"]["JOINT_MAX_SPEED"]
|
||||
m_rts = configs["MOTOR"]["RATED_TORQUE"] # 电机额定转矩rt for rated torque
|
||||
m_tcs = [1, 1, 1, 1, 1, 1] # 电机转矩常数,tc for torque constant
|
||||
m_rcs = []
|
||||
for i in range(len(m_tcs)):
|
||||
m_rcs.append(m_rts[i] / m_tcs[i]) # 电机额定电流,rc for rated current
|
||||
clibs.insert_logdb("INFO", "do_brake", f"get_configs: 机型文件版本 {robot_type}_{version}")
|
||||
clibs.insert_logdb("INFO", "do_brake", f"get_configs: 各关节角速度 {m_avs}")
|
||||
clibs.insert_logdb("INFO", "do_brake", f"get_configs: 各关节额定电流 {m_rcs}")
|
||||
return m_avs, m_rcs
|
||||
|
||||
prj_file, interval = check_files()
|
||||
avs, rcs = get_configs()
|
||||
params = {
|
||||
"prj_file": prj_file,
|
||||
"interval": interval,
|
||||
"avs": avs,
|
||||
"rcs": rcs,
|
||||
}
|
||||
self.logger("INFO", "factory-initialization", "数据目录合规性检查结束,未发现问题......", "green")
|
||||
return params
|
||||
|
||||
@staticmethod
|
||||
def change_curve_state(curves, stat):
|
||||
display_pdo_params = [{"name": name, "channel": chl} for name in curves for chl in range(6)]
|
||||
clibs.c_hr.execution("diagnosis.open", open=stat, display_open=stat, overrun=True, turn_area=True, delay_motion=False)
|
||||
clibs.c_hr.execution("diagnosis.set_params", display_pdo_params=display_pdo_params, frequency=50, version="1.4.1")
|
||||
|
||||
def run_rl(self, params, curves):
|
||||
prj_file, interval = params["prj_file"], params["interval"]
|
||||
# 1. 关闭诊断曲线,触发软急停,并解除,目的是让可能正在运行着的机器停下来,切手动模式并下电
|
||||
self.change_curve_state(curves, False)
|
||||
clibs.c_md.r_soft_estop(0)
|
||||
clibs.c_md.r_soft_estop(1)
|
||||
clibs.c_md.r_clear_alarm()
|
||||
clibs.c_md.write_act(False)
|
||||
time.sleep(1) # 让曲线彻底关闭
|
||||
|
||||
# 2. reload工程后,pp2main,并且自动模式和上电
|
||||
prj_name = ".".join(prj_file.split("/")[-1].split(".")[:-1])
|
||||
prj_path = f"{prj_name}/_build/{prj_name}.prj"
|
||||
clibs.c_hr.execution("overview.reload", prj_path=prj_path, tasks=["factory"])
|
||||
clibs.c_hr.execution("rl_task.pp_to_main", tasks=["factory"])
|
||||
clibs.c_hr.execution("state.switch_auto")
|
||||
clibs.c_hr.execution("state.switch_motor_on")
|
||||
|
||||
# 3. 开始运行程序
|
||||
clibs.c_hr.execution("rl_task.set_run_params", loop_mode=True, override=1.0)
|
||||
clibs.c_hr.execution("rl_task.run", tasks=["factory"])
|
||||
t_start = time.time()
|
||||
while True:
|
||||
if clibs.c_md.read_ready_to_go() == 1:
|
||||
clibs.c_md.write_act(True)
|
||||
break
|
||||
else:
|
||||
if (time.time() - t_start) > 15:
|
||||
self.logger("ERROR", "factory-run_rl", "15s 内未收到机器人的运行信号,需要确认RL程序编写正确并正常执行...", "red", "ReadySignalTimeoutError")
|
||||
else:
|
||||
time.sleep(1)
|
||||
|
||||
# 4. 获取初始数据,周期时间,首次的各轴平均电流值,打开诊断曲线,并执行采集
|
||||
time.sleep(10) # 等待 RL 程序中 scenario_time 初始化
|
||||
t_start = time.time()
|
||||
while True:
|
||||
scenario_time = float(f"{float(clibs.c_md.read_scenario_time()):.2f}")
|
||||
if scenario_time != 0:
|
||||
self.logger("INFO", "factory-run_rl", f"耐久工程的周期时间:{scenario_time}s | 单轮次执行时间:{scenario_time+interval}~{scenario_time*2+interval}")
|
||||
break
|
||||
else:
|
||||
time.sleep(1)
|
||||
if (time.time() - t_start) > 900:
|
||||
self.logger("ERROR", "factory-run_rl", f"900s 内未收到耐久工程的周期时间,需要确认RL程序和工具通信交互是否正常执行...", "red", "GetScenarioTimeError")
|
||||
|
||||
# 6. 准备数据保存文件
|
||||
for curve in curves:
|
||||
with open(f"{self.dir_path}/{curve}.csv", mode="a+", newline="") as f_csv:
|
||||
titles = [f"{curve}_{i}" for i in range(6)]
|
||||
titles.insert(0, "time")
|
||||
csv_writer = csv.writer(f_csv)
|
||||
csv_writer.writerow(titles)
|
||||
|
||||
# 7. 开始采集
|
||||
count = 0
|
||||
while clibs.running:
|
||||
this_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
|
||||
next_time_1 = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()+scenario_time+interval+1))
|
||||
next_time_2 = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()+scenario_time+interval+1+scenario_time))
|
||||
self.logger("INFO", "factory-run_rl", f"[{this_time}] 当前次数:{count:09d} | 预计下次数据更新时间:{next_time_1}~{next_time_2}", "#008B8B")
|
||||
count += 1
|
||||
# 固定间隔,更新一次数据,打开曲线,获取周期内电流,关闭曲线
|
||||
time.sleep(interval)
|
||||
while True:
|
||||
capture_start = clibs.c_md.read_capture_start()
|
||||
if capture_start == 1:
|
||||
break
|
||||
else:
|
||||
time.sleep(0.1)
|
||||
|
||||
self.change_curve_state(curves, True)
|
||||
time.sleep(scenario_time)
|
||||
end_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
|
||||
start_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()-scenario_time))
|
||||
self.change_curve_state(curves, False)
|
||||
# 保留数据并处理输出
|
||||
self.gen_results(params, curves, start_time, end_time)
|
||||
else:
|
||||
self.change_curve_state(curves, False)
|
||||
self.logger("INFO", "factory", "后台数据清零完成,现在可以重新运行其他程序。", "green")
|
||||
|
||||
def gen_results(self, params, curves, start_time, end_time):
|
||||
clibs.cursor.execute(f"select content from logs where time between '{start_time}' and '{end_time}' and content like '%diagnosis.result%' order by id asc")
|
||||
records = clibs.cursor.fetchall()
|
||||
self.data_proc(records, params, curves)
|
||||
|
||||
def data_proc(self, records, params, curves):
|
||||
for curve in curves:
|
||||
if curve == "device_servo_trq_feedback":
|
||||
# proc_device_servo_trq_feedback(records, params, w2t)
|
||||
t = threading.Thread(target=self.proc_device_servo_trq_feedback, args=(records, params))
|
||||
t.daemon = True
|
||||
t.start()
|
||||
elif curve == "hw_joint_vel_feedback":
|
||||
# proc_hw_joint_vel_feedback(records, params, w2t)
|
||||
t = threading.Thread(target=self.proc_hw_joint_vel_feedback, args=(records, params))
|
||||
t.daemon = True
|
||||
t.start()
|
||||
|
||||
def proc_device_servo_trq_feedback(self, records, params):
|
||||
d_trq, rcs, results = [[], [], [], [], [], []], params["rcs"], [time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))]
|
||||
for record in records:
|
||||
data = eval(record[0])["data"]
|
||||
for item in data:
|
||||
d_item = reversed(item["value"])
|
||||
for axis in range(6):
|
||||
if item.get("channel", None) == axis and item.get("name", None) == "device_servo_trq_feedback":
|
||||
d_trq[axis].extend(d_item)
|
||||
|
||||
for axis in range(6):
|
||||
df = pandas.DataFrame.from_dict({"device_servo_trq_feedback": d_trq[axis]})
|
||||
_ = math.sqrt(numpy.square(df[df.columns[0]].values * 1.27 / 1000).sum() / len(df))
|
||||
results.append(_)
|
||||
|
||||
path = "/".join(params["prj_file"].split("/")[:-1])
|
||||
with open(f"{path}/device_servo_trq_feedback.csv", mode="a+", newline="") as f_csv:
|
||||
csv_writer = csv.writer(f_csv)
|
||||
csv_writer.writerow(results)
|
||||
|
||||
def proc_hw_joint_vel_feedback(self, records, params):
|
||||
d_trq, rcs, results = [[], [], [], [], [], []], params["rcs"], [time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))]
|
||||
for record in records:
|
||||
data = eval(record[0])["data"]
|
||||
for item in data:
|
||||
d_item = reversed(item["value"])
|
||||
for axis in range(6):
|
||||
if item.get("channel", None) == axis and item.get("name", None) == "hw_joint_vel_feedback":
|
||||
d_trq[axis].extend(d_item)
|
||||
|
||||
for axis in range(6):
|
||||
df = pandas.DataFrame.from_dict({"hw_joint_vel_feedback": d_trq[axis]})
|
||||
_ = df.max().iloc[0]
|
||||
results.append(_)
|
||||
|
||||
path = "/".join(params["prj_file"].split("/")[:-1])
|
||||
with open(f"{path}/hw_joint_vel_feedback.csv", mode="a+", newline="") as f_csv:
|
||||
csv_writer = csv.writer(f_csv)
|
||||
csv_writer.writerow(results)
|
||||
|
||||
def processing(self):
|
||||
time_start = time.time()
|
||||
clibs.running[self.idx] = 1
|
||||
|
||||
data_dirs, data_files = clibs.traversal_files(self.dir_path, self.output)
|
||||
params = self.initialization(data_dirs, data_files)
|
||||
prj_file = params["prj_file"]
|
||||
clibs.c_pd.push_prj_to_server(prj_file)
|
||||
self.run_rl(params)
|
||||
|
||||
self.logger("INFO", "brake-processing", "-"*60 + "<br>全部处理完毕<br>", "purple")
|
||||
time_total = time.time() - time_start
|
||||
msg = f"处理时间:{time_total // 3600:02.0f} h {time_total % 3600 // 60:02.0f} m {time_total % 60:02.0f} s"
|
||||
self.logger("INFO", "brake-processing", msg)
|
113
code/test.py
Normal file
113
code/test.py
Normal file
@ -0,0 +1,113 @@
|
||||
import time
|
||||
|
||||
# import common.openapi as openapi
|
||||
#
|
||||
# hr = openapi.HmiRequest("10.2.21.252", 5050, 6666)
|
||||
# for _ in range(3):
|
||||
# hr.execution("controller.heart")
|
||||
# time.sleep(1)
|
||||
#
|
||||
# hr.close()
|
||||
|
||||
|
||||
|
||||
import pymysql
|
||||
|
||||
conn = pymysql.connect(host='10.2.20.216', user='root', password='Rokae_123457', port=13306, charset='utf8')
|
||||
cursor = conn.cursor()
|
||||
cursor.execute("SET autocommit = 1;")
|
||||
cursor.execute("use fanmingfu;")
|
||||
# cursor.execute("insert into 20250315153551_log (module, level, content) values (%s, %s, %s)", ("aioaaaaaa", "debug", "testing information"))
|
||||
# logger("ERROR", "clibs", f"数据文件夹{dir_path}不存在,请确认后重试......\n", signal, "red", "PathNotExistError", idx)
|
||||
|
||||
level = "ERROR"
|
||||
module = "clibs"
|
||||
content = "{'data': {'name': 'xCore'}, 'id': 'controller.heart-1742374255.8898985'}"
|
||||
tb_name = "20250319162718_log"
|
||||
cursor.execute(f"INSERT INTO {tb_name} (level, module, content) VALUES (%s, %s, %s)", (level, module, content))
|
||||
|
||||
# conn.commit()
|
||||
# ============================================
|
||||
# def tttt(flag, signal, cursor, **data):
|
||||
# if flag == "signal":
|
||||
# print(f"data = {data['signals']}")
|
||||
# elif flag == "cursor":
|
||||
# print(f"data = {data['cursors']}")
|
||||
# elif flag == "both":
|
||||
# print(f"data = {data}")
|
||||
# print(f"data = {data['signals']}")
|
||||
# print(f"data = {data['cursors']}")
|
||||
#
|
||||
#
|
||||
# tttt("both", 1, 1, signals=123, cursors=456)
|
||||
|
||||
# ============================================
|
||||
|
||||
# import sys
|
||||
# from time import sleep
|
||||
# from PySide6.QtCore import *
|
||||
# from PySide6.QtGui import *
|
||||
# from PySide6.QtWidgets import *
|
||||
#
|
||||
#
|
||||
# class MyWindow(QMainWindow):
|
||||
# range_number = Signal(int)
|
||||
#
|
||||
# def __init__(self) -> None:
|
||||
# super().__init__()
|
||||
# self.setWindowTitle("QThread学习")
|
||||
# self.resize(800, 600)
|
||||
# self.setup_ui()
|
||||
# self.setup_thread()
|
||||
#
|
||||
# def setup_ui(self):
|
||||
# self.mylistwidget = QListWidget(self)
|
||||
# self.mylistwidget.resize(500, 500)
|
||||
# self.mylistwidget.move(20, 20)
|
||||
#
|
||||
# self.additem_button = QPushButton(self)
|
||||
# self.additem_button.resize(150, 30)
|
||||
# self.additem_button.setText("填充QListWidget")
|
||||
# self.additem_button.move(530, 20)
|
||||
#
|
||||
# def setup_thread(self):
|
||||
# self.thread1 = QThread(self) # 创建一个线程
|
||||
# self.range_thread = WorkThread() # 实例化线程类
|
||||
# self.range_thread.moveToThread(self.thread1) # 将类移动到线程中运行
|
||||
# # 线程数据传回信号,用add_item函数处理
|
||||
# self.range_thread.range_requested.connect(self.add_item)
|
||||
# self.additem_button.clicked.connect(self.start_thread)
|
||||
# self.range_number.connect(self.range_thread.range_proc)
|
||||
# # self.additem_button.clicked.connect(self.range_thread.range_proc) # 连接到线程类的函数
|
||||
#
|
||||
# def start_thread(self):
|
||||
# self.thread1.start()
|
||||
# range_number = 30
|
||||
# self.range_number.emit(range_number) # 发射信号让线程接收需要range多少
|
||||
#
|
||||
# def add_item(self, requested_number): # 线程传回参数
|
||||
# text = f"第{requested_number}项————Item"
|
||||
# item = QListWidgetItem()
|
||||
# item.setIcon(QPixmap())
|
||||
# item.setText(text)
|
||||
# self.mylistwidget.addItem(item)
|
||||
#
|
||||
#
|
||||
# class WorkThread(QObject):
|
||||
# range_requested = Signal(int) # 括号里是传出的参数的类型
|
||||
#
|
||||
# def __init__(self):
|
||||
# super().__init__()
|
||||
#
|
||||
# def range_proc(self, number): # number即为从主线程接收的参数
|
||||
# print(number)
|
||||
# for i in range(number):
|
||||
# self.range_requested.emit(i) # 发射信号
|
||||
# sleep(0.5)
|
||||
#
|
||||
#
|
||||
# if __name__ == "__main__":
|
||||
# app = QApplication(sys.argv)
|
||||
# window = MyWindow()
|
||||
# window.show()
|
||||
# app.exec()
|
135
code/ui/login_window.py
Normal file
135
code/ui/login_window.py
Normal file
@ -0,0 +1,135 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'login.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.8.2
|
||||
##
|
||||
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
||||
################################################################################
|
||||
|
||||
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
|
||||
QMetaObject, QObject, QPoint, QRect,
|
||||
QSize, QTime, QUrl, Qt)
|
||||
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
|
||||
QFont, QFontDatabase, QGradient, QIcon,
|
||||
QImage, QKeySequence, QLinearGradient, QPainter,
|
||||
QPalette, QPixmap, QRadialGradient, QTransform)
|
||||
from PySide6.QtWidgets import (QApplication, QHBoxLayout, QLabel, QLineEdit,
|
||||
QPushButton, QSizePolicy, QVBoxLayout, QWidget)
|
||||
|
||||
class Ui_Form(QWidget):
|
||||
def setupUi(self, Form):
|
||||
if not Form.objectName():
|
||||
Form.setObjectName(u"Form")
|
||||
Form.setWindowModality(Qt.WindowModality.WindowModal)
|
||||
Form.resize(500, 270)
|
||||
sizePolicy = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(Form.sizePolicy().hasHeightForWidth())
|
||||
Form.setSizePolicy(sizePolicy)
|
||||
Form.setMinimumSize(QSize(500, 270))
|
||||
Form.setMaximumSize(QSize(500, 270))
|
||||
font = QFont()
|
||||
font.setFamilies([u"Consolas"])
|
||||
font.setPointSize(14)
|
||||
Form.setFont(font)
|
||||
icon = QIcon()
|
||||
icon.addFile(u"../assets/media/icon.ico", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
Form.setWindowIcon(icon)
|
||||
self.widget = QWidget(Form)
|
||||
self.widget.setObjectName(u"widget")
|
||||
self.widget.setGeometry(QRect(41, 41, 411, 211))
|
||||
self.verticalLayout = QVBoxLayout(self.widget)
|
||||
self.verticalLayout.setSpacing(2)
|
||||
self.verticalLayout.setObjectName(u"verticalLayout")
|
||||
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
|
||||
self.horizontalLayout_2 = QHBoxLayout()
|
||||
self.horizontalLayout_2.setSpacing(2)
|
||||
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
|
||||
self.label = QLabel(self.widget)
|
||||
self.label.setObjectName(u"label")
|
||||
self.label.setFont(font)
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.label)
|
||||
|
||||
self.le_username = QLineEdit(self.widget)
|
||||
self.le_username.setObjectName(u"le_username")
|
||||
self.le_username.setFont(font)
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.le_username)
|
||||
|
||||
|
||||
self.verticalLayout.addLayout(self.horizontalLayout_2)
|
||||
|
||||
self.horizontalLayout_3 = QHBoxLayout()
|
||||
self.horizontalLayout_3.setSpacing(2)
|
||||
self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
|
||||
self.label_2 = QLabel(self.widget)
|
||||
self.label_2.setObjectName(u"label_2")
|
||||
self.label_2.setFont(font)
|
||||
|
||||
self.horizontalLayout_3.addWidget(self.label_2)
|
||||
|
||||
self.le_password = QLineEdit(self.widget)
|
||||
self.le_password.setObjectName(u"le_password")
|
||||
self.le_password.setFont(font)
|
||||
self.le_password.setEchoMode(QLineEdit.EchoMode.Password)
|
||||
|
||||
self.horizontalLayout_3.addWidget(self.le_password)
|
||||
|
||||
|
||||
self.verticalLayout.addLayout(self.horizontalLayout_3)
|
||||
|
||||
self.label_hint = QLabel(self.widget)
|
||||
self.label_hint.setObjectName(u"label_hint")
|
||||
sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed)
|
||||
sizePolicy1.setHorizontalStretch(0)
|
||||
sizePolicy1.setVerticalStretch(0)
|
||||
sizePolicy1.setHeightForWidth(self.label_hint.sizePolicy().hasHeightForWidth())
|
||||
self.label_hint.setSizePolicy(sizePolicy1)
|
||||
font1 = QFont()
|
||||
font1.setFamilies([u"Consolas"])
|
||||
font1.setPointSize(12)
|
||||
self.label_hint.setFont(font1)
|
||||
|
||||
self.verticalLayout.addWidget(self.label_hint)
|
||||
|
||||
self.horizontalLayout = QHBoxLayout()
|
||||
self.horizontalLayout.setSpacing(2)
|
||||
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
||||
self.btn_login = QPushButton(self.widget)
|
||||
self.btn_login.setObjectName(u"btn_login")
|
||||
self.btn_login.setFont(font)
|
||||
|
||||
self.horizontalLayout.addWidget(self.btn_login)
|
||||
|
||||
self.btn_reset = QPushButton(self.widget)
|
||||
self.btn_reset.setObjectName(u"btn_reset")
|
||||
self.btn_reset.setFont(font)
|
||||
|
||||
self.horizontalLayout.addWidget(self.btn_reset)
|
||||
|
||||
|
||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||
|
||||
|
||||
self.retranslateUi(Form)
|
||||
self.btn_login.clicked.connect(Form.user_login)
|
||||
self.le_password.returnPressed.connect(Form.user_login)
|
||||
self.le_username.returnPressed.connect(Form.user_login)
|
||||
self.btn_reset.clicked.connect(Form.reset_password)
|
||||
|
||||
QMetaObject.connectSlotsByName(Form)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, Form):
|
||||
Form.setWindowTitle(QCoreApplication.translate("Form", u"\u767b\u5f55", None))
|
||||
self.label.setText(QCoreApplication.translate("Form", u"\u7528\u6237\u540d", None))
|
||||
self.label_2.setText(QCoreApplication.translate("Form", u"\u5bc6 \u7801", None))
|
||||
self.label_hint.setText("")
|
||||
self.btn_login.setText(QCoreApplication.translate("Form", u"\u767b\u5f55", None))
|
||||
self.btn_reset.setText(QCoreApplication.translate("Form", u"\u91cd\u7f6e", None))
|
||||
# retranslateUi
|
||||
|
954
code/ui/main_window.py
Normal file
954
code/ui/main_window.py
Normal file
@ -0,0 +1,954 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'main.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.8.2
|
||||
##
|
||||
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
||||
################################################################################
|
||||
|
||||
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
|
||||
QMetaObject, QObject, QPoint, QRect,
|
||||
QSize, QTime, QUrl, Qt)
|
||||
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
|
||||
QFont, QFontDatabase, QGradient, QIcon,
|
||||
QImage, QKeySequence, QLinearGradient, QPainter,
|
||||
QPalette, QPixmap, QRadialGradient, QTransform)
|
||||
from PySide6.QtWidgets import (QApplication, QCheckBox, QComboBox, QFormLayout,
|
||||
QFrame, QHBoxLayout, QHeaderView, QLabel,
|
||||
QLineEdit, QMainWindow, QPlainTextEdit, QPushButton,
|
||||
QScrollArea, QSizePolicy, QSpacerItem, QStackedWidget,
|
||||
QStatusBar, QTabWidget, QTreeWidget, QTreeWidgetItem,
|
||||
QVBoxLayout, QWidget)
|
||||
|
||||
class Ui_MainWindow(QMainWindow):
|
||||
def setupUi(self, MainWindow):
|
||||
if not MainWindow.objectName():
|
||||
MainWindow.setObjectName(u"MainWindow")
|
||||
MainWindow.setEnabled(True)
|
||||
MainWindow.resize(1002, 555)
|
||||
sizePolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth())
|
||||
MainWindow.setSizePolicy(sizePolicy)
|
||||
MainWindow.setMinimumSize(QSize(1000, 550))
|
||||
font = QFont()
|
||||
font.setFamilies([u"Consolas"])
|
||||
font.setPointSize(14)
|
||||
MainWindow.setFont(font)
|
||||
icon = QIcon()
|
||||
icon.addFile(u"../assets/media/icon.ico", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
MainWindow.setWindowIcon(icon)
|
||||
MainWindow.setStyleSheet(u"background-color: rgb(233, 233, 233);")
|
||||
MainWindow.setDocumentMode(False)
|
||||
self.centralwidget = QWidget(MainWindow)
|
||||
self.centralwidget.setObjectName(u"centralwidget")
|
||||
self.formLayout = QFormLayout(self.centralwidget)
|
||||
self.formLayout.setObjectName(u"formLayout")
|
||||
self.vl_1_left = QVBoxLayout()
|
||||
self.vl_1_left.setObjectName(u"vl_1_left")
|
||||
self.label = QLabel(self.centralwidget)
|
||||
self.label.setObjectName(u"label")
|
||||
sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed)
|
||||
sizePolicy1.setHorizontalStretch(0)
|
||||
sizePolicy1.setVerticalStretch(0)
|
||||
sizePolicy1.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth())
|
||||
self.label.setSizePolicy(sizePolicy1)
|
||||
self.label.setMinimumSize(QSize(200, 100))
|
||||
self.label.setMaximumSize(QSize(240, 120))
|
||||
font1 = QFont()
|
||||
font1.setFamilies([u"Segoe Print"])
|
||||
font1.setPointSize(24)
|
||||
font1.setBold(True)
|
||||
self.label.setFont(font1)
|
||||
self.label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
self.label.setMargin(0)
|
||||
|
||||
self.vl_1_left.addWidget(self.label, 0, Qt.AlignmentFlag.AlignHCenter|Qt.AlignmentFlag.AlignVCenter)
|
||||
|
||||
self.btn_start = QPushButton(self.centralwidget)
|
||||
self.btn_start.setObjectName(u"btn_start")
|
||||
sizePolicy1.setHeightForWidth(self.btn_start.sizePolicy().hasHeightForWidth())
|
||||
self.btn_start.setSizePolicy(sizePolicy1)
|
||||
self.btn_start.setMinimumSize(QSize(150, 36))
|
||||
self.btn_start.setMaximumSize(QSize(180, 45))
|
||||
font2 = QFont()
|
||||
font2.setFamilies([u"Consolas"])
|
||||
font2.setPointSize(14)
|
||||
font2.setBold(True)
|
||||
self.btn_start.setFont(font2)
|
||||
self.btn_start.setFlat(False)
|
||||
|
||||
self.vl_1_left.addWidget(self.btn_start, 0, Qt.AlignmentFlag.AlignHCenter|Qt.AlignmentFlag.AlignVCenter)
|
||||
|
||||
self.btn_stop = QPushButton(self.centralwidget)
|
||||
self.btn_stop.setObjectName(u"btn_stop")
|
||||
sizePolicy1.setHeightForWidth(self.btn_stop.sizePolicy().hasHeightForWidth())
|
||||
self.btn_stop.setSizePolicy(sizePolicy1)
|
||||
self.btn_stop.setMinimumSize(QSize(150, 36))
|
||||
self.btn_stop.setMaximumSize(QSize(180, 45))
|
||||
self.btn_stop.setFont(font2)
|
||||
self.btn_stop.setFlat(False)
|
||||
|
||||
self.vl_1_left.addWidget(self.btn_stop, 0, Qt.AlignmentFlag.AlignHCenter|Qt.AlignmentFlag.AlignVCenter)
|
||||
|
||||
self.btn_reset = QPushButton(self.centralwidget)
|
||||
self.btn_reset.setObjectName(u"btn_reset")
|
||||
sizePolicy1.setHeightForWidth(self.btn_reset.sizePolicy().hasHeightForWidth())
|
||||
self.btn_reset.setSizePolicy(sizePolicy1)
|
||||
self.btn_reset.setMinimumSize(QSize(150, 36))
|
||||
self.btn_reset.setMaximumSize(QSize(180, 45))
|
||||
self.btn_reset.setFont(font2)
|
||||
self.btn_reset.setFlat(False)
|
||||
|
||||
self.vl_1_left.addWidget(self.btn_reset, 0, Qt.AlignmentFlag.AlignHCenter|Qt.AlignmentFlag.AlignVCenter)
|
||||
|
||||
self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
|
||||
|
||||
self.vl_1_left.addItem(self.verticalSpacer)
|
||||
|
||||
self.vl_1_left.setStretch(0, 4)
|
||||
self.vl_1_left.setStretch(1, 1)
|
||||
self.vl_1_left.setStretch(2, 1)
|
||||
self.vl_1_left.setStretch(3, 1)
|
||||
self.vl_1_left.setStretch(4, 10)
|
||||
|
||||
self.formLayout.setLayout(0, QFormLayout.LabelRole, self.vl_1_left)
|
||||
|
||||
self.vl_1_right = QVBoxLayout()
|
||||
self.vl_1_right.setObjectName(u"vl_1_right")
|
||||
self.tw_funcs = QTabWidget(self.centralwidget)
|
||||
self.tw_funcs.setObjectName(u"tw_funcs")
|
||||
sizePolicy.setHeightForWidth(self.tw_funcs.sizePolicy().hasHeightForWidth())
|
||||
self.tw_funcs.setSizePolicy(sizePolicy)
|
||||
self.tw_funcs.setMinimumSize(QSize(0, 0))
|
||||
font3 = QFont()
|
||||
font3.setPointSize(14)
|
||||
font3.setBold(True)
|
||||
self.tw_funcs.setFont(font3)
|
||||
self.tw_funcs.setElideMode(Qt.TextElideMode.ElideNone)
|
||||
self.tw_funcs.setUsesScrollButtons(True)
|
||||
self.tw_funcs.setDocumentMode(True)
|
||||
self.tw_funcs.setTabsClosable(False)
|
||||
self.tw_funcs.setTabBarAutoHide(False)
|
||||
self.tab_data = QWidget()
|
||||
self.tab_data.setObjectName(u"tab_data")
|
||||
self.verticalLayout = QVBoxLayout(self.tab_data)
|
||||
self.verticalLayout.setObjectName(u"verticalLayout")
|
||||
self.horizontalLayout = QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
||||
self.cb_data_func = QComboBox(self.tab_data)
|
||||
self.cb_data_func.addItem("")
|
||||
self.cb_data_func.addItem("")
|
||||
self.cb_data_func.addItem("")
|
||||
self.cb_data_func.addItem("")
|
||||
self.cb_data_func.setObjectName(u"cb_data_func")
|
||||
self.cb_data_func.setMinimumSize(QSize(100, 0))
|
||||
font4 = QFont()
|
||||
font4.setFamilies([u"Consolas"])
|
||||
font4.setPointSize(12)
|
||||
self.cb_data_func.setFont(font4)
|
||||
|
||||
self.horizontalLayout.addWidget(self.cb_data_func)
|
||||
|
||||
self.cb_data_current = QComboBox(self.tab_data)
|
||||
self.cb_data_current.addItem("")
|
||||
self.cb_data_current.addItem("")
|
||||
self.cb_data_current.addItem("")
|
||||
self.cb_data_current.setObjectName(u"cb_data_current")
|
||||
self.cb_data_current.setMinimumSize(QSize(100, 0))
|
||||
self.cb_data_current.setFont(font4)
|
||||
|
||||
self.horizontalLayout.addWidget(self.cb_data_current)
|
||||
|
||||
self.label_4 = QLabel(self.tab_data)
|
||||
self.label_4.setObjectName(u"label_4")
|
||||
self.label_4.setFont(font4)
|
||||
self.label_4.setAlignment(Qt.AlignmentFlag.AlignRight|Qt.AlignmentFlag.AlignTrailing|Qt.AlignmentFlag.AlignVCenter)
|
||||
|
||||
self.horizontalLayout.addWidget(self.label_4)
|
||||
|
||||
self.le_data_path = QLineEdit(self.tab_data)
|
||||
self.le_data_path.setObjectName(u"le_data_path")
|
||||
self.le_data_path.setFont(font4)
|
||||
self.le_data_path.setAlignment(Qt.AlignmentFlag.AlignLeading|Qt.AlignmentFlag.AlignLeft|Qt.AlignmentFlag.AlignVCenter)
|
||||
|
||||
self.horizontalLayout.addWidget(self.le_data_path)
|
||||
|
||||
self.btn_data_open = QPushButton(self.tab_data)
|
||||
self.btn_data_open.setObjectName(u"btn_data_open")
|
||||
self.btn_data_open.setMaximumSize(QSize(30, 16777215))
|
||||
self.btn_data_open.setFont(font4)
|
||||
|
||||
self.horizontalLayout.addWidget(self.btn_data_open)
|
||||
|
||||
self.horizontalLayout.setStretch(0, 1)
|
||||
self.horizontalLayout.setStretch(1, 1)
|
||||
self.horizontalLayout.setStretch(2, 1)
|
||||
self.horizontalLayout.setStretch(3, 10)
|
||||
self.horizontalLayout.setStretch(4, 1)
|
||||
|
||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||
|
||||
self.verticalSpacer_2 = QSpacerItem(20, 161, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
|
||||
|
||||
self.verticalLayout.addItem(self.verticalSpacer_2)
|
||||
|
||||
self.tw_funcs.addTab(self.tab_data, "")
|
||||
self.tab_unit = QWidget()
|
||||
self.tab_unit.setObjectName(u"tab_unit")
|
||||
self.verticalLayout_2 = QVBoxLayout(self.tab_unit)
|
||||
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
|
||||
self.hl_2_unit1 = QHBoxLayout()
|
||||
self.hl_2_unit1.setObjectName(u"hl_2_unit1")
|
||||
self.cb_unit_func = QComboBox(self.tab_unit)
|
||||
self.cb_unit_func.addItem("")
|
||||
self.cb_unit_func.addItem("")
|
||||
self.cb_unit_func.setObjectName(u"cb_unit_func")
|
||||
self.cb_unit_func.setMinimumSize(QSize(100, 0))
|
||||
self.cb_unit_func.setFont(font4)
|
||||
|
||||
self.hl_2_unit1.addWidget(self.cb_unit_func)
|
||||
|
||||
self.cb_unit_tool = QComboBox(self.tab_unit)
|
||||
self.cb_unit_tool.addItem("")
|
||||
self.cb_unit_tool.addItem("")
|
||||
self.cb_unit_tool.addItem("")
|
||||
self.cb_unit_tool.addItem("")
|
||||
self.cb_unit_tool.setObjectName(u"cb_unit_tool")
|
||||
self.cb_unit_tool.setMinimumSize(QSize(100, 0))
|
||||
self.cb_unit_tool.setFont(font4)
|
||||
|
||||
self.hl_2_unit1.addWidget(self.cb_unit_tool)
|
||||
|
||||
self.label_6 = QLabel(self.tab_unit)
|
||||
self.label_6.setObjectName(u"label_6")
|
||||
sizePolicy1.setHeightForWidth(self.label_6.sizePolicy().hasHeightForWidth())
|
||||
self.label_6.setSizePolicy(sizePolicy1)
|
||||
self.label_6.setFont(font4)
|
||||
self.label_6.setAlignment(Qt.AlignmentFlag.AlignRight|Qt.AlignmentFlag.AlignTrailing|Qt.AlignmentFlag.AlignVCenter)
|
||||
|
||||
self.hl_2_unit1.addWidget(self.label_6)
|
||||
|
||||
self.le_unit_path = QLineEdit(self.tab_unit)
|
||||
self.le_unit_path.setObjectName(u"le_unit_path")
|
||||
self.le_unit_path.setFont(font4)
|
||||
|
||||
self.hl_2_unit1.addWidget(self.le_unit_path)
|
||||
|
||||
self.btn_unit_open = QPushButton(self.tab_unit)
|
||||
self.btn_unit_open.setObjectName(u"btn_unit_open")
|
||||
self.btn_unit_open.setMaximumSize(QSize(30, 16777215))
|
||||
self.btn_unit_open.setFont(font4)
|
||||
|
||||
self.hl_2_unit1.addWidget(self.btn_unit_open)
|
||||
|
||||
self.hl_2_unit1.setStretch(0, 1)
|
||||
self.hl_2_unit1.setStretch(1, 1)
|
||||
self.hl_2_unit1.setStretch(2, 1)
|
||||
self.hl_2_unit1.setStretch(3, 10)
|
||||
self.hl_2_unit1.setStretch(4, 1)
|
||||
|
||||
self.verticalLayout_2.addLayout(self.hl_2_unit1)
|
||||
|
||||
self.verticalSpacer_3 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
|
||||
|
||||
self.verticalLayout_2.addItem(self.verticalSpacer_3)
|
||||
|
||||
self.tw_funcs.addTab(self.tab_unit, "")
|
||||
self.tab_durable = QWidget()
|
||||
self.tab_durable.setObjectName(u"tab_durable")
|
||||
self.horizontalLayout_11 = QHBoxLayout(self.tab_durable)
|
||||
self.horizontalLayout_11.setObjectName(u"horizontalLayout_11")
|
||||
self.horizontalLayout_10 = QHBoxLayout()
|
||||
self.horizontalLayout_10.setObjectName(u"horizontalLayout_10")
|
||||
self.verticalLayout_9 = QVBoxLayout()
|
||||
self.verticalLayout_9.setObjectName(u"verticalLayout_9")
|
||||
self.frame = QFrame(self.tab_durable)
|
||||
self.frame.setObjectName(u"frame")
|
||||
self.frame.setMinimumSize(QSize(200, 0))
|
||||
self.frame.setMaximumSize(QSize(300, 16777215))
|
||||
self.frame.setFrameShape(QFrame.Shape.StyledPanel)
|
||||
self.frame.setFrameShadow(QFrame.Shadow.Raised)
|
||||
self.verticalLayout_8 = QVBoxLayout(self.frame)
|
||||
self.verticalLayout_8.setObjectName(u"verticalLayout_8")
|
||||
self.verticalLayout_7 = QVBoxLayout()
|
||||
self.verticalLayout_7.setObjectName(u"verticalLayout_7")
|
||||
self.label_11 = QLabel(self.frame)
|
||||
self.label_11.setObjectName(u"label_11")
|
||||
sizePolicy1.setHeightForWidth(self.label_11.sizePolicy().hasHeightForWidth())
|
||||
self.label_11.setSizePolicy(sizePolicy1)
|
||||
self.label_11.setFont(font2)
|
||||
self.label_11.setAlignment(Qt.AlignmentFlag.AlignLeading|Qt.AlignmentFlag.AlignLeft|Qt.AlignmentFlag.AlignVCenter)
|
||||
|
||||
self.verticalLayout_7.addWidget(self.label_11)
|
||||
|
||||
self.scrollArea = QScrollArea(self.frame)
|
||||
self.scrollArea.setObjectName(u"scrollArea")
|
||||
self.scrollArea.setWidgetResizable(True)
|
||||
self.scrollAreaWidgetContents = QWidget()
|
||||
self.scrollAreaWidgetContents.setObjectName(u"scrollAreaWidgetContents")
|
||||
self.scrollAreaWidgetContents.setGeometry(QRect(0, 0, 211, 78))
|
||||
self.horizontalLayout_9 = QHBoxLayout(self.scrollAreaWidgetContents)
|
||||
self.horizontalLayout_9.setObjectName(u"horizontalLayout_9")
|
||||
self.verticalLayout_5 = QVBoxLayout()
|
||||
self.verticalLayout_5.setObjectName(u"verticalLayout_5")
|
||||
self.cb_1 = QCheckBox(self.scrollAreaWidgetContents)
|
||||
self.cb_1.setObjectName(u"cb_1")
|
||||
self.cb_1.setFont(font4)
|
||||
|
||||
self.verticalLayout_5.addWidget(self.cb_1)
|
||||
|
||||
self.cb_2 = QCheckBox(self.scrollAreaWidgetContents)
|
||||
self.cb_2.setObjectName(u"cb_2")
|
||||
self.cb_2.setFont(font4)
|
||||
|
||||
self.verticalLayout_5.addWidget(self.cb_2)
|
||||
|
||||
self.verticalSpacer_5 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
|
||||
|
||||
self.verticalLayout_5.addItem(self.verticalSpacer_5)
|
||||
|
||||
|
||||
self.horizontalLayout_9.addLayout(self.verticalLayout_5)
|
||||
|
||||
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
|
||||
|
||||
self.verticalLayout_7.addWidget(self.scrollArea)
|
||||
|
||||
|
||||
self.verticalLayout_8.addLayout(self.verticalLayout_7)
|
||||
|
||||
|
||||
self.verticalLayout_9.addWidget(self.frame)
|
||||
|
||||
|
||||
self.horizontalLayout_10.addLayout(self.verticalLayout_9)
|
||||
|
||||
self.verticalLayout_6 = QVBoxLayout()
|
||||
self.verticalLayout_6.setObjectName(u"verticalLayout_6")
|
||||
self.horizontalLayout_6 = QHBoxLayout()
|
||||
self.horizontalLayout_6.setObjectName(u"horizontalLayout_6")
|
||||
self.label_8 = QLabel(self.tab_durable)
|
||||
self.label_8.setObjectName(u"label_8")
|
||||
sizePolicy1.setHeightForWidth(self.label_8.sizePolicy().hasHeightForWidth())
|
||||
self.label_8.setSizePolicy(sizePolicy1)
|
||||
self.label_8.setFont(font4)
|
||||
self.label_8.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
|
||||
self.horizontalLayout_6.addWidget(self.label_8)
|
||||
|
||||
self.le_durable_path = QLineEdit(self.tab_durable)
|
||||
self.le_durable_path.setObjectName(u"le_durable_path")
|
||||
self.le_durable_path.setFont(font4)
|
||||
|
||||
self.horizontalLayout_6.addWidget(self.le_durable_path)
|
||||
|
||||
self.btn_durable_open = QPushButton(self.tab_durable)
|
||||
self.btn_durable_open.setObjectName(u"btn_durable_open")
|
||||
self.btn_durable_open.setMaximumSize(QSize(30, 16777215))
|
||||
self.btn_durable_open.setFont(font4)
|
||||
|
||||
self.horizontalLayout_6.addWidget(self.btn_durable_open)
|
||||
|
||||
|
||||
self.verticalLayout_6.addLayout(self.horizontalLayout_6)
|
||||
|
||||
self.horizontalLayout_7 = QHBoxLayout()
|
||||
self.horizontalLayout_7.setObjectName(u"horizontalLayout_7")
|
||||
self.label_9 = QLabel(self.tab_durable)
|
||||
self.label_9.setObjectName(u"label_9")
|
||||
sizePolicy1.setHeightForWidth(self.label_9.sizePolicy().hasHeightForWidth())
|
||||
self.label_9.setSizePolicy(sizePolicy1)
|
||||
self.label_9.setFont(font4)
|
||||
self.label_9.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
|
||||
self.horizontalLayout_7.addWidget(self.label_9)
|
||||
|
||||
self.le_durable_interval = QLineEdit(self.tab_durable)
|
||||
self.le_durable_interval.setObjectName(u"le_durable_interval")
|
||||
self.le_durable_interval.setFont(font4)
|
||||
self.le_durable_interval.setInputMethodHints(Qt.InputMethodHint.ImhNone)
|
||||
|
||||
self.horizontalLayout_7.addWidget(self.le_durable_interval)
|
||||
|
||||
self.label_10 = QLabel(self.tab_durable)
|
||||
self.label_10.setObjectName(u"label_10")
|
||||
sizePolicy2 = QSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Preferred)
|
||||
sizePolicy2.setHorizontalStretch(0)
|
||||
sizePolicy2.setVerticalStretch(0)
|
||||
sizePolicy2.setHeightForWidth(self.label_10.sizePolicy().hasHeightForWidth())
|
||||
self.label_10.setSizePolicy(sizePolicy2)
|
||||
self.label_10.setMinimumSize(QSize(30, 0))
|
||||
|
||||
self.horizontalLayout_7.addWidget(self.label_10)
|
||||
|
||||
|
||||
self.verticalLayout_6.addLayout(self.horizontalLayout_7)
|
||||
|
||||
self.horizontalLayout_8 = QHBoxLayout()
|
||||
self.horizontalLayout_8.setObjectName(u"horizontalLayout_8")
|
||||
self.cb_durable_total = QCheckBox(self.tab_durable)
|
||||
self.cb_durable_total.setObjectName(u"cb_durable_total")
|
||||
font5 = QFont()
|
||||
font5.setFamilies([u"Consolas"])
|
||||
font5.setPointSize(12)
|
||||
font5.setBold(True)
|
||||
self.cb_durable_total.setFont(font5)
|
||||
|
||||
self.horizontalLayout_8.addWidget(self.cb_durable_total)
|
||||
|
||||
self.btn_draw = QPushButton(self.tab_durable)
|
||||
self.btn_draw.setObjectName(u"btn_draw")
|
||||
self.btn_draw.setFont(font5)
|
||||
|
||||
self.horizontalLayout_8.addWidget(self.btn_draw)
|
||||
|
||||
self.label_3 = QLabel(self.tab_durable)
|
||||
self.label_3.setObjectName(u"label_3")
|
||||
|
||||
self.horizontalLayout_8.addWidget(self.label_3)
|
||||
|
||||
self.horizontalLayout_8.setStretch(0, 2)
|
||||
self.horizontalLayout_8.setStretch(2, 8)
|
||||
|
||||
self.verticalLayout_6.addLayout(self.horizontalLayout_8)
|
||||
|
||||
self.verticalSpacer_4 = QSpacerItem(20, 40, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding)
|
||||
|
||||
self.verticalLayout_6.addItem(self.verticalSpacer_4)
|
||||
|
||||
|
||||
self.horizontalLayout_10.addLayout(self.verticalLayout_6)
|
||||
|
||||
self.horizontalLayout_10.setStretch(0, 1)
|
||||
self.horizontalLayout_10.setStretch(1, 2)
|
||||
|
||||
self.horizontalLayout_11.addLayout(self.horizontalLayout_10)
|
||||
|
||||
self.tw_funcs.addTab(self.tab_durable, "")
|
||||
self.tab_network = QWidget()
|
||||
self.tab_network.setObjectName(u"tab_network")
|
||||
self.horizontalLayout_13 = QHBoxLayout(self.tab_network)
|
||||
self.horizontalLayout_13.setObjectName(u"horizontalLayout_13")
|
||||
self.horizontalLayout_12 = QHBoxLayout()
|
||||
self.horizontalLayout_12.setObjectName(u"horizontalLayout_12")
|
||||
self.sw_network = QStackedWidget(self.tab_network)
|
||||
self.sw_network.setObjectName(u"sw_network")
|
||||
self.page = QWidget()
|
||||
self.page.setObjectName(u"page")
|
||||
self.horizontalLayout_14 = QHBoxLayout(self.page)
|
||||
self.horizontalLayout_14.setObjectName(u"horizontalLayout_14")
|
||||
self.verticalLayout_10 = QVBoxLayout()
|
||||
self.verticalLayout_10.setObjectName(u"verticalLayout_10")
|
||||
self.horizontalLayout_3 = QHBoxLayout()
|
||||
self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
|
||||
self.label_2 = QLabel(self.page)
|
||||
self.label_2.setObjectName(u"label_2")
|
||||
sizePolicy1.setHeightForWidth(self.label_2.sizePolicy().hasHeightForWidth())
|
||||
self.label_2.setSizePolicy(sizePolicy1)
|
||||
self.label_2.setMinimumSize(QSize(70, 0))
|
||||
self.label_2.setFont(font5)
|
||||
self.label_2.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
|
||||
self.horizontalLayout_3.addWidget(self.label_2)
|
||||
|
||||
self.le_hmi_ip = QLineEdit(self.page)
|
||||
self.le_hmi_ip.setObjectName(u"le_hmi_ip")
|
||||
self.le_hmi_ip.setMinimumSize(QSize(150, 0))
|
||||
self.le_hmi_ip.setFont(font4)
|
||||
|
||||
self.horizontalLayout_3.addWidget(self.le_hmi_ip)
|
||||
|
||||
self.btn_hmi_conn = QPushButton(self.page)
|
||||
self.btn_hmi_conn.setObjectName(u"btn_hmi_conn")
|
||||
self.btn_hmi_conn.setFont(font5)
|
||||
|
||||
self.horizontalLayout_3.addWidget(self.btn_hmi_conn)
|
||||
|
||||
self.label_5 = QLabel(self.page)
|
||||
self.label_5.setObjectName(u"label_5")
|
||||
self.label_5.setFont(font4)
|
||||
|
||||
self.horizontalLayout_3.addWidget(self.label_5)
|
||||
|
||||
self.cb_hmi_cmd = QComboBox(self.page)
|
||||
self.cb_hmi_cmd.addItem("")
|
||||
self.cb_hmi_cmd.addItem("")
|
||||
self.cb_hmi_cmd.addItem("")
|
||||
self.cb_hmi_cmd.setObjectName(u"cb_hmi_cmd")
|
||||
self.cb_hmi_cmd.setMinimumSize(QSize(240, 0))
|
||||
self.cb_hmi_cmd.setFont(font4)
|
||||
|
||||
self.horizontalLayout_3.addWidget(self.cb_hmi_cmd)
|
||||
|
||||
self.btn_hmi_send = QPushButton(self.page)
|
||||
self.btn_hmi_send.setObjectName(u"btn_hmi_send")
|
||||
self.btn_hmi_send.setFont(font5)
|
||||
|
||||
self.horizontalLayout_3.addWidget(self.btn_hmi_send)
|
||||
|
||||
self.horizontalLayout_3.setStretch(0, 1)
|
||||
self.horizontalLayout_3.setStretch(1, 4)
|
||||
self.horizontalLayout_3.setStretch(2, 1)
|
||||
self.horizontalLayout_3.setStretch(3, 4)
|
||||
self.horizontalLayout_3.setStretch(4, 8)
|
||||
self.horizontalLayout_3.setStretch(5, 1)
|
||||
|
||||
self.verticalLayout_10.addLayout(self.horizontalLayout_3)
|
||||
|
||||
self.horizontalLayout_5 = QHBoxLayout()
|
||||
self.horizontalLayout_5.setObjectName(u"horizontalLayout_5")
|
||||
self.pte_hmi_send = QPlainTextEdit(self.page)
|
||||
self.pte_hmi_send.setObjectName(u"pte_hmi_send")
|
||||
|
||||
self.horizontalLayout_5.addWidget(self.pte_hmi_send)
|
||||
|
||||
self.pte_him_recv = QPlainTextEdit(self.page)
|
||||
self.pte_him_recv.setObjectName(u"pte_him_recv")
|
||||
|
||||
self.horizontalLayout_5.addWidget(self.pte_him_recv)
|
||||
|
||||
|
||||
self.verticalLayout_10.addLayout(self.horizontalLayout_5)
|
||||
|
||||
|
||||
self.horizontalLayout_14.addLayout(self.verticalLayout_10)
|
||||
|
||||
self.sw_network.addWidget(self.page)
|
||||
self.page_2 = QWidget()
|
||||
self.page_2.setObjectName(u"page_2")
|
||||
self.horizontalLayout_17 = QHBoxLayout(self.page_2)
|
||||
self.horizontalLayout_17.setObjectName(u"horizontalLayout_17")
|
||||
self.verticalLayout_11 = QVBoxLayout()
|
||||
self.verticalLayout_11.setObjectName(u"verticalLayout_11")
|
||||
self.horizontalLayout_15 = QHBoxLayout()
|
||||
self.horizontalLayout_15.setObjectName(u"horizontalLayout_15")
|
||||
self.label_7 = QLabel(self.page_2)
|
||||
self.label_7.setObjectName(u"label_7")
|
||||
sizePolicy1.setHeightForWidth(self.label_7.sizePolicy().hasHeightForWidth())
|
||||
self.label_7.setSizePolicy(sizePolicy1)
|
||||
self.label_7.setMinimumSize(QSize(70, 0))
|
||||
self.label_7.setFont(font5)
|
||||
self.label_7.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
|
||||
self.horizontalLayout_15.addWidget(self.label_7)
|
||||
|
||||
self.le_md_port = QLineEdit(self.page_2)
|
||||
self.le_md_port.setObjectName(u"le_md_port")
|
||||
self.le_md_port.setMinimumSize(QSize(150, 0))
|
||||
self.le_md_port.setFont(font4)
|
||||
|
||||
self.horizontalLayout_15.addWidget(self.le_md_port)
|
||||
|
||||
self.btn_md_conn = QPushButton(self.page_2)
|
||||
self.btn_md_conn.setObjectName(u"btn_md_conn")
|
||||
self.btn_md_conn.setFont(font5)
|
||||
|
||||
self.horizontalLayout_15.addWidget(self.btn_md_conn)
|
||||
|
||||
self.label_12 = QLabel(self.page_2)
|
||||
self.label_12.setObjectName(u"label_12")
|
||||
self.label_12.setFont(font4)
|
||||
|
||||
self.horizontalLayout_15.addWidget(self.label_12)
|
||||
|
||||
self.cb_md_cmd = QComboBox(self.page_2)
|
||||
self.cb_md_cmd.addItem("")
|
||||
self.cb_md_cmd.addItem("")
|
||||
self.cb_md_cmd.setObjectName(u"cb_md_cmd")
|
||||
self.cb_md_cmd.setMinimumSize(QSize(240, 0))
|
||||
self.cb_md_cmd.setFont(font4)
|
||||
|
||||
self.horizontalLayout_15.addWidget(self.cb_md_cmd)
|
||||
|
||||
self.btn_md_send = QPushButton(self.page_2)
|
||||
self.btn_md_send.setObjectName(u"btn_md_send")
|
||||
self.btn_md_send.setFont(font5)
|
||||
|
||||
self.horizontalLayout_15.addWidget(self.btn_md_send)
|
||||
|
||||
self.horizontalLayout_15.setStretch(0, 1)
|
||||
self.horizontalLayout_15.setStretch(1, 4)
|
||||
self.horizontalLayout_15.setStretch(2, 1)
|
||||
self.horizontalLayout_15.setStretch(3, 4)
|
||||
self.horizontalLayout_15.setStretch(4, 8)
|
||||
self.horizontalLayout_15.setStretch(5, 1)
|
||||
|
||||
self.verticalLayout_11.addLayout(self.horizontalLayout_15)
|
||||
|
||||
self.horizontalLayout_16 = QHBoxLayout()
|
||||
self.horizontalLayout_16.setObjectName(u"horizontalLayout_16")
|
||||
self.pte_md_send = QPlainTextEdit(self.page_2)
|
||||
self.pte_md_send.setObjectName(u"pte_md_send")
|
||||
|
||||
self.horizontalLayout_16.addWidget(self.pte_md_send)
|
||||
|
||||
self.pte_md_recv = QPlainTextEdit(self.page_2)
|
||||
self.pte_md_recv.setObjectName(u"pte_md_recv")
|
||||
|
||||
self.horizontalLayout_16.addWidget(self.pte_md_recv)
|
||||
|
||||
|
||||
self.verticalLayout_11.addLayout(self.horizontalLayout_16)
|
||||
|
||||
|
||||
self.horizontalLayout_17.addLayout(self.verticalLayout_11)
|
||||
|
||||
self.sw_network.addWidget(self.page_2)
|
||||
self.page_3 = QWidget()
|
||||
self.page_3.setObjectName(u"page_3")
|
||||
self.horizontalLayout_26 = QHBoxLayout(self.page_3)
|
||||
self.horizontalLayout_26.setObjectName(u"horizontalLayout_26")
|
||||
self.verticalLayout_14 = QVBoxLayout()
|
||||
self.verticalLayout_14.setObjectName(u"verticalLayout_14")
|
||||
self.horizontalLayout_24 = QHBoxLayout()
|
||||
self.horizontalLayout_24.setObjectName(u"horizontalLayout_24")
|
||||
self.label_17 = QLabel(self.page_3)
|
||||
self.label_17.setObjectName(u"label_17")
|
||||
sizePolicy1.setHeightForWidth(self.label_17.sizePolicy().hasHeightForWidth())
|
||||
self.label_17.setSizePolicy(sizePolicy1)
|
||||
self.label_17.setMinimumSize(QSize(70, 0))
|
||||
self.label_17.setFont(font5)
|
||||
self.label_17.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
|
||||
self.horizontalLayout_24.addWidget(self.label_17)
|
||||
|
||||
self.le_ec_port = QLineEdit(self.page_3)
|
||||
self.le_ec_port.setObjectName(u"le_ec_port")
|
||||
self.le_ec_port.setMinimumSize(QSize(150, 0))
|
||||
self.le_ec_port.setFont(font4)
|
||||
|
||||
self.horizontalLayout_24.addWidget(self.le_ec_port)
|
||||
|
||||
self.btn_ec_conn = QPushButton(self.page_3)
|
||||
self.btn_ec_conn.setObjectName(u"btn_ec_conn")
|
||||
self.btn_ec_conn.setFont(font5)
|
||||
|
||||
self.horizontalLayout_24.addWidget(self.btn_ec_conn)
|
||||
|
||||
self.label_18 = QLabel(self.page_3)
|
||||
self.label_18.setObjectName(u"label_18")
|
||||
self.label_18.setFont(font4)
|
||||
|
||||
self.horizontalLayout_24.addWidget(self.label_18)
|
||||
|
||||
self.cb_ec_cmd = QComboBox(self.page_3)
|
||||
self.cb_ec_cmd.addItem("")
|
||||
self.cb_ec_cmd.addItem("")
|
||||
self.cb_ec_cmd.setObjectName(u"cb_ec_cmd")
|
||||
self.cb_ec_cmd.setMinimumSize(QSize(240, 0))
|
||||
self.cb_ec_cmd.setFont(font4)
|
||||
|
||||
self.horizontalLayout_24.addWidget(self.cb_ec_cmd)
|
||||
|
||||
self.btn_ec_send = QPushButton(self.page_3)
|
||||
self.btn_ec_send.setObjectName(u"btn_ec_send")
|
||||
self.btn_ec_send.setFont(font5)
|
||||
|
||||
self.horizontalLayout_24.addWidget(self.btn_ec_send)
|
||||
|
||||
self.horizontalLayout_24.setStretch(0, 1)
|
||||
self.horizontalLayout_24.setStretch(1, 4)
|
||||
self.horizontalLayout_24.setStretch(2, 1)
|
||||
self.horizontalLayout_24.setStretch(3, 4)
|
||||
self.horizontalLayout_24.setStretch(4, 8)
|
||||
self.horizontalLayout_24.setStretch(5, 1)
|
||||
|
||||
self.verticalLayout_14.addLayout(self.horizontalLayout_24)
|
||||
|
||||
self.horizontalLayout_25 = QHBoxLayout()
|
||||
self.horizontalLayout_25.setObjectName(u"horizontalLayout_25")
|
||||
self.pte_ec_send = QPlainTextEdit(self.page_3)
|
||||
self.pte_ec_send.setObjectName(u"pte_ec_send")
|
||||
|
||||
self.horizontalLayout_25.addWidget(self.pte_ec_send)
|
||||
|
||||
self.pte_ec_recv = QPlainTextEdit(self.page_3)
|
||||
self.pte_ec_recv.setObjectName(u"pte_ec_recv")
|
||||
|
||||
self.horizontalLayout_25.addWidget(self.pte_ec_recv)
|
||||
|
||||
|
||||
self.verticalLayout_14.addLayout(self.horizontalLayout_25)
|
||||
|
||||
|
||||
self.horizontalLayout_26.addLayout(self.verticalLayout_14)
|
||||
|
||||
self.sw_network.addWidget(self.page_3)
|
||||
|
||||
self.horizontalLayout_12.addWidget(self.sw_network)
|
||||
|
||||
self.verticalLayout_4 = QVBoxLayout()
|
||||
self.verticalLayout_4.setObjectName(u"verticalLayout_4")
|
||||
self.pushButton = QPushButton(self.tab_network)
|
||||
self.pushButton.setObjectName(u"pushButton")
|
||||
self.pushButton.setFont(font5)
|
||||
|
||||
self.verticalLayout_4.addWidget(self.pushButton)
|
||||
|
||||
self.pushButton_2 = QPushButton(self.tab_network)
|
||||
self.pushButton_2.setObjectName(u"pushButton_2")
|
||||
self.pushButton_2.setFont(font5)
|
||||
|
||||
self.verticalLayout_4.addWidget(self.pushButton_2)
|
||||
|
||||
self.pushButton_3 = QPushButton(self.tab_network)
|
||||
self.pushButton_3.setObjectName(u"pushButton_3")
|
||||
self.pushButton_3.setFont(font5)
|
||||
|
||||
self.verticalLayout_4.addWidget(self.pushButton_3)
|
||||
|
||||
|
||||
self.horizontalLayout_12.addLayout(self.verticalLayout_4)
|
||||
|
||||
self.horizontalLayout_12.setStretch(0, 11)
|
||||
self.horizontalLayout_12.setStretch(1, 1)
|
||||
|
||||
self.horizontalLayout_13.addLayout(self.horizontalLayout_12)
|
||||
|
||||
self.tw_funcs.addTab(self.tab_network, "")
|
||||
|
||||
self.vl_1_right.addWidget(self.tw_funcs)
|
||||
|
||||
self.tw_docs = QTabWidget(self.centralwidget)
|
||||
self.tw_docs.setObjectName(u"tw_docs")
|
||||
self.tw_docs.setFont(font3)
|
||||
self.tw_docs.setElideMode(Qt.TextElideMode.ElideNone)
|
||||
self.tw_docs.setDocumentMode(True)
|
||||
self.tab_output = QWidget()
|
||||
self.tab_output.setObjectName(u"tab_output")
|
||||
self.horizontalLayout_4 = QHBoxLayout(self.tab_output)
|
||||
self.horizontalLayout_4.setObjectName(u"horizontalLayout_4")
|
||||
self.pte_output = QPlainTextEdit(self.tab_output)
|
||||
self.pte_output.setObjectName(u"pte_output")
|
||||
self.pte_output.setFont(font4)
|
||||
self.pte_output.setLineWrapMode(QPlainTextEdit.LineWrapMode.WidgetWidth)
|
||||
self.pte_output.setReadOnly(True)
|
||||
|
||||
self.horizontalLayout_4.addWidget(self.pte_output)
|
||||
|
||||
self.tw_docs.addTab(self.tab_output, "")
|
||||
self.tab_log = QWidget()
|
||||
self.tab_log.setObjectName(u"tab_log")
|
||||
self.verticalLayout_3 = QVBoxLayout(self.tab_log)
|
||||
self.verticalLayout_3.setObjectName(u"verticalLayout_3")
|
||||
self.treew_log = QTreeWidget(self.tab_log)
|
||||
self.treew_log.setObjectName(u"treew_log")
|
||||
self.treew_log.setFont(font4)
|
||||
self.treew_log.header().setVisible(True)
|
||||
|
||||
self.verticalLayout_3.addWidget(self.treew_log)
|
||||
|
||||
self.horizontalLayout_2 = QHBoxLayout()
|
||||
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
|
||||
self.label_page = QLabel(self.tab_log)
|
||||
self.label_page.setObjectName(u"label_page")
|
||||
self.label_page.setMinimumSize(QSize(100, 0))
|
||||
font6 = QFont()
|
||||
font6.setFamilies([u"Consolas"])
|
||||
font6.setPointSize(10)
|
||||
font6.setBold(True)
|
||||
self.label_page.setFont(font6)
|
||||
self.label_page.setStyleSheet(u"background-color: rgb(222, 222, 222);")
|
||||
self.label_page.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.label_page)
|
||||
|
||||
self.btn_docs_previous = QPushButton(self.tab_log)
|
||||
self.btn_docs_previous.setObjectName(u"btn_docs_previous")
|
||||
self.btn_docs_previous.setFont(font4)
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.btn_docs_previous)
|
||||
|
||||
self.btn_docs_realtime = QPushButton(self.tab_log)
|
||||
self.btn_docs_realtime.setObjectName(u"btn_docs_realtime")
|
||||
self.btn_docs_realtime.setFont(font4)
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.btn_docs_realtime)
|
||||
|
||||
self.btn_docs_next = QPushButton(self.tab_log)
|
||||
self.btn_docs_next.setObjectName(u"btn_docs_next")
|
||||
self.btn_docs_next.setFont(font4)
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.btn_docs_next)
|
||||
|
||||
self.btn_docs_load = QPushButton(self.tab_log)
|
||||
self.btn_docs_load.setObjectName(u"btn_docs_load")
|
||||
self.btn_docs_load.setFont(font4)
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.btn_docs_load)
|
||||
|
||||
self.btn_docs_search = QPushButton(self.tab_log)
|
||||
self.btn_docs_search.setObjectName(u"btn_docs_search")
|
||||
self.btn_docs_search.setFont(font4)
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.btn_docs_search)
|
||||
|
||||
self.le_docs_search = QLineEdit(self.tab_log)
|
||||
self.le_docs_search.setObjectName(u"le_docs_search")
|
||||
self.le_docs_search.setFont(font4)
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.le_docs_search)
|
||||
|
||||
self.horizontalLayout_2.setStretch(0, 1)
|
||||
self.horizontalLayout_2.setStretch(1, 1)
|
||||
self.horizontalLayout_2.setStretch(2, 1)
|
||||
self.horizontalLayout_2.setStretch(3, 1)
|
||||
self.horizontalLayout_2.setStretch(4, 1)
|
||||
self.horizontalLayout_2.setStretch(5, 1)
|
||||
self.horizontalLayout_2.setStretch(6, 10)
|
||||
|
||||
self.verticalLayout_3.addLayout(self.horizontalLayout_2)
|
||||
|
||||
self.tw_docs.addTab(self.tab_log, "")
|
||||
|
||||
self.vl_1_right.addWidget(self.tw_docs)
|
||||
|
||||
self.vl_1_right.setStretch(0, 1)
|
||||
self.vl_1_right.setStretch(1, 3)
|
||||
|
||||
self.formLayout.setLayout(0, QFormLayout.FieldRole, self.vl_1_right)
|
||||
|
||||
MainWindow.setCentralWidget(self.centralwidget)
|
||||
self.statusbar = QStatusBar(MainWindow)
|
||||
self.statusbar.setObjectName(u"statusbar")
|
||||
sizePolicy3 = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
||||
sizePolicy3.setHorizontalStretch(0)
|
||||
sizePolicy3.setVerticalStretch(0)
|
||||
sizePolicy3.setHeightForWidth(self.statusbar.sizePolicy().hasHeightForWidth())
|
||||
self.statusbar.setSizePolicy(sizePolicy3)
|
||||
self.statusbar.setMinimumSize(QSize(0, 27))
|
||||
self.statusbar.setStyleSheet(u"background-color: rgb(200, 200, 200);")
|
||||
MainWindow.setStatusBar(self.statusbar)
|
||||
|
||||
self.retranslateUi(MainWindow)
|
||||
self.btn_start.clicked.connect(MainWindow.prog_start)
|
||||
self.btn_stop.clicked.connect(MainWindow.prog_stop)
|
||||
self.btn_reset.clicked.connect(MainWindow.prog_reset)
|
||||
self.btn_durable_open.clicked.connect(MainWindow.file_browser)
|
||||
self.btn_draw.clicked.connect(MainWindow.curve_draw)
|
||||
self.cb_durable_total.checkStateChanged.connect(MainWindow.durable_cb_change)
|
||||
self.btn_unit_open.clicked.connect(MainWindow.file_browser)
|
||||
self.btn_data_open.clicked.connect(MainWindow.file_browser)
|
||||
self.btn_docs_previous.clicked.connect(MainWindow.pre_page)
|
||||
self.btn_docs_realtime.clicked.connect(MainWindow.realtime_page)
|
||||
self.btn_docs_next.clicked.connect(MainWindow.next_page)
|
||||
self.btn_docs_load.clicked.connect(MainWindow.load_sql)
|
||||
self.btn_docs_search.clicked.connect(MainWindow.search_keyword)
|
||||
self.le_docs_search.returnPressed.connect(MainWindow.search_keyword)
|
||||
self.cb_hmi_cmd.currentTextChanged.connect(MainWindow.hmi_cb_change)
|
||||
self.btn_hmi_send.clicked.connect(MainWindow.hmi_send)
|
||||
self.pushButton.clicked.connect(MainWindow.hmi_page)
|
||||
self.pushButton_2.clicked.connect(MainWindow.md_page)
|
||||
self.pushButton_3.clicked.connect(MainWindow.ec_page)
|
||||
self.cb_md_cmd.currentTextChanged.connect(MainWindow.md_cb_change)
|
||||
self.btn_md_send.clicked.connect(MainWindow.md_send)
|
||||
self.btn_ec_send.clicked.connect(MainWindow.ec_send)
|
||||
self.btn_hmi_conn.clicked.connect(MainWindow.hmi_conn)
|
||||
self.btn_md_conn.clicked.connect(MainWindow.md_conn)
|
||||
self.btn_ec_conn.clicked.connect(MainWindow.ec_conn)
|
||||
self.le_durable_interval.editingFinished.connect(MainWindow.check_interval)
|
||||
self.cb_ec_cmd.currentTextChanged.connect(MainWindow.ec_cb_change)
|
||||
self.le_hmi_ip.returnPressed.connect(MainWindow.hmi_conn)
|
||||
|
||||
self.tw_funcs.setCurrentIndex(0)
|
||||
self.sw_network.setCurrentIndex(0)
|
||||
self.tw_docs.setCurrentIndex(1)
|
||||
|
||||
|
||||
QMetaObject.connectSlotsByName(MainWindow)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, MainWindow):
|
||||
MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"Rokae AIO", None))
|
||||
self.label.setText(QCoreApplication.translate("MainWindow", u"Rokae AIO", None))
|
||||
self.btn_start.setText(QCoreApplication.translate("MainWindow", u"\u5f00\u59cb\u6267\u884c", None))
|
||||
self.btn_stop.setText(QCoreApplication.translate("MainWindow", u"\u505c\u6b62\u6267\u884c", None))
|
||||
self.btn_reset.setText(QCoreApplication.translate("MainWindow", u"\u72b6\u6001\u91cd\u7f6e", None))
|
||||
self.cb_data_func.setItemText(0, QCoreApplication.translate("MainWindow", u"\u5236\u52a8", None))
|
||||
self.cb_data_func.setItemText(1, QCoreApplication.translate("MainWindow", u"\u8f6c\u77e9", None))
|
||||
self.cb_data_func.setItemText(2, QCoreApplication.translate("MainWindow", u"\u6fc0\u5149", None))
|
||||
self.cb_data_func.setItemText(3, QCoreApplication.translate("MainWindow", u"\u7cbe\u5ea6", None))
|
||||
|
||||
self.cb_data_current.setItemText(0, QCoreApplication.translate("MainWindow", u"\u5468\u671f", None))
|
||||
self.cb_data_current.setItemText(1, QCoreApplication.translate("MainWindow", u"\u6700\u5927\u503c", None))
|
||||
self.cb_data_current.setItemText(2, QCoreApplication.translate("MainWindow", u"\u5e73\u5747\u503c", None))
|
||||
|
||||
self.label_4.setText(QCoreApplication.translate("MainWindow", u"\u8def\u5f84", None))
|
||||
self.btn_data_open.setText(QCoreApplication.translate("MainWindow", u"...", None))
|
||||
self.tw_funcs.setTabText(self.tw_funcs.indexOf(self.tab_data), QCoreApplication.translate("MainWindow", u"\u6570\u636e\u5904\u7406", None))
|
||||
self.cb_unit_func.setItemText(0, QCoreApplication.translate("MainWindow", u"\u5236\u52a8", None))
|
||||
self.cb_unit_func.setItemText(1, QCoreApplication.translate("MainWindow", u"\u8f6c\u77e9", None))
|
||||
|
||||
self.cb_unit_tool.setItemText(0, QCoreApplication.translate("MainWindow", u"tool33", None))
|
||||
self.cb_unit_tool.setItemText(1, QCoreApplication.translate("MainWindow", u"tool66", None))
|
||||
self.cb_unit_tool.setItemText(2, QCoreApplication.translate("MainWindow", u"tool100", None))
|
||||
self.cb_unit_tool.setItemText(3, QCoreApplication.translate("MainWindow", u"inertia", None))
|
||||
|
||||
self.label_6.setText(QCoreApplication.translate("MainWindow", u"\u8def\u5f84", None))
|
||||
self.btn_unit_open.setText(QCoreApplication.translate("MainWindow", u"...", None))
|
||||
self.tw_funcs.setTabText(self.tw_funcs.indexOf(self.tab_unit), QCoreApplication.translate("MainWindow", u"\u6574\u673a\u6d4b\u8bd5", None))
|
||||
self.label_11.setText(QCoreApplication.translate("MainWindow", u"\u9009\u62e9\u6307\u6807", None))
|
||||
self.cb_1.setText(QCoreApplication.translate("MainWindow", u"\u5468\u671f\u5185\u5e73\u5747\u8f6c\u77e9", None))
|
||||
self.cb_2.setText(QCoreApplication.translate("MainWindow", u"\u5468\u671f\u5185\u5e73\u5747\u8f6c\u77e9", None))
|
||||
self.label_8.setText(QCoreApplication.translate("MainWindow", u"\u8def\u5f84", None))
|
||||
self.btn_durable_open.setText(QCoreApplication.translate("MainWindow", u"...", None))
|
||||
self.label_9.setText(QCoreApplication.translate("MainWindow", u"\u95f4\u9694", None))
|
||||
#if QT_CONFIG(whatsthis)
|
||||
self.le_durable_interval.setWhatsThis("")
|
||||
#endif // QT_CONFIG(whatsthis)
|
||||
self.le_durable_interval.setPlaceholderText(QCoreApplication.translate("MainWindow", u"\u6bcf\u6b21\u6570\u636e\u91c7\u96c6\u7684\u65f6\u95f4\u95f4\u9694\uff0c\u9ed8\u8ba4(\u6700\u5c0f)300s", None))
|
||||
self.label_10.setText("")
|
||||
self.cb_durable_total.setText(QCoreApplication.translate("MainWindow", u"\u5168\u90e8\u6253\u5f00/\u5173\u95ed", None))
|
||||
self.btn_draw.setText(QCoreApplication.translate("MainWindow", u"\u7ed8\u56fe", None))
|
||||
self.label_3.setText("")
|
||||
self.tw_funcs.setTabText(self.tw_funcs.indexOf(self.tab_durable), QCoreApplication.translate("MainWindow", u"\u8010\u4e45\u91c7\u96c6", None))
|
||||
self.label_2.setText(QCoreApplication.translate("MainWindow", u"HMI IP", None))
|
||||
self.le_hmi_ip.setText(QCoreApplication.translate("MainWindow", u"192.168.0.160", None))
|
||||
self.btn_hmi_conn.setText(QCoreApplication.translate("MainWindow", u"\u8fde\u63a5", None))
|
||||
self.label_5.setText("")
|
||||
self.cb_hmi_cmd.setItemText(0, QCoreApplication.translate("MainWindow", u"controller.heart", None))
|
||||
self.cb_hmi_cmd.setItemText(1, QCoreApplication.translate("MainWindow", u"device.get_params", None))
|
||||
self.cb_hmi_cmd.setItemText(2, QCoreApplication.translate("MainWindow", u"safety_area_data", None))
|
||||
|
||||
self.btn_hmi_send.setText(QCoreApplication.translate("MainWindow", u"\u53d1\u9001", None))
|
||||
self.label_7.setText(QCoreApplication.translate("MainWindow", u"MD Port", None))
|
||||
self.le_md_port.setText(QCoreApplication.translate("MainWindow", u"502", None))
|
||||
self.btn_md_conn.setText(QCoreApplication.translate("MainWindow", u"\u8fde\u63a5", None))
|
||||
self.label_12.setText("")
|
||||
self.cb_md_cmd.setItemText(0, QCoreApplication.translate("MainWindow", u"ctrl_motor_on", None))
|
||||
self.cb_md_cmd.setItemText(1, QCoreApplication.translate("MainWindow", u"ctrl_motor_off", None))
|
||||
|
||||
self.btn_md_send.setText(QCoreApplication.translate("MainWindow", u"\u53d1\u9001", None))
|
||||
self.label_17.setText(QCoreApplication.translate("MainWindow", u"EC Port", None))
|
||||
self.le_ec_port.setText(QCoreApplication.translate("MainWindow", u"8080", None))
|
||||
self.btn_ec_conn.setText(QCoreApplication.translate("MainWindow", u"\u8fde\u63a5", None))
|
||||
self.label_18.setText("")
|
||||
self.cb_ec_cmd.setItemText(0, QCoreApplication.translate("MainWindow", u"motor_on_state", None))
|
||||
self.cb_ec_cmd.setItemText(1, QCoreApplication.translate("MainWindow", u"robot_running_state", None))
|
||||
|
||||
self.btn_ec_send.setText(QCoreApplication.translate("MainWindow", u"\u53d1\u9001", None))
|
||||
self.pushButton.setText(QCoreApplication.translate("MainWindow", u"HMI", None))
|
||||
self.pushButton_2.setText(QCoreApplication.translate("MainWindow", u"Modbus", None))
|
||||
self.pushButton_3.setText(QCoreApplication.translate("MainWindow", u"EC", None))
|
||||
self.tw_funcs.setTabText(self.tw_funcs.indexOf(self.tab_network), QCoreApplication.translate("MainWindow", u"\u7f51\u7edc\u8bbe\u7f6e", None))
|
||||
self.tw_docs.setTabText(self.tw_docs.indexOf(self.tab_output), QCoreApplication.translate("MainWindow", u"\u8f93\u51fa", None))
|
||||
___qtreewidgetitem = self.treew_log.headerItem()
|
||||
___qtreewidgetitem.setText(4, QCoreApplication.translate("MainWindow", u"Content", None));
|
||||
___qtreewidgetitem.setText(3, QCoreApplication.translate("MainWindow", u"Module", None));
|
||||
___qtreewidgetitem.setText(2, QCoreApplication.translate("MainWindow", u"Level", None));
|
||||
___qtreewidgetitem.setText(1, QCoreApplication.translate("MainWindow", u"Timestamp", None));
|
||||
___qtreewidgetitem.setText(0, QCoreApplication.translate("MainWindow", u"ID", None));
|
||||
self.label_page.setText(QCoreApplication.translate("MainWindow", u"0/0", None))
|
||||
self.btn_docs_previous.setText(QCoreApplication.translate("MainWindow", u"\u4e0a\u4e00\u9875", None))
|
||||
self.btn_docs_realtime.setText(QCoreApplication.translate("MainWindow", u"\u5b9e\u65f6", None))
|
||||
self.btn_docs_next.setText(QCoreApplication.translate("MainWindow", u"\u4e0b\u4e00\u9875", None))
|
||||
self.btn_docs_load.setText(QCoreApplication.translate("MainWindow", u"\u52a0\u8f7d", None))
|
||||
self.btn_docs_search.setText(QCoreApplication.translate("MainWindow", u"\u67e5\u627e", None))
|
||||
self.le_docs_search.setPlaceholderText(QCoreApplication.translate("MainWindow", u"[id/level/module] \u67e5\u627e\u5185\u5bb9", None))
|
||||
self.tw_docs.setTabText(self.tw_docs.indexOf(self.tab_log), QCoreApplication.translate("MainWindow", u"\u65e5\u5fd7", None))
|
||||
# retranslateUi
|
||||
|
170
code/ui/reset_window.py
Normal file
170
code/ui/reset_window.py
Normal file
@ -0,0 +1,170 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'reset.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.8.2
|
||||
##
|
||||
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
||||
################################################################################
|
||||
|
||||
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
|
||||
QMetaObject, QObject, QPoint, QRect,
|
||||
QSize, QTime, QUrl, Qt)
|
||||
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
|
||||
QFont, QFontDatabase, QGradient, QIcon,
|
||||
QImage, QKeySequence, QLinearGradient, QPainter,
|
||||
QPalette, QPixmap, QRadialGradient, QTransform)
|
||||
from PySide6.QtWidgets import (QApplication, QHBoxLayout, QLabel, QLineEdit,
|
||||
QPushButton, QSizePolicy, QVBoxLayout, QWidget)
|
||||
|
||||
class Ui_Form(QWidget):
|
||||
def setupUi(self, Form):
|
||||
if not Form.objectName():
|
||||
Form.setObjectName(u"Form")
|
||||
Form.setWindowModality(Qt.WindowModality.WindowModal)
|
||||
Form.resize(500, 270)
|
||||
sizePolicy = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(Form.sizePolicy().hasHeightForWidth())
|
||||
Form.setSizePolicy(sizePolicy)
|
||||
Form.setMinimumSize(QSize(500, 270))
|
||||
Form.setMaximumSize(QSize(500, 270))
|
||||
font = QFont()
|
||||
font.setFamilies([u"Consolas"])
|
||||
font.setPointSize(14)
|
||||
Form.setFont(font)
|
||||
icon = QIcon()
|
||||
icon.addFile(u"../assets/media/icon.ico", QSize(), QIcon.Mode.Normal, QIcon.State.Off)
|
||||
Form.setWindowIcon(icon)
|
||||
self.widget = QWidget(Form)
|
||||
self.widget.setObjectName(u"widget")
|
||||
self.widget.setGeometry(QRect(40, 27, 411, 211))
|
||||
self.verticalLayout = QVBoxLayout(self.widget)
|
||||
self.verticalLayout.setObjectName(u"verticalLayout")
|
||||
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
|
||||
self.horizontalLayout_5 = QHBoxLayout()
|
||||
self.horizontalLayout_5.setObjectName(u"horizontalLayout_5")
|
||||
self.label = QLabel(self.widget)
|
||||
self.label.setObjectName(u"label")
|
||||
self.label.setFont(font)
|
||||
|
||||
self.horizontalLayout_5.addWidget(self.label)
|
||||
|
||||
self.le_username = QLineEdit(self.widget)
|
||||
self.le_username.setObjectName(u"le_username")
|
||||
self.le_username.setFont(font)
|
||||
|
||||
self.horizontalLayout_5.addWidget(self.le_username)
|
||||
|
||||
|
||||
self.verticalLayout.addLayout(self.horizontalLayout_5)
|
||||
|
||||
self.horizontalLayout_4 = QHBoxLayout()
|
||||
self.horizontalLayout_4.setObjectName(u"horizontalLayout_4")
|
||||
self.label_2 = QLabel(self.widget)
|
||||
self.label_2.setObjectName(u"label_2")
|
||||
self.label_2.setFont(font)
|
||||
|
||||
self.horizontalLayout_4.addWidget(self.label_2)
|
||||
|
||||
self.le_old_password = QLineEdit(self.widget)
|
||||
self.le_old_password.setObjectName(u"le_old_password")
|
||||
self.le_old_password.setFont(font)
|
||||
self.le_old_password.setEchoMode(QLineEdit.EchoMode.Password)
|
||||
|
||||
self.horizontalLayout_4.addWidget(self.le_old_password)
|
||||
|
||||
|
||||
self.verticalLayout.addLayout(self.horizontalLayout_4)
|
||||
|
||||
self.horizontalLayout_3 = QHBoxLayout()
|
||||
self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
|
||||
self.label_3 = QLabel(self.widget)
|
||||
self.label_3.setObjectName(u"label_3")
|
||||
self.label_3.setFont(font)
|
||||
|
||||
self.horizontalLayout_3.addWidget(self.label_3)
|
||||
|
||||
self.le_new_password_1 = QLineEdit(self.widget)
|
||||
self.le_new_password_1.setObjectName(u"le_new_password_1")
|
||||
self.le_new_password_1.setFont(font)
|
||||
self.le_new_password_1.setEchoMode(QLineEdit.EchoMode.Password)
|
||||
|
||||
self.horizontalLayout_3.addWidget(self.le_new_password_1)
|
||||
|
||||
|
||||
self.verticalLayout.addLayout(self.horizontalLayout_3)
|
||||
|
||||
self.horizontalLayout_2 = QHBoxLayout()
|
||||
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
|
||||
self.label_4 = QLabel(self.widget)
|
||||
self.label_4.setObjectName(u"label_4")
|
||||
self.label_4.setFont(font)
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.label_4)
|
||||
|
||||
self.le_new_password_2 = QLineEdit(self.widget)
|
||||
self.le_new_password_2.setObjectName(u"le_new_password_2")
|
||||
self.le_new_password_2.setFont(font)
|
||||
self.le_new_password_2.setEchoMode(QLineEdit.EchoMode.Password)
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.le_new_password_2)
|
||||
|
||||
|
||||
self.verticalLayout.addLayout(self.horizontalLayout_2)
|
||||
|
||||
self.label_hint = QLabel(self.widget)
|
||||
self.label_hint.setObjectName(u"label_hint")
|
||||
sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Preferred, QSizePolicy.Policy.Fixed)
|
||||
sizePolicy1.setHorizontalStretch(0)
|
||||
sizePolicy1.setVerticalStretch(0)
|
||||
sizePolicy1.setHeightForWidth(self.label_hint.sizePolicy().hasHeightForWidth())
|
||||
self.label_hint.setSizePolicy(sizePolicy1)
|
||||
font1 = QFont()
|
||||
font1.setFamilies([u"Consolas"])
|
||||
font1.setPointSize(12)
|
||||
self.label_hint.setFont(font1)
|
||||
|
||||
self.verticalLayout.addWidget(self.label_hint)
|
||||
|
||||
self.horizontalLayout = QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
||||
self.btn_reset = QPushButton(self.widget)
|
||||
self.btn_reset.setObjectName(u"btn_reset")
|
||||
self.btn_reset.setFont(font)
|
||||
|
||||
self.horizontalLayout.addWidget(self.btn_reset)
|
||||
|
||||
self.btn_cancel = QPushButton(self.widget)
|
||||
self.btn_cancel.setObjectName(u"btn_cancel")
|
||||
self.btn_cancel.setFont(font)
|
||||
|
||||
self.horizontalLayout.addWidget(self.btn_cancel)
|
||||
|
||||
|
||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||
|
||||
QWidget.setTabOrder(self.le_username, self.le_old_password)
|
||||
QWidget.setTabOrder(self.le_old_password, self.le_new_password_1)
|
||||
QWidget.setTabOrder(self.le_new_password_1, self.le_new_password_2)
|
||||
|
||||
self.retranslateUi(Form)
|
||||
self.btn_reset.clicked.connect(Form.reset_password)
|
||||
self.btn_cancel.clicked.connect(Form.reset_cancel)
|
||||
|
||||
QMetaObject.connectSlotsByName(Form)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, Form):
|
||||
Form.setWindowTitle(QCoreApplication.translate("Form", u"\u91cd\u7f6e\u5bc6\u7801", None))
|
||||
self.label.setText(QCoreApplication.translate("Form", u"\u7528\u6237\u540d", None))
|
||||
self.label_2.setText(QCoreApplication.translate("Form", u"\u65e7\u5bc6\u7801", None))
|
||||
self.label_3.setText(QCoreApplication.translate("Form", u"\u65b0\u5bc6\u7801", None))
|
||||
self.label_4.setText(QCoreApplication.translate("Form", u"\u786e \u8ba4", None))
|
||||
self.label_hint.setText("")
|
||||
self.btn_reset.setText(QCoreApplication.translate("Form", u"\u786e\u5b9a", None))
|
||||
self.btn_cancel.setText(QCoreApplication.translate("Form", u"\u53d6\u6d88", None))
|
||||
# retranslateUi
|
||||
|
Reference in New Issue
Block a user