24 Commits

Author SHA1 Message Date
340d48876b 10. [APIs: all]: 添加了 logger.setLevel(INFO),只有添加这个,单个模块内才生效 2024-08-01 19:15:08 +08:00
60726d9d07 7. [APIs: btn_functions.py]: 重写了告警输出函数,从日志中拿数据
8. [APIs: aio.py]: 将日志框输出的内容,也保存至日志文件
9. [APIs: do_brake.py]
   - 修改获取初始速度的逻辑,只获取configs文件中配置的时间内的速度
   - 新增 configs 参数 single_brake,可针对特定条件做测试
2024-08-01 17:11:12 +08:00
e713485d00 fix merge 2024-07-31 16:14:41 +08:00
25fc43be81 优化 ssh 输入密码的部分
create_plot 函数中增加 close('all'),解决循环画图不销毁占用内存的问题
2024-07-31 11:21:24 +08:00
924fad09e0 fix version again... 2024-07-31 08:28:39 +08:00
04bd1238d2 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 输出,后续持续优化
2024-07-31 08:05:36 +08:00
a7984a613d v0.2.0.4(2024/07/30)
1. [APIs: do_brake.py]: 修复制动数据处理过程中,只取曲线的最后 240 个数据
2. [APIs: aio.py]: 判定版本处,删除 self.destroy(),因为该语句会导致异常发生
2024-07-30 12:30:37 +08:00
af68f19d53 vers info 2024-07-27 21:32:02 +08:00
b01f8dc19c v0.2.0.3(2024/07/27)
1. [APIs: do_brake.py]: 精简程序,解决 OOM 问题
2. [APIs: do_current.py]: 精简程序,解决 OOM 问题
3. [APIs: factory_test.py]: 精简程序,解决 OOM 问题
4. [APIsL openapi.py]
   - 心跳修改为 1 s,因为 OOM 问题的解决依赖于长久的打开曲线开关,此时对于 hr.c_msg 的定时清理是个挑战,将心跳缩短,有利于清理日志后,避免丢失心跳
   - 新增 diagnosis.save 命令,但是执行时,有问题,待解决
2024-07-27 21:31:09 +08:00
d2794b2de7 remove sys module 2024-07-26 13:38:39 +08:00
0d814d384d fix version and will exit if not the latest one 2024-07-26 13:33:19 +08:00
82ae2681bb v0.2.0.2(2024/07/26)
1. [main: current.py]
   - 修正堵转电流无法正确写入结果文件的问题
2. [main: do_brake.py]
   - 初始速度采集等待时间设置为可通过configs.xlsx配置文件调整的
   - 初次速度采集停止逻辑修改为tasks.stop指令(未验证)
   - 急停信号触发前,pending时间设置为固定值10s
   - 实现正负方向速度采集逻辑
   - 工程名变更逻辑实现修改为通配符,方便后续根据机型保存文件
   - 增加超差后写诊断的逻辑,并可以通过configs.xlsx配置文件调整
   - 程序输出中增加时间戳,方便调试定位日志时间
3. [main: do_current.py]
   - 工程名变更逻辑实现修改为通配符,方便后续根据机型保存文件
4. 为工程文件添加更详细的注释
5. 补充了do_current/do_brake的流程图
6. [main: openapi.py]
   - ½«modbus motor_on/offµÄµÏ·½·¨¸Äª¸ߵç³崥·¢
7. configs.xlsx配置表新增write_diagnosis/get_init_speed两个参数
2024-07-26 13:24:44 +08:00
8b49d3b6e4 将count恢复为全局标量 2024-07-19 17:19:19 +08:00
2f782c9693 another try 2024-07-19 16:32:31 +08:00
73230a7133 remove durable folder 2024-07-19 11:21:27 +08:00
97cb4fe1d4 minor modification 2024-07-19 11:13:51 +08:00
bdccf3da47 新增保留历史数据功能,修改x轴坐标刻度显示 2024-07-19 11:09:34 +08:00
370fa051ae change axis x to time 2024-07-18 17:45:40 +08:00
e1866758b7 change x-axis content 2024-07-18 16:50:50 +08:00
1cefe4a16b minor modifications 2024-07-18 14:59:20 +08:00
dd0873637f minor fix 2024-07-18 11:04:31 +08:00
5ab03d23f2 aio.py 将canvas设定到tabview下,并将高度减小到600,将曲线选择的OP设定为不可伸缩 2024-07-17 17:31:32 +08:00
9088b90e34 fix OverflowError: (34, "Result too large") problem 2024-07-17 16:29:10 +08:00
9d252cc36f add projects for different conditions 2024-07-17 14:40:25 +08:00
30 changed files with 5629 additions and 1331 deletions

5
.gitignore vendored
View File

@ -7,5 +7,8 @@ aio/venv
aio/__pycache__/ aio/__pycache__/
aio/code/automatic_test/__pycache__/ aio/code/automatic_test/__pycache__/
aio/code/data_process/__pycache__/ aio/code/data_process/__pycache__/
aio/assets/templates/c_msg.log aio/assets/templates/c_msg.log*
aio/code/durable_action/__pycache__/ aio/code/durable_action/__pycache__/
aio/assets/templates/durable/
aio/assets/templates/.__c_msg.lock
aio/code/commons/__pycache__/

View File

@ -8,6 +8,7 @@
4. wavelogger 波形处理,几乎不花费时间 4. wavelogger 波形处理,几乎不花费时间
5. 制动自动化测试 5. 制动自动化测试
6. 电机电流自动化测试 6. 电机电流自动化测试
7. 耐久工程曲线指标采集(仅适用于六轴)
--- ---
@ -30,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 --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
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
``` ```
--- ---
@ -132,16 +134,18 @@ pyinstaller --noconfirm --onedir --windowed --add-data "C:/Users/Administrator/A
> **需要注意的点** > **需要注意的点**
1. 【重要】使用之前需要手动修改!!负载信息!!点位信息!!,确保所有点位不会发生撞击,确保所有程序正常运行之后,导出工程,再进行自动化测试 1. 修改该文件点位信息
2. 工程文件不能手动重命名需要重命名存档可以导入HMI然后另存为 2. 修改“编程”→“工具列表”中的工具信息制动只允许使用tool33/tool66/tool100/inertia这四个工具不可重命名
3. 务必正确填写configs.xlsx中的Target页面A1单元格可以选择正负方向急停但不完全保证100%大概有95%左右的准确度 3. 除了调试行,其他行请勿修改,包括增加空行等,尤其是有特别注释的地方
4. 由于xCore系统问题运行过程中可能会出现机器人宕机问题如果遇到可以手动重启控制柜重新运行 4. stop0_related半静态任务需要注意DO0_0的命名不同控制柜可能不一样
5. 运行过程中,如果是因为机器问题无法达到额定百分比速度,会在日志输出框提示,注意观察 5. 需要导入 autotest.xml 寄存器文件以及新建modbus总线设备命名为autotest其他默认即可
6. 运行自动化程序之前,确保机器处于正常状态,无故障,未触发急停 6. 其他无需修改如有其他需求可联系fanmingfu@rokae.com沟通
7. 需要额外硬件接线详细参考configs.xlsx中急停接线图sheet页 7. 需要额外硬件接线详细参考configs.xlsx中急停接线图sheet页其中DO0_0视硬件情况可能为其他名称
8. 注意观察二轴100%臂展时,是否可以获取到正确的数据 8. 运行自动化程序之前,确保机器处于正常状态,无故障,未触发急停
9. 将autotest.xml导入到寄存器并新建一个modbus命名为autotest 9. 运行过程中,如果是因为机器问题无法达到额定百分比速度,会在日志输出框提示,注意观察
10. 针对五轴机型六轴数据可以填写1-5轴任意一轴的点位信息 10. 由于xCore系统问题运行过程中可能会出现机器人宕机问题如果遇到可以手动重启控制柜重新运行
11. 务必正确填写configs.xlsx中的Target页面A1单元格可以选择正负方向急停
12. 工程文件可以手动重命名,按照机型存档,或者导出用于自动化测试
#### 6) 电机电流自动化测试 #### 6) 电机电流自动化测试
@ -152,7 +156,16 @@ pyinstaller --noconfirm --onedir --windowed --add-data "C:/Users/Administrator/A
> **需要注意的点** > **需要注意的点**
基本同第五点 基本同第五点,针对五轴以及以下的机型,缺失轴数据可以填写其他有效轴任意一轴的点位信息
#### 7) 耐久工程曲线指标采集
可实现固定周期指定曲线指标的采集,用于长时间观察指标的变化情况,输入文件:
- configs.xlsx执行之前需要手动修改好configs.xlsx中的参数以及间隔时间
- target.zip需要确认工程点位和动作无问题后保存导出
> 重新运行时,必须突出软件,重新运行
#### 其他 #### 其他
customtkinter的tabview组件不支持修改字体大小可以参考 [Changing Font of a Tabview](https://github.com/TomSchimansky/CustomTkinter/issues/2296) 进行手动修改源码实现: customtkinter的tabview组件不支持修改字体大小可以参考 [Changing Font of a Tabview](https://github.com/TomSchimansky/CustomTkinter/issues/2296) 进行手动修改源码实现:
@ -511,3 +524,75 @@ v0.2.0.0(2024/07/17)
- HmiRequest模块日志取消记录move.monitor相关 - HmiRequest模块日志取消记录move.monitor相关
- HmiRequest模块增加了durable_lock变量控制文件读写互斥 - HmiRequest模块增加了durable_lock变量控制文件读写互斥
v0.2.0.1(2024/07/19)
1. [main: aio.py]
- 修改了x轴显示使之为时间刻度
- 修改pre_warning函数增加了durable test的初始化
2. [main: factory_test.py]
- 增加了数据计算错误的判断逻辑
- 增加了历史数据保存的逻辑
- 增加了文件读写互斥的逻辑
- 修改功能为输出有效电流和最大电流,并将数据结构简化
v0.2.0.2(2024/07/26)
1. [main: current.py]
- 修正堵转电流无法正确写入结果文件的问题
2. [main: do_brake.py]
- 初始速度采集等待时间设置为可通过configs.xlsx配置文件调整的
- 初次速度采集停止逻辑修改为tasks.stop指令未验证
- 急停信号触发前pending时间设置为固定值10s
- 实现正负方向速度采集逻辑
- 工程名变更逻辑实现修改为通配符,方便后续根据机型保存文件
- 增加超差后写诊断的逻辑并可以通过configs.xlsx配置文件调整
- 程序输出中增加时间戳,方便调试定位日志时间
3. [main: do_current.py]
- 工程名变更逻辑实现修改为通配符,方便后续根据机型保存文件
4. 为工程文件添加更详细的注释
5. 补充了do_current/do_brake的流程图
6. [main: openapi.py]
- 将modbus motor_on/off的实现方法改为高电平脉冲触发
7. configs.xlsx配置表新增write_diagnosis/get_init_speed两个参数
v0.2.0.3(2024/07/27)
1. [APIs: do_brake.py]: 精简程序,解决 OOM 问题
2. [APIs: do_current.py]: 精简程序,解决 OOM 问题
3. [APIs: factory_test.py]: 精简程序,解决 OOM 问题
4. [APIsL openapi.py]
- 心跳修改为 1 s因为 OOM 问题的解决依赖于长久的打开曲线开关,此时对于 hr.c_msg 的定时清理是个挑战,将心跳缩短,有利于清理日志后,避免丢失心跳
- 新增 diagnosis.save 命令,但是执行时,有问题,待解决
v0.2.0.4(2024/07/30)
1. [APIs: do_brake.py]: 修复制动数据处理过程中,只取曲线的最后 240 个数据
2. [APIs: aio.py]: 判定版本处,删除 self.destroy(),因为该语句会导致异常发生
- 心跳修改为 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对应心跳
- create_plot 函数中增加 close('all'),解决循环画图不销毁占用内存的问题
4. [t_change_ui: do_brake.py]
- 使用一直打开曲线的方法规避解决了 OOM 的问题,同时修改数据处理方式,只取最后 12s
- 优化 ssh 输入密码的部分
5. [t_change_ui: do_current.py]
- 保持电流,只取最后 15s
- 优化 ssh 输入密码的部分
6. [t_change_ui: all the part]: 引入 commons 包,并定制了 logging 输出,后续持续优化
7. [APIs: btn_functions.py]: 重写了告警输出函数,从日志中拿数据
8. [APIs: aio.py]: 将日志框输出的内容,也保存至日志文件
9. [APIs: do_brake.py]
- 修改获取初始速度的逻辑只获取configs文件中配置的时间内的速度
- 新增 configs 参数 single_brake可针对特定条件做测试
10. [APIs: all]: 添加了 logger.setLevel(INFO),只有添加这个,单个模块内才生效

Binary file not shown.

View File

@ -6,8 +6,8 @@ VSVersionInfo(
ffi=FixedFileInfo( ffi=FixedFileInfo(
# filevers and prodvers should be always a tuple with four items: (1, 2, 3, 4) # filevers and prodvers should be always a tuple with four items: (1, 2, 3, 4)
# Set not needed items to zero 0. # Set not needed items to zero 0.
filevers=(0, 2, 0, 0), filevers=(0, 2, 0, 5),
prodvers=(0, 2, 0, 0), prodvers=(0, 2, 0, 5),
# Contains a bitmask that specifies the valid bits 'flags'r # Contains a bitmask that specifies the valid bits 'flags'r
mask=0x3f, mask=0x3f,
# Contains a bitmask that specifies the Boolean attributes of the file. # Contains a bitmask that specifies the Boolean attributes of the file.
@ -31,12 +31,12 @@ VSVersionInfo(
'040904b0', '040904b0',
[StringStruct('CompanyName', 'Rokae - https://www.rokae.com/'), [StringStruct('CompanyName', 'Rokae - https://www.rokae.com/'),
StringStruct('FileDescription', 'All in one automatic toolbox'), StringStruct('FileDescription', 'All in one automatic toolbox'),
StringStruct('FileVersion', '0.2.0.0 (2024-07-17)'), StringStruct('FileVersion', '0.2.0.5 (2024-08-02)'),
StringStruct('InternalName', 'AIO.exe'), StringStruct('InternalName', 'AIO.exe'),
StringStruct('LegalCopyright', '© 2024-2024 Manford Fan'), StringStruct('LegalCopyright', '© 2024-2024 Manford Fan'),
StringStruct('OriginalFilename', 'AIO.exe'), StringStruct('OriginalFilename', 'AIO.exe'),
StringStruct('ProductName', 'AIO'), StringStruct('ProductName', 'AIO'),
StringStruct('ProductVersion', '0.2.0.0 (2024-07-17)')]) StringStruct('ProductVersion', '0.2.0.5 (2024-08-02)')])
]), ]),
VarFileInfo([VarStruct('Translation', [1033, 1200])]) VarFileInfo([VarStruct('Translation', [1033, 1200])])
] ]

