diff --git a/aio/README.md b/aio/README.md index 6bcc7c4..1e34ecc 100644 --- a/aio/README.md +++ b/aio/README.md @@ -1,91 +1,101 @@ -### 程序功能 +### 一、程序功能 自动化测试数据处理工具,减少人工处理时长,提高测试数据处理的效率和准确度: -1. 制动数据,单轴数据处理3min以内 -2. 电机电流数据,全部轴数据处理1min以内 -3. ISO激光数据整理,1min以内 -4. wavelogger波形处理,几乎不花费时间 -### 使用方法 +1. 制动数据,单轴数据处理 3min 以内 +2. 电机电流数据,全部轴数据处理 1min 以内 +3. ISO 激光数据整理,1min 以内 +4. wavelogger 波形处理,几乎不花费时间 -点击可执行程序 AIO.exe,然后选择功能,根据提示填写必要参数,点击运行即可 +--- -### 第三方库 +### 二、使用方法 + +点击可执行程序 AIO.exe,然后选择功能,根据提示填写必要参数,红色标签提示是必填项,蓝色标签提示是可选项,然后点击运行即可 + +> 需要注意的是,可选项填写的不合适,有可能导致数据错误,或者无法运行!! + +--- + +### 三、第三方库 ```text -参考requirements.txt -``` - -### 打包方法 - -``` -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\brake.py -p ..\code\iso.py -p ..\code\current.py -p ..\code\wavelogger.py +参考 requirements.txt ``` --- -### 注意事项 +### 四、打包方法 -#### 制动数据 +``` +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 +``` + +--- + +### 五、注意事项 + +#### 1) 制动数据 ```text 1. 数据文件存储存储规则 -数据文件,就是我们拍急停的时候,采集到的 .data 文件,正方向拍三次急停,会采集到三个 .data 文件,存储在同一个文件夹内,即每组(三个 .data 文件)文件必须存储在同一个文件夹内,数据文件的命名无要求, +数据文件,就是我们拍急停的时候,采集到的 .data 文件,根据规则选择某个方向拍三次急停,会采集到三个 .data 文件,存储在同一个文件夹内,即每组(三个 .data 文件)文件必须存储在同一个文件夹内,数据文件的命名无要求 2. 文件夹命名规则 -采集到的 .data 文件没有命名要求,但是对于文件夹的命名是有要求的,必须是如下格式: - dXX_speedXX_reachXX 或者 loadXX_reachXX_speedXX +对采集到的 .data 文件没有命名要求,但是对于其存储的文件夹的命名是有要求的,必须是如下格式: + reachXX_loadXX_speedXX XX代表不同条件下的测试数值,比如: - d100_speed33_reach66,指的是,负载100%,速度33%,臂展66% + reach100_load66_speed33,指的是,臂展100%,负载66%,速度33% 3. 结果文件命名规则 -所谓结果文件,就是处理数据的那个 excle 文件,该文件名字的前缀必须是 loadXX_XXXXXXXXX.xlsx,比如: - load33_自研_制动性能测试.xlsx - load66_自研_制动性能测试.xlsx - load100_自研_制动性能测试.xlsx +所谓结果文件,就是处理数据的那个 excle 文件,该文件名字的前缀必须是 reachXX_XXXXXXXXX.xlsx,比如: + reach33_自研_制动性能测试.xlsx + reach66_自研_制动性能测试.xlsx + reach100_自研_制动性能测试.xlsx -!!结果文件可以是没有数据的,也可以是之前有数据的,只要保证第 6 点中的那几个数据准确即可 +!!结果文件可以是没有数据的,也可以是之前有数据的,只要保证输入参数的正确性即可 4. 数据存储的组织结 - ..../j1/load100_speed33_reach100 - ..../j1/load100_speed66_reach100 + ..../j1/reach100_load66_speed33 + ..../j1/reach100_load66_speed66 .... - ..../j1/load100_speed100_reach100 - ..../j1/load100_speed33_reach100/2024_05_16_09_18_52.data - ..../j1/load100_speed33_reach100/2024_05_16_09_19_52.data - ..../j1/load100_speed33_reach100/2024_05_16_09_20_52.data - ..../j1/load33_自研_制动性能测试.xlsx - ..../j1/load66_自研_制动性能测试.xlsx - ..../j1/load100_自研_制动性能测试.xlsx + ..../j1/reach100_load33_speed33 + ..../j1/reach100_load100_speed33/2024_05_16_09_18_52.data + ..../j1/reach100_load100_speed33/2024_05_16_09_19_52.data + ..../j1/reach100_load100_speed33/2024_05_16_09_20_52.data + ..../j1/reach33_自研_制动性能测试.xlsx + ..../j1/reach66_自研_制动性能测试.xlsx + ..../j1/reach100_自研_制动性能测试.xlsx 5. 文件的打开与关闭 a. 在执行程序之前,需要关闭所有相关 excle 文件 b. 在执行程序之中,不允许打开相关 excle 文件 c. 在执行程序之后,需要逐个打开结果文件,并保存一次 -6. 参数一致性检查 -执行程序前,需要确定 configs.xlsx 中设定的减速比/最大角速度/额定电流的值是正确的 - -7. 数据准确性检查 -执行完程序之后,需要对结果文件的数据准确性做核对,通过我自己的数据观察,误差基本在10ms以内,也即10个数据点,误差较大的情况可自行调整 - -8. 其他 -程序运行主要的耗时集中在打开,保存和关闭结果文件,第一次打开的时候会比较慢,是因为 excel 在做首次公式的计算,保存关闭之后,再打开会比较快一些,另外,如果在运行出错并重复运行程序的时候无响应,或者出现异常,请打开任务管理器,关闭一切和excel相关的进程,重新运行即可 +6. 数据准确性检查 +执行完程序之后,可以在日志输出框中看到全部文件的处理过程,对于有问题的文件,会用特殊颜色进行标识,需要注意观察 + +7. 其他 +程序运行主要的耗时集中在打开,保存和关闭结果文件,第一次打开的时候会比较慢,另外还需要注意采集的数据长度和结果文件中预设的数据长度是否一致,若采集的数据长度大于预设的数据长度,则需要补齐数据 ``` -#### 电机电流 +#### 2) 电机电流 -1. 单独使用max/avg功能时,对于文件命名同第二点,存放数据的文件夹,只允许有 .data 或者 .csv 文件,且每次只能处理rc相同的轴的数据 -2. cycle功能只处理单文件单轴数据,可以批量处理所有轴,但要确保遵守如下规则: - a. 数据整理文件以 .xlsx 为后缀 - b. 其他文件 - A. 单轴:j1_xxxxx.data/csv - B. 保持:j1_hold_xxxx.data/csv - C. 所有文件放在同一个文件夹即可 - d. 界面输入rc参数时,需要输入所有轴的数据 +1. 单独使用 max/avg 功能时,要求文件命名以 "jx_" 开头,例如 j1_2024_06_18_09_09_11.data,只允许有 .data 或者 .csv 文件,可同时处理所有轴的数据 +2. cycle 功能支持处理单轴数据以及场景电机电流的数据,可以批量处理所有轴,但要确保遵守如下规则: + - 包含电机电流结果汇总文件(excel) + - 单轴文件:jx_xxxxx.data/csv + - 保持电流:jx_hold_xxxx.data/csv + - 场景文件:factory_53.8_2024_06_18_09_01_26.data(需手动拆分) + - 所有文件放在同一个文件夹即可 + - 界面输入rc参数时,需要输入所有轴的数据,即使只处理个别轴的数据 -#### ISO数据 +> 程序运行主要的耗时集中在打开,保存和关闭结果文件 +> 需要注意采集的数据长度和结果文件中预设的数据长度是否一致,若采集的数据长度大于预设的数据长度,则需要补齐数据 +> 和制动数据统一,后续将仅支持对hw_joint_vel_feedback的解析和处理,不再支持device_servo_vel_feedback + +#### 3) iso 数据 所有文件放在同一个文件夹即可,命名规则如下: a. ISO.pdf @@ -93,7 +103,9 @@ pyinstaller --noconfirm --onedir --windowed --add-data "C:/Users/Administrator/A c. ISO-V100.pdf d. iso-results.xlsx -#### wavelogger波形数据 +> 目前仅能处理 6 轴数据 + +#### 4) wavelogger 波形数据 1. 需要提前将 .xdt 波形数据转换成 .csv 文件 2. 组织目录下只允许有 .csv 文件,对文件夹无要求 @@ -219,8 +231,8 @@ v0.1.5.3(2024/06/14) 3. [README.md] 稍作修改,包括打包方式,功能特性等 v0.1.6.0(2024/06/15) -[aio.py] 新增wavelogger处理界面 -[wavelogger.py] 新增精度数据处理模块 +1. [aio.py] 新增wavelogger处理界面 +2. [wavelogger.py] 新增精度数据处理模块 v0.1.6.1(2024/06/16) 1. [wavelogger.py] bugfix single_file_proc函数中,修改_start起始点的计算逻辑 @@ -234,3 +246,5 @@ v0.1.6.3(2024/06/18) > !!WARNING:目前版本的电机电流程序还支持DriverMaster采集的数据处理,等明确后,将不再支持,也即所有的电机电流数据(工业+协作),都是用诊断曲线来采集 +v0.1.7.0(2024/06/29) +1. [current.py] 适配电机电流中速度使用hw_joint_vel_feedback的数据,取消对device_servo_vel_feedback的支持,后续所有涉及到速度相关的数据均已前者为准,现已完成对单轴和场景的适配 diff --git a/aio/assets/layout.xlsx b/aio/assets/layout.xlsx index 29a4ec5..e50780f 100644 Binary files a/aio/assets/layout.xlsx and b/aio/assets/layout.xlsx differ diff --git a/aio/code/aio.py b/aio/code/aio.py index e2b1077..7366aca 100644 --- a/aio/code/aio.py +++ b/aio/code/aio.py @@ -3,10 +3,13 @@ from os import getcwd from threading import Thread import tkinter.messagebox import customtkinter -import brake, current, iso, wavelogger from time import time, strftime, localtime from urllib.request import urlopen from socket import setdefaulttimeout +import data_process.brake as brake +import data_process.current as current +import data_process.iso as iso +import data_process.wavelogger as wavelogger customtkinter.set_appearance_mode("System") # Modes: "System" (standard), "Dark", "Light" customtkinter.set_default_color_theme("blue") # Themes: "blue" (standard), "green", "dark-blue" diff --git a/aio/code/automatic_test/do_brake.py b/aio/code/automatic_test/do_brake.py new file mode 100644 index 0000000..052262d --- /dev/null +++ b/aio/code/automatic_test/do_brake.py @@ -0,0 +1,67 @@ +import json +from socket import * +import threading +import time +import binascii + + +class HmiRequest(object): + + def __init__(self): + self.c = socket(AF_INET, SOCK_STREAM) + self.c.connect(('192.168.84.129', 5050)) + self.c_xs = socket(AF_INET, SOCK_STREAM) + self.c_xs.connect(('192.168.84.129', 6666)) + self.c.setblocking(False) + self.c_xs.setblocking(False) + self.t = threading.Thread(target=self.__heartbeat_detection) + self.t.daemon = True + self.t.start() + + def __handle_command(self, cmd): + len_frame, len_pkg = len(cmd), len(cmd) + 6 + pkg_head = str(hex(len_pkg))[2:].rjust(4, '0') + frame_head = str(hex(len_frame))[2:].rjust(4, '0') + str0 = binascii.unhexlify(pkg_head) # 报文 + str1 = chr(0) + chr(0) # 保留字段 + str2 = binascii.unhexlify(frame_head) # 帧 + str3 = chr(2) + chr(0) # 协议类型 + return str0 + str1.encode() + str2 + str3.encode() + cmd.encode() + + def __heartbeat_detection(self): + data = { + "id": "system.controller.heart_0", + "module": "system", + "command": "controller.heart", + } + _id = 1 + while True: + data["id"] = f"#system.controller.heart_{_id}" + cmd = json.dumps(data, separators=(',', ':')) + self.c.send(self.__handle_command(cmd)) + time.sleep(10) + _id += 1 + + def motor_on(self): + """HMI上电""" + data = { + "command": "state.switch_motor_on", + "id": str(1234), + "module": "system" + } + cmd = json.dumps(data, separators=(',', ':')) + self.c.send(self.__handle_command(cmd)) + time.sleep(2) + response = self.c.recv(102400) + print(response) + print(type(response)) + print(response.decode()) + + # response = json.loads(self.c.recv(102400).decode('utf-16-be')) + # print(response) + + +hr = HmiRequest() +hr.motor_on() + + diff --git a/aio/code/automatic_test/openapi.py b/aio/code/automatic_test/openapi.py new file mode 100644 index 0000000..052262d --- /dev/null +++ b/aio/code/automatic_test/openapi.py @@ -0,0 +1,67 @@ +import json +from socket import * +import threading +import time +import binascii + + +class HmiRequest(object): + + def __init__(self): + self.c = socket(AF_INET, SOCK_STREAM) + self.c.connect(('192.168.84.129', 5050)) + self.c_xs = socket(AF_INET, SOCK_STREAM) + self.c_xs.connect(('192.168.84.129', 6666)) + self.c.setblocking(False) + self.c_xs.setblocking(False) + self.t = threading.Thread(target=self.__heartbeat_detection) + self.t.daemon = True + self.t.start() + + def __handle_command(self, cmd): + len_frame, len_pkg = len(cmd), len(cmd) + 6 + pkg_head = str(hex(len_pkg))[2:].rjust(4, '0') + frame_head = str(hex(len_frame))[2:].rjust(4, '0') + str0 = binascii.unhexlify(pkg_head) # 报文 + str1 = chr(0) + chr(0) # 保留字段 + str2 = binascii.unhexlify(frame_head) # 帧 + str3 = chr(2) + chr(0) # 协议类型 + return str0 + str1.encode() + str2 + str3.encode() + cmd.encode() + + def __heartbeat_detection(self): + data = { + "id": "system.controller.heart_0", + "module": "system", + "command": "controller.heart", + } + _id = 1 + while True: + data["id"] = f"#system.controller.heart_{_id}" + cmd = json.dumps(data, separators=(',', ':')) + self.c.send(self.__handle_command(cmd)) + time.sleep(10) + _id += 1 + + def motor_on(self): + """HMI上电""" + data = { + "command": "state.switch_motor_on", + "id": str(1234), + "module": "system" + } + cmd = json.dumps(data, separators=(',', ':')) + self.c.send(self.__handle_command(cmd)) + time.sleep(2) + response = self.c.recv(102400) + print(response) + print(type(response)) + print(response.decode()) + + # response = json.loads(self.c.recv(102400).decode('utf-16-be')) + # print(response) + + +hr = HmiRequest() +hr.motor_on() + + diff --git a/aio/code/brake.py b/aio/code/data_process/brake.py similarity index 100% rename from aio/code/brake.py rename to aio/code/data_process/brake.py diff --git a/aio/code/current.py b/aio/code/data_process/current.py similarity index 100% rename from aio/code/current.py rename to aio/code/data_process/current.py diff --git a/aio/code/iso.py b/aio/code/data_process/iso.py similarity index 100% rename from aio/code/iso.py rename to aio/code/data_process/iso.py diff --git a/aio/code/wavelogger.py b/aio/code/data_process/wavelogger.py similarity index 100% rename from aio/code/wavelogger.py rename to aio/code/data_process/wavelogger.py