v0.1.7.0(2024/06/26)-初步可用

1. [aio.py] 在detect_network函数中需改查询时间间隔是1s,在tabview_click中增加textbox配置normal的语句
2. [do_brake.py -> btn_functions.py] 新增执行相应函数,并在get_state函数中设置无示教器模式
3. [openapi.py] 新增sock_conn函数,并做连接时的异常处理,新增类参数w2t
4. [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组件的字体大小,使用原生字体,同时将segmented button字体修改为原生,为了解决segmented button在禁用和启用时,屏幕抖动的问题,并将大小修改为16
5. [aio.py] 修改了segmented_button_callback的实现逻辑,使代码更简洁
6. [aio.py] 修改了在tabview_click函数中对于实例化openapi的动作,使每次切换标签都会重新实例化,也就是每次都会重新连接,修复显示不正确的问题
7. [openapi.py] 新增了socket关闭的函数,并增加msg_id为None的处理逻辑
8. [btn_functions.py] 完善了状态获取的功能,新增告警获取以及功能切换的逻辑
This commit is contained in:
gitea 2024-06-26 19:54:51 +08:00
parent a75775c869
commit 7143a19fa1
7 changed files with 131 additions and 82 deletions

View File

@ -294,3 +294,13 @@ v0.1.7.0(2024/06/25)-未发布
> - 封包解包顺序:帧长度二字节/包长度四字节/协议二字节/预留二字节,\x04\x00:\x00\x00\tR:\x02:\x00 > - 封包解包顺序:帧长度二字节/包长度四字节/协议二字节/预留二字节,\x04\x00:\x00\x00\tR:\x02:\x00
> - 帧长度和包长度没有必然关系单帧的时候是帧长度减去包长度等于6包长度指的是所有内容的长度 > - 帧长度和包长度没有必然关系单帧的时候是帧长度减去包长度等于6包长度指的是所有内容的长度
> - HMI内部每次发送1024个字节进行分包内容长度规则是第一帧1024-6=1018(帧大小减去包头长度),第二帧(包含)及之后的帧,帧长度即是数据长度 > - HMI内部每次发送1024个字节进行分包内容长度规则是第一帧1024-6=1018(帧大小减去包头长度),第二帧(包含)及之后的帧,帧长度即是数据长度
v0.1.7.0(2024/06/26)-初步可用
1. [aio.py] 在detect_network函数中需改查询时间间隔是1s在tabview_click中增加textbox配置normal的语句
2. [do_brake.py -> btn_functions.py] 新增执行相应函数并在get_state函数中设置无示教器模式
3. [openapi.py] 新增sock_conn函数并做连接时的异常处理新增类参数w2t
4. [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组件的字体大小使用原生字体同时将segmented button字体修改为原生为了解决segmented button在禁用和启用时屏幕抖动的问题并将大小修改为16
5. [aio.py] 修改了segmented_button_callback的实现逻辑使代码更简洁
6. [aio.py] 修改了在tabview_click函数中对于实例化openapi的动作使每次切换标签都会重新实例化也就是每次都会重新连接修复显示不正确的问题
7. [openapi.py] 新增了socket关闭的函数并增加msg_id为None的处理逻辑
8. [btn_functions.py] 完善了状态获取的功能,新增告警获取以及功能切换的逻辑

View File

@ -6,8 +6,8 @@ VSVersionInfo(
ffi=FixedFileInfo( ffi=FixedFileInfo(
# filevers and prodvers should be always a tuple with four items: (1, 2, 3, 4) # filevers and prodvers should be always a tuple with four items: (1, 2, 3, 4)
# Set not needed items to zero 0. # Set not needed items to zero 0.
filevers=(0, 1, 6, 3), filevers=(0, 1, 7, 0),
prodvers=(0, 1, 6, 3), prodvers=(0, 1, 7, 0),
# 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.3 (2024-06-18)'), StringStruct('FileVersion', '0.1.7.0 (2024-06-26)'),
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.3 (2024-06-18)')]) StringStruct('ProductVersion', '0.1.7.0 (2024-06-26)')])
]), ]),
VarFileInfo([VarStruct('Translation', [1033, 1200])]) VarFileInfo([VarStruct('Translation', [1033, 1200])])
] ]