View File

@ -1,9 +1,9 @@
openpyxl==3.1.2 concurrent_log_handler==0.9.25
pdfplumber==0.11.0
customtkinter==5.2.2 customtkinter==5.2.2
Jinja2==3.1.4 matplotlib==3.9.1
lxml==5.2.2 numpy==2.0.1
numpy==1.26.4 openpyxl==3.1.2
pandas==2.2.2 pandas==2.2.2
pillow==10.3.0 paramiko==3.4.0
pyinstaller==6.7.0 pdfplumber==0.11.0
pymodbus==3.6.9

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -5,8 +5,8 @@
"data": { "data": {
"open": false, "open": false,
"display_open": false, "display_open": false,
"overrun": true, "overrun": false,
"turn_area": true, "turn_area": false,
"delay_motion": false "delay_motion": false
} }
} }

View File

@ -1 +1 @@
0.2.0.0 @ 07/17/2024 0.2.0.5 @ 08/02/2024

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1 +0,0 @@
__all__ = ['automatic_test', 'data_process']

View File

@ -1,49 +1,38 @@
import tkinter import tkinter
from os.path import exists, dirname from os.path import exists
from os import getcwd from os import getcwd, remove
from threading import Thread from threading import Thread
import tkinter.messagebox import tkinter.messagebox
import customtkinter import customtkinter
from time import time, strftime, localtime, sleep from time import time, strftime, localtime, sleep
from urllib.request import urlopen from urllib.request import urlopen
from socket import setdefaulttimeout
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from data_process import * from data_process import brake, current, iso, wavelogger
from automatic_test import * from automatic_test import do_current, do_brake, btn_functions
from durable_action import * from durable_action import factory_test
import openapi from commons import openapi, clibs
import matplotlib.pyplot as plt from matplotlib.pyplot import rcParams, figure, subplots_adjust, close
import matplotlib from matplotlib import use
import pandas as pd from pandas import DataFrame, read_excel
from logging import getLogger, INFO
matplotlib.use('Agg') with open(clibs.log_data, 'w') as _:
heartbeat = f'{dirname(__file__)}/../assets/templates/heartbeat' for i in range(1, 11):
durable_data_current_xlsx = f'{dirname(__file__)}/../assets/templates/durable/durable_data_current.xlsx' try:
durable_data_velocity_xlsx = f'{dirname(__file__)}/../assets/templates/durable/durable_data_velocity.xlsx' remove(f'{clibs.log_data}.{i}')
except FileNotFoundError:
pass
logger = getLogger(__file__)
logger.setLevel(INFO)
logger.info("日志文件初始化完成...")
use('Agg')
customtkinter.set_appearance_mode("System") # Modes: "System" (standard), "Dark", "Light" customtkinter.set_appearance_mode("System") # Modes: "System" (standard), "Dark", "Light"
customtkinter.set_default_color_theme("blue") # Themes: "blue" (standard), "green", "dark-blue" 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_widget_scaling(1.1) # widget dimensions and text size
customtkinter.set_window_scaling(1.1) # window geometry dimensions customtkinter.set_window_scaling(1.1) # window geometry dimensions
setdefaulttimeout(3)
# global vars # global vars
durable_data_current = {
'time': list(range(1, 26)),
'axis1': [0 for _ in range(25)],
'axis2': [0 for _ in range(25)],
'axis3': [0 for _ in range(25)],
'axis4': [0 for _ in range(25)],
'axis5': [0 for _ in range(25)],
'axis6': [0 for _ in range(25)],
}
durable_data_velocity = {
'time': list(range(1, 26)),
'axis1': [0 for _ in range(25)],
'axis2': [0 for _ in range(25)],
'axis3': [0 for _ in range(25)],
'axis4': [0 for _ in range(25)],
'axis5': [0 for _ in range(25)],
'axis6': [0 for _ in range(25)],
}
btns_func = { btns_func = {
'start': {'btn': '', 'row': 1, 'text': '开始运行'}, 'start': {'btn': '', 'row': 1, 'text': '开始运行'},
'check': {'btn': '', 'row': 2, 'text': '检查参数'}, 'check': {'btn': '', 'row': 2, 'text': '检查参数'},
@ -64,7 +53,7 @@ widgits_at = {
} }
widgits_da = { widgits_da = {
'path': {'label': '', 'entry': '', 'row': 1, 'col': 2, 'text': '数据文件夹路径'}, 'path': {'label': '', 'entry': '', 'row': 1, 'col': 2, 'text': '数据文件夹路径'},
'curvesel': {'label': '', 'optionmenu': '', 'row': 1, 'col': 1, 'text': '曲线选择'}, 'curvesel': {'label': '', 'optionmenu': '', 'row': 1, 'col': 1, 'text': '指标选择'},
} }
@ -79,6 +68,7 @@ class App(customtkinter.CTk):
self.flg = 0 self.flg = 0
self.df_copy = None self.df_copy = None
self.old_curve = None self.old_curve = None
self.myThread = None
# ===================================================================== # =====================================================================
# configure window # configure window
self.title("AIO - All in one automatic toolbox") self.title("AIO - All in one automatic toolbox")
@ -105,7 +95,7 @@ class App(customtkinter.CTk):
btns_func['log']['btn'].configure(command=lambda: self.thread_it(self.func_log_callback)) btns_func['log']['btn'].configure(command=lambda: self.thread_it(self.func_log_callback))
btns_func['end']['btn'].configure(command=lambda: self.thread_it(self.func_end_callback)) btns_func['end']['btn'].configure(command=lambda: self.thread_it(self.func_end_callback))
# create version info # create version info
self.label_version = customtkinter.CTkLabel(self.frame_func, justify='left', text="Vers: 0.2.0.0\nDate: 07/17/2024", font=self.my_font, text_color="#4F4F4F") self.label_version = customtkinter.CTkLabel(self.frame_func, justify='left', text="Vers: 0.2.0.5\nDate: 08/02/2024", font=self.my_font, text_color="#4F4F4F")
self.frame_func.rowconfigure(6, weight=1) self.frame_func.rowconfigure(6, weight=1)
self.label_version.grid(row=6, column=0, padx=20, pady=20, sticky='s') self.label_version.grid(row=6, column=0, padx=20, pady=20, sticky='s')
# ===================================================================== # =====================================================================
@ -185,7 +175,7 @@ class App(customtkinter.CTk):
widgits_da[widgit]['entry'] = customtkinter.CTkEntry(self.tabview.tab('Durable Action'), width=670, placeholder_text=widgits_da[widgit]['text'], font=self.my_font) widgits_da[widgit]['entry'] = customtkinter.CTkEntry(self.tabview.tab('Durable Action'), width=670, placeholder_text=widgits_da[widgit]['text'], font=self.my_font)
widgits_da[widgit]['entry'].grid(row=widgits_da[widgit]['row'], column=widgits_da[widgit]['col']+1, columnspan=11, padx=(5, 10), pady=10, sticky='we') widgits_da[widgit]['entry'].grid(row=widgits_da[widgit]['row'], column=widgits_da[widgit]['col']+1, columnspan=11, padx=(5, 10), pady=10, sticky='we')
elif widgit in ['curvesel']: elif widgit in ['curvesel']:
widgits_da[widgit]['optionmenu'] = customtkinter.CTkOptionMenu(self.tabview.tab('Durable Action'), button_color='#708090', fg_color='#778899', values=["device_servo_trq_feedback", "hw_joint_vel_feedback"], font=self.my_font) widgits_da[widgit]['optionmenu'] = customtkinter.CTkOptionMenu(self.tabview.tab('Durable Action'), dynamic_resizing=False, button_color='#708090', fg_color='#778899', values=['device_servo_trq_feedback', '[max] device_servo_trq_feedback'], font=self.my_font)
widgits_da[widgit]['optionmenu'].grid(row=widgits_da[widgit]['row'], column=widgits_da[widgit]['col'], padx=5, pady=10, sticky='we') widgits_da[widgit]['optionmenu'].grid(row=widgits_da[widgit]['row'], column=widgits_da[widgit]['col'], padx=5, pady=10, sticky='we')
widgits_da[widgit]['optionmenu'].set(widgits_da[widgit]['text']) widgits_da[widgit]['optionmenu'].set(widgits_da[widgit]['text'])
# For durable_action tab END ===================================================================== # For durable_action tab END =====================================================================
@ -206,32 +196,32 @@ class App(customtkinter.CTk):
tkinter.messagebox.showwarning(title="版本更新", message="连接服务器失败,无法确认当前是否是最新版本......") tkinter.messagebox.showwarning(title="版本更新", message="连接服务器失败,无法确认当前是否是最新版本......")
# functions below ↓ ---------------------------------------------------------------------------------------- # functions below ↓ ----------------------------------------------------------------------------------------
def create_canvas(self, figure): def create_canvas(self, _figure):
self.canvas = FigureCanvasTkAgg(figure, self) self.canvas = FigureCanvasTkAgg(_figure, self.tabview.tab('Durable Action'))
self.canvas.draw() self.canvas.draw()
self.canvas.get_tk_widget().configure(height=640) 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") self.canvas.get_tk_widget().grid(row=3, column=1, rowspan=3, columnspan=13, padx=20, pady=10, sticky="nsew")
def create_plot(self): def create_plot(self):
plt.rcParams['font.sans-serif'] = ['SimHei'] rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False rcParams['axes.unicode_minus'] = False
plt.rcParams['figure.dpi'] = 100 rcParams['figure.dpi'] = 100
plt.rcParams['font.size'] = 14 rcParams['font.size'] = 14
plt.rcParams['lines.marker'] = 'o' rcParams['lines.marker'] = 'o'
curvesel = widgits_da['curvesel']['optionmenu'].get() curvesel = widgits_da['curvesel']['optionmenu'].get()
while True: while True:
if not self.hr.durable_lock: if not self.hr.durable_lock:
self.hr.durable_lock = 1 self.hr.durable_lock = 1
if curvesel == 'device_servo_trq_feedback': if curvesel == 'device_servo_trq_feedback':
df = pd.read_excel(durable_data_current_xlsx) df = read_excel(clibs.durable_data_current_xlsx)
_title = 'device_servo_trq_feedback' _title = 'device_servo_trq_feedback'
elif curvesel == 'hw_joint_vel_feedback': elif curvesel == '[max] device_servo_trq_feedback':
_title = 'hw_joint_vel_feedback' _title = '[max] device_servo_trq_feedback'
df = pd.read_excel(durable_data_velocity_xlsx) df = read_excel(clibs.durable_data_current_max_xlsx)
else: else:
_title = 'device_servo_trq_feedback' _title = 'device_servo_trq_feedback'
df = pd.read_excel(durable_data_current_xlsx) df = read_excel(clibs.durable_data_current_xlsx)
self.hr.durable_lock = 0 self.hr.durable_lock = 0
break break
else: else:
@ -241,17 +231,24 @@ class App(customtkinter.CTk):
self.flg = 1 self.flg = 1
self.df_copy = df.copy() self.df_copy = df.copy()
self.old_curve = widgits_da['curvesel']['optionmenu'].get() self.old_curve = widgits_da['curvesel']['optionmenu'].get()
figure = plt.figure(frameon=True, facecolor='#E9E9E9') close('all')
plt.subplots_adjust(left=0.04, right=0.98, bottom=0.05, top=0.95) _figure = figure(frameon=True, facecolor='#E9E9E9')
ax = figure.add_subplot(1, 1, 1) 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.set_xticks(range(len(_xticks)))
ax.set_xticklabels(_xticks)
df.plot(grid=True, x='time', y='axis1', ax=ax) df.plot(grid=True, x='time', y='axis1', ax=ax)
df.plot(grid=True, x='time', y='axis2', ax=ax) df.plot(grid=True, x='time', y='axis2', ax=ax)
df.plot(grid=True, x='time', y='axis3', ax=ax) df.plot(grid=True, x='time', y='axis3', ax=ax)
df.plot(grid=True, x='time', y='axis4', ax=ax) df.plot(grid=True, x='time', y='axis4', ax=ax)
df.plot(grid=True, x='time', y='axis5', ax=ax) 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') 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): def thread_it(self, func, *args):
""" 将函数打包进线程 """ """ 将函数打包进线程 """
@ -266,7 +263,7 @@ class App(customtkinter.CTk):
self.seg_button.configure(state='disabled') self.seg_button.configure(state='disabled')
# self.tabview.configure(state='disabled') # self.tabview.configure(state='disabled')
self.textbox.delete(index1='1.0', index2='end') 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() c_state = f_h.read().strip()
if c_state == '0' and value != '功能切换': if c_state == '0' and value != '功能切换':
@ -281,12 +278,12 @@ class App(customtkinter.CTk):
# self.tabview.configure(state='normal') # self.tabview.configure(state='normal')
def detect_network(self): def detect_network(self):
df = pd.DataFrame(durable_data_current) df = DataFrame(clibs.durable_data_current)
df.to_excel(durable_data_current_xlsx, index=False) df.to_excel(clibs.durable_data_current_xlsx, index=False)
df = pd.DataFrame(durable_data_velocity) df = DataFrame(clibs.durable_data_current_max)
df.to_excel(durable_data_velocity_xlsx, index=False) 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') f_hb.write('0')
self.hr = openapi.HmiRequest(self.write2textbox) self.hr = openapi.HmiRequest(self.write2textbox)
self.md = openapi.ModbusRequest(self.write2textbox) self.md = openapi.ModbusRequest(self.write2textbox)
@ -295,21 +292,20 @@ class App(customtkinter.CTk):
if self.tabview.get() == 'Durable Action': if self.tabview.get() == 'Durable Action':
self.create_plot() 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() c_state = f_hb.read().strip()
pb_color = 'green' if c_state == '1' else 'red' pb_color = 'green' if c_state == '1' else 'red'
self.progressbar.configure(progress_color=pb_color) self.progressbar.configure(progress_color=pb_color)
self.progressbar_da.configure(progress_color=pb_color) self.progressbar_da.configure(progress_color=pb_color)
if c_state == '0': if c_state == '0':
self.hr.t_bool = False self.hr.t_bool = False
sleep(3) sleep(4)
del self.hr del self.hr
self.hr = openapi.HmiRequest(self.write2textbox) self.hr = openapi.HmiRequest(self.write2textbox)
sleep(3) sleep(3)
def tabview_click(self): def tabview_click(self):
self.initialization() self.initialization()
tab_name = self.tabview.get() tab_name = self.tabview.get()
if tab_name == 'Data Process': if tab_name == 'Data Process':
self.flg = 0 self.flg = 0
@ -323,10 +319,6 @@ class App(customtkinter.CTk):
def initialization(self): def initialization(self):
tab_name = self.tabview.get() tab_name = self.tabview.get()
try:
self.canvas.get_tk_widget().grid_forget()
except:
pass
self.textbox.delete(index1='1.0', index2='end') self.textbox.delete(index1='1.0', index2='end')
if tab_name == 'Data Process': if tab_name == 'Data Process':
for widgit in widgits_dp: for widgit in widgits_dp:
@ -458,6 +450,7 @@ class App(customtkinter.CTk):
self.textbox.tag_add(color, 'insert', 'end') self.textbox.tag_add(color, 'insert', 'end')
self.textbox.tag_config(tagName=color, foreground=color) self.textbox.tag_config(tagName=color, foreground=color)
tab_name_cur = self.tabview.get() tab_name_cur = self.tabview.get()
logger.info(text)
if tab_name == tab_name_cur: if tab_name == tab_name_cur:
if wait != 0: if wait != 0:
@ -583,7 +576,7 @@ class App(customtkinter.CTk):
path = widgits_da['path']['entry'].get().strip() path = widgits_da['path']['entry'].get().strip()
curvesel = widgits_da['curvesel']['optionmenu'].get() curvesel = widgits_da['curvesel']['optionmenu'].get()
c1 = exists(path) c1 = exists(path)
c2 = curvesel in ['device_servo_trq_feedback', 'hw_joint_vel_feedback'] c2 = curvesel in ['device_servo_trq_feedback', '[max] device_servo_trq_feedback']
if c1 and c2: if c1 and c2:
return 7, path, curvesel return 7, path, curvesel
else: else:
@ -618,6 +611,12 @@ class App(customtkinter.CTk):
tkinter.messagebox.showerror(title="参数错误", message="请检查对应参数是否填写正确!", ) tkinter.messagebox.showerror(title="参数错误", message="请检查对应参数是否填写正确!", )
def pre_warning(self): def pre_warning(self):
if self.tabview.get() == 'Durable Action':
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="确认机器已按照测试规范更新固件,并提按照测试机型前修改好工程?"): if tkinter.messagebox.askyesno(title="开始运行", message="确认机器已按照测试规范更新固件,并提按照测试机型前修改好工程?"):
pass pass
else: else:

View File

@ -1 +0,0 @@
__all__ = ['btn_functions', 'do_brake', 'do_current']

View File

@ -1,61 +1,58 @@
from json import loads from json import loads
from sys import argv from sys import argv
from logging import getLogger, INFO
from commons import clibs
tab_name = clibs.tab_names['at']
def execution(cmd, hr, w2t, **kwargs): logger = getLogger(__file__)
_id = hr.execution(cmd, **kwargs) logger.setLevel(INFO)
_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
def trigger_estop(md, w2t): def trigger_estop(md, w2t):
md.trigger_estop() md.trigger_estop()
w2t("触发急停成功,可点击机器状态验证。", 0, 0, 'green', 'Automatic Test') w2t("触发急停成功,可点击机器状态验证。", 0, 0, 'green', tab_name)
def reset_estop(md, w2t): def reset_estop(md, w2t):
md.reset_estop() md.reset_estop()
w2t("恢复急停成功,可点击机器状态验证。", 0, 0, 'green', 'Automatic Test') w2t("恢复急停成功,可点击机器状态验证。", 0, 0, 'green', tab_name)
def get_state(hr, w2t): 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': '工作任务空间'} stat_desc = {'engine': '上电状态', 'operate': '操作模式', 'rc_state': '控制器状态', 'robot_action': '机器人动作', 'safety_mode': '安全模式', 'servo_mode': '伺服工作模式', 'task_space': '工作任务空间'}
for component, state in _response['data'].items(): 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_desc = {0: '伺服版本', 1: '伺服参数', 2: '安全板固件', 3: '控制器', 4: '通讯总线', 5: '解释器', 6: '运动控制', 8: '力控版本', 9: '末端固件', 10: '机型文件', 11: '环境包'}
dev_vers = {} dev_vers = {}
for device in _response['data']['devices']: for device in _response['data']['devices']:
dev_vers[device['type']] = device['version'] dev_vers[device['type']] = device['version']
for i in sorted(dev_desc.keys()): 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): def warning_info(hr, w2t):
for msg in hr.c_msg: for postfix in ['', '.2', '.3', '.4', '.5', '.6', '.7', '.8', '.9', '.10']:
if 'alarm' in msg.lower(): log_name = clibs.log_data + postfix
w2t(str(loads(msg)), tab_name='Automatic Test') try:
for msg in hr.c_msg_xs: with open(log_name, 'r', encoding='utf-8') as f_log:
if 'alarm' in msg.lower(): for line in f_log:
w2t(str(loads(msg)), tab_name='Automatic Test') if 'alarm' in line:
w2t(line.strip(), tab_name=tab_name)
except FileNotFoundError:
pass
def main(hr, md, func, w2t): def main(hr, md, func, w2t):
if hr is None: 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/ # func: get_state/
match func: match func:
case 'trigger_estop': case 'trigger_estop':

View File

