basically done

This commit is contained in:
gitea 2025-03-27 19:05:02 +08:00
parent 09d322378a
commit 957071075d
110 changed files with 2180 additions and 1797 deletions

3
.gitignore vendored
View File

@ -2,3 +2,6 @@ venv/
.idea/
**/__pycache__/
assets/files/examples/
assets/logs/*
test.py
package/*

1022
aio.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
motor_off

View File

@ -0,0 +1 @@
motor_on

View File

@ -0,0 +1 @@
motor_on_state

View File

@ -0,0 +1 @@
operating_mode

View File

@ -0,0 +1 @@
robot_running_state

View File

@ -0,0 +1 @@
set_do:DO4_0,true

View File

@ -0,0 +1 @@
switch_mode:auto

View File

@ -0,0 +1 @@
switch_mode:manual

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "safety",
"command": "collision.get_params"
"command": "collision.get_params",
"p_type": 0
}

View File

@ -2,5 +2,6 @@
"id": "xxxxxxxxxxx",
"module": "safety",
"command": "collision.set_params",
"data": null
"data": null,
"p_type": 0
}

View File

@ -3,5 +3,6 @@
"command": "collision.set_state",
"data": {
"collision_state": false
}
},
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id":"xxxxxxxxxxx",
"module":"system",
"command":"controller.get_params"
"command":"controller.get_params",
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "system",
"command": "controller.heart"
"command": "controller.heart",
"p_type": 0
}

View File

@ -4,5 +4,6 @@
"command": "controller.reboot",
"data": {
"arg": 6
}
},
"p_type": 0
}

View File

@ -4,5 +4,6 @@
"command": "controller.set_params",
"data": {
"time": "2020-02-28 15:28:30"
}
},
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "system",
"command": "device.get_params"
"command": "device.get_params",
"p_type": 0
}

View File

@ -4,5 +4,6 @@
"command": "diagnosis.get_params",
"data": {
"version": "1.4.1"
}
},
"p_type": 0
}

View File

@ -8,5 +8,6 @@
"overrun": false,
"turn_area": false,
"delay_motion": false
}
},
"p_type": 0
}

View File

@ -4,5 +4,6 @@
"command": "diagnosis.save",
"data": {
"save": true
}
},
"p_type": 0
}

View File

@ -6,5 +6,6 @@
"display_pdo_params": [],
"frequency": 50,
"version": "1.4.1"
}
},
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "dynamic",
"command": "drag.get_params"
"command": "drag.get_params",
"p_type": 0
}

View File

@ -6,5 +6,6 @@
"enable": true,
"space": 0,
"type": 0
}
},
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "fieldbus",
"command": "fieldbus_device.get_params"
"command": "fieldbus_device.get_params",
"p_type": 0
}

View File

@ -4,5 +4,6 @@
"command": "fieldbus_device.load_cfg",
"data": {
"file_name": "fieldbus_device.json"
}
},
"p_type": 0
}

View File

@ -5,5 +5,6 @@
"data": {
"device_name": "modbus_1",
"enable": true
}
},
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "io",
"command": "io_device.load_cfg"
"command": "io_device.load_cfg",
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "motion",
"command": "jog.get_params"
"command": "jog.get_params",
"p_type": 0
}

View File

@ -1,5 +1,7 @@
{
"g": {
"id": "xxxxxxxxxxx",
"g": {
"log_code.data": "null"
}
},
"p_type": 1
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "fieldbus",
"command": "modbus.get_params"
"command": "modbus.get_params",
"p_type": 0
}

View File

@ -4,5 +4,6 @@
"command": "modbus.get_values",
"data": {
"mode": "all"
}
},
"p_type": 0
}

View File

@ -4,5 +4,6 @@
"command": "modbus.load_cfg",
"data": {
"file" : "registers.json"
}
},
"p_type": 0
}

View File

@ -8,5 +8,6 @@
"port": 502,
"slave_id": 0,
"enable_master": false
}
},
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "motion",
"command": "move.get_joint_pos"
"command": "move.get_joint_pos",
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "motion",
"command": "move.get_monitor_cfg"
"command": "move.get_monitor_cfg",
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "motion",
"command": "move.get_params"
"command": "move.get_params",
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "motion",
"command": "move.get_pos"
"command": "move.get_pos",
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "motion",
"command": "move.get_quickstop_distance"
"command": "move.get_quickstop_distance",
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id" : "xxxxxxxxx",
"module": "motion",
"command": "move.get_quickturn_pos"
"command": "move.get_quickturn_pos",
"p_type": 0
}

View File

@ -4,5 +4,6 @@
"command": "move.quick_turn",
"data": {
"name":"home"
}
},
"p_type": 0
}

View File

@ -4,5 +4,6 @@
"command": "move.set_monitor_cfg",
"data": {
"ref_coordinate": 1
}
},
"p_type": 0
}

View File

@ -12,6 +12,6 @@
"VEL_SMOOTH_FACTOR": 3.33,
"ACC_RAMPTIME_JOG": 0.01
}
}
},
"p_type": 0
}

View File

@ -4,5 +4,6 @@
"command": "move.set_quickstop_distance",
"data":{
"distance": 2
}
},
"p_type": 0
}

View File

@ -11,5 +11,6 @@
"joint_transport": [0.0,0.0,0.0,0.0,0.0,0.0,0.0],
"end_posture": 0,
"home_error_range":[0.0,0.0,0.0,0.0,0.0,0.0,0.0]
}
},
"p_type": 0
}

View File

@ -4,5 +4,6 @@
"command": "move.stop",
"data":{
"stoptype": 0
}
},
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "project",
"command": "overview.get_autoload"
"command": "overview.get_autoload",
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "project",
"command": "overview.get_cur_prj"
"command": "overview.get_cur_prj",
"p_type": 0
}

View File

@ -5,5 +5,6 @@
"data": {
"prj_path": "",
"tasks": []
}
},
"p_type": 0
}

View File

@ -4,5 +4,6 @@
"command": "overview.set_autoload",
"data": {
"autoload_prj_path": ""
}
},
"p_type": 0
}

View File

@ -7,5 +7,6 @@
"type": "bool",
"bias": 0,
"value": 0
}
},
"p_type": 0
}

View File

@ -4,5 +4,6 @@
"command": "rl_task.pp_to_main",
"data": {
"tasks": []
}
},
"p_type": 0
}

View File

@ -4,5 +4,6 @@
"command": "rl_task.run",
"data": {
"tasks": []
}
},
"p_type": 0
}

View File

@ -5,5 +5,6 @@
"data": {
"loop_mode": true,
"override": 1.0
}
},
"p_type": 0
}

View File

@ -4,5 +4,6 @@
"command": "rl_task.stop",
"data": {
"tasks": []
}
},
"p_type": 0
}

View File

@ -1,7 +1,9 @@
{
"c": {
"id": "xxxxxxxxxxx",
"c": {
"safety.safety_area.overall_enable": {
"enable": true
}
}
},
"p_type": 1
}

View File

@ -1,8 +1,10 @@
{
"c": {
"id": "xxxxxxxxxxx",
"c": {
"safety.safety_area.safety_area_enable": {
"id": 0,
"enable": true
}
}
},
"p_type": 1
}

View File

@ -1,5 +1,7 @@
{
"c": {
"id": "xxxxxxxxxxx",
"c": {
"safety.safety_area.set_param": null
}
},
"p_type": 1
}

View File

@ -1,7 +1,9 @@
{
"c": {
"id": "xxxxxxxxxxx",
"c": {
"safety.safety_area.signal_enable": {
"signal": true
}
}
},
"p_type": 1
}

View File

@ -1,5 +1,7 @@
{
"g": {
"id": "xxxxxxxxxxx",
"g": {
"safety_area_data": null
}
},
"p_type": 1
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "robot",
"command": "servo.clear_alarm"
"command": "servo.clear_alarm",
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "network",
"command": "socket.get_params"
"command": "socket.get_params",
"p_type": 0
}

View File

@ -13,5 +13,6 @@
"auto_connect": true,
"disconnection_triggering_behavior": 0,
"disconnection_detection_time": 10
}
},
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "safety",
"command": "soft_limit.get_params"
"command": "soft_limit.get_params",
"p_type": 0
}

View File

@ -8,5 +8,6 @@
"lower": [0,0,0,0,0,0,0],
"reduced_upper": [0,0,0,0,0,0,0],
"reduced_lower": [0,0,0,0,0,0,0]
}
},
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "system",
"command": "state.get_state"
"command": "state.get_state",
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "system",
"command": "state.get_tp_mode"
"command": "state.get_tp_mode",
"p_type": 0
}

View File

@ -4,5 +4,6 @@
"command": "state.set_tp_mode",
"data": {
"tp_mode": "with"
}
},
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "system",
"command": "state.switch_auto"
"command": "state.switch_auto",
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "system",
"command": "state.switch_manual"
"command": "state.switch_manual",
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "system",
"command": "state.switch_motor_off"
"command": "state.switch_motor_off",
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "system",
"command": "state.switch_motor_on"
"command": "state.switch_motor_on",
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "io",
"command": "system_io.query_configuration"
"command": "system_io.query_configuration",
"p_type": 0
}

View File

@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "io",
"command": "system_io.query_event_cfg"
"command": "system_io.query_event_cfg",
"p_type": 0
}

View File

@ -5,5 +5,6 @@
"data": {
"input_system_io": {},
"output_system_io": {}
}
},
"p_type": 0
}

View File

@ -0,0 +1,3 @@
40002: 0
40002: 1
40002: 0

View File

@ -0,0 +1,3 @@
40003: 0
40003: 1
40003: 0

View File

@ -0,0 +1,3 @@
40004: 0
40004: 1
40004: 0

View File

@ -0,0 +1 @@
40012: 1

View File

@ -0,0 +1 @@
40500:1:bool

View File

@ -0,0 +1 @@
40505:1:bool

View File

@ -0,0 +1 @@
40506:1:bool

View File

@ -0,0 +1 @@
40518:1:bool

View File

@ -0,0 +1 @@
0.3.1.7@03/24/2025

BIN
assets/media/splash.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,518 +0,0 @@
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())

View File

@ -1,62 +0,0 @@
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 # 各个指标所在列

View File

@ -1,85 +0,0 @@
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
#

View File

@ -1,239 +0,0 @@
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)

View File

@ -1,135 +0,0 @@
# -*- 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

View File

@ -1,170 +0,0 @@
# -*- 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

0
codes/__init__.py Normal file
View File

View File

View File

@ -5,7 +5,7 @@ import pandas
from PySide6.QtCore import Signal, QThread
import openpyxl
import re
from common import clibs
from codes.common import clibs
class BrakeDataProcess(QThread):
@ -17,17 +17,19 @@ class BrakeDataProcess(QThread):
self.idx = 0
def logger(self, level, module, content, color="black", error="", flag="both"):
flag = "cursor" if level.upper() == "DEBUG" else "both"
clibs.logger(level, module, content, color, flag, signal=self.output)
if level.upper() == "ERROR":
raise Exception(f"{error} | {content}")
@clibs.handle_exception
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")
self.logger("ERROR", "brake", msg_wrong, "red", "InitFileError")
config_file, reach33_file, reach66_file, reach100_file = None, None, None, None
for result_file in result_files:
@ -42,7 +44,7 @@ class BrakeDataProcess(QThread):
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")
self.logger("ERROR", "brake", msg_wrong, "red", "InitFileError")
reach_s = ['reach33', 'reach66', 'reach100']
load_s = ['load33', 'load66', 'load100']
@ -55,26 +57,27 @@ class BrakeDataProcess(QThread):
msg = f"报错信息:数据目录 {rawdata_dir} 命名不合规,请参考如下形式<br>"
msg += "命名规则reachAA_loadBB_speedCCAA/BB/CC 指的是臂展/负载/速度的比例<br>"
msg += "规则解释reach66_load100_speed33表示 66% 臂展100% 负载以及 33% 速度情况下的测试结果文件夹<br>"
self.logger("ERROR", "brake-check_files", msg, "red", "WrongDataFolder")
self.logger("ERROR", "brake", 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")
self.logger("ERROR", "brake", 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")
self.logger("ERROR", "brake", 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")
self.logger("INFO", "brake", "数据目录合规性检查结束,未发现问题......", "green")
return config_file, result_files
@clibs.handle_exception
def get_configs(self, config_file):
try:
with open(config_file, mode="r", encoding="utf-8") as f_config:
@ -82,7 +85,7 @@ class BrakeDataProcess(QThread):
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")
self.logger("ERROR", "brake", "被处理的根文件夹命名必须是 [Jj][123] 的格式", "red", "DirNameError")
axis = int(p_dir[-1]) # 要处理的轴
rrs = [abs(_) for _ in configs["TRANSMISSION"]["REDUCTION_RATIO_NUMERATOR"]] # 减速比rr for reduction ratio
@ -91,21 +94,22 @@ class BrakeDataProcess(QThread):
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")
self.logger("ERROR", "brake", 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} 中的数据......")
self.logger("INFO", "brake", f"[{now}] 正在处理目录 {docs} 中的数据......")
elif flag == 'start' and file_type == 'file':
self.logger("INFO", "brake-now_doing_msg", f"[{now}] 正在处理文件 {docs} 中的数据......")
self.logger("INFO", "brake", f"[{now}] 正在处理文件 {docs} 中的数据......")
elif flag == 'done' and file_type == 'dir':
self.logger("INFO", "brake-now_doing_msg", f"[{now}] 目录 {docs} 数据文件已处理完毕")
self.logger("INFO", "brake", f"[{now}] 目录 {docs} 数据文件已处理完毕")
elif flag == 'done' and file_type == 'file':
self.logger("INFO", "brake-now_doing_msg", f"[{now}] 文件 {docs} 数据已处理完毕")
self.logger("INFO", "brake", f"[{now}] 文件 {docs} 数据已处理完毕")
@staticmethod
@clibs.handle_exception
def data2result(df, ws_result, row_start, row_end):
data = []
for row in range(row_start, row_end):
@ -126,6 +130,7 @@ class BrakeDataProcess(QThread):
ws_result.cell(row=row, column=2).value = None
ws_result.cell(row=row, column=3).value = None
@clibs.handle_exception
def get_row_range(self, data_file, df, conditions, av, rr):
row_start, row_end = 0, 0
ratio = float(conditions[2].removeprefix('speed')) / 100
@ -137,7 +142,7 @@ class BrakeDataProcess(QThread):
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")
self.logger("ERROR", "brake", 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
@ -145,17 +150,18 @@ class BrakeDataProcess(QThread):
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")
self.logger("ERROR", "brake", 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")
self.logger("WARNING", "brake", msg, "#8A2BE2")
return row_start, row_end
@staticmethod
@clibs.handle_exception
def get_shtname(conditions, count):
# 33%负载_33%速度_1 - reach/load/speed
load = conditions[1].removeprefix('load')
@ -164,6 +170,7 @@ class BrakeDataProcess(QThread):
return result_sheet_name
@clibs.handle_exception
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
@ -173,13 +180,14 @@ class BrakeDataProcess(QThread):
row_start, row_end = self.get_row_range(data_file, df, conditions, av, rr)
self.data2result(df, ws, row_start, row_end)
@clibs.handle_exception
def data_process(self, result_file, rawdata_dirs, av, rr):
filename = result_file.split("/")[-1]
self.logger("INFO", "brake-data_process", f"正在打开文件 {filename},这可能需要一些时间......", "blue")
self.logger("INFO", "brake", 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")
self.logger("ERROR", "brake", f"{filename}文件打开失败,可能是文件已损坏,确认后重新执行!<br>{Err}", "red", "CannotOpenFile")
prefix = filename.split('_')[0]
for rawdata_dir in rawdata_dirs:
@ -197,10 +205,11 @@ class BrakeDataProcess(QThread):
# [t.join() for t in threads]
self.now_doing_msg(rawdata_dir, 'done')
self.logger("INFO", "brake-data_process", f"正在保存文件 {filename},这可能需要一些时间......<br>", "blue")
self.logger("INFO", "brake", f"正在保存文件 {filename},这可能需要一些时间......<br>", "blue")
wb.save(result_file)
wb.close()
@clibs.handle_exception
def processing(self):
time_start = time.time()
clibs.running[self.idx] = 1
@ -212,7 +221,7 @@ class BrakeDataProcess(QThread):
for result_file in result_files:
self.data_process(result_file, rawdata_dirs, av, rr)
self.logger("INFO", "brake-processing", "-"*60 + "<br>全部处理完毕<br>", "purple")
self.logger("INFO", "brake", "-"*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)
self.logger("INFO", "brake", msg)

View File

@ -5,7 +5,7 @@ import re
import csv
from PySide6.QtCore import Signal, QThread
import time
from common import clibs
from codes.common import clibs
class CurrentDataProcess(QThread):
@ -18,10 +18,12 @@ class CurrentDataProcess(QThread):
self.idx = 1
def logger(self, level, module, content, color="black", error="", flag="both"):
flag = "cursor" if level.upper() == "DEBUG" else "both"
clibs.logger(level, module, content, color, flag, signal=self.output)
if level.upper() == "ERROR":
raise Exception(f"{error} | {content}")
@clibs.handle_exception
def initialization(self):
_, data_files = clibs.traversal_files(self.dir_path, self.output)
count, config_file = 0, None
@ -36,16 +38,17 @@ class CurrentDataProcess(QThread):
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")
self.logger("ERROR", "current", msg, "red", "FilenameIllegal")
if count != 2:
msg = "需要有一个机型配置文件\"*.cfg\",以及一个数据处理文件\"T_电机电流.xlsx\"表格,请检查整改后重新运行"
self.logger("ERROR", "current-initialization", msg, "red", "FilenameIllegal")
self.logger("ERROR", "current", msg, "red", "FilenameIllegal")
return data_files, config_file
@clibs.handle_exception
def current_max(self, data_files, rts):
self.logger("INFO", "current-current_max", f"正在处理最大转矩值逻辑......")
self.logger("INFO", "current", f"正在处理最大转矩值逻辑......")
current = {1: [], 2: [], 3: [], 4: [], 5: [], 6: []}
for data_file in data_files:
if data_file.endswith(".data"):
@ -53,11 +56,11 @@ class CurrentDataProcess(QThread):
else:
continue
self.logger("INFO", "current-current_max", f"正在处理 {data_file} ...")
self.logger("DEBUG", "current", 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}")
self.logger("DEBUG", "current", f"最大列数为 {cols}{axis} 轴的额定转矩为 {rt}")
col = df.columns.values[clibs.c_servo_trq-1] # 获取 "device_servo_trq_feedback"
c_max = df[col].abs().max()
@ -65,8 +68,8 @@ class CurrentDataProcess(QThread):
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},最大转矩为 {_}")
self.logger("DEBUG", "current", f"{data_file}: {_:.2f}")
self.logger("DEBUG", "current", f"获取到的列名为 {col},最大转矩为 {_}")
with open(data_file, "a+") as f_data:
csv_writer = csv.writer(f_data, delimiter="\t")
@ -79,14 +82,15 @@ class CurrentDataProcess(QThread):
_ = ""
for value in cur:
_ += f"{value:.4f} "
self.logger("INFO", "current-current_max", f"{axis}轴最大转矩数据:{_}")
self.logger("INFO", "current", f"{axis}轴最大转矩数据:{_}")
self.logger("INFO", "current-current_max", f"获取最大转矩值结束 current_max = {current}")
self.logger("INFO", "current-current_max", f"最大转矩数据处理完毕......")
self.logger("DEBUG", "current", f"获取最大转矩值结束 current_max = {current}")
self.logger("INFO", "current", f"最大转矩数据处理完毕......")
return current
@clibs.handle_exception
def current_avg(self, data_files, rts):
self.logger("INFO", "current-current_avg", f"正在处理平均转矩值逻辑......")
self.logger("INFO", "current", f"正在处理平均转矩值逻辑......")
current = {1: [], 2: [], 3: [], 4: [], 5: [], 6: []}
for data_file in data_files:
if data_file.endswith(".data"):
@ -94,11 +98,11 @@ class CurrentDataProcess(QThread):
else:
continue
self.logger("INFO", "current-current_avg", f"正在处理 {data_file} ...")
self.logger("DEBUG", "current", 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}")
self.logger("DEBUG", "current", f"最大列数为 {cols}{axis} 轴的额定转矩为 {rt}")
col = df.columns.values[clibs.c_servo_trq-1]
c_std = df[col].std()
@ -107,8 +111,8 @@ class CurrentDataProcess(QThread):
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},平均转矩为 {_}")
self.logger("DEBUG", "current", f"{data_file}: {_:.2f}")
self.logger("DEBUG", "current", f"获取到的列名为 {col},平均转矩为 {_}")
with open(data_file, "a+") as f_data:
csv_writer = csv.writer(f_data, delimiter="\t")
@ -121,12 +125,13 @@ class CurrentDataProcess(QThread):
_ = ""
for value in cur:
_ += f"{value:.4f} "
self.logger("INFO", "current-current_avg", f"{axis}轴平均转矩数据:{_}")
self.logger("INFO", "current", f"{axis}轴平均转矩数据:{_}")
self.logger("INFO", "current-current_avg", f"获取平均转矩值结束 current_avg = {current}", flag="cursor")
self.logger("INFO", "current-current_avg", f"平均转矩数据处理完毕......")
self.logger("DEBUG", "current", f"获取平均转矩值结束 current_avg = {current}")
self.logger("INFO", "current", f"平均转矩数据处理完毕......")
return current
@clibs.handle_exception
def current_cycle(self, data_files, rrs, rts, params):
result, hold, single, scenario, dur_time = None, [], [], [], 0
for data_file in data_files:
@ -142,11 +147,11 @@ class CurrentDataProcess(QThread):
single.append(data_file)
clibs.stop, filename = True, result.split("/")[-1]
self.logger("INFO", "current-current_cycle", f"正在打开文件 {filename},这可能需要一些时间......", "blue")
self.logger("INFO", "current", 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")
self.logger("ERROR", "current", f"{filename}文件打开失败,可能是文件已损坏,确认后重新执行!<br>{Err}", "red", "CannotOpenFile")
ws = wb["统计"]
for idx in range(len(params)-1):
@ -166,10 +171,11 @@ class CurrentDataProcess(QThread):
else:
self.p_scenario(wb, scenario, rrs, dur_time)
self.logger("INFO", "current-current_cycle", f"正在保存文件 {filename},这可能需要一些时间......", "blue")
self.logger("INFO", "current", f"正在保存文件 {filename},这可能需要一些时间......", "blue")
wb.save(result)
wb.close()
@clibs.handle_exception
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:
@ -183,15 +189,13 @@ class CurrentDataProcess(QThread):
# 从实际数据看,这开逻辑很小概率能触发到
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")
self.logger("WARNING", "current", 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")
self.logger("ERROR", "current", 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
@ -201,11 +205,12 @@ class CurrentDataProcess(QThread):
# 从实际数据看,这开逻辑很小概率能触发到
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")
self.logger("WARNING", "current", 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")
self.logger("ERROR", "current", f"{data_file} 数据有误,需要检查,无法找到第 {seq} 个有效点......", "red", "AnchorNotFound")
@clibs.handle_exception
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":
@ -228,9 +233,10 @@ class CurrentDataProcess(QThread):
count_1 = 0
places = {"start": "起点", "middle": "中间点", "end": "终点"} # 因为是终点数据,所以可能有异常
self.logger("WARNING", "current-get_row_number", f"{axis} 轴获取{places[flag]}数据 {row_e} 可能有异常,需关注!", "purple")
self.logger("DEBUG", "current", f"{axis} 轴获取{places[flag]}数据 {row_e} 可能有异常,需关注!", "purple")
return row_e
@clibs.handle_exception
def p_single(self, wb, single, rrs):
# 1. 先找到第一个速度为零的点,数据从后往前找,一开始就是零的情况不予考虑
# 2. 记录第一个点的位置,继续向前查找第二个速度为零的点,同理,一开始为零的点不予考虑
@ -304,13 +310,13 @@ class CurrentDataProcess(QThread):
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}")
self.logger("DEBUG", "current", f"{axis} 轴起点:{row_start}")
self.logger("DEBUG", "current", f"{axis} 轴中间点:{row_middle}")
self.logger("DEBUG", "current", f"{axis} 轴终点:{row_end}")
self.logger("DEBUG", "current", f"{axis} 轴数据非零段点数:{row_middle-row_start+1}")
self.logger("DEBUG", "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")
self.logger("DEBUG", "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):
@ -334,6 +340,7 @@ class CurrentDataProcess(QThread):
cell.value = None
i += 1
@clibs.handle_exception
def p_scenario(self, wb, scenario, rrs, dur_time):
self.logger("INFO", "current", f"本次处理的是电机电流场景数据,场景运动周期为 {dur_time}s", "blue")
for data_file in scenario:
@ -352,7 +359,7 @@ class CurrentDataProcess(QThread):
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")
self.logger("ERROR", "current", 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):
@ -376,6 +383,7 @@ class CurrentDataProcess(QThread):
ws.cell((i//4)+2, 1).value = None
i += 1
@clibs.handle_exception
def get_configs(self, config_file):
try:
if re.match("^[NXEC]B.*", config_file.split("/")[-1]):
@ -407,6 +415,7 @@ class CurrentDataProcess(QThread):
except Exception as Err:
self.logger("ERROR", "current", f"get_config: 无法打开 {config_file},或获取配置文件参数错误 {Err}", "red", "OpenFileError")
@clibs.handle_exception
def processing(self):
time_start = time.time()
clibs.running[self.idx] = 1
@ -421,7 +430,7 @@ class CurrentDataProcess(QThread):
elif self.proc == "周期":
self.current_cycle(data_files, rrs, rts, params)
self.logger("INFO", "current-processing", "-"*60 + "<br>全部处理完毕<br>", "purple")
self.logger("INFO", "current", "-"*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)
self.logger("INFO", "current", msg)

View File

@ -3,7 +3,7 @@ import openpyxl
import os
import time
from PySide6.QtCore import Signal, QThread
from common import clibs
from codes.common import clibs
class IsoDataProcess(QThread):
@ -15,6 +15,7 @@ class IsoDataProcess(QThread):
self.idx = 2
def logger(self, level, module, content, color="black", error="", flag="both"):
flag = "cursor" if level.upper() == "DEBUG" else "both"
clibs.logger(level, module, content, color, flag, signal=self.output)
if level.upper() == "ERROR":
raise Exception(f"{error} | {content}")

View File

@ -4,7 +4,7 @@ import openpyxl
import chardet
import time
from PySide6.QtCore import Signal, QThread
from common import clibs
from codes.common import clibs
class WaveloggerDataProcess(QThread):
@ -16,6 +16,7 @@ class WaveloggerDataProcess(QThread):
self.idx = 3
def logger(self, level, module, content, color="black", error="", flag="both"):
flag = "cursor" if level.upper() == "DEBUG" else "both"
clibs.logger(level, module, content, color, flag, signal=self.output)
if level.upper() == "ERROR":
raise Exception(f"{error} | {content}")
@ -37,7 +38,7 @@ class WaveloggerDataProcess(QThread):
break
else:
if bof == "backward":
self.logger("ERROR", "wavelogger-find_point", f"find_point-gt: [{pos}] 在 {data_file} 中,无法正确识别数据,需要确认...", "red", "DataError")
self.logger("ERROR", "wavelogger", 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":
@ -51,7 +52,7 @@ class WaveloggerDataProcess(QThread):
break
else:
if bof == "backward":
self.logger("ERROR", "wavelogger-find_point", f"find_point-lt: [{pos}] 在 {data_file} 中,无法正确识别数据,需要确认...", "red", "DataError")
self.logger("ERROR", "wavelogger", 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
@ -88,7 +89,7 @@ class WaveloggerDataProcess(QThread):
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")
self.logger("ERROR", "wavelogger", f"init: {data_file} 文件后缀错误,只允许 .csv 文件,需要确认!", "red", "FileTypeError")
return data_files
@ -114,7 +115,7 @@ class WaveloggerDataProcess(QThread):
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")
self.logger("WARNING", "wavelogger", f"{data_file} 文件第 {count} 轮 第 {count_i} 个数据可能有问题,需人工手动确认,确认有问题可删除,无问题则保留", "purple")
data[count].append(value)
count_i += 1
@ -135,7 +136,7 @@ class WaveloggerDataProcess(QThread):
row += 1
def execution(self, data_files):
self.logger("INFO", "wavelogger-execution", "正在处理中......", "blue")
self.logger("INFO", "wavelogger", "正在处理中......", "blue")
wb = openpyxl.Workbook()
step, margin, data_length, threshold = 5, 50, 50, 5
for data_file in data_files:
@ -154,7 +155,7 @@ class WaveloggerDataProcess(QThread):
data_files = self.initialization()
self.execution(data_files)
self.logger("INFO", "wavelogger-processing", "-" * 60 + "<br>全部处理完毕<br>", "purple")
self.logger("INFO", "wavelogger", "-" * 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)
self.logger("INFO", "wavelogger", msg)

View File

View File

@ -5,7 +5,7 @@ import openpyxl
import pandas
import json
from PySide6.QtCore import Signal, QThread
from common import clibs
from codes.common import clibs
class DoBrakeTest(QThread):
@ -18,16 +18,18 @@ class DoBrakeTest(QThread):
self.idx = 4
def logger(self, level, module, content, color="black", error="", flag="both"):
flag = "cursor" if level.upper() == "DEBUG" else "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):
@clibs.handle_exception
def check_files():
msg = "初始路径下不允许有文件夹,初始路径下只能存在如下五个文件,且文件为关闭状态,确认后重新运行!<br>"
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")
self.logger("ERROR", "do_brake", 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:
@ -43,7 +45,7 @@ class DoBrakeTest(QThread):
elif filename.endswith(".zip"):
prj_file = data_file
else:
self.logger("ERROR", "do_brake-check_files", msg, "red", "InitFileError")
self.logger("ERROR", "do_brake", 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")
@ -60,15 +62,15 @@ class DoBrakeTest(QThread):
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")
self.logger("ERROR", "do_brake", msg, "red", "InitFileError")
@clibs.handle_exception
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)
msg_id = clibs.c_hr.execution("controller.get_params")
records = clibs.c_hr.get_from_id(msg_id)
for record in records:
if "请求发送成功" not in record[0]:
robot_type = eval(record[0])["data"]["robot_type"]
@ -80,28 +82,29 @@ class DoBrakeTest(QThread):
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")
self.logger("ERROR", "do_brake", 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}")
self.logger("INFO", "do_brake", f"get_configs: 机型文件版本 {robot_type}_{version}")
self.logger("INFO", "do_brake", f"get_configs: 各关节角速度 {avs}")
return avs
self.logger("INFO", "do_brake", "正在做初始化校验和配置,这可能需要一点时间......", "green")
_config_file, _prj_file, _result_dirs = check_files()
_avs = get_configs()
self.logger("INFO", "do_brake", "数据目录合规性检查结束,未发现问题......", "green")
return _config_file, _prj_file, _result_dirs, _avs
def gen_result_file(self, axis, t_end, reach, load, speed, speed_max, rounds):
@clibs.handle_exception
def gen_result_file(self, axis, end_time, 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))
s_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(end_time-clibs.INTERVAL*12))
e_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(end_time))
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")
clibs.cursor.execute(f"SELECT content FROM logs WHERE timestamp BETWEEN '{s_time}' AND '{e_time}' AND content LIKE '%diagnosis.result%' ORDER BY id ASC")
records = clibs.cursor.fetchall()
finally:
clibs.lock.release()
@ -124,13 +127,13 @@ class DoBrakeTest(QThread):
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")
self.logger("WARNING", "do_brake", 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")
self.logger("WARNING", "do_brake",f"尝试三次后仍无法获取正确数据,本次数据无效,继续执行...", "red")
df1 = pandas.DataFrame.from_dict({"hw_joint_vel_feedback": d_vel})
df2 = pandas.DataFrame.from_dict({"device_servo_trq_feedback": d_trq})
@ -140,15 +143,17 @@ class DoBrakeTest(QThread):
df.to_csv(filename, sep="\t", index=False)
@staticmethod
@clibs.handle_exception
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")
clibs.c_hr.execution("diagnosis.open", open=stat, display_open=stat)
clibs.c_hr.execution("diagnosis.set_params", display_pdo_params=display_pdo_params)
@clibs.handle_exception
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])
@ -161,14 +166,14 @@ class DoBrakeTest(QThread):
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)
self.logger("INFO", "do_brake", 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.logger("ERROR", "do_brake", "configs.xlsx 中 Target 页面 B5 单元格填写不正确,检查后重新运行...", "red", "DirectionError")
self.change_curve_state(True)
for condition in result_dirs:
@ -198,7 +203,7 @@ class DoBrakeTest(QThread):
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)
self.logger("INFO", "do_brake", msg)
# 1. 触发软急停,并解除,目的是让可能正在运行着的机器停下来,切手动模式并下电
clibs.c_md.r_soft_estop(0)
@ -247,7 +252,7 @@ class DoBrakeTest(QThread):
else:
time.sleep(1)
if (time.time() - t_start) > 15:
self.logger("ERROR", "do_brake-run_rl", "15s 内未收到机器人的运行信号,需要确认 RL 程序编写正确并正常执行...", "red", "ReadySignalTimeoutError")
self.logger("ERROR", "do_brake", "15s 内未收到机器人的运行信号,需要确认 RL 程序编写正确并正常执行...", "red", "ReadySignalTimeoutError")
# 4. 找出最大速度传递给RL程序最后清除相关记录
time.sleep(5) # 消除前 5s 的不稳定数据
start_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
@ -257,9 +262,10 @@ class DoBrakeTest(QThread):
# 找出最大速度
@clibs.db_lock
@clibs.handle_exception
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")
clibs.cursor.execute(f"SELECT content FROM logs WHERE timestamp 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"]
@ -274,15 +280,14 @@ class DoBrakeTest(QThread):
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}")
self.logger("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}")
self.logger("WARNING", "do_brake", f"Axis: {axis}-{count} | 采集获取最大 Speed: {speed_max} | Shouldbe: {speed_target}", "indigo")
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")
self.logger("WARNING", "do_brake", f"未获取到正确的速度,即将重新获取...", "red")
continue
else:
break
@ -306,7 +311,7 @@ class DoBrakeTest(QThread):
else:
time.sleep(5)
if time.time() - t_start > 60:
self.logger("ERROR", "do_brake-run_rl","60s 内程序未能正常执行,需检查...", "red", "RlProgramStartTimeout")
self.logger("ERROR", "do_brake","60s 内程序未能正常执行,需检查...", "red", "RlProgramStartTimeout")
for i in range(16):
if clibs.c_md.read_ready_to_go() == 1:
@ -315,14 +320,15 @@ class DoBrakeTest(QThread):
else:
time.sleep(1)
else:
self.logger("ERROR", "do_brake-run_rl", "16s 内未收到机器人的运行信号,需要确认 RL 程序配置正确并正常执行...", "red", "ReadySignalTimeoutError")
self.logger("ERROR", "do_brake", "16s 内未收到机器人的运行信号,需要确认 RL 程序配置正确并正常执行...", "red", "ReadySignalTimeoutError")
@clibs.handle_exception
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")
self.logger("ERROR", "do_brake", "20s 内未触发急停,需排查......", "red", "BrakeTimeoutError")
try:
clibs.lock.acquire(True)
@ -340,15 +346,15 @@ class DoBrakeTest(QThread):
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)
time.sleep(clibs.INTERVAL*2) # wait speed goes down to 0
flag = False
break
return time.time()
time.sleep(11) # 排除从其他位姿到零点位姿,再到轴极限位姿的时间
t_end = exec_brake()
end_time = exec_brake()
# 6. 保留数据并处理输出
ret = self.gen_result_file(axis, t_end, reach, load, speed, speed_max, rounds)
ret = self.gen_result_file(axis, end_time, reach, load, speed, speed_max, rounds)
if ret != "retry":
clibs.count = 0
break
@ -356,19 +362,22 @@ class DoBrakeTest(QThread):
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")
msg = f"<br>{self.tool.removeprefix('tool')}%负载的制动性能测试执行完毕,如需采集其他负载,须切换负载类型,并更换其他负载,重新执行"
self.logger("INFO", "do_brake", msg, "green")
@clibs.handle_exception
def processing(self):
time_start = time.time()
clibs.running[self.idx] = 1
if clibs.status["hmi"] != 1 or clibs.status["md"] != 1 or clibs.status["ec"] != 1:
self.logger("ERROR", "do_brake", "processing: 需要在网络设置中连接HMIModbus通信以及外部通信", "red", "NetworkError")
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")
self.logger("INFO", "do_brake", "-"*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)
self.logger("INFO", "do_brake", msg)

Some files were not shown because too many files have changed in this diff Show More