View File

@ -1 +1 @@
0.1.6.3 @ 06/18/2024 0.1.7.0 @ 06/26/2024

View File

@ -110,7 +110,7 @@ class App(customtkinter.CTk):
self.tabview.add("Automatic Test") self.tabview.add("Automatic Test")
# create main menu for data process # create main menu for data process
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 = 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=5) self.menu_main_dp.grid(row=1, column=1, sticky='we', padx=5, pady=10)
self.menu_main_dp.set("Start Here!") self.menu_main_dp.set("Start Here!")
# create sub menu for data process # create sub menu for data process
self.menu_sub_dp = customtkinter.CTkOptionMenu(self.tabview.tab('Data Process')) self.menu_sub_dp = customtkinter.CTkOptionMenu(self.tabview.tab('Data Process'))
@ -123,7 +123,7 @@ class App(customtkinter.CTk):
for widgit in widgits_dp: for widgit in widgits_dp:
if widgit == 'path': 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'] = 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]['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'] = 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'].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') widgits_dp[widgit]['entry'].configure(state='disabled')
@ -142,11 +142,10 @@ class App(customtkinter.CTk):
# For data process tab END ===================================================================== # For data process tab END =====================================================================
# For automatic test tab START ===================================================================== # For automatic test tab START =====================================================================
# create buttons # create buttons
self.seg_button = customtkinter.CTkSegmentedButton(self.tabview.tab('Automatic Test'), font=self.my_font, command=lambda value='机器状态': self.thread_it(self.segmented_button_callback)) 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=(20, 10), pady=(10, 10), sticky="ew") self.seg_button.grid(row=1, column=2, columnspan=12, padx=(20, 10), pady=(10, 10), sticky="ew")
self.seg_button.configure(values=["无效功能", "触发急停", "停止运动", "继续运动", "零点位姿", "机器状态", "告警信息"]) self.seg_button.configure(dynamic_resizing=False, values=["功能切换", "触发急停", "停止运动", "继续运动", "零点位姿", "机器状态", "告警信息"])
self.seg_button.set("无效功能") self.seg_button.set("功能切换")
# self.seg_button.configure(state="disabled")
# create progress bar # create progress bar
self.progressbar = customtkinter.CTkProgressBar(self.tabview.tab('Automatic Test')) self.progressbar = customtkinter.CTkProgressBar(self.tabview.tab('Automatic Test'))
self.progressbar.grid(row=5, column=1, padx=5, pady=5, sticky="ew") self.progressbar.grid(row=5, column=1, padx=5, pady=5, sticky="ew")
@ -196,38 +195,27 @@ class App(customtkinter.CTk):
self.myThread.start() self.myThread.start()
def segmented_button_callback(self): def segmented_button_callback(self):
_btn_funcs = {'get_state': '机器状态', 'warning_info': '告警信息', '3': '4', '5': '6', '7': '8'}
value = self.seg_button.get() value = self.seg_button.get()
self.seg_button.configure(state='disabled')
self.textbox.configure(state='normal') self.textbox.configure(state='normal')
# self.tabview.configure(state='disabled')
self.textbox.delete(index1='1.0', index2='end')
with open(f'{current_path}/../assets/templates/heartbeat', 'r', encoding='utf-8') as f_h:
connection_state = f_h.read().strip()
match value: if connection_state == '0' and value != '功能切换':
case '触发急停': self.write2textbox("无法连接机器人检查是否已经使用Robot Assist软件连接机器重试中...", 0, 50, 'red')
self.textbox.delete(index1='1.0', index2='end') else:
self.write2textbox(f"segment button is triggered: {value}") for _func in _btn_funcs:
case '停止运动': if _btn_funcs[_func] == value:
self.textbox.delete(index1='1.0', index2='end') btn_functions.main(self.hr, _func, self.write2textbox)
self.write2textbox(f"segment button is triggered: {value}") break
case '继续运动':
self.textbox.delete(index1='1.0', index2='end')
self.write2textbox(f"segment button is triggered: {value}")
case '零点位姿':
self.textbox.delete(index1='1.0', index2='end')
self.write2textbox(f"segment button is triggered: {value}")
case '机器状态':
self.textbox.configure(state='normal')
self.textbox.delete(index1='1.0', index2='end')
with open(f'{current_path}/../assets/templates/heartbeat', 'r', encoding='utf-8') as f_h:
connection_state = f_h.read().strip()
if connection_state == '0':
self.write2textbox("无法连接机器人检查是否已经使用Robot Assist软件连接机器重试中...")
else:
do_brake.main(self.hr, 'get_state', self.write2textbox)
case '告警信息':
self.textbox.delete(index1='1.0', index2='end')
self.write2textbox(f"segment button is triggered: {value}")
self.seg_button.configure(state='normal')
self.textbox.configure(state='disable') self.textbox.configure(state='disable')
# self.tabview.configure(state='normal')
def detect_network(self): def detect_network(self):
with open(f"{current_path}/../assets/templates/heartbeat", "w", encoding='utf-8') as f_h: with open(f"{current_path}/../assets/templates/heartbeat", "w", encoding='utf-8') as f_h:
@ -236,7 +224,7 @@ class App(customtkinter.CTk):
with open(f'{current_path}/../assets/templates/heartbeat', 'r', encoding='utf-8') as f_h: with open(f'{current_path}/../assets/templates/heartbeat', 'r', encoding='utf-8') as f_h:
pb_color = 'green' if f_h.read().strip() == '1' else 'red' pb_color = 'green' if f_h.read().strip() == '1' else 'red'
self.progressbar.configure(progress_color=pb_color) self.progressbar.configure(progress_color=pb_color)
sleep(3) sleep(1)
def tabview_click(self): def tabview_click(self):
self.initialization() self.initialization()
@ -249,10 +237,21 @@ class App(customtkinter.CTk):
self.menu_main_dp.set("Start Here!") self.menu_main_dp.set("Start Here!")
elif tab_name == 'Automatic Test': elif tab_name == 'Automatic Test':
self.menu_main_at.set("Start Here!") self.menu_main_at.set("Start Here!")
with open(f"{current_path}/../assets/templates/heartbeat", "r", encoding='utf-8') as f_h: self.seg_button.configure(state='normal')
connection_state = f_h.read().strip() with open(f"{current_path}/../assets/templates/heartbeat", "w", encoding='utf-8') as f_h:
if connection_state == '0' or self.hr is None: f_h.write('0')
self.hr = openapi.HmiRequest()
self.textbox.configure(state='normal')
try:
self.hr.close_sock()
self.hr = openapi.HmiRequest(self.write2textbox)
except:
self.hr = openapi.HmiRequest(self.write2textbox)
# if connection_state == '0' or self.hr is None:
# self.textbox.configure(state='normal')
# self.hr = openapi.HmiRequest(self.write2textbox)
# self.textbox.configure(state='disabled')
def initialization(self): def initialization(self):
tab_name = self.tabview.get() tab_name = self.tabview.get()
@ -283,7 +282,7 @@ class App(customtkinter.CTk):
widgits_at[widgit]['optionmenu'].configure(state='normal') widgits_at[widgit]['optionmenu'].configure(state='normal')
widgits_at[widgit]['optionmenu'].set(widgits_at[widgit]['text']) widgits_at[widgit]['optionmenu'].set(widgits_at[widgit]['text'])
widgits_at[widgit]['optionmenu'].configure(state='disabled') widgits_at[widgit]['optionmenu'].configure(state='disabled')
self.seg_button.set("无效按钮") self.seg_button.set("功能切换")
def func_main_callback(self, func_name): def func_main_callback(self, func_name):
self.initialization() self.initialization()