@ -1,36 +1,22 @@
from random import randint from time import sleep, time, strftime, localtime
from time import sleep, time
from sys import argv from sys import argv
from os import scandir, mkdir from os import mkdir
from os.path import exists
from paramiko import SSHClient, AutoAddPolicy from paramiko import SSHClient, AutoAddPolicy
from json import loads from json import loads
from openpyxl import load_workbook from openpyxl import load_workbook
import pandas from pandas import DataFrame, concat
from logging import getLogger, INFO
from commons import clibs
RADIAN = 57.3 # 180 / 3.1415926 tab_name = clibs.tab_names['at']
logger = getLogger(__file__)
logger.setLevel(INFO)
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): def check_files(path, loadsel, data_dirs, data_files, w2t):
if len(data_dirs) != 0 or len(data_files) != 5: if len(data_dirs) != 0 or len(data_files) != 5:
w2t('初始路径下不允许有文件夹,且初始路径下只能存在如下五个文件,确认后重新运行!', 0, 0, 'red', tab_name='Automatic Test') 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='Automatic Test') 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 config_file = reach33 = reach66 = reach100 = prj_file = None
for data_file in data_files: for data_file in data_files:
@ -46,8 +32,8 @@ def check_files(path, loadsel, data_dirs, data_files, w2t):
elif filename.endswith('.zip'): elif filename.endswith('.zip'):
prj_file = data_file prj_file = data_file
else: else:
w2t('初始路径下不允许有文件夹,且初始路径下只能存在如下五个文件,确认后重新运行!', 0, 0, 'red', tab_name='Automatic Test') 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='Automatic Test') 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: if config_file and reach33 and reach66 and reach100 and prj_file:
result_dirs = [] result_dirs = []
@ -65,63 +51,24 @@ def check_files(path, loadsel, data_dirs, data_files, w2t):
if _reach == 'reach100': if _reach == 'reach100':
mkdir(f"{path}\\j3\\{dir_name}") mkdir(f"{path}\\j3\\{dir_name}")
w2t("数据目录合规性检查结束,未发现问题......", tab_name='Automatic Test') w2t("数据目录合规性检查结束,未发现问题......", 0, 0, 'blue', tab_name)
return config_file, reach33, reach66, reach100, prj_file, result_dirs return config_file, reach33, reach66, reach100, prj_file, result_dirs
else: else:
w2t('初始路径下不允许有文件夹,且初始路径下只能存在如下五个文件,确认后重新运行!', 0, 0, 'red', tab_name='Automatic Test') 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='Automatic Test') 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
_prj_name = prj_file.split('\\')[-1].removesuffix('.zip')
cmd = 'cd /home/luoshi/bin/controller/; '
cmd += f'sudo mv projects/target/_build/{_prj_name}.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='Automatic Test')
else:
_response = loads(_msg)
if not _response:
w2t(f"无法获取{id}请求的响应信息", 0, 1, 'red', tab_name='Automatic Test')
return _response
def gen_result_file(path, curve_data, axis, _reach, _load, _speed, count): def gen_result_file(path, curve_data, axis, _reach, _load, _speed, count):
_d2d_vel = {'hw_joint_vel_feedback': []} _d2d_vel = {'hw_joint_vel_feedback': []}
_d2d_trq = {'device_servo_trq_feedback': []} _d2d_trq = {'device_servo_trq_feedback': []}
_d2d_stop = {'device_safety_estop': []} _d2d_stop = {'device_safety_estop': []}
for data in curve_data: for data in curve_data[-240:]: # 保留最后12s的数据
dict_results = data['data'] dict_results = data['data']
# dict_results.reverse()
for item in dict_results: for item in dict_results:
try:
item['value'].reverse() item['value'].reverse()
except KeyError:
continue
if item.get('channel', None) == axis-1 and item.get('name', None) == 'hw_joint_vel_feedback': 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']) _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': elif item.get('channel', None) == axis-1 and item.get('name', None) == 'device_servo_trq_feedback':
@ -129,17 +76,17 @@ def gen_result_file(path, curve_data, axis, _reach, _load, _speed, count):
elif item.get('channel', None) == 0 and item.get('name', None) == 'device_safety_estop': elif item.get('channel', None) == 0 and item.get('name', None) == 'device_safety_estop':
_d2d_stop['device_safety_estop'].extend(item['value']) _d2d_stop['device_safety_estop'].extend(item['value'])
df1 = pandas.DataFrame.from_dict(_d2d_vel) df1 = DataFrame.from_dict(_d2d_vel)
df2 = pandas.DataFrame.from_dict(_d2d_trq) df2 = DataFrame.from_dict(_d2d_trq)
df3 = pandas.DataFrame.from_dict(_d2d_stop) df3 = DataFrame.from_dict(_d2d_stop)
df = pandas.concat([df1, df2, df3], axis=1) 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" _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) df.to_csv(_filename, sep='\t', index=False)
def run_rl(path, loadsel, hr, md, config_file, prj_file, result_dirs, w2t): def run_rl(path, loadsel, hr, md, config_file, result_dirs, w2t):
_count = 0 _count = 0
speed_max = 0 _total = 63
display_pdo_params = [ display_pdo_params = [
{"name": "hw_joint_vel_feedback", "channel": 0}, {"name": "hw_joint_vel_feedback", "channel": 0},
{"name": "hw_joint_vel_feedback", "channel": 1}, {"name": "hw_joint_vel_feedback", "channel": 1},
@ -157,36 +104,58 @@ def run_rl(path, loadsel, hr, md, config_file, prj_file, result_dirs, w2t):
] ]
wb = load_workbook(config_file, read_only=True) wb = load_workbook(config_file, read_only=True)
ws = wb['Target'] ws = wb['Target']
if ws.cell(row=1, column=1).value == 'positive': write_diagnosis = float(ws.cell(row=3, column=10).value)
md.write_pon(True) get_init_speed = float(ws.cell(row=4, column=10).value)
elif ws.cell(row=1, column=1).value == 'negative': single_brake = str(ws.cell(row=5, column=10).value)
md.write_pon(False)
else:
w2t("configs.xlsx中Target页面A1单元格填写不正确检查后重新运行...", 0, 111, 'red', 'Automatic Test')
if ws.cell(row=1, column=1).value == 'positive':
md.write_pon(1)
elif ws.cell(row=1, column=1).value == 'negative':
md.write_pon(0)
else:
w2t("configs.xlsx中Target页面A1单元格填写不正确检查后重新运行...", 0, 111, 'red', tab_name)
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: for condition in result_dirs:
_reach = condition.split('_')[0].removeprefix('reach') _reach = condition.split('_')[0].removeprefix('reach')
_load = condition.split('_')[1].removeprefix('load') _load = condition.split('_')[1].removeprefix('load')
_speed = condition.split('_')[2].removeprefix('speed') _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]:
continue
for axis in range(1, 4): for axis in range(1, 4):
# for single condition test
if _single_axis != 0 and _single_axis != axis:
continue
md.write_axis(axis) md.write_axis(axis)
speed_max = 0 speed_max = 0
if axis == 3 and _reach != '100': if axis == 3 and _reach != '100':
continue continue
w2t(f"-"*90, 0, 0, 'purple', tab_name)
for count in range(1, 4): for count in range(1, 4):
_count += 1 _count += 1
w2t(f"[{_count}/63-{count}] 正在执行{axis}{condition}的制动测试......", 0, 0, 'purple', 'Automatic Test') 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)
# 1. 关闭诊断曲线,触发软急停,并解除,目的是让可能正在运行着的机器停下来,切手动模式并下电 # 1. 关闭诊断曲线,触发软急停,并解除,目的是让可能正在运行着的机器停下来,切手动模式并下电
md.trigger_estop() md.trigger_estop()
md.reset_estop() md.reset_estop()
md.write_act(False) md.clear_alarm()
_response = execution('diagnosis.open', hr, w2t, open=False, display_open=False) md.write_act(0)
sleep(1) # 让曲线彻底关闭 sleep(write_diagnosis) # 软急停超差后等待写诊断时间可通过configs.xlsx配置
_response = execution('state.switch_manual', hr, w2t)
_response = execution('state.switch_motor_off', hr, w2t)
while count == 1:
# 2. 修改未要执行的场景 # 2. 修改未要执行的场景
ssh = SSHClient() ssh = SSHClient()
ssh.set_missing_host_key_policy(AutoAddPolicy()) ssh.set_missing_host_key_policy(AutoAddPolicy())
@ -196,26 +165,27 @@ def run_rl(path, loadsel, hr, md, config_file, prj_file, result_dirs, w2t):
elif ws.cell(row=1, column=1).value == 'negative': 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)" _rl_cmd = f"brake_E(j{axis}_{_reach}_n, j{axis}_{_reach}_p, p_speed, p_tool)"
else: else:
w2t("configs.xlsx中Target页面A1单元格填写不正确检查后重新运行...", 0, 111, 'red', 'Automatic Test') w2t("configs.xlsx中Target页面A1单元格填写不正确检查后重新运行...", 0, 111, 'red', tab_name)
_rl_speed = f"VelSet {_speed}" _rl_speed = f"VelSet {_speed}"
_rl_tool = f"tool p_tool = tool{loadsel.removeprefix('tool')}"
cmd = 'cd /home/luoshi/bin/controller/; ' cmd = 'cd /home/luoshi/bin/controller/; '
cmd += 'sudo sed -i "/brake_E/d" projects/target/_build/brake/main.mod; ' 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 += '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; '
stdin, stdout, stderr = ssh.exec_command(cmd, get_pty=True) stdin, stdout, stderr = ssh.exec_command(cmd, get_pty=True)
stdin.write('luoshi2019' + '\n') stdin.write('luoshi2019' + '\n')
stdin.flush() stdout.read().decode() # 需要read一下才能正常执行
print(stdout.read().decode()) # 必须得输出一下stdout才能正确执行sudo stderr.read().decode()
print(stderr.read().decode()) # 顺便也执行以下stderr
# 3. reload工程后pp2main并且自动模式和上电最后运行程序 # 3. reload工程后pp2main并且自动模式和上电最后运行程序
prj_path = 'target/_build/target.prj' clibs.execution('overview.reload', hr, w2t, tab_name, prj_path=prj_path, tasks=['brake', 'stop0_related'])
_response = execution('overview.reload', hr, w2t, prj_path=prj_path, tasks=['brake', 'stop0_related']) clibs.execution('rl_task.pp_to_main', hr, w2t, tab_name, tasks=['brake', 'stop0_related'])
_response = execution('rl_task.pp_to_main', hr, w2t, tasks=['brake', 'stop0_related']) clibs.execution('state.switch_auto', hr, w2t, tab_name)
_response = execution('state.switch_auto', hr, w2t) clibs.execution('state.switch_motor_on', hr, w2t, tab_name)
_response = execution('state.switch_motor_on', hr, w2t) clibs.execution('rl_task.run', hr, w2t, tab_name, tasks=['brake', 'stop0_related'])
_response = execution('rl_task.run', hr, w2t, tasks=['brake', 'stop0_related'])
_t_start = time() _t_start = time()
while True: while True:
if md.read_ready_to_go() == 1: if md.read_ready_to_go() == 1:
@ -223,103 +193,105 @@ def run_rl(path, loadsel, hr, md, config_file, prj_file, result_dirs, w2t):
break break
else: else:
if (time() - _t_start) // 20 > 1: if (time() - _t_start) // 20 > 1:
w2t("20s内未收到机器人的运行信号需要确认RL程序编写正确并正常执行...", 0, 111, 'red', 'Automatic Test') w2t("20s内未收到机器人的运行信号需要确认RL程序编写正确并正常执行...", 0, 111, 'red', tab_name)
else: else:
sleep(1) sleep(1)
# 4. 第一次打开诊断曲线并执行采集8s之后触发软急停关闭曲线采集找出最大速度传递给RL程序最后清除相关记录 # 4. 找出最大速度传递给RL程序最后清除相关记录
if count == 1: sleep(get_init_speed+5) # 冗余5s指定时间后获取实际【正|负】方向的最大速度可通过configs.xlsx配置
_response = execution('diagnosis.open', hr, w2t, open=True, display_open=True) clibs.execution('rl_task.stop', hr, w2t, tab_name, tasks=['brake'])
_response = execution('diagnosis.set_params', hr, w2t, display_pdo_params=display_pdo_params)
sleep(10) # 前10秒获取实际最大速度
md.trigger_estop()
_response = execution('diagnosis.open', hr, w2t, open=False, display_open=False)
# 找出最大速度 # 找出最大速度
for _msg in hr.c_msg: _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: if 'diagnosis.result' in _msg:
_number += 1
dict_results = loads(_msg)['data'] dict_results = loads(_msg)['data']
for item in dict_results: for item in dict_results:
if item.get('channel', None) == axis-1 and item.get('name', None) == 'hw_joint_vel_feedback': if item.get('channel', None) == axis-1 and item.get('name', None) == 'hw_joint_vel_feedback':
_ = abs(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) speed_max = max(_, speed_max)
elif ws.cell(row=1, column=1).value == '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 speed_target = float(ws.cell(row=3, column=axis+1).value) * float(_speed) / 100
if speed_max < speed_target*0.95 or speed_max > speed_target*1.05: 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', 'Automatic Test') w2t(f"Axis: {axis}-{count} | Speed: {speed_max} | Shouldbe: {speed_target}", 0, 0, 'indigo', tab_name)
md.write_speed_max(speed_max) md.write_speed_max(speed_max)
sleep(1)
for _msg in hr.c_msg:
if 'diagnosis.result' in _msg:
_index = hr.c_msg.index(_msg)
del hr.c_msg[_index:]
hr.c_msg_xs.clear() 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)
continue
else:
break break
# 5. 清除软急停重新运行程序并打开曲线发送继续运动信号当速度达到最大值时通过DO触发急停 # 5. 清除软急停重新运行程序并打开曲线发送继续运动信号当速度达到最大值时通过DO触发急停
md.reset_estop() md.reset_estop() # 其实没必要
_response = execution('overview.reload', hr, w2t, prj_path=prj_path, tasks=['brake', 'stop0_related']) md.clear_alarm()
_response = execution('rl_task.pp_to_main', hr, w2t, tasks=['brake', 'stop0_related'])
_response = execution('state.switch_auto', hr, w2t) clibs.execution('overview.reload', hr, w2t, tab_name, prj_path=prj_path, tasks=['brake', 'stop0_related'])
_response = execution('state.switch_motor_on', hr, w2t) clibs.execution('rl_task.pp_to_main', hr, w2t, tab_name, tasks=['brake', 'stop0_related'])
_response = execution('rl_task.run', hr, w2t, 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): for i in range(3):
if md.read_ready_to_go() == 1: if md.read_ready_to_go() == 1:
md.write_act(True) md.write_act(1)
break break
else: else:
sleep(1) sleep(1)
else: else:
w2t("未收到机器人的运行信号需要确认RL程序编写正确并正常执行...", 0, 111, 'red', 'Automatic Test') w2t("未收到机器人的运行信号需要确认RL程序编写正确并正常执行...", 0, 111, 'red', tab_name)
_response = execution('diagnosis.open', hr, w2t, open=True, display_open=True) sleep(10) # 排除从其他位姿到零点位姿,再到轴极限位姿的时间
_response = execution('diagnosis.set_params', hr, w2t, display_pdo_params=display_pdo_params) md.write_probe(1)
sleep(randint(3, 6))
md.write_probe(True)
_t_start = time() _t_start = time()
while True: while True:
if md.read_brake_done() == 1: if md.read_brake_done() == 1:
sleep(1) # 保证所有数据均已返回 sleep(1) # 保证速度归零
md.write_probe(False) md.write_probe(0)
_response = execution('diagnosis.open', hr, w2t, open=False, display_open=False)
sleep(1) # 保证所有数据均已返回
break break
else: else:
if (time() - _t_start) > 30: if (time() - _t_start) > 30:
w2t(f"30s内未触发急停该条数据无效需要确认RL/Python程序编写正确并正常执行或者判别是否是机器本体问题...", 0, 0, 'red', 'Automatic Test') w2t(f"30s内未触发急停该条数据无效需要确认RL/Python程序编写正确并正常执行或者判别是否是机器本体问题,比如正负方向速度是否一致...", 0, 0, 'red', tab_name)
md.write_probe(False) md.write_probe(0)
_response = execution('diagnosis.open', hr, w2t, open=False, display_open=False)
sleep(1) # 保证所有数据均已返回
break break
else: else:
sleep(1) sleep(1)
# 6. 保留数据并处理输出 # 6. 保留数据并处理输出
curve_data = [] curve_data = []
for _msg in hr.c_msg: _c_msg = hr.c_msg.copy()
for _msg in _c_msg:
if 'diagnosis.result' in _msg: if 'diagnosis.result' in _msg:
curve_data.insert(0, loads(_msg)) curve_data.insert(0, loads(_msg))
else: else:
for _msg in hr.c_msg:
if 'diagnosis.result' in _msg:
_index = hr.c_msg.index(_msg)
del hr.c_msg[_index:]
hr.c_msg_xs.clear() hr.c_msg_xs.clear()
break 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, curve_data, axis, _reach, _load, _speed, count)
else: else:
w2t(f"\n{loadsel.removeprefix('tool')}%负载的制动性能测试执行完毕,如需采集其他负载,须切换负载类型,并更换其他负载,重新执行。", 0, 0, 'green', 'Automatic Test') w2t(f"\n{loadsel.removeprefix('tool')}%负载的制动性能测试执行完毕,如需采集其他负载,须切换负载类型,并更换其他负载,重新执行。", 0, 0, 'green', tab_name)
def main(path, hr, md, loadsel, w2t): def main(path, hr, md, loadsel, w2t):
_s_time = time() _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) 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, prj_file, result_dirs, w2t) run_rl(path, loadsel, hr, md, config_file, result_dirs, w2t)
_e_time = time() _e_time = time()
time_total = _e_time - _s_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', 'Automatic Test') 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)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -1,33 +1,36 @@
import os from os import mkdir
from time import sleep, time from time import sleep, time
from sys import argv from sys import argv
from os import scandir
from os.path import exists
from paramiko import SSHClient, AutoAddPolicy from paramiko import SSHClient, AutoAddPolicy
from json import loads from json import loads
import pandas from pandas import DataFrame, concat
from logging import getLogger, INFO
from commons import clibs
logger = getLogger(__file__)
logger.setLevel(INFO)
def traversal_files(path, w2t): tab_name = clibs.tab_names['at']
if not exists(path): display_pdo_params = [
msg = f'数据文件夹{path}不存在,请确认后重试......' {"name": "hw_joint_vel_feedback", "channel": 0},
w2t(msg, 0, 1, 'red', tab_name='Automatic Test') {"name": "hw_joint_vel_feedback", "channel": 1},
else: {"name": "hw_joint_vel_feedback", "channel": 2},
dirs = [] {"name": "hw_joint_vel_feedback", "channel": 3},
files = [] {"name": "hw_joint_vel_feedback", "channel": 4},
for item in scandir(path): {"name": "hw_joint_vel_feedback", "channel": 5},
if item.is_dir(): {"name": "device_servo_trq_feedback", "channel": 0},
dirs.append(item.path) {"name": "device_servo_trq_feedback", "channel": 1},
elif item.is_file(): {"name": "device_servo_trq_feedback", "channel": 2},
files.append(item.path) {"name": "device_servo_trq_feedback", "channel": 3},
{"name": "device_servo_trq_feedback", "channel": 4},
return dirs, files {"name": "device_servo_trq_feedback", "channel": 5},
]
def check_files(path, loadsel, data_dirs, data_files, w2t): def check_files(path, loadsel, data_dirs, data_files, w2t):
if len(data_dirs) != 0 or len(data_files) != 3: if len(data_dirs) != 0 or len(data_files) != 3:
w2t('初始路径下不允许有文件夹,且初始路径下只能存在如下三个文件,确认后重新运行!', 0, 0, '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='Automatic Test') w2t(' 1. configs.xlsx\n 2. T_电机电流.xlsx\n 3. xxxx.zip', 0, 1, 'red', tab_name)
config_file = current_file = prj_file = None config_file = current_file = prj_file = None
for data_file in data_files: for data_file in data_files:
@ -39,63 +42,22 @@ def check_files(path, loadsel, data_dirs, data_files, w2t):
elif filename.endswith('.zip'): elif filename.endswith('.zip'):
prj_file = data_file prj_file = data_file
else: else:
w2t('初始路径下不允许有文件夹,且初始路径下只能存在如下三个文件,确认后重新运行!', 0, 0, '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='Automatic Test') 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: if config_file and current_file and prj_file:
w2t("数据目录合规性检查结束,未发现问题......", tab_name='Automatic Test') w2t("数据目录合规性检查结束,未发现问题......", tab_name=tab_name)
if loadsel == 'tool100': if loadsel == 'tool100':
os.mkdir(f"{path}\\single") mkdir(f"{path}\\single")
os.mkdir(f"{path}\\s_1") mkdir(f"{path}\\s_1")
os.mkdir(f"{path}\\s_2") mkdir(f"{path}\\s_2")
os.mkdir(f"{path}\\s_3") mkdir(f"{path}\\s_3")
elif loadsel == 'inertia': elif loadsel == 'inertia':
os.mkdir(f"{path}\\inertia") mkdir(f"{path}\\inertia")
return config_file, current_file, prj_file return config_file, current_file, prj_file
else: else:
w2t('初始路径下不允许有文件夹,且初始路径下只能存在如下三个文件,确认后重新运行!', 0, 0, '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='Automatic Test') w2t(' 1. configs.xlsx\n 2. T_电机电流.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
_prj_name = prj_file.split('\\')[-1].removesuffix('.zip')
cmd = 'cd /home/luoshi/bin/controller/; '
cmd += f'sudo mv projects/target/_build/{_prj_name}.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
def data_proc_regular(path, filename, channel, scenario_time): def data_proc_regular(path, filename, channel, scenario_time):
@ -104,18 +66,21 @@ def data_proc_regular(path, filename, channel, scenario_time):
lines = f_obj.readlines() lines = f_obj.readlines()
_d2d_vel = {'hw_joint_vel_feedback': []} _d2d_vel = {'hw_joint_vel_feedback': []}
_d2d_trq = {'device_servo_trq_feedback': []} _d2d_trq = {'device_servo_trq_feedback': []}
for line in lines: for line in lines[-500:]: # 保留最后25s的数据
data = eval(line.strip())['data'] data = eval(line.strip())['data']
for item in data: for item in data:
try:
item['value'].reverse() item['value'].reverse()
except KeyError:
continue
if item.get('channel', None) == channel and item.get('name', None) == 'hw_joint_vel_feedback': if item.get('channel', None) == channel and item.get('name', None) == 'hw_joint_vel_feedback':
_d2d_vel['hw_joint_vel_feedback'].extend(item['value']) _d2d_vel['hw_joint_vel_feedback'].extend(item['value'])
elif item.get('channel', None) == channel and item.get('name', None) == 'device_servo_trq_feedback': elif item.get('channel', None) == channel and item.get('name', None) == 'device_servo_trq_feedback':
_d2d_trq['device_servo_trq_feedback'].extend(item['value']) _d2d_trq['device_servo_trq_feedback'].extend(item['value'])
df1 = pandas.DataFrame.from_dict(_d2d_vel) df1 = DataFrame.from_dict(_d2d_vel)
df2 = pandas.DataFrame.from_dict(_d2d_trq) df2 = DataFrame.from_dict(_d2d_trq)
df = pandas.concat([df1, df2], axis=1) df = concat([df1, df2], axis=1)
_filename = f'{path}\\single\\j{channel+1}_single_{time()}.data' _filename = f'{path}\\single\\j{channel+1}_single_{time()}.data'
df.to_csv(_filename, sep='\t', index=False) df.to_csv(_filename, sep='\t', index=False)
elif channel in list(range(6, 9)): elif channel in list(range(6, 9)):
@ -136,7 +101,10 @@ def data_proc_regular(path, filename, channel, scenario_time):
for line in lines: for line in lines:
data = eval(line.strip())['data'] data = eval(line.strip())['data']
for item in data: for item in data:
try:
item['value'].reverse() item['value'].reverse()
except KeyError:
continue
if item.get('channel', None) == 0 and item.get('name', None) == 'hw_joint_vel_feedback': 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']) _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': elif item.get('channel', None) == 0 and item.get('name', None) == 'device_servo_trq_feedback':
@ -162,39 +130,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': 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']) _d2d_trq_5['device_servo_trq_feedback'].extend(item['value'])
df_01 = pandas.DataFrame.from_dict(_d2d_vel_0) df_01 = DataFrame.from_dict(_d2d_vel_0)
df_02 = pandas.DataFrame.from_dict(_d2d_trq_0) df_02 = DataFrame.from_dict(_d2d_trq_0)
df = pandas.concat([df_01, df_02], axis=1) df = concat([df_01, df_02], axis=1)
_filename = f'{path}\\s_{channel-5}\\j1_s_{channel-5}_{scenario_time}_{time()}.data' _filename = f'{path}\\s_{channel-5}\\j1_s_{channel-5}_{scenario_time}_{time()}.data'
df.to_csv(_filename, sep='\t', index=False) df.to_csv(_filename, sep='\t', index=False)
df_01 = pandas.DataFrame.from_dict(_d2d_vel_1) df_01 = DataFrame.from_dict(_d2d_vel_1)
df_02 = pandas.DataFrame.from_dict(_d2d_trq_1) df_02 = DataFrame.from_dict(_d2d_trq_1)
df = pandas.concat([df_01, df_02], axis=1) df = concat([df_01, df_02], axis=1)
_filename = f'{path}\\s_{channel-5}\\j2_s_{channel-5}_{scenario_time}_{time()}.data' _filename = f'{path}\\s_{channel-5}\\j2_s_{channel-5}_{scenario_time}_{time()}.data'
df.to_csv(_filename, sep='\t', index=False) df.to_csv(_filename, sep='\t', index=False)
df_01 = pandas.DataFrame.from_dict(_d2d_vel_2) df_01 = DataFrame.from_dict(_d2d_vel_2)
df_02 = pandas.DataFrame.from_dict(_d2d_trq_2) df_02 = DataFrame.from_dict(_d2d_trq_2)
df = pandas.concat([df_01, df_02], axis=1) df = concat([df_01, df_02], axis=1)
_filename = f'{path}\\s_{channel-5}\\j3_s_{channel-5}_{scenario_time}_{time()}.data' _filename = f'{path}\\s_{channel-5}\\j3_s_{channel-5}_{scenario_time}_{time()}.data'
df.to_csv(_filename, sep='\t', index=False) df.to_csv(_filename, sep='\t', index=False)
df_01 = pandas.DataFrame.from_dict(_d2d_vel_3) df_01 = DataFrame.from_dict(_d2d_vel_3)
df_02 = pandas.DataFrame.from_dict(_d2d_trq_3) df_02 = DataFrame.from_dict(_d2d_trq_3)
df = pandas.concat([df_01, df_02], axis=1) df = concat([df_01, df_02], axis=1)
_filename = f'{path}\\s_{channel-5}\\j4_s_{channel-5}_{scenario_time}_{time()}.data' _filename = f'{path}\\s_{channel-5}\\j4_s_{channel-5}_{scenario_time}_{time()}.data'
df.to_csv(_filename, sep='\t', index=False) df.to_csv(_filename, sep='\t', index=False)
df_01 = pandas.DataFrame.from_dict(_d2d_vel_4) df_01 = DataFrame.from_dict(_d2d_vel_4)
df_02 = pandas.DataFrame.from_dict(_d2d_trq_4) df_02 = DataFrame.from_dict(_d2d_trq_4)
df = pandas.concat([df_01, df_02], axis=1) df = concat([df_01, df_02], axis=1)
_filename = f'{path}\\s_{channel-5}\\j5_s_{channel-5}_{scenario_time}_{time()}.data' _filename = f'{path}\\s_{channel-5}\\j5_s_{channel-5}_{scenario_time}_{time()}.data'
df.to_csv(_filename, sep='\t', index=False) df.to_csv(_filename, sep='\t', index=False)
df_01 = pandas.DataFrame.from_dict(_d2d_vel_5) df_01 = DataFrame.from_dict(_d2d_vel_5)
df_02 = pandas.DataFrame.from_dict(_d2d_trq_5) df_02 = DataFrame.from_dict(_d2d_trq_5)
df = pandas.concat([df_01, df_02], axis=1) df = concat([df_01, df_02], axis=1)
_filename = f'{path}\\s_{channel-5}\\j6_s_{channel-5}_{scenario_time}_{time()}.data' _filename = f'{path}\\s_{channel-5}\\j6_s_{channel-5}_{scenario_time}_{time()}.data'
df.to_csv(_filename, sep='\t', index=False) df.to_csv(_filename, sep='\t', index=False)
elif channel in list(range(9, 15)): elif channel in list(range(9, 15)):
@ -202,18 +170,21 @@ def data_proc_regular(path, filename, channel, scenario_time):
lines = f_obj.readlines() lines = f_obj.readlines()
_d2d_vel = {'hw_joint_vel_feedback': []} _d2d_vel = {'hw_joint_vel_feedback': []}
_d2d_trq = {'device_servo_trq_feedback': []} _d2d_trq = {'device_servo_trq_feedback': []}
for line in lines: for line in lines[-300:]: # 保留最后15s的数据
data = eval(line.strip())['data'] data = eval(line.strip())['data']
for item in data: for item in data:
try:
item['value'].reverse() item['value'].reverse()
except KeyError:
continue
if item.get('channel', None) == channel-9 and item.get('name', None) == 'hw_joint_vel_feedback': 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']) _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': 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']) _d2d_trq['device_servo_trq_feedback'].extend(item['value'])
df1 = pandas.DataFrame.from_dict(_d2d_vel) df1 = DataFrame.from_dict(_d2d_vel)
df2 = pandas.DataFrame.from_dict(_d2d_trq) df2 = DataFrame.from_dict(_d2d_trq)
df = pandas.concat([df1, df2], axis=1) df = concat([df1, df2], axis=1)
_filename = f'{path}\\single\\j{channel-8}_hold_{time()}.data' _filename = f'{path}\\single\\j{channel-8}_hold_{time()}.data'
df.to_csv(_filename, sep='\t', index=False) df.to_csv(_filename, sep='\t', index=False)
@ -226,15 +197,18 @@ def data_proc_inertia(path, filename, channel):
for line in lines: for line in lines:
data = eval(line.strip())['data'] data = eval(line.strip())['data']
for item in data: for item in data:
try:
item['value'].reverse() item['value'].reverse()
except KeyError:
continue
if item.get('channel', None) == channel+3 and item.get('name', None) == 'hw_joint_vel_feedback': 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']) _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': 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']) _d2d_trq['device_servo_trq_feedback'].extend(item['value'])
df1 = pandas.DataFrame.from_dict(_d2d_vel) df1 = DataFrame.from_dict(_d2d_vel)
df2 = pandas.DataFrame.from_dict(_d2d_trq) df2 = DataFrame.from_dict(_d2d_trq)
df = pandas.concat([df1, df2], axis=1) df = concat([df1, df2], axis=1)
_filename = f'{path}\\inertia\\j{channel+4}_inertia_{time()}.data' _filename = f'{path}\\inertia\\j{channel+4}_inertia_{time()}.data'
df.to_csv(_filename, sep='\t', index=False) df.to_csv(_filename, sep='\t', index=False)
@ -287,42 +261,39 @@ def run_rl(path, hr, md, loadsel, w2t):
conditions = c_inertia conditions = c_inertia
disc = disc_inertia disc = disc_inertia
for condition in conditions: # preparation 触发软急停,并解除,目的是让可能正在运行着的机器停下来
number = conditions.index(condition) clibs.execution('diagnosis.open', hr, w2t, tab_name, open=True, display_open=True)
w2t(f"正在执行{disc[number][0]}测试......", 0, 0, 'purple', 'Automatic Test') 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) # 这条命令有问题
# 1. 关闭诊断曲线,触发软急停,并解除,目的是让可能正在运行着的机器停下来,切手动模式并下电
_response = execution('diagnosis.open', hr, w2t, open=False, display_open=False)
md.trigger_estop() md.trigger_estop()
md.reset_estop() md.reset_estop()
md.write_act(False)
sleep(1) # 让曲线彻底关闭
_response = execution('state.switch_manual', hr, w2t)
_response = execution('state.switch_motor_off', hr, w2t)
# 2. 修改未要执行的场景 for condition in conditions:
number = conditions.index(condition)
w2t(f"正在执行{disc[number][0]}测试......", 0, 0, 'purple', tab_name)
# 1. 将act重置为False并修改未要执行的场景
md.write_act(False)
ssh = SSHClient() ssh = SSHClient()
ssh.set_missing_host_key_policy(AutoAddPolicy()) 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 = 'cd /home/luoshi/bin/controller/; '
cmd += 'sudo sed -i "/scenario/d" projects/target/_build/current/main.mod; ' 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' cmd += f'sudo sed -i "/DONOTDELETE/i {condition}" projects/target/_build/current/main.mod'
stdin, stdout, stderr = ssh.exec_command(cmd, get_pty=True) stdin, stdout, stderr = ssh.exec_command(cmd, get_pty=True)
stdin.write('luoshi2019' + '\n') stdin.write('luoshi2019' + '\n')
stdin.flush() stdout.read().decode() # 需要read一下才能正常执行
print(stdout.read().decode()) # 必须得输出一下stdout才能正确执行sudo stderr.read().decode()
print(stderr.read().decode()) # 顺便也执行以下stderr
# 3. reload工程后pp2main并且自动模式和上电 # 2. reload工程后pp2main并且自动模式和上电
prj_path = 'target/_build/target.prj' prj_path = 'target/_build/target.prj'
_response = execution('overview.reload', hr, w2t, prj_path=prj_path, tasks=['current']) clibs.execution('overview.reload', hr, w2t, tab_name, prj_path=prj_path, tasks=['current'])
_response = execution('overview.get_cur_prj', hr, w2t) clibs.execution('rl_task.pp_to_main', hr, w2t, tab_name, tasks=['current'])
_response = execution('rl_task.pp_to_main', hr, w2t, tasks=['current']) clibs.execution('state.switch_auto', hr, w2t, tab_name)
_response = execution('state.switch_auto', hr, w2t) clibs.execution('state.switch_motor_on', hr, w2t, tab_name)
_response = execution('state.switch_motor_on', hr, w2t)
# 4. 开始运行程序,单轴运行15s # 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() _t_start = time()
while True: while True:
if md.read_ready_to_go() == 1: if md.read_ready_to_go() == 1:
@ -330,29 +301,12 @@ def run_rl(path, hr, md, loadsel, w2t):
break break
else: else:
if (time() - _t_start) // 20 > 1: if (time() - _t_start) // 20 > 1:
w2t("20s内未收到机器人的运行信号需要确认RL程序编写正确并正常执行...", 0, 111, 'red', 'Automatic Test') w2t("20s内未收到机器人的运行信号需要确认RL程序编写正确并正常执行...", 0, 111, 'red', tab_name)
else: else:
sleep(1) sleep(1)
# 5. 打开诊断曲线,并执行采集 # 4. 打开诊断曲线,并执行采集
sleep(10) # 保证程序已经运行起来,其实主要是为了保持电流的采集而设定 sleep(10) # 保证程序已经运行起来,其实主要是为了保持电流的采集而设定
_response = execution('diagnosis.open', hr, w2t, open=True, display_open=True)
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},
]
_response = execution('diagnosis.set_params', hr, w2t, display_pdo_params=display_pdo_params)
scenario_time = 0 scenario_time = 0
if number < 6: if number < 6:
sleep(35) sleep(35)
@ -363,47 +317,39 @@ def run_rl(path, hr, md, loadsel, w2t):
while True: while True:
scenario_time = md.read_scenario_time() scenario_time = md.read_scenario_time()
if float(scenario_time) > 1: 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 break
else: else:
if (time()-_t_start)//60 > 3: 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: else:
sleep(5) sleep(5)
sleep(1) # 一定要延迟一秒再读一次scenario time寄存器因为一开始读取的数值不准确 sleep(1) # 一定要延迟一秒再读一次scenario time寄存器因为一开始读取的数值不准确
scenario_time = md.read_scenario_time() scenario_time = md.read_scenario_time()
sleep(float(scenario_time)*0.2) # 再运行周期的20%即可 sleep(float(scenario_time)*0.2) # 再运行周期的20%即可
# 6. 关闭诊断曲线,停止程序运行,下电并且换成手动模式 # 5.停止程序运行,保留数据并处理输出
_response = execution('diagnosis.open', hr, w2t, open=False, display_open=False) clibs.execution('rl_task.stop', hr, w2t, tab_name, tasks=['current'])
_response = execution('rl_task.stop', hr, w2t, tasks=['current']) _c_msg = hr.c_msg.copy()
_response = execution('state.switch_motor_off', hr, w2t) for _msg in _c_msg:
_response = execution('state.switch_manual', hr, w2t)
sleep(1) # 保证所有数据均已返回
# 7. 保留数据并处理输出
for _msg in hr.c_msg:
if 'diagnosis.result' in _msg: if 'diagnosis.result' in _msg:
disc[number][1].insert(0, loads(_msg)) disc[number][1].insert(0, loads(_msg))
else: else:
_index = 210
for _msg in hr.c_msg:
if 'diagnosis.result' in _msg:
_index = hr.c_msg.index(_msg)
break
del hr.c_msg[_index:]
hr.c_msg_xs.clear() 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) gen_result_file(path, loadsel, disc, number, scenario_time)
else: else:
if loadsel == 'tool100': if loadsel == 'tool100':
w2t("单轴和场景电机电流采集完毕,如需采集惯量负载,须切换负载类型,并更换惯量负载,重新执行。", 0, 0, 'green', 'Automatic Test') w2t("单轴和场景电机电流采集完毕,如需采集惯量负载,须切换负载类型,并更换惯量负载,重新执行。", 0, 0, 'green', tab_name)
elif loadsel == 'inertia': elif loadsel == 'inertia':
w2t("惯量负载电机电流采集完毕,如需采集单轴/场景/保持电机电流,须切换负载类型,并更换偏置负载,重新执行。", 0, 0, 'green', 'Automatic Test') w2t("惯量负载电机电流采集完毕,如需采集单轴/场景/保持电机电流,须切换负载类型,并更换偏置负载,重新执行。", 0, 0, 'green', tab_name)
def main(path, hr, md, loadsel, w2t): 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) 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) run_rl(path, hr, md, loadsel, w2t)

