diff --git a/.gitignore b/.gitignore
index b40a6ad..0914769 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,7 @@
venv/
.idea/
**/__pycache__/
-assets/files/examples/
\ No newline at end of file
+assets/files/examples/
+assets/logs/*
+test.py
+package/*
\ No newline at end of file
diff --git a/aio.py b/aio.py
new file mode 100644
index 0000000..9ceec6a
--- /dev/null
+++ b/aio.py
@@ -0,0 +1,1022 @@
+import datetime
+import json
+import os
+import re
+import sqlite3
+import sys
+import time
+from urllib import request
+import os.path
+import matplotlib
+import matplotlib.pyplot as plt
+import pandas
+from matplotlib.widgets import Slider
+matplotlib.use('QtAgg')
+
+from PySide6.QtCore import Qt, QThread, Signal, QObject, QTimer
+from PySide6.QtGui import QTextCursor, QFont, QPixmap, QColor, QBrush
+from PySide6.QtWidgets import QMessageBox, QCheckBox, QSplashScreen, QApplication, QFrame, QLabel, QTreeWidgetItem, QFileDialog, QHeaderView, QDialog, QVBoxLayout, QPlainTextEdit
+
+import codes.common.clibs as clibs
+import codes.common.openapi as openapi
+import codes.ui.main_window as main_window
+from codes.analysis import brake, current, wavelogger, iso
+from codes.autotest import do_current, do_brake
+from codes.durable import factory_test
+
+
+class MultiWindows:
+ login_window = None
+ reset_window = None
+ main_window = None
+
+
+class ContentDialog(QDialog):
+ def __init__(self, content, parent=None):
+ super().__init__(parent)
+ self.setWindowTitle("日志详情")
+ self.setGeometry(100, 100, 700, 300)
+
+ # 设置对话框在屏幕正中间
+ self.center_on_screen()
+
+ # 创建布局
+ layout = QVBoxLayout(self)
+
+ # 创建 QPlainTextEdit 并设置为只读
+ self.plain_text_edit = QPlainTextEdit()
+ self.plain_text_edit.setReadOnly(True)
+ self.plain_text_edit.setPlainText(content)
+
+ # 添加到布局
+ layout.addWidget(self.plain_text_edit)
+
+ def center_on_screen(self):
+ # 获取屏幕尺寸
+ screen_geometry = QApplication.primaryScreen().geometry()
+ screen_width = screen_geometry.width()
+ screen_height = screen_geometry.height()
+
+ # 获取对话框尺寸
+ dialog_width = self.width()
+ dialog_height = self.height()
+
+ # 计算位置
+ x = (screen_width - dialog_width) // 2
+ y = (screen_height - dialog_height) // 2
+
+ # 设置位置
+ self.move(x, y)
+
+
+class RunProg(QObject):
+ completed = Signal(tuple)
+
+ def __init__(self):
+ super().__init__()
+
+ def program(self, action): # 0: prog 1: idx
+ prog, idx, reserved = action
+ if idx in range(7):
+ run = prog.processing
+ elif idx == -1:
+ run = prog.net_conn
+ elif idx == -97:
+ run = prog.do_draw
+ elif idx == -98 or idx == -99:
+ run = prog
+
+ try:
+ ret = run()
+ self.completed.emit((True, prog, ret, "", idx, reserved)) # 运行是否成功/返回值/报错信息/idx
+ except Exception as err:
+ self.completed.emit((False, None, None, err, idx, reserved)) # 运行是否成功/返回值/报错信息/idx
+
+
+class MainWindow(main_window.Ui_MainWindow):
+ action = Signal(tuple)
+
+ def __init__(self):
+ super(MainWindow, self).__init__()
+ self.close_on_net_error = None
+ self.is_searching = False
+ self.setupUi(self)
+ self.predoes()
+
+ def predoes(self):
+ # ========================= treeview init =========================
+ self.treew_log.header().setFont(QFont("Arial", 12, QFont.Weight.Bold))
+ header = self.treew_log.header()
+ for i in range(self.treew_log.columnCount()):
+ header.setSectionResizeMode(i, QHeaderView.ResizeMode.ResizeToContents)
+ # ========================= clibs =========================
+ self.setup_statusbar()
+ # ========================= 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, reserved):
+ if idx != -98 and idx != -97:
+ self.tw_docs.setCurrentIndex(0)
+ if idx != -99 and idx != -98:
+ 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, reserved))
+
+ def w2t(self, msg, color="black"):
+ self.pte_output.appendHtml(f"{msg}")
+ cursor = self.pte_output.textCursor()
+ cursor.movePosition(QTextCursor.End)
+ self.pte_output.setTextCursor(cursor)
+ self.pte_output.ensureCursorVisible()
+ self.update()
+
+ def get_checkbox_states(self):
+ cb_durable_states = {}
+ container = self.sa_durable.widget()
+ for checkbox in container.findChildren(QCheckBox):
+ cb_durable_states[checkbox.text()] = checkbox.isChecked()
+ return cb_durable_states
+
+ def prog_start(self):
+ def prog_done(results):
+ flag, result, ret, 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: # tab: 数据处理 | func: 制动数据处理
+ 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: # tab: 数据处理 | func: 转矩数据处理
+ 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: # tab: 数据处理 | func: 激光数据处理
+ 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: # tab: 数据处理 | func: 精度数据处理
+ 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: # tab: 自动测试 | func: 制动测试
+ self.run_program_thread(do_brake.DoBrakeTest(self.le_unit_path.text(), self.cb_unit_tool.currentText()), 4, prog_done, None)
+ elif self.tw_funcs.currentIndex() == 1 and self.cb_unit_func.currentIndex() == 1: # tab: 自动测试 | func: 转矩测试
+ self.run_program_thread(do_current.DoCurrentTest(self.le_unit_path.text(), self.cb_unit_tool.currentText()), 5, prog_done, None)
+ elif self.tw_funcs.currentIndex() == 2: # tab: 耐久采集 | func: 场景数据持久化
+ self.run_program_thread(factory_test.DoFactoryTest(self.le_durable_path.text(), self.le_durable_interval.text(), self.get_checkbox_states()), 6, prog_done, None)
+
+ 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 = QFileDialog.getExistingDirectory()
+ tab_index = self.tw_funcs.currentIndex()
+ if dir_path:
+ idx_dict[tab_index].setText(dir_path)
+
+ def curve_draw(self):
+ output = Signal(str, str)
+ procs = self.get_checkbox_states()
+ dir_path = self.le_durable_path.text()
+ curve_map = {
+ "周期内平均转矩": ["device_servo_trq_feedback", ],
+ "周期内最大速度": ["hw_joint_vel_feedback", ],
+ }
+ ylabels = {"周期内最大速度": "速度(rad/s)", "周期内平均转矩": "转矩(Nm)"}
+ 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
+
+ if not os.path.exists(dir_path):
+ self.w2t(f"数据文件夹{dir_path}不存在,请确认后重试......", "red")
+ return
+ for proc_name, is_enabled in procs.items():
+ if is_enabled:
+ break
+ else:
+ self.w2t(f"需要选择至少一个功能,才能继续绘图......", "red")
+ return
+
+ _, files = clibs.traversal_files(dir_path, output)
+ csv_files = []
+ for file in files:
+ if file.endswith(".csv"):
+ csv_files.append(file)
+
+ if len(csv_files) == 0:
+ self.w2t("程序未开始运行,暂无数据可以展示......", "red")
+ return
+
+ for proc_name, is_enabled in procs.items():
+ if not is_enabled:
+ continue
+
+ title = proc_name
+ ylabel = ylabels[proc_name]
+ fig, axes = plt.subplots(figsize=(10, 4.5), dpi=100)
+ for curve in curve_map[proc_name]:
+ cols = [f"{curve}_{i}" for i in range(6)]
+ cols.insert(0, "time")
+
+ try:
+ df = pandas.read_csv(f"{dir_path}/{proc_name}.csv")
+ except Exception as err:
+ self.w2t(f"获取{dir_path}/{proc_name}.csv文件数据失败,需确认是否存在该文件......", "red")
+ self.w2t(f"报错信息:{err}", "red")
+ return
+
+ for i in range((len(cols) - 1) // 6):
+ plt.plot(df[cols[1]], label=f"一轴{curve_map[proc_name][i]}")
+ plt.plot(df[cols[2]], label=f"二轴{curve_map[proc_name][i]}")
+ plt.plot(df[cols[3]], label=f"三轴{curve_map[proc_name][i]}")
+ plt.plot(df[cols[4]], label=f"四轴{curve_map[proc_name][i]}")
+ plt.plot(df[cols[5]], label=f"五轴{curve_map[proc_name][i]}")
+ plt.plot(df[cols[6]], label=f"六轴{curve_map[proc_name][i]}")
+ axes.set_title(title)
+ axes.set_ylabel(ylabel)
+ 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)
+
+ plt.show()
+
+ def durable_cb_change(self):
+ stat = True if self.cb_durable_total.isChecked() else False
+ for cb in self.sa_durable.widget().findChildren(QCheckBox):
+ cb.setChecked(stat)
+
+ def display_tree_content(self, records):
+ for record in records:
+ item = QTreeWidgetItem(self.treew_log)
+ for i in range(self.treew_log.columnCount()):
+ item.setText(i, str(record[i]))
+ self.treew_log.addTopLevelItem(item)
+ color_map = {"DEBUG": QColor(220, 220, 220), "INFO": QColor(144, 238, 144), "WARNING": QColor(255, 240, 210), "ERROR": QColor(255, 220, 220)}
+ brush = QBrush(color_map[record[2].upper()])
+ for i in range(self.treew_log.columnCount()):
+ item.setBackground(i, brush)
+
+ last_item = self.treew_log.topLevelItem(self.treew_log.topLevelItemCount() - 1)
+ self.treew_log.scrollToItem(last_item)
+
+ def prog_done_pre(self, results):
+ flag, result, ret, error, idx, network = results
+ if ret is None:
+ return
+
+ pages_all, current_page, records = ret
+ self.treew_log.clear()
+ self.display_tree_content(records)
+ self.label_page.setText(f"{current_page}/{pages_all}")
+
+ def pre_page(self):
+ @clibs.db_lock
+ def do_pre():
+ if self.is_searching is False:
+ first_id = self.treew_log.topLevelItem(0).text(0)
+ end = int(first_id)-1 if int(first_id)-1 > 0 else None
+ start = int(first_id)-100 if int(first_id)-100 > 0 else 0
+ if end is None:
+ return
+
+ clibs.cursor.execute(f"SELECT * FROM logs WHERE id BETWEEN {start} AND {end}")
+ records = clibs.cursor.fetchall()
+ clibs.cursor.execute("SELECT COUNT(id) FROM logs")
+ len_records = clibs.cursor.fetchone()[0]
+ pages_all = len_records // 100 if len_records % 100 == 0 else len_records // 100 + 1
+ current_page = int(end) // 100 if int(end) % 100 == 0 else int(end) // 100 + 1
+ return pages_all, current_page, records
+
+ elif self.is_searching is True:
+ current_page, pages_all = self.label_page.text().split("/")
+ if int(current_page)-1 == 0:
+ return
+
+ current_page = int(current_page) - 1
+ first_row = []
+ for i in range(self.treew_log.columnCount()):
+ if i == 0:
+ first_row.append(int(self.treew_log.topLevelItem(0).text(i)))
+ else:
+ first_row.append(self.treew_log.topLevelItem(0).text(i))
+
+ index_end = clibs.search_records.index(tuple(first_row))
+ if index_end == 0:
+ return
+ elif index_end <= 100:
+ records = clibs.search_records[:index_end]
+ else:
+ records = clibs.search_records[index_end-100:index_end]
+ return pages_all, current_page, records
+
+ self.run_program_thread(do_pre, -98, self.prog_done_pre, None)
+
+ def prog_done_realtime(self, results):
+ flag, result, ret, error, idx, network = results
+ pages_all, records = ret
+
+ self.label_page.setText(f"{pages_all}/{pages_all}")
+ self.treew_log.clear()
+ self.display_tree_content(records)
+ self.is_searching = False
+ clibs.search_records = None
+
+ def realtime_page(self):
+ @clibs.db_lock
+ def do_realtime():
+ clibs.cursor.execute("SELECT COUNT(id) from logs")
+ len_records = clibs.cursor.fetchone()[0]
+ pages_all = len_records // 100 if len_records % 100 == 0 else len_records // 100 + 1
+ remainder = len_records % 100 if len_records % 100 != 0 else 100
+ end = len_records
+ start = len_records - remainder + 1 if len_records - remainder > 0 else 0
+ clibs.cursor.execute(f"select * from logs where id between {start} and {end}")
+ records = clibs.cursor.fetchall()
+ return pages_all, records
+
+ self.run_program_thread(do_realtime, -98, self.prog_done_realtime, None)
+
+ def prog_done_next(self, results):
+ flag, result, ret, error, idx, network = results
+ if ret is None:
+ return
+ pages_all, current_page, records = ret
+ self.treew_log.clear()
+ self.display_tree_content(records)
+ self.label_page.setText(f"{current_page}/{pages_all}")
+
+ def next_page(self):
+ @clibs.db_lock
+ def do_next():
+ clibs.cursor.execute("select count(id) from logs")
+ len_records = clibs.cursor.fetchone()[0]
+ if self.is_searching is False:
+ line_number = self.treew_log.topLevelItemCount()
+ last_id = int(self.treew_log.topLevelItem(line_number-1).text(0))
+ start = last_id + 1 if last_id % 100 == 0 else last_id - last_id % 100 + 1
+ end = int(last_id) + 100
+ if int(start) <= len_records:
+ clibs.cursor.execute(f"select * from logs where id between {start} and {end}")
+ records = clibs.cursor.fetchall()
+ pages_all = len_records // 100 if len_records % 100 == 0 else len_records // 100 + 1
+ current_page = int(start) // 100 if int(start) % 100 == 0 else int(start) // 100 + 1
+ return pages_all, current_page, records
+
+ elif self.is_searching is True:
+ current_page, pages_all = self.label_page.text().split("/")
+ if pages_all == current_page:
+ return
+
+ current_page = int(current_page) + 1
+ last_row = []
+ for i in range(self.treew_log.columnCount()):
+ if i == 0:
+ last_row.append(int(self.treew_log.topLevelItem(self.treew_log.topLevelItemCount()-1).text(i)))
+ else:
+ last_row.append(self.treew_log.topLevelItem(self.treew_log.topLevelItemCount()-1).text(i))
+ index_start = clibs.search_records.index(tuple(last_row)) + 1
+ if index_start > len(clibs.search_records):
+ return
+ elif index_start + 100 > len(clibs.search_records):
+ records = clibs.search_records[index_start:]
+ else:
+ records = clibs.search_records[index_start:index_start+100]
+ return pages_all, current_page, records
+
+ self.run_program_thread(do_next, -98, self.prog_done_next, None)
+
+ def show_item_content(self, item, column):
+ content = " | ".join([item.text(i) for i in range(self.treew_log.columnCount())])
+ dialog = ContentDialog(content, self)
+ dialog.exec()
+
+ def switch_log_tab(self, index):
+ if index == 1: # 切换到日志tab页时,自动执行实时日志功能
+ self.realtime_page()
+
+ def prog_done_search(self, results):
+ msg = "可单独查询 ID/Level/Module,也可以按照顺序组合查询指定条件,ID 范围使用 - 分隔,多个 Level 或者 Module 使用 : 分割,所有查询条件以 / 分隔并包含在 [] 内;如有关键字查询,则置于条件查询之后!"
+ flag, result, ret, error, idx, network = results
+ if ret is None:
+ QMessageBox.warning(self, "查询条件错误", msg)
+ self.realtime_page()
+ return
+ if ret == "nothing":
+ return
+
+ pages_all, records = ret
+ self.treew_log.clear()
+ self.display_tree_content(records)
+ self.label_page.setText(f"{pages_all}/{pages_all}")
+ self.is_searching = True
+
+ def search_keyword(self):
+ @clibs.db_lock
+ def do_search():
+ one_more = "!@#123asd"
+ kw = self.le_docs_search.text().strip()
+ if kw == "":
+ return "nothing"
+
+ match = re.search("^\\[.*]", kw)
+ if match:
+ condition = match.group().removeprefix("[").removesuffix("]").strip()
+ f_text = f"%{kw.removeprefix(match.group()).strip()}%"
+ if condition == "" and f_text == "%%":
+ return
+ elif condition == "" and f_text != "%%":
+ clibs.cursor.execute(f"SELECT * FROM logs WHERE content LIKE '{f_text}'")
+ elif condition != "" and f_text == "%%":
+ conditions = condition.split("/")
+ if len(conditions) == 1: # 可能是id/level(s)/module(s),任意其一
+ c1 = conditions[0]
+ if c1.isdigit() and int(c1) > 0: # 单独一个数字
+ clibs.cursor.execute(f"SELECT * FROM logs WHERE id = {int(c1)}")
+ elif "-" in c1 and len(c1.split("-")) == 2 and c1.split("-")[0].isdigit() and c1.split("-")[1].isdigit() and int(c1.split("-")[1]) - int(c1.split("-")[0]) > 0 and int(c1.split("-")[0]) > 0: # 1-4 这种格式
+ start = int(c1.split("-")[0])
+ end = int(c1.split("-")[1])
+ clibs.cursor.execute(f"SELECT * FROM logs WHERE id BETWEEN {start} AND {end}")
+ else:
+ for level in c1.split(":"):
+ if level.strip().upper() not in clibs.levels:
+ is_level = False
+ break
+ else:
+ is_level = True
+
+ if is_level: # 是告警等级
+ levels = tuple(level.strip().upper() for level in c1.split(":"))
+ levels = (*levels, one_more)
+ clibs.cursor.execute(f"SELECT * FROM logs WHERE level IN {levels}")
+ else: # 是模块
+ modules = tuple(module.strip() for module in c1.split(":"))
+ modules = (*modules, one_more)
+ clibs.cursor.execute(f"SELECT * FROM logs WHERE module IN {modules}")
+
+ elif len(conditions) == 2: # 可能是id/level(s)/module(s),任意两个的组合,有顺序
+ c1, c2 = conditions
+ if c1.isdigit() and int(c1) > 0: # 单独一个数字
+ for level in c2.split(":"):
+ if level.strip().upper() not in clibs.levels:
+ is_level = False
+ break
+ else:
+ is_level = True
+
+ if is_level: # 是告警等级
+ levels = tuple(level.strip().upper() for level in c2.split(":"))
+ levels = (*levels, one_more)
+ clibs.cursor.execute(f"SELECT * FROM logs WHERE id = {int(c1)} AND level IN {levels}")
+ else: # 是模块
+ modules = tuple(module.strip() for module in c2.split(":"))
+ modules = (*modules, one_more)
+ clibs.cursor.execute(f"SELECT * FROM logs WHERE id = {int(c1)} AND module IN {modules}")
+ elif "-" in c1 and len(c1.split("-")) == 2 and c1.split("-")[0].isdigit() and c1.split("-")[1].isdigit() and int(c1.split("-")[1]) - int(c1.split("-")[0]) > 0 and int(c1.split("-")[0]) > 0: # 1-4 这种格式
+ start = int(c1.split("-")[0])
+ end = int(c1.split("-")[1])
+ for level in c2.split(":"):
+ if level.strip().upper() not in clibs.levels:
+ is_level = False
+ break
+ else:
+ is_level = True
+
+ if is_level: # 是告警等级
+ levels = tuple(level.strip().upper() for level in c2.split(":"))
+ levels = (*levels, one_more)
+ clibs.cursor.execute(f"SELECT * FROM logs WHERE id BETWEEN {start} AND {end} AND level IN {levels}")
+ else: # 是模块
+ modules = tuple(module.strip() for module in c2.split(":"))
+ modules = (*modules, one_more)
+ clibs.cursor.execute(f"SELECT * FROM logs WHERE id BETWEEN {start} AND {end} AND module IN {modules}")
+ else: # c1是等级,c2是模块
+ for level in c1.split(":"):
+ if level.strip().upper() not in clibs.levels:
+ return
+
+ levels = tuple(level.strip().upper() for level in c1.split(":"))
+ levels = (*levels, one_more)
+ modules = tuple(module.strip() for module in c2.split(":"))
+ modules = (*modules, one_more)
+ clibs.cursor.execute(f"SELECT * FROM logs WHERE level IN {levels} AND module IN {modules}")
+
+ elif len(conditions) == 3: # 依次为id/level(s)/module(s)
+ c1, c2, c3 = conditions
+ for level in c2.split(":"):
+ if level.strip().upper() not in clibs.levels:
+ return
+ levels = tuple(level.strip().upper() for level in c2.split(":"))
+ levels = (*levels, one_more)
+ modules = tuple(module.strip() for module in c3.split(":"))
+ modules = (*modules, one_more)
+
+ if c1.isdigit() and int(c1) > 0: # 单独一个数字
+ clibs.cursor.execute(f"SELECT * FROM logs WHERE id = {int(c1)} AND level IN {levels} AND module IN {modules}")
+ elif "-" in c1 and len(c1.split("-")) == 2 and c1.split("-")[0].isdigit() and c1.split("-")[1].isdigit() and int(c1.split("-")[1]) - int(c1.split("-")[0]) > 0 and int(c1.split("-")[0]) > 0: # 1-4 这种格式
+ start = int(c1.split("-")[0])
+ end = int(c1.split("-")[1])
+ clibs.cursor.execute(f"SELECT * FROM logs WHERE id BETWEEN {start} AND {end} AND level IN {levels} AND module IN {modules}")
+ else:
+ return
+ else:
+ return
+ elif condition != "" and f_text != "%%": # 和上面基本一样,只不过加一个f_text的条件筛选
+ conditions = condition.split("/")
+ if len(conditions) == 1: # 可能是id/level(s)/module(s),任意其一
+ c1 = conditions[0]
+ if c1.isdigit() and int(c1) > 0: # 单独一个数字
+ clibs.cursor.execute(f"SELECT * FROM logs WHERE id = {int(c1)} AND content LIKE '{f_text}'")
+ elif "-" in c1 and len(c1.split("-")) == 2 and c1.split("-")[0].isdigit() and c1.split("-")[
+ 1].isdigit() and int(c1.split("-")[1]) - int(c1.split("-")[0]) > 0 and int(
+ c1.split("-")[0]) > 0: # 1-4 这种格式
+ start = int(c1.split("-")[0])
+ end = int(c1.split("-")[1])
+ clibs.cursor.execute(f"SELECT * FROM logs WHERE id BETWEEN {start} AND {end} AND content LIKE '{f_text}'")
+ else:
+ for level in c1.split(":"):
+ if level.strip().upper() not in clibs.levels:
+ is_level = False
+ break
+ else:
+ is_level = True
+
+ if is_level: # 是告警等级
+ levels = tuple(level.strip().upper() for level in c1.split(":"))
+ levels = (*levels, one_more)
+ clibs.cursor.execute(f"SELECT * FROM logs WHERE level IN {levels} AND content LIKE '{f_text}'")
+ else: # 是模块
+ modules = tuple(module.strip() for module in c1.split(":"))
+ modules = (*modules, one_more)
+ clibs.cursor.execute(f"SELECT * FROM logs WHERE module IN {modules} AND content LIKE '{f_text}'")
+
+ elif len(conditions) == 2: # 可能是id/level(s)/module(s),任意两个的组合,有顺序
+ c1, c2 = conditions
+ if c1.isdigit() and int(c1) > 0: # 单独一个数字
+ for level in c2.split(":"):
+ if level.strip().upper() not in clibs.levels:
+ is_level = False
+ break
+ else:
+ is_level = True
+
+ if is_level: # 是告警等级
+ levels = tuple(level.strip().upper() for level in c2.split(":"))
+ levels = (*levels, one_more)
+ clibs.cursor.execute(f"SELECT * FROM logs WHERE id = {int(c1)} AND level IN {levels} AND content LIKE '{f_text}'")
+ else: # 是模块
+ modules = tuple(module.strip() for module in c2.split(":"))
+ modules = (*modules, one_more)
+ clibs.cursor.execute(f"SELECT * FROM logs WHERE id = {int(c1)} AND module IN {modules} AND content LIKE '{f_text}'")
+ elif "-" in c1 and len(c1.split("-")) == 2 and c1.split("-")[0].isdigit() and c1.split("-")[
+ 1].isdigit() and int(c1.split("-")[1]) - int(c1.split("-")[0]) > 0 and int(
+ c1.split("-")[0]) > 0: # 1-4 这种格式
+ start = int(c1.split("-")[0])
+ end = int(c1.split("-")[1])
+ for level in c2.split(":"):
+ if level.strip().upper() not in clibs.levels:
+ is_level = False
+ break
+ else:
+ is_level = True
+
+ if is_level: # 是告警等级
+ levels = tuple(level.strip().upper() for level in c2.split(":"))
+ levels = (*levels, one_more)
+ clibs.cursor.execute(
+ f"SELECT * FROM logs WHERE id BETWEEN {start} AND {end} AND level IN {levels} AND content LIKE '{f_text}'")
+ else: # 是模块
+ modules = tuple(module.strip() for module in c2.split(":"))
+ modules = (*modules, one_more)
+ clibs.cursor.execute(
+ f"SELECT * FROM logs WHERE id BETWEEN {start} AND {end} AND module IN {modules} AND content LIKE '{f_text}'")
+ else: # c1是等级,c2是模块
+ for level in c1.split(":"):
+ if level.strip().upper() not in clibs.levels:
+ return
+
+ levels = tuple(level.strip().upper() for level in c1.split(":"))
+ levels = (*levels, one_more)
+ modules = tuple(module.strip() for module in c2.split(":"))
+ modules = (*modules, one_more)
+ clibs.cursor.execute(f"SELECT * FROM logs WHERE level IN {levels} AND module IN {modules} AND content LIKE '{f_text}'")
+
+ elif len(conditions) == 3: # 依次为id/level(s)/module(s)
+ c1, c2, c3 = conditions
+ for level in c2.split(":"):
+ if level.strip().upper() not in clibs.levels:
+ return
+ levels = tuple(level.strip().upper() for level in c2.split(":"))
+ levels = (*levels, one_more)
+ modules = tuple(module.strip() for module in c3.split(":"))
+ modules = (*modules, one_more)
+
+ if c1.isdigit() and int(c1) > 0: # 单独一个数字
+ clibs.cursor.execute(
+ f"SELECT * FROM logs WHERE id = {int(c1)} AND level IN {levels} AND module IN {modules} AND content LIKE '{f_text}'")
+ elif "-" in c1 and len(c1.split("-")) == 2 and c1.split("-")[0].isdigit() and c1.split("-")[
+ 1].isdigit() and int(c1.split("-")[1]) - int(c1.split("-")[0]) > 0 and int(
+ c1.split("-")[0]) > 0: # 1-4 这种格式
+ start = int(c1.split("-")[0])
+ end = int(c1.split("-")[1])
+ clibs.cursor.execute(
+ f"SELECT * FROM logs WHERE id BETWEEN {start} AND {end} AND level IN {levels} AND module IN {modules} AND content LIKE '{f_text}'")
+ else:
+ return
+ else:
+ return
+ else:
+ f_text = f"%{kw}%"
+ clibs.cursor.execute(f"SELECT * FROM logs WHERE content LIKE '{f_text}'")
+
+ clibs.search_records = clibs.cursor.fetchall()
+ len_records = len(clibs.search_records)
+ pages_all = len_records // 100 if len_records % 100 == 0 else len_records // 100 + 1
+ remainder = len_records % 100
+ records = clibs.search_records[-1 * remainder:]
+
+ return pages_all, records
+
+ self.run_program_thread(do_search, -98, self.prog_done_search, None)
+
+ def prog_done_conn(self, results):
+ self.btn_hmi_conn.setDisabled(False)
+ self.btn_md_conn.setDisabled(False)
+ self.btn_ec_conn.setDisabled(False)
+
+ flag, result, ret, 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):
+ self.btn_hmi_conn.setDisabled(False)
+ self.btn_md_conn.setDisabled(False)
+ self.btn_ec_conn.setDisabled(False)
+
+ flag, result, ret, 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):
+ self.btn_hmi_conn.setDisabled(True)
+ 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
+
+ self.btn_md_conn.setDisabled(True)
+ 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
+
+ self.btn_ec_conn.setDisabled(True)
+ 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 prog_done_hmi_send(self, results):
+ _, result, ret, error, idx, (msg_id, flag) = results
+ records = clibs.c_hr.get_from_id(msg_id)
+ for record in records:
+ if "请求发送成功" not in record[0]:
+ self.pte_him_recv.clear()
+ response = eval(record[0]) if flag == 0 else json.loads(record[0])
+ self.pte_him_recv.appendPlainText(json.dumps(response, indent=4, separators=(",", ":")))
+ else:
+ self.btn_hmi_send.setDisabled(False)
+
+ def hmi_send(self):
+ def hmi_send_thread():
+ nonlocal hmi_dict, cmd_json, flag
+ if flag == 0:
+ clibs.c_hr.c.send(clibs.c_hr.package(cmd_json))
+ clibs.c_hr.logger("DEBUG", "aio", f"hmi: [send] 老协议请求发送成功 {cmd_json}")
+ elif flag == 1:
+ clibs.c_hr.c_xs.send(clibs.c_hr.package_xs(hmi_dict))
+ clibs.c_hr.logger("DEBUG", "aio", f"hmi: xService请求发送成功 {cmd_json}")
+
+ if clibs.status["hmi"] == 0:
+ QMessageBox.critical(self, "错误", "使用该功能之前,需要先打开HMI连接!")
+ return
+ if self.pte_hmi_send.toPlainText() == "":
+ return
+
+ self.btn_hmi_send.setDisabled(True)
+ hmi_dict = json.loads(self.pte_hmi_send.toPlainText())
+ t = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f")
+ msg_id = hmi_dict["id"] = "@".join([hmi_dict["id"].split("@")[0], t])
+ self.pte_hmi_send.clear()
+ self.pte_hmi_send.appendPlainText(json.dumps(hmi_dict, indent=4, separators=(",", ":")))
+ flag = hmi_dict["p_type"]
+ del hmi_dict["p_type"]
+ cmd_json = json.dumps(hmi_dict, separators=(",", ":"))
+
+ self.run_program_thread(hmi_send_thread, -99, self.prog_done_hmi_send, (msg_id, flag))
+
+ def md_send(self):
+ if clibs.status["md"] == 0:
+ QMessageBox.critical(self, "连接错误", "使用该功能之前,需要先打开 Modbus 连接!")
+ return
+ if self.pte_md_send.toPlainText() == "":
+ return
+
+ self.pte_md_recv.clear()
+ content = self.pte_md_send.toPlainText().split("\n")
+ if content[0].strip().startswith("sta"):
+ for item in content[1:]:
+ addr = int(item.split(":")[0].strip())
+ count = int(item.split(":")[1].strip())
+ value_type = item.split(":")[2].strip()
+ if value_type == "bool":
+ try:
+ result = clibs.c_md.c.read_holding_registers(addr, count=count).registers[0]
+ self.pte_md_recv.appendPlainText(str(result))
+ except Exception as err:
+ self.pte_md_recv.appendPlainText(f"获取失败:{err}")
+ return
+ elif content[0].strip().startswith("ctrl"):
+ for item in content[1:]:
+ addr = int(item.split(":")[0].strip())
+ value = int(item.split(":")[1].strip())
+ try:
+ clibs.c_md.c.write_register(addr, value)
+ time.sleep(clibs.INTERVAL/4)
+ except Exception as err:
+ self.pte_md_recv.appendPlainText(f"操作失败:{err}")
+ return
+ else:
+ self.pte_md_recv.appendPlainText("操作成功!")
+ else:
+ QMessageBox.critical(self, "格式错误", "非法的发送内容,自定义发送需参考已有的格式!")
+
+ def ec_send(self):
+ if clibs.status["ec"] == 0:
+ QMessageBox.critical(self, "错误", "使用该功能之前,需要先打开MD连接!")
+ return
+ if self.pte_ec_send.toPlainText() == "":
+ return
+
+ self.pte_ec_recv.clear()
+ cmd = self.pte_ec_send.toPlainText().strip()
+ try:
+ clibs.c_ec.s_string(cmd)
+ time.sleep(clibs.INTERVAL/2)
+ result = clibs.c_ec.r_string(cmd)
+ self.pte_ec_recv.appendPlainText(str(result))
+ except Exception as err:
+ self.pte_ec_recv.appendPlainText(f"操作失败:{err}")
+
+ def hmi_cb_change(self):
+ cmd = self.cb_hmi_cmd.currentText()
+ self.pte_hmi_send.clear()
+ self.pte_him_recv.clear()
+ with open(f"assets/files/protocols/hmi/{cmd}.json", mode="r", encoding="utf-8") as f_hmi:
+ hmi_dict = json.load(f_hmi)
+ t = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f")
+ hmi_dict["id"] = "@".join([cmd, t])
+ self.pte_hmi_send.appendPlainText(json.dumps(hmi_dict, indent=4, separators=(",", ":")))
+
+ def md_cb_change(self):
+ cmd = self.cb_md_cmd.currentText()
+ self.pte_md_send.clear()
+ self.pte_md_recv.clear()
+ self.pte_md_send.appendPlainText(cmd)
+ with open(f"assets/files/protocols/md/{cmd}.txt", mode="r", encoding="utf-8") as f_md:
+ c_send = f_md.read()
+ self.pte_md_send.appendPlainText(c_send)
+
+ def ec_cb_change(self):
+ cmd = self.cb_ec_cmd.currentText()
+ self.pte_ec_send.clear()
+ self.pte_ec_recv.clear()
+ with open(f"assets/files/protocols/ec/{cmd}.txt", mode="r", encoding="utf-8") as f_md:
+ c_send = f_md.read()
+ self.pte_ec_send.appendPlainText(c_send)
+
+ 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:
+ os.chdir(clibs.log_path)
+ t = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
+ disk_conn = sqlite3.connect(f"log_{t}.db", isolation_level=None, check_same_thread=False, cached_statements=256)
+
+ clibs.conn.backup(target=disk_conn, pages=1, progress=None)
+
+ _, logs = clibs.traversal_files(".", None)
+ logs.sort()
+ while len(logs) > 10:
+ _ = logs.pop(0)
+ os.remove(_)
+
+ 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")
+
+ event.accept()
+ else:
+ event.ignore()
+
+ def setup_statusbar(self):
+ with open(f"assets/files/version/local_vers", mode="r", encoding="utf-8") as f_local:
+ local_vers = f_local.read().strip()
+ l_version, update = local_vers.split("@")
+ vers_info = f" v{l_version} Update@{update}"
+ with open(f"assets/files/version/server_vers", mode="r", encoding="utf-8") as f_server:
+ server_vers = f_server.read().strip()
+
+ update_label = QLabel()
+ version_label = QLabel()
+ self.statusbar.addWidget(version_label, 0)
+ self.statusbar.addPermanentWidget(update_label, 0) # 添加到右侧
+ if local_vers == server_vers:
+ update_label.setText('
当前是最新版本,继续保持! ')
+ elif local_vers > server_vers:
+ pass
+ elif local_vers < server_vers:
+ update_label.setText(f'''
v{server_vers.split('@')[0]}已经发布,尽快更新至最新版本! ''')
+
+ version_label.setText(f' {vers_info}')
+ update_label.setOpenExternalLinks(True) # 允许超链接在浏览器中打开
+ # update_label.setAlignment(Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignRight)
+ update_label.setStyleSheet("border: none;")
+ update_label.setFrameShape(QFrame.Shape.NoFrame)
+ update_label.setFrameShadow(QFrame.Shadow.Plain)
+ self.close_on_net_error = False
+
+
+class InitWork(QThread):
+ completed = Signal(str)
+
+ def program(self, action):
+ url_vers, server_vers = "https://www.rustle.cc/server_vers", ""
+ try:
+ headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 Firefox/23.0'}
+ req = request.Request(url_vers, headers=headers)
+ response = request.urlopen(req, timeout=clibs.INTERVAL * 10)
+ server_vers = response.read().decode("utf-8").strip()
+ with open("assets/files/version/server_vers", mode="w", encoding="utf-8") as f_server:
+ f_server.write(server_vers)
+ self.completed.emit("true")
+ except Exception as err:
+ print(f"err = {err}")
+ clibs.cursor.close()
+ clibs.conn.close()
+ self.completed.emit("false")
+
+
+class SplashScreen(QApplication):
+ action = Signal(int)
+
+ def __init__(self, argv):
+ super().__init__(argv)
+ self.window = None
+
+ pixmap = QPixmap("./assets/media/splash.png")
+ self.splash = QSplashScreen(pixmap, Qt.WindowType.WindowStaysOnTopHint)
+ scaled_pixmap = pixmap.scaled(800, 400, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation)
+ self.splash.setPixmap(scaled_pixmap)
+ self.splash.setEnabled(False) # 禁用交互
+ self.splash.setFont(QFont("Arial", 12))
+ self.splash.show()
+ self.splash.showMessage("正在加载资源.....", Qt.AlignmentFlag.AlignBottom | Qt.AlignmentFlag.AlignHCenter, Qt.GlobalColor.white)
+
+ self.t = QThread(self)
+ self.run = InitWork()
+ self.run.moveToThread(self.t)
+ self.run.completed.connect(self.prog_done)
+ self.action.connect(self.run.program)
+ self.t.start()
+ self.action.emit(1)
+
+ def prog_done(self, result):
+ if result == "false" or result == "":
+ self.splash.showMessage("网络错误,无法连接至服务器,确认当前网络环境是否可以访问www.rustle.cc......", Qt.AlignmentFlag.AlignBottom | Qt.AlignmentFlag.AlignHCenter, Qt.GlobalColor.white)
+ time.sleep(clibs.INTERVAL*2)
+ self.splash.close()
+ sys.exit()
+ elif result == "true":
+ self.window = MainWindow()
+ self.splash.showMessage("初始化完成,即将进入主界面......", Qt.AlignmentFlag.AlignBottom | Qt.AlignmentFlag.AlignHCenter, Qt.GlobalColor.white)
+ QTimer.singleShot(1000, lambda: (self.splash.finish(self.window), self.window.show()))
+
+
+if __name__ == '__main__':
+ app = SplashScreen(sys.argv)
+ sys.exit(app.exec())
diff --git a/assets/files/protocols/ec/motor_off.txt b/assets/files/protocols/ec/motor_off.txt
new file mode 100644
index 0000000..78e4452
--- /dev/null
+++ b/assets/files/protocols/ec/motor_off.txt
@@ -0,0 +1 @@
+motor_off
\ No newline at end of file
diff --git a/assets/files/protocols/ec/motor_on.txt b/assets/files/protocols/ec/motor_on.txt
new file mode 100644
index 0000000..b489817
--- /dev/null
+++ b/assets/files/protocols/ec/motor_on.txt
@@ -0,0 +1 @@
+motor_on
\ No newline at end of file
diff --git a/assets/files/protocols/ec/motor_on_state.txt b/assets/files/protocols/ec/motor_on_state.txt
new file mode 100644
index 0000000..614bc7c
--- /dev/null
+++ b/assets/files/protocols/ec/motor_on_state.txt
@@ -0,0 +1 @@
+motor_on_state
\ No newline at end of file
diff --git a/assets/files/protocols/ec/operating_mode.txt b/assets/files/protocols/ec/operating_mode.txt
new file mode 100644
index 0000000..365cf9c
--- /dev/null
+++ b/assets/files/protocols/ec/operating_mode.txt
@@ -0,0 +1 @@
+operating_mode
\ No newline at end of file
diff --git a/assets/files/protocols/ec/robot_running_state.txt b/assets/files/protocols/ec/robot_running_state.txt
new file mode 100644
index 0000000..871016b
--- /dev/null
+++ b/assets/files/protocols/ec/robot_running_state.txt
@@ -0,0 +1 @@
+robot_running_state
\ No newline at end of file
diff --git a/assets/files/protocols/ec/set_do.txt b/assets/files/protocols/ec/set_do.txt
new file mode 100644
index 0000000..e2e2db5
--- /dev/null
+++ b/assets/files/protocols/ec/set_do.txt
@@ -0,0 +1 @@
+set_do:DO4_0,true
\ No newline at end of file
diff --git a/assets/files/protocols/ec/switch_mode_auto.txt b/assets/files/protocols/ec/switch_mode_auto.txt
new file mode 100644
index 0000000..018094d
--- /dev/null
+++ b/assets/files/protocols/ec/switch_mode_auto.txt
@@ -0,0 +1 @@
+switch_mode:auto
\ No newline at end of file
diff --git a/assets/files/protocols/ec/switch_mode_manual.txt b/assets/files/protocols/ec/switch_mode_manual.txt
new file mode 100644
index 0000000..6da1fb2
--- /dev/null
+++ b/assets/files/protocols/ec/switch_mode_manual.txt
@@ -0,0 +1 @@
+switch_mode:manual
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/collision.get_params.json b/assets/files/protocols/hmi/collision.get_params.json
index 62b0a45..55c7d1a 100644
--- a/assets/files/protocols/hmi/collision.get_params.json
+++ b/assets/files/protocols/hmi/collision.get_params.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "safety",
- "command": "collision.get_params"
+ "command": "collision.get_params",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/collision.set_params.json b/assets/files/protocols/hmi/collision.set_params.json
index 813f7ca..c3fe0bc 100644
--- a/assets/files/protocols/hmi/collision.set_params.json
+++ b/assets/files/protocols/hmi/collision.set_params.json
@@ -2,5 +2,6 @@
"id": "xxxxxxxxxxx",
"module": "safety",
"command": "collision.set_params",
- "data": null
+ "data": null,
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/collision.set_state.json b/assets/files/protocols/hmi/collision.set_state.json
index 04bfbb5..628dac4 100644
--- a/assets/files/protocols/hmi/collision.set_state.json
+++ b/assets/files/protocols/hmi/collision.set_state.json
@@ -3,5 +3,6 @@
"command": "collision.set_state",
"data": {
"collision_state": false
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/controller.get_params.json b/assets/files/protocols/hmi/controller.get_params.json
index 92dac53..1476b8f 100644
--- a/assets/files/protocols/hmi/controller.get_params.json
+++ b/assets/files/protocols/hmi/controller.get_params.json
@@ -1,5 +1,6 @@
{
"id":"xxxxxxxxxxx",
"module":"system",
- "command":"controller.get_params"
+ "command":"controller.get_params",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/controller.heart.json b/assets/files/protocols/hmi/controller.heart.json
index 27300d6..cf570aa 100644
--- a/assets/files/protocols/hmi/controller.heart.json
+++ b/assets/files/protocols/hmi/controller.heart.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "system",
- "command": "controller.heart"
+ "command": "controller.heart",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/controller.reboot.json b/assets/files/protocols/hmi/controller.reboot.json
index a0ef6da..4631a04 100644
--- a/assets/files/protocols/hmi/controller.reboot.json
+++ b/assets/files/protocols/hmi/controller.reboot.json
@@ -4,5 +4,6 @@
"command": "controller.reboot",
"data": {
"arg": 6
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/controller.set_params.json b/assets/files/protocols/hmi/controller.set_params.json
index 3759298..d433000 100644
--- a/assets/files/protocols/hmi/controller.set_params.json
+++ b/assets/files/protocols/hmi/controller.set_params.json
@@ -4,5 +4,6 @@
"command": "controller.set_params",
"data": {
"time": "2020-02-28 15:28:30"
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/device.get_params.json b/assets/files/protocols/hmi/device.get_params.json
index 62cd79d..55a246d 100644
--- a/assets/files/protocols/hmi/device.get_params.json
+++ b/assets/files/protocols/hmi/device.get_params.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "system",
- "command": "device.get_params"
+ "command": "device.get_params",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/diagnosis.get_params.json b/assets/files/protocols/hmi/diagnosis.get_params.json
index 7e57457..a1925df 100644
--- a/assets/files/protocols/hmi/diagnosis.get_params.json
+++ b/assets/files/protocols/hmi/diagnosis.get_params.json
@@ -4,5 +4,6 @@
"command": "diagnosis.get_params",
"data": {
"version": "1.4.1"
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/diagnosis.open.json b/assets/files/protocols/hmi/diagnosis.open.json
index 7fe21c2..93f3d65 100644
--- a/assets/files/protocols/hmi/diagnosis.open.json
+++ b/assets/files/protocols/hmi/diagnosis.open.json
@@ -8,5 +8,6 @@
"overrun": false,
"turn_area": false,
"delay_motion": false
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/diagnosis.save.json b/assets/files/protocols/hmi/diagnosis.save.json
index 6564248..7da8366 100644
--- a/assets/files/protocols/hmi/diagnosis.save.json
+++ b/assets/files/protocols/hmi/diagnosis.save.json
@@ -4,5 +4,6 @@
"command": "diagnosis.save",
"data": {
"save": true
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/diagnosis.set_params.json b/assets/files/protocols/hmi/diagnosis.set_params.json
index 0bb13cc..0128af4 100644
--- a/assets/files/protocols/hmi/diagnosis.set_params.json
+++ b/assets/files/protocols/hmi/diagnosis.set_params.json
@@ -6,5 +6,6 @@
"display_pdo_params": [],
"frequency": 50,
"version": "1.4.1"
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/drag.get_params.json b/assets/files/protocols/hmi/drag.get_params.json
index 9c56d28..8562a45 100644
--- a/assets/files/protocols/hmi/drag.get_params.json
+++ b/assets/files/protocols/hmi/drag.get_params.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "dynamic",
- "command": "drag.get_params"
+ "command": "drag.get_params",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/drag.set_params.json b/assets/files/protocols/hmi/drag.set_params.json
index 52b0b6f..cc7a525 100644
--- a/assets/files/protocols/hmi/drag.set_params.json
+++ b/assets/files/protocols/hmi/drag.set_params.json
@@ -6,5 +6,6 @@
"enable": true,
"space": 0,
"type": 0
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/fieldbus_device.get_params.json b/assets/files/protocols/hmi/fieldbus_device.get_params.json
index 6eca806..8f0c407 100644
--- a/assets/files/protocols/hmi/fieldbus_device.get_params.json
+++ b/assets/files/protocols/hmi/fieldbus_device.get_params.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "fieldbus",
- "command": "fieldbus_device.get_params"
+ "command": "fieldbus_device.get_params",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/fieldbus_device.load_cfg.json b/assets/files/protocols/hmi/fieldbus_device.load_cfg.json
index 79e1731..8b46df8 100644
--- a/assets/files/protocols/hmi/fieldbus_device.load_cfg.json
+++ b/assets/files/protocols/hmi/fieldbus_device.load_cfg.json
@@ -4,5 +4,6 @@
"command": "fieldbus_device.load_cfg",
"data": {
"file_name": "fieldbus_device.json"
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/fieldbus_device.set_params.json b/assets/files/protocols/hmi/fieldbus_device.set_params.json
index d6828f6..5b360b4 100644
--- a/assets/files/protocols/hmi/fieldbus_device.set_params.json
+++ b/assets/files/protocols/hmi/fieldbus_device.set_params.json
@@ -5,5 +5,6 @@
"data": {
"device_name": "modbus_1",
"enable": true
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/io_device.load_cfg.json b/assets/files/protocols/hmi/io_device.load_cfg.json
index 790f75c..e3d0583 100644
--- a/assets/files/protocols/hmi/io_device.load_cfg.json
+++ b/assets/files/protocols/hmi/io_device.load_cfg.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "io",
- "command": "io_device.load_cfg"
+ "command": "io_device.load_cfg",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/jog.get_params.json b/assets/files/protocols/hmi/jog.get_params.json
index db98a71..03e6eed 100644
--- a/assets/files/protocols/hmi/jog.get_params.json
+++ b/assets/files/protocols/hmi/jog.get_params.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "motion",
- "command": "jog.get_params"
+ "command": "jog.get_params",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/log_code.data.json b/assets/files/protocols/hmi/log_code.data.json
index 021b678..b0898e2 100644
--- a/assets/files/protocols/hmi/log_code.data.json
+++ b/assets/files/protocols/hmi/log_code.data.json
@@ -1,5 +1,7 @@
{
- "g": {
+ "id": "xxxxxxxxxxx",
+ "g": {
"log_code.data": "null"
- }
+ },
+ "p_type": 1
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/modbus.get_params.json b/assets/files/protocols/hmi/modbus.get_params.json
index 8bdde30..1ee55bd 100644
--- a/assets/files/protocols/hmi/modbus.get_params.json
+++ b/assets/files/protocols/hmi/modbus.get_params.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "fieldbus",
- "command": "modbus.get_params"
+ "command": "modbus.get_params",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/modbus.get_values.json b/assets/files/protocols/hmi/modbus.get_values.json
index d356362..42ba949 100644
--- a/assets/files/protocols/hmi/modbus.get_values.json
+++ b/assets/files/protocols/hmi/modbus.get_values.json
@@ -4,5 +4,6 @@
"command": "modbus.get_values",
"data": {
"mode": "all"
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/modbus.load_cfg.json b/assets/files/protocols/hmi/modbus.load_cfg.json
index 95d5e69..22f199e 100644
--- a/assets/files/protocols/hmi/modbus.load_cfg.json
+++ b/assets/files/protocols/hmi/modbus.load_cfg.json
@@ -4,5 +4,6 @@
"command": "modbus.load_cfg",
"data": {
"file" : "registers.json"
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/modbus.set_params.json b/assets/files/protocols/hmi/modbus.set_params.json
index 46a651e..7a3fa11 100644
--- a/assets/files/protocols/hmi/modbus.set_params.json
+++ b/assets/files/protocols/hmi/modbus.set_params.json
@@ -8,5 +8,6 @@
"port": 502,
"slave_id": 0,
"enable_master": false
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/move.get_joint_pos.json b/assets/files/protocols/hmi/move.get_joint_pos.json
index 9754405..51c50d9 100644
--- a/assets/files/protocols/hmi/move.get_joint_pos.json
+++ b/assets/files/protocols/hmi/move.get_joint_pos.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "motion",
- "command": "move.get_joint_pos"
+ "command": "move.get_joint_pos",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/move.get_monitor_cfg.json b/assets/files/protocols/hmi/move.get_monitor_cfg.json
index 75fb033..35419f9 100644
--- a/assets/files/protocols/hmi/move.get_monitor_cfg.json
+++ b/assets/files/protocols/hmi/move.get_monitor_cfg.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "motion",
- "command": "move.get_monitor_cfg"
+ "command": "move.get_monitor_cfg",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/move.get_params.json b/assets/files/protocols/hmi/move.get_params.json
index bfe06e2..d7802fd 100644
--- a/assets/files/protocols/hmi/move.get_params.json
+++ b/assets/files/protocols/hmi/move.get_params.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "motion",
- "command": "move.get_params"
+ "command": "move.get_params",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/move.get_pos.json b/assets/files/protocols/hmi/move.get_pos.json
index 9124631..4cce83b 100644
--- a/assets/files/protocols/hmi/move.get_pos.json
+++ b/assets/files/protocols/hmi/move.get_pos.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "motion",
- "command": "move.get_pos"
+ "command": "move.get_pos",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/move.get_quickstop_distance.json b/assets/files/protocols/hmi/move.get_quickstop_distance.json
index ac5f0b2..ddcfa11 100644
--- a/assets/files/protocols/hmi/move.get_quickstop_distance.json
+++ b/assets/files/protocols/hmi/move.get_quickstop_distance.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "motion",
- "command": "move.get_quickstop_distance"
+ "command": "move.get_quickstop_distance",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/move.get_quickturn_pos.json b/assets/files/protocols/hmi/move.get_quickturn_pos.json
index 74ecae0..a02b8c2 100644
--- a/assets/files/protocols/hmi/move.get_quickturn_pos.json
+++ b/assets/files/protocols/hmi/move.get_quickturn_pos.json
@@ -1,5 +1,6 @@
{
"id" : "xxxxxxxxx",
"module": "motion",
- "command": "move.get_quickturn_pos"
+ "command": "move.get_quickturn_pos",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/move.quick_turn.json b/assets/files/protocols/hmi/move.quick_turn.json
index 3a72afc..8db1988 100644
--- a/assets/files/protocols/hmi/move.quick_turn.json
+++ b/assets/files/protocols/hmi/move.quick_turn.json
@@ -4,5 +4,6 @@
"command": "move.quick_turn",
"data": {
"name":"home"
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/move.set_monitor_cfg.json b/assets/files/protocols/hmi/move.set_monitor_cfg.json
index 68c3f35..0a638de 100644
--- a/assets/files/protocols/hmi/move.set_monitor_cfg.json
+++ b/assets/files/protocols/hmi/move.set_monitor_cfg.json
@@ -4,5 +4,6 @@
"command": "move.set_monitor_cfg",
"data": {
"ref_coordinate": 1
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/move.set_params.json b/assets/files/protocols/hmi/move.set_params.json
index 8788a6c..b65b1db 100644
--- a/assets/files/protocols/hmi/move.set_params.json
+++ b/assets/files/protocols/hmi/move.set_params.json
@@ -12,6 +12,6 @@
"VEL_SMOOTH_FACTOR": 3.33,
"ACC_RAMPTIME_JOG": 0.01
}
- }
-
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/move.set_quickstop_distance.json b/assets/files/protocols/hmi/move.set_quickstop_distance.json
index 000d5f5..50c53fd 100644
--- a/assets/files/protocols/hmi/move.set_quickstop_distance.json
+++ b/assets/files/protocols/hmi/move.set_quickstop_distance.json
@@ -4,5 +4,6 @@
"command": "move.set_quickstop_distance",
"data":{
"distance": 2
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/move.set_quickturn_pos.json b/assets/files/protocols/hmi/move.set_quickturn_pos.json
index 164e442..8da5353 100644
--- a/assets/files/protocols/hmi/move.set_quickturn_pos.json
+++ b/assets/files/protocols/hmi/move.set_quickturn_pos.json
@@ -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
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/move.stop.json b/assets/files/protocols/hmi/move.stop.json
index 17648f0..f79c140 100644
--- a/assets/files/protocols/hmi/move.stop.json
+++ b/assets/files/protocols/hmi/move.stop.json
@@ -4,5 +4,6 @@
"command": "move.stop",
"data":{
"stoptype": 0
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/overview.get_autoload.json b/assets/files/protocols/hmi/overview.get_autoload.json
index 49e3b79..4b59f13 100644
--- a/assets/files/protocols/hmi/overview.get_autoload.json
+++ b/assets/files/protocols/hmi/overview.get_autoload.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "project",
- "command": "overview.get_autoload"
+ "command": "overview.get_autoload",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/overview.get_cur_prj.json b/assets/files/protocols/hmi/overview.get_cur_prj.json
index 8e50c5a..ab192ad 100644
--- a/assets/files/protocols/hmi/overview.get_cur_prj.json
+++ b/assets/files/protocols/hmi/overview.get_cur_prj.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "project",
- "command": "overview.get_cur_prj"
+ "command": "overview.get_cur_prj",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/overview.reload.json b/assets/files/protocols/hmi/overview.reload.json
index a2485a2..185f8ba 100644
--- a/assets/files/protocols/hmi/overview.reload.json
+++ b/assets/files/protocols/hmi/overview.reload.json
@@ -5,5 +5,6 @@
"data": {
"prj_path": "",
"tasks": []
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/overview.set_autoload.json b/assets/files/protocols/hmi/overview.set_autoload.json
index 791d4fb..928bb9f 100644
--- a/assets/files/protocols/hmi/overview.set_autoload.json
+++ b/assets/files/protocols/hmi/overview.set_autoload.json
@@ -4,5 +4,6 @@
"command": "overview.set_autoload",
"data": {
"autoload_prj_path": ""
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/register.set_value.json b/assets/files/protocols/hmi/register.set_value.json
index 6b64af3..d4cded4 100644
--- a/assets/files/protocols/hmi/register.set_value.json
+++ b/assets/files/protocols/hmi/register.set_value.json
@@ -7,5 +7,6 @@
"type": "bool",
"bias": 0,
"value": 0
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/rl_task.pp_to_main.json b/assets/files/protocols/hmi/rl_task.pp_to_main.json
index 3e2247f..c5f518e 100644
--- a/assets/files/protocols/hmi/rl_task.pp_to_main.json
+++ b/assets/files/protocols/hmi/rl_task.pp_to_main.json
@@ -4,5 +4,6 @@
"command": "rl_task.pp_to_main",
"data": {
"tasks": []
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/rl_task.run.json b/assets/files/protocols/hmi/rl_task.run.json
index 52e89a1..534a5fd 100644
--- a/assets/files/protocols/hmi/rl_task.run.json
+++ b/assets/files/protocols/hmi/rl_task.run.json
@@ -4,5 +4,6 @@
"command": "rl_task.run",
"data": {
"tasks": []
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/rl_task.set_run_params.json b/assets/files/protocols/hmi/rl_task.set_run_params.json
index 8490383..efc5368 100644
--- a/assets/files/protocols/hmi/rl_task.set_run_params.json
+++ b/assets/files/protocols/hmi/rl_task.set_run_params.json
@@ -5,5 +5,6 @@
"data": {
"loop_mode": true,
"override": 1.0
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/rl_task.stop.json b/assets/files/protocols/hmi/rl_task.stop.json
index 03b0f6b..0fe2a91 100644
--- a/assets/files/protocols/hmi/rl_task.stop.json
+++ b/assets/files/protocols/hmi/rl_task.stop.json
@@ -4,5 +4,6 @@
"command": "rl_task.stop",
"data": {
"tasks": []
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/safety.safety_area.overall_enable.json b/assets/files/protocols/hmi/safety.safety_area.overall_enable.json
index 517e64b..694946e 100644
--- a/assets/files/protocols/hmi/safety.safety_area.overall_enable.json
+++ b/assets/files/protocols/hmi/safety.safety_area.overall_enable.json
@@ -1,7 +1,9 @@
{
- "c": {
+ "id": "xxxxxxxxxxx",
+ "c": {
"safety.safety_area.overall_enable": {
"enable": true
}
- }
+ },
+ "p_type": 1
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/safety.safety_area.safety_area_enable.json b/assets/files/protocols/hmi/safety.safety_area.safety_area_enable.json
index 505fe50..723e1cf 100644
--- a/assets/files/protocols/hmi/safety.safety_area.safety_area_enable.json
+++ b/assets/files/protocols/hmi/safety.safety_area.safety_area_enable.json
@@ -1,8 +1,10 @@
{
- "c": {
+ "id": "xxxxxxxxxxx",
+ "c": {
"safety.safety_area.safety_area_enable": {
"id": 0,
"enable": true
}
- }
+ },
+ "p_type": 1
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/safety.safety_area.set_param.json b/assets/files/protocols/hmi/safety.safety_area.set_param.json
index 28b65da..1205fe0 100644
--- a/assets/files/protocols/hmi/safety.safety_area.set_param.json
+++ b/assets/files/protocols/hmi/safety.safety_area.set_param.json
@@ -1,5 +1,7 @@
{
- "c": {
+ "id": "xxxxxxxxxxx",
+ "c": {
"safety.safety_area.set_param": null
- }
+ },
+ "p_type": 1
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/safety.safety_area.signal_enable.json b/assets/files/protocols/hmi/safety.safety_area.signal_enable.json
index 8a1fbac..2a37a4c 100644
--- a/assets/files/protocols/hmi/safety.safety_area.signal_enable.json
+++ b/assets/files/protocols/hmi/safety.safety_area.signal_enable.json
@@ -1,7 +1,9 @@
{
- "c": {
+ "id": "xxxxxxxxxxx",
+ "c": {
"safety.safety_area.signal_enable": {
"signal": true
}
- }
+ },
+ "p_type": 1
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/safety_area_data.json b/assets/files/protocols/hmi/safety_area_data.json
index e9b982a..cd43bdd 100644
--- a/assets/files/protocols/hmi/safety_area_data.json
+++ b/assets/files/protocols/hmi/safety_area_data.json
@@ -1,5 +1,7 @@
{
- "g": {
+ "id": "xxxxxxxxxxx",
+ "g": {
"safety_area_data": null
- }
+ },
+ "p_type": 1
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/servo.clear_alarm.json b/assets/files/protocols/hmi/servo.clear_alarm.json
index bc3b7f8..cffeb4e 100644
--- a/assets/files/protocols/hmi/servo.clear_alarm.json
+++ b/assets/files/protocols/hmi/servo.clear_alarm.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "robot",
- "command": "servo.clear_alarm"
+ "command": "servo.clear_alarm",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/socket.get_params.json b/assets/files/protocols/hmi/socket.get_params.json
index 2971e6a..6a92e1d 100644
--- a/assets/files/protocols/hmi/socket.get_params.json
+++ b/assets/files/protocols/hmi/socket.get_params.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "network",
- "command": "socket.get_params"
+ "command": "socket.get_params",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/socket.set_params.json b/assets/files/protocols/hmi/socket.set_params.json
index 9635cae..2507cfb 100644
--- a/assets/files/protocols/hmi/socket.set_params.json
+++ b/assets/files/protocols/hmi/socket.set_params.json
@@ -13,5 +13,6 @@
"auto_connect": true,
"disconnection_triggering_behavior": 0,
"disconnection_detection_time": 10
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/soft_limit.get_params.json b/assets/files/protocols/hmi/soft_limit.get_params.json
index 6f1f222..861b1ee 100644
--- a/assets/files/protocols/hmi/soft_limit.get_params.json
+++ b/assets/files/protocols/hmi/soft_limit.get_params.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "safety",
- "command": "soft_limit.get_params"
+ "command": "soft_limit.get_params",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/soft_limit.set_params.json b/assets/files/protocols/hmi/soft_limit.set_params.json
index a0a3844..eda482b 100644
--- a/assets/files/protocols/hmi/soft_limit.set_params.json
+++ b/assets/files/protocols/hmi/soft_limit.set_params.json
@@ -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
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/state.get_state.json b/assets/files/protocols/hmi/state.get_state.json
index 1a2b981..c3e92fa 100644
--- a/assets/files/protocols/hmi/state.get_state.json
+++ b/assets/files/protocols/hmi/state.get_state.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "system",
- "command": "state.get_state"
+ "command": "state.get_state",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/state.get_tp_mode.json b/assets/files/protocols/hmi/state.get_tp_mode.json
index 5b59ed0..3d41c3b 100644
--- a/assets/files/protocols/hmi/state.get_tp_mode.json
+++ b/assets/files/protocols/hmi/state.get_tp_mode.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "system",
- "command": "state.get_tp_mode"
+ "command": "state.get_tp_mode",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/state.set_tp_mode.json b/assets/files/protocols/hmi/state.set_tp_mode.json
index 608dd02..7185d96 100644
--- a/assets/files/protocols/hmi/state.set_tp_mode.json
+++ b/assets/files/protocols/hmi/state.set_tp_mode.json
@@ -4,5 +4,6 @@
"command": "state.set_tp_mode",
"data": {
"tp_mode": "with"
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/state.switch_auto.json b/assets/files/protocols/hmi/state.switch_auto.json
index 0c0a872..67d5635 100644
--- a/assets/files/protocols/hmi/state.switch_auto.json
+++ b/assets/files/protocols/hmi/state.switch_auto.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "system",
- "command": "state.switch_auto"
+ "command": "state.switch_auto",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/state.switch_manual.json b/assets/files/protocols/hmi/state.switch_manual.json
index 0451d04..7b08ce6 100644
--- a/assets/files/protocols/hmi/state.switch_manual.json
+++ b/assets/files/protocols/hmi/state.switch_manual.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "system",
- "command": "state.switch_manual"
+ "command": "state.switch_manual",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/state.switch_motor_off.json b/assets/files/protocols/hmi/state.switch_motor_off.json
index 0618931..e6f7357 100644
--- a/assets/files/protocols/hmi/state.switch_motor_off.json
+++ b/assets/files/protocols/hmi/state.switch_motor_off.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "system",
- "command": "state.switch_motor_off"
+ "command": "state.switch_motor_off",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/state.switch_motor_on.json b/assets/files/protocols/hmi/state.switch_motor_on.json
index 0bbcc72..cba491e 100644
--- a/assets/files/protocols/hmi/state.switch_motor_on.json
+++ b/assets/files/protocols/hmi/state.switch_motor_on.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "system",
- "command": "state.switch_motor_on"
+ "command": "state.switch_motor_on",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/system_io.query_configuration.json b/assets/files/protocols/hmi/system_io.query_configuration.json
index 27d16bd..c9120d3 100644
--- a/assets/files/protocols/hmi/system_io.query_configuration.json
+++ b/assets/files/protocols/hmi/system_io.query_configuration.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "io",
- "command": "system_io.query_configuration"
+ "command": "system_io.query_configuration",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/system_io.query_event_cfg.json b/assets/files/protocols/hmi/system_io.query_event_cfg.json
index 5af3217..69e69e4 100644
--- a/assets/files/protocols/hmi/system_io.query_event_cfg.json
+++ b/assets/files/protocols/hmi/system_io.query_event_cfg.json
@@ -1,5 +1,6 @@
{
"id": "xxxxxxxxxxx",
"module": "io",
- "command": "system_io.query_event_cfg"
+ "command": "system_io.query_event_cfg",
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/hmi/system_io.update_configuration.json b/assets/files/protocols/hmi/system_io.update_configuration.json
index aaeb41f..bc5bac8 100644
--- a/assets/files/protocols/hmi/system_io.update_configuration.json
+++ b/assets/files/protocols/hmi/system_io.update_configuration.json
@@ -5,5 +5,6 @@
"data": {
"input_system_io": {},
"output_system_io": {}
- }
+ },
+ "p_type": 0
}
\ No newline at end of file
diff --git a/assets/files/protocols/md/ctrl_estop_reset_clear_alarm.txt b/assets/files/protocols/md/ctrl_estop_reset_clear_alarm.txt
new file mode 100644
index 0000000..4d4abec
--- /dev/null
+++ b/assets/files/protocols/md/ctrl_estop_reset_clear_alarm.txt
@@ -0,0 +1,3 @@
+40002: 0
+40002: 1
+40002: 0
\ No newline at end of file
diff --git a/assets/files/protocols/md/ctrl_motor_off.txt b/assets/files/protocols/md/ctrl_motor_off.txt
new file mode 100644
index 0000000..c7c4228
--- /dev/null
+++ b/assets/files/protocols/md/ctrl_motor_off.txt
@@ -0,0 +1,3 @@
+40003: 0
+40003: 1
+40003: 0
\ No newline at end of file
diff --git a/assets/files/protocols/md/ctrl_motor_on.txt b/assets/files/protocols/md/ctrl_motor_on.txt
new file mode 100644
index 0000000..7bcc075
--- /dev/null
+++ b/assets/files/protocols/md/ctrl_motor_on.txt
@@ -0,0 +1,3 @@
+40004: 0
+40004: 1
+40004: 0
\ No newline at end of file
diff --git a/assets/files/protocols/md/ctrl_soft_estop.txt b/assets/files/protocols/md/ctrl_soft_estop.txt
new file mode 100644
index 0000000..1eaa804
--- /dev/null
+++ b/assets/files/protocols/md/ctrl_soft_estop.txt
@@ -0,0 +1 @@
+40012: 1
\ No newline at end of file
diff --git a/assets/files/protocols/md/sta_alarm.txt b/assets/files/protocols/md/sta_alarm.txt
new file mode 100644
index 0000000..97e3c40
--- /dev/null
+++ b/assets/files/protocols/md/sta_alarm.txt
@@ -0,0 +1 @@
+40500:1:bool
\ No newline at end of file
diff --git a/assets/files/protocols/md/sta_estop.txt b/assets/files/protocols/md/sta_estop.txt
new file mode 100644
index 0000000..edff8ea
--- /dev/null
+++ b/assets/files/protocols/md/sta_estop.txt
@@ -0,0 +1 @@
+40505:1:bool
\ No newline at end of file
diff --git a/assets/files/protocols/md/sta_motor.txt b/assets/files/protocols/md/sta_motor.txt
new file mode 100644
index 0000000..f36cf19
--- /dev/null
+++ b/assets/files/protocols/md/sta_motor.txt
@@ -0,0 +1 @@
+40506:1:bool
\ No newline at end of file
diff --git a/assets/files/protocols/md/sta_soft_estop.txt b/assets/files/protocols/md/sta_soft_estop.txt
new file mode 100644
index 0000000..dfeda2c
--- /dev/null
+++ b/assets/files/protocols/md/sta_soft_estop.txt
@@ -0,0 +1 @@
+40518:1:bool
\ No newline at end of file
diff --git a/assets/files/version/version b/assets/files/version/local_vers
similarity index 100%
rename from assets/files/version/version
rename to assets/files/version/local_vers
diff --git a/assets/files/version/server_vers b/assets/files/version/server_vers
new file mode 100644
index 0000000..bd78cb6
--- /dev/null
+++ b/assets/files/version/server_vers
@@ -0,0 +1 @@
+0.3.1.7@03/24/2025
\ No newline at end of file
diff --git a/assets/media/splash.png b/assets/media/splash.png
new file mode 100644
index 0000000..f6b930c
Binary files /dev/null and b/assets/media/splash.png differ
diff --git a/code/aio.py b/code/aio.py
deleted file mode 100644
index d585d18..0000000
--- a/code/aio.py
+++ /dev/null
@@ -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"{msg}")
- 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())
-
diff --git a/code/common/clibs.py b/code/common/clibs.py
deleted file mode 100644
index 8a42f5b..0000000
--- a/code/common/clibs.py
+++ /dev/null
@@ -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 # 各个指标所在列
diff --git a/code/durable/create_plot.py b/code/durable/create_plot.py
deleted file mode 100644
index 3074b22..0000000
--- a/code/durable/create_plot.py
+++ /dev/null
@@ -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
-#
\ No newline at end of file
diff --git a/code/durable/factory_test.py b/code/durable/factory_test.py
deleted file mode 100644
index ed146f8..0000000
--- a/code/durable/factory_test.py
+++ /dev/null
@@ -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}
{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 + "
全部处理完毕
", "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)
\ No newline at end of file
diff --git a/code/ui/login_window.py b/code/ui/login_window.py
deleted file mode 100644
index df2f7b4..0000000
--- a/code/ui/login_window.py
+++ /dev/null
@@ -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
-
diff --git a/code/ui/reset_window.py b/code/ui/reset_window.py
deleted file mode 100644
index ec6c7d6..0000000
--- a/code/ui/reset_window.py
+++ /dev/null
@@ -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
-
diff --git a/codes/__init__.py b/codes/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/codes/analysis/__init__.py b/codes/analysis/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/code/analysis/brake.py b/codes/analysis/brake.py
similarity index 78%
rename from code/analysis/brake.py
rename to codes/analysis/brake.py
index a855df6..68b6a20 100644
--- a/code/analysis/brake.py
+++ b/codes/analysis/brake.py
@@ -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 = "需要有四个文件和若干个数据文件夹,可参考如下确认:
"
msg_wrong += "- reach33/66/100_XXXXXXX.xlsx
- *.cfg
"
msg_wrong += "- reach33_load33_speed33
- reach33_load33_speed66
...
- reach100_load100_speed66
- reach100_load100_speed100
"
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} 命名不合规,请参考如下形式
"
msg += "命名规则:reachAA_loadBB_speedCC,AA/BB/CC 指的是臂展/负载/速度的比例
"
msg += "规则解释:reach66_load100_speed33,表示 66% 臂展,100% 负载以及 33% 速度情况下的测试结果文件夹
"
- 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},或者使用了错误的机型配置文件,需检查
{Err}", "red", "OpenFileError")
+ self.logger("ERROR", "brake", f"无法打开 {config_file},或者使用了错误的机型配置文件,需检查
{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}文件打开失败,可能是文件已损坏,确认后重新执行!
{Err}", "red", "CannotOpenFile")
+ self.logger("ERROR", "brake", f"{filename}文件打开失败,可能是文件已损坏,确认后重新执行!
{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},这可能需要一些时间......
", "blue")
+ self.logger("INFO", "brake", f"正在保存文件 {filename},这可能需要一些时间......
", "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 + "
全部处理完毕
", "purple")
+ self.logger("INFO", "brake", "-"*60 + "
全部处理完毕
", "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)
diff --git a/code/analysis/current.py b/codes/analysis/current.py
similarity index 81%
rename from code/analysis/current.py
rename to codes/analysis/current.py
index 533ec1e..a88fcf1 100644
--- a/code/analysis/current.py
+++ b/codes/analysis/current.py
@@ -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}
"
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}文件打开失败,可能是文件已损坏,确认后重新执行!
{Err}", "red", "CannotOpenFile")
+ self.logger("ERROR", "current", f"{filename}文件打开失败,可能是文件已损坏,确认后重新执行!
{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 + "
全部处理完毕
", "purple")
+ self.logger("INFO", "current", "-"*60 + "
全部处理完毕
", "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)
diff --git a/code/analysis/iso.py b/codes/analysis/iso.py
similarity index 99%
rename from code/analysis/iso.py
rename to codes/analysis/iso.py
index 2aeacda..a3b5a9c 100644
--- a/code/analysis/iso.py
+++ b/codes/analysis/iso.py
@@ -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}")
diff --git a/code/analysis/wavelogger.py b/codes/analysis/wavelogger.py
similarity index 86%
rename from code/analysis/wavelogger.py
rename to codes/analysis/wavelogger.py
index 1a3422f..1dc275e 100644
--- a/code/analysis/wavelogger.py
+++ b/codes/analysis/wavelogger.py
@@ -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 + "
全部处理完毕
", "purple")
+ self.logger("INFO", "wavelogger", "-" * 60 + "
全部处理完毕
", "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)
diff --git a/codes/autotest/__init__.py b/codes/autotest/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/code/autotest/do_brake.py b/codes/autotest/do_brake.py
similarity index 79%
rename from code/autotest/do_brake.py
rename to codes/autotest/do_brake.py
index b30a5fb..eeecf6d 100644
--- a/code/autotest/do_brake.py
+++ b/codes/autotest/do_brake.py
@@ -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 = "初始路径下不允许有文件夹,初始路径下只能存在如下五个文件,且文件为关闭状态,确认后重新运行!
"
+ msg = "初始路径下不允许有文件夹,只能存在如下五个文件,且文件为关闭状态,确认后重新运行!
"
msg += "1. configs.xlsx
2. reach33/reach66/reach100_xxxx.xlsx
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}
{Err}", "red", "OpenFileError")
+ self.logger("ERROR", "do_brake", f"无法打开 {local_file}
{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"
{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: 需要在网络设置中连接HMI,Modbus通信以及外部通信!", "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 + "
全部处理完毕
", "purple")
+ self.logger("INFO", "do_brake", "-"*60 + "
全部处理完毕
", "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)
diff --git a/code/autotest/do_current.py b/codes/autotest/do_current.py
similarity index 77%
rename from code/autotest/do_current.py
rename to codes/autotest/do_current.py
index 0901d33..d95ebc4 100644
--- a/code/autotest/do_current.py
+++ b/codes/autotest/do_current.py
@@ -4,10 +4,10 @@ import time
import paramiko
import pandas
from PySide6.QtCore import Signal, QThread
-from common import clibs
+from codes.common import clibs
-class DoBrakeTest(QThread):
+class DoCurrentTest(QThread):
output = Signal(str, str)
def __init__(self, dir_path, tool, /):
@@ -17,16 +17,18 @@ class DoBrakeTest(QThread):
self.idx = 5
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 = "初始路径下不允许有文件夹,初始路径下只能存在如下两个文件,且文件为关闭状态,确认后重新运行!
"
msg += "1. T_电机电流.xlsx
2. xxxx.zip"
if len(data_dirs) != 0 or len(data_files) != 2:
- self.logger("ERROR", "do_current-check_files", msg, "red", "InitFileError")
+ self.logger("ERROR", "do_current", msg, "red", "InitFileError")
prj_file, count = None, 0
for data_file in data_files:
@@ -37,12 +39,11 @@ class DoBrakeTest(QThread):
count += 1
prj_file = data_file
else:
- self.logger("ERROR", "do_current-check_files", msg, "red", "InitFileError")
+ self.logger("ERROR", "do_current", msg, "red", "InitFileError")
if count != 2:
- self.logger("ERROR", "do_current-check_files", msg, "red", "InitFileError")
+ self.logger("ERROR", "do_current", 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")
@@ -51,14 +52,15 @@ class DoBrakeTest(QThread):
elif self.tool == "inertia":
os.mkdir(f"{self.dir_path}/inertia")
else:
- self.logger("ERROR", "do_current-check_files", "负载选择错误,电机电流测试只能选择 tool100/inertia 规格!", "red", "LoadSelectError")
+ self.logger("ERROR", "do_current", "负载选择错误,电机电流测试只能选择 tool100/inertia 规格!", "red", "LoadSelectError")
return prj_file
+ @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"]
@@ -66,11 +68,13 @@ class DoBrakeTest(QThread):
local_file = self.dir_path + f"/{robot_type}.cfg"
clibs.c_pd.pull_file_from_server(server_file, local_file)
+ self.logger("INFO", "do_current", "正在做初始化校验和配置,这可能需要一点时间......", "green")
_prj_file = check_files()
get_configs()
-
+ self.logger("INFO", "do_current", "数据目录合规性检查结束,未发现问题......", "green")
return _prj_file
+ @clibs.handle_exception
def single_axis_proc(self, records, number):
text = "single" if number < 6 else "hold"
number = number if number < 6 else number - 6
@@ -96,6 +100,7 @@ class DoBrakeTest(QThread):
filename = f"{self.dir_path}/single/j{number + 1}_{text}_{time.time()}.data"
df.to_csv(filename, sep="\t", index=False)
+ @clibs.handle_exception
def scenario_proc(self, records, number, scenario_time):
d_vel, d_trq, d_sensor, d_trans = [[], [], [], [], [], []], [[], [], [], [], [], []], [[], [], [], [], [], []], [[], [], [], [], [], []]
for record in records:
@@ -121,30 +126,40 @@ class DoBrakeTest(QThread):
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)
+ @clibs.handle_exception
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 _
+ @clibs.handle_exception
+ def get_records():
+ s_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(start_time))
+ e_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(end_time+clibs.INTERVAL))
+
+ try:
+ clibs.lock.acquire(True)
+ 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")
+ return clibs.cursor.fetchall()
+ finally:
+ clibs.lock.release()
if number < 12:
- records = get_records(start_time, end_time)
+ records = get_records()
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)
+ records = get_records()
t = threading.Thread(target=self.scenario_proc, args=(records, number, scenario_time))
t.daemon = True
t.start()
@staticmethod
+ @clibs.handle_exception
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")
+ 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, prj_file):
prj_name = ".".join(prj_file.split("/")[-1].split(".")[:-1])
c_regular = [
@@ -184,7 +199,10 @@ class DoBrakeTest(QThread):
for condition in conditions:
number = conditions.index(condition)
- self.logger("INFO", "do_current-run_rl", f"正在执行{disc[number]}测试......")
+ # for testing
+ # if number < 12:
+ # continue
+ self.logger("INFO", "do_current", f"正在执行{disc[number]}测试......")
# 1. 将act重置为False,并修改将要执行的场景
clibs.c_md.write_act(False)
@@ -217,12 +235,12 @@ class DoBrakeTest(QThread):
else:
time.sleep(1)
if (time.time() - t_start) > 15:
- self.logger("ERROR", "do_current-run_rl", "15s 内未收到机器人的运行信号,需要确认RL程序和工具通信是否正常执行...", "red", "ReadySignalTimeoutError")
+ self.logger("ERROR", "do_current", "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()))
+ start_time = time.time()
single_time, stall_time, scenario_time = 40, 10, 0
if number < 6: # 单轴
time.sleep(single_time)
@@ -233,36 +251,39 @@ class DoBrakeTest(QThread):
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}")
+ self.logger("INFO", "do_current", 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")
+ self.logger("ERROR", "do_current", 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()))
+ end_time = time.time()
clibs.c_hr.execution("rl_task.stop", tasks=["current"])
- time.sleep(2) # 确保数据都拿到
self.change_curve_state(False)
+ time.sleep(2) # 确保数据都入库
self.gen_result_file(number, start_time, end_time, scenario_time)
else:
if self.tool == "tool100":
- self.logger("INFO", "do_current-run_rl", "单轴和场景电机电流采集完毕,如需采集惯量负载,须切换负载类型,并更换惯量负载,重新执行", "green")
+ self.logger("INFO", "do_current", "单轴和场景电机电流采集完毕,如需采集惯量负载,须切换负载类型,并更换惯量负载,重新执行", "green")
elif self.tool == "inertia":
- self.logger("INFO", "do_current-run_rl", "惯量负载电机电流采集完毕,如需采集单轴/场景/保持电机电流,须切换负载类型,并更换偏置负载,重新执行", "green")
+ self.logger("INFO", "do_current", "惯量负载电机电流采集完毕,如需采集单轴/场景/保持电机电流,须切换负载类型,并更换偏置负载,重新执行", "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:
+ self.logger("ERROR", "do_current", "processing: 需要在网络设置中连接HMI以及Modbus通信!", "red", "NetworkError")
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 + "
全部处理完毕
", "purple")
+ self.logger("INFO", "do_current", "-" * 60 + "
全部处理完毕
", "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_current", msg)
diff --git a/codes/common/__init__.py b/codes/common/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/codes/common/clibs.py b/codes/common/clibs.py
new file mode 100644
index 0000000..6ef9471
--- /dev/null
+++ b/codes/common/clibs.py
@@ -0,0 +1,103 @@
+import os
+import os.path
+import threading
+import sqlite3
+
+
+def traversal_files(dir_path, signal):
+ # 功能:以列表的形式分别返回指定路径下的文件和文件夹,不包含子目录
+ # 参数:路径/信号/游标/功能编号
+ # 返回值:路径下的文件夹列表 路径下的文件列表
+ 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 init_logdb():
+ global conn, cursor
+ conn = sqlite3.connect(":memory:", isolation_level=None, check_same_thread=False, cached_statements=2048)
+ cursor = conn.cursor()
+ cursor.execute("PRAGMA journal_mode=wal")
+ cursor.execute("PRAGMA wal_checkpoint=TRUNCATE")
+ cursor.execute("PRAGMA synchronous=normal")
+ cursor.execute("PRAGMA temp_store=memory")
+ cursor.execute("PRAGMA mmap_size=30000000000")
+ cursor.execute("PRAGMA cache_size=200000")
+ cursor.execute(
+ """
+ create table if not exists logs(
+ id integer primary key autoincrement,
+ timestamp DATETIME DEFAULT(STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW', 'localtime')),
+ level text,
+ module text,
+ content text
+ )
+ """
+ )
+
+
+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
+ if "move.monitor" in content:
+ return
+
+ if flag == "signal":
+ signal.emit(content, color)
+ elif flag == "cursor":
+ cursor.execute(f"INSERT INTO logs (level, module, content) VALUES (?, ?, ?)", (level, module, content))
+ elif flag == "both":
+ signal.emit(content, color)
+ cursor.execute(f"INSERT INTO logs (level, module, content) VALUES (?, ?, ?)", (level, module, content))
+
+
+def handle_exception(func):
+ def wrapper(*args, **kwargs):
+ try:
+ return func(*args, **kwargs)
+ except Exception as err:
+ print(f"{func.__name__} err = {err}")
+ logger("DEBUG", "clibs", f"{func.__name__} err = {err}", flag="cursor")
+ return wrapper
+
+
+log_path = f"assets/logs"
+lock = threading.Lock()
+running = [0, 0, 0, 0, 0, 0, 0] # 制动数据/转矩数据/激光数据/精度数据/制动自动化/转矩自动化/耐久数据采集
+functions = ["制动数据处理", "转矩数据处理", "激光数据处理", "精度数据处理", "制动自动化测试", "转矩自动化测试", "耐久数据采集"]
+levels = ["DEBUG", "INFO", "WARNING", "ERROR"]
+ip_addr, ssh_port, socket_port, xService_port, external_port, modbus_port, upgrade_port = "", 22, 5050, 6666, 8080, 502, 4567
+username, password = "luoshi", "luoshi2019"
+INTERVAL, RADIAN, MAX_FRAME_SIZE, MAX_LOG_NUMBER = 1, 57.3, 1024, 10
+c_md, c_hr, c_ec, c_pd, conn, cursor, search_records = None, None, 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 # 各个指标所在列
+
+init_logdb()
+
+# ============== ↓↓↓DEBUG CODE↓↓↓ ==============
+for i in range(100):
+ logger("DEBUG", "clibs", 'running123', flag="cursor")
+ logger("INFO", "aio", 'running234', flag="cursor")
+ logger("WARNING", "openapi", 'running345', flag="cursor")
+ logger("ERROR", "brake", 'running456', flag="cursor")
diff --git a/code/common/openapi.py b/codes/common/openapi.py
similarity index 81%
rename from code/common/openapi.py
rename to codes/common/openapi.py
index 24c3c16..ff5259a 100644
--- a/code/common/openapi.py
+++ b/codes/common/openapi.py
@@ -2,7 +2,6 @@ import json
import socket
from inspect import currentframe
import threading
-import functools
from paramiko import SSHClient, AutoAddPolicy
from pymodbus.client.tcp import ModbusTcpClient
import selectors
@@ -11,8 +10,9 @@ import os.path
from ctypes import *
import hashlib
import struct
+from datetime import datetime
from PySide6.QtCore import Signal, QThread
-from common import clibs
+from codes.common import clibs
class ModbusRequest(QThread):
@@ -24,317 +24,319 @@ class ModbusRequest(QThread):
self.port = port
def net_conn(self):
+ self.logger("INFO", "openapi", f"Modbus 正在连接中,需要配置设备,这可能需要一点时间......", "blue")
RobotInit.modbus_init()
- self.__c = ModbusTcpClient(host=self.ip, port=self.port)
- if self.__c.connect():
- self.logger("DEBUG", "openapi", f"Modbus connection({clibs.ip_addr}:{clibs.modbus_port}) success...", "green")
+ self.c = ModbusTcpClient(host=self.ip, port=self.port)
+ if self.c.connect():
+ self.logger("INFO", "openapi", f"Modbus connection({clibs.ip_addr}:{clibs.modbus_port}) success!", "green")
else:
- self.logger("ERROR", "openapi", f"Modbus connection({clibs.ip_addr}:{clibs.modbus_port}) failed...", "red", "MdConnFailed")
+ self.logger("ERROR", "openapi", f"Modbus connection({clibs.ip_addr}:{clibs.modbus_port}) failed!", "red", "MdConnFailed")
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 close(self):
- if self.__c.connect():
+ if self.c.connect():
try:
- self.__c.close()
+ self.c.close()
+ self.logger("INFO", "openapi", f"modbus: 关闭 Modbus 连接成功", "green")
except Exception as err:
self.logger("ERROR", "openapi", f"modbus: 关闭 Modbus 连接失败:{err}", "red", "MdCloseFailed")
def __reg_high_pulse(self, addr: int) -> None:
- self.__c.write_register(addr, 0)
+ self.c.write_register(addr, 0)
time.sleep(clibs.INTERVAL)
- self.__c.write_register(addr, 1)
+ self.c.write_register(addr, 1)
time.sleep(clibs.INTERVAL+1)
- self.__c.write_register(addr, 0)
+ self.c.write_register(addr, 0)
def r_clear_alarm(self): # OK
self.__reg_high_pulse(40000)
- self.logger("INFO", "openapi", "modbus: 40000-010 执行清除告警信息")
+ self.logger("DEBUG", "openapi", "modbus: 40000-010 执行清除告警信息")
def r_reset_estop(self): # OK
self.__reg_high_pulse(40001)
- self.logger("INFO", "openapi", "modbus: 40001-010 执行复位急停状态(非软急停)")
+ self.logger("DEBUG", "openapi", "modbus: 40001-010 执行复位急停状态(非软急停)")
def r_reset_estop_clear_alarm(self): # OK
self.__reg_high_pulse(40002)
- self.logger("INFO", "openapi", "modbus: 40002-010 执行复位急停状态(非软急停),并清除告警信息")
+ self.logger("DEBUG", "openapi", "modbus: 40002-010 执行复位急停状态(非软急停),并清除告警信息")
def r_motor_off(self): # OK
self.__reg_high_pulse(40003)
- self.logger("INFO", "openapi", "modbus: 40003-010 执行机器人下电")
+ self.logger("DEBUG", "openapi", "modbus: 40003-010 执行机器人下电")
def r_motor_on(self): # OK
self.__reg_high_pulse(40004)
- self.logger("INFO", "openapi", "modbus: 40004-010 执行机器人上电")
+ self.logger("DEBUG", "openapi", "modbus: 40004-010 执行机器人上电")
def r_motoron_pp2main_start(self): # OK
self.__reg_high_pulse(40005)
- self.logger("INFO", "openapi", "modbus: 40005-010 执行机器人上电/pp2main/开始运行程序,需自动模式执行,若运行失败,可清除告警后再次尝试")
+ self.logger("DEBUG", "openapi", "modbus: 40005-010 执行机器人上电/pp2main/开始运行程序,需自动模式执行,若运行失败,可清除告警后再次尝试")
def r_motoron_start(self): # OK
self.__reg_high_pulse(40006)
- self.logger("INFO", "openapi", "modbus: 40006-010 执行机器人上电/开始运行程序,需自动模式执行,若运行失败,可清除告警、执行pp2main后再次尝试")
+ self.logger("DEBUG", "openapi", "modbus: 40006-010 执行机器人上电/开始运行程序,需自动模式执行,若运行失败,可清除告警、执行pp2main后再次尝试")
def r_pulse_motoroff(self): # OK
self.__reg_high_pulse(40007)
- self.logger("INFO", "openapi", "modbus: 40007-010 执行机器人停止,并下电,手动模式下可停止程序运行,但不能下电,若运行失败,可清除告警后再次尝试")
+ self.logger("DEBUG", "openapi", "modbus: 40007-010 执行机器人停止,并下电,手动模式下可停止程序运行,但不能下电,若运行失败,可清除告警后再次尝试")
def r_pp2main(self): # OK
self.__reg_high_pulse(40008)
- self.logger("INFO", "openapi", "modbus: 40008-010 执行机器人 pp2main,需自动模式执行,若运行失败,可清除告警后再次尝试")
+ self.logger("DEBUG", "openapi", "modbus: 40008-010 执行机器人 pp2main,需自动模式执行,若运行失败,可清除告警后再次尝试")
def r_program_start(self): # OK
self.__reg_high_pulse(40009)
- self.logger("INFO", "openapi", "modbus: 40009-010 执行机器人默认程序运行,需有 pp2main 前置操作,若运行失败,可清除告警后再次尝试")
+ self.logger("DEBUG", "openapi", "modbus: 40009-010 执行机器人默认程序运行,需有 pp2main 前置操作,若运行失败,可清除告警后再次尝试")
def r_program_stop(self): # OK
self.__reg_high_pulse(40010)
- self.logger("INFO", "openapi", "modbus: 40010-010 执行机器人默认程序停止,需有 pp2main 前置操作,若运行失败,可清除告警后再次尝试")
+ self.logger("DEBUG", "openapi", "modbus: 40010-010 执行机器人默认程序停止,需有 pp2main 前置操作,若运行失败,可清除告警后再次尝试")
def r_reduced_mode(self, action: int): # OK
- self.__c.write_register(40011, action)
+ self.c.write_register(40011, action)
actions = "进入" if action == 1 else "退出"
- self.logger("INFO", "openapi", f"modbus: 40011-{action} 执行机器人{actions}缩减模式")
+ self.logger("DEBUG", "openapi", f"modbus: 40011-{action} 执行机器人{actions}缩减模式")
time.sleep(clibs.INTERVAL)
def r_soft_estop(self, action: int): # OK
- self.__c.write_register(40012, action)
+ self.c.write_register(40012, action)
actions = "解除" if action == 1 else "触发"
- self.logger("INFO", "openapi", f"modbus: 40012-{action} 执行{actions}急停动作")
+ self.logger("DEBUG", "openapi", f"modbus: 40012-{action} 执行{actions}急停动作")
time.sleep(clibs.INTERVAL)
def r_switch_auto_motoron(self): # OK
self.__reg_high_pulse(40013)
- self.logger("INFO", "openapi", "modbus: 40013-010 执行切换为自动模式,并上电,初始状态 !!不能是!! 手动上电模式")
+ self.logger("DEBUG", "openapi", "modbus: 40013-010 执行切换为自动模式,并上电,初始状态 !!不能是!! 手动上电模式")
def r_switch_auto(self): # OK
self.__reg_high_pulse(40014)
- self.logger("INFO", "openapi", "modbus: 40014-010 执行切换为自动模式")
+ self.logger("DEBUG", "openapi", "modbus: 40014-010 执行切换为自动模式")
def r_switch_manual(self): # OK
self.__reg_high_pulse(40015)
- self.logger("INFO", "openapi", "modbus: 40015-010 执行切换为手动模式")
+ self.logger("DEBUG", "openapi", "modbus: 40015-010 执行切换为手动模式")
def r_switch_safe_region01(self, action: bool): # OK | 上升沿打开,下降沿关闭
if action:
- self.__c.write_register(40016, False)
+ self.c.write_register(40016, False)
time.sleep(clibs.INTERVAL)
- self.__c.write_register(40016, True)
+ self.c.write_register(40016, True)
else:
- self.__c.write_register(40016, True)
+ self.c.write_register(40016, True)
time.sleep(clibs.INTERVAL)
- self.__c.write_register(40016, False)
+ self.c.write_register(40016, False)
actions = "打开" if action else "关闭"
- self.logger("INFO", "openapi", f"modbus: 40016-{action} 执行{actions}安全区 safe region 01")
+ self.logger("DEBUG", "openapi", f"modbus: 40016-{action} 执行{actions}安全区 safe region 01")
time.sleep(clibs.INTERVAL)
def r_switch_safe_region02(self, action: bool): # OK | 上升沿打开,下降沿关闭
if action:
- self.__c.write_register(40017, False)
+ self.c.write_register(40017, False)
time.sleep(clibs.INTERVAL)
- self.__c.write_register(40017, True)
+ self.c.write_register(40017, True)
else:
- self.__c.write_register(40017, True)
+ self.c.write_register(40017, True)
time.sleep(clibs.INTERVAL)
- self.__c.write_register(40017, False)
+ self.c.write_register(40017, False)
actions = "打开" if action else "关闭"
- self.logger("INFO", "openapi", f"modbus: 40017-{action} 执行{actions}安全区 safe region 02")
+ self.logger("DEBUG", "openapi", f"modbus: 40017-{action} 执行{actions}安全区 safe region 02")
time.sleep(clibs.INTERVAL)
def r_switch_safe_region03(self, action: bool): # OK | 上升沿打开,下降沿关闭
if action:
- self.__c.write_register(40018, False)
+ self.c.write_register(40018, False)
time.sleep(clibs.INTERVAL)
- self.__c.write_register(40018, True)
+ self.c.write_register(40018, True)
else:
- self.__c.write_register(40018, True)
+ self.c.write_register(40018, True)
time.sleep(clibs.INTERVAL)
- self.__c.write_register(40018, False)
+ self.c.write_register(40018, False)
actions = "打开" if action else "关闭"
- self.logger("INFO", "openapi", f"modbus: 40018-{action} 执行{actions}安全区 safe region 03")
+ self.logger("DEBUG", "openapi", f"modbus: 40018-{action} 执行{actions}安全区 safe region 03")
time.sleep(clibs.INTERVAL)
def write_act(self, number):
- self.__c.write_register(40100, number)
- self.logger("INFO", "openapi", f"modbus: 40100 将 {number} 写入")
+ self.c.write_register(40100, number)
+ self.logger("DEBUG", "openapi", f"modbus: 40100 将 {number} 写入")
def write_probe(self, probe):
- self.__c.write_register(40101, probe)
- self.logger("INFO", "openapi", f"modbus: 40101 将 {probe} 写入")
+ self.c.write_register(40101, probe)
+ self.logger("DEBUG", "openapi", f"modbus: 40101 将 {probe} 写入")
def write_pon(self, pon):
- self.__c.write_register(40102, pon)
- self.logger("INFO", "openapi", f"modbus: 40102 将 {pon} 写入")
+ self.c.write_register(40102, pon)
+ self.logger("DEBUG", "openapi", f"modbus: 40102 将 {pon} 写入")
def write_axis(self, axis):
- result = self.__c.convert_to_registers(int(axis), self.__c.DATATYPE.INT32, "little")
- self.__c.write_registers(40103, result)
- self.logger("INFO", "openapi", f"modbus: 40103 将 {axis} 写入")
+ result = self.c.convert_to_registers(int(axis), self.c.DATATYPE.INT32, "little")
+ self.c.write_registers(40103, result)
+ self.logger("DEBUG", "openapi", f"modbus: 40103 将 {axis} 写入")
def write_speed_max(self, speed):
- result = self.__c.convert_to_registers(float(speed), self.__c.DATATYPE.FLOAT32, "little")
- self.__c.write_registers(40105, result)
- self.logger("INFO", "openapi", f"modbus: 40105 将 {speed} 写入")
+ result = self.c.convert_to_registers(float(speed), self.c.DATATYPE.FLOAT32, "little")
+ self.c.write_registers(40105, result)
+ self.logger("DEBUG", "openapi", f"modbus: 40105 将 {speed} 写入")
def r_write_signals(self, addr: int, value): # OK | 40100 - 40109: signal_0 ~ signal_9
if -1 < addr < 10 and addr.is_integer():
- self.__c.write_register(40100+addr, value)
- self.logger("INFO", "openapi", f"modbus: {40100+addr}-{value} 将寄存器 signal_{addr} 赋值为 {value}")
+ self.c.write_register(40100+addr, value)
+ self.logger("DEBUG", "openapi", f"modbus: {40100+addr}-{value} 将寄存器 signal_{addr} 赋值为 {value}")
else:
- self.logger("INFO", "openapi", f"modbus: {40100+addr}-{value} 地址错误,无法赋值!")
+ self.logger("INFO", "openapi", f"modbus: {40100+addr}-{value} 地址错误,无法赋值!", "red")
@property
def w_alarm_state(self): # OK
- res = self.__c.read_holding_registers(40500, count=1).registers[0]
- self.logger("INFO", "openapi", f"modbus: 40500 获取告警状态,结果为 {res} :--: 0 表示无告警,,1 表示有告警")
+ res = self.c.read_holding_registers(40500, count=1).registers[0]
+ self.logger("DEBUG", "openapi", f"modbus: 40500 获取告警状态,结果为 {res} :--: 0 表示无告警,,1 表示有告警")
return res
@property
def w_collision_alarm_state(self): # OK
- res = self.__c.read_holding_registers(40501, count=1).registers[0]
- self.logger("INFO", "openapi", f"modbus: 40501 获取碰撞告警状态,结果为 {res} :--: 0 表示未触发,1 表示已触发")
+ res = self.c.read_holding_registers(40501, count=1).registers[0]
+ self.logger("DEBUG", "openapi", f"modbus: 40501 获取碰撞告警状态,结果为 {res} :--: 0 表示未触发,1 表示已触发")
return res
@property
def w_collision_open_state(self): # OK
- res = self.__c.read_holding_registers(40502, count=1).registers[0]
- self.logger("INFO", "openapi", f"modbus: 40502 获取碰撞检测开启状态,结果为 {res} :--: 0 表示关闭,1 表示开启")
+ res = self.c.read_holding_registers(40502, count=1).registers[0]
+ self.logger("DEBUG", "openapi", f"modbus: 40502 获取碰撞检测开启状态,结果为 {res} :--: 0 表示关闭,1 表示开启")
return res
@property
def w_controller_is_running(self): # OK
- res = self.__c.read_holding_registers(40503, count=1).registers[0]
- self.logger("INFO", "openapi", f"modbus: 40503 获取控制器运行状态,结果为 {res} :--: 0 表示运行异常,1 表示运行正常")
+ res = self.c.read_holding_registers(40503, count=1).registers[0]
+ self.logger("DEBUG", "openapi", f"modbus: 40503 获取控制器运行状态,结果为 {res} :--: 0 表示运行异常,1 表示运行正常")
return res
@property
def w_encoder_low_battery(self): # OK
- res = self.__c.read_holding_registers(40504, count=1).registers[0]
- self.logger("INFO", "openapi", f"modbus: 40504 获取编码器低电压状态,结果为 {res} :--: 0 表示非低电压,1 表示低电压 需关注")
+ res = self.c.read_holding_registers(40504, count=1).registers[0]
+ self.logger("DEBUG", "openapi", f"modbus: 40504 获取编码器低电压状态,结果为 {res} :--: 0 表示非低电压,1 表示低电压 需关注")
return res
@property
def w_estop_state(self): # OK
- res = self.__c.read_holding_registers(40505, count=1).registers[0]
- self.logger("INFO", "openapi", f"modbus: 40505 获取机器人急停状态(非软急停),结果为 {res} :--: 0 表示未触发,1 表示已触发")
+ res = self.c.read_holding_registers(40505, count=1).registers[0]
+ self.logger("DEBUG", "openapi", f"modbus: 40505 获取机器人急停状态(非软急停),结果为 {res} :--: 0 表示未触发,1 表示已触发")
return res
@property
def w_motor_state(self): # OK
- res = self.__c.read_holding_registers(40506, count=1).registers[0]
- self.logger("INFO", "openapi", f"modbus: 40506 获取机器人上电状态,结果为 {res} :--: 0 表示未上电,1 表示已上电")
+ res = self.c.read_holding_registers(40506, count=1).registers[0]
+ self.logger("DEBUG", "openapi", f"modbus: 40506 获取机器人上电状态,结果为 {res} :--: 0 表示未上电,1 表示已上电")
return res
@property
def w_operation_mode(self): # OK
- res = self.__c.read_holding_registers(40507, count=1).registers[0]
- self.logger("INFO", "openapi", f"modbus: 40507 获取机器人操作模式,结果为 {res} :--: 0 表示手动模式,1 表示自动模式")
+ res = self.c.read_holding_registers(40507, count=1).registers[0]
+ self.logger("DEBUG", "openapi", f"modbus: 40507 获取机器人操作模式,结果为 {res} :--: 0 表示手动模式,1 表示自动模式")
return res
@property
def w_program_state(self): # OK
- res = self.__c.read_holding_registers(40508, count=1).registers[0]
- self.logger("INFO", "openapi", f"modbus: 40508 获取程序的运行状态,结果为 {res} :--: 0 表示未运行,1 表示正在运行")
+ res = self.c.read_holding_registers(40508, count=1).registers[0]
+ self.logger("DEBUG", "openapi", f"modbus: 40508 获取程序的运行状态,结果为 {res} :--: 0 表示未运行,1 表示正在运行")
return res
@property
def w_program_not_run(self): # OK
- res = self.__c.read_holding_registers(40509, count=1).registers[0]
- self.logger("INFO", "openapi", f"modbus: 40509 判定程序为未运行状态,结果为 {res} :--: 0 表示正在运行,1 表示未运行")
+ res = self.c.read_holding_registers(40509, count=1).registers[0]
+ self.logger("DEBUG", "openapi", f"modbus: 40509 判定程序为未运行状态,结果为 {res} :--: 0 表示正在运行,1 表示未运行")
return res
@property
def w_program_reset(self): # OK
- res = self.__c.read_holding_registers(40510, count=1).registers[0]
- self.logger("INFO", "openapi", f"modbus: 40510 判定程序指针为 pp2main 状态,结果为 {res} :--: 0 表示指针不在 main 函数,1 表示指针在 main 函数")
+ res = self.c.read_holding_registers(40510, count=1).registers[0]
+ self.logger("DEBUG", "openapi", f"modbus: 40510 判定程序指针为 pp2main 状态,结果为 {res} :--: 0 表示指针不在 main 函数,1 表示指针在 main 函数")
return res
@property
def w_reduce_mode_state(self): # OK
- res = self.__c.read_holding_registers(40511, count=1).registers[0]
- self.logger("INFO", "openapi", f"modbus: 40511 获取机器人缩减模式状态,结果为 {res} :--: 0 表示非缩减模式,1 表示缩减模式")
+ res = self.c.read_holding_registers(40511, count=1).registers[0]
+ self.logger("DEBUG", "openapi", f"modbus: 40511 获取机器人缩减模式状态,结果为 {res} :--: 0 表示非缩减模式,1 表示缩减模式")
return res
@property
def w_robot_is_busy(self): # OK
- res = self.__c.read_holding_registers(40512, count=1).registers[0]
- self.logger("INFO", "openapi", f"modbus: 40512 获取机器人是否处于 busy 状态,结果为 {res} :--: 0 表示未处于 busy 状态,1 表示处于 busy 状态")
+ res = self.c.read_holding_registers(40512, count=1).registers[0]
+ self.logger("DEBUG", "openapi", f"modbus: 40512 获取机器人是否处于 busy 状态,结果为 {res} :--: 0 表示未处于 busy 状态,1 表示处于 busy 状态")
return res
@property
def w_robot_is_moving(self): # OK
- res = self.__c.read_holding_registers(40513, count=1).registers[0]
- self.logger("INFO", "openapi", f"modbus: 40513 获取机器人是否处于运动状态,结果为 {res} :--: 0 表示未运动,1 表示正在运动")
+ res = self.c.read_holding_registers(40513, count=1).registers[0]
+ self.logger("DEBUG", "openapi", f"modbus: 40513 获取机器人是否处于运动状态,结果为 {res} :--: 0 表示未运动,1 表示正在运动")
return res
@property
def w_safe_door_state(self): # OK
- res = self.__c.read_holding_registers(40514, count=1).registers[0]
- self.logger("INFO", "openapi", f"modbus: 40514 获取机器人是否处于安全门打开状态,需自动模式下执行,结果为 {res} :--: 0 表示未触发安全门,1 表示已触发安全门")
+ res = self.c.read_holding_registers(40514, count=1).registers[0]
+ self.logger("DEBUG", "openapi", f"modbus: 40514 获取机器人是否处于安全门打开状态,需自动模式下执行,结果为 {res} :--: 0 表示未触发安全门,1 表示已触发安全门")
return res
@property
def w_safe_region01_trig_state(self): # OK
- res = self.__c.read_holding_registers(40515, count=1).registers[0]
- self.logger("INFO", "openapi", f"modbus: 40515 获取安全区域 safe region01 的触发状态,结果为 {res} :--: 0 表示未触发,1 表示已触发")
+ res = self.c.read_holding_registers(40515, count=1).registers[0]
+ self.logger("DEBUG", "openapi", f"modbus: 40515 获取安全区域 safe region01 的触发状态,结果为 {res} :--: 0 表示未触发,1 表示已触发")
return res
@property
def w_safe_region02_trig_state(self): # OK
- res = self.__c.read_holding_registers(40516, count=1).registers[0]
- self.logger("INFO", "openapi", f"modbus: 40516 获取安全区域 safe region02 的触发状态,结果为 {res} :--: 0 表示未触发,1 表示已触发")
+ res = self.c.read_holding_registers(40516, count=1).registers[0]
+ self.logger("DEBUG", "openapi", f"modbus: 40516 获取安全区域 safe region02 的触发状态,结果为 {res} :--: 0 表示未触发,1 表示已触发")
return res
@property
def w_safe_region03_trig_state(self): # OK
- res = self.__c.read_holding_registers(40517, count=1).registers[0]
- self.logger("INFO", "openapi", f"modbus: 40517 获取安全区域 safe region03 的触发状态,结果为 {res} :--: 0 表示未触发,1 表示已触发")
+ res = self.c.read_holding_registers(40517, count=1).registers[0]
+ self.logger("DEBUG", "openapi", f"modbus: 40517 获取安全区域 safe region03 的触发状态,结果为 {res} :--: 0 表示未触发,1 表示已触发")
return res
@property
def w_soft_estop_state(self): # OK
- res = self.__c.read_holding_registers(40518, count=1).registers[0]
- self.logger("INFO", "openapi", f"modbus: 40518 获取机器人软急停状态,结果为 {res} :--: 0 表示未触发软急停,1 表示已触发软急停")
+ res = self.c.read_holding_registers(40518, count=1).registers[0]
+ self.logger("DEBUG", "openapi", f"modbus: 40518 获取机器人软急停状态,结果为 {res} :--: 0 表示未触发软急停,1 表示已触发软急停")
return res
def io_write_coils(self, addr, action): # OK | 名字叫写线圈,其实是写 modbus 的 discrete inputs(DI)
# e.g. io_write_coils(0, 1)
# e.g. io_write_coils(1, 1)
# e.g. io_write_coils(0, [1, 1, 1])
- self.__c.write_coils(addr, action)
- self.logger("INFO", "openapi", f"modbus: 执行给 DI 地址 {addr} 赋值为 {action},可根据情况传递列表,实现一次性赋值多个")
+ self.c.write_coils(addr, action)
+ self.logger("DEBUG", "openapi", f"modbus: 执行给 DI 地址 {addr} 赋值为 {action},可根据情况传递列表,实现一次性赋值多个")
time.sleep(clibs.INTERVAL)
def io_read_coils(self): # OK | 读 modbus 的 16 个 discrete inputs(DI)
- res = self.__c.read_coils(0, count=16).bits
- self.logger("INFO", "openapi", f"modbus: 执行读取所有 DI 的结果为 {res}")
+ res = self.c.read_coils(0, count=16).bits
+ self.logger("DEBUG", "openapi", f"modbus: 执行读取所有 DI 的结果为 {res}")
return res
def io_read_discretes(self): # OK | 读 modbus 的 coil outputs(DO)
- res = self.__c.read_discrete_inputs(0, count=16).bits
- self.logger("INFO", "openapi", f"modbus: 执行读取所有 DO 的结果为 {res}")
+ res = self.c.read_discrete_inputs(0, count=16).bits
+ self.logger("DEBUG", "openapi", f"modbus: 执行读取所有 DO 的结果为 {res}")
return res
def read_ready_to_go(self):
- result = self.__c.read_holding_registers(40600, count=1)
+ result = self.c.read_holding_registers(40600, count=1)
return result.registers[0]
def read_scenario_time(self):
- results = self.__c.read_holding_registers(40601, count=2)
- result = self.__c.convert_from_registers(registers=results.registers, data_type=self.__c.DATATYPE.FLOAT32, word_order="little")
+ results = self.c.read_holding_registers(40601, count=2)
+ result = self.c.convert_from_registers(registers=results.registers, data_type=self.c.DATATYPE.FLOAT32, word_order="little")
return result
def read_capture_start(self):
- result = self.__c.read_holding_registers(40603, count=1)
+ result = self.c.read_holding_registers(40603, count=1)
return result.registers[0]
class HmiRequest(QThread):
output = Signal(str, str)
- socket.setdefaulttimeout(clibs.INTERVAL * 3)
def __init__(self, ip, port, port_xs, /):
super().__init__()
@@ -369,6 +371,7 @@ class HmiRequest(QThread):
self.__t_unpackage_xs.start()
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}")
@@ -381,11 +384,11 @@ class HmiRequest(QThread):
if self.__is_connected:
try:
self.__is_connected = False
- time.sleep(clibs.INTERVAL*2)
+ time.sleep(clibs.INTERVAL/2)
self.c.close()
self.c_xs.close()
- time.sleep(clibs.INTERVAL*2)
clibs.status["hmi"] = 0
+ self.logger("INFO", "openapi", f"hmi: 关闭 Socket 连接成功", "green")
except Exception as err:
self.logger("ERROR", "openapi", f"hmi: 关闭 Socket 连接失败 {err}", "red", "HmiCloseFailed")
@@ -393,21 +396,20 @@ class HmiRequest(QThread):
self.close()
try:
self.c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.c.settimeout(clibs.INTERVAL*5)
self.c.connect((self.__ip, self.__port))
self.c_xs = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.c_xs.settimeout(clibs.INTERVAL*5)
self.c_xs.connect((self.__ip, self.__port_xs))
# 尝试连续三次发送心跳包,确认建联成功
state = None
for i in range(3):
- _, state = self.execution.__wrapped__(self, "controller.heart")
- time.sleep(clibs.INTERVAL/5)
- if state is not None:
- self.__is_connected = True
- self.logger("INFO", "openapi", "hmi: HMI connection success...", "green")
- else:
- self.logger("ERROR", "openapi", "hmi: HMI connection failed...", "red", "HmiConnFailed")
+ _ = self.execution("controller.heart")
+ time.sleep(clibs.INTERVAL/2)
+ self.__is_connected = True
+ self.logger("INFO", "openapi", "hmi: HMI connection success...", "green")
except Exception as err:
- self.logger("ERROR", "openapi", f"hmi: HMI connection timeout...
err = {err}", "red", "HmiConnTimeout")
+ self.logger("ERROR", "openapi", f"hmi: HMI connection timeout...", "red", "HmiConnTimeout")
def __heartbeat(self):
while self.__is_connected:
@@ -443,7 +445,7 @@ class HmiRequest(QThread):
callback = key.data
callback(key.fileobj, mask)
except Exception as Err:
- self.logger("INFO", "openapi", f"hmi: 老协议解包报错 {Err}")
+ self.logger("DEBUG", "openapi", f"hmi: 老协议解包报错 {Err}", "red", "UnpackageFailed")
def __get_headers(self, index, data):
if index + 8 < len(data):
@@ -484,7 +486,7 @@ class HmiRequest(QThread):
if len(data[self.__index:]) >= pkg_value:
self.__response = data[self.__index:self.__index + pkg_value]
self.__index += pkg_value
- self.logger("INFO", "openapi", str(json.loads(self.__response.decode())))
+ self.logger("DEBUG", "openapi", str(json.loads(self.__response.decode())))
self.__response = b""
self.__leftovers = 0
self.__is_first_frame = True
@@ -532,7 +534,7 @@ class HmiRequest(QThread):
if self.__valid_data_length == 0:
# with open(f"{clibs.log_path}/response.txt", mode="a", encoding="utf-8") as f_res:
# f_res.write(f"{json.loads(self.__response.decode())}" + "\n")
- self.logger("INFO", "openapi", str(json.loads(self.__response.decode())))
+ self.logger("DEBUG", "openapi", str(json.loads(self.__response.decode())))
self.__response = b""
self.__is_first_frame = True
continue # 此时应该重新 get_headers
@@ -617,7 +619,7 @@ class HmiRequest(QThread):
self.__half_frm_flag = -1
if self.__valid_data_length == 0:
- self.logger("INFO", "openapi", str(json.loads(self.__response.decode())))
+ self.logger("DEBUG", "openapi", str(json.loads(self.__response.decode())))
self.__response = b""
self.__is_first_frame = True
continue
@@ -645,7 +647,7 @@ class HmiRequest(QThread):
self.__index += frm_value
self.__valid_data_length -= frm_value
if self.__valid_data_length == 0:
- self.logger("INFO", "openapi", str(json.loads(self.__response.decode())))
+ self.logger("DEBUG", "openapi", str(json.loads(self.__response.decode())))
self.__response = b""
self.__is_first_frame = True
continue
@@ -705,7 +707,7 @@ class HmiRequest(QThread):
callback = key.data
callback(key.fileobj, mask)
except Exception as err:
- self.logger("INFO", "openapi", f"hmi: xService解包报错 {err}", "red")
+ self.logger("DEBUG", "openapi", f"hmi: xService解包报错 {err}", "red", "XsUnpackageFailed")
def get_response_xs(self, data):
char, response = "", self.__response_xs
@@ -713,170 +715,70 @@ class HmiRequest(QThread):
if char != "\r":
response = "".join([response, char])
else:
- self.logger("INFO", "openapi", response)
+ self.logger("DEBUG", "openapi", response)
self.response_xs = response
response = ""
else:
self.__response_xs = response
- def get_from_id(self, msg_id, state):
- if state == "done_xs":
- return
- f_text = f"%{msg_id}%"
- for _ in range(3):
- time.sleep(clibs.INTERVAL * 4)
+ @clibs.handle_exception
+ def get_from_id(self, msg_id):
+ f_text, flag, records, time_delay, ts = f"%{msg_id}%", False, "Null", clibs.INTERVAL*10, msg_id.split("@")[-1]
+ t = ts.replace("T", " ")
+ t_ts = datetime.timestamp(datetime.strptime(t, "%Y-%m-%d %H:%M:%S.%f"))
+ t_send = datetime.strftime(datetime.fromtimestamp(t_ts-time_delay), '%Y-%m-%d %H:%M:%S.%f')
+ t_receive = datetime.strftime(datetime.fromtimestamp(t_ts+time_delay), '%Y-%m-%d %H:%M:%S.%f')
+ for idx in range(time_delay):
+ time.sleep(clibs.INTERVAL)
try:
clibs.lock.acquire(True)
- clibs.cursor.execute(f"select content from {clibs.tb_name} where content like '{f_text}'")
+ clibs.cursor.execute(f"SELECT content FROM logs WHERE timestamp BETWEEN '{t_send}' AND '{t_receive}' AND content LIKE '{f_text}'")
records = clibs.cursor.fetchall()
+ flag = True if len(records) == 2 else False
finally:
clibs.lock.release()
- if len(records) == 2:
- return records
+ if flag is True:
+ return records
else:
- self.close()
- self.logger("ERROR", "openapi", f"hmi: 无法找到请求 {msg_id} 的响应", "red", "ResponseNotFound")
+ self.logger("ERROR", "openapi", f"hmi: {time_delay}s内无法找到请求 {msg_id} 的响应!", "red", "ResponseNotFound")
- @staticmethod
- def validate_req(func):
- @functools.wraps(func)
- def wrapper(self, *args, **kwargs):
- msg_id, state = func(self, *args, **kwargs)
- t = threading.Thread(target=self.get_from_id, args=(msg_id, state))
- t.daemon = True
- t.start()
- return msg_id, state
- return wrapper
-
- @validate_req
- def execution(self, command, p_flag=0, **kwargs):
- req, state = None, None
+ def execution(self, command, **kwargs):
+ req = None
try:
- with open(f"{clibs.PREFIX}/files/protocols/hmi/{command}.json", encoding="utf-8", mode="r") as f_json:
+ with open(f"assets/files/protocols/hmi/{command}.json", encoding="utf-8", mode="r") as f_json:
req = json.load(f_json)
+ t = datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f")
+ req["id"] = f"{command}@{t}"
+ flag = req["p_type"]
+ del req["p_type"]
except Exception as err:
self.logger("ERROR", "openapi", f"hmi: 暂不支持 {command} 功能,或确认该功能存在... {err}", "red", "CommandNotSupport")
- if p_flag == 0: # for old protocols
- match command:
- case "state.set_tp_mode":
- req["data"]["tp_mode"] = kwargs["tp_mode"]
- case "overview.set_autoload":
- req["data"]["autoload_prj_path"] = kwargs["autoload_prj_path"]
- case "overview.reload":
- req["data"]["prj_path"] = kwargs["prj_path"]
- req["data"]["tasks"] = kwargs["tasks"]
- case "rl_task.pp_to_main" | "rl_task.run" | "rl_task.stop":
- req["data"]["tasks"] = kwargs["tasks"]
- case "rl_task.set_run_params":
- req["data"]["loop_mode"] = kwargs["loop_mode"]
- req["data"]["override"] = kwargs["override"]
- case "diagnosis.set_params":
- req["data"]["display_pdo_params"] = kwargs["display_pdo_params"]
- req["data"]["frequency"] = kwargs["frequency"]
- req["data"]["version"] = kwargs["version"]
- case "diagnosis.open":
- req["data"]["open"] = kwargs["open"]
- req["data"]["display_open"] = kwargs["display_open"]
- req["data"]["overrun"] = kwargs["overrun"]
- req["data"]["turn_area"] = kwargs["turn_area"]
- req["data"]["delay_motion"] = kwargs["delay_motion"]
- case "register.set_value":
- req["data"]["name"] = kwargs["name"]
- req["data"]["type"] = kwargs["type"]
- req["data"]["bias"] = kwargs["bias"]
- req["data"]["value"] = kwargs["value"]
- case "diagnosis.save":
- req["data"]["save"] = kwargs["save"]
- case "socket.set_params":
- req["data"] = kwargs["data"]
- case "fieldbus_device.set_params":
- req["data"]["device_name"] = kwargs["device_name"]
- req["data"]["enable"] = kwargs["enable"]
- case "soft_limit.set_params":
- req["data"] = kwargs["data"]
- case "move.set_quickturn_pos":
- req["data"]["enable_home"] = kwargs["enable_home"]
- req["data"]["enable_drag"] = kwargs["enable_drag"]
- req["data"]["enable_transport"] = kwargs["enable_transport"]
- req["data"]["end_posture"] = kwargs["end_posture"]
- case "move.quick_turn":
- req["data"]["name"] = kwargs["name"]
- case "move.stop":
- req["data"]["stoptype"] = kwargs["stoptype"]
- case "jog.start":
- req["data"]["index"] = kwargs["index"]
- req["data"]["direction"] = kwargs["direction"]
- req["data"]["is_ext"] = kwargs["is_ext"]
- case "jog.set_params":
- req["data"]["step"] = kwargs["step"]
- req["data"]["override"] = kwargs["override"]
- req["data"]["space"] = kwargs["space"]
- case "diagnosis.get_params":
- req["data"]["version"] = kwargs["version"]
- case "system_io.update_configuration":
- req["data"]["input_system_io"] = kwargs["input_system_io"]
- req["data"]["output_system_io"] = kwargs["output_system_io"]
- case "modbus.set_params":
- req["data"]["enable_slave"] = kwargs["enable_slave"]
- req["data"]["ip"] = kwargs["ip"]
- req["data"]["port"] = kwargs["port"]
- req["data"]["slave_id"] = kwargs["slave_id"]
- req["data"]["enable_master"] = kwargs["enable_master"]
- case "modbus.get_values":
- req["data"]["mode"] = kwargs["mode"]
- case "move.set_monitor_cfg":
- req["data"]["ref_coordinate"] = kwargs["ref_coordinate"]
- case "move.set_params":
- req["data"]["MOTION"] = kwargs["data"]
- case "move.set_quickstop_distance":
- req["data"]["distance"] = kwargs["distance"]
- case "collision.set_params":
- req["data"] = kwargs["data"]
- case "collision.set_state":
- req["data"]["collision_state"] = kwargs["collision_state"]
- case "controller.set_params":
- req["data"]["time"] = kwargs["time"]
- case "drag.set_params":
- req["data"]["enable"] = kwargs["enable"]
- req["data"]["space"] = kwargs["space"]
- req["data"]["type"] = kwargs["type"]
- case _:
- pass
+ match command:
+ case "state.set_tp_mode" | "overview.set_autoload" | "overview.reload" | "rl_task.pp_to_main" | "rl_task.run" | "rl_task.stop" | "rl_task.set_run_params" | "diagnosis.set_params" | "diagnosis.open" | "drag.set_params" | "controller.set_params" | "collision.set_state" | "collision.set_params" | "move.set_quickstop_distance" | "move.set_params" | "move.set_monitor_cfg" | "modbus.get_values" | "modbus.set_params" | "system_io.update_configuration" | "diagnosis.get_params" | "jog.set_params" | "jog.start" | "move.stop" | "move.quick_turn" | "move.set_quickturn_pos" | "soft_limit.set_params" | "fieldbus_device.set_params" | "socket.set_params" | "diagnosis.save" | "register.set_value":
+ req["data"].update(kwargs)
+ case "safety.safety_area.signal_enable" | "safety.safety_area.overall_enable" | "safety.safety_area.safety_area_enable" | "safety.safety_area.set_param":
+ req["c"].update(kwargs)
+ case "log_code.data.code_list":
+ req["s"]["log_code.data"]["code_list"] = kwargs["code_list"]
+ case _:
+ pass
- req["id"] = f"{command}-{time.time()}"
+ if flag == 0:
cmd = json.dumps(req, separators=(",", ":"))
- print(f"correct cmd = {cmd}")
try:
self.c.send(self.package(cmd))
- self.logger("INFO", "openapi", f"hmi: 老协议请求发送成功 {cmd}")
- state = "done"
+ self.logger("DEBUG", "openapi", f"hmi: 老协议请求发送成功 {cmd}")
except Exception as err:
self.logger("ERROR", "openapi", f"hmi: 老协议请求发送失败 {cmd},报错信息 {err}", "red", "CommandSendFailed")
- return req["id"], state
- elif p_flag == 1: # for xService
- match command:
- case "safety.safety_area.signal_enable":
- req["c"]["safety.safety_area.signal_enable"]["signal"] = kwargs["signal"]
- case "safety.safety_area.overall_enable":
- req["c"]["safety.safety_area.overall_enable"]["enable"] = kwargs["enable"]
- case "log_code.data.code_list":
- req["s"]["log_code.data"]["code_list"] = kwargs["code_list"]
- case "safety.safety_area.safety_area_enable":
- req["c"]["safety.safety_area.safety_area_enable"]["id"] = kwargs["id"]
- req["c"]["safety.safety_area.safety_area_enable"]["enable"] = kwargs["enable"]
- case "safety.safety_area.set_param":
- req["c"]["safety.safety_area.set_param"] = kwargs["data"]
- case _:
- pass
-
+ elif flag == 1:
try:
self.c_xs.send(self.package_xs(req))
- self.logger("INFO", "openapi", f"hmi: xService请求发送成功 {req}")
- state = "done"
+ self.logger("DEBUG", "openapi", f"hmi: xService请求发送成功 {req}")
except Exception as Err:
self.logger("ERROR", "openapi", f"hr: xService请求发送失败 {req} 报错信息 {Err}", "red", "CommandSendFailed")
- return command, state
+
+ return req["id"]
# =================================== ↓↓↓ specific functions ↓↓↓ ===================================
@@ -1859,7 +1761,7 @@ class HmiRequest(QThread):
def __get_data(self, upper_func, command, flag=0, **kwargs):
msg_id, state = self.execution(command, protocol_flag=flag, **kwargs)
- records = clibs.c_hr.get_from_id(msg_id, state)
+ records = clibs.c_hr.get_from_id(msg_id)
for record in records:
if "请求发送成功" not in record[0]:
data = eval(record[0])["data"]
@@ -1872,49 +1774,52 @@ class ExternalCommunication(QThread):
def __init__(self, ip, port, /):
super().__init__()
- self.__c = None
+ self.c = None
self.ip = ip
self.port = int(port)
self.suffix = "\r"
self.exec_desc = " :--: 返回 true 表示执行成功,false 失败"
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 net_conn(self):
- clibs.c_hr.set_socket_params(False, "0.0.0.0", self.port, "\r")
- clibs.c_hr.set_socket_params(True, "0.0.0.0", self.port, "\r")
- self.__c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ # clibs.c_hr.execution("socket.set_params", enable=False, ip="0.0.0.0", port=str(self.port), suffix="\r", type=1)
+ # time.sleep(clibs.INTERVAL)
+ clibs.c_hr.execution("socket.set_params", enable=True, ip="0.0.0.0", port=str(self.port), suffix="\r", type=1)
+ time.sleep(clibs.INTERVAL*2)
+ self.c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.c.settimeout(clibs.INTERVAL*5)
try:
- self.__c.connect((self.ip, self.port))
+ self.c.connect((self.ip, self.port))
self.logger("INFO", "openapi", f"ec: 外部通信连接成功...", "green")
- return self.__c
+ return self.c
except Exception as err:
self.logger("ERROR", "openapi", f"ec: 外部通信连接失败... {err}", "red", "EcConnFailed")
def close(self):
if clibs.status["ec"]:
try:
- self.__c.close()
+ self.c.close()
+ self.logger("INFO", "openapi", f"ec: 关闭 EC 连接成功", "green")
except Exception as err:
self.logger("ERROR", "openapi", f"ec: 关闭 EC 连接失败:{err}", "red", "EcCloseFailed")
def s_string(self, directive):
order = "".join([directive, self.suffix])
- self.__c.send(order.encode())
- time.sleep(clibs.INTERVAL)
+ self.c.send(order.encode())
def r_string(self, directive):
result, char = "", ""
while char != self.suffix:
try:
- char = self.__c.recv(1).decode(encoding="unicode_escape")
+ char = self.c.recv(1).decode(encoding="unicode_escape")
except Exception as err:
self.logger("ERROR", "openapi", f"ec: 获取请求指令 {directive} 的返回数据超时,需确认指令发送格式以及内容正确!具体报错信息如下 {err}", "red", "RecvMsgFailed")
result = "".join([result, char])
- time.sleep(clibs.INTERVAL)
return result
# =================================== ↓↓↓ specific functions ↓↓↓ ===================================
@@ -2150,6 +2055,7 @@ class ExternalCommunication(QThread):
def __exec_cmd(self, directive, description, more_desc=""):
self.s_string(directive)
+ time.sleep(clibs.INTERVAL)
result = self.r_string(directive).strip()
self.logger("INFO", "openapi", f"ec: 执行{description}指令是 {directive},返回值为 {result}{more_desc}")
return result
@@ -2174,6 +2080,7 @@ class PreDos(object):
print(f"predos: SSH 无法连接到 {self.ip}:{self.ssh_port},需检查网络连通性或者登录信息是否正确 {err}")
raise Exception("SshConnFailed")
+ @clibs.handle_exception
def push_prj_to_server(self, prj_file):
# prj_file:本地工程完整路径
self.__ssh2server()
@@ -2242,35 +2149,38 @@ class PreDos(object):
class RobotInit(object):
@staticmethod
+ @clibs.handle_exception
def modbus_init():
- pd = PreDos(clibs.ip_addr, clibs.ssh_port, clibs.username, clibs.password)
+ clibs.c_pd = PreDos(clibs.ip_addr, clibs.ssh_port, clibs.username, clibs.password)
# 推送配置文件
- print("init: 推送配置文件 fieldbus_device.json/registers.json/registers.xml 到控制器,并配置 IO 设备,设备号为 7...")
- robot_params = clibs.c_hr.get_robot_params
- robot_type = robot_params["robot_type"]
- security_type = robot_params["security_type"]
- controller_type = robot_params["controller_type"]
+ 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_params = eval(record[0])
+ robot_type = robot_params["data"]["robot_type"]
+ security_type = robot_params["data"]["security_type"]
+ controller_type = robot_params["data"]["controller_type"]
io_device_file = "_".join(["io_device", controller_type, security_type, "1"])
user_settings = "/home/luoshi/bin/controller/user_settings"
interactive_data = f"/home/luoshi/bin/controller/interactive_data/{robot_type}"
config_files = [
- f"{clibs.PREFIX}/files/projects/fieldbus_device.json",
- f"{clibs.PREFIX}/files/projects/registers.json",
- f"{clibs.PREFIX}/files/projects/registers.xml"
+ f"assets/files/projects/fieldbus_device.json",
+ f"assets/files/projects/registers.json",
+ f"assets/files/projects/registers.xml"
]
for config_file in config_files:
filename = config_file.split("/")[-1]
- pd.push_file_to_server(config_file, f"{user_settings}/{filename}")
- pd.push_file_to_server(config_file, f"{interactive_data}/{filename}")
+ clibs.c_pd.push_file_to_server(config_file, f"{user_settings}/{filename}")
+ clibs.c_pd.push_file_to_server(config_file, f"{interactive_data}/{filename}")
io_device_autotest = {"ai_num": 0, "ao_num": 0, "di_num": 16, "do_num": 16, "extend_attr": {"mode": "slaver", "name": "autotest", "type": "MODBUS"}, "id": 7, "name": "autotest", "type": 6}
-
io_device_file_local = f"{io_device_file}"
io_device_file_local_tmp = f"{io_device_file}_tmp"
io_device_file_remote = f"{user_settings}/{io_device_file}"
- pd.pull_file_from_server(io_device_file_remote, io_device_file_local)
+ clibs.c_pd.pull_file_from_server(io_device_file_remote, io_device_file_local)
with open(io_device_file_local, mode="r", encoding="utf-8") as f:
data = json.load(f)
for _ in data["device_list"]:
@@ -2280,15 +2190,17 @@ class RobotInit(object):
data["device_list"].append(io_device_autotest)
with open(io_device_file_local_tmp, mode="w", encoding="utf-8") as f_tmp:
json.dump(data, f_tmp, indent=4)
- pd.push_file_to_server(io_device_file_local_tmp, f"{user_settings}/{io_device_file}")
- pd.push_file_to_server(io_device_file_local_tmp, f"{interactive_data}/{io_device_file}")
-
- # os.remove(io_device_file_local)
- # os.remove(io_device_file_local_tmp)
- clibs.c_hr.reload_io()
- clibs.c_hr.reload_registers()
- clibs.c_hr.reload_fieldbus()
- clibs.c_hr.set_fieldbus_device_params("autotest", True)
+ clibs.c_pd.push_file_to_server(io_device_file_local_tmp, f"{user_settings}/{io_device_file}")
+ clibs.c_pd.push_file_to_server(io_device_file_local_tmp, f"{interactive_data}/{io_device_file}")
+ try:
+ os.remove(io_device_file_local)
+ os.remove(io_device_file_local_tmp)
+ except:
+ ...
+ clibs.c_hr.execution("io_device.load_cfg")
+ clibs.c_hr.execution("modbus.load_cfg")
+ clibs.c_hr.execution("fieldbus_device.load_cfg")
+ clibs.c_hr.execution("fieldbus_device.set_params", device_name="autotest", enable=True)
def robot_init(self):
pd = PreDos(clibs.ip_addr, clibs.ssh_port, clibs.username, clibs.password)
@@ -2495,17 +2407,17 @@ class RobotInit(object):
class UpgradeJsonCmd(object):
def __init__(self):
- self.__c = None
+ self.c = None
self.__sock_conn()
def __sock_conn(self):
# socket connect
print(f"正在连接 {clibs.ip_addr}:{clibs.upgrade_port}...")
try:
- self.__c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- self.__c.connect((clibs.ip_addr, clibs.upgrade_port))
- self.__c.setblocking(True)
- self.__c.settimeout(3)
+ self.c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ self.c.connect((clibs.ip_addr, clibs.upgrade_port))
+ self.c.setblocking(True)
+ self.c.settimeout(3)
except Exception as Err:
print(f"upgrade: {Err} | 连接 {clibs.ip_addr}:{clibs.upgrade_port} 失败...")
raise Exception("UpgradePortConnFailed")
@@ -2520,7 +2432,7 @@ class UpgradeJsonCmd(object):
def __recv_result(self, cmd):
time.sleep(clibs.INTERVAL)
try:
- res = self.__c.recv(10240).decode()
+ res = self.c.recv(10240).decode()
except Exception as err:
print(f"upgrade: 请求命令 {cmd.decode()} 的返回错误 {err}")
raise Exception("ResponseError")
@@ -2530,11 +2442,11 @@ class UpgradeJsonCmd(object):
def __exec(self, command: dict):
try:
- self.__c.recv(10240)
+ self.c.recv(10240)
except Exception:
pass
cmd = json.dumps(command, separators=(",", ":")).encode("utf-8")
- self.__c.sendall(self.__do_package(cmd))
+ self.c.sendall(self.__do_package(cmd))
res = self.__recv_result(cmd)
print(f"upgrade: 请求命令 {cmd.decode()} 的返回信息:{res}")
diff --git a/codes/durable/__init__.py b/codes/durable/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/codes/durable/factory_test.py b/codes/durable/factory_test.py
new file mode 100644
index 0000000..8d7f461
--- /dev/null
+++ b/codes/durable/factory_test.py
@@ -0,0 +1,293 @@
+import json
+import threading
+import time
+import pandas
+import numpy
+import math
+import csv
+from PySide6.QtCore import Signal, QThread
+from codes.common import clibs
+
+
+class DoFactoryTest(QThread):
+ output = Signal(str, str)
+ curve_map = {
+ "周期内平均转矩": ["device_servo_trq_feedback", ],
+ "周期内最大速度": ["hw_joint_vel_feedback", ],
+ }
+
+ def __init__(self, dir_path, interval, procs, /):
+ super().__init__()
+ self.dir_path = dir_path
+ self.interval = int(interval) if interval != "" else 300
+ self.procs = procs
+ self.idx = 6
+ self.curves = []
+
+ 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():
+ for proc_name, is_enabled in self.procs.items():
+ if is_enabled:
+ self.curves.extend(self.curve_map[proc_name])
+
+ if len(self.curves) == 0:
+ self.logger("ERROR", "factory", "未查询到需要记录数据的曲线,至少选择一个!", "red", "CurveNameError")
+
+ if len(data_dirs) != 0 or len(data_files) != 1:
+ self.logger("ERROR", "factory", "初始路径下不允许有文件夹,且初始路径下只能存在一个工程文件 —— *.zip,确认后重新运行!", "red", "InitFileError")
+
+ if not data_files[0].endswith(".zip"):
+ self.logger("ERROR", "factory", f"{data_files[0]} 不是一个有效的工程文件,需确认!", "red", "ProjectFileError")
+
+ return data_files[0]
+
+ @clibs.handle_exception
+ def get_configs():
+ robot_type, records = None, None
+ 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"]
+ 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", f"无法打开 {local_file}
{Err}", "red", "OpenFileError")
+
+ # 最大角速度,额定电流,减速比,额定转速
+ version = configs["VERSION"]
+ m_avs = configs["MOTION"]["JOINT_MAX_SPEED"]
+ self.logger("INFO", "factory", f"get_configs: 机型文件版本 {robot_type}_{version}")
+ self.logger("INFO", "factory", f"get_configs: 各关节角速度 {m_avs}")
+ return m_avs
+
+ self.logger("INFO", "factory", "正在做初始化校验和配置,这可能需要一点时间......", "green")
+ prj_file = check_files()
+ if prj_file is None:
+ return
+ avs = get_configs()
+ params = {
+ "prj_file": prj_file,
+ "interval": self.interval,
+ "avs": avs,
+ }
+ self.logger("INFO", "factory", "数据目录合规性检查结束,未发现问题......", "green")
+ return params
+
+ @clibs.handle_exception
+ def change_curve_state(self, stat):
+ display_pdo_params = [{"name": name, "channel": chl} for name in self.curves for chl in range(6)]
+ 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, params):
+ prj_file, interval = params["prj_file"], params["interval"]
+ # 1. 关闭诊断曲线,触发软急停,并解除,目的是让可能正在运行着的机器停下来,切手动模式并下电
+ self.change_curve_state(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. 开始运行程序
+ self.logger("INFO", "factory", f"正在采集场景工程的周期,大概1min左右......", "blue")
+ 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", "15s 内未收到机器人的运行信号,需要确认RL程序编写正确并正常执行...", "red", "ReadySignalTimeoutError")
+ else:
+ time.sleep(clibs.INTERVAL)
+
+ # 4. 获取初始数据,周期时间,首次的各轴平均电流值,打开诊断曲线,并执行采集
+ time.sleep(clibs.INTERVAL*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", f"耐久工程的周期时间:{scenario_time}s | 单轮次执行时间:{scenario_time+interval}~{scenario_time*2+interval}")
+ break
+ else:
+ time.sleep(clibs.INTERVAL)
+ if (time.time() - t_start) > 900:
+ self.logger("ERROR", "factory", f"900s内未收到耐久工程的周期时间,需要确认RL程序和工具通信交互是否正常执行(支持最长工程周期时间为300s)......", "red", "GetScenarioTimeError")
+
+ # 6. 准备数据保存文件
+ for proc_name, is_enabled in self.procs.items():
+ if not is_enabled:
+ continue
+
+ with open(f"{self.dir_path}/{proc_name}.csv", mode="a+", newline="") as f_csv:
+ for curve in self.curve_map[proc_name]:
+ 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[self.idx]:
+ 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", 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(clibs.INTERVAL/10)
+
+ self.change_curve_state(True)
+ time.sleep(scenario_time)
+ end_time = time.time()
+ start_time = end_time - scenario_time
+ self.change_curve_state(False)
+ # 保留数据并处理输出
+ self.gen_results(params, start_time, end_time)
+ else:
+ self.change_curve_state(False)
+ self.logger("INFO", "factory", "后台数据清零完成,现在可以重新运行其他程序。", "green")
+
+ @clibs.handle_exception
+ def gen_results(self, params, start_time, end_time):
+ s_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(start_time))
+ 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 timestamp BETWEEN '{s_time}' AND '{e_time}' AND content LIKE '%diagnosis.result%' ORDER BY id ASC")
+ records = clibs.cursor.fetchall()
+ finally:
+ clibs.lock.release()
+
+ self.data_proc(records, params)
+
+ @clibs.handle_exception
+ def data_proc(self, records, params):
+ for proc_name, is_enabled in self.procs.items():
+ if not is_enabled:
+ continue
+
+ if proc_name == "周期内平均转矩":
+ # get_avg_trq(records, params, w2t)
+ t = threading.Thread(target=self.get_avg_trq, args=(records, params, proc_name))
+ t.daemon = True
+ t.start()
+ elif proc_name == "周期内最大速度":
+ # get_joint_max_vel(records, params, w2t)
+ t = threading.Thread(target=self.get_joint_max_vel, args=(records, params, proc_name))
+ t.daemon = True
+ t.start()
+
+ @clibs.handle_exception
+ def get_avg_trq(self, records, params, proc_name):
+ d_trq, results = [[], [], [], [], [], []], [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}/{proc_name}.csv", mode="a+", newline="") as f_csv:
+ csv_writer = csv.writer(f_csv)
+ csv_writer.writerow(results)
+
+ @clibs.handle_exception
+ def get_joint_max_vel(self, records, params, proc_name):
+ d_trq, results = [[], [], [], [], [], []], [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}/{proc_name}.csv", mode="a+", newline="") as f_csv:
+ csv_writer = csv.writer(f_csv)
+ csv_writer.writerow(results)
+
+ @staticmethod
+ def detect_db_size():
+ @clibs.db_lock
+ @clibs.handle_exception
+ def release_memory():
+ line_number = 20000
+ leftover = 4000 # 200s
+ clibs.cursor.execute("SELECT COUNT(id) FROM logs")
+ len_records = clibs.cursor.fetchone()[0]
+ if len_records > line_number:
+ del_num = len_records - leftover + 1
+ clibs.cursor.execute(f"DELETE FROM logs WHERE id < {del_num}")
+ clibs.cursor.execute(f"UPDATE logs SET id=(id-{del_num - 1}) WHERE id > {del_num - 1}")
+ clibs.cursor.execute(f"UPDATE sqlite_sequence SET seq = {leftover + 1} WHERE name = 'logs' ")
+ clibs.cursor.execute("VACUUM")
+
+ while True:
+ release_memory()
+ time.sleep(clibs.INTERVAL*10)
+
+ @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:
+ self.logger("ERROR", "factory", "processing: 需要在网络设置中连接HMI以及Modbus通信!", "red", "NetworkError")
+
+ t = threading.Thread(target=self.detect_db_size)
+ t.daemon = True
+ t.start()
+
+ data_dirs, data_files = clibs.traversal_files(self.dir_path, self.output)
+ params = self.initialization(data_dirs, data_files)
+ clibs.c_pd.push_prj_to_server(params["prj_file"])
+ self.run_rl(params)
+
+ self.logger("INFO", "factory", "-"*60 + "
全部处理完毕
", "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", "factory", msg)
diff --git a/codes/ui/__init__.py b/codes/ui/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/code/ui/main_window.py b/codes/ui/main_window.py
similarity index 93%
rename from code/ui/main_window.py
rename to codes/ui/main_window.py
index 9d6e659..b591b20 100644
--- a/code/ui/main_window.py
+++ b/codes/ui/main_window.py
@@ -27,7 +27,7 @@ class Ui_MainWindow(QMainWindow):
if not MainWindow.objectName():
MainWindow.setObjectName(u"MainWindow")
MainWindow.setEnabled(True)
- MainWindow.resize(1002, 555)
+ MainWindow.resize(1004, 560)
sizePolicy = QSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
@@ -285,12 +285,12 @@ class Ui_MainWindow(QMainWindow):
self.verticalLayout_7.addWidget(self.label_11)
- self.scrollArea = QScrollArea(self.frame)
- self.scrollArea.setObjectName(u"scrollArea")
- self.scrollArea.setWidgetResizable(True)
+ self.sa_durable = QScrollArea(self.frame)
+ self.sa_durable.setObjectName(u"sa_durable")
+ self.sa_durable.setWidgetResizable(True)
self.scrollAreaWidgetContents = QWidget()
self.scrollAreaWidgetContents.setObjectName(u"scrollAreaWidgetContents")
- self.scrollAreaWidgetContents.setGeometry(QRect(0, 0, 211, 78))
+ self.scrollAreaWidgetContents.setGeometry(QRect(0, 0, 212, 78))
self.horizontalLayout_9 = QHBoxLayout(self.scrollAreaWidgetContents)
self.horizontalLayout_9.setObjectName(u"horizontalLayout_9")
self.verticalLayout_5 = QVBoxLayout()
@@ -314,9 +314,9 @@ class Ui_MainWindow(QMainWindow):
self.horizontalLayout_9.addLayout(self.verticalLayout_5)
- self.scrollArea.setWidget(self.scrollAreaWidgetContents)
+ self.sa_durable.setWidget(self.scrollAreaWidgetContents)
- self.verticalLayout_7.addWidget(self.scrollArea)
+ self.verticalLayout_7.addWidget(self.sa_durable)
self.verticalLayout_8.addLayout(self.verticalLayout_7)
@@ -478,6 +478,8 @@ class Ui_MainWindow(QMainWindow):
self.cb_hmi_cmd.addItem("")
self.cb_hmi_cmd.addItem("")
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)
@@ -558,6 +560,12 @@ class Ui_MainWindow(QMainWindow):
self.cb_md_cmd = QComboBox(self.page_2)
self.cb_md_cmd.addItem("")
self.cb_md_cmd.addItem("")
+ self.cb_md_cmd.addItem("")
+ self.cb_md_cmd.addItem("")
+ self.cb_md_cmd.addItem("")
+ self.cb_md_cmd.addItem("")
+ 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)
@@ -638,6 +646,12 @@ class Ui_MainWindow(QMainWindow):
self.cb_ec_cmd = QComboBox(self.page_3)
self.cb_ec_cmd.addItem("")
self.cb_ec_cmd.addItem("")
+ self.cb_ec_cmd.addItem("")
+ self.cb_ec_cmd.addItem("")
+ self.cb_ec_cmd.addItem("")
+ self.cb_ec_cmd.addItem("")
+ 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)
@@ -775,11 +789,10 @@ class Ui_MainWindow(QMainWindow):
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.label_13 = QLabel(self.tab_log)
+ self.label_13.setObjectName(u"label_13")
- self.horizontalLayout_2.addWidget(self.btn_docs_load)
+ self.horizontalLayout_2.addWidget(self.label_13)
self.btn_docs_search = QPushButton(self.tab_log)
self.btn_docs_search.setObjectName(u"btn_docs_search")
@@ -797,7 +810,7 @@ class Ui_MainWindow(QMainWindow):
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(4, 3)
self.horizontalLayout_2.setStretch(5, 1)
self.horizontalLayout_2.setStretch(6, 10)
@@ -836,7 +849,6 @@ class Ui_MainWindow(QMainWindow):
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)
@@ -853,10 +865,12 @@ class Ui_MainWindow(QMainWindow):
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_docs.currentChanged.connect(MainWindow.switch_log_tab)
+ self.treew_log.itemDoubleClicked.connect(MainWindow.show_item_content)
self.tw_funcs.setCurrentIndex(0)
self.sw_network.setCurrentIndex(0)
- self.tw_docs.setCurrentIndex(1)
+ self.tw_docs.setCurrentIndex(0)
QMetaObject.connectSlotsByName(MainWindow)
@@ -893,7 +907,7 @@ class Ui_MainWindow(QMainWindow):
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.cb_2.setText(QCoreApplication.translate("MainWindow", u"\u5468\u671f\u5185\u6700\u5927\u901f\u5ea6", 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))
@@ -911,8 +925,10 @@ class Ui_MainWindow(QMainWindow):
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.cb_hmi_cmd.setItemText(1, QCoreApplication.translate("MainWindow", u"diagnosis.open", None))
+ self.cb_hmi_cmd.setItemText(2, QCoreApplication.translate("MainWindow", u"diagnosis.get_params", None))
+ self.cb_hmi_cmd.setItemText(3, QCoreApplication.translate("MainWindow", u"device.get_params", None))
+ self.cb_hmi_cmd.setItemText(4, 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))
@@ -921,14 +937,26 @@ class Ui_MainWindow(QMainWindow):
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.cb_md_cmd.setItemText(2, QCoreApplication.translate("MainWindow", u"ctrl_soft_estop", None))
+ self.cb_md_cmd.setItemText(3, QCoreApplication.translate("MainWindow", u"ctrl_estop_reset_clear_alarm", None))
+ self.cb_md_cmd.setItemText(4, QCoreApplication.translate("MainWindow", u"sta_motor", None))
+ self.cb_md_cmd.setItemText(5, QCoreApplication.translate("MainWindow", u"sta_soft_estop", None))
+ self.cb_md_cmd.setItemText(6, QCoreApplication.translate("MainWindow", u"sta_estop", None))
+ self.cb_md_cmd.setItemText(7, QCoreApplication.translate("MainWindow", u"sta_alarm", 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.cb_ec_cmd.setItemText(0, QCoreApplication.translate("MainWindow", u"motor_on", None))
+ self.cb_ec_cmd.setItemText(1, QCoreApplication.translate("MainWindow", u"motor_off", None))
+ self.cb_ec_cmd.setItemText(2, QCoreApplication.translate("MainWindow", u"set_do", None))
+ self.cb_ec_cmd.setItemText(3, QCoreApplication.translate("MainWindow", u"switch_mode_auto", None))
+ self.cb_ec_cmd.setItemText(4, QCoreApplication.translate("MainWindow", u"switch_mode_manual", None))
+ self.cb_ec_cmd.setItemText(5, QCoreApplication.translate("MainWindow", u"operating_mode", None))
+ self.cb_ec_cmd.setItemText(6, QCoreApplication.translate("MainWindow", u"motor_on_state", None))
+ self.cb_ec_cmd.setItemText(7, 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))
@@ -946,7 +974,7 @@ class Ui_MainWindow(QMainWindow):
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.label_13.setText("")
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))
diff --git a/code/test.py b/test.py
similarity index 84%
rename from code/test.py
rename to test.py
index 2265c7f..f701f83 100644
--- a/code/test.py
+++ b/test.py
@@ -1,3 +1,9 @@
+def test(flag: int, **kwargs):
+ print(f"flag = {flag}")
+ print(f"kwargs = {kwargs}")
+
+test(11, a=1,b="b")
+
import time
# import common.openapi as openapi
@@ -11,20 +17,20 @@ import time
-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;")
+# 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))
+# 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()
# ============================================
diff --git a/ui/main.ui b/ui/main.ui
index 53452a8..5c4ed7d 100644
--- a/ui/main.ui
+++ b/ui/main.ui
@@ -9,8 +9,8 @@
0
0
- 1002
- 555
+ 1004
+ 560
@@ -578,7 +578,7 @@
-
-
+
true
@@ -587,7 +587,7 @@
0
0
- 211
+ 212
78
@@ -616,7 +616,7 @@
- 周期内平均转矩
+ 周期内最大速度
@@ -937,6 +937,16 @@
controller.heart
+ -
+
+ diagnosis.open
+
+
+ -
+
+ diagnosis.get_params
+
+
-
device.get_params
@@ -1084,6 +1094,36 @@
ctrl_motor_off
+ -
+
+ ctrl_soft_estop
+
+
+ -
+
+ ctrl_estop_reset_clear_alarm
+
+
+ -
+
+ sta_motor
+
+
+ -
+
+ sta_soft_estop
+
+
+ -
+
+ sta_estop
+
+
+ -
+
+ sta_alarm
+
+
-
@@ -1211,6 +1251,36 @@
12
+
-
+
+ motor_on
+
+
+ -
+
+ motor_off
+
+
+ -
+
+ set_do
+
+
+ -
+
+ switch_mode_auto
+
+
+ -
+
+ switch_mode_manual
+
+
+ -
+
+ operating_mode
+
+
-
motor_on_state
@@ -1316,7 +1386,7 @@
- 1
+ 0
Qt::TextElideMode::ElideNone
@@ -1391,7 +1461,7 @@
-
-
+
-
@@ -1458,15 +1528,9 @@
-
-
-
-
- Consolas
- 12
-
-
+
- 加载
+
@@ -1702,22 +1766,6 @@
-
- btn_docs_load
- clicked()
- MainWindow
- load_sql()
-
-
- 651
- 507
-
-
- 606
- 521
-
-
-
btn_docs_search
clicked()
@@ -1725,7 +1773,7 @@
search_keyword()
- 732
+ 730
507
@@ -1837,8 +1885,8 @@
md_cb_change()
- 805
- 89
+ 467
+ 81
612
@@ -1853,8 +1901,8 @@
md_send()
- 887
- 89
+ 327
+ 81
795
@@ -1869,8 +1917,8 @@
ec_send()
- 887
- 89
+ 327
+ 81
652
@@ -1901,8 +1949,8 @@
md_conn()
- 545
- 89
+ 327
+ 81
398
@@ -1917,8 +1965,8 @@
ec_conn()
- 545
- 89
+ 327
+ 81
412
@@ -1949,8 +1997,8 @@
ec_cb_change()
- 805
- 89
+ 467
+ 81
540
@@ -1974,6 +2022,38 @@
+
+ tw_docs
+ currentChanged(int)
+ MainWindow
+ switch_log_tab()
+
+
+ 313
+ 193
+
+
+ 202
+ 172
+
+
+
+
+ treew_log
+ itemDoubleClicked(QTreeWidgetItem*,int)
+ MainWindow
+ show_item_content()
+
+
+ 441
+ 321
+
+
+ 205
+ 308
+
+
+
prog_start()
@@ -2000,5 +2080,7 @@
md_cb_change()
ec_cb_change()
check_interval()
+ switch_log_tab()
+ show_item_content()