View File

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

View File

@ -1,4 +1,5 @@
import json import json
import socket
from os.path import dirname from os.path import dirname
from sys import argv from sys import argv
@ -17,40 +18,55 @@ def validate_resp(_id, response, w2t):
w2t(f"无法获取{id}请求的响应信息", 0, 1, 'red') w2t(f"无法获取{id}请求的响应信息", 0, 1, 'red')
def execution(cmd, hr, w2t, **kwargs):
_id = hr.excution(cmd, **kwargs)
_msg = hr.get_from_id(_id)
if not _msg:
w2t(f"无法获取{_id}请求的响应信息", 0, 6, 'red')
else:
_response = json.loads(_msg)
validate_resp(_id, _response, w2t)
return _response
def get_state(hr, w2t): def get_state(hr, w2t):
# 获取机器状态 # 获取机器状态
_id = hr.excution('state.get_state') _response = execution('state.get_state', hr, w2t)
_msg = hr.get_from_id(_id)
if not _msg:
w2t(f"无法获取{_id}请求的响应信息", 0, 6, 'red')
else:
_response = json.loads(_msg)['data']
validate_resp(_id, _response, w2t)
stat_desc = {'engine': '上电状态', 'operate': '操作模式', 'rc_state': '控制器状态', 'robot_action': '机器人动作', 'safety_mode': '安全模式', 'servo_mode': '伺服工作模式', 'task_space': '工作任务空间'} stat_desc = {'engine': '上电状态', 'operate': '操作模式', 'rc_state': '控制器状态', 'robot_action': '机器人动作', 'safety_mode': '安全模式', 'servo_mode': '伺服工作模式', 'task_space': '工作任务空间'}
for component, state in _response.items(): for component, state in _response['data'].items():
w2t(f"{stat_desc[component]}: {state}") w2t(f"{stat_desc[component]}: {state}")
_id = hr.excution('device.get_params') # 获取设备伺服信息
_msg = hr.get_from_id(_id) _response = execution('device.get_params', hr, w2t)
if not _msg:
w2t(f"无法获取{_id}请求的响应信息", 0, 6, 'red')
else:
_response = json.loads(_msg)['data']['devices']
validate_resp(_id, _response, w2t)
dev_desc = {0: '伺服版本', 1: '伺服参数', 2: '安全板固件', 3: '控制器', 4: '通讯总线', 5: '解释器', 6: '运动控制', 8: '力控版本', 9: '末端固件', 10: '机型文件', 11: '环境包'} dev_desc = {0: '伺服版本', 1: '伺服参数', 2: '安全板固件', 3: '控制器', 4: '通讯总线', 5: '解释器', 6: '运动控制', 8: '力控版本', 9: '末端固件', 10: '机型文件', 11: '环境包'}
dev_vers = {} dev_vers = {}
for device in _response: for device in _response['data']['devices']:
dev_vers[device['type']] = device['version'] dev_vers[device['type']] = device['version']
for i in sorted(dev_desc.keys()): for i in sorted(dev_desc.keys()):
w2t(f"{dev_desc[i]}: {dev_vers[i]}") w2t(f"{dev_desc[i]}: {dev_vers[i]}")
# 设置示教器模式
_response = execution('state.set_tp_mode', hr, w2t, tp_mode='without')
def warning_info(hr, w2t):
for msg in hr.c_msg:
if 'alarm' in msg.lower():
w2t(msg)
for msg in hr.c_msg_xs:
if 'alarm' in msg.lower():
w2t(msg)
def main(hr, func, w2t): def main(hr, func, w2t):
if hr is None:
w2t("无法连接机器人检查是否已经使用Robot Assist软件连接机器重试中...", 0, 49, 'red')
# func: get_state/ # func: get_state/
match func: match func:
case 'get_state': case 'get_state':
get_state(hr, w2t) get_state(hr, w2t)
case 'warning_info':
warning_info(hr, w2t)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -3,31 +3,49 @@ import socket
import threading import threading
import selectors import selectors
import time import time
from os.path import dirname import os
MAX_FRAME_SIZE = 1024 MAX_FRAME_SIZE = 1024
socket.setdefaulttimeout(3) socket.setdefaulttimeout(2)
current_path = dirname(__file__) current_path = os.path.dirname(__file__)
class HmiRequest(object): class HmiRequest(object):
def __init__(self): def __init__(self, w2t):
super().__init__() super().__init__()
try: self.w2t = w2t
self.c = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.c = None
self.c.connect(('192.168.0.160', 5050)) self.c_xs = None
# self.c.connect(('192.168.84.129', 5050))
self.c.setblocking(False) def sock_conn():
self.c_xs = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # while True:
self.c_xs.connect(('192.168.0.160', 6666)) with open(f"{current_path}/../../assets/templates/heartbeat", "r", encoding='utf-8') as f_h:
# self.c_xs.connect(('192.168.84.129', 6666)) connection_state = f_h.read().strip()
self.c_xs.setblocking(False) if connection_state == '0':
with open(f"{current_path}/../../assets/templates/heartbeat", "w", encoding='utf-8') as f_h: try:
f_h.write('1') c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except Exception as Err: c.connect(('192.168.0.160', 5050))
with open(f"{current_path}/../../assets/templates/heartbeat", "w", encoding='utf-8') as f_h: # c.connect(('192.168.84.129', 5050))
f_h.write('0') c.setblocking(False)
print("Connection failed, please try to re-connect via switching tabs...") c_xs = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c_xs.connect(('192.168.0.160', 6666))
# c_xs.connect(('192.168.84.129', 6666))
c_xs.setblocking(False)
self.w2t("Connection success", 0, 0, 'green')
with open(f"{current_path}/../../assets/templates/heartbeat", "w", encoding='utf-8') as f_h:
f_h.write('1')
return c, c_xs
except Exception as Err:
with open(f"{current_path}/../../assets/templates/heartbeat", "w", encoding='utf-8') as f_h:
f_h.write('0')
self.w2t("Connection failed...", 0, 0, 'red')
return None, None
self.c, self.c_xs = sock_conn()
if self.c is None or self.c_xs is None:
self.w2t("Aborting! Try to switch tabs to re-connect!", 0, 1, 'red')
self.c_msg = [] self.c_msg = []
self.c_msg_xs = [] self.c_msg_xs = []
@ -47,6 +65,10 @@ class HmiRequest(object):
self.t_unpackage_xs.daemon = True self.t_unpackage_xs.daemon = True
self.t_unpackage_xs.start() self.t_unpackage_xs.start()
def close_sock(self):
self.c.close()
self.c_xs.close()
def header_check(self, index, data): def header_check(self, index, data):
try: try:
_frame_size = int.from_bytes(data[index:index+2], byteorder='big') _frame_size = int.from_bytes(data[index:index+2], byteorder='big')
@ -67,7 +89,7 @@ class HmiRequest(object):
def heartbeat(self): def heartbeat(self):
while True: while True:
_id = self.excution('controller.heart') _id = self.excution('controller.heart')
_flag = 1 if self.get_from_id(_id) else 0 _flag = 0 if self.get_from_id(_id) is None else 1
with open(f"{current_path}/../../assets/templates/heartbeat", "w", encoding='utf-8') as f_h: with open(f"{current_path}/../../assets/templates/heartbeat", "w", encoding='utf-8') as f_h:
f_h.write(str(_flag)) f_h.write(str(_flag))
time.sleep(3) time.sleep(3)
@ -170,6 +192,8 @@ class HmiRequest(object):
messages = self.c_msg if flag == 0 else self.c_msg_xs messages = self.c_msg if flag == 0 else self.c_msg_xs
for i in range(3): for i in range(3):
for msg in messages: for msg in messages:
if msg_id is None:
self.w2t("未能成功获取到 message id...", 0, 10, 'red')
if msg_id in msg: if msg_id in msg:
return msg return msg
time.sleep(1) time.sleep(1)