124
aio/code/commons/clibs.py Normal file
View File

@ -0,0 +1,124 @@
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)],
}
file_handler = ConcurrentRotatingFileHandler(filename=log_data, backupCount=10, maxBytes=50*1024*1024, encoding='utf-8')
file_handler.setLevel(INFO)
console_handler = StreamHandler()
console_handler.setLevel(WARNING)
basicConfig( # level=INFO,
datefmt='%Y-%m-%dT%H:%M:%S',
format='%(asctime)s # %(levelname)s-%(filename)s-%(funcName)s # %(message)s',
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')
stdout.read().decode() # 需要read一下才能正常执行
stderr.read().decode()
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')
stdout.read().decode() # 需要read一下才能正常执行
stderr.read().decode()
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])

View File

@ -1,17 +1,16 @@
from json import load, dumps, loads 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 from threading import Thread
import selectors import selectors
from time import time, sleep from time import time, sleep
from os.path import dirname
from pymodbus.client.tcp import ModbusTcpClient from pymodbus.client.tcp import ModbusTcpClient
from pymodbus.payload import BinaryPayloadDecoder, BinaryPayloadBuilder from pymodbus.payload import BinaryPayloadDecoder, BinaryPayloadBuilder
from pymodbus.constants import Endian from pymodbus.constants import Endian
from logging import getLogger, INFO
from commons import clibs
MAX_FRAME_SIZE = 1024 logger = getLogger(__file__)
setdefaulttimeout(2) logger.setLevel(INFO)
current_path = dirname(__file__)
heartbeat = f'{current_path}/../assets/templates/heartbeat'
class ModbusRequest(object): class ModbusRequest(object):
@ -19,20 +18,29 @@ class ModbusRequest(object):
super().__init__() super().__init__()
self.w2t = w2t self.w2t = w2t
self.tab_name = 'openapi' self.tab_name = 'openapi'
self.host = '192.168.0.160' self.host = clibs.ip_addr
self.port = 502 self.port = 502
self.interval = 0.3
self.c = ModbusTcpClient(self.host, self.port) self.c = ModbusTcpClient(self.host, self.port)
self.c.connect() self.c.connect()
def motor_off(self): def motor_off(self):
try: try:
self.c.write_register(40002, 0)
sleep(self.interval)
self.c.write_register(40002, 1) self.c.write_register(40002, 1)
sleep(self.interval)
self.c.write_register(40002, 0)
except Exception as Err: except Exception as Err:
self.w2t(f"{Err}\n无法正常下电连接Modbus失败需要确认网络是否通畅或是未正确导入寄存器文件...", 0, 100, 'red', self.tab_name) self.w2t(f"{Err}\n无法正常下电连接Modbus失败需要确认网络是否通畅或是未正确导入寄存器文件...", 0, 100, 'red', self.tab_name)
def motor_on(self): def motor_on(self):
try: try:
self.c.write_register(40003, 0)
sleep(self.interval)
self.c.write_register(40003, 1) self.c.write_register(40003, 1)
sleep(self.interval)
self.c.write_register(40003, 0)
except Exception as Err: except Exception as Err:
self.w2t(f"{Err}\n无法正常上电连接Modbus失败需要确认网络是否通畅或是未正确导入寄存器文件...", 0, 100, 'red', self.tab_name) self.w2t(f"{Err}\n无法正常上电连接Modbus失败需要确认网络是否通畅或是未正确导入寄存器文件...", 0, 100, 'red', self.tab_name)
@ -45,11 +53,11 @@ class ModbusRequest(object):
def reset_estop(self): def reset_estop(self):
try: try:
self.c.write_register(40012, 1) self.c.write_register(40012, 1)
sleep(0.2) sleep(self.interval)
self.c.write_register(40001, 0) self.c.write_register(40001, 0)
sleep(0.2) sleep(self.interval)
self.c.write_register(40001, 1) self.c.write_register(40001, 1)
sleep(0.2) sleep(self.interval)
self.c.write_register(40001, 0) self.c.write_register(40001, 0)
except Exception as Err: except Exception as Err:
self.w2t(f"{Err}\n无法重置软急停连接Modbus失败需要确认网络是否通畅或是未正确导入寄存器文件...", 0, 100, 'red', self.tab_name) self.w2t(f"{Err}\n无法重置软急停连接Modbus失败需要确认网络是否通畅或是未正确导入寄存器文件...", 0, 100, 'red', self.tab_name)
@ -186,21 +194,19 @@ class HmiRequest(object):
def sock_conn(self): def sock_conn(self):
# while True: # 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() c_state = f_hb.read().strip()
if c_state == '0': if c_state == '0':
try: try:
self.c = socket(AF_INET, SOCK_STREAM) self.c = socket(AF_INET, SOCK_STREAM)
self.c.connect(('192.168.0.160', 5050)) self.c.connect((clibs.ip_addr, 5050))
# self.c.connect(('192.168.84.129', 5050))
self.c.setblocking(False) self.c.setblocking(False)
self.c_xs = socket(AF_INET, SOCK_STREAM) self.c_xs = socket(AF_INET, SOCK_STREAM)
self.c_xs.connect(('192.168.0.160', 6666)) self.c_xs.connect((clibs.ip_addr, 6666))
# self.c_xs.connect(('192.168.84.129', 6666))
self.c_xs.setblocking(False) self.c_xs.setblocking(False)
self.w2t("Connection success", 0, 0, 'green', tab_name=self.tab_name) 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') f_hb.write('1')
md = ModbusRequest(self.w2t) md = ModbusRequest(self.w2t)
md.reset_estop() md.reset_estop()
@ -210,7 +216,7 @@ class HmiRequest(object):
md.write_axis(1) md.write_axis(1)
except Exception as Err: except Exception as Err:
self.w2t("Connection failed...", 0, 0, 'red', tab_name=self.tab_name) 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') f_hb.write('0')
def header_check(self, index, data): def header_check(self, index, data):
@ -238,31 +244,29 @@ class HmiRequest(object):
# print(f"in head check data: {data}") # print(f"in head check data: {data}")
self.broke = 100 self.broke = 100
index += MAX_FRAME_SIZE index += clibs.MAX_FRAME_SIZE
return index, 0, 0 return index, 0, 0
def heartbeat(self): def heartbeat(self):
while self.t_bool: while self.t_bool:
_id = self.execution('controller.heart') _id = self.execution('controller.heart')
_flag = '0' if self.get_from_id(_id) is None else '1' _flag = '0' if self.get_from_id(_id) is None else '1'
print(f"hb = {_flag}", end=' ') # print(f"hb = {_flag}", end=' ')
print(f"len(c_msg) = {len(self.c_msg)}", end=' ') # print(f"len(c_msg) = {len(self.c_msg)}", end=' ')
print(f"len(c_msg_xs) = {len(self.c_msg_xs)}", end='\n') # print(f"len(c_msg_xs) = {len(self.c_msg_xs)}", end='\n')
with open(heartbeat, "w", encoding='utf-8') as f_hb: with open(clibs.heartbeat, "w", encoding='utf-8') as f_hb:
f_hb.write(_flag) f_hb.write(_flag)
if _flag == '0': if _flag == '0':
self.w2t(f"{_id} 心跳丢失,连接失败,重新连接中...", 0, 7, 'red', tab_name=self.tab_name) self.w2t(f"{_id} 心跳丢失,连接失败,重新连接中...", 0, 7, 'red', tab_name=self.tab_name)
sleep(2) sleep(2)
# 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(loads(msg)) + '\n')
def msg_storage(self, response, flag=0): def msg_storage(self, response, flag=0):
# response是解码后的字符串 # response是解码后的字符串
messages = self.c_msg if flag == 0 else self.c_msg_xs messages = self.c_msg if flag == 0 else self.c_msg_xs
logger.info(f"{loads(response)}")
if 'move.monitor' in response: if 'move.monitor' in response:
pass pass
elif len(messages) < 20000: elif len(messages) < 10000:
messages.insert(0, response) messages.insert(0, response)
else: else:
messages.insert(0, response) messages.insert(0, response)
@ -306,7 +310,7 @@ class HmiRequest(object):
# print(f"broke == 0 index = {self.index-8}") # print(f"broke == 0 index = {self.index-8}")
# print(f"broke == 0 INIT pkg size = {self.pkg_size}") # print(f"broke == 0 INIT pkg size = {self.pkg_size}")
# print(f"broke == 0 data = {data}") # print(f"broke == 0 data = {data}")
if self.index > MAX_FRAME_SIZE: if self.index > clibs.MAX_FRAME_SIZE:
break break
# 详见解包原理数据.txtself.pkg_size 永远是除了当前data之外剩余未处理的数据大小 # 详见解包原理数据.txtself.pkg_size 永远是除了当前data之外剩余未处理的数据大小
if self.pkg_size <= len(data) - self.index: if self.pkg_size <= len(data) - self.index:
@ -350,15 +354,15 @@ class HmiRequest(object):
# print('flag = 0 encounter broke == 3') # print('flag = 0 encounter broke == 3')
self.broke = 3 self.broke = 3
self.index += MAX_FRAME_SIZE self.index += clibs.MAX_FRAME_SIZE
self.reset_index = 1 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): elif self.index+_frame_size-6 > len(data):
self.response = data[self.index:].decode() self.response = data[self.index:].decode()
self.pkg_size -= (len(data) - self.index) # 详见解包原理数据.txtself.pkg_size self.pkg_size -= (len(data) - self.index) # 详见解包原理数据.txtself.pkg_size
self.leftover = (_frame_size-6-(len(data)-self.index)) self.leftover = (_frame_size-6-(len(data)-self.index))
self.index += MAX_FRAME_SIZE self.index += clibs.MAX_FRAME_SIZE
self.reset_index = 1 self.reset_index = 1
# print(f"in flag=0 else data = {data}") # print(f"in flag=0 else data = {data}")
@ -427,9 +431,9 @@ class HmiRequest(object):
# print('flag = 1 encounter broke == 3') # print('flag = 1 encounter broke == 3')
self.broke = 3 self.broke = 3
self.index += MAX_FRAME_SIZE self.index += clibs.MAX_FRAME_SIZE
self.reset_index = 1 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 data = {data}")
# print(f"in pkg size > 0 loop after if index = {self.index}") # 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}") # print(f"in pkg size > 0 loop after if pkg size = {self.pkg_size}")
@ -446,7 +450,7 @@ class HmiRequest(object):
self.response += data[self.index:].decode() self.response += data[self.index:].decode()
self.leftover -= (len(data) - self.index) self.leftover -= (len(data) - self.index)
self.pkg_size -= (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 self.reset_index = 1
# print(f"in pkg size > 0 loop after else data = {data}") # print(f"in pkg size > 0 loop after else data = {data}")
# print(f"in pkg size > 0 loop after else index = {self.index}") # print(f"in pkg size > 0 loop after else index = {self.index}")
@ -500,14 +504,20 @@ class HmiRequest(object):
def get_from_id(self, msg_id, flag=0): def get_from_id(self, msg_id, flag=0):
for i in range(3): for i in range(3):
messages = self.c_msg if flag == 0 else self.c_msg_xs with open(clibs.log_data, mode='r', encoding='utf-8') as f_log:
for msg in messages: for line in f_log:
if msg_id is None: if msg_id in line.strip():
return None return line
elif msg_id in msg:
return msg
sleep(1) sleep(1)
else: 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 return None
def package(self, cmd): def package(self, cmd):
@ -522,7 +532,7 @@ class HmiRequest(object):
def unpackage(self, sock): def unpackage(self, sock):
def to_read(conn, mask): def to_read(conn, mask):
data = conn.recv(MAX_FRAME_SIZE) data = conn.recv(clibs.MAX_FRAME_SIZE)
if data: if data:
# print(data) # print(data)
self.get_response(data) self.get_response(data)
@ -569,7 +579,7 @@ class HmiRequest(object):
if flg == 0: # for old protocols if flg == 0: # for old protocols
req = None req = None
try: 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: mode='r') as f_json:
req = load(f_json) req = load(f_json)
except: except:
@ -595,6 +605,8 @@ class HmiRequest(object):
req['data']['type'] = kwargs['type'] req['data']['type'] = kwargs['type']
req['data']['bias'] = kwargs['bias'] req['data']['bias'] = kwargs['bias']
req['data']['value'] = kwargs['value'] req['data']['value'] = kwargs['value']
case 'diagnosis.save':
req['data']['save'] = kwargs['save']
case _: case _:
pass pass

