22 Commits

Author SHA1 Message Date
4d297118e0 1. [current: do_current.py] 增加了 hw_sensor_trq_feedback 曲线的采集
2. [current: current.py] 增加了 hw_sensor_trq_feedback 曲线数据的处理,以及修改了之前数据处理的逻辑
3. [current: clibs.py] 新增可手动修改连接 IP 地址的功能,存储在 assets/templates/ipaddr.txt 中,默认是 192.168.0.160
2024-12-05 16:14:59 +08:00
5c5168442f update configs.xlsx 2024-10-25 14:21:21 +08:00
c9fa3a4473 modify current max senario time from 150s to 250s 2024-10-12 21:49:16 +08:00
880964f675 重新修改制动结束延迟时间洛杉矶 2024-10-12 16:09:58 +08:00
3481d3b496 每次制动完成之后,pending时间修改为3s 2024-10-10 09:19:43 +08:00
bebaf292ac 修复制动性能测试,采集的数据速度未降为0的问题 2024-10-09 16:00:47 +08:00
9f78b0e563 minor modification of UI for current data process 2024-09-20 14:13:54 +08:00
59711d9c65 4. [main: openapi.py]:新增 rl_task.set_run_params 指令支持,可设定速度滑块以及是否重复运行
5. [main: do_brake/do_current/factory_test.py]:在初始化运动时增加 `clibs.execution('rl_task.set_run_params', hr, w2t, tab_name, loop_mode=True, override=1.0)`
2024-08-20 18:03:44 +08:00
edafd91567 v0.2.0.8(2024/08/20)
1. [t_change_ui: clibs.py]
   - 从外部拷贝 icon.ico 文件到 templates 目录
   - 在 assets 目录新建 logs 目录,存放日志文件,并增加了相应的逻辑保证正常执行
2. [t_change_ui: aio.py]:增加 App 窗口图标代码
3. [t_change_ui: openapi.py]:将重复输出的网络错误提示,从 textbox 中转移到 debug.log 日志文件中
2024-08-20 11:13:45 +08:00
03b15751c2 add exception handle for openapi-selector 2024-08-17 09:28:33 +08:00
29bd4185c4 version change 2024-08-16 17:48:08 +08:00
97071d231f Merge branch 't_change_ui' 2024-08-16 17:23:25 +08:00
2d12c160b9 v0.2.0.7(2024/08/16)
1. [t_change_ui: clibs.py]:修改了 hmi.log 的日志等级为 WARNING
2. [t_change_ui: openapi.py]:根据第一步的修改,将此模块日志记录等级调整至 warning
3. [current: current.py]
   - README新增了整机自动化测试的前置条件,即滑块需要滑动到最右端
   - current修改了文件校验的逻辑
4. [t_change_ui: aio.py]
   - 修改变量命名,widgit -> widget
   - 根据第 5 点变动,同步修改代码实现
   - 调整 UI 界面代码顺序,使之符合 layout.xlsx 描述
   - 将版本检查的部分单独封装成一个函数,在 detect_network 线程初始化时调用一次,并且程序启动也不会受到阻塞
5. [t_change_ui: layout.xlsx]:修改了组件布局方式
2024-08-16 17:22:52 +08:00
62e5e6ab50 README中增加整机自动化测试前需要调整速度滑块的提醒,完善current数据预处理的逻辑 2024-08-16 16:05:31 +08:00
8f342832b2 fix merge while merging from main 2024-08-16 15:57:00 +08:00
4925d899b4 千分表自动采集程序 2024-08-10 17:23:20 +08:00
3814d163c5 v0.2.0.6(2024/08/09)
1. [t_change_ui: all files]
   - 修改了 logger 的实现
   - 尤其是 clibs.py,使用日志字典,重写了日志记录的功能
2024-08-09 10:47:22 +08:00
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
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
addb123a8a [current: current.py]: 在find_point函数种,当无法找到正确点位时,继续执行,而不是直接终止执行 2024-07-13 13:32:57 +08:00
26 changed files with 681 additions and 316 deletions

6
.gitignore vendored
View File

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

View File

@ -34,7 +34,7 @@
打包时,只需要修改 clibs.py 中的 PREFIX 即可,调试时再修改回来
```
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 --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-Gitea\aio\aio\assets\templates:templates" --version-file ../assets/file_version_info.txt -i ../assets/templates/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
```
---
@ -146,6 +146,7 @@ pyinstaller --noconfirm --onedir --windowed --optimize 2 --contents-directory .
10. 由于xCore系统问题运行过程中可能会出现机器人宕机问题如果遇到可以手动重启控制柜重新运行
11. 务必正确填写configs.xlsx中的Target页面A1单元格可以选择正负方向急停
12. 工程文件可以手动重命名,按照机型存档,或者导出用于自动化测试
13. 可废弃但未验证自动化测试前需要将HMI程序速度设置为100%并同步至控制器,也即左下方速度滑条滑动至最大
#### 6) 电机电流自动化测试
@ -274,7 +275,7 @@ v0.1.5.1(2024/06/12)
5. [requirements.txt] 新增必要库配置文件
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
3. [brake.py] 将threshold修改为常量50
4. [brake.py] 提高了输出提示语的明确性,删除了不必要的省略号
@ -448,18 +449,18 @@ v0.1.7.6(2024/07/04)
3. [APIs: openapi.py]
- 增加了modbus读取浮点数的功能
- 优化了get_from_id的逻辑
4. [autotest.xml]: 新增了scenario_time只写寄存器
4. [autotest.xml] 新增了scenario_time只写寄存器
v0.1.8.0(2024/07/04)
1. [APIs: do_current.py]: 完成了堵转电流和惯量负载电机电流的采集和处理,至此,电机电流的自动化工作基本完成
1. [APIs: do_current.py] 完成了堵转电流和惯量负载电机电流的采集和处理,至此,电机电流的自动化工作基本完成
v0.1.8.1(2024/07/05)
1. [APIs: do_brake.py]: 完成了制动性能测试框架的搭建,可以顺利执行完整的测试程序,但是未实现急停和数据处理
2. [APIs: aio.py]: 修改了do_brake主函数的参数
1. [APIs: do_brake.py] 完成了制动性能测试框架的搭建,可以顺利执行完整的测试程序,但是未实现急停和数据处理
2. [APIs: aio.py] 修改了do_brake主函数的参数
3. 增加工程文件target.zip
v0.1.8.2(2024/07/08)
1. [APIs: do_brake.py]: 完成了制动性能测试逻辑只不过制动信号传递生效延迟不可控暂时pending
1. [APIs: do_brake.py] 完成了制动性能测试逻辑只不过制动信号传递生效延迟不可控暂时pending
2. [APIs: do_current.py]: 修改曲线数据时序主要是value data取反即可解决了波形锯齿明细的问题
3. [APIs: openapi.py]: modbus新增了触发急停信号的寄存器 stop0_signal并重写了解除急停socket新增了register.set_value协议
@ -558,6 +559,12 @@ v0.2.0.3(2024/07/27)
2. [APIs: do_current.py]: 精简程序,解决 OOM 问题
3. [APIs: factory_test.py]: 精简程序,解决 OOM 问题
4. [APIsL openapi.py]
- 心跳修改为 1 s因为 OOM 问题的解决依赖于长久的打开曲线开关,此时对于 hr.c_msg 的定时清理是个挑战,将心跳缩短,有利于清理日志后,避免丢失心跳
- 新增 diagnosis.save 命令,但是执行时,有问题,待解决
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 命令,但是执行时,有问题,待解决
@ -584,5 +591,47 @@ v0.2.0.5(2024/07/31)
- 保持电流,只取最后 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),只有添加这个,单个模块内才生效
v0.2.0.6(2024/08/09)
1. [t_change_ui: all files]
- 修改了 logger 的实现
- 尤其是 clibs.py使用日志字典重写了日志记录的功能
v0.2.0.7(2024/08/16)
1. [t_change_ui: clibs.py]:修改了 hmi.log 的日志等级为 WARNING
2. [t_change_ui: openapi.py]:根据第一步的修改,将此模块日志记录等级调整至 warning
3. [current: current.py]
- README新增了整机自动化测试的前置条件即滑块需要滑动到最右端
- current修改了文件校验的逻辑
4. [t_change_ui: aio.py]
- 修改变量命名widgit -> widget
- 根据第 5 点变动,同步修改代码实现
- 调整 UI 界面代码顺序,使之符合 layout.xlsx 描述
- 将版本检查的部分单独封装成一个函数,在 detect_network 线程初始化时调用一次,并且程序启动也不会受到阻塞
5. [t_change_ui: layout.xlsx]:修改了组件布局方式
> 前两个修改点,修复的是网络提示的颜色不正确问题,因为日志将 textbox 中的内容也作为 debug 信息写入 hmi.log 了
v0.2.0.8(2024/08/20)
1. [t_change_ui: clibs.py]
- 从外部拷贝 icon.ico 文件到 templates 目录
- 在 assets 目录新建 logs 目录,存放日志文件,并增加了相应的逻辑保证正常执行
2. [t_change_ui: aio.py]:增加 App 窗口图标代码
3. [t_change_ui: openapi.py]:将重复输出的网络错误提示,从 textbox 中转移到 debug.log 日志文件中
4. [main: openapi.py]:新增 rl_task.set_run_params 指令支持,可设定速度滑块以及是否重复运行
5. [main: do_brake/do_current/factory_test.py]:在初始化运动时增加 `clibs.execution('rl_task.set_run_params', hr, w2t, tab_name, loop_mode=True, override=1.0)`
v0.2.0.9(2024/10/09)
1. [main: do_brake.py] 采集完成后pending 3s使速度完全将为 0
v0.2.1.0(2024/12/05)
1. [current: do_current.py] 增加了 hw_sensor_trq_feedback 曲线的采集
2. [current: current.py] 增加了 hw_sensor_trq_feedback 曲线数据的处理,以及修改了之前数据处理的逻辑
3. [current: clibs.py] 新增可手动修改连接 IP 地址的功能,存储在 assets/templates/ipaddr.txt 中,默认是 192.168.0.160

Binary file not shown.

View File

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

Binary file not shown.

View File

Before

Width:  |  Height:  |  Size: 162 KiB

After

Width:  |  Height:  |  Size: 162 KiB

View File

@ -0,0 +1 @@
192.168.0.160

View File

@ -0,0 +1,9 @@
{
"id": "xxxxxxxxxxx",
"module": "project",
"command": "rl_task.set_run_params",
"data": {
"loop_mode": true,
"override": 1.0
}
}

View File

@ -1 +1 @@
0.2.0.5 @ 08/02/2024
0.2.1.0 @ 12/05/2024

View File

