Compare commits
13 Commits
wavelogger
...
8975d8a37c
Author | SHA1 | Date | |
---|---|---|---|
8975d8a37c | |||
14f269b570 | |||
2917f4ae97 | |||
d04d90f1a7 | |||
284dabee76 | |||
0646ae13de | |||
c3dbb2cff0 | |||
780fed29af | |||
4ba8af842c | |||
a0fe9b5939 | |||
2f2f0d430d | |||
78a79e4aa0 | |||
a1b45bf941 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@ aio/.idea/
|
|||||||
aio/code/__pycache__/
|
aio/code/__pycache__/
|
||||||
aio/package/
|
aio/package/
|
||||||
aio/venv
|
aio/venv
|
||||||
|
aio/__pycache__/
|
190
aio/README.md
190
aio/README.md
@ -1,91 +1,101 @@
|
|||||||
### 程序功能
|
### 一、程序功能
|
||||||
|
|
||||||
自动化测试数据处理工具,减少人工处理时长,提高测试数据处理的效率和准确度:
|
自动化测试数据处理工具,减少人工处理时长,提高测试数据处理的效率和准确度:
|
||||||
1. 制动数据,单轴数据处理3min以内
|
|
||||||
2. 电机电流数据,全部轴数据处理1min以内
|
|
||||||
3. ISO激光数据整理,1min以内
|
|
||||||
4. wavelogger波形处理,几乎不花费时间
|
|
||||||
|
|
||||||
### 使用方法
|
1. 制动数据,单轴数据处理 3min 以内
|
||||||
|
2. 电机电流数据,全部轴数据处理 1min 以内
|
||||||
|
3. ISO 激光数据整理,1min 以内
|
||||||
|
4. wavelogger 波形处理,几乎不花费时间
|
||||||
|
|
||||||
点击可执行程序 AIO.exe,然后选择功能,根据提示填写必要参数,点击运行即可
|
---
|
||||||
|
|
||||||
### 第三方库
|
### 二、使用方法
|
||||||
|
|
||||||
|
点击可执行程序 AIO.exe,然后选择功能,根据提示填写必要参数,红色标签提示是必填项,蓝色标签提示是可选项,然后点击运行即可
|
||||||
|
|
||||||
|
> 需要注意的是,可选项填写的不合适,有可能导致数据错误,或者无法运行!!
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 三、第三方库
|
||||||
|
|
||||||
```text
|
```text
|
||||||
参考requirements.txt
|
参考 requirements.txt
|
||||||
```
|
|
||||||
|
|
||||||
### 打包方法
|
|
||||||
|
|
||||||
```
|
|
||||||
pyinstaller.exe -F --version-file file_version_info.txt -i .\icon.ico .\aio.py -p .\brake.py -p .\current.py
|
|
||||||
pyinstaller --noconfirm --onedir --windowed --add-data "C:/Users/Administrator/AppData/Local/Programs/Python/Python312/Lib/site-packages/customtkinter;customtkinter/" --version-file ..\assets\file_version_info.txt -i ..\assets\icon.ico ..\code\aio.py -p ..\code\brake.py -p ..\code\iso.py -p ..\code\current.py -p ..\code\wavelogger.py
|
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 注意事项
|
### 四、打包方法
|
||||||
|
|
||||||
#### 制动数据
|
```
|
||||||
|
pyinstaller.exe -F --version-file file_version_info.txt -i .\icon.ico .\aio.py -p .\brake.py -p .\current.py
|
||||||
|
pyinstaller --noconfirm --onedir --windowed --add-data "C:/Users/Administrator/AppData/Local/Programs/Python/Python312/Lib/site-packages/customtkinter;customtkinter/" --version-file ..\assets\file_version_info.txt -i ..\assets\icon.ico ..\code\aio.py -p ..\code\data_process\brake.py -p ..\code\data_process\iso.py -p ..\code\data_process\current.py -p ..\code\data_process\wavelogger.py
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 五、注意事项
|
||||||
|
|
||||||
|
#### 1) 制动数据
|
||||||
|
|
||||||
```text
|
```text
|
||||||
1. 数据文件存储存储规则
|
1. 数据文件存储存储规则
|
||||||
数据文件,就是我们拍急停的时候,采集到的 .data 文件,正方向拍三次急停,会采集到三个 .data 文件,存储在同一个文件夹内,即每组(三个 .data 文件)文件必须存储在同一个文件夹内,数据文件的命名无要求,
|
数据文件,就是我们拍急停的时候,采集到的 .data 文件,根据规则选择某个方向拍三次急停,会采集到三个 .data 文件,存储在同一个文件夹内,即每组(三个 .data 文件)文件必须存储在同一个文件夹内,数据文件的命名无要求
|
||||||
|
|
||||||
2. 文件夹命名规则
|
2. 文件夹命名规则
|
||||||
采集到的 .data 文件没有命名要求,但是对于文件夹的命名是有要求的,必须是如下格式:
|
对采集到的 .data 文件没有命名要求,但是对于其存储的文件夹的命名是有要求的,必须是如下格式:
|
||||||
dXX_speedXX_reachXX 或者 loadXX_reachXX_speedXX
|
reachXX_loadXX_speedXX
|
||||||
XX代表不同条件下的测试数值,比如:
|
XX代表不同条件下的测试数值,比如:
|
||||||
d100_speed33_reach66,指的是,负载100%,速度33%,臂展66%
|
reach100_load66_speed33,指的是,臂展100%,负载66%,速度33%
|
||||||
|
|
||||||
3. 结果文件命名规则
|
3. 结果文件命名规则
|
||||||
所谓结果文件,就是处理数据的那个 excle 文件,该文件名字的前缀必须是 loadXX_XXXXXXXXX.xlsx,比如:
|
所谓结果文件,就是处理数据的那个 excle 文件,该文件名字的前缀必须是 reachXX_XXXXXXXXX.xlsx,比如:
|
||||||
load33_自研_制动性能测试.xlsx
|
reach33_自研_制动性能测试.xlsx
|
||||||
load66_自研_制动性能测试.xlsx
|
reach66_自研_制动性能测试.xlsx
|
||||||
load100_自研_制动性能测试.xlsx
|
reach100_自研_制动性能测试.xlsx
|
||||||
|
|
||||||
!!结果文件可以是没有数据的,也可以是之前有数据的,只要保证第 6 点中的那几个数据准确即可
|
!!结果文件可以是没有数据的,也可以是之前有数据的,只要保证输入参数的正确性即可
|
||||||
|
|
||||||
4. 数据存储的组织结
|
4. 数据存储的组织结
|
||||||
..../j1/load100_speed33_reach100
|
..../j1/reach100_load66_speed33
|
||||||
..../j1/load100_speed66_reach100
|
..../j1/reach100_load66_speed66
|
||||||
....
|
....
|
||||||
..../j1/load100_speed100_reach100
|
..../j1/reach100_load33_speed33
|
||||||
..../j1/load100_speed33_reach100/2024_05_16_09_18_52.data
|
..../j1/reach100_load100_speed33/2024_05_16_09_18_52.data
|
||||||
..../j1/load100_speed33_reach100/2024_05_16_09_19_52.data
|
..../j1/reach100_load100_speed33/2024_05_16_09_19_52.data
|
||||||
..../j1/load100_speed33_reach100/2024_05_16_09_20_52.data
|
..../j1/reach100_load100_speed33/2024_05_16_09_20_52.data
|
||||||
..../j1/load33_自研_制动性能测试.xlsx
|
..../j1/reach33_自研_制动性能测试.xlsx
|
||||||
..../j1/load66_自研_制动性能测试.xlsx
|
..../j1/reach66_自研_制动性能测试.xlsx
|
||||||
..../j1/load100_自研_制动性能测试.xlsx
|
..../j1/reach100_自研_制动性能测试.xlsx
|
||||||
|
|
||||||
5. 文件的打开与关闭
|
5. 文件的打开与关闭
|
||||||
a. 在执行程序之前,需要关闭所有相关 excle 文件
|
a. 在执行程序之前,需要关闭所有相关 excle 文件
|
||||||
b. 在执行程序之中,不允许打开相关 excle 文件
|
b. 在执行程序之中,不允许打开相关 excle 文件
|
||||||
c. 在执行程序之后,需要逐个打开结果文件,并保存一次
|
c. 在执行程序之后,需要逐个打开结果文件,并保存一次
|
||||||
|
|
||||||
6. 参数一致性检查
|
6. 数据准确性检查
|
||||||
执行程序前,需要确定 configs.xlsx 中设定的减速比/最大角速度/额定电流的值是正确的
|
执行完程序之后,可以在日志输出框中看到全部文件的处理过程,对于有问题的文件,会用特殊颜色进行标识,需要注意观察
|
||||||
|
|
||||||
7. 数据准确性检查
|
7. 其他
|
||||||
执行完程序之后,需要对结果文件的数据准确性做核对,通过我自己的数据观察,误差基本在10ms以内,也即10个数据点,误差较大的情况可自行调整
|
程序运行主要的耗时集中在打开,保存和关闭结果文件,第一次打开的时候会比较慢,另外还需要注意采集的数据长度和结果文件中预设的数据长度是否一致,若采集的数据长度大于预设的数据长度,则需要补齐数据
|
||||||
|
|
||||||
8. 其他
|
|
||||||
程序运行主要的耗时集中在打开,保存和关闭结果文件,第一次打开的时候会比较慢,是因为 excel 在做首次公式的计算,保存关闭之后,再打开会比较快一些,另外,如果在运行出错并重复运行程序的时候无响应,或者出现异常,请打开任务管理器,关闭一切和excel相关的进程,重新运行即可
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 电机电流
|
#### 2) 电机电流
|
||||||
|
|
||||||
1. 单独使用max/avg功能时,对于文件命名同第二点,存放数据的文件夹,只允许有 .data 或者 .csv 文件,且每次只能处理rc相同的轴的数据
|
1. 单独使用 max/avg 功能时,要求文件命名以 "jx_" 开头,例如 j1_2024_06_18_09_09_11.data,只允许有 .data 或者 .csv 文件,可同时处理所有轴的数据
|
||||||
2. cycle功能只处理单文件单轴数据,可以批量处理所有轴,但要确保遵守如下规则:
|
2. cycle 功能支持处理单轴数据以及场景电机电流的数据,可以批量处理所有轴,但要确保遵守如下规则:
|
||||||
a. 数据整理文件以 .xlsx 为后缀
|
- 包含电机电流结果汇总文件(excel)
|
||||||
b. 其他文件
|
- 单轴文件:jx_xxxxx.data/csv
|
||||||
A. 单轴:j1_xxxxx.data/csv
|
- 保持电流:jx_hold_xxxx.data/csv
|
||||||
B. 保持:j1_hold_xxxx.data/csv
|
- 场景文件:factory_53.8_2024_06_18_09_01_26.data(需手动拆分)
|
||||||
C. 所有文件放在同一个文件夹即可
|
- 所有文件放在同一个文件夹即可
|
||||||
d. 界面输入rc参数时,需要输入所有轴的数据
|
- 界面输入rc参数时,需要输入所有轴的数据,即使只处理个别轴的数据
|
||||||
|
|
||||||
#### ISO数据
|
> 程序运行主要的耗时集中在打开,保存和关闭结果文件
|
||||||
|
> 需要注意采集的数据长度和结果文件中预设的数据长度是否一致,若采集的数据长度大于预设的数据长度,则需要补齐数据
|
||||||
|
> 和制动数据统一,后续将仅支持对hw_joint_vel_feedback的解析和处理,不再支持device_servo_vel_feedback
|
||||||
|
|
||||||
|
#### 3) iso 数据
|
||||||
|
|
||||||
所有文件放在同一个文件夹即可,命名规则如下:
|
所有文件放在同一个文件夹即可,命名规则如下:
|
||||||
a. ISO.pdf
|
a. ISO.pdf
|
||||||
@ -93,7 +103,9 @@ pyinstaller --noconfirm --onedir --windowed --add-data "C:/Users/Administrator/A
|
|||||||
c. ISO-V100.pdf
|
c. ISO-V100.pdf
|
||||||
d. iso-results.xlsx
|
d. iso-results.xlsx
|
||||||
|
|
||||||
#### wavelogger波形数据
|
> 目前仅能处理 6 轴数据
|
||||||
|
|
||||||
|
#### 4) wavelogger 波形数据
|
||||||
|
|
||||||
1. 需要提前将 .xdt 波形数据转换成 .csv 文件
|
1. 需要提前将 .xdt 波形数据转换成 .csv 文件
|
||||||
2. 组织目录下只允许有 .csv 文件,对文件夹无要求
|
2. 组织目录下只允许有 .csv 文件,对文件夹无要求
|
||||||
@ -188,42 +200,58 @@ v0.1.4(2024/06/06)
|
|||||||
6. 支持工业/协作两条产品线的电机电流数据处理,包括单轴,场景,max/avg计算
|
6. 支持工业/协作两条产品线的电机电流数据处理,包括单轴,场景,max/avg计算
|
||||||
|
|
||||||
v0.1.5(2024/06/12)
|
v0.1.5(2024/06/12)
|
||||||
1. [aio.py]: 主界面切换不同功能时保持placehold一致
|
1. [aio.py] 主界面切换不同功能时保持placehold一致
|
||||||
2. [brake.py]: 由于制动采集模板和内容的更改,适配了新的数据,更新了算法
|
2. [brake.py] 由于制动采集模板和内容的更改,适配了新的数据,更新了算法
|
||||||
3. [aio.py]: 新增tabview组件,区分数据处理和自动化测试功能
|
3. [aio.py] 新增tabview组件,区分数据处理和自动化测试功能
|
||||||
4. [aio.py]: 重新调整界面配色
|
4. [aio.py] 重新调整界面配色
|
||||||
5. [aio.py]: 修改了write2textbox函数,定制化显示每一行的颜色,针对每一行可自定义输出内容颜色
|
5. [aio.py] 修改了write2textbox函数,定制化显示每一行的颜色,针对每一行可自定义输出内容颜色
|
||||||
6. [brake.py/iso.py/current.py]: 由于第 5 点的更改,同时修改了其他文件相关引用的部分
|
6. [brake.py/iso.py/current.py] 由于第 5 点的更改,同时修改了其他文件相关引用的部分
|
||||||
7. [aio.py]: 更改label/entry/optionmenu等控件的生成方式,使用循环实现,更加简洁和容易维护
|
7. [aio.py] 更改label/entry/optionmenu等控件的生成方式,使用循环实现,更加简洁和容易维护
|
||||||
8. [aio.py]: 修改customtkinter库中C:\Users\Administrator\AppData\Local\Programs\Python\Python312\Lib\site-packages\customtkinter\windows\widgets\ctk_tabview.py文件,参考https://github.com/TomSchimansky/CustomTkinter/issues/2296,实现修改tabview组件的字体大小
|
8. [aio.py] 修改customtkinter库中C:\Users\Administrator\AppData\Local\Programs\Python\Python312\Lib\site-packages\customtkinter\windows\widgets\ctk_tabview.py文件,参考https://github.com/TomSchimansky/CustomTkinter/issues/2296,实现修改tabview组件的字体大小
|
||||||
9. [aio.py]: 修改menu_main->menu_main_dp,menu_sub->menu_sub_dp,为后续其他tab功能按钮做扩展,是针对第三点做出的相应调整
|
9. [aio.py] 修改menu_main->menu_main_dp,menu_sub->menu_sub_dp,为后续其他tab功能按钮做扩展,是针对第三点做出的相应调整
|
||||||
10. [layout.xlsx]: 添加了各个功能的流程图
|
10. [layout.xlsx] 添加了各个功能的流程图
|
||||||
|
|
||||||
v0.1.5.1(2024/06/12)
|
v0.1.5.1(2024/06/12)
|
||||||
1. [current.py]: 修改cycle功能中,数据清理范围为70000行,并将threshold从2调整为5
|
1. [current.py] 修改cycle功能中,数据清理范围为70000行,并将threshold从2调整为5
|
||||||
2. [current.py]: 修改位置超限提示,使更清楚了解问题原因
|
2. [current.py] 修改位置超限提示,使更清楚了解问题原因
|
||||||
3. [current.py]: 修改find_point函数中错误提示,增加定位信息
|
3. [current.py] 修改find_point函数中错误提示,增加定位信息
|
||||||
4. [README.md]: 精简打包命令
|
4. [README.md] 精简打包命令
|
||||||
5. [requirements.txt]: 新增必要库配置文件
|
5. [requirements.txt] 新增必要库配置文件
|
||||||
|
|
||||||
v0.1.5.2(2024/06/13)
|
v0.1.5.2(2024/06/13)
|
||||||
1. [brake.py/aio.py]: 将sto修改为estop
|
1. [brake.py/aio.py]: 将sto修改为estop
|
||||||
2. [brake.py]: 修改了速度计算逻辑,新版本的vel列数据遵循如下规则,av = vel * 180 / pi,根据av再计算speed
|
2. [brake.py] 修改了速度计算逻辑,新版本的vel列数据遵循如下规则,av = vel * 180 / pi,根据av再计算speed
|
||||||
3. [brake.py]: 将threshold修改为常量50
|
3. [brake.py] 将threshold修改为常量50
|
||||||
4. [brake.py]: 提高了输出提示语的明确性,删除了不必要的省略号
|
4. [brake.py] 提高了输出提示语的明确性,删除了不必要的省略号
|
||||||
5. [brake.py]: 更正了之前的数据copy错误,重新优化了estop处是否达到指定百分比的判定逻辑
|
5. [brake.py] 更正了之前的数据copy错误,重新优化了estop处是否达到指定百分比的判定逻辑
|
||||||
|
|
||||||
v0.1.5.3(2024/06/14)
|
v0.1.5.3(2024/06/14)
|
||||||
1. [aio.py]: 修改w_param为84,适配14寸电脑屏幕
|
1. [aio.py] 修改w_param为84,适配14寸电脑屏幕
|
||||||
2. [brake.py]: 将判定合规逻辑修改为角速度超过指定角速度的95%
|
2. [brake.py] 将判定合规逻辑修改为角速度超过指定角速度的95%
|
||||||
3. [README.md]: 稍作修改,包括打包方式,功能特性等
|
3. [README.md] 稍作修改,包括打包方式,功能特性等
|
||||||
|
|
||||||
v0.1.6.0(2024/06/15)
|
v0.1.6.0(2024/06/15)
|
||||||
1. [aio.py]: 新增wavelogger处理界面
|
1. [aio.py] 新增wavelogger处理界面
|
||||||
2. [wavelogger.py]: 新增精度数据处理模块
|
2. [wavelogger.py] 新增精度数据处理模块
|
||||||
|
|
||||||
v0.1.6.1(2024/06/16)
|
v0.1.6.1(2024/06/16)
|
||||||
1. [wavelogger.py]: bugfix single_file_proc函数中,修改_start起始点的计算逻辑
|
1. [wavelogger.py] bugfix single_file_proc函数中,修改_start起始点的计算逻辑
|
||||||
2. [wavelogger.py]: bugfix find_point函数中,当判断条件为临界值 2.0 的时候,针对forward和backward两种情况,对row_target做与判断逻辑相同的处理,目的是避免形成死循环
|
2. [wavelogger.py] bugfix find_point函数中,当判断条件为临界值 2.0 的时候,针对forward和backward两种情况,对row_target做与判断逻辑相同的处理,目的是避免形成死循环
|
||||||
|
|
||||||
|
v0.1.6.2(2024/06/16)
|
||||||
|
1. [current.py] 修改了max/avg相关功能中对于返回值的处理逻辑,并在输出框以行的形式打印出来
|
||||||
|
|
||||||
|
v0.1.6.3(2024/06/18)
|
||||||
|
1. [current.py] 适配电机电流中速度使用hw_joint_vel_feedback的数据,取消对device_servo_vel_feedback的支持,后续所有涉及到速度相关的数据均已前者为准,现已完成对单轴和场景的适配
|
||||||
|
|
||||||
|
> !!WARNING:目前版本的电机电流程序还支持DriverMaster采集的数据处理,等明确后,将不再支持,也即所有的电机电流数据(工业+协作),都是用诊断曲线来采集
|
||||||
|
|
||||||
|
v0.1.7.0(2024/06/29)
|
||||||
|
1. [openapi.py] 初步搭建起框架,完成了新老协议的封包/解包/异步采集日志的操作(未充分测试,但基本无问题)
|
||||||
|
2.
|
||||||
|
|
||||||
|
> **关于HMI接口**
|
||||||
|
> - 封包解包顺序:帧长度二字节/包长度四字节/协议二字节/预留二字节,\x04\x00:\x00\x00\tR:\x02:\x00
|
||||||
|
> - 帧长度和包长度没有必然关系,单帧的时候是帧长度减去包长度等于6,包长度指的是所有内容的长度
|
||||||
|
> - HMI内部每次发送1024个字节,进行分包,内容长度规则是:第一帧1024-6=1018,第二帧(包含)及之后的帧,帧长度即是数据长度
|
||||||
|
> -
|
@ -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, 1, 6, 1),
|
filevers=(0, 1, 6, 3),
|
||||||
prodvers=(0, 1, 6, 1),
|
prodvers=(0, 1, 6, 3),
|
||||||
# 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.1.6.1 (2024-06-16)'),
|
StringStruct('FileVersion', '0.1.6.3 (2024-06-18)'),
|
||||||
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.1.6.1 (2024-06-16)')])
|
StringStruct('ProductVersion', '0.1.6.3 (2024-06-18)')])
|
||||||
]),
|
]),
|
||||||
VarFileInfo([VarStruct('Translation', [1033, 1200])])
|
VarFileInfo([VarStruct('Translation', [1033, 1200])])
|
||||||
]
|
]
|
||||||
|
Binary file not shown.
@ -1 +1 @@
|
|||||||
0.1.6.1 @ 06/16/2024
|
0.1.6.3 @ 06/18/2024
|
@ -3,10 +3,13 @@ from os import getcwd
|
|||||||
from threading import Thread
|
from threading import Thread
|
||||||
import tkinter.messagebox
|
import tkinter.messagebox
|
||||||
import customtkinter
|
import customtkinter
|
||||||
import brake, current, iso, wavelogger
|
|
||||||
from time import time, strftime, localtime
|
from time import time, strftime, localtime
|
||||||
from urllib.request import urlopen
|
from urllib.request import urlopen
|
||||||
from socket import setdefaulttimeout
|
from socket import setdefaulttimeout
|
||||||
|
import data_process.brake as brake
|
||||||
|
import data_process.current as current
|
||||||
|
import data_process.iso as iso
|
||||||
|
import data_process.wavelogger as wavelogger
|
||||||
|
|
||||||
customtkinter.set_appearance_mode("System") # Modes: "System" (standard), "Dark", "Light"
|
customtkinter.set_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"
|
||||||
@ -72,7 +75,7 @@ class App(customtkinter.CTk):
|
|||||||
btns['log']['btn'].configure(command=lambda: self.thread_it(self.func_log_callback))
|
btns['log']['btn'].configure(command=lambda: self.thread_it(self.func_log_callback))
|
||||||
btns['end']['btn'].configure(command=lambda: self.thread_it(self.func_end_callback))
|
btns['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.1.6.1\nDate: 06/16/2024", font=self.my_font, text_color="#4F4F4F")
|
self.label_version = customtkinter.CTkLabel(self.frame_func, justify='left', text="Vers: 0.1.6.3\nDate: 06/18/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')
|
||||||
# =====================================================================
|
# =====================================================================
|
||||||
|
28
aio/code/automatic_test/do_brake.py
Normal file
28
aio/code/automatic_test/do_brake.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import openapi
|
||||||
|
|
||||||
|
hr = openapi.hr
|
||||||
|
|
||||||
|
# 一、设置/检测机器人状态:
|
||||||
|
# 1. 上电
|
||||||
|
# 2. 软限位打开
|
||||||
|
# 3. 示教器断开
|
||||||
|
# 4. 操作模式
|
||||||
|
# 5. 控制器状态/工作任务控件/机器人动态
|
||||||
|
|
||||||
|
# 二、加载RL程序开始运行
|
||||||
|
|
||||||
|
|
||||||
|
# 三、运行过程中,收集数据,并处理出结果
|
||||||
|
|
||||||
|
# 四
|
||||||
|
|
||||||
|
|
||||||
|
# _id = hr.excution("state.get_state")
|
||||||
|
# print(hr.get_from_id(_id))
|
||||||
|
# _id = hr.excution('state.set_tp_mode', tp_mode='without')
|
||||||
|
# print(hr.get_from_id(_id))
|
||||||
|
|
||||||
|
_id = hr.excution('device.get_params')
|
||||||
|
print(hr.get_from_id(_id))
|
||||||
|
# _id = hr.excution('state.switch_manual')
|
||||||
|
# print(hr.get_from_id(_id))
|
248
aio/code/automatic_test/openapi.py
Normal file
248
aio/code/automatic_test/openapi.py
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
import json
|
||||||
|
import socket
|
||||||
|
import threading
|
||||||
|
import selectors
|
||||||
|
import time
|
||||||
|
import binascii
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
class HmiRequest(object):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
self.c.connect(('192.168.0.160', 5050))
|
||||||
|
# self.c.connect(('192.168.84.129', 5050))
|
||||||
|
self.c.setblocking(False)
|
||||||
|
self.c_msg = []
|
||||||
|
self.c_xs = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
self.c_xs.connect(('192.168.0.160', 6666))
|
||||||
|
# self.c_xs.connect(('192.168.84.129', 6666))
|
||||||
|
self.c_xs.setblocking(False)
|
||||||
|
self.c_msg_xs = []
|
||||||
|
self.t_unpackage = threading.Thread(target=self.__unpackage, args=(self.c, ))
|
||||||
|
self.t_unpackage.daemon = True
|
||||||
|
self.t_unpackage.start()
|
||||||
|
self.t_unpackage_xs = threading.Thread(target=self.__unpackage_xs, args=(self.c_xs, ))
|
||||||
|
self.t_unpackage_xs.daemon = True
|
||||||
|
self.t_unpackage_xs.start()
|
||||||
|
# self.t = threading.Thread(target=self.__heartbeat)
|
||||||
|
# self.t.daemon = True
|
||||||
|
# self.t.start()
|
||||||
|
self.flag = 0
|
||||||
|
self.response = ''
|
||||||
|
self.leftover = 0
|
||||||
|
self.flag_xs = 0
|
||||||
|
self.response_xs = ''
|
||||||
|
self.leftover_xs = 0
|
||||||
|
|
||||||
|
def __header_check(self, index, data):
|
||||||
|
try:
|
||||||
|
_frame_size = int(binascii.b2a_hex(data[index:index+2]).decode(), 16)
|
||||||
|
_pkg_size = int(binascii.b2a_hex(data[index+2:index+6]).decode(), 16)
|
||||||
|
_protocol = int(binascii.b2a_hex(data[index+6:index+7]).decode(), 16)
|
||||||
|
_reserved = int(binascii.b2a_hex(data[index+7:index+8]).decode(), 16)
|
||||||
|
|
||||||
|
if _reserved == 0 and _protocol == 2:
|
||||||
|
return index+8, _frame_size, _pkg_size
|
||||||
|
else:
|
||||||
|
print("数据有误,需要确认")
|
||||||
|
exit(9)
|
||||||
|
except Exception as Err:
|
||||||
|
print(f"Err = {Err}")
|
||||||
|
print("无法读取数据,需要确认")
|
||||||
|
exit(10)
|
||||||
|
|
||||||
|
def __msg_storage(self, response, flag=0):
|
||||||
|
messages = self.c_msg if flag == 0 else self.c_msg_xs
|
||||||
|
if len(messages) < 1000:
|
||||||
|
messages.insert(0, response)
|
||||||
|
else:
|
||||||
|
messages.insert(0, response)
|
||||||
|
while len(messages) > 1000:
|
||||||
|
messages.pop()
|
||||||
|
|
||||||
|
def __get_response(self, data):
|
||||||
|
_index = 0
|
||||||
|
while _index < len(data):
|
||||||
|
if self.flag == 0:
|
||||||
|
_index, _frame_size, _pkg_size = self.__header_check(_index, data)
|
||||||
|
if _pkg_size <= len(data) - _index:
|
||||||
|
# 说明剩余部分的数据正好就是完整的包数据
|
||||||
|
self.response = data[_index:_index+_pkg_size].decode()
|
||||||
|
self.__msg_storage(flag=0, response=self.response)
|
||||||
|
_index += _pkg_size
|
||||||
|
self.flag = 0
|
||||||
|
self.response = ''
|
||||||
|
self.leftover = 0
|
||||||
|
elif _pkg_size > len(data) - _index:
|
||||||
|
# 说有有分包的情况发生了,需要flag=1的处理
|
||||||
|
self.flag = 1
|
||||||
|
self.response = data[_index:].decode()
|
||||||
|
self.leftover = _frame_size - 6 - (len(data) - _index) # 其实就是常量 2
|
||||||
|
_index += _pkg_size # 也可以换成 break,效果都是退出循环
|
||||||
|
|
||||||
|
elif self.flag == 1:
|
||||||
|
# 处理完之后,将flag重置为0
|
||||||
|
_index = self.leftover
|
||||||
|
self.response += data[:_index].decode()
|
||||||
|
_index += 2
|
||||||
|
|
||||||
|
try:
|
||||||
|
_frame_size = int.from_bytes(data[_index-2:_index])
|
||||||
|
except:
|
||||||
|
self.__msg_storage(flag=0, response=self.response)
|
||||||
|
self.flag = 0
|
||||||
|
self.response = ''
|
||||||
|
self.leftover = 0
|
||||||
|
break
|
||||||
|
|
||||||
|
if _frame_size == 1024:
|
||||||
|
self.leftover = 1024 - (len(data) - _index)
|
||||||
|
self.response += data[_index:].decode()
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if _index+_frame_size <= 1024:
|
||||||
|
self.response += data[_index:_index+_frame_size].decode()
|
||||||
|
self.__msg_storage(flag=0, response=self.response)
|
||||||
|
|
||||||
|
self.flag = 0
|
||||||
|
self.response = ''
|
||||||
|
self.leftover = 0
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.response += data[_index:].decode()
|
||||||
|
self.leftover = _index + _frame_size - 1024
|
||||||
|
|
||||||
|
def __get_response_xs(self, data):
|
||||||
|
if self.flag_xs == 0:
|
||||||
|
if data[-1].decode() == '\r':
|
||||||
|
_responses = data.decode().split('\r')
|
||||||
|
for _response in _responses:
|
||||||
|
self.__msg_storage(flag=1, response=_response)
|
||||||
|
|
||||||
|
else:
|
||||||
|
_responses = data.decode().split('\r')
|
||||||
|
for _response in _responses[:-1]:
|
||||||
|
if not _response:
|
||||||
|
break
|
||||||
|
self.__msg_storage(flag=1, response=_response)
|
||||||
|
|
||||||
|
self.response_xs = _responses[-1]
|
||||||
|
self.flag_xs = 1
|
||||||
|
else:
|
||||||
|
if data[-1].decode() == '\r':
|
||||||
|
_responses = (self.response_xs.encode() + data).decode().split('\r')
|
||||||
|
for _response in _responses:
|
||||||
|
self.__msg_storage(flag=1, response=_response)
|
||||||
|
|
||||||
|
self.response_xs = ''
|
||||||
|
self.flag_xs = 0
|
||||||
|
else:
|
||||||
|
_responses = (self.response_xs.encode() + data).decode().split('\r')
|
||||||
|
for _response in _responses[:-1]:
|
||||||
|
if not _response:
|
||||||
|
break
|
||||||
|
self.__msg_storage(flag=1, response=_response)
|
||||||
|
|
||||||
|
self.response_xs = _responses[-1]
|
||||||
|
self.flag_xs = 1
|
||||||
|
|
||||||
|
def get_from_id(self, msg_id, flag=0):
|
||||||
|
messages = self.c_msg if flag == 0 else self.c_msg_xs
|
||||||
|
for i in range(3):
|
||||||
|
for msg in messages:
|
||||||
|
if msg_id in msg:
|
||||||
|
return msg
|
||||||
|
time.sleep(1)
|
||||||
|
else:
|
||||||
|
print(f'无法查询到{msg_id}对应的响应')
|
||||||
|
|
||||||
|
def __package(self, cmd):
|
||||||
|
pkg_size = str(hex(len(cmd)+6))[2:].rjust(4, '0')
|
||||||
|
package = binascii.a2b_hex(pkg_size) # 包的长度
|
||||||
|
reserved = chr(0) + chr(0) # 保留字段
|
||||||
|
frame_size = str(hex(len(cmd)))[2:].rjust(4, '0')
|
||||||
|
frame = binascii.a2b_hex(frame_size) # 帧的长度
|
||||||
|
protocol = chr(2) + chr(0) # 协议类型
|
||||||
|
return package + reserved.encode() + frame + protocol.encode() + cmd.encode()
|
||||||
|
|
||||||
|
def __package_xs(self, cmd):
|
||||||
|
return f"{json.dumps(cmd, separators=(',', ':'))}\r".encode()
|
||||||
|
|
||||||
|
def __unpackage(self, sock):
|
||||||
|
def to_read(conn):
|
||||||
|
data = conn.recv(1024) # Should be ready
|
||||||
|
if data:
|
||||||
|
print(data)
|
||||||
|
self.__get_response(data)
|
||||||
|
else:
|
||||||
|
print('closing', sock)
|
||||||
|
sel.unregister(conn)
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
sel = selectors.DefaultSelector()
|
||||||
|
sel.register(sock, selectors.EVENT_READ, to_read)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
events = sel.select()
|
||||||
|
for key, mask in events:
|
||||||
|
callback = key.data
|
||||||
|
callback(key.fileobj)
|
||||||
|
|
||||||
|
def __unpackage_xs(self, sock):
|
||||||
|
def to_read(conn):
|
||||||
|
data = conn.recv(1024) # Should be ready
|
||||||
|
if data:
|
||||||
|
# print(data)
|
||||||
|
self.__get_response_xs(data)
|
||||||
|
else:
|
||||||
|
print('closing', sock)
|
||||||
|
sel.unregister(conn)
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
sel = selectors.DefaultSelector()
|
||||||
|
sel.register(sock, selectors.EVENT_READ, to_read)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
events = sel.select()
|
||||||
|
for key, mask in events:
|
||||||
|
callback = key.data
|
||||||
|
callback(key.fileobj)
|
||||||
|
|
||||||
|
def __gen_id(self, command):
|
||||||
|
_now = time.time()
|
||||||
|
_id = f"{command}-{_now}"
|
||||||
|
return _id
|
||||||
|
|
||||||
|
def excution(self, command, flag=0, **kwargs):
|
||||||
|
if flag == 0: # for old protocols
|
||||||
|
req = None
|
||||||
|
try:
|
||||||
|
with open(f'./templates/{command}.json', encoding='utf-8', mode='r') as f_json:
|
||||||
|
req = json.load(f_json)
|
||||||
|
except:
|
||||||
|
print(f"暂不支持 {command} 功能,或确认该功能存在...")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
match command:
|
||||||
|
case 'state.set_tp_mode':
|
||||||
|
req['data']['tp_mode'] = kwargs['tp_mode']
|
||||||
|
case 1:
|
||||||
|
pass
|
||||||
|
req['id'] = self.__gen_id(command)
|
||||||
|
print(f"req = {req}")
|
||||||
|
cmd = json.dumps(req, separators=(',', ':'))
|
||||||
|
self.c.send(self.__package(cmd))
|
||||||
|
time.sleep(2)
|
||||||
|
return req['id']
|
||||||
|
else: # for xService
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
hr = HmiRequest()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
5
aio/code/automatic_test/templates/device.get_params.json
Normal file
5
aio/code/automatic_test/templates/device.get_params.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"id": "xxxxxxxxxxx",
|
||||||
|
"module": "system",
|
||||||
|
"command": "device.get_params"
|
||||||
|
}
|
5
aio/code/automatic_test/templates/state.get_state.json
Normal file
5
aio/code/automatic_test/templates/state.get_state.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"id": "xxxxxxxxxxx",
|
||||||
|
"module": "system",
|
||||||
|
"command": "state.get_state"
|
||||||
|
}
|
5
aio/code/automatic_test/templates/state.get_tp_mode.json
Normal file
5
aio/code/automatic_test/templates/state.get_tp_mode.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"id": "xxxxxxxxxxx",
|
||||||
|
"module": "system",
|
||||||
|
"command": "state.get_tp_mode"
|
||||||
|
}
|
8
aio/code/automatic_test/templates/state.set_tp_mode.json
Normal file
8
aio/code/automatic_test/templates/state.set_tp_mode.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"id": "xxxxxxxxxxx",
|
||||||
|
"module": "system",
|
||||||
|
"command": "state.set_tp_mode",
|
||||||
|
"data": {
|
||||||
|
"tp_mode": "with"
|
||||||
|
}
|
||||||
|
}
|
5
aio/code/automatic_test/templates/state.switch_auto.json
Normal file
5
aio/code/automatic_test/templates/state.switch_auto.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"id": "xxxxxxxxxxx",
|
||||||
|
"module": "system",
|
||||||
|
"command": "state.switch_auto"
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"id": "xxxxxxxxxxx",
|
||||||
|
"module": "system",
|
||||||
|
"command": "state.switch_manual"
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"id": "xxxxxxxxxxx",
|
||||||
|
"module": "system",
|
||||||
|
"command": "state.switch_motor_off"
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"id": "xxxxxxxxxxx",
|
||||||
|
"module": "system",
|
||||||
|
"command": "state.switch_motor_on"
|
||||||
|
}
|
@ -81,7 +81,7 @@ def initialization(path, sub, w2t):
|
|||||||
|
|
||||||
|
|
||||||
def current_max(data_files, rcs, trqh, w2t):
|
def current_max(data_files, rcs, trqh, w2t):
|
||||||
current = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0}
|
current = {1: [], 2: [], 3: [], 4: [], 5: [], 6: [], 7: []}
|
||||||
for data_file in data_files:
|
for data_file in data_files:
|
||||||
if data_file.endswith('.data'):
|
if data_file.endswith('.data'):
|
||||||
df = read_csv(data_file, sep='\t')
|
df = read_csv(data_file, sep='\t')
|
||||||
@ -96,15 +96,23 @@ def current_max(data_files, rcs, trqh, w2t):
|
|||||||
|
|
||||||
scale = 1 if data_file.endswith('.csv') else 1000
|
scale = 1 if data_file.endswith('.csv') else 1000
|
||||||
_ = abs(c_max/scale*rca)
|
_ = abs(c_max/scale*rca)
|
||||||
current[axis] = _
|
current[axis].append(_)
|
||||||
w2t(f"{data_file}: {_:.4f}")
|
w2t(f"{data_file}: {_:.4f}")
|
||||||
|
|
||||||
w2t("【MAX】数据处理完毕......")
|
for axis, cur in current.items():
|
||||||
|
if not cur:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
w2t(f"{axis}轴数据:", 1, 0, 'purple')
|
||||||
|
for value in cur:
|
||||||
|
w2t(f"{value:.4f} ", 1, 0, 'purple')
|
||||||
|
w2t('')
|
||||||
|
w2t("\n【MAX】数据处理完毕......")
|
||||||
return current
|
return current
|
||||||
|
|
||||||
|
|
||||||
def current_avg(data_files, rcs, trqh, w2t):
|
def current_avg(data_files, rcs, trqh, w2t):
|
||||||
current = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0}
|
current = {1: [], 2: [], 3: [], 4: [], 5: [], 6: [], 7: []}
|
||||||
for data_file in data_files:
|
for data_file in data_files:
|
||||||
if data_file.endswith('.data'):
|
if data_file.endswith('.data'):
|
||||||
df = read_csv(data_file, sep='\t')
|
df = read_csv(data_file, sep='\t')
|
||||||
@ -120,10 +128,18 @@ def current_avg(data_files, rcs, trqh, w2t):
|
|||||||
|
|
||||||
scale = 1 if data_file.endswith('.csv') else 1000
|
scale = 1 if data_file.endswith('.csv') else 1000
|
||||||
_ = (abs(c_avg)+c_std)/scale*rca
|
_ = (abs(c_avg)+c_std)/scale*rca
|
||||||
current[axis] = _
|
current[axis].append(_)
|
||||||
w2t(f"{data_file}: {_:.4f}")
|
w2t(f"{data_file}: {_:.4f}")
|
||||||
|
|
||||||
w2t("【AVG】数据处理完毕......")
|
for axis, cur in current.items():
|
||||||
|
if not cur:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
w2t(f"{axis}轴数据:", 1, 0, 'purple')
|
||||||
|
for value in cur:
|
||||||
|
w2t(f"{value:.4f} ", 1, 0, 'purple')
|
||||||
|
w2t('')
|
||||||
|
w2t("\n【AVG】数据处理完毕......")
|
||||||
return current
|
return current
|
||||||
|
|
||||||
|
|
||||||
@ -216,10 +232,12 @@ def p_single(wb, single, vel, trq, rpm, w2t):
|
|||||||
axis = int(data_file.split('\\')[-1].split('_')[0].removeprefix('j'))
|
axis = int(data_file.split('\\')[-1].split('_')[0].removeprefix('j'))
|
||||||
shtname = f"J{axis}"
|
shtname = f"J{axis}"
|
||||||
ws = wb[shtname]
|
ws = wb[shtname]
|
||||||
|
addition = 1
|
||||||
set_option("display.precision", 2)
|
set_option("display.precision", 2)
|
||||||
if data_file.endswith('.data'):
|
if data_file.endswith('.data'):
|
||||||
df = read_csv(data_file, sep='\t')
|
df = read_csv(data_file, sep='\t')
|
||||||
|
rr = float(wb['统计'].cell(row=2, column=axis+1).value)
|
||||||
|
addition = 180 / 3.1415926 * 60 / 360 * rr
|
||||||
elif data_file.endswith('.csv'):
|
elif data_file.endswith('.csv'):
|
||||||
df = read_csv(data_file, sep=',', encoding='gbk', header=8)
|
df = read_csv(data_file, sep=',', encoding='gbk', header=8)
|
||||||
csv_reader = reader(open(data_file))
|
csv_reader = reader(open(data_file))
|
||||||
@ -233,7 +251,7 @@ def p_single(wb, single, vel, trq, rpm, w2t):
|
|||||||
ws["H11"] = cycle
|
ws["H11"] = cycle
|
||||||
|
|
||||||
col_names = list(df.columns)
|
col_names = list(df.columns)
|
||||||
df_1 = df[col_names[vel-1]].multiply(rpm)
|
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)
|
||||||
df = concat([df_1, df_2], axis=1)
|
df = concat([df_1, df_2], axis=1)
|
||||||
|
|
||||||
@ -293,10 +311,12 @@ def p_scenario(wb, single, vel, trq, rpm, dur, w2t):
|
|||||||
axis = int(data_file.split('\\')[-1].split('_')[0].removeprefix('j'))
|
axis = int(data_file.split('\\')[-1].split('_')[0].removeprefix('j'))
|
||||||
shtname = f"J{axis}"
|
shtname = f"J{axis}"
|
||||||
ws = wb[shtname]
|
ws = wb[shtname]
|
||||||
|
addition = 1
|
||||||
set_option("display.precision", 2)
|
set_option("display.precision", 2)
|
||||||
if data_file.endswith('.data'):
|
if data_file.endswith('.data'):
|
||||||
df = read_csv(data_file, sep='\t')
|
df = read_csv(data_file, sep='\t')
|
||||||
|
rr = float(wb['统计'].cell(row=2, column=axis+1).value)
|
||||||
|
addition = 180 / 3.1415926 * 60 / 360 * rr
|
||||||
elif data_file.endswith('.csv'):
|
elif data_file.endswith('.csv'):
|
||||||
df = read_csv(data_file, sep=',', encoding='gbk', header=8)
|
df = read_csv(data_file, sep=',', encoding='gbk', header=8)
|
||||||
csv_reader = reader(open(data_file))
|
csv_reader = reader(open(data_file))
|
||||||
@ -310,7 +330,7 @@ def p_scenario(wb, single, vel, trq, rpm, dur, w2t):
|
|||||||
ws["H11"] = cycle
|
ws["H11"] = cycle
|
||||||
|
|
||||||
col_names = list(df.columns)
|
col_names = list(df.columns)
|
||||||
df_1 = df[col_names[vel-1]].multiply(rpm)
|
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)
|
||||||
df = concat([df_1, df_2], axis=1)
|
df = concat([df_1, df_2], axis=1)
|
||||||
|
|
Reference in New Issue
Block a user