View File

@ -1 +0,0 @@
__all__ = ['brake', 'current', 'iso', 'wavelogger']

View File

@ -1,49 +1,15 @@
# coding: utf-8 # coding: utf-8
from os import scandir from os.path import isfile
from os.path import isfile, exists
from sys import argv from sys import argv
from openpyxl import load_workbook from openpyxl import load_workbook
from time import time, sleep, strftime, localtime from time import time, sleep, strftime, localtime
from threading import Thread from threading import Thread
from pandas import read_csv from pandas import read_csv
from logging import getLogger, INFO
from commons import clibs
logger = getLogger(__file__)
class GetThreadResult(Thread): logger.setLevel(INFO)
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 check_files(path, raw_data_dirs, result_files, w2t): def check_files(path, raw_data_dirs, result_files, w2t):
@ -83,7 +49,7 @@ def check_files(path, raw_data_dirs, result_files, w2t):
规则解释AA/BB/CC 指的是臂展/负载/速度的比例例如reach66_load100_speed3366%臂展100%负载以及33%速度情况下的测试结果文件夹""" 规则解释AA/BB/CC 指的是臂展/负载/速度的比例例如reach66_load100_speed3366%臂展100%负载以及33%速度情况下的测试结果文件夹"""
w2t(msg, 0, 4, 'red') 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: if len(raw_data_files) != 3:
msg = f"数据目录 {raw_data_dir} 下数据文件个数错误,每个数据目录下有且只能有三个以 .data 为后缀的数据文件" msg = f"数据目录 {raw_data_dir} 下数据文件个数错误,每个数据目录下有且只能有三个以 .data 为后缀的数据文件"
w2t(msg, 0, 5, 'red') w2t(msg, 0, 5, 'red')
@ -109,6 +75,7 @@ def get_configs(configfile, w2t):
return av, rr return av, rr
def now_doing_msg(docs, flag, w2t): def now_doing_msg(docs, flag, w2t):
# 功能:输出正在处理的文件或目录 # 功能:输出正在处理的文件或目录
# 参数文件或目录start 或 done 标识 # 参数文件或目录start 或 done 标识
@ -228,7 +195,7 @@ def data_process(result_file, raw_data_dirs, av, rr, vel, trq, estop, w2t):
global stop global stop
stop = 0 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_wait = Thread(target=w2t_local, args=('.', 1, w2t))
t_excel.start() t_excel.start()
t_wait.start() t_wait.start()
@ -242,7 +209,7 @@ def data_process(result_file, raw_data_dirs, av, rr, vel, trq, estop, w2t):
for raw_data_dir in raw_data_dirs: for raw_data_dir in raw_data_dirs:
if raw_data_dir.split('\\')[-1].split('_')[0] == prefix: if raw_data_dir.split('\\')[-1].split('_')[0] == prefix:
now_doing_msg(raw_data_dir, 'start', w2t) 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 # count = 1
# for data_file in data_files: # for data_file in data_files:
@ -280,7 +247,7 @@ def main(path, vel, trq, estop, w2t):
# 参数initialization函数的返回值 # 参数initialization函数的返回值
# 返回值:- # 返回值:-
time_start = time() time_start = time()
raw_data_dirs, result_files = traversal_files(path, w2t) raw_data_dirs, result_files = clibs.traversal_files(path, w2t)
try: try:
# threads = [] # threads = []

