From 855448664ceb63fa35d160325d366c4d174c4932 Mon Sep 17 00:00:00 2001 From: gitea Date: Tue, 14 Jan 2025 23:52:52 +0800 Subject: [PATCH] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=8C=96=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E7=9A=84=E5=8A=9F=E8=83=BD=E8=BF=81=E7=A7=BB=E5=AE=8C=E6=AF=95?= =?UTF-8?q?=EF=BC=8C=E5=BE=85=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/files/projects/NB4h_R580_3B.zip | Bin 0 -> 26454 bytes .../projects/{registers.xml => autotest.xml} | 250 ++++---- assets/files/projects/configs.xlsx | Bin 226878 -> 226178 bytes assets/files/projects/registers.json | 592 ------------------ code/aio.py | 2 + code/automatic_test/do_brake.py | 396 ++++++------ code/automatic_test/do_current.py | 402 ++++-------- code/common/openapi.py | 44 +- code/data_process/current.py | 32 +- 9 files changed, 520 insertions(+), 1198 deletions(-) create mode 100644 assets/files/projects/NB4h_R580_3B.zip rename assets/files/projects/{registers.xml => autotest.xml} (89%) delete mode 100644 assets/files/projects/registers.json diff --git a/assets/files/projects/NB4h_R580_3B.zip b/assets/files/projects/NB4h_R580_3B.zip new file mode 100644 index 0000000000000000000000000000000000000000..0e2a341171212aaa43a35bd6bdd9ae6dfeb3f713 GIT binary patch literal 26454 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 PJUTo?#=llC-Ddv-PYtH@ literal 0 HcmV?d00001 diff --git a/assets/files/projects/registers.xml b/assets/files/projects/autotest.xml similarity index 89% rename from assets/files/projects/registers.xml rename to assets/files/projects/autotest.xml index 4d079df..6f1db45 100644 --- a/assets/files/projects/registers.xml +++ b/assets/files/projects/autotest.xml @@ -18,6 +18,7 @@ + @@ -37,6 +38,7 @@ + @@ -56,6 +58,7 @@ + @@ -75,6 +78,7 @@ + @@ -94,6 +98,7 @@ + @@ -113,6 +118,7 @@ + @@ -132,6 +138,7 @@ + @@ -151,6 +158,7 @@ + @@ -170,6 +178,7 @@ + @@ -189,6 +198,7 @@ + @@ -208,6 +218,7 @@ + @@ -227,6 +238,7 @@ + @@ -246,6 +258,7 @@ + @@ -265,6 +278,7 @@ + @@ -284,6 +298,7 @@ + @@ -303,6 +318,7 @@ + @@ -322,6 +338,7 @@ + @@ -341,6 +358,7 @@ + @@ -360,6 +378,7 @@ + @@ -367,18 +386,19 @@ - + - + + @@ -386,18 +406,19 @@ - + - + + @@ -405,18 +426,19 @@ - + - + + @@ -424,37 +446,19 @@ - - - - - - - - - - - - - - - - - - - - + - + - + + @@ -462,94 +466,19 @@ - - - - - - - - - - - - - - - - - - - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + @@ -569,6 +498,7 @@ + @@ -588,6 +518,7 @@ + @@ -607,6 +538,7 @@ + @@ -626,6 +558,7 @@ + @@ -645,6 +578,7 @@ + @@ -664,6 +598,7 @@ + @@ -683,6 +618,7 @@ + @@ -702,6 +638,7 @@ + @@ -721,6 +658,7 @@ + @@ -740,6 +678,7 @@ + @@ -759,6 +698,7 @@ + @@ -778,6 +718,7 @@ + @@ -797,6 +738,7 @@ + @@ -816,6 +758,7 @@ + @@ -835,6 +778,7 @@ + @@ -854,6 +798,7 @@ + @@ -873,6 +818,7 @@ + @@ -892,6 +838,7 @@ + @@ -911,5 +858,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/files/projects/configs.xlsx b/assets/files/projects/configs.xlsx index d9c683dbfb9ba2a683827d4c11fa960ee20c53d3..d7eb8d478b9f83d4cb11da5b699ed51963b287c8 100644 GIT binary patch delta 7266 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 delta 7885 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 diff --git a/assets/files/projects/registers.json b/assets/files/projects/registers.json deleted file mode 100644 index f4539a1..0000000 --- a/assets/files/projects/registers.json +++ /dev/null @@ -1,592 +0,0 @@ -{ - "MODBUS": [ - { - "property": { - "device_name": "autotest", - "endian": 1 - }, - "regs": { - "rd": [ - { - "addr": 40000, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "ctrl_clear_alarm", - "len": 1, - "name": "r_clear_alarm", - "retain": false, - "type": "bool" - }, - { - "addr": 40001, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "ctrl_estop_reset", - "len": 1, - "name": "r_estop_reset", - "retain": false, - "type": "bool" - }, - { - "addr": 40002, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "ctrl_estop_reset_clear_alarm", - "len": 1, - "name": "r_onekey_reset", - "retain": false, - "type": "bool" - }, - { - "addr": 40003, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "ctrl_motor_off", - "len": 1, - "name": "r_motor_off", - "retain": false, - "type": "bool" - }, - { - "addr": 40004, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "ctrl_motor_on", - "len": 1, - "name": "r_motor_on", - "retain": false, - "type": "bool" - }, - { - "addr": 40005, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "ctrl_motoron_pptomain_start", - "len": 1, - "name": "r_onekey_start", - "retain": false, - "type": "bool" - }, - { - "addr": 40006, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "ctrl_motoron_start", - "len": 1, - "name": "r_motoron_start", - "retain": false, - "type": "bool" - }, - { - "addr": 40007, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "ctrl_pause_motoroff", - "len": 1, - "name": "r_pause_motoroff", - "retain": false, - "type": "bool" - }, - { - "addr": 40008, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "ctrl_pptomain", - "len": 1, - "name": "r_pp2main", - "retain": false, - "type": "bool" - }, - { - "addr": 40009, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "ctrl_program_start", - "len": 1, - "name": "r_prog_start", - "retain": false, - "type": "bool" - }, - { - "addr": 40010, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "ctrl_program_stop", - "len": 1, - "name": "r_prog_stop", - "retain": false, - "type": "bool" - }, - { - "addr": 40011, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "ctrl_reduced_mode", - "len": 1, - "name": "r_reduced_mode", - "retain": false, - "type": "bool" - }, - { - "addr": 40012, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "ctrl_soft_estop", - "len": 1, - "name": "r_soft_estop", - "retain": false, - "type": "bool" - }, - { - "addr": 40013, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "ctrl_switch_auto_motoron", - "len": 1, - "name": "r_auto_motoron", - "retain": false, - "type": "bool" - }, - { - "addr": 40014, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "ctrl_switch_operation_auto", - "len": 1, - "name": "r_switch_auto", - "retain": false, - "type": "bool" - }, - { - "addr": 40015, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "ctrl_switch_operation_manu", - "len": 1, - "name": "r_switch_manual", - "retain": false, - "type": "bool" - }, - { - "addr": 40016, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "enable_safe_region01", - "len": 1, - "name": "r_safe_region01", - "retain": false, - "type": "bool" - }, - { - "addr": 40017, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "enable_safe_region02", - "len": 1, - "name": "r_safe_region02", - "retain": false, - "type": "bool" - }, - { - "addr": 40018, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "enable_safe_region03", - "len": 1, - "name": "r_safe_region03", - "retain": false, - "type": "bool" - }, - { - "addr": 40100, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "", - "len": 1, - "name": "signal_0", - "retain": false, - "type": "bool" - }, - { - "addr": 40101, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "", - "len": 1, - "name": "signal_1", - "retain": false, - "type": "bool" - }, - { - "addr": 40102, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "", - "len": 1, - "name": "signal_2", - "retain": false, - "type": "bool" - }, - { - "addr": 40103, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "", - "len": 1, - "name": "signal_3", - "retain": false, - "type": "bool" - }, - { - "addr": 40104, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "", - "len": 1, - "name": "signal_4", - "retain": false, - "type": "bool" - }, - { - "addr": 40105, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "", - "len": 1, - "name": "signal_5", - "retain": false, - "type": "bool" - }, - { - "addr": 40106, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "", - "len": 1, - "name": "signal_6", - "retain": false, - "type": "bool" - }, - { - "addr": 40107, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "", - "len": 1, - "name": "signal_7", - "retain": false, - "type": "bool" - }, - { - "addr": 40108, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "", - "len": 1, - "name": "signal_8", - "retain": false, - "type": "bool" - }, - { - "addr": 40109, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "", - "len": 1, - "name": "signal_9", - "retain": false, - "type": "bool" - } - ], - "rdwr": [ - { - "addr": 40500, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "sta_alarm", - "len": 1, - "name": "w_alarm_state", - "retain": false, - "type": "bool" - }, - { - "addr": 40501, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "sta_collision", - "len": 1, - "name": "w_clsn_alarm_stat", - "retain": false, - "type": "bool" - }, - { - "addr": 40502, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "sta_collision_open", - "len": 1, - "name": "w_clsn_open_stat", - "retain": false, - "type": "bool" - }, - { - "addr": 40503, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "sta_controller_is_running", - "len": 1, - "name": "w_controller_running", - "retain": false, - "type": "bool" - }, - { - "addr": 40504, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "sta_encoder_low_battery", - "len": 1, - "name": "w_encoder_low", - "retain": false, - "type": "bool" - }, - { - "addr": 40505, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "sta_estop", - "len": 1, - "name": "w_estop_stat", - "retain": false, - "type": "bool" - }, - { - "addr": 40506, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "sta_motor", - "len": 1, - "name": "w_motor_stat", - "retain": false, - "type": "bool" - }, - { - "addr": 40507, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "sta_operation_mode", - "len": 1, - "name": "w_operation_mode", - "retain": false, - "type": "bool" - }, - { - "addr": 40508, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "sta_program", - "len": 1, - "name": "w_prog_stat", - "retain": false, - "type": "bool" - }, - { - "addr": 40509, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "sta_program_not_run", - "len": 1, - "name": "w_prog_not_run", - "retain": false, - "type": "bool" - }, - { - "addr": 40510, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "sta_program_reset", - "len": 1, - "name": "w_prog_reset", - "retain": false, - "type": "bool" - }, - { - "addr": 40511, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "sta_reduced_mode", - "len": 1, - "name": "w_reduced_mode_stat", - "retain": false, - "type": "bool" - }, - { - "addr": 40512, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "sta_robot_is_busy", - "len": 1, - "name": "w_robot_is_busy", - "retain": false, - "type": "bool" - }, - { - "addr": 40513, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "sta_robot_moving", - "len": 1, - "name": "w_robot_moving", - "retain": false, - "type": "bool" - }, - { - "addr": 40514, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "sta_safe_door", - "len": 1, - "name": "w_safe_door", - "retain": false, - "type": "bool" - }, - { - "addr": 40515, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "sta_safe_region01", - "len": 1, - "name": "w_safe_region01", - "retain": false, - "type": "bool" - }, - { - "addr": 40516, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "sta_safe_region02", - "len": 1, - "name": "w_safe_region02", - "retain": false, - "type": "bool" - }, - { - "addr": 40517, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "sta_safe_region03", - "len": 1, - "name": "w_safe_region03", - "retain": false, - "type": "bool" - }, - { - "addr": 40518, - "addr_1st": 0, - "addr_2nd": 0, - "bit_bias": 0, - "byte_bias": 0, - "function": "sta_soft_estop", - "len": 1, - "name": "w_soft_estop_stat", - "retain": false, - "type": "bool" - } - ] - } - } - ] -} diff --git a/code/aio.py b/code/aio.py index 25ff35f..9f05b4e 100644 --- a/code/aio.py +++ b/code/aio.py @@ -261,6 +261,7 @@ class App: eval(clibs.data_dp["_main"] + ".main()") finally: clibs.running = False + clibs.stop = False else: messagebox.showinfo(title="进行中...", message="当前有程序正在运行!") elif self.tabview_top.get() == "自动测试": @@ -271,6 +272,7 @@ class App: eval("do_" + clibs.data_at["_main"] + ".main()") finally: clibs.running = False + clibs.stop = False else: messagebox.showinfo(title="进行中...", message="当前有程序正在运行!") diff --git a/code/automatic_test/do_brake.py b/code/automatic_test/do_brake.py index eba2cff..07f2359 100644 --- a/code/automatic_test/do_brake.py +++ b/code/automatic_test/do_brake.py @@ -1,153 +1,164 @@ from time import sleep, time, strftime, localtime -from sys import argv from os import mkdir from paramiko import SSHClient, AutoAddPolicy -from json import loads from openpyxl import load_workbook from pandas import DataFrame, concat +import json from commons import clibs -tab_name = clibs.tab_names['at'] -logger = clibs.log_prod +def initialization(path, sub, data_dirs, data_files, hr, w2t): + def check_files(): + if len(data_dirs) != 0 or len(data_files) != 6: + w2t("初始路径下不允许有文件夹,且初始路径下只能存在如下五个文件,确认后重新运行!", "red") + w2t("1. configs.xlsx\n2. reach33/reach66/reach100_xxxx.xlsx\n3. xxxx.zip\n", "red", "InitFileError") -def check_files(path, loadsel, data_dirs, data_files, w2t): - if len(data_dirs) != 0 or len(data_files) != 5: - w2t('初始路径下不允许有文件夹,且初始路径下只能存在如下五个文件,确认后重新运行!', 0, 0, 'red', tab_name) - w2t(' 1. configs.xlsx\n 2. reach33/reach66/reach100_xxxx.xlsx\n 3. xxxx.zip', 0, 1, 'red', tab_name) + config_file, reach33, reach66, reach100, prj_file = None, None, None, None, None + for data_file in data_files: + filename = data_file.split("/")[-1] + if filename == "configs.xlsx": + config_file = data_file + elif filename.startswith("reach33_") and filename.endswith(".xlsx"): + reach33 = data_file + elif filename.startswith("reach66_") and filename.endswith(".xlsx"): + reach66 = data_file + elif filename.startswith("reach100_") and filename.endswith(".xlsx"): + reach100 = data_file + elif filename.endswith(".zip"): + prj_file = data_file + else: + w2t("初始路径下不允许有文件夹,且初始路径下只能存在如下五个文件,确认后重新运行!", "red") + w2t("1. configs.xlsx\n2. reach33/reach66/reach100_xxxx.xlsx\n3. xxxx.zip\n", "red", "InitFileError") - config_file = reach33 = reach66 = reach100 = prj_file = None - for data_file in data_files: - filename = data_file.split('\\')[-1] - if filename == 'configs.xlsx': - config_file = data_file - elif filename.startswith('reach33_') and filename.endswith('.xlsx'): - reach33 = data_file - elif filename.startswith('reach66_') and filename.endswith('.xlsx'): - reach66 = data_file - elif filename.startswith('reach100_') and filename.endswith('.xlsx'): - reach100 = data_file - elif filename.endswith('.zip'): - prj_file = data_file - else: - w2t('初始路径下不允许有文件夹,且初始路径下只能存在如下五个文件,确认后重新运行!', 0, 0, 'red', tab_name) - w2t(' 1. configs.xlsx\n 2. reach33/reach66/reach100_xxxx.xlsx\n 3. xxxx.zip', 0, 2, 'red', tab_name) + if config_file and reach33 and reach66 and reach100 and prj_file: + result_dirs = [] + mkdir(f"{path}/j1") + mkdir(f"{path}/j2") + mkdir(f"{path}/j3") - if config_file and reach33 and reach66 and reach100 and prj_file: - result_dirs = [] - mkdir(f"{path}\\j1") - mkdir(f"{path}\\j2") - mkdir(f"{path}\\j3") - - for _reach in ['reach33', 'reach66', 'reach100']: - for _load in [f'load{loadsel.removeprefix("tool")}']: - for _speed in ['speed33', 'speed66', 'speed100']: - dir_name = '_'.join([_reach, _load, _speed]) + load = f"load{sub.removeprefix("tool")}" + for reach in ["reach33", "reach66", "reach100"]: + for speed in ["speed33", "speed66", "speed100"]: + dir_name = "_".join([reach, load, speed]) result_dirs.append(dir_name) - mkdir(f"{path}\\j1\\{dir_name}") - mkdir(f"{path}\\j2\\{dir_name}") - if _reach == 'reach100': - mkdir(f"{path}\\j3\\{dir_name}") + mkdir(f"{path}/j1/{dir_name}") + mkdir(f"{path}/j2/{dir_name}") + if reach == "reach100": + mkdir(f"{path}/j3/{dir_name}") - w2t("数据目录合规性检查结束,未发现问题......", 0, 0, 'blue', tab_name) - return config_file, reach33, reach66, reach100, prj_file, result_dirs - else: - w2t('初始路径下不允许有文件夹,且初始路径下只能存在如下五个文件,确认后重新运行!', 0, 0, 'red', tab_name) - w2t(' 1. configs.xlsx\n 2. reach33/reach66/reach100_xxxx.xlsx\n 3. xxxx.zip', 0, 1, 'red', tab_name) + w2t("数据目录合规性检查结束,未发现问题......\n", "blue") + return config_file, reach33, reach66, reach100, prj_file, result_dirs + else: + w2t("初始路径下不允许有文件夹,且初始路径下只能存在如下五个文件,确认后重新运行!", "red") + w2t("1. configs.xlsx\n2. reach33/reach66/reach100_xxxx.xlsx\n3. xxxx.zip\n", "red", "InitFileError") + + def get_configs(): + robot_type = None + msg_id, state = hr.execution("controller.get_params") + records = 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 = 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: + clibs.insert_logdb("ERROR", "current", f"get_config: 无法打开 {local_file},获取配置文件参数错误 {Err}") + w2t(f"无法打开 {local_file}", color="red", desc="OpenFileError") + + # 最大角速度,额定电流,减速比,额定转速 + version = configs["VERSION"] + avs = configs["MOTION"]["JOINT_MAX_SPEED"] + clibs.insert_logdb("INFO", "do_brake", f"get_configs: 机型文件版本 {robot_type}_{version}") + clibs.insert_logdb("INFO", "do_brake", f"get_configs: 各关节角速度 {avs}") + return avs + + config_file, reach33, reach66, reach100, prj_file, result_dirs = check_files() + avs = get_configs() + + return config_file, reach33, reach66, reach100, prj_file, result_dirs, avs -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[-240:]: # 保留最后12s的数据 - dict_results = data['data'] - for item in dict_results: - try: - item['value'].reverse() - except KeyError: - continue - if item.get('channel', None) == axis-1 and item.get('name', None) == 'hw_joint_vel_feedback': - _d2d_vel['hw_joint_vel_feedback'].extend(item['value']) - elif item.get('channel', None) == axis-1 and item.get('name', None) == 'device_servo_trq_feedback': - _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']) +@clibs.db_lock +def gen_result_file(path, axis, reach, load, speed, rounds): + d_vel, d_trq, d_stop = [], [], [] - df1 = DataFrame.from_dict(_d2d_vel) - df2 = DataFrame.from_dict(_d2d_trq) - df3 = DataFrame.from_dict(_d2d_stop) + len_records = 12 * 1000 // 50 + clibs.cursor.execute(f"select content from logs where content like 'diagnosis.result' limit {len_records}") + records = clibs.cursor.fetchall() + + for record in records: # 保留最后12s的数据 + data = eval(record)["data"] + for item in data: + if item.get("channel", None) == axis-1 and item.get("name", None) == "hw_joint_vel_feedback": + d_vel.extend(item["value"]) + elif item.get("channel", None) == axis-1 and item.get("name", None) == "device_servo_trq_feedback": + d_trq.extend(item["value"]) + elif item.get("channel", None) == 0 and item.get("name", None) == "device_safety_estop": + d_stop.extend(item["value"]) + + df1 = DataFrame.from_dict({"hw_joint_vel_feedback": d_vel}) + df2 = DataFrame.from_dict({"device_servo_trq_feedback": d_trq}) + df3 = DataFrame.from_dict({"device_safety_estop": d_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) + filename = f"{path}\\j{axis}\\reach{reach}_load{load}_speed{speed}\\reach{reach}_load{load}_speed{speed}_{rounds}.data" + df.to_csv(filename, sep="\t", index=False) -def run_rl(path, loadsel, hr, md, config_file, result_dirs, w2t): - _count = 0 - _total = 63 - display_pdo_params = [ - {"name": "hw_joint_vel_feedback", "channel": 0}, - {"name": "hw_joint_vel_feedback", "channel": 1}, - {"name": "hw_joint_vel_feedback", "channel": 2}, - {"name": "hw_joint_vel_feedback", "channel": 3}, - {"name": "hw_joint_vel_feedback", "channel": 4}, - {"name": "hw_joint_vel_feedback", "channel": 5}, - {"name": "device_servo_trq_feedback", "channel": 0}, - {"name": "device_servo_trq_feedback", "channel": 1}, - {"name": "device_servo_trq_feedback", "channel": 2}, - {"name": "device_servo_trq_feedback", "channel": 3}, - {"name": "device_servo_trq_feedback", "channel": 4}, - {"name": "device_servo_trq_feedback", "channel": 5}, - {"name": "device_safety_estop", "channel": 0}, - ] +def run_rl(path, sub, hr, md, config_file, prj_file, result_dirs, avs, w2t): + count, total = 0, 63 + prj_name = prj_file.split("/")[-1].split(".")[0] + 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}) wb = load_workbook(config_file, read_only=True) - ws = wb['Target'] - write_diagnosis = float(ws.cell(row=3, column=10).value) - get_init_speed = float(ws.cell(row=4, column=10).value) - single_brake = str(ws.cell(row=5, column=10).value) - logger.info(f"write_diagnosis = {write_diagnosis}, get_init_speed = {get_init_speed}, single_brake = {single_brake}") + ws = wb["Target"] + write_diagnosis = float(ws.cell(row=2, column=2).value) + get_init_speed = float(ws.cell(row=3, column=2).value) + single_brake = str(ws.cell(row=4, column=2).value) + pon = ws.cell(row=5, column=2).value + w2t(f"write_diagnosis = {write_diagnosis}, get_init_speed = {get_init_speed}, single_brake = {single_brake}\n") - if ws.cell(row=1, column=1).value == 'positive': + if pon == "positive": md.write_pon(1) - elif ws.cell(row=1, column=1).value == 'negative': + elif pon == "negative": md.write_pon(0) else: - w2t("configs.xlsx中Target页面A1单元格填写不正确,检查后重新运行...", 0, 111, 'red', tab_name) + w2t("configs.xlsx 中 Target 页面 B5 单元格填写不正确,检查后重新运行...", "red", "DirectionError") - 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) + hr.execution("diagnosis.open", open=True, display_open=True, overrun=True, turn_area=True, delay_motion=False) + hr.execution("diagnosis.set_params", display_pdo_params=display_pdo_params, frequency=50, version="1.4.1") for condition in result_dirs: - _reach = condition.split('_')[0].removeprefix('reach') - _load = condition.split('_')[1].removeprefix('load') - _speed = condition.split('_')[2].removeprefix('speed') + reach = condition.split("_")[0].removeprefix("reach") + load = condition.split("_")[1].removeprefix("load") + speed = condition.split("_")[2].removeprefix("speed") # for single condition test - _single_axis = 0 - if single_brake != '0': - _total = 3 - _single_axis = int(single_brake.split('-')[0]) - if _reach != single_brake.split('-')[1] or _load != single_brake.split('-')[2] or _speed != single_brake.split('-')[3]: + single_axis = 0 + if single_brake != "0": + total = 3 + single_axis = int(single_brake.split("-")[0]) + if reach != single_brake.split("-")[1] or load != single_brake.split("-")[2] or speed != single_brake.split("-")[3]: continue for axis in range(1, 4): # for single condition test - if _single_axis != 0 and _single_axis != axis: + if (single_axis != 0 and single_axis != axis) or (axis == 3 and reach != "100"): continue md.write_axis(axis) speed_max = 0 - if axis == 3 and _reach != '100': - continue - - w2t(f"-"*90, 0, 0, 'purple', tab_name) - - for count in range(1, 4): - _count += 1 + w2t(f"-"*90+"\n", "purple") + for rounds in range(1, 4): + count += 1 this_time = strftime("%Y-%m-%d %H:%M:%S", localtime(time())) - prj_path = 'target/_build/target.prj' - w2t(f"[{this_time} | {_count}/{_total}] 正在执行 {axis} 轴 {condition} 的第 {count} 次制动测试...", 0, 0, 'purple', tab_name) + prj_path = f"{prj_name}/_build/{prj_name}.prj" + w2t(f"[{this_time} | {count}/{total}] 正在执行 {axis} 轴 {condition} 的第 {count} 次制动测试...\n") - # 1. 关闭诊断曲线,触发软急停,并解除,目的是让可能正在运行着的机器停下来,切手动模式并下电 + # 1. 触发软急停,并解除,目的是让可能正在运行着的机器停下来,切手动模式并下电 md.trigger_estop() md.reset_estop() md.clear_alarm() @@ -156,80 +167,77 @@ def run_rl(path, loadsel, hr, md, config_file, result_dirs, w2t): while count == 1: # 2. 修改要执行的场景 + rl_cmd = "" ssh = SSHClient() ssh.set_missing_host_key_policy(AutoAddPolicy()) - ssh.connect(hostname=clibs.ip_addr, port=22, username='luoshi', password='luoshi2019') - if ws.cell(row=1, column=1).value == 'positive': - _rl_cmd = f"brake_E(j{axis}_{_reach}_p, j{axis}_{_reach}_n, p_speed, p_tool)" - elif ws.cell(row=1, column=1).value == 'negative': - _rl_cmd = f"brake_E(j{axis}_{_reach}_n, j{axis}_{_reach}_p, p_speed, p_tool)" - else: - w2t("configs.xlsx中Target页面A1单元格填写不正确,检查后重新运行...", 0, 111, 'red', tab_name) - _rl_speed = f"VelSet {_speed}" - _rl_tool = f"tool p_tool = tool{loadsel.removeprefix('tool')}" - cmd = 'cd /home/luoshi/bin/controller/; ' + ssh.connect(hostname=clibs.ip_addr, port=clibs.ssh_port, username=clibs.username, password=clibs.password) + if pon == "positive": + rl_cmd = f"brake_E(j{axis}_{reach}_p, j{axis}_{reach}_n, p_speed, p_tool)" + elif pon == "negative": + rl_cmd = f"brake_E(j{axis}_{reach}_n, j{axis}_{reach}_p, p_speed, p_tool)" + rl_speed = f"VelSet {speed}" + rl_tool = f"tool p_tool = tool{sub.removeprefix("tool")}" + cmd = "cd /home/luoshi/bin/controller/; " cmd += 'sudo sed -i "/brake_E/d" projects/target/_build/brake/main.mod; ' - cmd += f'sudo sed -i "/DONOTDELETE/i {_rl_cmd}" projects/target/_build/brake/main.mod; ' + cmd += f'sudo sed -i "/DONOTDELETE/i {rl_cmd}" projects/target/_build/brake/main.mod; ' cmd += 'sudo sed -i "/VelSet/d" projects/target/_build/brake/main.mod; ' - cmd += f'sudo sed -i "/MoveAbsJ/i {_rl_speed}" projects/target/_build/brake/main.mod; ' + cmd += f'sudo sed -i "/MoveAbsJ/i {rl_speed}" projects/target/_build/brake/main.mod; ' cmd += 'sudo sed -i "/tool p_tool/d" projects/target/_build/brake/main.mod; ' - cmd += f'sudo sed -i "/VelSet/i {_rl_tool}" projects/target/_build/brake/main.mod; ' + cmd += f'sudo sed -i "/VelSet/i {rl_tool}" projects/target/_build/brake/main.mod; ' stdin, stdout, stderr = ssh.exec_command(cmd, get_pty=True) - stdin.write('luoshi2019' + '\n') + stdin.write(clibs.password + "\n") stdout.read().decode() # 需要read一下才能正常执行 stderr.read().decode() # 3. reload工程后,pp2main,并且自动模式和上电,最后运行程序 - 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.set_run_params', hr, w2t, tab_name, loop_mode=True, override=1.0) - clibs.execution('rl_task.run', hr, w2t, tab_name, tasks=['brake', 'stop0_related']) - _t_start = time() + hr.execution("overview.reload", prj_path=prj_path, tasks=["brake", "stop0_related"]) + hr.execution("rl_task.pp_to_main", tasks=["brake", "stop0_related"]) + hr.execution("state.switch_auto") + hr.execution("state.switch_motor_on") + hr.execution("rl_task.set_run_params", loop_mode=True, override=1.0) + hr.execution("rl_task.run", tasks=["brake", "stop0_related"]) + t_start = time() while True: if md.read_ready_to_go() == 1: md.write_act(True) break else: - if (time() - _t_start) // 20 > 1: - w2t("20s内未收到机器人的运行信号,需要确认RL程序编写正确并正常执行...", 0, 111, 'red', tab_name) - else: - sleep(1) + sleep(1) + if (time() - t_start) // 20 > 1: + w2t("20s 内未收到机器人的运行信号,需要确认 RL 程序编写正确并正常执行...", "red", "ReadySignalTimeoutError") # 4. 找出最大速度,传递给RL程序,最后清除相关记录 - sleep(get_init_speed+5) # 冗余5s,指定时间后获取实际【正|负】方向的最大速度,可通过configs.xlsx配置 - clibs.execution('rl_task.stop', hr, w2t, tab_name, tasks=['brake']) + sleep(get_init_speed) # 指定时间后获取实际【正|负】方向的最大速度,可通过configs.xlsx配置 + clibs.execution("rl_task.stop", tasks=["brake"]) + # 找出最大速度 - _c_msg = hr.c_msg.copy() - _number = 0 - for _msg in _c_msg: - if _number > get_init_speed*20: # 最开始回零点的时候,二轴速度可以达到最大值,实际摆动时,某一方向可能达不到 - break - if 'diagnosis.result' in _msg: - _number += 1 - 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': - _ = clibs.RADIAN * sum(item['value']) / len(item['value']) - if ws.cell(row=1, column=1).value == 'positive': + @clibs.db_lock + def get_speed_max(axis, pon): + speed_max = 0 + len_records = int(get_init_speed * 20) + 1 # 1000 / 50 = 20 + clibs.cursor.execute(f"select content from logs where content like 'diagnosis.result' limit {len_records}") + records = clibs.cursor.fetchall() + for record in records: + data = eval(record)["data"] + for item in data: + if item.get("channel", None) == axis-1 and item.get("name", None) == "hw_joint_vel_feedback": + _ = clibs.RADIAN * sum(item["value"]) / len(item["value"]) + if pon == "positive": speed_max = max(_, speed_max) - elif ws.cell(row=1, column=1).value == 'negative': + elif pon == "negative": speed_max = min(_, speed_max) - logger.info(f"speed max = {speed_max}") - speed_max = abs(speed_max) - speed_target = float(ws.cell(row=3, column=axis+1).value) * float(_speed) / 100 + return speed_max + + speed_max = abs(get_speed_max(axis, pon)) + speed_target = avs[axis-1] * float(speed) / 100 + clibs.insert_logdb("INFO", "do_brake", f"axis = {axis}, direction = {pon}, max speed = {speed_max}") if speed_max < speed_target*0.95 or speed_max > speed_target*1.05: - w2t(f"Axis: {axis}-{count} | Speed: {speed_max} | Shouldbe: {speed_target}", 0, 0, 'indigo', tab_name) - + w2t(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}") md.write_speed_max(speed_max) - hr.c_msg_xs.clear() - if len(hr.c_msg) > 270: - del hr.c_msg[270:] - if speed_max < 10: md.clear_alarm() - w2t("未获取到正确的速度,即将重新获取...", 0, 0, 'red', tab_name) + w2t("未获取到正确的速度,即将重新获取...\n", "red") continue else: break @@ -238,11 +246,10 @@ def run_rl(path, loadsel, hr, md, config_file, result_dirs, w2t): md.reset_estop() # 其实没必要 md.clear_alarm() - # 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']) + hr.execution("rl_task.pp_to_main", tasks=["brake", "stop0_related"]) + hr.execution("state.switch_auto") + hr.execution("state.switch_motor_on") + hr.execution("rl_task.run", tasks=["brake", "stop0_related"]) for i in range(3): if md.read_ready_to_go() == 1: md.write_act(1) @@ -250,49 +257,48 @@ def run_rl(path, loadsel, hr, md, config_file, result_dirs, w2t): else: sleep(1) else: - w2t("未收到机器人的运行信号,需要确认RL程序编写正确并正常执行...", 0, 111, 'red', tab_name) + w2t("3s 内未收到机器人的运行信号,需要确认 RL 程序配置正确并正常执行...", "red", "ReadySignalTimeoutError") sleep(10) # 排除从其他位姿到零点位姿,再到轴极限位姿的时间 md.write_probe(1) - _t_start = time() + t_start = time() while True: if md.read_brake_done() == 1: sleep(4) # 保证速度归零 md.write_probe(0) break else: - if (time() - _t_start) > 30: - w2t(f"30s内未触发急停,该条数据无效,需要确认RL/Python程序编写正确并正常执行,或者判别是否是机器本体问题,比如正负方向速度是否一致...", 0, 0, 'red', tab_name) + sleep(1) + if (time() - t_start) > 30: md.write_probe(0) - break - else: - sleep(1) + w2t(f"30s 内未触发急停,该条数据无效,需要确认 RL/Python 程序配置正确并正常执行,或者判别是否是机器本体问题,比如正负方向速度是否一致...", "red", "NoEstopTriggeredError") # 6. 保留数据并处理输出 - curve_data = [] - _c_msg = hr.c_msg.copy() - for _msg in _c_msg: - if 'diagnosis.result' in _msg: - curve_data.insert(0, loads(_msg)) - else: - hr.c_msg_xs.clear() - if len(hr.c_msg) > 270: - del hr.c_msg[270:] - gen_result_file(path, curve_data, axis, _reach, _load, _speed, count) + gen_result_file(path, axis, reach, load, speed, rounds) else: - w2t(f"\n{loadsel.removeprefix('tool')}%负载的制动性能测试执行完毕,如需采集其他负载,须切换负载类型,并更换其他负载,重新执行。", 0, 0, 'green', tab_name) + w2t(f"\n{sub.removeprefix("tool")}%负载的制动性能测试执行完毕,如需采集其他负载,须切换负载类型,并更换其他负载,重新执行。\n", "green") + hr.execution("diagnosis.open", open=False, display_open=False, overrun=True, turn_area=True, delay_motion=False) + hr.execution("diagnosis.set_params", display_pdo_params=[], frequency=50, version="1.4.1") -def main(path, hr, md, loadsel, w2t): - _s_time = time() +def main(): + # path, hr, md, loadsel, w2t + path = clibs.data_at["_path"] + sub = clibs.data_at["_sub"] + w2t = clibs.w2t + hr = clibs.c_hr + md = clibs.c_md + insert_logdb = clibs.insert_logdb + + s_time = time() 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) - 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 - w2t(f"处理总时长:{time_total // 3600:02.0f} h {time_total % 3600 // 60:02.0f} m {time_total % 60:02.0f} s", 0, 0, 'green', tab_name) + config_file, reach33, reach66, reach100, prj_file, result_dirs, avs = initialization(path, sub, data_dirs, data_files, hr, w2t) + clibs.c_pd.push_prj_to_server(prj_file) + run_rl(path, sub, hr, md, config_file, prj_file, result_dirs, avs, w2t) + e_time = time() + time_total = e_time - s_time + w2t(f"处理总时长:{time_total // 3600:02.0f} h {time_total % 3600 // 60:02.0f} m {time_total % 60:02.0f} s", "green") -if __name__ == '__main__': - main(*argv[1:]) +if __name__ == "__main__": + main() diff --git a/code/automatic_test/do_current.py b/code/automatic_test/do_current.py index 9e01abd..f7355cd 100644 --- a/code/automatic_test/do_current.py +++ b/code/automatic_test/do_current.py @@ -1,15 +1,9 @@ -import json -from os import mkdir +import os import time -from time import sleep, time -from sys import argv -from paramiko import SSHClient, AutoAddPolicy -from json import loads -from pandas import DataFrame, concat +import paramiko +import pandas from common import clibs -display_pdo_params = [{"name": name, "channel": chl} for name in ["hw_joint_vel_feedback", "device_servo_trq_feedback", "hw_sensor_trq_feedback"] for chl in range(6)] - def initialization(path, sub, data_dirs, data_files, hr, w2t): def check_files(): @@ -34,12 +28,12 @@ def initialization(path, sub, data_dirs, data_files, hr, w2t): w2t("1. T_电机电流.xlsx\n2. xxxx.zip\n", "red", "ConfigFileError") w2t("数据目录合规性检查结束,未发现问题......\n") if sub == "tool100" or sub == "inertia": - mkdir(f"{path}/single") - mkdir(f"{path}/s_1") - mkdir(f"{path}/s_2") - mkdir(f"{path}/s_3") + os.mkdir(f"{path}/single") + os.mkdir(f"{path}/s_1") + os.mkdir(f"{path}/s_2") + os.mkdir(f"{path}/s_3") elif sub == "inertia": - mkdir(f"{path}/inertia") + os.mkdir(f"{path}/inertia") else: w2t("负载选择错误,电机电流测试只能选择 tool100/inertia 规格!\n", "red", "LoadSelectError") @@ -55,216 +49,75 @@ def initialization(path, sub, data_dirs, data_files, hr, w2t): server_file = f"/home/luoshi/bin/controller/robot_cfg/{robot_type}/{robot_type}.cfg" local_file = path + f"/{robot_type}.cfg" clibs.c_pd.pull_file_from_server(server_file, local_file) - return local_file prj_file = check_files() - config_file = get_configs() + get_configs() - return config_file, prj_file + return prj_file -def data_proc_regular(path, filename, channel, scenario_time): - if channel in list(range(6)): - with open(filename, 'r', encoding='utf-8') as f_obj: - lines = f_obj.readlines() - _d2d_vel = {'hw_joint_vel_feedback': []} - _d2d_trq = {'device_servo_trq_feedback': []} - _d2d_sensor = {'hw_sensor_trq_feedback': []} - for line in lines[-500:]: # 保留最后25s的数据 - data = eval(line.strip())['data'] - for item in data: - try: - item['value'].reverse() - except KeyError: - continue - if item.get('channel', None) == channel and item.get('name', None) == 'hw_joint_vel_feedback': - _d2d_vel['hw_joint_vel_feedback'].extend(item['value']) - elif item.get('channel', None) == channel and item.get('name', None) == 'device_servo_trq_feedback': - _d2d_trq['device_servo_trq_feedback'].extend(item['value']) - elif item.get('channel', None) == channel and item.get('name', None) == 'hw_sensor_trq_feedback': - _d2d_sensor['hw_sensor_trq_feedback'].extend(item['value']) +def single_axis_proc(path, records, number): + text = "single" if number < 6 else "hold" + number = number if number < 6 else number - 6 + d_vel, d_trq, d_sensor = [], [], [] + for record in records: + print(f"record = {record}") + data = eval(record)["data"] + for item in data: + if item.get("channel", None) == number and item.get("name", None) == "hw_joint_vel_feedback": + d_vel.extend(item["value"]) + elif item.get("channel", None) == number and item.get("name", None) == "device_servo_trq_feedback": + d_trq.extend(item["value"]) + elif item.get("channel", None) == number and item.get("name", None) == "hw_sensor_trq_feedback": + d_sensor.extend(item["value"]) - df1 = DataFrame.from_dict(_d2d_vel) - df2 = DataFrame.from_dict(_d2d_trq) - df3 = DataFrame.from_dict(_d2d_sensor) - df = concat([df1, df2, df3], 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)): - with open(filename, 'r', encoding='utf-8') as f_obj: - lines = f_obj.readlines() - _d2d_vel_0 = {'hw_joint_vel_feedback': []} - _d2d_trq_0 = {'device_servo_trq_feedback': []} - _d2d_sensor_0 = {'hw_sensor_trq_feedback': []} - _d2d_vel_1 = {'hw_joint_vel_feedback': []} - _d2d_trq_1 = {'device_servo_trq_feedback': []} - _d2d_sensor_1 = {'hw_sensor_trq_feedback': []} - _d2d_vel_2 = {'hw_joint_vel_feedback': []} - _d2d_trq_2 = {'device_servo_trq_feedback': []} - _d2d_sensor_2 = {'hw_sensor_trq_feedback': []} - _d2d_vel_3 = {'hw_joint_vel_feedback': []} - _d2d_trq_3 = {'device_servo_trq_feedback': []} - _d2d_sensor_3 = {'hw_sensor_trq_feedback': []} - _d2d_vel_4 = {'hw_joint_vel_feedback': []} - _d2d_trq_4 = {'device_servo_trq_feedback': []} - _d2d_sensor_4 = {'hw_sensor_trq_feedback': []} - _d2d_vel_5 = {'hw_joint_vel_feedback': []} - _d2d_trq_5 = {'device_servo_trq_feedback': []} - _d2d_sensor_5 = {'hw_sensor_trq_feedback': []} - for line in lines: - data = eval(line.strip())['data'] - for item in data: - try: - item['value'].reverse() - except KeyError: - continue - if item.get('channel', None) == 0 and item.get('name', None) == 'hw_joint_vel_feedback': - _d2d_vel_0['hw_joint_vel_feedback'].extend(item['value']) - elif item.get('channel', None) == 0 and item.get('name', None) == 'device_servo_trq_feedback': - _d2d_trq_0['device_servo_trq_feedback'].extend(item['value']) - elif item.get('channel', None) == 0 and item.get('name', None) == 'hw_sensor_trq_feedback': - _d2d_sensor_0['hw_sensor_trq_feedback'].extend(item['value']) - elif item.get('channel', None) == 1 and item.get('name', None) == 'hw_joint_vel_feedback': - _d2d_vel_1['hw_joint_vel_feedback'].extend(item['value']) - elif item.get('channel', None) == 1 and item.get('name', None) == 'device_servo_trq_feedback': - _d2d_trq_1['device_servo_trq_feedback'].extend(item['value']) - elif item.get('channel', None) == 1 and item.get('name', None) == 'hw_sensor_trq_feedback': - _d2d_sensor_1['hw_sensor_trq_feedback'].extend(item['value']) - elif item.get('channel', None) == 2 and item.get('name', None) == 'hw_joint_vel_feedback': - _d2d_vel_2['hw_joint_vel_feedback'].extend(item['value']) - elif item.get('channel', None) == 2 and item.get('name', None) == 'device_servo_trq_feedback': - _d2d_trq_2['device_servo_trq_feedback'].extend(item['value']) - elif item.get('channel', None) == 3 and item.get('name', None) == 'hw_sensor_trq_feedback': - _d2d_sensor_2['hw_sensor_trq_feedback'].extend(item['value']) - elif item.get('channel', None) == 3 and item.get('name', None) == 'hw_joint_vel_feedback': - _d2d_vel_3['hw_joint_vel_feedback'].extend(item['value']) - elif item.get('channel', None) == 3 and item.get('name', None) == 'device_servo_trq_feedback': - _d2d_trq_3['device_servo_trq_feedback'].extend(item['value']) - elif item.get('channel', None) == 3 and item.get('name', None) == 'hw_sensor_trq_feedback': - _d2d_sensor_3['hw_sensor_trq_feedback'].extend(item['value']) - elif item.get('channel', None) == 4 and item.get('name', None) == 'hw_joint_vel_feedback': - _d2d_vel_4['hw_joint_vel_feedback'].extend(item['value']) - elif item.get('channel', None) == 4 and item.get('name', None) == 'device_servo_trq_feedback': - _d2d_trq_4['device_servo_trq_feedback'].extend(item['value']) - elif item.get('channel', None) == 4 and item.get('name', None) == 'hw_sensor_trq_feedback': - _d2d_sensor_4['hw_sensor_trq_feedback'].extend(item['value']) - elif item.get('channel', None) == 5 and item.get('name', None) == 'hw_joint_vel_feedback': - _d2d_vel_5['hw_joint_vel_feedback'].extend(item['value']) - 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']) - elif item.get('channel', None) == 5 and item.get('name', None) == 'hw_sensor_trq_feedback': - _d2d_sensor_5['hw_sensor_trq_feedback'].extend(item['value']) - - df_01 = DataFrame.from_dict(_d2d_vel_0) - df_02 = DataFrame.from_dict(_d2d_trq_0) - df_03 = DataFrame.from_dict(_d2d_sensor_0) - df = concat([df_01, df_02, df_03], 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 = DataFrame.from_dict(_d2d_vel_1) - df_02 = DataFrame.from_dict(_d2d_trq_1) - df_03 = DataFrame.from_dict(_d2d_sensor_1) - df = concat([df_01, df_02, df_03], 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 = DataFrame.from_dict(_d2d_vel_2) - df_02 = DataFrame.from_dict(_d2d_trq_2) - df_03 = DataFrame.from_dict(_d2d_sensor_2) - df = concat([df_01, df_02, df_03], 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 = DataFrame.from_dict(_d2d_vel_3) - df_02 = DataFrame.from_dict(_d2d_trq_3) - df_03 = DataFrame.from_dict(_d2d_sensor_3) - df = concat([df_01, df_02, df_03], 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 = DataFrame.from_dict(_d2d_vel_4) - df_02 = DataFrame.from_dict(_d2d_trq_4) - df_03 = DataFrame.from_dict(_d2d_sensor_4) - df = concat([df_01, df_02, df_03], 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 = DataFrame.from_dict(_d2d_vel_5) - df_02 = DataFrame.from_dict(_d2d_trq_5) - df_03 = DataFrame.from_dict(_d2d_sensor_5) - df = concat([df_01, df_02, df_03], 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)): - with open(filename, 'r', encoding='utf-8') as f_obj: - lines = f_obj.readlines() - _d2d_vel = {'hw_joint_vel_feedback': []} - _d2d_trq = {'device_servo_trq_feedback': []} - _d2d_sensor = {'hw_sensor_trq_feedback': []} - for line in lines[-300:]: # 保留最后15s的数据 - data = eval(line.strip())['data'] - for item in data: - try: - item['value'].reverse() - except KeyError: - continue - if item.get('channel', None) == channel-9 and item.get('name', None) == 'hw_joint_vel_feedback': - _d2d_vel['hw_joint_vel_feedback'].extend(item['value']) - 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']) - elif item.get('channel', None) == channel-9 and item.get('name', None) == 'hw_sensor_trq_feedback': - _d2d_sensor['hw_sensor_trq_feedback'].extend(item['value']) - - df1 = DataFrame.from_dict(_d2d_vel) - df2 = DataFrame.from_dict(_d2d_trq) - df3 = DataFrame.from_dict(_d2d_sensor) - df = concat([df1, df2, df3], axis=1) - _filename = f'{path}\\single\\j{channel-8}_hold_{time()}.data' - df.to_csv(_filename, sep='\t', index=False) + df1 = pandas.DataFrame.from_dict({"hw_joint_vel_feedback": d_vel}) + df2 = pandas.DataFrame.from_dict({"device_servo_trq_feedback": d_trq}) + df3 = pandas.DataFrame.from_dict({"hw_sensor_trq_feedback": d_sensor}) + df = pandas.concat([df1, df2, df3], axis=1) + filename = f"{path}/single/j{number + 1}_{text}_{time.time()}.data" + df.to_csv(filename, sep="\t", index=False) -def data_proc_inertia(path, filename, channel): - with open(filename, 'r', encoding='utf-8') as f_obj: - lines = f_obj.readlines() - _d2d_vel = {'hw_joint_vel_feedback': []} - _d2d_trq = {'device_servo_trq_feedback': []} - _d2d_sensor = {'hw_sensor_trq_feedback': []} - for line in lines: - data = eval(line.strip())['data'] +def scenario_proc(path, records, number, scenario_time): + d_vel, d_trq, d_sensor = [], [], [] + for record in records: + print(f"record = {record}") + data = eval(record)["data"] + for axis in range(6): for item in data: - try: - item['value'].reverse() - except KeyError: - continue - if item.get('channel', None) == channel+3 and item.get('name', None) == 'hw_joint_vel_feedback': - _d2d_vel['hw_joint_vel_feedback'].extend(item['value']) - 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']) - elif item.get('channel', None) == channel+3 and item.get('name', None) == 'hw_sensor_trq_feedback': - _d2d_trq['hw_sensor_trq_feedback'].extend(item['value']) + if item.get("channel", None) == axis and item.get("name", None) == "hw_joint_vel_feedback": + d_vel.extend(item["value"]) + elif item.get("channel", None) == axis and item.get("name", None) == "device_servo_trq_feedback": + d_trq.extend(item["value"]) + elif item.get("channel", None) == axis and item.get("name", None) == "hw_sensor_trq_feedback": + d_sensor.extend(item["value"]) - df1 = DataFrame.from_dict(_d2d_vel) - df2 = DataFrame.from_dict(_d2d_trq) - df3 = DataFrame.from_dict(_d2d_sensor) - df = concat([df1, df2, df3], axis=1) - _filename = f'{path}\\inertia\\j{channel+4}_inertia_{time()}.data' - df.to_csv(_filename, sep='\t', index=False) + df1 = pandas.DataFrame.from_dict({"hw_joint_vel_feedback": d_vel}) + df2 = pandas.DataFrame.from_dict({"device_servo_trq_feedback": d_trq}) + df3 = pandas.DataFrame.from_dict({"hw_sensor_trq_feedback": d_sensor}) + df = pandas.concat([df1, df2, df3], axis=1) + filename = f"{path}/s_{number-11}/j{axis}_s_{number-11}_{scenario_time}_{time.time()}.data" + df.to_csv(filename, sep="\t", index=False) -def gen_result_file(path, loadsel, disc, number, scenario_time): - filename = path + f'\\data.txt' - with open(filename, 'w', encoding='utf-8') as f_obj: - for line in disc[number][1]: - f_obj.write(str(line)+'\n') - - if loadsel == 'tool100': - data_proc_regular(path, filename, number, scenario_time) - elif loadsel == 'inertia': - data_proc_inertia(path, filename, number) +@clibs.db_lock +def gen_result_file(path, number, scenario_time): + if number < 12: # 35s/15s == 700/300 + len_records = 700 if number < 6 else 300 + clibs.cursor.execute(f"select content from logs where content like 'diagnosis.result' limit {len_records}") + records = clibs.cursor.fetchall() + single_axis_proc(path, records, number) + elif number < 15: # scenario time + len_records = int(scenario_time * 20) + 1 + clibs.cursor.execute(f"select content from logs where content like 'diagnosis.result' limit {len_records}") + records = clibs.cursor.fetchall() + scenario_proc(path, records, number, scenario_time) -def run_rl(path, hr, md, sub, w2t): +def run_rl(path, prj_file, hr, md, sub, w2t): + prj_name = prj_file.split("/")[-1].split(".")[0] + display_pdo_params = [{"name": name, "channel": chl} for name in ["hw_joint_vel_feedback", "device_servo_trq_feedback", "hw_sensor_trq_feedback"] for chl in range(6)] c_regular = [ "scenario(0, j1_p, j1_n, p_speed, p_tool, i_tool)", "scenario(0, j2_p, j2_n, p_speed, p_tool, i_tool)", @@ -272,118 +125,104 @@ def run_rl(path, hr, md, sub, w2t): "scenario(0, j4_p, j4_n, p_speed, p_tool, i_tool)", "scenario(0, j5_p, j5_n, p_speed, p_tool, i_tool)", "scenario(0, j6_p, j6_n, p_speed, p_tool, i_tool)", - "scenario(1, j6_p, j6_n, p_speed, p_tool, i_tool)", - "scenario(2, j6_p, j6_n, p_speed, p_tool, i_tool)", - "scenario(3, j6_p, j6_n, p_speed, p_tool, i_tool)", "scenario(4, j1_hold, j1_hold, p_speed, p_tool, i_tool)", "scenario(4, j2_hold, j2_hold, p_speed, p_tool, i_tool)", "scenario(4, j3_hold, j3_hold, p_speed, p_tool, i_tool)", "scenario(4, j4_hold, j4_hold, p_speed, p_tool, i_tool)", "scenario(4, j5_hold, j5_hold, p_speed, p_tool, i_tool)", "scenario(4, j6_hold, j6_hold, p_speed, p_tool, i_tool)", + "scenario(1, j6_p, j6_n, p_speed, p_tool, i_tool)", + "scenario(2, j6_p, j6_n, p_speed, p_tool, i_tool)", + "scenario(3, j6_p, j6_n, p_speed, p_tool, i_tool)", ] c_inertia = [ "scenario(5, j4_p_inertia, j4_n_inertia, p_speed, p_tool, i_tool)", "scenario(5, j5_p_inertia, j5_n_inertia, p_speed, p_tool, i_tool)", "scenario(5, j6_p_inertia, j6_n_inertia, p_speed, p_tool, i_tool)", ] - disc_regular = { - 0: ['一轴', []], 1: ['二轴', []], 2: ['三轴', []], 3: ['四轴', []], 4: ['五轴', []], 5: ['六轴', []], - 6: ['场景一', []], 7: ['场景二', []], 8: ['场景三', []], 9: ['一轴保持', []], 10: ['二轴保持', []], - 11: ['三轴保持', []], 12: ['四轴保持', []], 13: ['五轴保持', []], 14: ['六轴保持', []] - } - disc_inertia = {0: ['四轴惯量', []], 1: ['五轴惯量', []], 2: ['六轴惯量', []]} - if sub == 'tool100': - conditions = c_regular - disc = disc_regular - elif sub == 'inertia': - conditions = c_inertia - disc = disc_inertia + disc_regular = ["一轴", "二轴", "三轴", "四轴", "五轴", "六轴", "一轴保持", "二轴保持", "三轴保持", "四轴保持", "五轴保持", "六轴保持", "场景一", "场景二", "场景三"] + disc_inertia = ["四轴惯量", "五轴惯量", "六轴惯量"] + conditions, disc = [], [] + if sub == "tool100": + conditions, disc = c_regular, disc_regular + elif sub == "inertia": + conditions, disc = c_inertia, disc_inertia - # preparation 触发软急停,并解除,目的是让可能正在运行着的机器停下来 - hr.execution('diagnosis.open', hr, w2t, tab_name, open=True, display_open=True) - hr.execution('diagnosis.set_params', hr, w2t, tab_name, display_pdo_params=display_pdo_params) - # clibs.execution('diagnosis.save', hr, w2t, tab_name, save=True) # 这条命令有问题 + # 打开诊断曲线,触发软急停,并解除,目的是让可能正在运行着的机器停下来 + hr.execution("diagnosis.open", open=True, display_open=True, overrun=True, turn_area=True, delay_motion=False) + hr.execution("diagnosis.set_params", display_pdo_params=display_pdo_params, frequency=50, version="1.4.1") md.trigger_estop() md.reset_estop() for condition in conditions: number = conditions.index(condition) - w2t(f"正在执行{disc[number][0]}测试......", 0, 0, 'purple', tab_name) + w2t(f"正在执行{disc[number]}测试......\n") - # 1. 将act重置为False,并修改未要执行的场景 + # 1. 将act重置为False,并修改将要执行的场景 md.write_act(False) - ssh = SSHClient() - ssh.set_missing_host_key_policy(AutoAddPolicy()) - 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' + ssh = paramiko.SSHClient() + ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) + ssh.connect(clibs.ip_addr, clibs.ssh_port, username=clibs.username, password=clibs.password) + cmd = "cd /home/luoshi/bin/controller/; " + cmd += f'sudo sed -i "/scenario/d" projects/{prj_name}/_build/current/main.mod; ' + cmd += f'sudo sed -i "/DONOTDELETE/i {condition}" projects/{prj_name}/_build/current/main.mod' stdin, stdout, stderr = ssh.exec_command(cmd, get_pty=True) - stdin.write('luoshi2019' + '\n') + stdin.write(clibs.password + "\n") stdout.read().decode() # 需要read一下才能正常执行 stderr.read().decode() # 2. reload工程后,pp2main,并且自动模式和上电 - prj_path = 'target/_build/target.prj' - 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) + prj_path = f"{prj_name}/_build/{prj_name}.prj" + hr.execution("overview.reload", prj_path=prj_path, tasks=["current"]) + hr.execution("rl_task.pp_to_main", tasks=["current"]) + hr.execution("state.switch_auto") + hr.execution("state.switch_motor_on") # 3. 开始运行程序,单轴运行35s - clibs.execution('rl_task.set_run_params', hr, w2t, tab_name, loop_mode=True, override=1.0) - clibs.execution('rl_task.run', hr, w2t, tab_name, tasks=['current']) - _t_start = time() + hr.execution("rl_task.set_run_params", loop_mode=True, override=1.0) + hr.execution("rl_task.run", tasks=["current"]) + t_start = time.time() while True: if md.read_ready_to_go() == 1: md.write_act(True) break else: - if (time() - _t_start) // 20 > 1: - w2t("20s内未收到机器人的运行信号,需要确认RL程序编写正确并正常执行...", 0, 111, 'red', tab_name) - else: - sleep(1) + time.sleep(1) + if (time.time() - t_start) // 20 > 1: + w2t("20s 内未收到机器人的运行信号,需要确认RL程序编写正确并正常执行...", "red", "ReadySignalTimeoutError") # 4. 打开诊断曲线,并执行采集 - sleep(10) # 保证程序已经运行起来,其实主要是为了保持电流的采集而设定 + time.sleep(10) # 保证程序已经运行起来,其实主要是为了保持电流的采集而设定 scenario_time = 0 - if number < 6: - sleep(35) - elif number > 8: - sleep(15) - else: - _t_start = time() + if number < 6: # 单轴 + time.sleep(35) + elif number < 12: # 堵转 + time.sleep(15) + else: # 场景 + t_start = time.time() while True: scenario_time = md.read_scenario_time() if float(scenario_time) > 1: - w2t(f"场景{number-5}的周期时间:{scenario_time}", 0, 0, 'green', tab_name) + w2t(f"场景{number-5}的周期时间:{scenario_time}\n") break else: - if (time()-_t_start)//60 > 3: - w2t(f"未收到场景{number-5}的周期时间,需要确认RL程序编写正确并正常执行...", 0, 111, 'red', tab_name) - else: - sleep(5) - sleep(1) # 一定要延迟一秒再读一次scenario time寄存器,因为一开始读取的数值不准确 + time.sleep(5) + if (time.time()-t_start)//60 > 3: + w2t(f"未收到场景{number-5}的周期时间,需要确认RL程序编写正确并正常执行...\n", "red", "GetScenarioTimeError") + time.sleep(1) # 一定要延迟一秒再读一次scenario time寄存器,因为一开始读取的数值不准确 scenario_time = md.read_scenario_time() - sleep(float(scenario_time)*0.2) # 再运行周期的20%即可 + time.sleep(float(scenario_time)*0.2) # 再运行周期的20%即可 # 5.停止程序运行,保留数据并处理输出 - 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) > 270: - del hr.c_msg[270:] - gen_result_file(path, loadsel, disc, number, scenario_time) + clibs.execution("rl_task.stop", tasks=["current"]) + gen_result_file(path, number, scenario_time) else: - if loadsel == 'tool100': - w2t("单轴和场景电机电流采集完毕,如需采集惯量负载,须切换负载类型,并更换惯量负载,重新执行。", 0, 0, 'green', tab_name) - elif loadsel == 'inertia': - w2t("惯量负载电机电流采集完毕,如需采集单轴/场景/保持电机电流,须切换负载类型,并更换偏置负载,重新执行。", 0, 0, 'green', tab_name) + if sub == "tool100": + w2t("单轴和场景电机电流采集完毕,如需采集惯量负载,须切换负载类型,并更换惯量负载,重新执行。\n", "green") + elif sub == "inertia": + w2t("惯量负载电机电流采集完毕,如需采集单轴/场景/保持电机电流,须切换负载类型,并更换偏置负载,重新执行。\n", "green") + hr.execution("diagnosis.open", open=False, display_open=False, overrun=True, turn_area=True, delay_motion=False) + hr.execution("diagnosis.set_params", display_pdo_params=[], frequency=50, version="1.4.1") def main(): @@ -395,11 +234,10 @@ def main(): insert_logdb = clibs.insert_logdb data_dirs, data_files = clibs.traversal_files(path, w2t) - config_file, prj_file = initialization(path, sub, data_dirs, data_files, hr, w2t) + prj_file = initialization(path, sub, data_dirs, data_files, hr, w2t) clibs.c_pd.push_prj_to_server(prj_file) - clibs.c_hr.execution("diagnosis.open", open=False, display_open=False, overrun=True, turn_area=True, delay_motion=False) - # run_rl(path, hr, md, sub, w2t) + run_rl(path, prj_file, hr, md, sub, w2t) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/code/common/openapi.py b/code/common/openapi.py index 55a64c0..a1e1a65 100644 --- a/code/common/openapi.py +++ b/code/common/openapi.py @@ -11,8 +11,8 @@ import time from common import clibs from os import listdir -# from pymodbus.payload import BinaryPayloadDecoder, BinaryPayloadBuilder -# from pymodbus.constants import Endian +from pymodbus.payload import BinaryPayloadDecoder, BinaryPayloadBuilder +from pymodbus.constants import Endian import os.path from ctypes import * import hashlib @@ -148,6 +148,32 @@ class ModbusRequest(object): clibs.insert_logdb("INFO", "openapi", f"modbus: 40018-{action} 执行{actions}安全区 safe region 03") time.sleep(clibs.interval) + def write_act(self, number): + self.__c.write_register(40100, number) + clibs.insert_logdb("INFO", "openapi", f"modbus: 40100 将 {number} 写入") + + def write_probe(self, probe): + self.__c.write_register(40101, probe) + clibs.insert_logdb("INFO", "openapi", f"modbus: 40101 将 {probe} 写入") + + def write_pon(self, pon): + self.__c.write_register(40101, pon) + clibs.insert_logdb("INFO", "openapi", f"modbus: 40102 将 {pon} 写入") + + def write_axis(self, axis): + builder = BinaryPayloadBuilder(byteorder=Endian.BIG, wordorder=Endian.LITTLE) + builder.add_32bit_int(int(axis)) + payload = builder.to_registers() + self.__c.write_registers(40103, payload) + clibs.insert_logdb("INFO", "openapi", f"modbus: 40103 将 {axis} 写入") + + def write_speed_max(self, speed): + builder = BinaryPayloadBuilder(byteorder=Endian.BIG, wordorder=Endian.LITTLE) + builder.add_32bit_float(float(speed)) + payload = builder.build() + self.__c.write_registers(40105, payload, skip_encode=True) + clibs.insert_logdb("INFO", "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) @@ -287,6 +313,20 @@ class ModbusRequest(object): clibs.insert_logdb("INFO", "openapi", f"modbus: 执行读取所有 DO 的结果为 {res}") return res + def read_ready_to_go(self): + result = self.__c.read_holding_registers(40600, count=1) + return result.registers[0] + + def read_scenario_time(self): + results = self.__c.read_holding_registers(41002, count=2) + result = BinaryPayloadDecoder.fromRegisters(results.registers, byteorder=Endian.BIG, wordorder=Endian.LITTLE) + result = f"{result.decode_32bit_float():.3f}" + return result + + def read_brake_done(self): + result = self.__c.read_holding_registers(41007, count=1) + return result.registers[0] + class HmiRequest(object): socket.setdefaulttimeout(clibs.interval * 6) diff --git a/code/data_process/current.py b/code/data_process/current.py index 95679bb..bb424f9 100644 --- a/code/data_process/current.py +++ b/code/data_process/current.py @@ -177,16 +177,12 @@ def find_point(data_file, df, flag, row_s, row_e, threshold, step, end_point, sk row_s -= step continue else: - # one more time,如果连续两次 200 个点的平均值都大于 2,说明已经到了临界点了(其实也不一定,只不过相对遇到一次就判定临界点更安全一点点) + # one more time,如果连续两次 200 个点的平均值都大于 threshold,说明已经到了临界点了(其实也不一定,只不过相对遇到一次就判定临界点更安全一点点) # 从实际数据看,这开逻辑很小概率能触发到 speed_avg = df.iloc[row_s-end_point*skip_scale:row_e-end_point*skip_scale].abs().mean() if speed_avg < threshold: - insert_logdb("WARNING", "current", f"【lt】{axis} 轴第 {seq} 次查找数据有异常,row_s = {row_s}, row_e = {row_e}!") - row_e -= end_point*skip_scale - row_s -= end_point*skip_scale - continue - else: - return row_s, row_e + insert_logdb("WARNING", "current", f"【lt】{axis} 轴第 {seq} 次查找数据可能有异常,row_s = {row_s}, row_e = {row_e}!") + return row_s, row_e else: w2t(f"{data_file} 数据有误,需要检查,无法找到第 {seq} 个有效点...", "red", "AnchorNotFound") elif flag == "gt": @@ -199,16 +195,12 @@ def find_point(data_file, df, flag, row_s, row_e, threshold, step, end_point, sk row_s -= step continue else: - # one more time,如果连续两次 200 个点的平均值都小于 2,说明已经到了临界点了(其实也不一定,只不过相对遇到一次就判定临界点更安全一点点) + # one more time,如果连续两次 200 个点的平均值都小于 threshold,说明已经到了临界点了(其实也不一定,只不过相对遇到一次就判定临界点更安全一点点) # 从实际数据看,这开逻辑很小概率能触发到 speed_avg = df.iloc[row_s-end_point*skip_scale:row_e-end_point*skip_scale].abs().mean() if speed_avg > threshold: - insert_logdb("WARNING", "current", f"【gt】{axis} 轴第 {seq} 次查找数据有异常,row_s = {row_s}, row_e = {row_e}!") - row_e -= end_point*skip_scale - row_s -= end_point*skip_scale - continue - else: - return row_s, row_e + insert_logdb("WARNING", "current", f"【gt】{axis} 轴第 {seq} 次查找数据可能有异常,row_s = {row_s}, row_e = {row_e}!") + return row_s, row_e else: w2t(f"{data_file} 数据有误,需要检查,无法找到第 {seq} 个有效点...", "red", "AnchorNotFound") @@ -257,7 +249,7 @@ def p_single(wb, single, vel, trq, sensor, rrs, w2t, insert_logdb): step = 50 # 步进值 end_point = 200 # 有效数值的数目 - threshold = 2 # 200个点的平均阈值线 + threshold = 5 # 200个点的平均阈值线 skip_scale = 2 row_start, row_middle, row_end = 0, 0, 0 row_e = df.index[-1] @@ -265,15 +257,15 @@ def p_single(wb, single, vel, trq, sensor, rrs, w2t, insert_logdb): speed_avg = df.iloc[row_s:row_e].abs().mean() if speed_avg < 2: # 第一次过滤:消除速度为零的数据,找到速度即将大于零的上升临界点 - row_s, row_e = find_point(data_file, df, "lt", row_s, row_e, threshold, step, end_point, skip_scale, axis, 0, w2t, insert_logdb) + row_s, row_e = find_point(data_file, df, "lt", row_s, row_e, threshold, step, end_point, skip_scale, axis, "pre-1", w2t, insert_logdb) row_e -= end_point*skip_scale row_s -= end_point*skip_scale # 第二次过滤:消除速度大于零的数据,找到速度即将趋近于零的下降临界点 - row_s, row_e = find_point(data_file, df, "gt", row_s, row_e, threshold, step, end_point, skip_scale, axis, 0, w2t, insert_logdb) + row_s, row_e = find_point(data_file, df, "gt", row_s, row_e, threshold, step, end_point, skip_scale, axis, "pre-2", w2t, insert_logdb) row_e -= end_point*skip_scale row_s -= end_point*skip_scale # 第三次过滤:消除速度为零的数据,找到速度即将大于零的上升临界点 - row_s, row_e = find_point(data_file, df, "lt", row_s, row_e, threshold, step, end_point, skip_scale, axis, 0, w2t, insert_logdb) + row_s, row_e = find_point(data_file, df, "lt", row_s, row_e, threshold, step, end_point, skip_scale, axis, "pre-3", w2t, insert_logdb) row_e -= end_point*skip_scale row_s -= end_point*skip_scale # 正式第一次采集:消除速度大于零的数据,找到速度即将趋近于零的下降临界点 @@ -291,11 +283,11 @@ def p_single(wb, single, vel, trq, sensor, rrs, w2t, insert_logdb): row_start = get_row_number(threshold, "start", df, row_s, row_e, axis, insert_logdb) elif speed_avg > 2: # 第一次过滤:消除速度大于零的数据,找到速度即将趋近于零的下降临界点 - row_s, row_e = find_point(data_file, df, "gt", row_s, row_e, threshold, step, end_point, skip_scale, axis, 0, w2t, insert_logdb) + row_s, row_e = find_point(data_file, df, "gt", row_s, row_e, threshold, step, end_point, skip_scale, axis, "pre-1", w2t, insert_logdb) row_e -= end_point*skip_scale row_s -= end_point*skip_scale # 第二次过滤:消除速度为零的数据,找到速度即将大于零的上升临界点 - row_s, row_e = find_point(data_file, df, "lt", row_s, row_e, threshold, step, end_point, skip_scale, axis, 0, w2t, insert_logdb) + row_s, row_e = find_point(data_file, df, "lt", row_s, row_e, threshold, step, end_point, skip_scale, axis, "pre-2", w2t, insert_logdb) row_e -= end_point*skip_scale row_s -= end_point*skip_scale # 第一次正式采集:消除速度大于零的数据,找到速度即将趋近于零的下降临界点