@ -14,15 +14,14 @@ from commons import openapi, clibs
from matplotlib.pyplot import rcParams, figure, subplots_adjust, close
from matplotlib import use
from pandas import DataFrame, read_excel
import logging
with open(clibs.log_data, 'w') as _:
with open(clibs.log_data_hmi, 'w') as _hmi, open(clibs.log_data_debug, 'w', encoding='utf-8') as _debug:
for i in range(1, 11):
try:
remove(f'{clibs.log_data}.{i}')
remove(f'{clibs.log_data_hmi}.{i}')
except FileNotFoundError:
pass
logger = logging.getLogger(__file__)
logger = clibs.log_prod
logger.info("日志文件初始化完成...")
use('Agg')
@ -38,21 +37,21 @@ btns_func = {
'log': {'btn': '', 'row': 3, 'text': '保存日志'},
'end': {'btn': '', 'row': 4, 'text': '结束运行'},
}
widgits_dp = {
'path': {'label': '', 'entry': '', 'row': 1, 'col': 2, 'text': '数据文件夹路径'},
'dur': {'label': '', 'entry': '', 'row': 2, 'col': 2, 'text': '周期时间'},
'vel': {'label': '', 'optionmenu': '', 'row': 2, 'col': 4, 'text': ''},
'trq': {'label': '', 'optionmenu': '', 'row': 2, 'col': 6, 'text': ''},
'trqh': {'label': '', 'optionmenu': '', 'row': 2, 'col': 8, 'text': ''},
'estop': {'label': '', 'optionmenu': '', 'row': 2, 'col': 10, 'text': ''},
widgets_dp = {
'path': {'label': '', 'entry': '', 'row': 0, 'col': 1, 'text': '数据文件夹路径'},
'dur': {'label': '', 'entry': '', 'row': 1, 'col': 9, 'text': '周期时间'},
'vel': {'label': '', 'optionmenu': '', 'row': 1, 'col': 1, 'text': ''},
'trq': {'label': '', 'optionmenu': '', 'row': 1, 'col': 3, 'text': ''},
'trqh': {'label': '', 'optionmenu': '', 'row': 1, 'col': 5, 'text': ''},
'estop': {'label': '', 'optionmenu': '', 'row': 1, 'col': 7, 'text': ''},
}
widgits_at = {
'path': {'label': '', 'entry': '', 'row': 2, 'col': 2, 'text': '数据文件夹路径'},
'loadsel': {'label': '', 'optionmenu': '', 'row': 2, 'col': 1, 'text': '负载信息'},
widgets_at = {
'path': {'label': '', 'entry': '', 'row': 1, 'col': 1, 'text': '数据文件夹路径'},
'loadsel': {'label': '', 'optionmenu': '', 'row': 1, 'col': 0, 'text': '负载信息'},
}
widgits_da = {
'path': {'label': '', 'entry': '', 'row': 1, 'col': 2, 'text': '数据文件夹路径'},
'curvesel': {'label': '', 'optionmenu': '', 'row': 1, 'col': 1, 'text': '指标选择'},
widgets_da = {
'path': {'label': '', 'entry': '', 'row': 0, 'col': 1, 'text': '数据文件夹路径'},
'curvesel': {'label': '', 'optionmenu': '', 'row': 0, 'col': 0, 'text': '指标选择'},
}
@ -71,21 +70,24 @@ class App(customtkinter.CTk):
# =====================================================================
# configure window
self.title("AIO - All in one automatic toolbox")
# self.iconbitmap('./icon.ico')
self.wm_iconbitmap(clibs.app_icon)
self.geometry("1200x550+30+30")
self.protocol("WM_DELETE_WINDOW", self.func_end_callback)
self.config(bg='#E9E9E9')
self.grid_rowconfigure(6, weight=1)
self.grid_columnconfigure((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13), weight=1)
self.grid_rowconfigure(0, weight=1)
self.grid_rowconfigure(1, weight=19)
self.grid_columnconfigure(0, weight=1)
self.grid_columnconfigure(1, weight=19)
self.minsize(1200, 550)
# =====================================================================
# create frame sidebar(left)
self.frame_func = customtkinter.CTkFrame(self, width=120, corner_radius=0, fg_color='#E9E9E9')
self.frame_func.grid(row=0, column=0, rowspan=7, sticky='nsew')
# create AIO logo
# 1. create frame sidebar(left)
# =====================================================================
self.frame_func = customtkinter.CTkFrame(self, width=200, corner_radius=0, fg_color='#E9E9E9')
self.frame_func.grid(row=0, column=0, rowspan=2, sticky='nsew')
# 1.1 create AIO logo
self.label_logo = customtkinter.CTkLabel(self.frame_func, text="Rokae AIO", height=60, font=customtkinter.CTkFont(family="Segoe Script Bold", size=24, weight="bold"), text_color="#4F4F4F")
self.label_logo.grid(row=0, column=0, padx=15, pady=15)
# create buttons
# 1.2 create buttons
for func in btns_func:
btns_func[func]['btn'] = customtkinter.CTkButton(self.frame_func, corner_radius=10, text=btns_func[func]['text'], fg_color='#4F4F4F', font=self.my_font)
btns_func[func]['btn'].grid(row=btns_func[func]['row'], column=0, sticky='new', padx=10, pady=10, ipadx=5, ipady=5)
@ -93,95 +95,104 @@ class App(customtkinter.CTk):
btns_func['check']['btn'].configure(command=lambda: self.thread_it(self.func_check_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))
# create version info
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")
# 1.3 create version info
self.label_version = customtkinter.CTkLabel(self.frame_func, justify='left', text="Vers: 0.2.1.0\nDate: 12/05/2024", font=self.my_font, text_color="#4F4F4F")
self.frame_func.rowconfigure(6, weight=1)
self.label_version.grid(row=6, column=0, padx=20, pady=20, sticky='s')
# =====================================================================
# create tabviews
self.tabview = customtkinter.CTkTabview(self, width=10000, height=100, anchor='w', fg_color='#E9E9E9', border_width=2, border_color='#CDCDCD', command=self.tabview_click)
# 2. create tabviews
# =====================================================================
self.tabview = customtkinter.CTkTabview(self, anchor='w', fg_color='#E9E9E9', width=1000, height=45, border_width=2, border_color='#CDCDCD', command=self.tabview_click)
self.tabview.grid(row=0, column=1, padx=10, pady=5, sticky="nsew")
self.tabview.add("Data Process")
self.tabview.add("Automatic Test")
self.tabview.add("Durable Action")
# create main menu for data process
# 2.1 create widgets of tab "Data Process"
# 2.1.1 create main menu
self.menu_main_dp = customtkinter.CTkOptionMenu(self.tabview.tab('Data Process'), values=["init", "brake", "current", "iso", "wavelogger"], font=self.my_font, text_color='yellow', button_color='red', fg_color='green', command=self.func_main_callback)
self.menu_main_dp.grid(row=1, column=1, sticky='we', padx=5, pady=10)
self.menu_main_dp.grid(row=0, column=0, sticky='we', padx=5, pady=10)
self.menu_main_dp.set("Start Here!")
# create sub menu for data process
# 2.2.2 create sub menu
self.menu_sub_dp = customtkinter.CTkOptionMenu(self.tabview.tab('Data Process'))
# create main menu for automatic test
# 2.2.3 create labels, entries and option menus
for widget in widgets_dp:
if widget == 'path':
self.tabview.tab('Data Process').columnconfigure(12, weight=1)
widgets_dp[widget]['label'] = customtkinter.CTkLabel(self.tabview.tab('Data Process'), text=f'{widget.upper()}', font=self.my_font)
widgets_dp[widget]['label'].grid(row=widgets_dp[widget]['row'], column=widgets_dp[widget]['col'], sticky='e', pady=10)
widgets_dp[widget]['entry'] = customtkinter.CTkEntry(self.tabview.tab('Data Process'), placeholder_text=widgets_dp[widget]['text'], font=self.my_font)
widgets_dp[widget]['entry'].grid(row=widgets_dp[widget]['row'], column=widgets_dp[widget]['col']+1, columnspan=11, padx=(5, 10), pady=5, sticky='we')
widgets_dp[widget]['entry'].configure(state='disabled')
elif widget in ['dur']:
widgets_dp[widget]['label'] = customtkinter.CTkLabel(self.tabview.tab('Data Process'), text=f"{widget.upper()}", font=self.my_font)
widgets_dp[widget]['label'].grid(row=widgets_dp[widget]['row'], column=widgets_dp[widget]['col'], sticky='e', pady=5)
widgets_dp[widget]['entry'] = customtkinter.CTkEntry(self.tabview.tab('Data Process'), width=self.w_param, placeholder_text=f"{widgets_dp[widget]['text']}", font=self.my_font)
widgets_dp[widget]['entry'].grid(row=widgets_dp[widget]['row'], column=widgets_dp[widget]['col']+1, padx=(5, 10), pady=5, sticky='w')
widgets_dp[widget]['entry'].configure(state='disabled')
elif widget in ['vel', 'trq', 'trqh', 'estop']:
widgets_dp[widget]['label'] = customtkinter.CTkLabel(self.tabview.tab('Data Process'), text=f"{widget.upper()}", font=self.my_font)
widgets_dp[widget]['label'].grid(row=widgets_dp[widget]['row'], column=widgets_dp[widget]['col'], sticky='e', pady=5)
widgets_dp[widget]['optionmenu'] = customtkinter.CTkOptionMenu(self.tabview.tab('Data Process'), button_color='#708090', fg_color='#778899', values=["1", "2", "3", "4", "5", "6", "7"], width=self.w_param, font=self.my_font)
widgets_dp[widget]['optionmenu'].grid(row=widgets_dp[widget]['row'], column=widgets_dp[widget]['col']+1, padx=(5, 10), pady=5, sticky='w')
widgets_dp[widget]['optionmenu'].configure(state='disabled')
# =====================================================================
# 2.2 create widgets of tab "Automatic Test"
# 2.2.1 create main menu
self.menu_main_at = customtkinter.CTkOptionMenu(self.tabview.tab('Automatic Test'), values=["init", "brake", "current"], font=self.my_font, text_color='yellow', button_color='red', fg_color='green', command=self.func_main_callback)
self.menu_main_at.grid(row=1, column=1, sticky='we', padx=5, pady=5)
self.menu_main_at.grid(row=0, column=0, sticky='we', padx=5, pady=5)
self.menu_main_at.set("Start Here!")
# For data process tab START =====================================================================
# create widgits_dp
for widgit in widgits_dp:
if widgit == 'path':
widgits_dp[widgit]['label'] = customtkinter.CTkLabel(self.tabview.tab('Data Process'), text=f'{widgit.upper()}', font=self.my_font)
widgits_dp[widgit]['label'].grid(row=widgits_dp[widgit]['row'], column=widgits_dp[widgit]['col'], sticky='e', pady=10)
widgits_dp[widgit]['entry'] = customtkinter.CTkEntry(self.tabview.tab('Data Process'), width=670, placeholder_text=widgits_dp[widgit]['text'], font=self.my_font)
widgits_dp[widgit]['entry'].grid(row=widgits_dp[widgit]['row'], column=widgits_dp[widgit]['col']+1, columnspan=11, padx=(5, 10), pady=5, sticky='we')
widgits_dp[widgit]['entry'].configure(state='disabled')
elif widgit in ['dur']:
widgits_dp[widgit]['label'] = customtkinter.CTkLabel(self.tabview.tab('Data Process'), text=f"{widgit.upper()}", font=self.my_font)
widgits_dp[widgit]['label'].grid(row=widgits_dp[widgit]['row'], column=widgits_dp[widgit]['col'], sticky='e', pady=5)
widgits_dp[widgit]['entry'] = customtkinter.CTkEntry(self.tabview.tab('Data Process'), width=self.w_param, placeholder_text=f"{widgits_dp[widgit]['text']}", font=self.my_font)
widgits_dp[widgit]['entry'].grid(row=widgits_dp[widgit]['row'], column=widgits_dp[widgit]['col']+1, padx=(5, 10), pady=5, sticky='w')
widgits_dp[widgit]['entry'].configure(state='disabled')
elif widgit in ['vel', 'trq', 'trqh', 'estop']:
widgits_dp[widgit]['label'] = customtkinter.CTkLabel(self.tabview.tab('Data Process'), text=f"{widgit.upper()}", font=self.my_font)
widgits_dp[widgit]['label'].grid(row=widgits_dp[widgit]['row'], column=widgits_dp[widgit]['col'], sticky='e', pady=5)
widgits_dp[widgit]['optionmenu'] = customtkinter.CTkOptionMenu(self.tabview.tab('Data Process'), button_color='#708090', fg_color='#778899', values=["1", "2", "3", "4", "5", "6", "7"], width=self.w_param, font=self.my_font)
widgits_dp[widgit]['optionmenu'].grid(row=widgits_dp[widgit]['row'], column=widgits_dp[widgit]['col']+1, padx=(5, 10), pady=5, sticky='w')
widgits_dp[widgit]['optionmenu'].configure(state='disabled')
# For data process tab END =====================================================================
# For automatic test tab START =====================================================================
# create buttons
# 2.2.2 create segment buttons
self.seg_button = customtkinter.CTkSegmentedButton(self.tabview.tab('Automatic Test'), dynamic_resizing=False, font=customtkinter.CTkFont(size=16, weight='bold'), command=lambda value='机器状态': self.thread_it(self.segmented_button_callback))
self.seg_button.grid(row=1, column=2, columnspan=12, padx=(65, 10), pady=(10, 10), sticky="ew")
self.seg_button.grid(row=0, column=1, columnspan=12, padx=(65, 10), pady=(10, 10), sticky="ew")
self.seg_button.configure(dynamic_resizing=False, values=["功能切换", "触发急停", "恢复急停", "待定功能", "功能待定", "机器状态", "告警信息"])
self.seg_button.set("功能切换")
# create progress bar
# 2.2.3 create progress bar
self.progressbar = customtkinter.CTkProgressBar(self.tabview.tab('Automatic Test'))
self.progressbar.grid(row=5, column=1, padx=5, pady=5, sticky="ew")
self.progressbar.configure(mode="determinnate", width=10)
self.progressbar.grid(row=2, column=0, padx=5, pady=5, sticky="ew")
self.progressbar.configure(mode="determinnate", width=self.w_param)
self.progressbar.start()
# create widgits_at
for widgit in widgits_at:
if widgit == 'path':
widgits_at[widgit]['label'] = customtkinter.CTkLabel(self.tabview.tab('Automatic Test'), text=f'{widgit.upper()}', font=self.my_font)
widgits_at[widgit]['label'].grid(row=widgits_at[widgit]['row'], column=widgits_at[widgit]['col'], sticky='e', padx=(20, 5), pady=5)
widgits_at[widgit]['entry'] = customtkinter.CTkEntry(self.tabview.tab('Automatic Test'), width=670, placeholder_text=widgits_at[widgit]['text'], font=self.my_font)
widgits_at[widgit]['entry'].grid(row=widgits_at[widgit]['row'], column=widgits_at[widgit]['col']+1, columnspan=11, padx=(5, 10), pady=5, sticky='we')
widgits_at[widgit]['entry'].configure(state='disabled')
elif widgit in ['loadsel', ]:
widgits_at[widgit]['optionmenu'] = customtkinter.CTkOptionMenu(self.tabview.tab('Automatic Test'), button_color='#708090', fg_color='#778899', values=["tool33", "tool66", "tool100", "inertia"], width=self.w_param, font=self.my_font)
widgits_at[widgit]['optionmenu'].grid(row=widgits_at[widgit]['row'], column=widgits_at[widgit]['col'], padx=5, pady=5, sticky='we')
widgits_at[widgit]['optionmenu'].set(widgits_at[widgit]['text'])
widgits_at[widgit]['optionmenu'].configure(state='disabled')
# For automatic test tab END =====================================================================
# For durable_action tab START =====================================================================
# create progress bar
# 2.2.4 create labels, entries and option menus
for widget in widgets_at:
if widget == 'path':
self.tabview.tab('Automatic Test').columnconfigure(12, weight=1)
widgets_at[widget]['label'] = customtkinter.CTkLabel(self.tabview.tab('Automatic Test'), text=f'{widget.upper()}', font=self.my_font)
widgets_at[widget]['label'].grid(row=widgets_at[widget]['row'], column=widgets_at[widget]['col'], sticky='e', padx=(20, 5), pady=5)
widgets_at[widget]['entry'] = customtkinter.CTkEntry(self.tabview.tab('Automatic Test'), placeholder_text=widgets_at[widget]['text'], font=self.my_font)
widgets_at[widget]['entry'].grid(row=widgets_at[widget]['row'], column=widgets_at[widget]['col']+1, columnspan=11, padx=(5, 10), pady=5, sticky='we')
widgets_at[widget]['entry'].configure(state='disabled')
elif widget in ['loadsel', ]:
widgets_at[widget]['optionmenu'] = customtkinter.CTkOptionMenu(self.tabview.tab('Automatic Test'), button_color='#708090', fg_color='#778899', values=["tool33", "tool66", "tool100", "inertia"], width=self.w_param, font=self.my_font)
widgets_at[widget]['optionmenu'].grid(row=widgets_at[widget]['row'], column=widgets_at[widget]['col'], padx=5, pady=5, sticky='we')
widgets_at[widget]['optionmenu'].set(widgets_at[widget]['text'])
widgets_at[widget]['optionmenu'].configure(state='disabled')
# =====================================================================
# 2.3 create widgets of tab "Durable Action"
# 2.3.1 create progress bar
self.progressbar_da = customtkinter.CTkProgressBar(self.tabview.tab('Durable Action'))
self.progressbar_da.grid(row=2, column=1, padx=5, pady=5, sticky="ew")
self.progressbar_da.grid(row=1, column=0, padx=5, pady=5, sticky="ew")
self.progressbar_da.configure(mode="determinnate", width=self.w_param)
self.progressbar_da.start()
for widgit in widgits_da:
if widgit == 'path':
widgits_da[widgit]['label'] = customtkinter.CTkLabel(self.tabview.tab('Durable Action'), text=f'{widgit.upper()}', font=self.my_font)
widgits_da[widgit]['label'].grid(row=widgits_da[widgit]['row'], column=widgits_da[widgit]['col'], sticky='e', padx=(20, 5), pady=10)
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')
elif widgit in ['curvesel']:
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'].set(widgits_da[widgit]['text'])
# For durable_action tab END =====================================================================
# create textbox
# 2.3.2 create labels, entries and option menus
for widget in widgets_da:
if widget == 'path':
self.tabview.tab('Durable Action').columnconfigure(12, weight=1)
widgets_da[widget]['label'] = customtkinter.CTkLabel(self.tabview.tab('Durable Action'), text=f'{widget.upper()}', font=self.my_font)
widgets_da[widget]['label'].grid(row=widgets_da[widget]['row'], column=widgets_da[widget]['col'], sticky='e', padx=(20, 5), pady=10)
widgets_da[widget]['entry'] = customtkinter.CTkEntry(self.tabview.tab('Durable Action'), placeholder_text=widgets_da[widget]['text'], font=self.my_font)
widgets_da[widget]['entry'].grid(row=widgets_da[widget]['row'], column=widgets_da[widget]['col']+1, columnspan=11, padx=(5, 10), pady=10, sticky='we')
elif widget in ['curvesel']:
widgets_da[widget]['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)
widgets_da[widget]['optionmenu'].grid(row=widgets_da[widget]['row'], column=widgets_da[widget]['col'], padx=5, pady=10, sticky='we')
widgets_da[widget]['optionmenu'].set(widgets_da[widget]['text'])
# =====================================================================
# 3. create textbox
# =====================================================================
self.textbox = customtkinter.CTkTextbox(self, wrap='none', font=customtkinter.CTkFont(family="consolas", size=14), text_color="blue", fg_color='#E9E9E9', border_width=2, border_color='#CDCDCD', border_spacing=5)
self.textbox.grid(row=6, column=1, columnspan=13, ipadx=10, ipady=10, padx=10, pady=(5, 10), sticky='nsew')
self.textbox.grid(row=1, column=1, columnspan=13, ipadx=10, ipady=10, padx=10, pady=(5, 10), sticky='nsew')
self.textbox.configure(state='normal')
# functions below ↓ ----------------------------------------------------------------------------------------
def version_check(self):
# =====================================================================
# version check
cur_vers = self.label_version.cget("text").replace('\n', ' @ ').replace("Vers: ", '').replace("Date: ", '')
@ -193,13 +204,12 @@ class App(customtkinter.CTk):
tkinter.messagebox.showwarning(title="版本更新", message=msg)
except:
tkinter.messagebox.showwarning(title="版本更新", message="连接服务器失败,无法确认当前是否是最新版本......")
# functions below ↓ ----------------------------------------------------------------------------------------
def create_canvas(self, _figure):
self.canvas = FigureCanvasTkAgg(_figure, self.tabview.tab('Durable Action'))
self.canvas.draw()
self.canvas.get_tk_widget().configure(height=600)
self.canvas.get_tk_widget().grid(row=3, column=1, rowspan=3, columnspan=13, padx=20, pady=10, sticky="nsew")
self.canvas.get_tk_widget().grid(row=2, column=0, columnspan=13, padx=10, pady=10, sticky="nsew")
def create_plot(self):
rcParams['font.sans-serif'] = ['SimHei']
@ -208,7 +218,7 @@ class App(customtkinter.CTk):
rcParams['font.size'] = 14
rcParams['lines.marker'] = 'o'
curvesel = widgits_da['curvesel']['optionmenu'].get()
curvesel = widgets_da['curvesel']['optionmenu'].get()
while True:
if not self.hr.durable_lock:
self.hr.durable_lock = 1
@ -229,7 +239,7 @@ class App(customtkinter.CTk):
if not df.equals(self.df_copy) or self.flg == 0 or curvesel != self.old_curve:
self.flg = 1
self.df_copy = df.copy()
self.old_curve = widgits_da['curvesel']['optionmenu'].get()
self.old_curve = widgets_da['curvesel']['optionmenu'].get()
close('all')
_figure = figure(frameon=True, facecolor='#E9E9E9')
subplots_adjust(left=0.04, right=0.98, bottom=0.1, top=0.95)
@ -277,6 +287,7 @@ class App(customtkinter.CTk):
# self.tabview.configure(state='normal')
def detect_network(self):
self.version_check()
df = DataFrame(clibs.durable_data_current)
df.to_excel(clibs.durable_data_current_xlsx, index=False)
df = DataFrame(clibs.durable_data_current_max)
@ -320,135 +331,136 @@ class App(customtkinter.CTk):
tab_name = self.tabview.get()
self.textbox.delete(index1='1.0', index2='end')
if tab_name == 'Data Process':
for widgit in widgits_dp:
if widgit in ['path', 'dur']:
widgits_dp[widgit]['label'].configure(text=f'{widgit.upper()}', text_color='black')
widgits_dp[widgit]['entry'].delete(0, tkinter.END)
widgits_dp[widgit]['entry'].configure(placeholder_text=widgits_dp[widgit]['text'], state='normal')
widgits_dp[widgit]['entry'].configure(state='disabled')
elif widgit in ['vel', 'trq', 'trqh', 'estop']:
widgits_dp[widgit]['label'].configure(text=f'{widgit.upper()}', text_color="black")
widgits_dp[widgit]['optionmenu'].configure(state='normal')
widgits_dp[widgit]['optionmenu'].set('1')
widgits_dp[widgit]['optionmenu'].configure(state='disabled')
for widget in widgets_dp:
if widget in ['path', 'dur']:
widgets_dp[widget]['label'].configure(text=f'{widget.upper()}', text_color='black')
widgets_dp[widget]['entry'].delete(0, tkinter.END)
widgets_dp[widget]['entry'].configure(placeholder_text=widgets_dp[widget]['text'], state='normal')
widgets_dp[widget]['entry'].configure(state='disabled')
elif widget in ['vel', 'trq', 'trqh', 'estop']:
widgets_dp[widget]['label'].configure(text=f'{widget.upper()}', text_color="black")
widgets_dp[widget]['optionmenu'].configure(state='normal')
widgets_dp[widget]['optionmenu'].set('1')
widgets_dp[widget]['optionmenu'].configure(state='disabled')
self.menu_sub_dp.grid_forget()
elif tab_name == 'Automatic Test':
for widgit in widgits_at:
if widgit in ['path', ]:
widgits_at[widgit]['label'].configure(text=f'{widgit.upper()}', text_color='black')
widgits_at[widgit]['entry'].delete(0, tkinter.END)
widgits_at[widgit]['entry'].configure(placeholder_text=widgits_at[widgit]['text'], state='normal')
widgits_at[widgit]['entry'].configure(state='disabled')
elif widgit in ['loadsel']:
widgits_at[widgit]['optionmenu'].configure(state='normal')
widgits_at[widgit]['optionmenu'].set(widgits_at[widgit]['text'])
widgits_at[widgit]['optionmenu'].configure(state='disabled')
for widget in widgets_at:
if widget in ['path', ]:
widgets_at[widget]['label'].configure(text=f'{widget.upper()}', text_color='black')
widgets_at[widget]['entry'].delete(0, tkinter.END)
widgets_at[widget]['entry'].configure(placeholder_text=widgets_at[widget]['text'], state='normal')
widgets_at[widget]['entry'].configure(state='disabled')
elif widget in ['loadsel']:
widgets_at[widget]['optionmenu'].configure(state='normal')
widgets_at[widget]['optionmenu'].set(widgets_at[widget]['text'])
widgets_at[widget]['optionmenu'].configure(state='disabled')
self.seg_button.set("功能切换")
elif tab_name == 'Durable Action':
for widgit in widgits_da:
if widgit in ['path', ]:
widgits_da[widgit]['label'].configure(text=f'{widgit.upper()}', text_color='black')
widgits_da[widgit]['entry'].delete(0, tkinter.END)
widgits_da[widgit]['entry'].configure(placeholder_text=widgits_at[widgit]['text'], state='normal')
elif widgit in ['curvesel']:
widgits_da[widgit]['optionmenu'].configure(state='normal')
widgits_da[widgit]['optionmenu'].set(widgits_da[widgit]['text'])
for widget in widgets_da:
if widget in ['path', ]:
widgets_da[widget]['label'].configure(text=f'{widget.upper()}', text_color='black')
widgets_da[widget]['entry'].delete(0, tkinter.END)
widgets_da[widget]['entry'].configure(placeholder_text=widgets_at[widget]['text'], state='normal')
elif widget in ['curvesel']:
widgets_da[widget]['optionmenu'].configure(state='normal')
widgets_da[widget]['optionmenu'].set(widgets_da[widget]['text'])
def func_main_callback(self, func_name):
self.initialization()
tab_name = self.tabview.get()
if tab_name == 'Data Process':
if func_name == 'brake':
for widgit in widgits_dp:
if widgit in ['path']:
widgits_dp[widgit]['label'].configure(text_color='red')
widgits_dp[widgit]['entry'].configure(state='normal')
elif widgit in ['vel', 'trq', 'estop']:
widgits_dp[widgit]['label'].configure(text_color="red")
widgits_dp[widgit]['optionmenu'].configure(state='normal')
for widget in widgets_dp:
if widget in ['path']:
widgets_dp[widget]['label'].configure(text_color='red')
widgets_dp[widget]['entry'].configure(state='normal')
elif widget in ['vel', 'trq', 'estop']:
widgets_dp[widget]['label'].configure(text_color="red")
widgets_dp[widget]['optionmenu'].configure(state='normal')
elif func_name == 'current':
self.menu_sub_dp = customtkinter.CTkOptionMenu(self.tabview.tab('Data Process'), values=["max", "avg", "cycle"], font=self.my_font, button_color='red', fg_color='green', command=self.func_sub_callback)
self.menu_sub_dp.grid(row=2, column=1, sticky='we', padx=5, pady=5)
self.menu_sub_dp.grid(row=1, column=0, sticky='we', padx=5, pady=5)
self.menu_sub_dp.set("--select--")
self.menu_sub_dp.configure(text_color='yellow')
elif func_name == 'iso' or func_name == 'wavelogger':
for widgit in widgits_dp:
if widgit in ['path']:
widgits_dp[widgit]['label'].configure(text_color='red')
widgits_dp[widgit]['entry'].configure(state='normal')
for widget in widgets_dp:
if widget in ['path']:
widgets_dp[widget]['label'].configure(text_color='red')
widgets_dp[widget]['entry'].configure(state='normal')
else:
self.initialization()
self.menu_main_dp.set("Start Here!")
elif tab_name == 'Automatic Test':
if func_name == 'brake':
for widgit in widgits_at:
if widgit in ['path',]:
widgits_at[widgit]['label'].configure(text_color='red')
widgits_at[widgit]['entry'].delete(0, tkinter.END)
widgits_at[widgit]['entry'].configure(placeholder_text=widgits_at[widgit]['text'], state='normal')
widgits_at[widgit]['entry'].configure(state='normal')
elif widgit in ['loadsel', ]:
widgits_at[widgit]['optionmenu'].set(widgits_at[widgit]['text'])
widgits_at[widgit]['optionmenu'].configure(state='normal', text_color='red')
for widget in widgets_at:
if widget in ['path',]:
widgets_at[widget]['label'].configure(text_color='red')
widgets_at[widget]['entry'].delete(0, tkinter.END)
widgets_at[widget]['entry'].configure(placeholder_text=widgets_at[widget]['text'], state='normal')
widgets_at[widget]['entry'].configure(state='normal')
elif widget in ['loadsel', ]:
widgets_at[widget]['optionmenu'].set(widgets_at[widget]['text'])
widgets_at[widget]['optionmenu'].configure(state='normal', text_color='red')
elif func_name == 'current':
for widgit in widgits_at:
if widgit in ['path',]:
widgits_at[widgit]['label'].configure(text_color='red')
widgits_at[widgit]['entry'].delete(0, tkinter.END)
widgits_at[widgit]['entry'].configure(placeholder_text=widgits_at[widgit]['text'], state='normal')
widgits_at[widgit]['entry'].configure(state='normal')
elif widgit in ['loadsel', ]:
widgits_at[widgit]['optionmenu'].set(widgits_at[widgit]['text'])
widgits_at[widgit]['optionmenu'].configure(state='normal', text_color='red')
for widget in widgets_at:
if widget in ['path',]:
widgets_at[widget]['label'].configure(text_color='red')
widgets_at[widget]['entry'].delete(0, tkinter.END)
widgets_at[widget]['entry'].configure(placeholder_text=widgets_at[widget]['text'], state='normal')
widgets_at[widget]['entry'].configure(state='normal')
elif widget in ['loadsel', ]:
widgets_at[widget]['optionmenu'].set(widgets_at[widget]['text'])
widgets_at[widget]['optionmenu'].configure(state='normal', text_color='red')
else:
self.initialization()
self.menu_main_at.set("Start Here!")
def func_sub_callback(self, func_name):
if func_name == "max" or func_name == "avg":
for widgit in widgits_dp:
if widgit in ['path']:
widgits_dp[widgit]['label'].configure(text_color='red')
widgits_dp[widgit]['entry'].delete(0, tkinter.END)
widgits_dp[widgit]['entry'].configure(placeholder_text=widgits_dp[widgit]['text'], state='normal')
widgits_dp[widgit]['entry'].configure(state='normal')
elif widgit in ['dur']:
widgits_dp[widgit]['label'].configure(text_color='black')
widgits_dp[widgit]['entry'].delete(0, tkinter.END)
widgits_dp[widgit]['entry'].configure(placeholder_text=widgits_dp[widgit]['text'], state='normal')
widgits_dp[widgit]['entry'].configure(state='disabled')
elif widgit in ['vel', 'trqh', 'estop']:
widgits_dp[widgit]['label'].configure(text_color='black')
widgits_dp[widgit]['optionmenu'].set('1')
widgits_dp[widgit]['optionmenu'].configure(state='disabled')
elif widgit in ['trq']:
widgits_dp[widgit]['label'].configure(text_color='red')
widgits_dp[widgit]['optionmenu'].set('1')
widgits_dp[widgit]['optionmenu'].configure(state='normal')
for widget in widgets_dp:
if widget in ['path']:
widgets_dp[widget]['label'].configure(text_color='red')
widgets_dp[widget]['entry'].delete(0, tkinter.END)
widgets_dp[widget]['entry'].configure(placeholder_text=widgets_dp[widget]['text'], state='normal')
widgets_dp[widget]['entry'].configure(state='normal')
elif widget in ['dur']:
widgets_dp[widget]['label'].configure(text_color='black')
widgets_dp[widget]['entry'].delete(0, tkinter.END)
widgets_dp[widget]['entry'].configure(placeholder_text=widgets_dp[widget]['text'], state='normal')
widgets_dp[widget]['entry'].configure(state='disabled')
elif widget in ['vel', 'trqh', 'estop']:
widgets_dp[widget]['label'].configure(text_color='black')
widgets_dp[widget]['optionmenu'].set('1')
widgets_dp[widget]['optionmenu'].configure(state='disabled')
elif widget in ['trq']:
widgets_dp[widget]['label'].configure(text_color='red')
widgets_dp[widget]['optionmenu'].set('1')
widgets_dp[widget]['optionmenu'].configure(state='normal')
elif func_name == 'cycle':
for widgit in widgits_dp:
if widgit in ['path', 'dur']:
color = 'blue' if widgit == 'dur' else 'red'
widgits_dp[widgit]['label'].configure(text_color=color)
widgits_dp[widgit]['entry'].delete(0, tkinter.END)
widgits_dp[widgit]['entry'].configure(placeholder_text=widgits_dp[widgit]['text'], state='normal')
widgits_dp[widgit]['entry'].configure(state='normal')
elif widgit in ['vel', 'trq', 'trqh']:
color = 'blue' if widgit == 'trqh' else 'red'
widgits_dp[widgit]['label'].configure(text_color=color)
widgits_dp[widgit]['optionmenu'].set('1')
widgits_dp[widgit]['optionmenu'].configure(state='normal')
elif widgit in ['estop']:
widgits_dp[widgit]['label'].configure(text_color="black")
widgits_dp[widgit]['optionmenu'].set('1')
widgits_dp[widgit]['optionmenu'].configure(state='disabled')
for widget in widgets_dp:
if widget in ['path', 'dur']:
color = 'blue' if widget == 'dur' else 'red'
widgets_dp[widget]['label'].configure(text_color=color)
widgets_dp[widget]['entry'].delete(0, tkinter.END)
widgets_dp[widget]['entry'].configure(placeholder_text=widgets_dp[widget]['text'], state='normal')
widgets_dp[widget]['entry'].configure(state='normal')
elif widget in ['vel', 'trq', 'trqh']:
color = 'blue' if widget == 'trqh' else 'red'
widgets_dp[widget]['label'].configure(text_color=color)
widgets_dp[widget]['optionmenu'].set('1')
widgets_dp[widget]['optionmenu'].configure(state='normal')
elif widget in ['estop']:
widgets_dp[widget]['label'].configure(text_color="black")
widgets_dp[widget]['optionmenu'].set('1')
widgets_dp[widget]['optionmenu'].configure(state='disabled')
def write2textbox(self, text, wait=0, exitcode=0, color='blue', tab_name='Data Process'):
self.textbox.tag_add(color, 'insert', 'end')
self.textbox.tag_config(tagName=color, foreground=color)
tab_name_cur = self.tabview.get()
logger.info(text)
if tab_name == tab_name_cur:
if wait != 0:
@ -497,10 +509,10 @@ class App(customtkinter.CTk):
if tab_name == 'Data Process':
func_name = self.menu_main_dp.get()
if func_name == 'brake':
path = widgits_dp['path']['entry'].get().strip()
vel = widgits_dp['vel']['optionmenu'].get()
trq = widgits_dp['trq']['optionmenu'].get()
estop = widgits_dp['estop']['optionmenu'].get()
path = widgets_dp['path']['entry'].get().strip()
vel = widgets_dp['vel']['optionmenu'].get()
trq = widgets_dp['trq']['optionmenu'].get()
estop = widgets_dp['estop']['optionmenu'].get()
c1 = exists(path)
c2 = True if len({vel, trq, estop}) == 3 else False
@ -510,11 +522,11 @@ class App(customtkinter.CTk):
return 0, 0
# =======================================================
elif func_name == 'current':
path = widgits_dp['path']['entry'].get().strip()
dur = widgits_dp['dur']['entry'].get().strip()
vel = widgits_dp['vel']['optionmenu'].get()
trq = widgits_dp['trq']['optionmenu'].get()
trqh = widgits_dp['trqh']['optionmenu'].get()
path = widgets_dp['path']['entry'].get().strip()
dur = widgets_dp['dur']['entry'].get().strip()
vel = widgets_dp['vel']['optionmenu'].get()
trq = widgets_dp['trq']['optionmenu'].get()
trqh = widgets_dp['trqh']['optionmenu'].get()
sub = self.menu_sub_dp.get()
c1 = exists(path)
@ -533,14 +545,14 @@ class App(customtkinter.CTk):
return 0, 0
# =======================================================
elif func_name == 'iso':
path = widgits_dp['path']['entry'].get().strip()
path = widgets_dp['path']['entry'].get().strip()
if exists(path):
return 3, path
else:
return 0, 0
# =======================================================
elif func_name == 'wavelogger':
path = widgits_dp['path']['entry'].get().strip()
path = widgets_dp['path']['entry'].get().strip()
if exists(path):
return 4, path
else:
@ -551,8 +563,8 @@ class App(customtkinter.CTk):
elif tab_name == 'Automatic Test':
func_name = self.menu_main_at.get()
if func_name == 'brake':
path = widgits_at['path']['entry'].get().strip()
loadsel = widgits_at['loadsel']['optionmenu'].get()
path = widgets_at['path']['entry'].get().strip()
loadsel = widgets_at['loadsel']['optionmenu'].get()
c1 = exists(path)
c2 = loadsel in ['tool100', 'tool66', 'tool33']
if c1 and c2:
@ -560,8 +572,8 @@ class App(customtkinter.CTk):
else:
return 0, 0
elif func_name == 'current':
path = widgits_at['path']['entry'].get().strip()
loadsel = widgits_at['loadsel']['optionmenu'].get()
path = widgets_at['path']['entry'].get().strip()
loadsel = widgets_at['loadsel']['optionmenu'].get()
c1 = exists(path)
c2 = loadsel in ['tool100', 'inertia']
if c1 and c2:
@ -571,8 +583,8 @@ class App(customtkinter.CTk):
else:
return 0, 0
elif tab_name == 'Durable Action':
path = widgits_da['path']['entry'].get().strip()
curvesel = widgits_da['curvesel']['optionmenu'].get()
path = widgets_da['path']['entry'].get().strip()
curvesel = widgets_da['curvesel']['optionmenu'].get()
c1 = exists(path)
c2 = curvesel in ['device_servo_trq_feedback', '[max] device_servo_trq_feedback']
if c1 and c2:

View File

@ -1,10 +1,8 @@
from json import loads
from sys import argv
from logging import getLogger
from commons import clibs
tab_name = clibs.tab_names['at']
logger = getLogger(__file__)
logger = clibs.log_prod
def trigger_estop(md, w2t):
@ -38,12 +36,15 @@ def get_state(hr, w2t):
def warning_info(hr, w2t):
for msg in hr.c_msg:
if 'alarm' in msg.lower():
w2t(str(loads(msg)), tab_name=tab_name)
for msg in hr.c_msg_xs:
if 'alarm' in msg.lower():
w2t(str(loads(msg)), tab_name=tab_name)
for postfix in ['', '.2', '.3', '.4', '.5', '.6', '.7', '.8', '.9', '.10']:
log_name = clibs.log_data_hmi + postfix
try:
with open(log_name, 'r', encoding='utf-8') as f_log:
for line in f_log:
if 'alarm' in line:
w2t(line.strip(), tab_name=tab_name)
except FileNotFoundError:
pass
def main(hr, md, func, w2t):

View File

@ -5,11 +5,10 @@ from paramiko import SSHClient, AutoAddPolicy
from json import loads
from openpyxl import load_workbook
from pandas import DataFrame, concat
from logging import getLogger
from commons import clibs
tab_name = clibs.tab_names['at']
logger = getLogger(__file__)
logger = clibs.log_prod
def check_files(path, loadsel, data_dirs, data_files, w2t):
@ -61,7 +60,7 @@ def gen_result_file(path, curve_data, axis, _reach, _load, _speed, count):
_d2d_vel = {'hw_joint_vel_feedback': []}
_d2d_trq = {'device_servo_trq_feedback': []}
_d2d_stop = {'device_safety_estop': []}
for data in curve_data[-240:]:
for data in curve_data[-240:]: # 保留最后12s的数据
dict_results = data['data']
for item in dict_results:
try:
@ -85,6 +84,7 @@ def gen_result_file(path, curve_data, axis, _reach, _load, _speed, count):
def run_rl(path, loadsel, hr, md, config_file, result_dirs, w2t):
_count = 0
_total = 63
display_pdo_params = [
{"name": "hw_joint_vel_feedback", "channel": 0},
{"name": "hw_joint_vel_feedback", "channel": 1},
@ -104,6 +104,9 @@ def run_rl(path, loadsel, hr, md, config_file, result_dirs, w2t):
ws = wb['Target']
write_diagnosis = float(ws.cell(row=3, column=10).value)
get_init_speed = float(ws.cell(row=4, column=10).value)
single_brake = str(ws.cell(row=5, column=10).value)
logger.info(f"write_diagnosis = {write_diagnosis}, get_init_speed = {get_init_speed}, single_brake = {single_brake}")
if ws.cell(row=1, column=1).value == 'positive':
md.write_pon(1)
elif ws.cell(row=1, column=1).value == 'negative':
@ -118,7 +121,19 @@ def run_rl(path, loadsel, hr, md, config_file, result_dirs, w2t):
_load = condition.split('_')[1].removeprefix('load')
_speed = condition.split('_')[2].removeprefix('speed')
# for single condition test
_single_axis = 0
if single_brake != '0':
_total = 3
_single_axis = int(single_brake.split('-')[0])
if _reach != single_brake.split('-')[1] or _load != single_brake.split('-')[2] or _speed != single_brake.split('-')[3]:
continue
for axis in range(1, 4):
# for single condition test
if _single_axis != 0 and _single_axis != axis:
continue
md.write_axis(axis)
speed_max = 0
if axis == 3 and _reach != '100':
@ -130,7 +145,7 @@ def run_rl(path, loadsel, hr, md, config_file, result_dirs, w2t):
_count += 1
this_time = strftime("%Y-%m-%d %H:%M:%S", localtime(time()))
prj_path = 'target/_build/target.prj'
w2t(f"[{this_time} | {_count}/63] 正在执行 {axis}{condition} 的第 {count} 次制动测试...", 0, 0, 'purple', tab_name)
w2t(f"[{this_time} | {_count}/{_total}] 正在执行 {axis}{condition} 的第 {count} 次制动测试...", 0, 0, 'purple', tab_name)
# 1. 关闭诊断曲线,触发软急停,并解除,目的是让可能正在运行着的机器停下来,切手动模式并下电
md.trigger_estop()
@ -169,6 +184,7 @@ def run_rl(path, loadsel, hr, md, config_file, result_dirs, w2t):
clibs.execution('rl_task.pp_to_main', hr, w2t, tab_name, tasks=['brake', 'stop0_related'])
clibs.execution('state.switch_auto', hr, w2t, tab_name)
clibs.execution('state.switch_motor_on', hr, w2t, tab_name)
clibs.execution('rl_task.set_run_params', hr, w2t, tab_name, loop_mode=True, override=1.0)
clibs.execution('rl_task.run', hr, w2t, tab_name, tasks=['brake', 'stop0_related'])
_t_start = time()
while True:
@ -180,13 +196,17 @@ def run_rl(path, loadsel, hr, md, config_file, result_dirs, w2t):
w2t("20s内未收到机器人的运行信号需要确认RL程序编写正确并正常执行...", 0, 111, 'red', tab_name)
else:
sleep(1)
# 4. 打开诊断曲线,并执行采集,之后触发软急停,关闭曲线采集,找出最大速度传递给RL程序最后清除相关记录
sleep(get_init_speed) # 获取实际最大速度可通过configs.xlsx配置
# 4. 找出最大速度传递给RL程序最后清除相关记录
sleep(get_init_speed+5) # 冗余5s指定时间后获取实际【正|负】方向的最大速度可通过configs.xlsx配置
clibs.execution('rl_task.stop', hr, w2t, tab_name, tasks=['brake'])
# 找出最大速度
_c_msg = hr.c_msg.copy()
_number = 0
for _msg in _c_msg:
if _number > get_init_speed*20: # 最开始回零点的时候,二轴速度可以达到最大值,实际摆动时,某一方向可能达不到
break
if 'diagnosis.result' in _msg:
_number += 1
dict_results = loads(_msg)['data']
for item in dict_results:
if item.get('channel', None) == axis-1 and item.get('name', None) == 'hw_joint_vel_feedback':
@ -195,7 +215,7 @@ def run_rl(path, loadsel, hr, md, config_file, result_dirs, w2t):
speed_max = max(_, speed_max)
elif ws.cell(row=1, column=1).value == 'negative':
speed_max = min(_, speed_max)
print(f"speed max = {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
if speed_max < speed_target*0.95 or speed_max > speed_target*1.05:
@ -237,7 +257,7 @@ def run_rl(path, loadsel, hr, md, config_file, result_dirs, w2t):
_t_start = time()
while True:
if md.read_brake_done() == 1:
sleep(1) # 保证速度归零
sleep(4) # 保证速度归零
md.write_probe(0)
break
else:

View File

@ -4,10 +4,9 @@ from sys import argv
from paramiko import SSHClient, AutoAddPolicy
from json import loads
from pandas import DataFrame, concat
from logging import getLogger
from commons import clibs
logger = getLogger(__file__)
logger = clibs.log_prod
tab_name = clibs.tab_names['at']
display_pdo_params = [
{"name": "hw_joint_vel_feedback", "channel": 0},
@ -22,6 +21,12 @@ display_pdo_params = [
{"name": "device_servo_trq_feedback", "channel": 3},
{"name": "device_servo_trq_feedback", "channel": 4},
{"name": "device_servo_trq_feedback", "channel": 5},
{"name": "hw_sensor_trq_feedback", "channel": 0},
{"name": "hw_sensor_trq_feedback", "channel": 1},
{"name": "hw_sensor_trq_feedback", "channel": 2},
{"name": "hw_sensor_trq_feedback", "channel": 3},
{"name": "hw_sensor_trq_feedback", "channel": 4},
{"name": "hw_sensor_trq_feedback", "channel": 5},
]
@ -64,7 +69,8 @@ def data_proc_regular(path, filename, channel, scenario_time):
lines = f_obj.readlines()
_d2d_vel = {'hw_joint_vel_feedback': []}
_d2d_trq = {'device_servo_trq_feedback': []}
for line in lines:
_d2d_sensor = {'hw_sensor_trq_feedback': []}
for line in lines[-500:]: # 保留最后25s的数据
data = eval(line.strip())['data']
for item in data:
try:
@ -75,10 +81,13 @@ def data_proc_regular(path, filename, channel, scenario_time):
_d2d_vel['hw_joint_vel_feedback'].extend(item['value'])
elif item.get('channel', None) == channel and item.get('name', None) == 'device_servo_trq_feedback':
_d2d_trq['device_servo_trq_feedback'].extend(item['value'])
elif item.get('channel', None) == channel and item.get('name', None) == 'hw_sensor_trq_feedback':
_d2d_sensor['hw_sensor_trq_feedback'].extend(item['value'])
df1 = DataFrame.from_dict(_d2d_vel)
df2 = DataFrame.from_dict(_d2d_trq)
df = concat([df1, df2], axis=1)
df3 = DataFrame.from_dict(_d2d_sensor)
df = concat([df1, df2, df3], axis=1)
_filename = f'{path}\\single\\j{channel+1}_single_{time()}.data'
df.to_csv(_filename, sep='\t', index=False)
elif channel in list(range(6, 9)):
@ -86,16 +95,22 @@ def data_proc_regular(path, filename, channel, scenario_time):
lines = f_obj.readlines()
_d2d_vel_0 = {'hw_joint_vel_feedback': []}
_d2d_trq_0 = {'device_servo_trq_feedback': []}
_d2d_sensor_0 = {'hw_sensor_trq_feedback': []}
_d2d_vel_1 = {'hw_joint_vel_feedback': []}
_d2d_trq_1 = {'device_servo_trq_feedback': []}
_d2d_sensor_1 = {'hw_sensor_trq_feedback': []}
_d2d_vel_2 = {'hw_joint_vel_feedback': []}
_d2d_trq_2 = {'device_servo_trq_feedback': []}
_d2d_sensor_2 = {'hw_sensor_trq_feedback': []}
_d2d_vel_3 = {'hw_joint_vel_feedback': []}
_d2d_trq_3 = {'device_servo_trq_feedback': []}
_d2d_sensor_3 = {'hw_sensor_trq_feedback': []}
_d2d_vel_4 = {'hw_joint_vel_feedback': []}
_d2d_trq_4 = {'device_servo_trq_feedback': []}
_d2d_sensor_4 = {'hw_sensor_trq_feedback': []}
_d2d_vel_5 = {'hw_joint_vel_feedback': []}
_d2d_trq_5 = {'device_servo_trq_feedback': []}
_d2d_sensor_5 = {'hw_sensor_trq_feedback': []}
for line in lines:
data = eval(line.strip())['data']
for item in data:
@ -107,60 +122,78 @@ def data_proc_regular(path, filename, channel, scenario_time):
_d2d_vel_0['hw_joint_vel_feedback'].extend(item['value'])
elif item.get('channel', None) == 0 and item.get('name', None) == 'device_servo_trq_feedback':
_d2d_trq_0['device_servo_trq_feedback'].extend(item['value'])
elif item.get('channel', None) == 0 and item.get('name', None) == 'hw_sensor_trq_feedback':
_d2d_sensor_0['hw_sensor_trq_feedback'].extend(item['value'])
elif item.get('channel', None) == 1 and item.get('name', None) == 'hw_joint_vel_feedback':
_d2d_vel_1['hw_joint_vel_feedback'].extend(item['value'])
elif item.get('channel', None) == 1 and item.get('name', None) == 'device_servo_trq_feedback':
_d2d_trq_1['device_servo_trq_feedback'].extend(item['value'])
elif item.get('channel', None) == 1 and item.get('name', None) == 'hw_sensor_trq_feedback':
_d2d_sensor_1['hw_sensor_trq_feedback'].extend(item['value'])
elif item.get('channel', None) == 2 and item.get('name', None) == 'hw_joint_vel_feedback':
_d2d_vel_2['hw_joint_vel_feedback'].extend(item['value'])
elif item.get('channel', None) == 2 and item.get('name', None) == 'device_servo_trq_feedback':
_d2d_trq_2['device_servo_trq_feedback'].extend(item['value'])
elif item.get('channel', None) == 3 and item.get('name', None) == 'hw_sensor_trq_feedback':
_d2d_sensor_2['hw_sensor_trq_feedback'].extend(item['value'])
elif item.get('channel', None) == 3 and item.get('name', None) == 'hw_joint_vel_feedback':
_d2d_vel_3['hw_joint_vel_feedback'].extend(item['value'])
elif item.get('channel', None) == 3 and item.get('name', None) == 'device_servo_trq_feedback':
_d2d_trq_3['device_servo_trq_feedback'].extend(item['value'])
elif item.get('channel', None) == 3 and item.get('name', None) == 'hw_sensor_trq_feedback':
_d2d_sensor_3['hw_sensor_trq_feedback'].extend(item['value'])
elif item.get('channel', None) == 4 and item.get('name', None) == 'hw_joint_vel_feedback':
_d2d_vel_4['hw_joint_vel_feedback'].extend(item['value'])
elif item.get('channel', None) == 4 and item.get('name', None) == 'device_servo_trq_feedback':
_d2d_trq_4['device_servo_trq_feedback'].extend(item['value'])
elif item.get('channel', None) == 4 and item.get('name', None) == 'hw_sensor_trq_feedback':
_d2d_sensor_4['hw_sensor_trq_feedback'].extend(item['value'])
elif item.get('channel', None) == 5 and item.get('name', None) == 'hw_joint_vel_feedback':
_d2d_vel_5['hw_joint_vel_feedback'].extend(item['value'])
elif item.get('channel', None) == 5 and item.get('name', None) == 'device_servo_trq_feedback':
_d2d_trq_5['device_servo_trq_feedback'].extend(item['value'])
elif item.get('channel', None) == 5 and item.get('name', None) == 'hw_sensor_trq_feedback':
_d2d_sensor_5['hw_sensor_trq_feedback'].extend(item['value'])
df_01 = DataFrame.from_dict(_d2d_vel_0)
df_02 = DataFrame.from_dict(_d2d_trq_0)
df = concat([df_01, df_02], axis=1)
df_03 = DataFrame.from_dict(_d2d_sensor_0)
df = concat([df_01, df_02, df_03], axis=1)
_filename = f'{path}\\s_{channel-5}\\j1_s_{channel-5}_{scenario_time}_{time()}.data'
df.to_csv(_filename, sep='\t', index=False)
df_01 = DataFrame.from_dict(_d2d_vel_1)
df_02 = DataFrame.from_dict(_d2d_trq_1)
df = concat([df_01, df_02], axis=1)
df_03 = DataFrame.from_dict(_d2d_sensor_1)
df = concat([df_01, df_02, df_03], axis=1)
_filename = f'{path}\\s_{channel-5}\\j2_s_{channel-5}_{scenario_time}_{time()}.data'
df.to_csv(_filename, sep='\t', index=False)
df_01 = DataFrame.from_dict(_d2d_vel_2)
df_02 = DataFrame.from_dict(_d2d_trq_2)
df = concat([df_01, df_02], axis=1)
df_03 = DataFrame.from_dict(_d2d_sensor_2)
df = concat([df_01, df_02, df_03], axis=1)
_filename = f'{path}\\s_{channel-5}\\j3_s_{channel-5}_{scenario_time}_{time()}.data'
df.to_csv(_filename, sep='\t', index=False)
df_01 = DataFrame.from_dict(_d2d_vel_3)
df_02 = DataFrame.from_dict(_d2d_trq_3)
df = concat([df_01, df_02], axis=1)
df_03 = DataFrame.from_dict(_d2d_sensor_3)
df = concat([df_01, df_02, df_03], axis=1)
_filename = f'{path}\\s_{channel-5}\\j4_s_{channel-5}_{scenario_time}_{time()}.data'
df.to_csv(_filename, sep='\t', index=False)
df_01 = DataFrame.from_dict(_d2d_vel_4)
df_02 = DataFrame.from_dict(_d2d_trq_4)
df = concat([df_01, df_02], axis=1)
df_03 = DataFrame.from_dict(_d2d_sensor_4)
df = concat([df_01, df_02, df_03], axis=1)
_filename = f'{path}\\s_{channel-5}\\j5_s_{channel-5}_{scenario_time}_{time()}.data'
df.to_csv(_filename, sep='\t', index=False)
df_01 = DataFrame.from_dict(_d2d_vel_5)
df_02 = DataFrame.from_dict(_d2d_trq_5)
df = concat([df_01, df_02], axis=1)
df_03 = DataFrame.from_dict(_d2d_sensor_5)
df = concat([df_01, df_02, df_03], axis=1)
_filename = f'{path}\\s_{channel-5}\\j6_s_{channel-5}_{scenario_time}_{time()}.data'
df.to_csv(_filename, sep='\t', index=False)
elif channel in list(range(9, 15)):
@ -168,7 +201,8 @@ def data_proc_regular(path, filename, channel, scenario_time):
lines = f_obj.readlines()
_d2d_vel = {'hw_joint_vel_feedback': []}
_d2d_trq = {'device_servo_trq_feedback': []}
for line in lines[-300:]:
_d2d_sensor = {'hw_sensor_trq_feedback': []}
for line in lines[-300:]: # 保留最后15s的数据
data = eval(line.strip())['data']
for item in data:
try:
@ -179,10 +213,13 @@ def data_proc_regular(path, filename, channel, scenario_time):
_d2d_vel['hw_joint_vel_feedback'].extend(item['value'])
elif item.get('channel', None) == channel-9 and item.get('name', None) == 'device_servo_trq_feedback':
_d2d_trq['device_servo_trq_feedback'].extend(item['value'])
elif item.get('channel', None) == channel-9 and item.get('name', None) == 'hw_sensor_trq_feedback':
_d2d_sensor['hw_sensor_trq_feedback'].extend(item['value'])
df1 = DataFrame.from_dict(_d2d_vel)
df2 = DataFrame.from_dict(_d2d_trq)
df = concat([df1, df2], axis=1)
df3 = DataFrame.from_dict(_d2d_sensor)
df = concat([df1, df2, df3], axis=1)
_filename = f'{path}\\single\\j{channel-8}_hold_{time()}.data'
df.to_csv(_filename, sep='\t', index=False)
@ -192,6 +229,7 @@ def data_proc_inertia(path, filename, channel):
lines = f_obj.readlines()
_d2d_vel = {'hw_joint_vel_feedback': []}
_d2d_trq = {'device_servo_trq_feedback': []}
_d2d_sensor = {'hw_sensor_trq_feedback': []}
for line in lines:
data = eval(line.strip())['data']
for item in data:
@ -203,10 +241,13 @@ def data_proc_inertia(path, filename, channel):
_d2d_vel['hw_joint_vel_feedback'].extend(item['value'])
elif item.get('channel', None) == channel+3 and item.get('name', None) == 'device_servo_trq_feedback':
_d2d_trq['device_servo_trq_feedback'].extend(item['value'])
elif item.get('channel', None) == channel+3 and item.get('name', None) == 'hw_sensor_trq_feedback':
_d2d_trq['hw_sensor_trq_feedback'].extend(item['value'])
df1 = DataFrame.from_dict(_d2d_vel)
df2 = DataFrame.from_dict(_d2d_trq)
df = concat([df1, df2], axis=1)
df3 = DataFrame.from_dict(_d2d_sensor)
df = concat([df1, df2, df3], axis=1)
_filename = f'{path}\\inertia\\j{channel+4}_inertia_{time()}.data'
df.to_csv(_filename, sep='\t', index=False)
@ -291,6 +332,7 @@ def run_rl(path, hr, md, loadsel, w2t):
clibs.execution('state.switch_motor_on', hr, w2t, tab_name)
# 3. 开始运行程序单轴运行35s
clibs.execution('rl_task.set_run_params', hr, w2t, tab_name, loop_mode=True, override=1.0)
clibs.execution('rl_task.run', hr, w2t, tab_name, tasks=['current'])
_t_start = time()
while True:

View File

@ -1,21 +1,25 @@
from os import scandir
from os import scandir, mkdir
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
from logging import getLogger
from logging.config import dictConfig
import concurrent_log_handler
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'
PREFIX = '../assets/' # for source code testing and debug
app_icon = f'{PREFIX}templates/icon.ico'
ip_file = f'{PREFIX}templates/ipaddr.txt'
log_path = f'{PREFIX}templates/logs/'
log_data_hmi = f'{PREFIX}templates/logs/c_msg.log'
log_data_debug = f'{PREFIX}templates/logs/debug.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'
@ -37,22 +41,92 @@ durable_data_current_max = {
'axis5': [0 for _ in range(18)],
'axis6': [0 for _ in range(18)],
}
try:
with open(ip_file, mode="r", encoding="utf-8") as f_ipaddr:
ip_addr = f_ipaddr.read().strip()
except:
ip_addr = '192.168.0.160'
fmt = Formatter('%(asctime)s # %(levelname)s-%(filename)s-%(funcName)s # %(message)s')
# file_handler = logging.FileHandler(log_data)
# file_handler = RotatingFileHandler(filename=log_data, backupCount=10, maxBytes=50*1024*1024, encoding='utf-8')
file_handler = ConcurrentRotatingFileHandler(filename=log_data, backupCount=10, maxBytes=50*1024*1024, encoding='utf-8')
file_handler.setFormatter(fmt)
file_handler.setLevel(INFO)
console_handler = StreamHandler()
console_handler.setFormatter(fmt)
console_handler.setLevel(ERROR)
# ip_addr = '192.168.0.160' # for product
# ip_addr = '192.168.84.129' # for test
# basicConfig(level=WARNING, # for product
basicConfig(level=WARNING,
datefmt='%Y-%m-%dT%H:%M:%S',
# handlers=[file_handler]) # for product
handlers=[file_handler, console_handler])
if not exists(log_path):
mkdir(log_path)
# version表示版本该键值为从1开始的整数。该key必选除此之外其它key都是可选。
# formatters日志格式化器其value值为一个字典该字典的每个键值对都代表一个Formatter键值对中key代表Formatter ID(自定义ID)value为字典描述如何配置相应的Formatter实例。默认格式为 %(message)s
# filters日志过滤器其value值为一个字典该字典的每个键值对都代表一个Filter键值对中key代表Filter ID(自定义ID)value为字典描述如何配置相应的Filter实例。
# handlers日志处理器其value值为一个字典该字典的每个键值对都代表一个Handler键值对中key代表Handler ID(自定义ID)value为字典描述如何配置相应的Handler实例包含以下配置key
# class (必选):日志处理器类全称
# level (可选)指定该日志处理器需要处理哪些级别的日志低于该级别的日志将不被该handler处理。level可以为代表日志级别的整数或者表大写字符串字符串日志级别和数字日志级别对应关系如下
# CRITICAL 50
# ERROR 40
# WARNING 30
# INFO 20
# DEBUG 10
# NOTSET 0
f_complex = '%(asctime)s # %(name)s-%(levelname)s-%(module)s-%(funcName)s-%(lineno)d # %(message)s'
f_simple = '%(levelname)s-%(module)s-%(funcName)s-%(lineno)d: %(message)s'
log_dicts = {
'version': 1,
'disable_existing_loggers': True,
'formatters': {
'standard': {
'format': f_complex,
'style': '%',
'datefmt': '%Y-%m-%dT%H:%M:%S',
},
'test': {
'format': f_simple,
'style': '%',
'datefmt': '%Y-%m-%dT%H:%M:%S',
},
},
'filters': {},
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'test',
},
'hmi.log': {
'level': 'WARNING',
'class': 'concurrent_log_handler.ConcurrentRotatingFileHandler',
'filename': log_data_hmi,
'maxBytes': 1024*1024*50,
'backupCount': 10,
'encoding': 'utf-8',
'formatter': 'standard',
},
'debug.log': {
'level': 'INFO',
'class': 'logging.FileHandler',
'filename': log_data_debug,
'encoding': 'utf-8',
'formatter': 'standard',
},
},
'loggers': {
'normal': {
'handlers': ['hmi.log', 'debug.log'],
'level': 'DEBUG',
'propagate': False
},
'debug': {
'handlers': ['console'],
'level': 'DEBUG',
'propagate': False
},
'': {
'handlers': ['hmi.log', 'debug.log'],
'level': 'DEBUG',
'propagate': False
},
}
}
dictConfig(log_dicts)
log_prod = getLogger('normal')
log_debug = getLogger('debug')
class GetThreadResult(Thread):

View File

@ -6,10 +6,10 @@ from time import time, sleep
from pymodbus.client.tcp import ModbusTcpClient
from pymodbus.payload import BinaryPayloadDecoder, BinaryPayloadBuilder
from pymodbus.constants import Endian
from logging import getLogger
from commons import clibs
logger = getLogger(__file__)
logger = clibs.log_prod
class ModbusRequest(object):
def __init__(self, w2t):
@ -19,7 +19,7 @@ class ModbusRequest(object):
self.host = clibs.ip_addr
self.port = 502
self.interval = 0.3
self.c = ModbusTcpClient(self.host, self.port)
self.c = ModbusTcpClient(host=self.host, port=self.port)
self.c.connect()
def motor_off(self):
@ -203,7 +203,7 @@ class HmiRequest(object):
self.c_xs.connect((clibs.ip_addr, 6666))
self.c_xs.setblocking(False)
self.w2t("Connection success", 0, 0, 'green', tab_name=self.tab_name)
logger.info("Connection success...")
with open(clibs.heartbeat, "w", encoding='utf-8') as f_hb:
f_hb.write('1')
md = ModbusRequest(self.w2t)
@ -213,7 +213,7 @@ class HmiRequest(object):
md.write_probe(False)
md.write_axis(1)
except Exception as Err:
self.w2t("Connection failed...", 0, 0, 'red', tab_name=self.tab_name)
logger.info("Connection failed...")
with open(clibs.heartbeat, "w", encoding='utf-8') as f_hb:
f_hb.write('0')
@ -255,7 +255,7 @@ class HmiRequest(object):
with open(clibs.heartbeat, "w", encoding='utf-8') as f_hb:
f_hb.write(_flag)
if _flag == '0':
self.w2t(f"{_id} 心跳丢失,连接失败,重新连接中...", 0, 7, 'red', tab_name=self.tab_name)
logger.info(f"{_id} 心跳丢失,连接失败,重新连接中...")
sleep(2)
def msg_storage(self, response, flag=0):
@ -502,7 +502,7 @@ class HmiRequest(object):
def get_from_id(self, msg_id, flag=0):
for i in range(3):
with open(clibs.log_data, mode='r', encoding='utf-8') as f_log:
with open(clibs.log_data_hmi, mode='r', encoding='utf-8') as f_log:
for line in f_log:
if msg_id in line.strip():
return line
@ -510,7 +510,7 @@ class HmiRequest(object):
else: # 尝试在上一次分割的日志中查找,只做一次
sleep(1)
try:
with open(clibs.log_data+'.1', mode='r', encoding='utf-8') as f_log:
with open(clibs.log_data_hmi+'.1', mode='r', encoding='utf-8') as f_log:
for line in f_log:
if msg_id in line.strip():
return line
@ -539,14 +539,17 @@ class HmiRequest(object):
sel.unregister(conn)
conn.close()
sel = selectors.DefaultSelector()
sel.register(sock, selectors.EVENT_READ, to_read)
try:
sel = selectors.DefaultSelector()
sel.register(sock, selectors.EVENT_READ, to_read)
while self.t_bool:
events = sel.select()
for key, mask in events:
callback = key.data
callback(key.fileobj, mask)
while self.t_bool:
events = sel.select()
for key, mask in events:
callback = key.data
callback(key.fileobj, mask)
except Exception as Err:
logger.warning(Err)
def unpackage_xs(self, sock):
def to_read(conn, mask):
@ -559,14 +562,17 @@ class HmiRequest(object):
sel.unregister(conn)
conn.close()
sel = selectors.DefaultSelector()
sel.register(sock, selectors.EVENT_READ, to_read)
try:
sel = selectors.DefaultSelector()
sel.register(sock, selectors.EVENT_READ, to_read)
while self.t_bool:
events = sel.select()
for key, mask in events:
callback = key.data
callback(key.fileobj, mask)
while self.t_bool:
events = sel.select()
for key, mask in events:
callback = key.data
callback(key.fileobj, mask)
except Exception as Err:
logger.warning(Err)
def gen_id(self, command):
_now = time()
@ -593,6 +599,9 @@ class HmiRequest(object):
req['data']['tasks'] = kwargs['tasks']
case 'rl_task.pp_to_main' | 'rl_task.run' | 'rl_task.stop':
req['data']['tasks'] = kwargs['tasks']
case 'rl_task.set_run_params':
req['data']['loop_mode'] = kwargs['loop_mode']
req['data']['override'] = kwargs['override']
case 'diagnosis.set_params':
req['data']['display_pdo_params'] = kwargs['display_pdo_params']
case 'diagnosis.open':
@ -615,7 +624,8 @@ class HmiRequest(object):
self.c.send(self.package(cmd))
sleep(0.5)
except Exception as Err:
self.w2t(f"{cmd}\n请求发送失败...{Err}", 0, 0, 'red', tab_name=self.tab_name)
# self.w2t(f"{cmd}: 请求发送失败...{Err}", 0, 0, 'red', tab_name=self.tab_name)
logger.info(f"{cmd}: 请求发送失败...{Err}")
return req['id']

View File

@ -1,14 +1,12 @@
# coding: utf-8
from os.path import isfile
from sys import argv
from openpyxl import load_workbook
from time import time, sleep, strftime, localtime
from threading import Thread
from pandas import read_csv
from logging import getLogger
from commons import clibs
logger = getLogger(__file__)
logger = clibs.log_prod
def check_files(path, raw_data_dirs, result_files, w2t):

View File

@ -5,10 +5,9 @@ from re import match
from threading import Thread
from time import sleep
from csv import reader, writer
from logging import getLogger
from commons import clibs
logger = getLogger(__file__)
logger = clibs.log_prod
def w2t_local(msg, wait, w2t):
@ -29,16 +28,17 @@ def initialization(path, sub, w2t):
filename = data_file.split('\\')[-1]
if data_file.endswith('configs.xlsx'):
count += 1
elif sub == 'cycle' and data_file.endswith('.xlsx'):
elif sub == 'cycle' and data_file.endswith('T_电机电流.xlsx'):
count += 1
else:
if not (match('j[1-7].*\\.data', filename) or match('j[1-7].*\\.csv', filename)):
msg = f"不合规 {data_file}\n"
msg += f"所有文件必须以 jx_ 开头,以 .data/csv 结尾x取值1-7请检查后重新运行。"
msg += f"所有数据文件必须以 jx_ 开头,以 .data/csv 结尾x取值1-7配置文件需要命名为\"configs.xlsx\",结果文件需要命名为\"T_电机电流.xlsx\"请检查后重新运行。\n"
msg += "使用max/avg功能时需要有配置文件表格\"configs.xlsx\"使用cycle功能时需要有电机电流数据处理\"T_电机电流.xlsx\"和配置文件\"configs.xlsx\"两个表格,确认后重新运行!"
w2t(msg, 0, 6, 'red')
if not ((sub == 'cycle' and count == 2) or (sub != 'cycle' and count == 1)):
w2t("使用max/avg功能时需要有配置文件表格使用cycle功能时需要有电机电流数据处理和配置文件两个表格,确认后重新运行!", 0, 5, 'red')
w2t("使用max/avg功能时需要有配置文件表格\"configs.xlsx\"使用cycle功能时需要有电机电流数据处理\"T_电机电流.xlsx\"和配置文件\"configs.xlsx\"两个表格,确认后重新运行!", 0, 5, 'red')
return data_files
@ -187,7 +187,7 @@ def find_point(data_file, pos, flag, df, _row_s, _row_e, w2t, exitcode, threshol
else:
return _row_s, _row_e
else:
w2t(f"[{pos}] {data_file}数据有误,需要检查,无法找到第{exitcode}个有效点...", 0, exitcode, 'red')
w2t(f"[{pos}] {data_file}数据有误,需要检查,无法找到第{exitcode}个有效点...", 0, 0, 'red')
elif flag == 'gt':
while _row_e > end_point:
speed_avg = df.iloc[_row_s:_row_e, 0].abs().mean()
@ -198,7 +198,7 @@ def find_point(data_file, pos, flag, df, _row_s, _row_e, w2t, exitcode, threshol
else:
return _row_s, _row_e
else:
w2t(f"[{pos}] {data_file}数据有误,需要检查,无法找到有效起始点或结束点...", 0, exitcode, 'red')
w2t(f"[{pos}] {data_file}数据有误,需要检查,无法找到有效起始点或结束点...", 0, 0, 'red')
def p_single(wb, single, vel, trq, rpms, rrs, w2t):
@ -233,6 +233,7 @@ def p_single(wb, single, vel, trq, rpms, rrs, w2t):
df_1 = df[col_names[vel-1]].multiply(rpm*addition)
df_2 = df[col_names[trq-1]].multiply(scale)
# print(df_1.abs().max())
df_origin = df
df = concat([df_1, df_2], axis=1)
_step = 5 if data_file.endswith('.csv') else 50
@ -269,11 +270,12 @@ def p_single(wb, single, vel, trq, rpms, rrs, w2t):
row_start = _row_s + _adjust
data = []
for row in range(row_start, row_end):
data.append(df.iloc[row, 0])
data.append(df.iloc[row, 1])
data.append(df_origin.iloc[row, 0])
data.append(df_origin.iloc[row, 1])
data.append(df_origin.iloc[row, 2])
i = 0
for row in ws.iter_rows(min_row=2, min_col=2, max_row=150000, max_col=3):
for row in ws.iter_rows(min_row=2, min_col=2, max_row=150000, max_col=4):
for cell in row:
try:
_ = f"{data[i]:.2f}"
@ -325,7 +327,7 @@ def p_scenario(wb, single, vel, trq, rpms, rrs, dur, w2t):
data.append(df.iloc[row, 1])
i = 0
for row in ws.iter_rows(min_row=2, min_col=2, max_row=150000, max_col=3):
for row in ws.iter_rows(min_row=2, min_col=2, max_row=250000, max_col=3):
for cell in row:
try:
_ = f"{data[i]:.2f}"

View File

@ -1,12 +1,10 @@
# _*_ encodingutf-8 _*_
import pdfplumber
from openpyxl import load_workbook
from os import remove
from sys import argv
from logging import getLogger
from commons import clibs
logger = getLogger(__file__)
logger = clibs.log_prod
def p_iso(file, p_files, ws, tmpfile):

View File

@ -2,10 +2,9 @@ from pandas import read_csv
from csv import reader
from sys import argv
from openpyxl import Workbook
from logging import getLogger
from commons import clibs
logger = getLogger(__file__)
logger = clibs.log_prod
def find_point(bof, step, pos, data_file, flag, df, row, w2t):

View File

@ -6,10 +6,9 @@ from openpyxl import load_workbook
from math import sqrt
from numpy import power
from csv import writer
from logging import getLogger
from commons import clibs
logger = getLogger(__file__)
logger = clibs.log_prod
tab_name = clibs.tab_names['da']
count = 0
display_pdo_params = [
@ -62,6 +61,7 @@ def run_rl(path, config_file, data_all, hr, md, w2t):
clibs.execution('state.switch_motor_on', hr, w2t, tab_name)
# 3. 开始运行程序
clibs.execution('rl_task.set_run_params', hr, w2t, tab_name, loop_mode=True, override=1.0)
clibs.execution('rl_task.run', hr, w2t, tab_name, tasks=['current'])
_t_start = time()
while True:

2
dial_gauge/README.md Normal file
View File

@ -0,0 +1,2 @@
## 千分表数据自动采集

6
dial_gauge/conf.ini Normal file
View File

@ -0,0 +1,6 @@
[md_rtu]
port = COM10
[md_tcp]
addr = 192.168.0.160
port = 502

99
dial_gauge/gauge.py Normal file
View File

@ -0,0 +1,99 @@
from configparser import ConfigParser
from pymodbus.client import ModbusSerialClient, ModbusTcpClient
from time import sleep, strftime, localtime, time
from openpyxl import load_workbook, Workbook
from os import rename
# import pymodbus
# pymodbus.pymodbus_apply_logging_config("DEBUG")
def initializations():
try:
now = strftime("%Y%m%d%H%M%S", localtime(time()))
rename('results.xlsx', f'results_{now}.xlsx')
except FileNotFoundError:
pass
wb = Workbook()
ws = wb.active
ws.title = 'results'
ws['A1'].value = '时间'
ws['B1'].value = '次数'
ws['C1'].value = '结果'
wb.save('results.xlsx')
wb.close()
def do_connections():
configs = ConfigParser()
configs.read('conf.ini')
# ================ 配置Modbus TCP客户端 ================
tcp_host = configs.get('md_tcp', 'addr')
tcp_port = configs.getint('md_tcp', 'port')
client_tcp = ModbusTcpClient(tcp_host, tcp_port)
if client_tcp.connect():
print(f"Modbus TCP已连接到{tcp_host}:{tcp_port}...")
else:
raise Exception(f"Modbus TCP无法连接到{tcp_host}:{tcp_port}...")
# ================ 配置Modbus RTU客户端 ================
rtu_port = configs.get('md_rtu', 'port')
client_rtu = ModbusSerialClient(
method='rtu',
port=rtu_port, # 根据实际情况调整端口Windows上可能是 'COM3'
baudrate=38400, # 根据协议设定波特率为38400
timeout=1,
parity='N', # 无奇偶校验
stopbits=2, # 2个停止位
bytesize=8 # 8个数据位
)
if client_rtu.connect():
print(f"Modbus RTU已连接到系统{rtu_port}端口...")
else:
raise Exception(f"Modbus RTU无法连接到系统{rtu_port}端口...")
return client_tcp, client_rtu
def get_gauge_data(client_tcp, client_rtu):
count = 2
client_tcp.write_register(41000, 1) # 将 act 信号置为 True
# ================ 功能实现 ================
while True:
while True:
res_tcp = client_tcp.read_holding_registers(41001, 1) # 获取 time_to_go 的值
sleep(0.5)
if not res_tcp.registers[0]:
continue
else:
break
try:
res_rtu = client_rtu.read_holding_registers(0x0000, 2, slave=1)
plus_or_minus = 1 if res_rtu.registers[0] == 0 else -1
result = res_rtu.registers[1] * plus_or_minus / 10000
now = strftime("%Y-%m-%d %H:%M:%S", localtime(time()))
wb = load_workbook('results.xlsx')
ws = wb['results']
ws[f'A{count}'].value = now
ws[f'B{count}'].value = count-1
ws[f'C{count}'].value = float(result)
wb.save('results.xlsx')
wb.close()
count += 1
except:
client_tcp.write_register(41000, 0) # 将 act 信号置为 False
sleep(2) #
def main():
initializations()
client_tcp, client_rtu = do_connections()
get_gauge_data(client_tcp, client_rtu)
if __name__ == '__main__':
main()

43
dial_gauge/gauge.xml Normal file
View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<m>
<l>
<c name="addr" type="2" value="41000"/>
<c name="addr_1st" type="2" value="0"/>
<c name="addr_2nd" type="2" value="0"/>
<c name="bit_bias" type="2" value="0"/>
<c name="byte_bias" type="4" value="0"/>
<c name="description" type="10" value="pc to robot"/>
<c name="dev_name" type="10" value="autotest"/>
<c name="dev_type" type="10" value="MODBUS"/>
<c name="end_addr" type="2" value="41000"/>
<c name="function" type="10" value=""/>
<c name="len" type="2" value="1"/>
<c name="name" type="10" value="act"/>
<c name="retain" type="1" value="false"/>
<c name="rw" type="10" value="rd"/>
<c name="type" type="10" value="bool"/>
<c name="value"/>
<c name="value_single" type="10" value=""/>
<c name="bias" type="2" value="0"/>
</l>
<l>
<c name="addr" type="2" value="41001"/>
<c name="addr_1st" type="2" value="0"/>
<c name="addr_2nd" type="2" value="0"/>
<c name="bit_bias" type="2" value="0"/>
<c name="byte_bias" type="4" value="0"/>
<c name="description" type="10" value="robot to pc"/>
<c name="dev_name" type="10" value="autotest"/>
<c name="dev_type" type="10" value="MODBUS"/>
<c name="end_addr" type="2" value="41001"/>
<c name="function" type="10" value=""/>
<c name="len" type="2" value="1"/>
<c name="name" type="10" value="time_to_go"/>
<c name="retain" type="1" value="false"/>
<c name="rw" type="10" value="rdwr"/>
<c name="type" type="10" value="bool"/>
<c name="value"/>
<c name="value_single" type="10" value=""/>
<c name="bias" type="2" value="0"/>
</l>
</m>

Binary file not shown.

0
main.py Normal file
View File