From 04bd1238d213e9edfbda8f9b6572d25105fc57b8 Mon Sep 17 00:00:00 2001 From: gitea Date: Wed, 31 Jul 2024 08:05:36 +0800 Subject: [PATCH] =?UTF-8?q?v0.2.0.5(2024/07/31)=20=E6=AD=A4=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E6=94=B9=E5=8A=A8=E8=BE=83=E5=A4=A7=EF=BC=8C=E5=85=AC?= =?UTF-8?q?=E5=85=B1=E9=83=A8=E5=88=86=E5=81=9A=E4=BA=86=E8=A7=84=E6=95=B4?= =?UTF-8?q?=EF=BC=8C=E6=94=BE=E7=BD=AE=E5=88=B0=E6=96=B0=E5=BB=BA=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E5=A4=B9=20commons=20=E5=BD=93=E4=B8=AD=EF=BC=8C?= =?UTF-8?q?=E5=B9=B6=E6=89=80=E6=9C=89=E8=87=AA=E5=AE=9A=E4=B9=89=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=E5=BC=95=E5=85=A5=20logging=20=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=EF=BC=8C=E8=AE=B0=E5=BD=95=E9=87=8D=E8=A6=81=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=201.=20[t=5Fchange=5Fui:=20clibs.py]=20=20=20=20-=20=E8=B0=83?= =?UTF-8?q?=E6=95=B4=E4=BB=A3=E7=A0=81=E7=BB=84=E7=BB=87=E7=BB=93=E6=9E=84?= =?UTF-8?q?=EF=BC=8C=E6=96=B0=E5=A2=9E=E6=A8=A1=E5=9D=97=EF=BC=8C=E5=B0=86?= =?UTF-8?q?=E5=85=AC=E5=85=B1=E5=87=BD=E6=95=B0=E4=BB=A5=E5=8F=8A=E7=B1=BB?= =?UTF-8?q?=E5=90=88=E5=B9=B6=E5=85=A5=E6=AD=A4=20=20=20=20-=20=E5=B0=86?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=E5=B8=B8=E9=87=8F=E6=94=BE=E5=85=A5=E8=AF=A5?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=20=20=20=20-=20=E5=BC=95=E5=85=A5logging/con?= =?UTF-8?q?current=5Flog=5Fhandler=E6=A8=A1=E5=9D=97=EF=BC=8C=E5=B9=B6?= =?UTF-8?q?=E4=BD=9C=E5=88=9D=E5=A7=8B=E5=8C=96=E6=93=8D=E4=BD=9C=EF=BC=8C?= =?UTF-8?q?=E4=BE=9B=E5=85=B6=E4=BB=96=E6=A8=A1=E5=9D=97=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=EF=BC=8C=E6=8C=8950M=E5=88=87=E5=89=B2=EF=BC=8C=E6=9C=80?= =?UTF-8?q?=E5=A4=9A=E4=BF=9D=E7=95=9910=E4=BB=BD=20=20=20=20-=20prj=5Fto?= =?UTF-8?q?=5Fxcore=E5=87=BD=E6=95=B0=E8=AE=BE=E7=BD=AE=E5=B7=A5=E7=A8=8B?= =?UTF-8?q?=E5=90=8D=E9=83=A8=E5=88=86=E9=87=8D=E5=86=99=EF=BC=8C=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E4=BA=86=E5=A4=9A=E4=B8=AAprj=E5=B7=A5=E7=A8=8B?= =?UTF-8?q?=E5=8F=AF=E8=83=BD=E4=B8=8D=E8=83=BD=E6=89=A7=E8=A1=8C=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98=202.=20[t=5Fchange=5Fui:=20openapi.py]=20=20?= =?UTF-8?q?=20=20-=20=E5=AE=8C=E5=85=A8=E9=87=8D=E5=86=99=E4=BA=86=20get?= =?UTF-8?q?=5Ffrom=5Fid=20=E5=87=BD=E6=95=B0=EF=BC=8C=E4=BD=BF=E6=9B=B4?= =?UTF-8?q?=E7=B2=BE=E5=87=86=20=20=20=20-=20=E5=9C=A8=20msg=5Fstorage=20?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E4=B8=AD=EF=BC=8C=E5=A2=9E=E5=8A=A0=20logger?= =?UTF-8?q?=EF=BC=8C=E4=BF=9D=E7=95=99=E6=89=80=E6=9C=89=E5=93=8D=E5=BA=94?= =?UTF-8?q?=E6=B6=88=E6=81=AF=20=20=20=20-=20=E5=88=A0=E9=99=A4=20heartbea?= =?UTF-8?q?t=20=E5=87=BD=E6=95=B0=E4=B8=AD=E7=9A=84=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E4=BF=9D=E5=AD=98=E5=8A=9F=E8=83=BD=E9=83=A8=E5=88=86=20=20=20?= =?UTF-8?q?=20-=20=E5=BF=83=E8=B7=B3=E5=86=8D=E6=AC=A1=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=202s...=203.=20[t=5Fchange=5Fui:=20aio.py]=20=20=20?= =?UTF-8?q?=20-=20=E5=A2=9E=E5=8A=A0=E4=BA=86=E6=97=A5=E5=BF=97=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96=E9=83=A8=E5=88=86=20=20=20=20-=20detect=5Fne?= =?UTF-8?q?twork=20=E5=87=BD=E6=95=B0=E4=B8=AD=E4=BF=AE=E6=94=B9=E9=87=8D?= =?UTF-8?q?=E6=96=B0=E5=AE=9E=E4=BE=8B=E5=8C=96HR=E9=97=B4=E9=9A=94?= =?UTF-8?q?=E4=B8=BA=204s=EF=BC=8C=E5=AF=B9=E5=BA=94=E5=BF=83=E8=B7=B3=204?= =?UTF-8?q?.=20[t=5Fchange=5Fui:=20do=5Fbrake.py]=20=20=20=20-=20=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E4=B8=80=E7=9B=B4=E6=89=93=E5=BC=80=E6=9B=B2=E7=BA=BF?= =?UTF-8?q?=E7=9A=84=E6=96=B9=E6=B3=95=E8=A7=84=E9=81=BF=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E4=BA=86=20OOM=20=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=8C=E5=90=8C?= =?UTF-8?q?=E6=97=B6=E4=BF=AE=E6=94=B9=E6=95=B0=E6=8D=AE=E5=A4=84=E7=90=86?= =?UTF-8?q?=E6=96=B9=E5=BC=8F=EF=BC=8C=E5=8F=AA=E5=8F=96=E6=9C=80=E5=90=8E?= =?UTF-8?q?=2012s=205.=20[t=5Fchange=5Fui:=20do=5Fcurrent.py]=20=20=20=20-?= =?UTF-8?q?=20=E4=BF=9D=E6=8C=81=E7=94=B5=E6=B5=81=EF=BC=8C=E5=8F=AA?= =?UTF-8?q?=E5=8F=96=E6=9C=80=E5=90=8E=2015s=206.=20[t=5Fchange=5Fui:=20al?= =?UTF-8?q?l=20the=20part]:=20=E5=BC=95=E5=85=A5=20commons=20=E5=8C=85?= =?UTF-8?q?=EF=BC=8C=E5=B9=B6=E5=AE=9A=E5=88=B6=E4=BA=86=20logging=20?= =?UTF-8?q?=E8=BE=93=E5=87=BA=EF=BC=8C=E5=90=8E=E7=BB=AD=E6=8C=81=E7=BB=AD?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 6 +- aio/README.md | 32 +++- aio/assets/file_version_info.txt | 8 +- aio/assets/requirements.txt | 14 +- aio/assets/vers | 2 +- aio/code/__init__.py | 1 - aio/code/aio.py | 102 ++++++------- aio/code/automatic_test/__init__.py | 1 - aio/code/automatic_test/btn_functions.py | 35 ++--- aio/code/automatic_test/do_brake.py | 123 ++++----------- aio/code/automatic_test/do_current.py | 185 ++++++++--------------- aio/code/commons/clibs.py | 131 ++++++++++++++++ aio/code/{ => commons}/openapi.py | 89 ++++++----- aio/code/data_process/__init__.py | 1 - aio/code/data_process/brake.py | 52 ++----- aio/code/data_process/current.py | 52 +------ aio/code/data_process/iso.py | 25 +-- aio/code/data_process/wavelogger.py | 38 ++--- aio/code/durable_action/__init__.py | 1 - aio/code/durable_action/factory_test.py | 112 +++----------- 20 files changed, 424 insertions(+), 586 deletions(-) delete mode 100644 aio/code/__init__.py delete mode 100644 aio/code/automatic_test/__init__.py create mode 100644 aio/code/commons/clibs.py rename aio/code/{ => commons}/openapi.py (92%) delete mode 100644 aio/code/data_process/__init__.py delete mode 100644 aio/code/durable_action/__init__.py diff --git a/.gitignore b/.gitignore index 89a9f58..d0af568 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,8 @@ aio/venv aio/__pycache__/ aio/code/automatic_test/__pycache__/ aio/code/data_process/__pycache__/ -aio/assets/templates/c_msg.log +aio/assets/templates/c_msg.log* aio/code/durable_action/__pycache__/ -aio/assets/templates/durable/ \ No newline at end of file +aio/assets/templates/durable/ +aio/assets/templates/.__c_msg.lock +aio/code/commons/__pycache__/ \ No newline at end of file diff --git a/aio/README.md b/aio/README.md index 0bf3d67..4d1469d 100644 --- a/aio/README.md +++ b/aio/README.md @@ -31,9 +31,10 @@ ### 四、打包方法 +打包时,只需要修改 clibs.py 中的 PREFIX 即可,调试时再修改回来 + ``` -pyinstaller.exe -F --version-file file_version_info.txt -i .\icon.ico .\aio.py -p .\brake.py -p .\current.py -pyinstaller --noconfirm --onedir --windowed --add-data "C:/Users/Administrator/AppData/Local/Programs/Python/Python312/Lib/site-packages/customtkinter;customtkinter/" --version-file ..\assets\file_version_info.txt -i ..\assets\icon.ico ..\code\aio.py -p ..\code\data_process\brake.py -p ..\code\data_process\iso.py -p ..\code\data_process\current.py -p ..\code\data_process\wavelogger.py +pyinstaller --noconfirm --onedir --windowed --optimize 2 --contents-directory . --upx-dir "D:/Syncthing/common/A_Program/upx-4.2.4-win64/" --add-data "C:/Users/Administrator/AppData/Local/Programs/Python/Python312/Lib/site-packages/customtkinter;customtkinter/" --add-data "D:/Syncthing/company/D-测试工作/X-自动化测试/01-AIO/rokae/aio/assets/templates:templates" --version-file ../assets/file_version_info.txt -i ../assets/icon.ico ../code/aio.py -p ../code/data_process/brake.py -p ../code/data_process/iso.py -p ../code/data_process/current.py -p ../code/data_process/wavelogger.py -p ../code/commons/openapi.py -p ../code/commons/clibs.py -p ../code/automatic_test/btn_functions.py -p ../code/automatic_test/do_current.py -p ../code/automatic_test/do_brake.py -p ../code/durable_action/factory_test.py ``` --- @@ -557,5 +558,28 @@ v0.2.0.3(2024/07/27) 2. [APIs: do_current.py]: 精简程序,解决 OOM 问题 3. [APIs: factory_test.py]: 精简程序,解决 OOM 问题 4. [APIsL openapi.py] - - 心跳修改为 1 s,因为 OOM 问题的解决依赖于长久的打开曲线开关,此时对于 hr.c_msg 的定时清理是个挑战,将心跳缩短,有利于清理日志后,避免丢失心跳 - - 新增 diagnosis.save 命令,但是执行时,有问题,待解决 \ No newline at end of file + - 心跳修改为 1s,因为 OOM 问题的解决依赖于长久的打开曲线开关,此时对于 hr.c_msg 的定时清理是个挑战,将心跳缩短,有利于清理日志后,避免丢失心跳 + - 新增 diagnosis.save 命令,但是执行时,有问题,待解决 + +v0.2.0.5(2024/07/31) +此版本改动较大,公共部分做了规整,放置到新建文件夹 commons 当中,并所有自定义模块引入 logging 模块,记录重要信息 +1. [t_change_ui: clibs.py] + - 调整代码组织结构,新增模块,将公共函数以及类合并入此 + - 将一些常量放入该模块 + - 引入logging/concurrent_log_handler模块,并作初始化操作,供其他模块使用,按50M切割,最多保留10份 + - prj_to_xcore函数设置工程名部分重写,修复了多个prj工程可能不能执行的问题 +2. [t_change_ui: openapi.py] + - 完全重写了 get_from_id 函数,使更精准 + - 在 msg_storage 函数中,增加 logger,保留所有响应消息 + - 删除 heartbeat 函数中的日志保存功能部分 + - 心跳再次修改为 2s... +3. [t_change_ui: aio.py] + - 增加了日志初始化部分 + - detect_network 函数中修改重新实例化HR间隔为 4s,对应心跳 +4. [t_change_ui: do_brake.py] + - 使用一直打开曲线的方法规避解决了 OOM 的问题,同时修改数据处理方式,只取最后 12s +5. [t_change_ui: do_current.py] + - 保持电流,只取最后 15s +6. [t_change_ui: all the part]: 引入 commons 包,并定制了 logging 输出,后续持续优化 + + diff --git a/aio/assets/file_version_info.txt b/aio/assets/file_version_info.txt index a4ff150..ec3ed0c 100644 --- a/aio/assets/file_version_info.txt +++ b/aio/assets/file_version_info.txt @@ -6,8 +6,8 @@ VSVersionInfo( ffi=FixedFileInfo( # filevers and prodvers should be always a tuple with four items: (1, 2, 3, 4) # Set not needed items to zero 0. - filevers=(0, 2, 0, 3), - prodvers=(0, 2, 0, 3), + filevers=(0, 2, 0, 5), + prodvers=(0, 2, 0, 5), # Contains a bitmask that specifies the valid bits 'flags'r mask=0x3f, # Contains a bitmask that specifies the Boolean attributes of the file. @@ -31,12 +31,12 @@ VSVersionInfo( '040904b0', [StringStruct('CompanyName', 'Rokae - https://www.rokae.com/'), StringStruct('FileDescription', 'All in one automatic toolbox'), - StringStruct('FileVersion', '0.2.0.3 (2024-07-27)'), + StringStruct('FileVersion', '0.2.0.5 (2024-08-02)'), StringStruct('InternalName', 'AIO.exe'), StringStruct('LegalCopyright', '© 2024-2024 Manford Fan'), StringStruct('OriginalFilename', 'AIO.exe'), StringStruct('ProductName', 'AIO'), - StringStruct('ProductVersion', '0.2.0.3 (2024-07-27)')]) + StringStruct('ProductVersion', '0.2.0.5 (2024-08-02)')]) ]), VarFileInfo([VarStruct('Translation', [1033, 1200])]) ] diff --git a/aio/assets/requirements.txt b/aio/assets/requirements.txt index ad41cdf..63a94b4 100644 --- a/aio/assets/requirements.txt +++ b/aio/assets/requirements.txt @@ -1,9 +1,9 @@ -openpyxl==3.1.2 -pdfplumber==0.11.0 +concurrent_log_handler==0.9.25 customtkinter==5.2.2 -Jinja2==3.1.4 -lxml==5.2.2 -numpy==1.26.4 +matplotlib==3.9.1 +numpy==2.0.1 +openpyxl==3.1.2 pandas==2.2.2 -pillow==10.3.0 -pyinstaller==6.7.0 +paramiko==3.4.0 +pdfplumber==0.11.0 +pymodbus==3.6.9 diff --git a/aio/assets/vers b/aio/assets/vers index 81dc3db..4f1ec33 100644 --- a/aio/assets/vers +++ b/aio/assets/vers @@ -1 +1 @@ -0.2.0.3 @ 07/27/2024 \ No newline at end of file +0.2.0.5 @ 08/02/2024 \ No newline at end of file diff --git a/aio/code/__init__.py b/aio/code/__init__.py deleted file mode 100644 index e6e51aa..0000000 --- a/aio/code/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__all__ = ['automatic_test', 'data_process'] \ No newline at end of file diff --git a/aio/code/aio.py b/aio/code/aio.py index e90793b..a535af9 100644 --- a/aio/code/aio.py +++ b/aio/code/aio.py @@ -1,49 +1,37 @@ import tkinter -from os.path import exists, dirname -from os import getcwd +from os.path import exists +from os import getcwd, remove from threading import Thread import tkinter.messagebox import customtkinter from time import time, strftime, localtime, sleep from urllib.request import urlopen -from socket import setdefaulttimeout from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg -from data_process import * -from automatic_test import * -from durable_action import * -import openapi -import matplotlib.pyplot as plt +from data_process import brake, current, iso, wavelogger +from automatic_test import do_current, do_brake, btn_functions +from durable_action import factory_test +from commons import openapi, clibs +from matplotlib.pyplot import rcParams, figure, subplots_adjust from matplotlib import use from pandas import DataFrame, read_excel +import logging + +with open(clibs.log_data, 'w') as _: + for i in range(1, 11): + try: + remove(f'{clibs.log_data}.{i}') + except FileNotFoundError: + pass +logger = logging.getLogger(__file__) +logger.info("日志文件初始化完成...") use('Agg') -heartbeat = f'{dirname(__file__)}/../assets/templates/heartbeat' -durable_data_current_xlsx = f'{dirname(__file__)}/../assets/templates/durable/durable_data_current.xlsx' -durable_data_current_max_xlsx = f'{dirname(__file__)}/../assets/templates/durable/durable_data_current_max.xlsx' customtkinter.set_appearance_mode("System") # Modes: "System" (standard), "Dark", "Light" customtkinter.set_default_color_theme("blue") # Themes: "blue" (standard), "green", "dark-blue" customtkinter.set_widget_scaling(1.1) # widget dimensions and text size customtkinter.set_window_scaling(1.1) # window geometry dimensions -setdefaulttimeout(3) + # global vars -durable_data_current = { - 'time': list(range(1, 19)), - 'axis1': [0 for _ in range(18)], - 'axis2': [0 for _ in range(18)], - 'axis3': [0 for _ in range(18)], - 'axis4': [0 for _ in range(18)], - 'axis5': [0 for _ in range(18)], - 'axis6': [0 for _ in range(18)], -} -durable_data_current_max = { - 'time': list(range(1, 19)), - 'axis1': [0 for _ in range(18)], - 'axis2': [0 for _ in range(18)], - 'axis3': [0 for _ in range(18)], - 'axis4': [0 for _ in range(18)], - 'axis5': [0 for _ in range(18)], - 'axis6': [0 for _ in range(18)], -} btns_func = { 'start': {'btn': '', 'row': 1, 'text': '开始运行'}, 'check': {'btn': '', 'row': 2, 'text': '检查参数'}, @@ -79,6 +67,7 @@ class App(customtkinter.CTk): self.flg = 0 self.df_copy = None self.old_curve = None + self.myThread = None # ===================================================================== # configure window self.title("AIO - All in one automatic toolbox") @@ -202,37 +191,36 @@ class App(customtkinter.CTk): if cur_vers.strip() != new_vers.strip(): msg = f"""当前版本:{cur_vers}\n更新版本:{new_vers}\n\n请及时前往钉盘更新~~~""" tkinter.messagebox.showwarning(title="版本更新", message=msg) - self.destroy() except: tkinter.messagebox.showwarning(title="版本更新", message="连接服务器失败,无法确认当前是否是最新版本......") # functions below ↓ ---------------------------------------------------------------------------------------- - def create_canvas(self, figure): - self.canvas = FigureCanvasTkAgg(figure, self.tabview.tab('Durable Action')) + def create_canvas(self, _figure): + self.canvas = FigureCanvasTkAgg(_figure, self.tabview.tab('Durable Action')) self.canvas.draw() self.canvas.get_tk_widget().configure(height=600) self.canvas.get_tk_widget().grid(row=3, column=1, rowspan=3, columnspan=13, padx=20, pady=10, sticky="nsew") def create_plot(self): - 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' + rcParams['font.sans-serif'] = ['SimHei'] + rcParams['axes.unicode_minus'] = False + rcParams['figure.dpi'] = 100 + rcParams['font.size'] = 14 + rcParams['lines.marker'] = 'o' curvesel = widgits_da['curvesel']['optionmenu'].get() while True: if not self.hr.durable_lock: self.hr.durable_lock = 1 if curvesel == 'device_servo_trq_feedback': - df = read_excel(durable_data_current_xlsx) + df = read_excel(clibs.durable_data_current_xlsx) _title = 'device_servo_trq_feedback' elif curvesel == '[max] device_servo_trq_feedback': _title = '[max] device_servo_trq_feedback' - df = read_excel(durable_data_current_max_xlsx) + df = read_excel(clibs.durable_data_current_max_xlsx) else: _title = 'device_servo_trq_feedback' - df = read_excel(durable_data_current_xlsx) + df = read_excel(clibs.durable_data_current_xlsx) self.hr.durable_lock = 0 break else: @@ -242,12 +230,12 @@ class App(customtkinter.CTk): self.flg = 1 self.df_copy = df.copy() self.old_curve = widgits_da['curvesel']['optionmenu'].get() - figure = plt.figure(frameon=True, facecolor='#E9E9E9') - plt.subplots_adjust(left=0.04, right=0.98, bottom=0.1, top=0.95) + _figure = figure(frameon=True, facecolor='#E9E9E9') + subplots_adjust(left=0.04, right=0.98, bottom=0.1, top=0.95) _ = df['time'].to_list() _xticks = [str(_i) for _i in _] - ax = figure.add_subplot(1, 1, 1) + ax = _figure.add_subplot(1, 1, 1) ax.set_xticks(range(len(_xticks))) ax.set_xticklabels(_xticks) @@ -258,7 +246,7 @@ class App(customtkinter.CTk): df.plot(grid=True, x='time', y='axis5', ax=ax) df.plot(grid=True, x='time', y='axis6', ax=ax, title=_title, legend='upper left', rot=30) - self.create_canvas(figure) + self.create_canvas(_figure) def thread_it(self, func, *args): """ 将函数打包进线程 """ @@ -273,7 +261,7 @@ class App(customtkinter.CTk): self.seg_button.configure(state='disabled') # self.tabview.configure(state='disabled') self.textbox.delete(index1='1.0', index2='end') - with open(heartbeat, 'r', encoding='utf-8') as f_h: + with open(clibs.heartbeat, 'r', encoding='utf-8') as f_h: c_state = f_h.read().strip() if c_state == '0' and value != '功能切换': @@ -288,12 +276,12 @@ class App(customtkinter.CTk): # self.tabview.configure(state='normal') def detect_network(self): - df = DataFrame(durable_data_current) - df.to_excel(durable_data_current_xlsx, index=False) - df = DataFrame(durable_data_current_max) - df.to_excel(durable_data_current_max_xlsx, index=False) + df = DataFrame(clibs.durable_data_current) + df.to_excel(clibs.durable_data_current_xlsx, index=False) + df = DataFrame(clibs.durable_data_current_max) + df.to_excel(clibs.durable_data_current_max_xlsx, index=False) - with open(heartbeat, "w", encoding='utf-8') as f_hb: + with open(clibs.heartbeat, "w", encoding='utf-8') as f_hb: f_hb.write('0') self.hr = openapi.HmiRequest(self.write2textbox) self.md = openapi.ModbusRequest(self.write2textbox) @@ -302,14 +290,14 @@ class App(customtkinter.CTk): if self.tabview.get() == 'Durable Action': self.create_plot() - with open(heartbeat, 'r', encoding='utf-8') as f_hb: + with open(clibs.heartbeat, 'r', encoding='utf-8') as f_hb: c_state = f_hb.read().strip() pb_color = 'green' if c_state == '1' else 'red' self.progressbar.configure(progress_color=pb_color) self.progressbar_da.configure(progress_color=pb_color) if c_state == '0': self.hr.t_bool = False - sleep(3) + sleep(4) del self.hr self.hr = openapi.HmiRequest(self.write2textbox) sleep(3) @@ -621,10 +609,10 @@ class App(customtkinter.CTk): def pre_warning(self): if self.tabview.get() == 'Durable Action': - df = DataFrame(durable_data_current) - df.to_excel(durable_data_current_xlsx, index=False) - df = DataFrame(durable_data_current_max) - df.to_excel(durable_data_current_max_xlsx, index=False) + df = DataFrame(clibs.durable_data_current) + df.to_excel(clibs.durable_data_current_xlsx, index=False) + df = DataFrame(clibs.durable_data_current_max) + df.to_excel(clibs.durable_data_current_max_xlsx, index=False) if tkinter.messagebox.askyesno(title="开始运行", message="确认机器已按照测试规范更新固件,并提按照测试机型前修改好工程?"): pass diff --git a/aio/code/automatic_test/__init__.py b/aio/code/automatic_test/__init__.py deleted file mode 100644 index 5c1ee4d..0000000 --- a/aio/code/automatic_test/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__all__ = ['btn_functions', 'do_brake', 'do_current'] \ No newline at end of file diff --git a/aio/code/automatic_test/btn_functions.py b/aio/code/automatic_test/btn_functions.py index 2f57992..a5271dc 100644 --- a/aio/code/automatic_test/btn_functions.py +++ b/aio/code/automatic_test/btn_functions.py @@ -1,61 +1,54 @@ from json import loads from sys import argv +from logging import getLogger +from commons import clibs - -def execution(cmd, hr, w2t, **kwargs): - _id = hr.execution(cmd, **kwargs) - _msg = hr.get_from_id(_id) - if not _msg: - w2t(f"无法获取{_id}请求的响应信息", 0, 6, 'red', tab_name='Automatic Test') - else: - _response = loads(_msg) - if not _response: - w2t(f"无法获取{id}请求的响应信息", 0, 1, 'red', tab_name='Automatic Test') - return _response +tab_name = clibs.tab_names['at'] +logger = getLogger(__file__) def trigger_estop(md, w2t): md.trigger_estop() - w2t("触发急停成功,可点击机器状态验证。", 0, 0, 'green', 'Automatic Test') + w2t("触发急停成功,可点击机器状态验证。", 0, 0, 'green', tab_name) def reset_estop(md, w2t): md.reset_estop() - w2t("恢复急停成功,可点击机器状态验证。", 0, 0, 'green', 'Automatic Test') + w2t("恢复急停成功,可点击机器状态验证。", 0, 0, 'green', tab_name) def get_state(hr, w2t): # 获取机器状态 - _response = execution('state.get_state', hr, w2t) + _response = clibs.execution('state.get_state', hr, w2t, tab_name) stat_desc = {'engine': '上电状态', 'operate': '操作模式', 'rc_state': '控制器状态', 'robot_action': '机器人动作', 'safety_mode': '安全模式', 'servo_mode': '伺服工作模式', 'task_space': '工作任务空间'} for component, state in _response['data'].items(): - w2t(f"{stat_desc[component]}: {state}", tab_name='Automatic Test') + w2t(f"{stat_desc[component]}: {state}", tab_name=tab_name) # 获取设备伺服信息 - _response = execution('device.get_params', hr, w2t) + _response = clibs.execution('device.get_params', hr, w2t, tab_name) dev_desc = {0: '伺服版本', 1: '伺服参数', 2: '安全板固件', 3: '控制器', 4: '通讯总线', 5: '解释器', 6: '运动控制', 8: '力控版本', 9: '末端固件', 10: '机型文件', 11: '环境包'} dev_vers = {} for device in _response['data']['devices']: dev_vers[device['type']] = device['version'] for i in sorted(dev_desc.keys()): - w2t(f"{dev_desc[i]}: {dev_vers[i]}", tab_name='Automatic Test') + w2t(f"{dev_desc[i]}: {dev_vers[i]}", tab_name=tab_name) # 设置示教器模式 - _response = execution('state.set_tp_mode', hr, w2t, tp_mode='without') + _response = clibs.execution('state.set_tp_mode', hr, w2t, tab_name, tp_mode='without') def warning_info(hr, w2t): for msg in hr.c_msg: if 'alarm' in msg.lower(): - w2t(str(loads(msg)), tab_name='Automatic Test') + w2t(str(loads(msg)), tab_name=tab_name) for msg in hr.c_msg_xs: if 'alarm' in msg.lower(): - w2t(str(loads(msg)), tab_name='Automatic Test') + w2t(str(loads(msg)), tab_name=tab_name) def main(hr, md, func, w2t): if hr is None: - w2t("无法连接机器人,检查是否已经使用Robot Assist软件连接机器,重试中...", 0, 49, 'red', tab_name='Automatic Test') + w2t("无法连接机器人,检查是否已经使用Robot Assist软件连接机器,重试中...", 0, 49, 'red', tab_name) # func: get_state/ match func: case 'trigger_estop': diff --git a/aio/code/automatic_test/do_brake.py b/aio/code/automatic_test/do_brake.py index 33868d5..6a79748 100644 --- a/aio/code/automatic_test/do_brake.py +++ b/aio/code/automatic_test/do_brake.py @@ -1,30 +1,15 @@ from time import sleep, time, strftime, localtime from sys import argv -from os import scandir, mkdir -from os.path import exists +from os import mkdir from paramiko import SSHClient, AutoAddPolicy from json import loads from openpyxl import load_workbook -import pandas +from pandas import DataFrame, concat +from logging import getLogger +from commons import clibs -RADIAN = 57.3 # 180 / 3.1415926 -tab_name = 'Automatic Test' - - -def traversal_files(path, w2t): - if not exists(path): - msg = f'数据文件夹{path}不存在,请确认后重试......' - w2t(msg, 0, 1, 'red', tab_name) - else: - dirs = [] - files = [] - for item in scandir(path): - if item.is_dir(): - dirs.append(item.path) - elif item.is_file(): - files.append(item.path) - - return dirs, files +tab_name = clibs.tab_names['at'] +logger = getLogger(__file__) def check_files(path, loadsel, data_dirs, data_files, w2t): @@ -72,51 +57,11 @@ def check_files(path, loadsel, data_dirs, data_files, w2t): w2t(' 1. configs.xlsx\n 2. reach33/reach66/reach100_xxxx.xlsx\n 3. xxxx.zip', 0, 1, 'red', tab_name) -def prj_to_xcore(prj_file): - ssh = SSHClient() - ssh.set_missing_host_key_policy(AutoAddPolicy()) - ssh.connect('192.168.0.160', 22, username='luoshi', password='luoshi2019') - sftp = ssh.open_sftp() - sftp.put(prj_file, '/tmp/target.zip') - cmd = 'cd /tmp; rm -rf target/; mkdir target; unzip -d target/ -q target.zip; ' - cmd += 'chmod 777 -R target/; rm target.zip' - ssh.exec_command(cmd) - - cmd = 'sudo rm -rf /home/luoshi/bin/controller/projects/target; ' - cmd += 'sudo mv /tmp/target/ /home/luoshi/bin/controller/projects/' - stdin, stdout, stderr = ssh.exec_command(cmd, get_pty=True) - stdin.write('luoshi2019' + '\n') - stdin.flush() - print(stdout.read().decode()) # 必须得输出一下stdout,才能正确执行sudo - print(stderr.read().decode()) # 顺便也执行以下stderr - - cmd = 'cd /home/luoshi/bin/controller/; ' - cmd += 'sudo mv projects/target/_build/*.prj projects/target/_build/target.prj' - stdin, stdout, stderr = ssh.exec_command(cmd, get_pty=True) - stdin.write('luoshi2019' + '\n') - stdin.flush() - print(stdout.read().decode()) # 必须得输出一下stdout,才能正确执行sudo - print(stderr.read().decode()) # 顺便也执行以下stderr - ssh.close() - - -def execution(cmd, hr, w2t, **kwargs): - _id = hr.execution(cmd, **kwargs) - _msg = hr.get_from_id(_id) - if not _msg: - w2t(f"无法获取{_id}请求的响应信息", 0, 6, 'red', tab_name) - else: - _response = loads(_msg) - if not _response: - w2t(f"无法获取{id}请求的响应信息", 0, 1, 'red', tab_name) - return _response - - def gen_result_file(path, curve_data, axis, _reach, _load, _speed, count): _d2d_vel = {'hw_joint_vel_feedback': []} _d2d_trq = {'device_servo_trq_feedback': []} _d2d_stop = {'device_safety_estop': []} - for data in curve_data: + for data in curve_data[-240:]: dict_results = data['data'] for item in dict_results: try: @@ -129,13 +74,11 @@ def gen_result_file(path, curve_data, axis, _reach, _load, _speed, count): _d2d_trq['device_servo_trq_feedback'].extend(item['value']) elif item.get('channel', None) == 0 and item.get('name', None) == 'device_safety_estop': _d2d_stop['device_safety_estop'].extend(item['value']) - if len(_d2d_trq['device_servo_trq_feedback']) / 1000 > 10: - break - df1 = pandas.DataFrame.from_dict(_d2d_vel) - df2 = pandas.DataFrame.from_dict(_d2d_trq) - df3 = pandas.DataFrame.from_dict(_d2d_stop) - df = pandas.concat([df1, df2, df3], axis=1) + df1 = DataFrame.from_dict(_d2d_vel) + df2 = DataFrame.from_dict(_d2d_trq) + df3 = DataFrame.from_dict(_d2d_stop) + df = concat([df1, df2, df3], axis=1) _filename = f"{path}\\j{axis}\\reach{_reach}_load{_load}_speed{_speed}\\reach{_reach}_load{_load}_speed{_speed}_{count}.data" df.to_csv(_filename, sep='\t', index=False) @@ -168,14 +111,13 @@ def run_rl(path, loadsel, hr, md, config_file, result_dirs, w2t): else: w2t("configs.xlsx中Target页面A1单元格填写不正确,检查后重新运行...", 0, 111, 'red', tab_name) - _response = execution('diagnosis.open', hr, w2t, open=True, display_open=True) - _response = execution('diagnosis.set_params', hr, w2t, display_pdo_params=display_pdo_params) + clibs.execution('diagnosis.open', hr, w2t, tab_name, open=True, display_open=True) + clibs.execution('diagnosis.set_params', hr, w2t, tab_name, display_pdo_params=display_pdo_params) for condition in result_dirs: _reach = condition.split('_')[0].removeprefix('reach') _load = condition.split('_')[1].removeprefix('load') _speed = condition.split('_')[2].removeprefix('speed') - # if _speed != '100' or _reach != '100': - # continue + for axis in range(1, 4): md.write_axis(axis) speed_max = 0 @@ -224,11 +166,11 @@ def run_rl(path, loadsel, hr, md, config_file, result_dirs, w2t): print(stderr.read().decode()) # 顺便也执行以下stderr # 3. reload工程后,pp2main,并且自动模式和上电,最后运行程序 - _response = execution('overview.reload', hr, w2t, prj_path=prj_path, tasks=['brake', 'stop0_related']) - _response = execution('rl_task.pp_to_main', hr, w2t, tasks=['brake', 'stop0_related']) - _response = execution('state.switch_auto', hr, w2t) - _response = execution('state.switch_motor_on', hr, w2t) - _response = execution('rl_task.run', hr, w2t, tasks=['brake', 'stop0_related']) + clibs.execution('overview.reload', hr, w2t, tab_name, prj_path=prj_path, tasks=['brake', 'stop0_related']) + clibs.execution('rl_task.pp_to_main', hr, w2t, tab_name, tasks=['brake', 'stop0_related']) + clibs.execution('state.switch_auto', hr, w2t, tab_name) + clibs.execution('state.switch_motor_on', hr, w2t, tab_name) + clibs.execution('rl_task.run', hr, w2t, tab_name, tasks=['brake', 'stop0_related']) _t_start = time() while True: if md.read_ready_to_go() == 1: @@ -241,8 +183,7 @@ def run_rl(path, loadsel, hr, md, config_file, result_dirs, w2t): sleep(1) # 4. 打开诊断曲线,并执行采集,之后触发软急停,关闭曲线采集,找出最大速度,传递给RL程序,最后清除相关记录 sleep(get_init_speed) # 获取实际最大速度,可通过configs.xlsx配置 - _response = execution('rl_task.stop', hr, w2t, tasks=['brake']) - # sleep(1) + clibs.execution('rl_task.stop', hr, w2t, tab_name, tasks=['brake']) # 找出最大速度 _c_msg = hr.c_msg.copy() for _msg in _c_msg: @@ -250,7 +191,7 @@ def run_rl(path, loadsel, hr, md, config_file, result_dirs, w2t): dict_results = loads(_msg)['data'] for item in dict_results: if item.get('channel', None) == axis-1 and item.get('name', None) == 'hw_joint_vel_feedback': - _ = RADIAN * sum(item['value']) / len(item['value']) + _ = clibs.RADIAN * sum(item['value']) / len(item['value']) if ws.cell(row=1, column=1).value == 'positive': speed_max = max(_, speed_max) elif ws.cell(row=1, column=1).value == 'negative': @@ -264,8 +205,8 @@ def run_rl(path, loadsel, hr, md, config_file, result_dirs, w2t): md.write_speed_max(speed_max) hr.c_msg_xs.clear() - if len(hr.c_msg) > 240: - del hr.c_msg[240:] + if len(hr.c_msg) > 270: + del hr.c_msg[270:] if speed_max < 10: md.clear_alarm() @@ -278,11 +219,11 @@ def run_rl(path, loadsel, hr, md, config_file, result_dirs, w2t): md.reset_estop() # 其实没必要 md.clear_alarm() - _response = execution('overview.reload', hr, w2t, prj_path=prj_path, tasks=['brake', 'stop0_related']) - _response = execution('rl_task.pp_to_main', hr, w2t, tasks=['brake', 'stop0_related']) - _response = execution('state.switch_auto', hr, w2t) - _response = execution('state.switch_motor_on', hr, w2t) - _response = execution('rl_task.run', hr, w2t, tasks=['brake', 'stop0_related']) + clibs.execution('overview.reload', hr, w2t, tab_name, prj_path=prj_path, tasks=['brake', 'stop0_related']) + clibs.execution('rl_task.pp_to_main', hr, w2t, tab_name, tasks=['brake', 'stop0_related']) + clibs.execution('state.switch_auto', hr, w2t, tab_name) + clibs.execution('state.switch_motor_on', hr, w2t, tab_name) + clibs.execution('rl_task.run', hr, w2t, tab_name, tasks=['brake', 'stop0_related']) for i in range(3): if md.read_ready_to_go() == 1: md.write_act(1) @@ -316,8 +257,8 @@ def run_rl(path, loadsel, hr, md, config_file, result_dirs, w2t): curve_data.insert(0, loads(_msg)) else: hr.c_msg_xs.clear() - if len(hr.c_msg) > 240: - del hr.c_msg[240:] + if len(hr.c_msg) > 270: + del hr.c_msg[270:] gen_result_file(path, curve_data, axis, _reach, _load, _speed, count) else: w2t(f"\n{loadsel.removeprefix('tool')}%负载的制动性能测试执行完毕,如需采集其他负载,须切换负载类型,并更换其他负载,重新执行。", 0, 0, 'green', tab_name) @@ -325,9 +266,9 @@ def run_rl(path, loadsel, hr, md, config_file, result_dirs, w2t): def main(path, hr, md, loadsel, w2t): _s_time = time() - data_dirs, data_files = traversal_files(path, w2t) + data_dirs, data_files = clibs.traversal_files(path, w2t) config_file, reach33, reach66, reach100, prj_file, result_dirs = check_files(path, loadsel, data_dirs, data_files, w2t) - prj_to_xcore(prj_file) + clibs.prj_to_xcore(prj_file) run_rl(path, loadsel, hr, md, config_file, result_dirs, w2t) _e_time = time() time_total = _e_time - _s_time diff --git a/aio/code/automatic_test/do_current.py b/aio/code/automatic_test/do_current.py index b47a77d..ac528ba 100644 --- a/aio/code/automatic_test/do_current.py +++ b/aio/code/automatic_test/do_current.py @@ -1,12 +1,14 @@ -import os +from os import mkdir from time import sleep, time from sys import argv -from os import scandir -from os.path import exists from paramiko import SSHClient, AutoAddPolicy from json import loads -import pandas +from pandas import DataFrame, concat +from logging import getLogger +from commons import clibs +logger = getLogger(__file__) +tab_name = clibs.tab_names['at'] display_pdo_params = [ {"name": "hw_joint_vel_feedback", "channel": 0}, {"name": "hw_joint_vel_feedback", "channel": 1}, @@ -22,26 +24,11 @@ display_pdo_params = [ {"name": "device_servo_trq_feedback", "channel": 5}, ] -def traversal_files(path, w2t): - if not exists(path): - msg = f'数据文件夹{path}不存在,请确认后重试......' - w2t(msg, 0, 1, 'red', tab_name='Automatic Test') - else: - dirs = [] - files = [] - for item in scandir(path): - if item.is_dir(): - dirs.append(item.path) - elif item.is_file(): - files.append(item.path) - - return dirs, files - def check_files(path, loadsel, data_dirs, data_files, w2t): if len(data_dirs) != 0 or len(data_files) != 3: - w2t('初始路径下不允许有文件夹,且初始路径下只能存在如下三个文件,确认后重新运行!', 0, 0, 'red', tab_name='Automatic Test') - w2t(' 1. configs.xlsx\n 2. T_电机电流.xlsx\n 3. xxxx.zip', 0, 1, 'red', tab_name='Automatic Test') + w2t('初始路径下不允许有文件夹,且初始路径下只能存在如下三个文件,确认后重新运行!', 0, 0, 'red', tab_name) + w2t(' 1. configs.xlsx\n 2. T_电机电流.xlsx\n 3. xxxx.zip', 0, 1, 'red', tab_name) config_file = current_file = prj_file = None for data_file in data_files: @@ -53,62 +40,22 @@ def check_files(path, loadsel, data_dirs, data_files, w2t): elif filename.endswith('.zip'): prj_file = data_file else: - w2t('初始路径下不允许有文件夹,且初始路径下只能存在如下三个文件,确认后重新运行!', 0, 0, 'red', tab_name='Automatic Test') - w2t(' 1. configs.xlsx\n 2. T_电机电流.xlsx\n 3. xxxx.zip', 0, 1, 'red', tab_name='Automatic Test') + w2t('初始路径下不允许有文件夹,且初始路径下只能存在如下三个文件,确认后重新运行!', 0, 0, 'red', tab_name) + w2t(' 1. configs.xlsx\n 2. T_电机电流.xlsx\n 3. xxxx.zip', 0, 1, 'red', tab_name) if config_file and current_file and prj_file: - w2t("数据目录合规性检查结束,未发现问题......", tab_name='Automatic Test') + w2t("数据目录合规性检查结束,未发现问题......", tab_name=tab_name) if loadsel == 'tool100': - os.mkdir(f"{path}\\single") - os.mkdir(f"{path}\\s_1") - os.mkdir(f"{path}\\s_2") - os.mkdir(f"{path}\\s_3") + mkdir(f"{path}\\single") + mkdir(f"{path}\\s_1") + mkdir(f"{path}\\s_2") + mkdir(f"{path}\\s_3") elif loadsel == 'inertia': - os.mkdir(f"{path}\\inertia") + mkdir(f"{path}\\inertia") return config_file, current_file, prj_file else: - w2t('初始路径下不允许有文件夹,且初始路径下只能存在如下三个文件,确认后重新运行!', 0, 0, 'red', tab_name='Automatic Test') - w2t(' 1. configs.xlsx\n 2. T_电机电流.xlsx\n 3. xxxx.zip', 0, 1, 'red', tab_name='Automatic Test') - - -def prj_to_xcore(prj_file): - ssh = SSHClient() - ssh.set_missing_host_key_policy(AutoAddPolicy()) - ssh.connect('192.168.0.160', 22, username='luoshi', password='luoshi2019') - sftp = ssh.open_sftp() - sftp.put(prj_file, '/tmp/target.zip') - cmd = 'cd /tmp; rm -rf target/; mkdir target; unzip -d target/ -q target.zip; ' - cmd += 'chmod 777 -R target/; rm target.zip' - ssh.exec_command(cmd) - - cmd = 'sudo rm -rf /home/luoshi/bin/controller/projects/target; ' - cmd += 'sudo mv /tmp/target/ /home/luoshi/bin/controller/projects/' - stdin, stdout, stderr = ssh.exec_command(cmd, get_pty=True) - stdin.write('luoshi2019' + '\n') - stdin.flush() - print(stdout.read().decode()) # 必须得输出一下stdout,才能正确执行sudo - print(stderr.read().decode()) # 顺便也执行以下stderr - - cmd = 'cd /home/luoshi/bin/controller/; ' - cmd += 'sudo mv projects/target/_build/*.prj projects/target/_build/target.prj' - stdin, stdout, stderr = ssh.exec_command(cmd, get_pty=True) - stdin.write('luoshi2019' + '\n') - stdin.flush() - print(stdout.read().decode()) # 必须得输出一下stdout,才能正确执行sudo - print(stderr.read().decode()) # 顺便也执行以下stderr - ssh.close() - - -def execution(cmd, hr, w2t, **kwargs): - _id = hr.execution(cmd, **kwargs) - _msg = hr.get_from_id(_id) - if not _msg: - w2t(f"无法获取{_id}请求的响应信息", 0, 7, 'red', tab_name='Automatic Test') - else: - _response = loads(_msg) - if not _response: - w2t(f"无法获取{id}请求的响应信息", 0, 1, 'red', tab_name='Automatic Test') - return _response + w2t('初始路径下不允许有文件夹,且初始路径下只能存在如下三个文件,确认后重新运行!', 0, 0, 'red', tab_name) + w2t(' 1. configs.xlsx\n 2. T_电机电流.xlsx\n 3. xxxx.zip', 0, 1, 'red', tab_name) def data_proc_regular(path, filename, channel, scenario_time): @@ -129,9 +76,9 @@ def data_proc_regular(path, filename, channel, scenario_time): elif item.get('channel', None) == channel and item.get('name', None) == 'device_servo_trq_feedback': _d2d_trq['device_servo_trq_feedback'].extend(item['value']) - df1 = pandas.DataFrame.from_dict(_d2d_vel) - df2 = pandas.DataFrame.from_dict(_d2d_trq) - df = pandas.concat([df1, df2], axis=1) + df1 = DataFrame.from_dict(_d2d_vel) + df2 = DataFrame.from_dict(_d2d_trq) + df = concat([df1, df2], axis=1) _filename = f'{path}\\single\\j{channel+1}_single_{time()}.data' df.to_csv(_filename, sep='\t', index=False) elif channel in list(range(6, 9)): @@ -181,39 +128,39 @@ def data_proc_regular(path, filename, channel, scenario_time): elif item.get('channel', None) == 5 and item.get('name', None) == 'device_servo_trq_feedback': _d2d_trq_5['device_servo_trq_feedback'].extend(item['value']) - df_01 = pandas.DataFrame.from_dict(_d2d_vel_0) - df_02 = pandas.DataFrame.from_dict(_d2d_trq_0) - df = pandas.concat([df_01, df_02], axis=1) + df_01 = DataFrame.from_dict(_d2d_vel_0) + df_02 = DataFrame.from_dict(_d2d_trq_0) + df = concat([df_01, df_02], axis=1) _filename = f'{path}\\s_{channel-5}\\j1_s_{channel-5}_{scenario_time}_{time()}.data' df.to_csv(_filename, sep='\t', index=False) - df_01 = pandas.DataFrame.from_dict(_d2d_vel_1) - df_02 = pandas.DataFrame.from_dict(_d2d_trq_1) - df = pandas.concat([df_01, df_02], axis=1) + df_01 = DataFrame.from_dict(_d2d_vel_1) + df_02 = DataFrame.from_dict(_d2d_trq_1) + df = concat([df_01, df_02], axis=1) _filename = f'{path}\\s_{channel-5}\\j2_s_{channel-5}_{scenario_time}_{time()}.data' df.to_csv(_filename, sep='\t', index=False) - df_01 = pandas.DataFrame.from_dict(_d2d_vel_2) - df_02 = pandas.DataFrame.from_dict(_d2d_trq_2) - df = pandas.concat([df_01, df_02], axis=1) + df_01 = DataFrame.from_dict(_d2d_vel_2) + df_02 = DataFrame.from_dict(_d2d_trq_2) + df = concat([df_01, df_02], axis=1) _filename = f'{path}\\s_{channel-5}\\j3_s_{channel-5}_{scenario_time}_{time()}.data' df.to_csv(_filename, sep='\t', index=False) - df_01 = pandas.DataFrame.from_dict(_d2d_vel_3) - df_02 = pandas.DataFrame.from_dict(_d2d_trq_3) - df = pandas.concat([df_01, df_02], axis=1) + df_01 = DataFrame.from_dict(_d2d_vel_3) + df_02 = DataFrame.from_dict(_d2d_trq_3) + df = concat([df_01, df_02], axis=1) _filename = f'{path}\\s_{channel-5}\\j4_s_{channel-5}_{scenario_time}_{time()}.data' df.to_csv(_filename, sep='\t', index=False) - df_01 = pandas.DataFrame.from_dict(_d2d_vel_4) - df_02 = pandas.DataFrame.from_dict(_d2d_trq_4) - df = pandas.concat([df_01, df_02], axis=1) + df_01 = DataFrame.from_dict(_d2d_vel_4) + df_02 = DataFrame.from_dict(_d2d_trq_4) + df = concat([df_01, df_02], axis=1) _filename = f'{path}\\s_{channel-5}\\j5_s_{channel-5}_{scenario_time}_{time()}.data' df.to_csv(_filename, sep='\t', index=False) - df_01 = pandas.DataFrame.from_dict(_d2d_vel_5) - df_02 = pandas.DataFrame.from_dict(_d2d_trq_5) - df = pandas.concat([df_01, df_02], axis=1) + df_01 = DataFrame.from_dict(_d2d_vel_5) + df_02 = DataFrame.from_dict(_d2d_trq_5) + df = concat([df_01, df_02], axis=1) _filename = f'{path}\\s_{channel-5}\\j6_s_{channel-5}_{scenario_time}_{time()}.data' df.to_csv(_filename, sep='\t', index=False) elif channel in list(range(9, 15)): @@ -221,7 +168,7 @@ def data_proc_regular(path, filename, channel, scenario_time): lines = f_obj.readlines() _d2d_vel = {'hw_joint_vel_feedback': []} _d2d_trq = {'device_servo_trq_feedback': []} - for line in lines: + for line in lines[-300:]: data = eval(line.strip())['data'] for item in data: try: @@ -233,9 +180,9 @@ def data_proc_regular(path, filename, channel, scenario_time): elif item.get('channel', None) == channel-9 and item.get('name', None) == 'device_servo_trq_feedback': _d2d_trq['device_servo_trq_feedback'].extend(item['value']) - df1 = pandas.DataFrame.from_dict(_d2d_vel) - df2 = pandas.DataFrame.from_dict(_d2d_trq) - df = pandas.concat([df1, df2], axis=1) + df1 = DataFrame.from_dict(_d2d_vel) + df2 = DataFrame.from_dict(_d2d_trq) + df = concat([df1, df2], axis=1) _filename = f'{path}\\single\\j{channel-8}_hold_{time()}.data' df.to_csv(_filename, sep='\t', index=False) @@ -257,9 +204,9 @@ def data_proc_inertia(path, filename, channel): elif item.get('channel', None) == channel+3 and item.get('name', None) == 'device_servo_trq_feedback': _d2d_trq['device_servo_trq_feedback'].extend(item['value']) - df1 = pandas.DataFrame.from_dict(_d2d_vel) - df2 = pandas.DataFrame.from_dict(_d2d_trq) - df = pandas.concat([df1, df2], axis=1) + df1 = DataFrame.from_dict(_d2d_vel) + df2 = DataFrame.from_dict(_d2d_trq) + df = concat([df1, df2], axis=1) _filename = f'{path}\\inertia\\j{channel+4}_inertia_{time()}.data' df.to_csv(_filename, sep='\t', index=False) @@ -313,21 +260,21 @@ def run_rl(path, hr, md, loadsel, w2t): disc = disc_inertia # preparation 触发软急停,并解除,目的是让可能正在运行着的机器停下来 - _response = execution('diagnosis.open', hr, w2t, open=True, display_open=True) - _response = execution('diagnosis.set_params', hr, w2t, display_pdo_params=display_pdo_params) - # _response = execution('diagnosis.save', hr, w2t, save=True) # 这条命令有问题 + clibs.execution('diagnosis.open', hr, w2t, tab_name, open=True, display_open=True) + clibs.execution('diagnosis.set_params', hr, w2t, tab_name, display_pdo_params=display_pdo_params) + # clibs.execution('diagnosis.save', hr, w2t, tab_name, save=True) # 这条命令有问题 md.trigger_estop() md.reset_estop() for condition in conditions: number = conditions.index(condition) - w2t(f"正在执行{disc[number][0]}测试......", 0, 0, 'purple', 'Automatic Test') + w2t(f"正在执行{disc[number][0]}测试......", 0, 0, 'purple', tab_name) # 1. 将act重置为False,并修改未要执行的场景 md.write_act(False) ssh = SSHClient() ssh.set_missing_host_key_policy(AutoAddPolicy()) - ssh.connect('192.168.0.160', 22, username='luoshi', password='luoshi2019') + ssh.connect(clibs.ip_addr, 22, username='luoshi', password='luoshi2019') cmd = 'cd /home/luoshi/bin/controller/; ' cmd += 'sudo sed -i "/scenario/d" projects/target/_build/current/main.mod; ' cmd += f'sudo sed -i "/DONOTDELETE/i {condition}" projects/target/_build/current/main.mod' @@ -339,13 +286,13 @@ def run_rl(path, hr, md, loadsel, w2t): # 2. reload工程后,pp2main,并且自动模式和上电 prj_path = 'target/_build/target.prj' - _response = execution('overview.reload', hr, w2t, prj_path=prj_path, tasks=['current']) - _response = execution('rl_task.pp_to_main', hr, w2t, tasks=['current']) - _response = execution('state.switch_auto', hr, w2t) - _response = execution('state.switch_motor_on', hr, w2t) + clibs.execution('overview.reload', hr, w2t, tab_name, prj_path=prj_path, tasks=['current']) + clibs.execution('rl_task.pp_to_main', hr, w2t, tab_name, tasks=['current']) + clibs.execution('state.switch_auto', hr, w2t, tab_name) + clibs.execution('state.switch_motor_on', hr, w2t, tab_name) # 3. 开始运行程序,单轴运行35s - _response = execution('rl_task.run', hr, w2t, tasks=['current']) + clibs.execution('rl_task.run', hr, w2t, tab_name, tasks=['current']) _t_start = time() while True: if md.read_ready_to_go() == 1: @@ -353,7 +300,7 @@ def run_rl(path, hr, md, loadsel, w2t): break else: if (time() - _t_start) // 20 > 1: - w2t("20s内未收到机器人的运行信号,需要确认RL程序编写正确并正常执行...", 0, 111, 'red', 'Automatic Test') + w2t("20s内未收到机器人的运行信号,需要确认RL程序编写正确并正常执行...", 0, 111, 'red', tab_name) else: sleep(1) @@ -369,11 +316,11 @@ def run_rl(path, hr, md, loadsel, w2t): while True: scenario_time = md.read_scenario_time() if float(scenario_time) > 1: - w2t(f"场景{number-5}的周期时间:{scenario_time}", 0, 0, 'green', 'Automatic Test') + w2t(f"场景{number-5}的周期时间:{scenario_time}", 0, 0, 'green', tab_name) break else: if (time()-_t_start)//60 > 3: - w2t(f"未收到场景{number-5}的周期时间,需要确认RL程序编写正确并正常执行...", 0, 111, 'red', 'Automatic Test') + w2t(f"未收到场景{number-5}的周期时间,需要确认RL程序编写正确并正常执行...", 0, 111, 'red', tab_name) else: sleep(5) sleep(1) # 一定要延迟一秒再读一次scenario time寄存器,因为一开始读取的数值不准确 @@ -381,27 +328,27 @@ def run_rl(path, hr, md, loadsel, w2t): sleep(float(scenario_time)*0.2) # 再运行周期的20%即可 # 5.停止程序运行,保留数据并处理输出 - _response = execution('rl_task.stop', hr, w2t, tasks=['current']) + clibs.execution('rl_task.stop', hr, w2t, tab_name, tasks=['current']) _c_msg = hr.c_msg.copy() for _msg in _c_msg: if 'diagnosis.result' in _msg: disc[number][1].insert(0, loads(_msg)) else: hr.c_msg_xs.clear() - if len(hr.c_msg) > 240: - del hr.c_msg[240:] + if len(hr.c_msg) > 270: + del hr.c_msg[270:] gen_result_file(path, loadsel, disc, number, scenario_time) else: if loadsel == 'tool100': - w2t("单轴和场景电机电流采集完毕,如需采集惯量负载,须切换负载类型,并更换惯量负载,重新执行。", 0, 0, 'green', 'Automatic Test') + w2t("单轴和场景电机电流采集完毕,如需采集惯量负载,须切换负载类型,并更换惯量负载,重新执行。", 0, 0, 'green', tab_name) elif loadsel == 'inertia': - w2t("惯量负载电机电流采集完毕,如需采集单轴/场景/保持电机电流,须切换负载类型,并更换偏置负载,重新执行。", 0, 0, 'green', 'Automatic Test') + w2t("惯量负载电机电流采集完毕,如需采集单轴/场景/保持电机电流,须切换负载类型,并更换偏置负载,重新执行。", 0, 0, 'green', tab_name) def main(path, hr, md, loadsel, w2t): - data_dirs, data_files = traversal_files(path, w2t) + data_dirs, data_files = clibs.traversal_files(path, w2t) config_file, current_file, prj_file = check_files(path, loadsel, data_dirs, data_files, w2t) - prj_to_xcore(prj_file) + clibs.prj_to_xcore(prj_file) run_rl(path, hr, md, loadsel, w2t) diff --git a/aio/code/commons/clibs.py b/aio/code/commons/clibs.py new file mode 100644 index 0000000..8876185 --- /dev/null +++ b/aio/code/commons/clibs.py @@ -0,0 +1,131 @@ +from os import scandir +from threading import Thread +from time import sleep +from os.path import exists +from paramiko import SSHClient, AutoAddPolicy +from socket import setdefaulttimeout +from logging import DEBUG, INFO, WARNING, ERROR, CRITICAL, Formatter, StreamHandler, basicConfig +from concurrent_log_handler import ConcurrentRotatingFileHandler + +ip_addr = '192.168.0.160' +RADIAN = 57.3 # 180 / 3.1415926 +MAX_FRAME_SIZE = 1024 +TIMEOUT = 5 +setdefaulttimeout(TIMEOUT) +tab_names = {'dp': 'Data Process', 'at': 'Automatic Test', 'da': 'Duration Action', 'op': 'openapi'} +# PREFIX = '' # for pyinstaller packaging +PREFIX = '../assets/' # for source code debug +log_data = f'{PREFIX}templates/c_msg.log' +heartbeat = f'{PREFIX}templates/heartbeat' +durable_data_current_xlsx = f'{PREFIX}templates/durable/durable_data_current.xlsx' +durable_data_current_max_xlsx = f'{PREFIX}templates/durable/durable_data_current_max.xlsx' +durable_data_current = { + 'time': list(range(1, 19)), + 'axis1': [0 for _ in range(18)], + 'axis2': [0 for _ in range(18)], + 'axis3': [0 for _ in range(18)], + 'axis4': [0 for _ in range(18)], + 'axis5': [0 for _ in range(18)], + 'axis6': [0 for _ in range(18)], +} +durable_data_current_max = { + 'time': list(range(1, 19)), + 'axis1': [0 for _ in range(18)], + 'axis2': [0 for _ in range(18)], + 'axis3': [0 for _ in range(18)], + 'axis4': [0 for _ in range(18)], + 'axis5': [0 for _ in range(18)], + 'axis6': [0 for _ in range(18)], +} + +fmt = Formatter('%(asctime)s # %(levelname)s-%(filename)s-%(funcName)s # %(message)s') +# file_handler = logging.FileHandler(log_data) +# file_handler = RotatingFileHandler(filename=log_data, backupCount=10, maxBytes=50*1024*1024, encoding='utf-8') +file_handler = ConcurrentRotatingFileHandler(filename=log_data, backupCount=10, maxBytes=50*1024*1024, encoding='utf-8') +file_handler.setFormatter(fmt) +file_handler.setLevel(INFO) +console_handler = StreamHandler() +console_handler.setFormatter(fmt) +console_handler.setLevel(ERROR) + +# basicConfig(level=WARNING, # for product +basicConfig(level=WARNING, + datefmt='%Y-%m-%dT%H:%M:%S', + # handlers=[file_handler]) # for product + handlers=[file_handler, console_handler]) + + +class GetThreadResult(Thread): + def __init__(self, func, args=()): + super(GetThreadResult, self).__init__() + self.func = func + self.args = args + self.result = 0 + + def run(self): + sleep(1) + self.result = self.func(*self.args) + + def get_result(self): + Thread.join(self) # 等待线程执行完毕 + try: + return self.result + except Exception as Err: + return None + + +def traversal_files(path, w2t): + # 功能:以列表的形式分别返回指定路径下的文件和文件夹,不包含子目录 + # 参数:路径 + # 返回值:路径下的文件夹列表 路径下的文件列表 + if not exists(path): + msg = f'数据文件夹{path}不存在,请确认后重试......' + w2t(msg, 0, 1, 'red') + else: + dirs = [] + files = [] + for item in scandir(path): + if item.is_dir(): + dirs.append(item.path) + elif item.is_file(): + files.append(item.path) + + return dirs, files + + +def prj_to_xcore(prj_file): + ssh = SSHClient() + ssh.set_missing_host_key_policy(AutoAddPolicy()) + ssh.connect(ip_addr, 22, username='luoshi', password='luoshi2019') + sftp = ssh.open_sftp() + sftp.put(prj_file, '/tmp/target.zip') + cmd = 'cd /tmp; rm -rf target/; mkdir target; unzip -d target/ -q target.zip; ' + cmd += 'chmod 777 -R target/; rm target.zip' + ssh.exec_command(cmd) + + cmd = 'sudo rm -rf /home/luoshi/bin/controller/projects/target; ' + cmd += 'sudo mv /tmp/target/ /home/luoshi/bin/controller/projects/' + stdin, stdout, stderr = ssh.exec_command(cmd, get_pty=True) + stdin.write('luoshi2019' + '\n') + stdin.flush() + print(stdout.read().decode()) # 必须得输出一下stdout,才能正确执行sudo + print(stderr.read().decode()) # 顺便也执行以下stderr + + cmd = 'cd /home/luoshi/bin/controller/; ' + cmd += 'sudo chmod -R 755 projects; rm /tmp/*.prj; sudo mv projects/target/_build/*.prj /tmp; cd /tmp; ' + cmd += 'prj=($(ls *.prj)); sudo mv ${prj[0]} /home/luoshi/bin/controller/projects/target/_build/target.prj; ' + stdin, stdout, stderr = ssh.exec_command(cmd, get_pty=True) + stdin.write('luoshi2019' + '\n') + stdin.flush() + print(stdout.read().decode()) # 必须得输出一下stdout,才能正确执行sudo + print(stderr.read().decode()) # 顺便也执行以下stderr + ssh.close() + + +def execution(cmd, hr, w2t, tab_name, **kwargs): + _id = hr.execution(cmd, **kwargs) + _msg = hr.get_from_id(_id) + if not _msg: + w2t(f"无法获取{_id}请求的响应信息", 0, 6, 'red', tab_name) + else: + return eval(_msg.split('#')[2]) diff --git a/aio/code/openapi.py b/aio/code/commons/openapi.py similarity index 92% rename from aio/code/openapi.py rename to aio/code/commons/openapi.py index ed70430..95b422e 100644 --- a/aio/code/openapi.py +++ b/aio/code/commons/openapi.py @@ -1,25 +1,22 @@ from json import load, dumps, loads -from socket import socket, setdefaulttimeout, AF_INET, SOCK_STREAM +from socket import socket, AF_INET, SOCK_STREAM from threading import Thread import selectors from time import time, sleep -from os.path import dirname from pymodbus.client.tcp import ModbusTcpClient from pymodbus.payload import BinaryPayloadDecoder, BinaryPayloadBuilder from pymodbus.constants import Endian +from logging import getLogger +from commons import clibs -MAX_FRAME_SIZE = 1024 -setdefaulttimeout(2) -current_path = dirname(__file__) -heartbeat = f'{current_path}/../assets/templates/heartbeat' - +logger = getLogger(__file__) class ModbusRequest(object): def __init__(self, w2t): super().__init__() self.w2t = w2t self.tab_name = 'openapi' - self.host = '192.168.0.160' + self.host = clibs.ip_addr self.port = 502 self.interval = 0.3 self.c = ModbusTcpClient(self.host, self.port) @@ -195,21 +192,19 @@ class HmiRequest(object): def sock_conn(self): # while True: - with open(heartbeat, "r", encoding='utf-8') as f_hb: + with open(clibs.heartbeat, "r", encoding='utf-8') as f_hb: c_state = f_hb.read().strip() if c_state == '0': try: self.c = socket(AF_INET, SOCK_STREAM) - self.c.connect(('192.168.0.160', 5050)) - # self.c.connect(('192.168.84.129', 5050)) + self.c.connect((clibs.ip_addr, 5050)) self.c.setblocking(False) self.c_xs = socket(AF_INET, SOCK_STREAM) - self.c_xs.connect(('192.168.0.160', 6666)) - # self.c_xs.connect(('192.168.84.129', 6666)) + self.c_xs.connect((clibs.ip_addr, 6666)) self.c_xs.setblocking(False) self.w2t("Connection success", 0, 0, 'green', tab_name=self.tab_name) - with open(heartbeat, "w", encoding='utf-8') as f_hb: + with open(clibs.heartbeat, "w", encoding='utf-8') as f_hb: f_hb.write('1') md = ModbusRequest(self.w2t) md.reset_estop() @@ -219,7 +214,7 @@ class HmiRequest(object): md.write_axis(1) except Exception as Err: self.w2t("Connection failed...", 0, 0, 'red', tab_name=self.tab_name) - with open(heartbeat, "w", encoding='utf-8') as f_hb: + with open(clibs.heartbeat, "w", encoding='utf-8') as f_hb: f_hb.write('0') def header_check(self, index, data): @@ -247,33 +242,29 @@ class HmiRequest(object): # print(f"in head check data: {data}") self.broke = 100 - index += MAX_FRAME_SIZE + index += clibs.MAX_FRAME_SIZE return index, 0, 0 def heartbeat(self): while self.t_bool: _id = self.execution('controller.heart') _flag = '0' if self.get_from_id(_id) is None else '1' - print(f"hb = {_flag}", end=' ') - print(f"len(c_msg) = {len(self.c_msg)}", end=' ') - print(f"len(c_msg_xs) = {len(self.c_msg_xs)}", end='\n') - with open(heartbeat, "w", encoding='utf-8') as f_hb: + # print(f"hb = {_flag}", end=' ') + # print(f"len(c_msg) = {len(self.c_msg)}", end=' ') + # print(f"len(c_msg_xs) = {len(self.c_msg_xs)}", end='\n') + with open(clibs.heartbeat, "w", encoding='utf-8') as f_hb: f_hb.write(_flag) - if _flag == '0': - self.w2t(f"{_id} 心跳丢失,连接失败,重新连接中...", 0, 7, 'red', tab_name=self.tab_name) - t = time() - with open(f"{current_path}/../assets/templates/c_msg.log", "w", encoding='utf-8') as f: - for msg in self.c_msg: - f.write(str(t) + '-' + str(loads(msg)) + '\n') - sleep(1) - + if _flag == '0': + self.w2t(f"{_id} 心跳丢失,连接失败,重新连接中...", 0, 7, 'red', tab_name=self.tab_name) + sleep(2) def msg_storage(self, response, flag=0): # response是解码后的字符串 messages = self.c_msg if flag == 0 else self.c_msg_xs + logger.warning(f"{loads(response)}") if 'move.monitor' in response: pass - elif len(messages) < 20000: + elif len(messages) < 10000: messages.insert(0, response) else: messages.insert(0, response) @@ -317,7 +308,7 @@ class HmiRequest(object): # print(f"broke == 0 index = {self.index-8}") # print(f"broke == 0 INIT pkg size = {self.pkg_size}") # print(f"broke == 0 data = {data}") - if self.index > MAX_FRAME_SIZE: + if self.index > clibs.MAX_FRAME_SIZE: break # 详见解包原理数据.txt,self.pkg_size 永远是除了当前data之外剩余未处理的数据大小 if self.pkg_size <= len(data) - self.index: @@ -361,15 +352,15 @@ class HmiRequest(object): # print('flag = 0 encounter broke == 3') self.broke = 3 - self.index += MAX_FRAME_SIZE + self.index += clibs.MAX_FRAME_SIZE self.reset_index = 1 - break # 因为 index + 2 的大小超过 MAX_FRAME_SIZE + break # 因为 index + 2 的大小超过 clibs.MAX_FRAME_SIZE elif self.index+_frame_size-6 > len(data): self.response = data[self.index:].decode() self.pkg_size -= (len(data) - self.index) # 详见解包原理数据.txt,self.pkg_size self.leftover = (_frame_size-6-(len(data)-self.index)) - self.index += MAX_FRAME_SIZE + self.index += clibs.MAX_FRAME_SIZE self.reset_index = 1 # print(f"in flag=0 else data = {data}") @@ -438,9 +429,9 @@ class HmiRequest(object): # print('flag = 1 encounter broke == 3') self.broke = 3 - self.index += MAX_FRAME_SIZE + self.index += clibs.MAX_FRAME_SIZE self.reset_index = 1 - break # 因为 index + 2 的大小超过 MAX_FRAME_SIZE + break # 因为 index + 2 的大小超过 clibs.MAX_FRAME_SIZE # print(f"in pkg size > 0 loop after if data = {data}") # print(f"in pkg size > 0 loop after if index = {self.index}") # print(f"in pkg size > 0 loop after if pkg size = {self.pkg_size}") @@ -457,7 +448,7 @@ class HmiRequest(object): self.response += data[self.index:].decode() self.leftover -= (len(data) - self.index) self.pkg_size -= (len(data) - self.index) - self.index += MAX_FRAME_SIZE + self.index += clibs.MAX_FRAME_SIZE self.reset_index = 1 # print(f"in pkg size > 0 loop after else data = {data}") # print(f"in pkg size > 0 loop after else index = {self.index}") @@ -511,15 +502,21 @@ class HmiRequest(object): def get_from_id(self, msg_id, flag=0): for i in range(3): - messages = self.c_msg if flag == 0 else self.c_msg_xs - for msg in messages: - if msg_id is None: - return None - elif msg_id in msg: - return msg + with open(clibs.log_data, mode='r', encoding='utf-8') as f_log: + for line in f_log: + if msg_id in line.strip(): + return line sleep(1) - else: - return None + else: # 尝试在上一次分割的日志中查找,只做一次 + sleep(1) + try: + with open(clibs.log_data+'.1', mode='r', encoding='utf-8') as f_log: + for line in f_log: + if msg_id in line.strip(): + return line + except FileNotFoundError: + pass + return None def package(self, cmd): _frame_head = (len(cmd) + 6).to_bytes(length=2, byteorder='big') @@ -533,7 +530,7 @@ class HmiRequest(object): def unpackage(self, sock): def to_read(conn, mask): - data = conn.recv(MAX_FRAME_SIZE) + data = conn.recv(clibs.MAX_FRAME_SIZE) if data: # print(data) self.get_response(data) @@ -580,7 +577,7 @@ class HmiRequest(object): if flg == 0: # for old protocols req = None try: - with open(f'{current_path}/../assets/templates/json/{command}.json', encoding='utf-8', + with open(f'{clibs.PREFIX}templates/json/{command}.json', encoding='utf-8', mode='r') as f_json: req = load(f_json) except: diff --git a/aio/code/data_process/__init__.py b/aio/code/data_process/__init__.py deleted file mode 100644 index 3913f0e..0000000 --- a/aio/code/data_process/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__all__ = ['brake', 'current', 'iso', 'wavelogger'] \ No newline at end of file diff --git a/aio/code/data_process/brake.py b/aio/code/data_process/brake.py index 233e0c6..b2f1333 100644 --- a/aio/code/data_process/brake.py +++ b/aio/code/data_process/brake.py @@ -1,49 +1,14 @@ # coding: utf-8 -from os import scandir -from os.path import isfile, exists +from os.path import isfile from sys import argv from openpyxl import load_workbook from time import time, sleep, strftime, localtime from threading import Thread from pandas import read_csv +from logging import getLogger +from commons import clibs - -class GetThreadResult(Thread): - def __init__(self, func, args=()): - super(GetThreadResult, self).__init__() - self.func = func - self.args = args - self.result = 0 - - def run(self): - sleep(1) - self.result = self.func(*self.args) - - def get_result(self): - Thread.join(self) # 等待线程执行完毕 - try: - return self.result - except Exception as Err: - return None - - -def traversal_files(path, w2t): - # 功能:以列表的形式分别返回指定路径下的文件和文件夹,不包含子目录 - # 参数:路径 - # 返回值:路径下的文件夹列表 路径下的文件列表 - if not exists(path): - msg = f'数据文件夹{path}不存在,请确认后重试......' - w2t(msg, 0, 1, 'red') - else: - dirs = [] - files = [] - for item in scandir(path): - if item.is_dir(): - dirs.append(item.path) - elif item.is_file(): - files.append(item.path) - - return dirs, files +logger = getLogger(__file__) def check_files(path, raw_data_dirs, result_files, w2t): @@ -83,7 +48,7 @@ def check_files(path, raw_data_dirs, result_files, w2t): 规则解释:AA/BB/CC 指的是臂展/负载/速度的比例,例如reach66_load100_speed33:66%臂展,100%负载以及33%速度情况下的测试结果文件夹""" w2t(msg, 0, 4, 'red') - _, raw_data_files = traversal_files(raw_data_dir, w2t) + _, raw_data_files = clibs.traversal_files(raw_data_dir, w2t) if len(raw_data_files) != 3: msg = f"数据目录 {raw_data_dir} 下数据文件个数错误,每个数据目录下有且只能有三个以 .data 为后缀的数据文件" w2t(msg, 0, 5, 'red') @@ -109,6 +74,7 @@ def get_configs(configfile, w2t): return av, rr + def now_doing_msg(docs, flag, w2t): # 功能:输出正在处理的文件或目录 # 参数:文件或目录,start 或 done 标识 @@ -228,7 +194,7 @@ def data_process(result_file, raw_data_dirs, av, rr, vel, trq, estop, w2t): global stop stop = 0 - t_excel = GetThreadResult(load_workbook, args=(result_file, )) + t_excel = clibs.GetThreadResult(load_workbook, args=(result_file, )) t_wait = Thread(target=w2t_local, args=('.', 1, w2t)) t_excel.start() t_wait.start() @@ -242,7 +208,7 @@ def data_process(result_file, raw_data_dirs, av, rr, vel, trq, estop, w2t): for raw_data_dir in raw_data_dirs: if raw_data_dir.split('\\')[-1].split('_')[0] == prefix: now_doing_msg(raw_data_dir, 'start', w2t) - _, data_files = traversal_files(raw_data_dir, w2t) + _, data_files = clibs.traversal_files(raw_data_dir, w2t) # 数据文件串行处理模式--------------------------------- # count = 1 # for data_file in data_files: @@ -280,7 +246,7 @@ def main(path, vel, trq, estop, w2t): # 参数:initialization函数的返回值 # 返回值:- time_start = time() - raw_data_dirs, result_files = traversal_files(path, w2t) + raw_data_dirs, result_files = clibs.traversal_files(path, w2t) try: # threads = [] diff --git a/aio/code/data_process/current.py b/aio/code/data_process/current.py index 78771f7..19f5876 100644 --- a/aio/code/data_process/current.py +++ b/aio/code/data_process/current.py @@ -1,31 +1,14 @@ from openpyxl import load_workbook -from os import scandir -from os.path import exists from sys import argv from pandas import read_csv, concat, set_option from re import match from threading import Thread from time import sleep from csv import reader, writer +from logging import getLogger +from commons import clibs - -class GetThreadResult(Thread): - def __init__(self, func, args=()): - super(GetThreadResult, self).__init__() - self.func = func - self.args = args - self.result = 0 - - def run(self): - sleep(1) - self.result = self.func(*self.args) - - def get_result(self): - Thread.join(self) # 等待线程执行完毕 - try: - return self.result - except Exception as Err: - return None +logger = getLogger(__file__) def w2t_local(msg, wait, w2t): @@ -38,27 +21,8 @@ def w2t_local(msg, wait, w2t): break -def traversal_files(path, w2t): - # 功能:以列表的形式分别返回指定路径下的文件和文件夹,不包含子目录 - # 参数:路径 - # 返回值:路径下的文件夹列表 路径下的文件列表 - if not exists(path): - msg = f'数据文件夹{path}不存在,请确认后重试......' - w2t(msg, 0, 8, 'red') - else: - dirs = [] - files = [] - for item in scandir(path): - if item.is_dir(): - dirs.append(item.path) - elif item.is_file(): - files.append(item.path) - - return dirs, files - - def initialization(path, sub, w2t): - _, data_files = traversal_files(path, w2t) + _, data_files = clibs.traversal_files(path, w2t) count = 0 for data_file in data_files: @@ -69,8 +33,8 @@ def initialization(path, sub, w2t): count += 1 else: if not (match('j[1-7].*\\.data', filename) or match('j[1-7].*\\.csv', filename)): - print(f"不合规 {data_file}") - msg = f"所有文件必须以 jx_ 开头,以 .data/csv 结尾(x取值1-7),请检查后重新运行。" + msg = f"不合规 {data_file}\n" + msg += f"所有文件必须以 jx_ 开头,以 .data/csv 结尾(x取值1-7),请检查后重新运行。" w2t(msg, 0, 6, 'red') if not ((sub == 'cycle' and count == 2) or (sub != 'cycle' and count == 1)): @@ -174,7 +138,7 @@ def current_cycle(dur, data_files, rcs, rrs, vel, trq, trqh, rpms, w2t): w2t(f"正在打开文件 {result},需要 10s 左右", 1, 0, 'orange') global stop stop = 0 - t_excel = GetThreadResult(load_workbook, args=(result, )) + t_excel = clibs.GetThreadResult(load_workbook, args=(result, )) t_wait = Thread(target=w2t_local, args=('.', 1, w2t)) t_excel.start() t_wait.start() @@ -268,7 +232,7 @@ def p_single(wb, single, vel, trq, rpms, rrs, w2t): col_names = list(df.columns) df_1 = df[col_names[vel-1]].multiply(rpm*addition) df_2 = df[col_names[trq-1]].multiply(scale) - print(df_1.abs().max()) + # print(df_1.abs().max()) df = concat([df_1, df_2], axis=1) _step = 5 if data_file.endswith('.csv') else 50 diff --git a/aio/code/data_process/iso.py b/aio/code/data_process/iso.py index a6be621..5318d64 100644 --- a/aio/code/data_process/iso.py +++ b/aio/code/data_process/iso.py @@ -1,27 +1,12 @@ # _*_ encoding:utf-8 _*_ import pdfplumber from openpyxl import load_workbook -from os import scandir, remove -from os.path import exists +from os import remove from sys import argv +from logging import getLogger +from commons import clibs - -def traversal_files(path, w2t): - # 功能:以列表的形式分别返回指定路径下的文件和文件夹,不包含子目录 - # 参数:路径 - # 返回值:路径下的文件夹列表 路径下的文件列表 - if not exists(path): - msg = f'数据文件夹{path}不存在,请确认后重试......' - w2t(msg, 0, 1, 'red') - else: - dirs = files = [] - for item in scandir(path): - if item.is_dir(): - dirs.append(item.path) - elif item.is_file(): - files.append(item.path) - - return dirs, files +logger = getLogger(__file__) def p_iso(file, p_files, ws, tmpfile): @@ -153,7 +138,7 @@ def p_iso_1000(file, p_files, ws, tmpfile): def main(path, w2t): - dirs, files = traversal_files(path, 1) + dirs, files = clibs.traversal_files(path, 1) try: wb = load_workbook(path + "/iso-results.xlsx") diff --git a/aio/code/data_process/wavelogger.py b/aio/code/data_process/wavelogger.py index 730d276..625b2a5 100644 --- a/aio/code/data_process/wavelogger.py +++ b/aio/code/data_process/wavelogger.py @@ -1,31 +1,11 @@ -import os -import random - from pandas import read_csv from csv import reader from sys import argv -from os.path import exists -from os import scandir, remove from openpyxl import Workbook -from random import randint +from logging import getLogger +from commons import clibs -def traversal_files(path, w2t): - # 功能:以列表的形式分别返回指定路径下的文件和文件夹,不包含子目录 - # 参数:路径 - # 返回值:路径下的文件夹列表 路径下的文件列表 - if not exists(path): - msg = f'数据文件夹{path}不存在,请确认后重试......' - w2t(msg, 0, 1, 'red') - else: - dirs = [] - files = [] - for item in scandir(path): - if item.is_dir(): - dirs.append(item.path) - elif item.is_file(): - files.append(item.path) - - return dirs, files +logger = getLogger(__file__) def find_point(bof, step, pos, data_file, flag, df, row, w2t): @@ -95,7 +75,7 @@ def get_cycle_info(data_file, df, row, step, w2t): def initialization(path, w2t): - _, data_files = traversal_files(path, w2t) + _, data_files = clibs.traversal_files(path, w2t) for data_file in data_files: if not data_file.lower().endswith('.csv'): @@ -126,7 +106,7 @@ def single_file_proc(ws, data_file, df, low, high, cycle, w2t): _step = 5 _data = {} row_max = df.index[-1]-100 - print(data_file) + # print(data_file) while _row < row_max: if count not in _data.keys(): _data[count] = [] @@ -149,7 +129,7 @@ def single_file_proc(ws, data_file, df, low, high, cycle, w2t): ws.cell(row=1, column=i).value = f"第{i-1}次测试" ws.cell(row=i, column=1).value = f"第{i-1}次精度变化" - print(_data) + # print(_data) for i in sorted(_data.keys()): _row = 2 _column = i + 1 @@ -162,9 +142,9 @@ def execution(data_files, w2t): wb = Workbook() for data_file in data_files: ws, df, low, high, cycle = preparation(data_file, wb, w2t) - print(f"low = {low}") - print(f"high = {high}") - print(f"cycle = {cycle}") + # print(f"low = {low}") + # print(f"high = {high}") + # print(f"cycle = {cycle}") single_file_proc(ws, data_file, df, low, high, cycle, w2t) wd = data_files[0].split('\\') diff --git a/aio/code/durable_action/__init__.py b/aio/code/durable_action/__init__.py deleted file mode 100644 index 913ac28..0000000 --- a/aio/code/durable_action/__init__.py +++ /dev/null @@ -1 +0,0 @@ -__all__ = ['factory_test'] \ No newline at end of file diff --git a/aio/code/durable_action/factory_test.py b/aio/code/durable_action/factory_test.py index 094b416..930a1d2 100644 --- a/aio/code/durable_action/factory_test.py +++ b/aio/code/durable_action/factory_test.py @@ -1,7 +1,4 @@ from sys import argv -from os.path import exists, dirname -from os import scandir -from paramiko import SSHClient, AutoAddPolicy from json import loads from time import sleep, time, strftime, localtime from pandas import DataFrame @@ -9,11 +6,12 @@ from openpyxl import load_workbook from math import sqrt from numpy import power from csv import writer +from logging import getLogger +from commons import clibs -tab_name = 'Durable Action' +logger = getLogger(__file__) +tab_name = clibs.tab_names['da'] count = 0 -durable_data_current_xlsx = f'{dirname(__file__)}/../../assets/templates/durable/durable_data_current.xlsx' -durable_data_current_max_xlsx = f'{dirname(__file__)}/../../assets/templates/durable/durable_data_current_max.xlsx' display_pdo_params = [ # {"name": "hw_joint_vel_feedback", "channel": 0}, # {"name": "hw_joint_vel_feedback", "channel": 1}, @@ -34,22 +32,6 @@ title = [ ] -def traversal_files(path, w2t): - if not exists(path): - msg = f'数据文件夹{path}不存在,请确认后重试......' - w2t(msg, 0, 1, 'red', tab_name=tab_name) - else: - dirs = [] - files = [] - for item in scandir(path): - if item.is_dir(): - dirs.append(item.path) - elif item.is_file(): - files.append(item.path) - - return dirs, files - - def check_files(data_dirs, data_files, w2t): if len(data_dirs) != 0 or len(data_files) != 2: w2t('初始路径下不允许有文件夹,且初始路径下只能存在如下文件,确认后重新运行!\n1. target.zip\n2. configs.xlsx', 0, 10, 'red', tab_name) @@ -63,50 +45,10 @@ def check_files(data_dirs, data_files, w2t): return data_files -def prj_to_xcore(prj_file): - ssh = SSHClient() - ssh.set_missing_host_key_policy(AutoAddPolicy()) - ssh.connect('192.168.0.160', 22, username='luoshi', password='luoshi2019') - sftp = ssh.open_sftp() - sftp.put(prj_file, '/tmp/target.zip') - cmd = 'cd /tmp; rm -rf target/; mkdir target; unzip -d target/ -q target.zip; ' - cmd += 'chmod 777 -R target/; rm target.zip' - ssh.exec_command(cmd) - - cmd = 'sudo rm -rf /home/luoshi/bin/controller/projects/target; ' - cmd += 'sudo mv /tmp/target/ /home/luoshi/bin/controller/projects/' - stdin, stdout, stderr = ssh.exec_command(cmd, get_pty=True) - stdin.write('luoshi2019' + '\n') - stdin.flush() - print(stdout.read().decode()) # 必须得输出一下stdout,才能正确执行sudo - print(stderr.read().decode()) # 顺便也执行以下stderr - - cmd = 'cd /home/luoshi/bin/controller/; ' - cmd += 'sudo mv projects/target/_build/*.prj projects/target/_build/target.prj' - stdin, stdout, stderr = ssh.exec_command(cmd, get_pty=True) - stdin.write('luoshi2019' + '\n') - stdin.flush() - print(stdout.read().decode()) # 必须得输出一下stdout,才能正确执行sudo - print(stderr.read().decode()) # 顺便也执行以下stderr - ssh.close() - - -def execution(cmd, hr, w2t, **kwargs): - _id = hr.execution(cmd, **kwargs) - _msg = hr.get_from_id(_id) - if not _msg: - w2t(f"无法获取{_id}请求的响应信息", 0, 7, 'red', tab_name=tab_name) - else: - _response = loads(_msg) - if not _response: - w2t(f"无法获取{id}请求的响应信息", 0, 1, 'red', tab_name=tab_name) - return _response - - def run_rl(path, config_file, data_all, hr, md, w2t): # 1. 关闭诊断曲线,触发软急停,并解除,目的是让可能正在运行着的机器停下来,切手动模式并下电 - _response = execution('diagnosis.open', hr, w2t, open=True, display_open=True) - _response = execution('diagnosis.set_params', hr, w2t, display_pdo_params=display_pdo_params) + clibs.execution('diagnosis.open', hr, w2t, tab_name, open=True, display_open=True) + clibs.execution('diagnosis.set_params', hr, w2t, tab_name, display_pdo_params=display_pdo_params) md.trigger_estop() md.reset_estop() md.write_act(False) @@ -114,13 +56,13 @@ def run_rl(path, config_file, data_all, hr, md, w2t): # 2. reload工程后,pp2main,并且自动模式和上电 prj_path = 'target/_build/target.prj' - _response = execution('overview.reload', hr, w2t, prj_path=prj_path, tasks=['current']) - _response = execution('rl_task.pp_to_main', hr, w2t, tasks=['current']) - _response = execution('state.switch_auto', hr, w2t) - _response = execution('state.switch_motor_on', hr, w2t) + clibs.execution('overview.reload', hr, w2t, tab_name, prj_path=prj_path, tasks=['current']) + clibs.execution('rl_task.pp_to_main', hr, w2t, tab_name, tasks=['current']) + clibs.execution('state.switch_auto', hr, w2t, tab_name) + clibs.execution('state.switch_motor_on', hr, w2t, tab_name) # 3. 开始运行程序 - _response = execution('rl_task.run', hr, w2t, tasks=['current']) + clibs.execution('rl_task.run', hr, w2t, tab_name, tasks=['current']) _t_start = time() while True: if md.read_ready_to_go() == 1: @@ -178,8 +120,8 @@ def get_durable_data(path, data, scenario_time, wait_time, rcs, hr, md, w2t): _data_list.insert(0, loads(_msg)) else: hr.c_msg_xs.clear() - if len(hr.c_msg) > 240: - del hr.c_msg[240:] + if len(hr.c_msg) > 270: + del hr.c_msg[270:] # with open(f'{path}\\log.txt', 'w', encoding='utf-8') as f_obj: # for _ in _data_list: @@ -253,8 +195,8 @@ def get_durable_data(path, data, scenario_time, wait_time, rcs, hr, md, w2t): while True: if not hr.durable_lock: hr.durable_lock = 1 - _df_1.to_excel(durable_data_current_xlsx, index=False) - _df_2.to_excel(durable_data_current_max_xlsx, index=False) + _df_1.to_excel(clibs.durable_data_current_xlsx, index=False) + _df_2.to_excel(clibs.durable_data_current_max_xlsx, index=False) hr.durable_lock = 0 break else: @@ -272,28 +214,10 @@ def get_durable_data(path, data, scenario_time, wait_time, rcs, hr, md, w2t): def main(path, hr, md, w2t): - durable_data_current = { - 'time': list(range(1, 19)), - 'axis1': [0 for _ in range(18)], - 'axis2': [0 for _ in range(18)], - 'axis3': [0 for _ in range(18)], - 'axis4': [0 for _ in range(18)], - 'axis5': [0 for _ in range(18)], - 'axis6': [0 for _ in range(18)], - } - durable_data_current_max = { - 'time': list(range(1, 19)), - 'axis1': [0 for _ in range(18)], - 'axis2': [0 for _ in range(18)], - 'axis3': [0 for _ in range(18)], - 'axis4': [0 for _ in range(18)], - 'axis5': [0 for _ in range(18)], - 'axis6': [0 for _ in range(18)], - } - data_all = [durable_data_current, durable_data_current_max] - data_dirs, data_files = traversal_files(path, w2t) + data_all = [clibs.durable_data_current, clibs.durable_data_current_max] + data_dirs, data_files = clibs.traversal_files(path, w2t) config_file, prj_file = check_files(data_dirs, data_files, w2t) - prj_to_xcore(prj_file) + clibs.prj_to_xcore(prj_file) run_rl(path, config_file, data_all, hr, md, w2t)