View File

@ -1,31 +1,15 @@
from openpyxl import load_workbook from openpyxl import load_workbook
from os import scandir
from os.path import exists
from sys import argv from sys import argv
from pandas import read_csv, concat, set_option from pandas import read_csv, concat, set_option
from re import match from re import match
from threading import Thread from threading import Thread
from time import sleep from time import sleep
from csv import reader, writer from csv import reader, writer
from logging import getLogger, INFO
from commons import clibs
logger = getLogger(__file__)
class GetThreadResult(Thread): logger.setLevel(INFO)
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 w2t_local(msg, wait, w2t): def w2t_local(msg, wait, w2t):
@ -38,27 +22,8 @@ def w2t_local(msg, wait, w2t):
break 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): def initialization(path, sub, w2t):
_, data_files = traversal_files(path, w2t) _, data_files = clibs.traversal_files(path, w2t)
count = 0 count = 0
for data_file in data_files: for data_file in data_files:
@ -69,8 +34,8 @@ def initialization(path, sub, w2t):
count += 1 count += 1
else: else:
if not (match('j[1-7].*\\.data', filename) or match('j[1-7].*\\.csv', filename)): if not (match('j[1-7].*\\.data', filename) or match('j[1-7].*\\.csv', filename)):
print(f"不合规 {data_file}") msg = f"不合规 {data_file}\n"
msg = f"所有文件必须以 jx_ 开头,以 .data/csv 结尾x取值1-7请检查后重新运行。" msg += f"所有文件必须以 jx_ 开头,以 .data/csv 结尾x取值1-7请检查后重新运行。"
w2t(msg, 0, 6, 'red') w2t(msg, 0, 6, 'red')
if not ((sub == 'cycle' and count == 2) or (sub != 'cycle' and count == 1)): if not ((sub == 'cycle' and count == 2) or (sub != 'cycle' and count == 1)):
@ -174,7 +139,7 @@ def current_cycle(dur, data_files, rcs, rrs, vel, trq, trqh, rpms, w2t):
w2t(f"正在打开文件 {result},需要 10s 左右", 1, 0, 'orange') w2t(f"正在打开文件 {result},需要 10s 左右", 1, 0, 'orange')
global stop global stop
stop = 0 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_wait = Thread(target=w2t_local, args=('.', 1, w2t))
t_excel.start() t_excel.start()
t_wait.start() t_wait.start()
@ -189,7 +154,7 @@ def current_cycle(dur, data_files, rcs, rrs, vel, trq, trqh, rpms, w2t):
for axis, cur_value in avg.items(): for axis, cur_value in avg.items():
try: try:
shtname = f"J{axis}" shtname = f"J{axis}"
wb[shtname]["J4"].value = float(cur_value) wb[shtname]["J4"].value = float(cur_value[0])
except: except:
pass pass
@ -268,7 +233,7 @@ def p_single(wb, single, vel, trq, rpms, rrs, w2t):
col_names = list(df.columns) col_names = list(df.columns)
df_1 = df[col_names[vel-1]].multiply(rpm*addition) df_1 = df[col_names[vel-1]].multiply(rpm*addition)
df_2 = df[col_names[trq-1]].multiply(scale) 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) df = concat([df_1, df_2], axis=1)
_step = 5 if data_file.endswith('.csv') else 50 _step = 5 if data_file.endswith('.csv') else 50

View File

@ -1,27 +1,13 @@
# _*_ encodingutf-8 _*_ # _*_ encodingutf-8 _*_
import pdfplumber import pdfplumber
from openpyxl import load_workbook from openpyxl import load_workbook
from os import scandir, remove from os import remove
from os.path import exists
from sys import argv from sys import argv
from logging import getLogger, INFO
from commons import clibs
logger = getLogger(__file__)
def traversal_files(path, w2t): logger.setLevel(INFO)
# 功能:以列表的形式分别返回指定路径下的文件和文件夹,不包含子目录
# 参数:路径
# 返回值:路径下的文件夹列表 路径下的文件列表
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 p_iso(file, p_files, ws, tmpfile): def p_iso(file, p_files, ws, tmpfile):
@ -153,7 +139,7 @@ def p_iso_1000(file, p_files, ws, tmpfile):
def main(path, w2t): def main(path, w2t):
dirs, files = traversal_files(path, 1) dirs, files = clibs.traversal_files(path, 1)
try: try:
wb = load_workbook(path + "/iso-results.xlsx") wb = load_workbook(path + "/iso-results.xlsx")

View File

@ -1,31 +1,12 @@
import os
import random
from pandas import read_csv from pandas import read_csv
from csv import reader from csv import reader
from sys import argv from sys import argv
from os.path import exists
from os import scandir, remove
from openpyxl import Workbook from openpyxl import Workbook
from random import randint from logging import getLogger, INFO
from commons import clibs
def traversal_files(path, w2t): logger = getLogger(__file__)
# 功能:以列表的形式分别返回指定路径下的文件和文件夹,不包含子目录 logger.setLevel(INFO)
# 参数:路径
# 返回值:路径下的文件夹列表 路径下的文件列表
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 find_point(bof, step, pos, data_file, flag, df, row, w2t): def find_point(bof, step, pos, data_file, flag, df, row, w2t):
@ -95,7 +76,7 @@ def get_cycle_info(data_file, df, row, step, w2t):
def initialization(path, w2t): def initialization(path, w2t):
_, data_files = traversal_files(path, w2t) _, data_files = clibs.traversal_files(path, w2t)
for data_file in data_files: for data_file in data_files:
if not data_file.lower().endswith('.csv'): if not data_file.lower().endswith('.csv'):
@ -126,7 +107,7 @@ def single_file_proc(ws, data_file, df, low, high, cycle, w2t):
_step = 5 _step = 5
_data = {} _data = {}
row_max = df.index[-1]-100 row_max = df.index[-1]-100
print(data_file) # print(data_file)
while _row < row_max: while _row < row_max:
if count not in _data.keys(): if count not in _data.keys():
_data[count] = [] _data[count] = []
@ -149,7 +130,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=1, column=i).value = f"{i-1}次测试"
ws.cell(row=i, column=1).value = f"{i-1}次精度变化" ws.cell(row=i, column=1).value = f"{i-1}次精度变化"
print(_data) # print(_data)
for i in sorted(_data.keys()): for i in sorted(_data.keys()):
_row = 2 _row = 2
_column = i + 1 _column = i + 1
@ -162,9 +143,9 @@ def execution(data_files, w2t):
wb = Workbook() wb = Workbook()
for data_file in data_files: for data_file in data_files:
ws, df, low, high, cycle = preparation(data_file, wb, w2t) ws, df, low, high, cycle = preparation(data_file, wb, w2t)
print(f"low = {low}") # print(f"low = {low}")
print(f"high = {high}") # print(f"high = {high}")
print(f"cycle = {cycle}") # print(f"cycle = {cycle}")
single_file_proc(ws, data_file, df, low, high, cycle, w2t) single_file_proc(ws, data_file, df, low, high, cycle, w2t)
wd = data_files[0].split('\\') wd = data_files[0].split('\\')

View File

@ -1 +0,0 @@
__all__ = ['factory_test']

View File

@ -1,23 +1,26 @@
from sys import argv from sys import argv
from os.path import exists, dirname
from os import scandir
from paramiko import SSHClient, AutoAddPolicy
from json import loads from json import loads
from time import sleep, time from time import sleep, time, strftime, localtime
import pandas as pd from pandas import DataFrame
from openpyxl import load_workbook from openpyxl import load_workbook
from math import sqrt from math import sqrt
from numpy import power
from csv import writer
from logging import getLogger, INFO
from commons import clibs
tab_name = 'Durable Action' logger = getLogger(__file__)
durable_data_current_xlsx = f'{dirname(__file__)}/../../assets/templates/durable/durable_data_current.xlsx' logger.setLevel(INFO)
durable_data_velocity_xlsx = f'{dirname(__file__)}/../../assets/templates/durable/durable_data_velocity.xlsx'
tab_name = clibs.tab_names['da']
count = 0
display_pdo_params = [ display_pdo_params = [
{"name": "hw_joint_vel_feedback", "channel": 0}, # {"name": "hw_joint_vel_feedback", "channel": 0},
{"name": "hw_joint_vel_feedback", "channel": 1}, # {"name": "hw_joint_vel_feedback", "channel": 1},
{"name": "hw_joint_vel_feedback", "channel": 2}, # {"name": "hw_joint_vel_feedback", "channel": 2},
{"name": "hw_joint_vel_feedback", "channel": 3}, # {"name": "hw_joint_vel_feedback", "channel": 3},
{"name": "hw_joint_vel_feedback", "channel": 4}, # {"name": "hw_joint_vel_feedback", "channel": 4},
{"name": "hw_joint_vel_feedback", "channel": 5}, # {"name": "hw_joint_vel_feedback", "channel": 5},
{"name": "device_servo_trq_feedback", "channel": 0}, {"name": "device_servo_trq_feedback", "channel": 0},
{"name": "device_servo_trq_feedback", "channel": 1}, {"name": "device_servo_trq_feedback", "channel": 1},
{"name": "device_servo_trq_feedback", "channel": 2}, {"name": "device_servo_trq_feedback", "channel": 2},
@ -25,119 +28,43 @@ display_pdo_params = [
{"name": "device_servo_trq_feedback", "channel": 4}, {"name": "device_servo_trq_feedback", "channel": 4},
{"name": "device_servo_trq_feedback", "channel": 5}, {"name": "device_servo_trq_feedback", "channel": 5},
] ]
durable_data_current = { title = [
'time': list(range(1, 26)), 'time', 'trq-1', 'trq-2', 'trq-3', 'trq-4', 'trq-5', 'trq-6', 'trq-max-1', 'trq-max-2', 'trq-max-3', 'trq-max-4',
'axis1': [0 for _ in range(25)], 'trq-max-5', 'trq-max-6'
'axis2': [0 for _ in range(25)], ]
'axis3': [0 for _ in range(25)],
'axis4': [0 for _ in range(25)],
'axis5': [0 for _ in range(25)],
'axis6': [0 for _ in range(25)],
}
durable_data_velocity = {
'time': list(range(1, 26)),
'axis1': [0 for _ in range(25)],
'axis2': [0 for _ in range(25)],
'axis3': [0 for _ in range(25)],
'axis4': [0 for _ in range(25)],
'axis5': [0 for _ in range(25)],
'axis6': [0 for _ in range(25)],
}
data_all = [durable_data_current, durable_data_velocity]
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): def check_files(data_dirs, data_files, w2t):
if len(data_dirs) != 0 or len(data_files) != 2: if len(data_dirs) != 0 or len(data_files) != 2:
w2t('初始路径下不允许有文件夹,且初始路径下只能存在如下文件,确认后重新运行!\n1. target.zip\n2.configs.xlsx', 0, w2t('初始路径下不允许有文件夹,且初始路径下只能存在如下文件,确认后重新运行!\n1. target.zip\n2. configs.xlsx', 0, 10, 'red', tab_name)
10, 'red', tab_name)
_files = [data_files[0].split('\\')[-1], data_files[1].split('\\')[-1]] _files = [data_files[0].split('\\')[-1], data_files[1].split('\\')[-1]]
_files.sort() _files.sort()
if _files != ['configs.xlsx', 'target.zip']: if _files != ['configs.xlsx', 'target.zip']:
w2t('初始路径下只能存在如下文件,确认后重新运行!\n1. target.zip\n2.configs.xlsx', 0, 10, 'red', tab_name) w2t('初始路径下只能存在如下文件,确认后重新运行!\n1. target.zip\n2. configs.xlsx', 0, 10, 'red', tab_name)
data_files.sort() data_files.sort()
return data_files return data_files
def prj_to_xcore(prj_file): def run_rl(path, config_file, data_all, hr, md, w2t):
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
_prj_name = prj_file.split('\\')[-1].removesuffix('.zip')
cmd = 'cd /home/luoshi/bin/controller/; '
cmd += f'sudo mv projects/target/_build/{_prj_name}.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, hr, md, w2t):
# 1. 关闭诊断曲线,触发软急停,并解除,目的是让可能正在运行着的机器停下来,切手动模式并下电 # 1. 关闭诊断曲线,触发软急停,并解除,目的是让可能正在运行着的机器停下来,切手动模式并下电
_response = execution('diagnosis.open', hr, w2t, open=False, display_open=False) clibs.execution('diagnosis.open', hr, w2t, tab_name, open=True, display_open=True)
_response = execution('diagnosis.set_params', hr, w2t, display_pdo_params=[]) clibs.execution('diagnosis.set_params', hr, w2t, tab_name, display_pdo_params=display_pdo_params)
md.trigger_estop() md.trigger_estop()
md.reset_estop() md.reset_estop()
md.write_act(False) md.write_act(False)
sleep(1) # 让曲线彻底关闭 sleep(1) # 让曲线彻底关闭
_response = execution('state.switch_manual', hr, w2t)
_response = execution('state.switch_motor_off', hr, w2t)
# 2. reload工程后pp2main并且自动模式和上电 # 2. reload工程后pp2main并且自动模式和上电
prj_path = 'target/_build/target.prj' prj_path = 'target/_build/target.prj'
_response = execution('overview.reload', hr, w2t, prj_path=prj_path, tasks=['current']) clibs.execution('overview.reload', hr, w2t, tab_name, prj_path=prj_path, tasks=['current'])
_response = execution('overview.get_cur_prj', hr, w2t) clibs.execution('rl_task.pp_to_main', hr, w2t, tab_name, tasks=['current'])
_response = execution('rl_task.pp_to_main', hr, w2t, tasks=['current']) clibs.execution('state.switch_auto', hr, w2t, tab_name)
_response = execution('state.switch_auto', hr, w2t) clibs.execution('state.switch_motor_on', hr, w2t, tab_name)
_response = execution('state.switch_motor_on', hr, w2t)
# 3. 开始运行程序 # 3. 开始运行程序
_response = execution('rl_task.run', hr, w2t, tasks=['current']) clibs.execution('rl_task.run', hr, w2t, tab_name, tasks=['current'])
_t_start = time() _t_start = time()
while True: while True:
if md.read_ready_to_go() == 1: if md.read_ready_to_go() == 1:
@ -150,13 +77,12 @@ def run_rl(path, config_file, hr, md, w2t):
sleep(1) sleep(1)
# 4. 获取初始数据,周期时间,首次的各轴平均电流值,打开诊断曲线,并执行采集 # 4. 获取初始数据,周期时间,首次的各轴平均电流值,打开诊断曲线,并执行采集
_response = execution('diagnosis.open', hr, w2t, open=True, display_open=True) sleep(20) # 初始化 scenario time 为 0
_response = execution('diagnosis.set_params', hr, w2t, display_pdo_params=display_pdo_params)
_t_start = time() _t_start = time()
while True: while True:
scenario_time = md.read_scenario_time() scenario_time = md.read_scenario_time()
if float(scenario_time) > 1: if float(scenario_time) > 1:
w2t(f"场景的周期时间:{scenario_time}", 0, 0, 'green', tab_name) w2t(f"场景的周期时间:{scenario_time}s", 0, 0, 'green', tab_name)
break break
else: else:
if (time() - _t_start) // 60 > 3: if (time() - _t_start) // 60 > 3:
@ -165,114 +91,136 @@ def run_rl(path, config_file, hr, md, w2t):
sleep(5) sleep(5)
sleep(1) # 一定要延迟一秒再读一次scenario time寄存器因为一开始读取的数值不准确 sleep(1) # 一定要延迟一秒再读一次scenario time寄存器因为一开始读取的数值不准确
scenario_time = float(md.read_scenario_time()) scenario_time = float(md.read_scenario_time())
sleep(scenario_time * 0.2) # 再运行周期的20%即可 sleep(scenario_time*0.2)
# 6. 关闭诊断曲线,停止程序运行,下电并且换成手动模式
_response = execution('diagnosis.open', hr, w2t, open=False, display_open=False)
_response = execution('diagnosis.set_params', hr, w2t, display_pdo_params=[])
_response = execution('rl_task.stop', hr, w2t, tasks=['current'])
sleep(1) # 保证所有数据均已返回
# 7. 保留数据并处理输出
get_durable_data(path, config_file, data_all, scenario_time, hr, w2t)
# 8. 继续运行
_response = execution('rl_task.run', hr, w2t, tasks=['current'])
while True:
# 每3分钟更新一次数据打开曲线获取周期内电流关闭曲线
sleep(180)
_response = execution('diagnosis.open', hr, w2t, open=True, display_open=True)
_response = execution('diagnosis.set_params', hr, w2t, display_pdo_params=display_pdo_params)
sleep(scenario_time + 10)
_response = execution('diagnosis.open', hr, w2t, open=False, display_open=False)
_response = execution('diagnosis.set_params', hr, w2t, display_pdo_params=[])
# 7. 保留数据并处理输出
get_durable_data(path, config_file, data_all, scenario_time, hr, w2t)
def get_durable_data(path, config_file, data, scenario_time, hr, w2t):
_data_list = []
for _msg in hr.c_msg:
if 'diagnosis.result' in _msg:
_data_list.insert(0, loads(_msg))
else:
_index = 210
for _msg in hr.c_msg:
if 'diagnosis.result' in _msg:
_index = hr.c_msg.index(_msg)
break
del hr.c_msg[_index:]
hr.c_msg_xs.clear()
# with open('log.txt', 'w', encoding='utf-8') as f_obj:
# for _ in _data_list:
# f_obj.write(f"{_}\n")
# 6. 准备初始数据,关闭诊断曲线,保留数据并处理输出
with open(f'{path}\\results.csv', mode='a+', newline='') as f_csv:
csv_writer = writer(f_csv)
csv_writer.writerow(title)
_wb = load_workbook(config_file, read_only=True) _wb = load_workbook(config_file, read_only=True)
_ws = _wb['Target'] _ws = _wb['Target']
wait_time = float(_ws.cell(row=2, column=10).value)
rcs = [] rcs = []
for i in range(6): for i in range(6):
rcs.append(float(_ws.cell(row=6, column=i + 2).value)) rcs.append(float(_ws.cell(row=6, column=i + 2).value))
_d2d_trq = { get_durable_data(path, data_all, scenario_time, wait_time, rcs, hr, md, w2t)
'device_servo_trq_feedback_0': [], 'device_servo_trq_feedback_1': [], 'device_servo_trq_feedback_2': [],
'device_servo_trq_feedback_3': [], 'device_servo_trq_feedback_4': [], 'device_servo_trq_feedback_5': [], # 7. 继续运行
} while True:
_d2d_vel = { # 固定间隔,更新一次数据,打开曲线,获取周期内电流,关闭曲线
'hw_joint_vel_feedback_0': [], 'hw_joint_vel_feedback_1': [], 'hw_joint_vel_feedback_2': [], sleep(wait_time+scenario_time+7)
'hw_joint_vel_feedback_3': [], 'hw_joint_vel_feedback_4': [], 'hw_joint_vel_feedback_5': [], # 保留数据并处理输出
} get_durable_data(path, data_all, scenario_time, wait_time, rcs, hr, md, w2t)
def get_durable_data(path, data, scenario_time, wait_time, rcs, hr, md, w2t):
_data_list = []
_c_msg = hr.c_msg.copy()
for _msg in _c_msg:
if 'diagnosis.result' in _msg:
_data_list.insert(0, loads(_msg))
else:
hr.c_msg_xs.clear()
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:
# f_obj.write(f"{_}\n")
_d2d_trq = {0: [], 1: [], 2: [], 3: [], 4: [], 5: []}
for line in _data_list: for line in _data_list:
for item in line['data']: for item in line['data']:
for i in range(6): for i in range(6):
item['value'].reverse() item['value'].reverse()
if item.get('channel', None) == i and item.get('name', None) == 'device_servo_trq_feedback': if item.get('channel', None) == i and item.get('name', None) == 'device_servo_trq_feedback':
_d2d_trq[f'device_servo_trq_feedback_{i}'].extend(item['value']) _d2d_trq[i].extend(item['value'])
elif item.get('channel', None) == i and item.get('name', None) == 'hw_joint_vel_feedback':
_d2d_vel[f'hw_joint_vel_feedback_{i}'].extend(item['value'])
if len(_d2d_trq['device_servo_trq_feedback_0']) / 1000 > scenario_time + 1: if len(_d2d_trq[0]) / 1000 > scenario_time + 1:
_df = pd.DataFrame(_d2d_trq) this_time = strftime("%Y-%m-%d %H:%M:%S", localtime(time()))
next_time = strftime("%Y-%m-%d %H:%M:%S", localtime(time()+wait_time+10+scenario_time)).split()[-1]
_df = DataFrame(_d2d_trq)
_flg = 0
_res = []
for i in range(6): for i in range(6):
_ = sqrt(_df[f'device_servo_trq_feedback_{i}'].apply(lambda x: (rcs[i]*x/1000)**2).sum()/len(_df[f'device_servo_trq_feedback_{i}'])) def overmax_data(df, index, number, flag):
if number > 100:
md.trigger_estop()
hr.durable_quit = 1
df.to_excel(f'{path}\\{this_time}.xlsx')
w2t(f"[{this_time}] {flag}-axis-{index} 数据过大错误,需要检查确定。", 0, 10, 'red', tab_name)
try:
_ = sqrt(_df[i].apply(lambda x: power((rcs[i]*x/1000), 2)).sum()/len(_df[i]))
except:
md.trigger_estop()
_df.to_excel(path+"\\err_data.xlsx")
w2t(f"{i}calculate error", 0, 11, 'red', tab_name)
if not _flg:
del data[0]['time'][0]
data[0]['time'].append(this_time.split()[-1])
del data[1]['time'][0]
data[1]['time'].append(this_time.split()[-1])
_res.append(this_time)
_flg = 1
del data[0][f"axis{i + 1}"][0] del data[0][f"axis{i + 1}"][0]
overmax_data(_df, i, _, 'trq')
data[0][f"axis{i + 1}"].append(_) data[0][f"axis{i + 1}"].append(_)
_df = pd.DataFrame(data[0]) _res.append(_)
while True:
if not hr.durable_lock:
hr.durable_lock = 1
_df.to_excel(durable_data_current_xlsx, index=False)
hr.durable_lock = 0
break
else:
sleep(1)
_df = pd.DataFrame(_d2d_vel) _ = rcs[i] * _df[i].abs().max() / 1000
for i in range(6): overmax_data(_df, i, _, 'trq-max')
_ = sqrt(_df[f'hw_joint_vel_feedback_{i}'].apply(lambda x: (rcs[i]*x/1000)**2).sum()/len(_df[f'hw_joint_vel_feedback_{i}']))
del data[1][f"axis{i + 1}"][0] del data[1][f"axis{i + 1}"][0]
data[1][f"axis{i + 1}"].append(_) data[1][f"axis{i + 1}"].append(_)
_df = pd.DataFrame(data[1]) _res.append(_)
_df_1 = DataFrame(data[0])
_df_2 = DataFrame(data[1])
with open(f'{path}\\results.csv', mode='a+', newline='') as f_csv:
def change_order(res):
_time = res[0:1]
_trq = []
_trq_max = []
for _item in res[1::2]:
_trq.append(_item)
for _item in res[2::2]:
_trq_max.append(_item)
return _time + _trq + _trq_max
csv_writer = writer(f_csv)
csv_writer.writerow(change_order(_res))
while True: while True:
if not hr.durable_lock: if not hr.durable_lock:
hr.durable_lock = 1 hr.durable_lock = 1
_df.to_excel(durable_data_velocity_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 hr.durable_lock = 0
break break
else: else:
sleep(1) sleep(1)
global count
count += 1
w2t(f"[{this_time}] 当前次数:{count:09d} | 预计下次数据更新时间:{next_time}", 0, 0, '#008B8B', tab_name)
break break
else: else:
md.trigger_estop()
with open(f'{path}\\device_servo_trq_feedback_0.txt', 'w', encoding='utf-8') as f_obj: with open(f'{path}\\device_servo_trq_feedback_0.txt', 'w', encoding='utf-8') as f_obj:
for _ in _d2d_trq['device_servo_trq_feedback_0']: for _ in _d2d_trq[0]:
f_obj.write(f"{_}\n") f_obj.write(f"{_}\n")
w2t("采集的数据时间长度不够,需要确认。", 0, 2, 'red', tab_name) w2t("采集的数据时间长度不够,需要确认。", 0, 10, 'red', tab_name)
def main(path, hr, md, w2t): def main(path, hr, md, w2t):
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) 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, hr, md, w2t) run_rl(path, config_file, data_all, hr, md, w2t)
if __name__ == '__main__': if __name__ == '__main__':