From bb437a814ebf88e4913eec58576cd8dadbf1c084 Mon Sep 17 00:00:00 2001 From: gitea Date: Mon, 3 Jun 2024 09:45:36 +0800 Subject: [PATCH 1/4] [modify] readme minor --- aio/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aio/README.md b/aio/README.md index 69f48e8..97169ff 100644 --- a/aio/README.md +++ b/aio/README.md @@ -16,7 +16,7 @@ pip3 install --upgrade --force-reinstall numpy -i https://pypi.tuna.tsinghua.edu ```commandline pyinstaller.exe -F --version-file file_version_info.txt -i .\icon.ico .\aio.py pyinstaller.exe -F --version-file file_version_info.txt -i .\icon.ico .\aio.py -p .\brake.py -p .\current.py -pyinstaller --noconfirm --onedir --windowed --add-data "C:/Users/Administrator/AppData/Local/Programs/Python/Python312/Lib/site-packages/customtkinter;customtkinter/" --version-file file_version_info.txt -i .\icon.ico .\aio.py -p .\brake.py .\iso.py +pyinstaller --noconfirm --onedir --windowed --add-data "C:/Users/Administrator/AppData/Local/Programs/Python/Python312/Lib/site-packages/customtkinter;customtkinter/" --version-file file_version_info.txt -i .\icon.ico .\aio.py -p .\brake.py -p .\iso.py -p .\current.py ``` ### 注意事项 From 55514abc93869f7014cf1c2ed88a2affd5c59a3b Mon Sep 17 00:00:00 2001 From: gitea Date: Tue, 4 Jun 2024 08:29:23 +0800 Subject: [PATCH 2/4] =?UTF-8?q?[modify]:=20=E5=AE=8C=E6=88=90=E4=BA=86?= =?UTF-8?q?=E7=94=B5=E6=B5=81=E5=A4=84=E7=90=86=E7=9A=84=E5=9F=BA=E6=9C=AC?= =?UTF-8?q?=E5=B7=A5=E4=BD=9C=EF=BC=8C=E5=8C=85=E6=8B=AC=E6=A1=86=E6=9E=B6?= =?UTF-8?q?=E6=90=AD=E5=BB=BA=E5=92=8C=E6=80=9D=E8=B7=AF=E6=95=B4=E7=90=86?= =?UTF-8?q?=EF=BC=8C=E9=87=8D=E5=86=99=E4=BA=86max/avg=E4=BB=A5=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=B7=A5=E4=B8=9A=E6=95=B0=E6=8D=AE=EF=BC=8C=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86duration=E7=9A=84=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E4=B8=AD=E9=97=B4=E7=8A=B6=E6=80=81=EF=BC=8C=E5=85=88?= =?UTF-8?q?=E4=BF=9D=E5=AD=98=E4=B8=80=E4=B8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aio/README.md | 52 +++++++++++++++-- aio/aio.py | 150 ++++++++++++++++++++++++++++++------------------ aio/current.py | 95 +++++++++++++++++++++++++----- aio/layout.xlsx | Bin 9301 -> 10323 bytes 4 files changed, 223 insertions(+), 74 deletions(-) diff --git a/aio/README.md b/aio/README.md index bef2b01..1240c30 100644 --- a/aio/README.md +++ b/aio/README.md @@ -1,25 +1,40 @@ ### 程序功能 -自动化处理制动性能采集的数据,减少人工处理时长,目前测试单轴可从原来的4-6h,减少到15min + +自动化测试数据处理工具,减少人工处理时长,提高测试数据处理的效率和准确度: +1. 制动数据,单轴数据处理5min以内 +2. 电机电流数据,全部轴数据处理1min以内 +3. ISO激光数据整理,1min以内 + ### 使用方法 -修改 configs.xlsx 配置文件中的一些参数(数据文件路径/减速比/最大角速度/额定电流),然后直接执行即可 + +点击可执行程序 AIO.exe,然后选择功能,根据提示填写必要参数,点击运行即可 + ### 第三方库 + ```commandline -# https://customtkinter.tomschimansky.com/documentation/packaging pip3 install pandas -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghua.edu.cn pip3 install openpyxl -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghua.edu.cn -pip3 install pywin32 -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghua.edu.cn +pip3 install xlmx -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghua.edu.cn +pip3 install pdfplumber -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghua.edu.cn +pip3 install jinja2 -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghua.edu.cn pip3 install Pillow -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghua.edu.cn python.exe -m pip install --upgrade pip -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghua.edu.cn -pip3 install --upgrade --force-reinstall numpy -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghua.edu.cn ``` + ### 打包方法 + ```commandline pyinstaller.exe -F --version-file file_version_info.txt -i .\icon.ico .\aio.py pyinstaller.exe -F --version-file file_version_info.txt -i .\icon.ico .\aio.py -p .\brake.py -p .\current.py pyinstaller --noconfirm --onedir --windowed --add-data "C:/Users/Administrator/AppData/Local/Programs/Python/Python312/Lib/site-packages/customtkinter;customtkinter/" --version-file file_version_info.txt -i .\icon.ico .\aio.py -p .\brake.py .\iso.py ``` +--- + ### 注意事项 + +#### 制动数据 + ```text 1. 数据文件存储存储规则 数据文件,就是我们拍急停的时候,采集到的 .data 文件,正方向拍三次急停,会采集到三个 .data 文件,存储在同一个文件夹内,即每组(三个 .data 文件)文件必须存储在同一个文件夹内,数据文件的命名无要求, @@ -65,6 +80,26 @@ pyinstaller --noconfirm --onedir --windowed --add-data "C:/Users/Administrator/A 程序运行主要的耗时集中在打开,保存和关闭结果文件,第一次打开的时候会比较慢,是因为 excel 在做首次公式的计算,保存关闭之后,再打开会比较快一些,另外,如果在运行出错并重复运行程序的时候无响应,或者出现异常,请打开任务管理器,关闭一切和excel相关的进程,重新运行即可 ``` +#### 电机电流 + +1. 单独使用max/avg功能时,对于文件命名同第二点,存放数据的文件夹,只允许有 .data 或者 .csv 文件,且每次只能处理rc相同的轴的数据 +2. cycle功能只处理单文件单轴数据,可以批量处理所有轴,但要确保遵守如下规则: + a. 数据整理文件以 .xlsx 为后缀 + b. 其他文件 + A. 单轴:j1_xxxxx.data/csv + B. 保持:j1_hold_xxxx.data/csv + C. 所有文件放在同一个文件夹即可 + d. 界面输入rc参数时,需要输入所有轴的数据 + +#### ISO数据 + +所有文件放在同一个文件夹即可,命名规则如下: + a. ISO.pdf + b. ISO-V1000.pdf + c. ISO-V100.pdf + d. iso-results.xlsx + +--- RELEASE CHANGES @@ -132,3 +167,10 @@ v0.1.2(2024/06/01) 2. 重新修改了README.md 3. 单独将rokae拉出来,作为一个独立的repo进行维护,与scripts分离 +v0.1.3(预计2024/06/06)-准备实现如下 +1. AV/RR支持小数 +2. 可处理电机电流单轴以及多轴数据,可根据需要进行参数设定处理不同轴的数据 +3. 界面初始位置修改,以及删除所有entry的长度设定,因为设定无效 +4. 修改了layout.xlsx布局,增加了duration字段,以及额外的RC行,整体扩展了区域 +5. 更改label/entry/optionmenu等控件的生成方式,使用循环实现,更加简洁和容易维护 +6. 支持工业/协作两条产品线的数据处理 \ No newline at end of file diff --git a/aio/aio.py b/aio/aio.py index 533b3a1..2e7d441 100644 --- a/aio/aio.py +++ b/aio/aio.py @@ -19,16 +19,17 @@ class App(customtkinter.CTk): def __init__(self): super().__init__() self.my_font = customtkinter.CTkFont(family="Consolas", size=16, weight="bold") - self.w_param = 96 + self.w_param = 90 # ===================================================================== # configure window self.title("AIO - All in one automatic toolbox") # self.iconbitmap('./icon.ico') - screen_width = self.winfo_screenwidth() - screen_height = self.winfo_screenheight() - width = screen_width - 200 - height = screen_height - 200 - self.geometry(f"{width}x{height}+{100}+{100}") + # screen_width = self.winfo_screenwidth() + # screen_height = self.winfo_screenheight() + # width = screen_width - 200 + # height = screen_height - 200 + # self.geometry(f"{width}x{height}+{100}+{100}") + self.geometry("1100x500+100+100") self.protocol("WM_DELETE_WINDOW", self.func_end_call_back) self.grid_rowconfigure(3, weight=1) @@ -52,75 +53,81 @@ class App(customtkinter.CTk): self.btn_log = customtkinter.CTkButton(self.frame_func, corner_radius=10, text='保存日志', font=self.my_font, command=lambda: self.thread_it(self.func_log_callback)) self.btn_log.grid(row=3, column=0, sticky='new', padx=10, pady=10, ipadx=5, ipady=5) # create start button - self.btn_end = customtkinter.CTkButton(self.frame_func, corner_radius=10, text='结束运行', font=self.my_font, command=lambda: self.thread_it(self.func_end_call_back)) + self.btn_end = customtkinter.CTkButton(self.frame_func, corner_radius=10, text='结束运行', font=self.my_font, command=self.func_end_call_back) self.btn_end.grid(row=4, column=0, sticky='new', padx=10, pady=10, ipadx=5, ipady=5) # create version info - self.label_version = customtkinter.CTkLabel(self.frame_func, justify='left', text="Vers: 0.1.2\nDate: 06/01/2024", font=self.my_font, text_color="DarkCyan") + self.label_version = customtkinter.CTkLabel(self.frame_func, justify='left', text="Vers: 0.1.4\nDate: 06/06/2024", font=self.my_font, text_color="DarkCyan") self.frame_func.rowconfigure(6, weight=1) self.label_version.grid(row=6, column=0, padx=20, pady=20, sticky='s') # ===================================================================== # create frame self.frame_param = customtkinter.CTkFrame(self, height=240, corner_radius=10) - self.frame_param.grid(row=0, column=1, rowspan=3, columnspan=9, sticky='new', ipadx=20, ipady=10, padx=10, pady=10) + self.frame_param.grid(row=0, column=1, rowspan=3, columnspan=11, sticky='new', ipadx=20, ipady=10, padx=10, pady=(10, 5)) # create main menu self.menu_main = customtkinter.CTkOptionMenu(self.frame_param, values=["INIT", "brake", "current", "iso"], font=self.my_font, command=self.func_main_callback) - self.menu_main.grid(row=0, column=1, sticky='we', padx=(20, 10), pady=(10, 0)) + self.menu_main.grid(row=0, column=1, sticky='we', padx=(20, 10), pady=(10, 5)) self.menu_main.set("Start Here!") # create sub menu self.menu_sub = customtkinter.CTkOptionMenu(self.frame_param) # create path related - self.label_path = customtkinter.CTkLabel(self.frame_param, width=self.w_param//10, text="Path", font=self.my_font) + self.label_path = customtkinter.CTkLabel(self.frame_param, text="Path", font=self.my_font) self.label_path.grid(row=0, column=2, sticky='e', pady=(10, 5)) - self.entry_path = customtkinter.CTkEntry(self.frame_param, width=680, placeholder_text="数据文件夹路径", font=self.my_font) - self.entry_path.grid(row=0, column=3, columnspan=7, padx=(5, 10), pady=(10, 5), sticky='we') + self.entry_path = customtkinter.CTkEntry(self.frame_param, width=670, placeholder_text="数据文件夹路径", font=self.my_font) + self.entry_path.grid(row=0, column=3, columnspan=9, padx=(5, 10), pady=(10, 5), sticky='we') self.entry_path.configure(state='disabled') # create av related - self.label_av = customtkinter.CTkLabel(self.frame_param, width=self.w_param//10, text="AV", font=self.my_font) + self.label_av = customtkinter.CTkLabel(self.frame_param, text="AV", font=self.my_font) self.label_av.grid(row=1, column=2, sticky='e', pady=(5, 5)) self.entry_av = customtkinter.CTkEntry(self.frame_param, width=self.w_param, placeholder_text=f"角速度", font=self.my_font) - self.entry_av.grid(row=1, column=3, padx=(5, 20), pady=(5, 5), sticky='w') + self.entry_av.grid(row=1, column=3, padx=(5, 10), pady=(5, 5), sticky='w') self.entry_av.configure(state='disabled') # create rc related - self.label_rc = customtkinter.CTkLabel(self.frame_param, width=self.w_param//10, text="RC", font=self.my_font) + self.label_rc = customtkinter.CTkLabel(self.frame_param, text="RC", font=self.my_font) self.label_rc.grid(row=1, column=4, sticky='e', pady=(5, 5)) self.entry_rc = customtkinter.CTkEntry(self.frame_param, width=self.w_param, placeholder_text=f"额定电流", font=self.my_font) - self.entry_rc.grid(row=1, column=5, padx=(5, 20), pady=(5, 5), sticky='w') + self.entry_rc.grid(row=1, column=5, padx=(5, 10), pady=(5, 5), sticky='w') self.entry_rc.configure(state='disabled') # create rpm related - self.label_rpm = customtkinter.CTkLabel(self.frame_param, width=self.w_param//10, text="RPM", font=self.my_font) + self.label_rpm = customtkinter.CTkLabel(self.frame_param, text="RPM", font=self.my_font) self.label_rpm.grid(row=1, column=6, sticky='e', pady=(5, 5)) self.entry_rpm = customtkinter.CTkEntry(self.frame_param, width=self.w_param, placeholder_text=f"额定转速", font=self.my_font) - self.entry_rpm.grid(row=1, column=7, padx=(5, 20), pady=(5, 5), sticky='w') + self.entry_rpm.grid(row=1, column=7, padx=(5, 10), pady=(5, 5), sticky='w') self.entry_rpm.configure(state='disabled') # create rr related - self.label_rr = customtkinter.CTkLabel(self.frame_param, width=self.w_param//10, text="RR", font=self.my_font) + self.label_rr = customtkinter.CTkLabel(self.frame_param, text="RR", font=self.my_font) self.label_rr.grid(row=1, column=8, sticky='e', pady=(5, 5)) self.entry_rr = customtkinter.CTkEntry(self.frame_param, width=self.w_param, placeholder_text=f"减速比", font=self.my_font) - self.entry_rr.grid(row=1, column=9, padx=(5, 20), pady=(5, 5), sticky='w') + self.entry_rr.grid(row=1, column=9, padx=(5, 10), pady=(5, 5), sticky='w') self.entry_rr.configure(state='disabled') + # create duration related + self.label_dur = customtkinter.CTkLabel(self.frame_param, text="Dur", font=self.my_font) + self.label_dur.grid(row=1, column=10, sticky='e', pady=(5, 5)) + self.entry_dur = customtkinter.CTkEntry(self.frame_param, width=self.w_param, placeholder_text=f"周期", font=self.my_font) + self.entry_dur.grid(row=1, column=11, padx=(5, 10), pady=(5, 5), sticky='w') + self.entry_dur.configure(state='disabled') # create axis related - self.label_axis = customtkinter.CTkLabel(self.frame_param, width=self.w_param//10, text="AXIS", font=self.my_font) + self.label_axis = customtkinter.CTkLabel(self.frame_param, text="AXIS", font=self.my_font) self.label_axis.grid(row=2, column=2, sticky='e', pady=(5, 5)) self.option_axis = customtkinter.CTkOptionMenu(self.frame_param, values=["1", "2", "3", "4", "5", "6", "7"], width=self.w_param, font=self.my_font) - self.option_axis.grid(row=2, column=3, padx=(5, 20), pady=(5, 5), sticky='w') + self.option_axis.grid(row=2, column=3, padx=(5, 10), pady=(5, 5), sticky='w') self.option_axis.configure(state='disabled') # create vel related - self.label_vel = customtkinter.CTkLabel(self.frame_param, width=self.w_param//10, text="Vel", font=self.my_font) + self.label_vel = customtkinter.CTkLabel(self.frame_param, text="Vel", font=self.my_font) self.label_vel.grid(row=2, column=4, sticky='e', pady=(5, 5)) self.option_vel = customtkinter.CTkOptionMenu(self.frame_param, values=["1", "2", "3", "4", "5", "6", "7"], width=self.w_param, font=self.my_font) - self.option_vel.grid(row=2, column=5, padx=(5, 20), pady=(5, 5), sticky='w') + self.option_vel.grid(row=2, column=5, padx=(5, 10), pady=(5, 5), sticky='w') self.option_vel.configure(state='disabled') # create trq related - self.label_trq = customtkinter.CTkLabel(self.frame_param, width=self.w_param//10, text="Trq", font=self.my_font) + self.label_trq = customtkinter.CTkLabel(self.frame_param, text="Trq", font=self.my_font) self.label_trq.grid(row=2, column=6, sticky='e', pady=(5, 5)) self.option_trq = customtkinter.CTkOptionMenu(self.frame_param, values=["1", "2", "3", "4", "5", "6", "7"], width=self.w_param, font=self.my_font) - self.option_trq.grid(row=2, column=7, padx=(5, 20), pady=(5, 5), sticky='w') + self.option_trq.grid(row=2, column=7, padx=(5, 10), pady=(5, 5), sticky='w') self.option_trq.configure(state='disabled') # ===================================================================== # create textbox self.textbox = customtkinter.CTkTextbox(self, height=640, wrap='none', font=customtkinter.CTkFont(family="consolas", size=14), text_color="blue") - self.textbox.grid(row=3, column=1, rowspan=5, columnspan=13, ipadx=10, ipady=10, padx=10, pady=10, sticky='nsew') + self.textbox.grid(row=3, column=1, rowspan=5, columnspan=15, ipadx=10, ipady=10, padx=10, pady=(5, 10), sticky='nsew') self.textbox.configure(state='disabled') # ===================================================================== # version check @@ -146,6 +153,7 @@ class App(customtkinter.CTk): self.label_rc.configure(text="RC", text_color="black") self.label_rpm.configure(text="RPM", text_color="black") self.label_rr.configure(text="RR", text_color="black") + self.label_dur.configure(text="Dur", text_color="black") self.label_axis.configure(text="AXIS", text_color="black") self.label_vel.configure(text="Vel", text_color="black") self.label_trq.configure(text="Trq", text_color="black") @@ -155,6 +163,7 @@ class App(customtkinter.CTk): self.entry_rc.configure(placeholder_text="额定电流", state="disabled") self.entry_rpm.configure(placeholder_text="额定转速", state="disabled") self.entry_rr.configure(placeholder_text="减速比", state="disabled") + self.entry_dur.configure(placeholder_text="周期", state="disabled") self.option_axis.configure(state="disabled") self.option_vel.configure(state="disabled") self.option_trq.configure(state="disabled") @@ -186,7 +195,7 @@ class App(customtkinter.CTk): self.option_trq.configure(state="normal") elif func_name == 'current': - self.menu_sub = customtkinter.CTkOptionMenu(self.frame_param, values=["max", "avg"], font=self.my_font, command=self.func_sub_callback) + self.menu_sub = customtkinter.CTkOptionMenu(self.frame_param, values=["max", "avg", "cycle"], font=self.my_font, command=self.func_sub_callback) self.menu_sub.grid(row=1, column=1, sticky='we', padx=(20, 10), pady=(5, 5)) self.menu_sub.set("--select--") @@ -211,9 +220,21 @@ class App(customtkinter.CTk): self.label_rpm.configure(text="RPM", text_color='black') self.entry_rpm.configure(state="disabled") elif func_name == "max": - pass + self.label_dur.configure(text="Dur", text_color='black') + self.entry_dur.configure(state="disabled") + self.label_vel.configure(text="Vel", text_color='black') + self.option_vel.configure(state="disabled") elif func_name == 'avg': - pass + self.label_dur.configure(text="Dur", text_color='black') + self.entry_dur.configure(state="disabled") + self.label_vel.configure(text="Vel", text_color='black') + self.option_vel.configure(state="disabled") + elif func_name == 'cycle': + self.label_dur.configure(text="*Dur", text_color='red') + self.entry_dur.configure(state="normal") + self.label_vel.configure(text="*Vel", text_color='red') + self.option_vel.configure(state="normal") + def write2textbox(self, text, wait=0, exitcode=0): if wait != 0: @@ -245,47 +266,67 @@ class App(customtkinter.CTk): sub_func = self.menu_sub.get() c1 = exists(path) - c2 = av.isdigit() - c3 = rr.isdigit() - c4 = rpm = 1 - c5 = sub_func in ['industrial', 'cobot'] - c6 = True if vel != trq else False + try: + _a = float(av) + _b = float(rr) + c2 = True + except: + c2 = False + c3 = rpm = 1 + c4 = sub_func in ['industrial', 'cobot'] + c5 = True if vel != trq else False if self.menu_sub.get() == 'industrial': rpm = self.entry_rpm.get().strip('- ') - c4 = rpm.isdigit() + c3 = rpm.isdigit() elif self.menu_sub.get() == 'cobot': pass else: pass - if c1 and c2 and c3 and c4 and c5 and c6: - return 1, path, int(av), int(rr), int(rpm), int(axis), int(vel), int(trq) + if c1 and c2 and c3 and c4 and c5: + return 1, path, float(av), float(rr), int(rpm), int(axis), int(vel), int(trq) else: return 0, 0 - + # ======================================================= elif func_name == 'current': path = self.entry_path.get() rc = self.entry_rc.get() + dur = self.entry_dur.get() vel = self.option_vel.get() trq = self.option_trq.get() - sub_func = self.menu_sub.get() + sub = self.menu_sub.get() c1 = exists(path) - c2 = sub_func in ['max', 'avg', 'cycle'] - if sub_func == 'cycle': - c3 = True if vel != trq else False - else: - c3 = 1 - try: - _ = float(rc) - c4 = True - except ValueError: - c4 = False + c2 = sub in ['max', 'avg', 'cycle'] - if c1 and c2 and c3 and c4: - return 2, path, sub_func, float(rc), int(vel), int(trq) + rcs = rc.split() + for _ in rcs: + try: + _t = float(_) + except: + c3 = False + break + else: + c3 = True + + c4 = c5 = True + if sub == 'cycle': + try: + _ = float(dur) + c4 = True + except: + c4 = False + c5 = True if vel != trq else False + + if c1 and c2 and c3 and c4 and c5: + rcs = [] + for x in rc.split(): + rcs.append(float(x)) + dur = 0 if sub != 'cycle' else dur + return 2, path, sub, rcs, int(vel), int(trq), float(dur) else: return 0, 0 + # ======================================================= elif func_name == 'iso': path = self.entry_path.get() c1 = exists(path) @@ -297,7 +338,6 @@ class App(customtkinter.CTk): return 0, 0 def func_start_callback(self): - self.textbox.configure(state='normal') self.textbox.delete(index1='1.0', index2='end') @@ -308,7 +348,7 @@ class App(customtkinter.CTk): func_dict[flag](path=args[0], av=args[1], rr=args[2], rpm=args[3], axis=args[4], vel=args[5], trq=args[6], w2t=self.write2textbox) elif flag == 2: # tkinter.messagebox.showinfo(title="TBD", message="功能待实现......") - func_dict[flag](path=args[0], sub=args[1], rc=args[2], vel=args[3], trq=args[4], w2t=self.write2textbox) + func_dict[flag](path=args[0], sub=args[1], rc=args[2], vel=args[3], trq=args[4], dur=args[5], w2t=self.write2textbox) elif flag == 3: func_dict[flag](path=args[0], w2t=self.write2textbox) else: diff --git a/aio/current.py b/aio/current.py index ac5580a..9d38c7d 100644 --- a/aio/current.py +++ b/aio/current.py @@ -1,8 +1,8 @@ -import openpyxl +from openpyxl import load_workbook from os import scandir from os.path import exists from sys import argv -import pandas +from pandas import read_csv def traversal_files(path, w2t): @@ -24,47 +24,114 @@ def traversal_files(path, w2t): return dirs, files -def initialization(path, w2t): +def initialization(path, sub, w2t): _, data_files = traversal_files(path, w2t) + count = 0 for data_file in data_files: - if not data_file.endswith('.data'): - msg = f"所有文件必须以 .data 结尾,请检查后重新运行。" - w2t(msg, 0, 2) + if sub != 'cycle': + if not (data_file.endswith('.data') or data_file.endswith('.csv')): + msg = f"所有文件必须以 .data 结尾,请检查后重新运行。" + w2t(msg, 0, 2) + else: + if data_file.endswith('.xlsx'): + count += 1 + elif not (data_file.endswith('.data') or data_file.endswith('.csv')): + msg = f"所有文件必须以 .data 结尾,请检查后重新运行。" + w2t(msg, 0, 3) + + if sub == 'cycle' and count != 1: + w2t("未找到电机电流数据处理excel表格,确认后重新运行!", 0, 4) return data_files def current_max(data_files, rc, trq, w2t): + current = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0} for data_file in data_files: - df = pandas.read_csv(data_file, sep='\t') + if data_file.endswith('.data'): + df = read_csv(data_file, sep='\t') + elif data_file.endswith('.csv'): + df = read_csv(data_file, sep=',', encoding='gbk', header=8) + + axis = int(data_file.split('\\')[-1].split('_')[0].removeprefix('j')) + rca = rc[axis-1] + col = df.columns.values[trq-1] c_max = df[col].max() - w2t(f"{data_file}: {c_max/1000*rc:.4f}") + + scale = 1 if data_file.endswith('.csv') else 1000 + _ = abs(c_max/scale*rca) + current[axis] = _ + w2t(f"{data_file}: {_:.4f}") w2t("【MAX】数据处理完毕......") + return current def current_avg(data_files, rc, trq, w2t): + current = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0} for data_file in data_files: - df = pandas.read_csv(data_file, sep='\t') - col = df.columns.values[trq-1] + if data_file.endswith('.data'): + df = read_csv(data_file, sep='\t') + elif data_file.endswith('.csv'): + df = read_csv(data_file, sep=',', encoding='gbk', header=8) + + axis = int(data_file.split('\\')[-1].split('_')[0].removeprefix('j')) + rca = rc[axis-1] + + col = df.columns.values[trq - 1] c_std = df[col].std() c_avg = df[col].mean() - w2t(f"{data_file}: {(abs(c_avg)+c_std)/1000*rc:.4f}") + scale = 1 if data_file.endswith('.csv') else 1000 + _ = (abs(c_avg)+c_std)/scale*rca + current[axis] = _ + w2t(f"{data_file}: {_:.4f}") w2t("【AVG】数据处理完毕......") + return current -def main(path, sub, rc, vel, trq, w2t): - data_files = initialization(path, w2t) +def current_cycle(dur, data_files, rc, vel, trq, w2t): + result = None + hold = [] + single = [] + for data_file in data_files: + if data_file.endswith('.xlsx'): + result = data_file + elif (data_file.endswith('.csv') or data_file.endswith('.data')) and data_file.startswith('hold', 3, 10): + hold.append(data_file) + else: + single.append(data_file) + + if hold != []: + avg = current_avg(hold, rc, trq, w2t) + wb = load_workbook(result) + for k, v in avg.items(): + try: + shtname = f"J{k}" + wb[shtname]["J4"].value = v + except: + pass + + for data_file in single: + axis = int(data_file.split('\\')[-1].split('_')[0].removeprefix('j')) + rcs = rc[axis-1] + pass +# ======================================= + + +def main(path, sub, rc, vel, trq, dur, w2t): + data_files = initialization(path, sub, w2t) if sub == 'max': current_max(data_files, rc, trq, w2t) elif sub == 'avg': current_avg(data_files, rc, trq, w2t) + elif sub == 'cycle': + current_cycle(dur, data_files, rc, vel, trq, w2t) else: pass if __name__ == '__main__': - main(path=argv[1], sub=argv[2], rc=argv[3], vel=argv[4], trq=argv[5], w2t=argv[6]) + main(*argv[1:]) diff --git a/aio/layout.xlsx b/aio/layout.xlsx index 42c83dedc24b602a50f3dd36a5fca7aab2f9baea..7af97d87e4a52d64c4328d08f8d04beae515c7b0 100644 GIT binary patch delta 5967 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 delta 4922 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 F Date: Wed, 5 Jun 2024 21:27:11 +0800 Subject: [PATCH 3/4] [modify] support single axis cycle data process --- aio/aio.py | 197 +++++++++++++++++++++++++++++++++--------------- aio/current.py | 188 +++++++++++++++++++++++++++++++++++++++------ aio/layout.xlsx | Bin 10323 -> 10272 bytes 3 files changed, 300 insertions(+), 85 deletions(-) diff --git a/aio/aio.py b/aio/aio.py index 2e7d441..93e14eb 100644 --- a/aio/aio.py +++ b/aio/aio.py @@ -24,17 +24,12 @@ class App(customtkinter.CTk): # configure window self.title("AIO - All in one automatic toolbox") # self.iconbitmap('./icon.ico') - # screen_width = self.winfo_screenwidth() - # screen_height = self.winfo_screenheight() - # width = screen_width - 200 - # height = screen_height - 200 - # self.geometry(f"{width}x{height}+{100}+{100}") - self.geometry("1100x500+100+100") + self.geometry("1180x550+100+100") self.protocol("WM_DELETE_WINDOW", self.func_end_call_back) - self.grid_rowconfigure(3, weight=1) - self.grid_columnconfigure((1, 2, 3, 4, 5, 6, 7, 8, 9), weight=1) - self.minsize(1100, 500) + self.grid_rowconfigure(4, weight=1) + self.grid_columnconfigure((1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13), weight=1) + self.minsize(1180, 550) # ===================================================================== # create frame sidebar(left) @@ -62,8 +57,8 @@ class App(customtkinter.CTk): # ===================================================================== # create frame - self.frame_param = customtkinter.CTkFrame(self, height=240, corner_radius=10) - self.frame_param.grid(row=0, column=1, rowspan=3, columnspan=11, sticky='new', ipadx=20, ipady=10, padx=10, pady=(10, 5)) + self.frame_param = customtkinter.CTkFrame(self, corner_radius=10) + self.frame_param.grid(row=0, column=1, rowspan=3, columnspan=13, sticky='new', ipadx=20, ipady=10, padx=10, pady=(10, 5)) # create main menu self.menu_main = customtkinter.CTkOptionMenu(self.frame_param, values=["INIT", "brake", "current", "iso"], font=self.my_font, command=self.func_main_callback) self.menu_main.grid(row=0, column=1, sticky='we', padx=(20, 10), pady=(10, 5)) @@ -74,7 +69,7 @@ class App(customtkinter.CTk): self.label_path = customtkinter.CTkLabel(self.frame_param, text="Path", font=self.my_font) self.label_path.grid(row=0, column=2, sticky='e', pady=(10, 5)) self.entry_path = customtkinter.CTkEntry(self.frame_param, width=670, placeholder_text="数据文件夹路径", font=self.my_font) - self.entry_path.grid(row=0, column=3, columnspan=9, padx=(5, 10), pady=(10, 5), sticky='we') + self.entry_path.grid(row=0, column=3, columnspan=11, padx=(5, 10), pady=(10, 5), sticky='we') self.entry_path.configure(state='disabled') # create av related self.label_av = customtkinter.CTkLabel(self.frame_param, text="AV", font=self.my_font) @@ -124,10 +119,52 @@ class App(customtkinter.CTk): self.option_trq = customtkinter.CTkOptionMenu(self.frame_param, values=["1", "2", "3", "4", "5", "6", "7"], width=self.w_param, font=self.my_font) self.option_trq.grid(row=2, column=7, padx=(5, 10), pady=(5, 5), sticky='w') self.option_trq.configure(state='disabled') + # create trqH related + self.label_trqh = customtkinter.CTkLabel(self.frame_param, text="TrqH", font=self.my_font) + self.label_trqh.grid(row=2, column=8, sticky='e', pady=(5, 5)) + self.option_trqh = customtkinter.CTkOptionMenu(self.frame_param, values=["1", "2", "3", "4", "5", "6", "7"], width=self.w_param, font=self.my_font) + self.option_trqh.grid(row=2, column=9, padx=(5, 10), pady=(5, 5), sticky='w') + self.option_trqh.configure(state='disabled') + # create STO related + self.label_sto = customtkinter.CTkLabel(self.frame_param, text="STO", font=self.my_font) + self.label_sto.grid(row=2, column=10, sticky='e', pady=(5, 5)) + self.option_sto = customtkinter.CTkOptionMenu(self.frame_param, values=["1", "2", "3", "4", "5", "6", "7"], width=self.w_param, font=self.my_font) + self.option_sto.grid(row=2, column=11, padx=(5, 10), pady=(5, 5), sticky='w') + self.option_sto.configure(state='disabled') + # create rc1 + self.label_rc_1 = customtkinter.CTkLabel(self.frame_param, text="RC1", font=self.my_font) + self.label_rc_1.grid(row=3, column=2, sticky='e', pady=(5, 5)) + self.entry_rc_1 = customtkinter.CTkEntry(self.frame_param, width=self.w_param, placeholder_text=f"optional", font=self.my_font) + self.entry_rc_1.grid(row=3, column=3, padx=(5, 10), pady=(5, 5), sticky='w') + + self.label_rc_2 = customtkinter.CTkLabel(self.frame_param, text="RC2", font=self.my_font) + self.label_rc_2.grid(row=3, column=4, sticky='e', pady=(5, 5)) + self.entry_rc_2 = customtkinter.CTkEntry(self.frame_param, width=self.w_param, placeholder_text=f"optional", font=self.my_font) + self.entry_rc_2.grid(row=3, column=5, padx=(5, 10), pady=(5, 5), sticky='w') + + self.label_rc_3 = customtkinter.CTkLabel(self.frame_param, text="RC3", font=self.my_font) + self.label_rc_3.grid(row=3, column=6, sticky='e', pady=(5, 5)) + self.entry_rc_3 = customtkinter.CTkEntry(self.frame_param, width=self.w_param, placeholder_text=f"optional", font=self.my_font) + self.entry_rc_3.grid(row=3, column=7, padx=(5, 10), pady=(5, 5), sticky='w') + + self.label_rc_4 = customtkinter.CTkLabel(self.frame_param, text="RC4", font=self.my_font) + self.label_rc_4.grid(row=3, column=8, sticky='e', pady=(5, 5)) + self.entry_rc_4 = customtkinter.CTkEntry(self.frame_param, width=self.w_param, placeholder_text=f"optional", font=self.my_font) + self.entry_rc_4.grid(row=3, column=9, padx=(5, 10), pady=(5, 5), sticky='w') + + self.label_rc_5 = customtkinter.CTkLabel(self.frame_param, text="RC5", font=self.my_font) + self.label_rc_5.grid(row=3, column=10, sticky='e', pady=(5, 5)) + self.entry_rc_5 = customtkinter.CTkEntry(self.frame_param, width=self.w_param, placeholder_text=f"optional", font=self.my_font) + self.entry_rc_5.grid(row=3, column=11, padx=(5, 10), pady=(5, 5), sticky='w') + + self.label_rc_6 = customtkinter.CTkLabel(self.frame_param, text="RC6", font=self.my_font) + self.label_rc_6.grid(row=3, column=12, sticky='e', pady=(5, 5)) + self.entry_rc_6 = customtkinter.CTkEntry(self.frame_param, width=self.w_param, placeholder_text=f"optional", font=self.my_font) + self.entry_rc_6.grid(row=3, column=13, padx=(5, 10), pady=(5, 5), sticky='w') # ===================================================================== # create textbox - self.textbox = customtkinter.CTkTextbox(self, height=640, wrap='none', font=customtkinter.CTkFont(family="consolas", size=14), text_color="blue") - self.textbox.grid(row=3, column=1, rowspan=5, columnspan=15, ipadx=10, ipady=10, padx=10, pady=(5, 10), sticky='nsew') + self.textbox = customtkinter.CTkTextbox(self, wrap='none', font=customtkinter.CTkFont(family="consolas", size=14), text_color="blue") + self.textbox.grid(row=4, column=1, rowspan=3, columnspan=13, ipadx=10, ipady=10, padx=10, pady=(5, 10), sticky='nsew') self.textbox.configure(state='disabled') # ===================================================================== # version check @@ -157,6 +194,14 @@ class App(customtkinter.CTk): self.label_axis.configure(text="AXIS", text_color="black") self.label_vel.configure(text="Vel", text_color="black") self.label_trq.configure(text="Trq", text_color="black") + self.label_trqh.configure(text="TrqH", text_color="black") + self.label_sto.configure(text="STO", text_color="black") + self.label_rc_1.configure(text="RC1", text_color="black") + self.label_rc_2.configure(text="RC2", text_color="black") + self.label_rc_3.configure(text="RC3", text_color="black") + self.label_rc_4.configure(text="RC4", text_color="black") + self.label_rc_5.configure(text="RC5", text_color="black") + self.label_rc_6.configure(text="RC6", text_color="black") self.entry_path.configure(placeholder_text="数据文件夹路径", state="disabled") self.entry_av.configure(placeholder_text="角速度", state="disabled") @@ -167,6 +212,14 @@ class App(customtkinter.CTk): self.option_axis.configure(state="disabled") self.option_vel.configure(state="disabled") self.option_trq.configure(state="disabled") + self.option_trqh.configure(state="disabled") + self.option_sto.configure(state="disabled") + self.entry_rc_1.configure(placeholder_text="optional", state="disabled") + self.entry_rc_2.configure(placeholder_text="optional", state="disabled") + self.entry_rc_3.configure(placeholder_text="optional", state="disabled") + self.entry_rc_4.configure(placeholder_text="optional", state="disabled") + self.entry_rc_5.configure(placeholder_text="optional", state="disabled") + self.entry_rc_6.configure(placeholder_text="optional", state="disabled") self.menu_sub.grid_forget() self.textbox.delete(index1='1.0', index2='end') @@ -180,12 +233,12 @@ class App(customtkinter.CTk): self.menu_sub.grid(row=1, column=1, sticky='we', padx=(20, 10), pady=(5, 5)) self.menu_sub.set("--select--") - self.label_path.configure(text="*Path", text_color='red') - self.label_av.configure(text="*AV", text_color='red') - self.label_rr.configure(text="*RR", text_color='red') - self.label_axis.configure(text="*AXIS", text_color='red') - self.label_vel.configure(text="*Vel", text_color='red') - self.label_trq.configure(text="*Trq", text_color='red') + self.label_path.configure(text="Path", text_color='red') + self.label_av.configure(text="AV", text_color='red') + self.label_rr.configure(text="RR", text_color='red') + self.label_axis.configure(text="AXIS", text_color='red') + self.label_vel.configure(text="Vel", text_color='red') + self.label_trq.configure(text="Trq", text_color='red') self.entry_path.configure(state="normal") self.entry_av.configure(state="normal") @@ -199,22 +252,36 @@ class App(customtkinter.CTk): self.menu_sub.grid(row=1, column=1, sticky='we', padx=(20, 10), pady=(5, 5)) self.menu_sub.set("--select--") - self.label_path.configure(text="*Path", text_color='red') - self.label_rc.configure(text="*RC", text_color='red') - self.label_trq.configure(text="*Trq", text_color='red') + self.label_path.configure(text="Path", text_color='red') + self.label_rc.configure(text="RC", text_color='blue') + self.label_trqh.configure(text="TrqH", text_color='red') + self.label_rc_1.configure(text="RC1", text_color='red') + self.label_rc_2.configure(text="RC2", text_color='red') + self.label_rc_3.configure(text="RC3", text_color='red') + self.label_rc_4.configure(text="RC4", text_color='red') + self.label_rc_5.configure(text="RC5", text_color='red') + self.label_rc_6.configure(text="RC6", text_color='red') self.entry_path.configure(state="normal") - self.entry_rc.configure(state="normal") - self.option_trq.configure(state="normal") + self.entry_rc.configure(state="normal", placeholder_text="optional") + self.option_trqh.configure(state="normal") + self.entry_rc_1.configure(state="normal", placeholder_text="额定电流") + self.entry_rc_2.configure(state="normal", placeholder_text="额定电流") + self.entry_rc_3.configure(state="normal", placeholder_text="额定电流") + self.entry_rc_4.configure(state="normal", placeholder_text="额定电流") + self.entry_rc_5.configure(state="normal", placeholder_text="额定电流") + self.entry_rc_6.configure(state="normal", placeholder_text="额定电流") + elif func_name == 'iso': - self.label_path.configure(text="*Path", text_color='red') + self.label_path.configure(text="Path", text_color='red') self.entry_path.configure(state="normal") + else: self.initialization() self.menu_main.set("Start Here!") def func_sub_callback(self, func_name): if func_name == "industrial": - self.label_rpm.configure(text="*RPM", text_color='red') + self.label_rpm.configure(text="RPM", text_color='red') self.entry_rpm.configure(state="normal") elif func_name == "cobot": self.label_rpm.configure(text="RPM", text_color='black') @@ -224,16 +291,22 @@ class App(customtkinter.CTk): self.entry_dur.configure(state="disabled") self.label_vel.configure(text="Vel", text_color='black') self.option_vel.configure(state="disabled") + self.label_trq.configure(text="Trq", text_color='black') + self.option_trq.configure(state="disabled") elif func_name == 'avg': self.label_dur.configure(text="Dur", text_color='black') self.entry_dur.configure(state="disabled") self.label_vel.configure(text="Vel", text_color='black') self.option_vel.configure(state="disabled") + self.label_trq.configure(text="Trq", text_color='black') + self.option_trq.configure(state="disabled") elif func_name == 'cycle': - self.label_dur.configure(text="*Dur", text_color='red') - self.entry_dur.configure(state="normal") - self.label_vel.configure(text="*Vel", text_color='red') + self.label_dur.configure(text="Dur", text_color='blue') + self.entry_dur.configure(state="normal", placeholder_text='scenario') + self.label_vel.configure(text="Vel", text_color='red') self.option_vel.configure(state="normal") + self.label_trq.configure(text="Trq", text_color='red') + self.option_trq.configure(state="normal") def write2textbox(self, text, wait=0, exitcode=0): @@ -247,6 +320,7 @@ class App(customtkinter.CTk): self.textbox.insert(index='end', text=text + '\n') self.textbox.update() self.textbox.see('end') + self.textbox.configure(state='disabled') raise Exception(f"Error code: {exitcode}") else: self.textbox.configure(text_color='blue') @@ -254,6 +328,19 @@ class App(customtkinter.CTk): self.textbox.update() self.textbox.see('end') + def is_float(self, flag, *args): + for item in args: + try: + if flag == 'optional': + item = 0 if item == '' else item + _ = float(item) + elif flag == 'required': + _ = float(item) + except Exception as Err: + self.write2textbox(str(Err)) + self.write2textbox("参数数据缺失,或者数据类型错误,更正后重新运行...", 0, 3) + return True + def check_param(self): func_name = self.menu_main.get() if func_name == 'brake': @@ -266,12 +353,7 @@ class App(customtkinter.CTk): sub_func = self.menu_sub.get() c1 = exists(path) - try: - _a = float(av) - _b = float(rr) - c2 = True - except: - c2 = False + c2 = self.is_float(av, rr) c3 = rpm = 1 c4 = sub_func in ['industrial', 'cobot'] c5 = True if vel != trq else False @@ -295,35 +377,32 @@ class App(customtkinter.CTk): dur = self.entry_dur.get() vel = self.option_vel.get() trq = self.option_trq.get() + trqh = self.option_trqh.get() sub = self.menu_sub.get() + rc1 = self.entry_rc_1.get() + rc2 = self.entry_rc_2.get() + rc3 = self.entry_rc_3.get() + rc4 = self.entry_rc_4.get() + rc5 = self.entry_rc_5.get() + rc6 = self.entry_rc_6.get() + c1 = exists(path) c2 = sub in ['max', 'avg', 'cycle'] + c3 = self.is_float('optional', rc) + _ = [rc1, rc2, rc3, rc4, rc5, rc6] + c4 = self.is_float('required', *_) - rcs = rc.split() - for _ in rcs: - try: - _t = float(_) - except: - c3 = False - break - else: - c3 = True - - c4 = c5 = True + c5 = c6 = True if sub == 'cycle': - try: - _ = float(dur) - c4 = True - except: - c4 = False c5 = True if vel != trq else False + c6 = self.is_float('optional', dur) - if c1 and c2 and c3 and c4 and c5: + if c1 and c2 and c3 and c4 and c5 and c6: rcs = [] - for x in rc.split(): + for x in _: rcs.append(float(x)) - dur = 0 if sub != 'cycle' else dur - return 2, path, sub, rcs, int(vel), int(trq), float(dur) + dur = 0 if sub != 'cycle' or dur == '' else dur + return 2, path, sub, rcs, int(vel), int(trq), int(trqh), float(dur) else: return 0, 0 # ======================================================= @@ -348,7 +427,7 @@ class App(customtkinter.CTk): func_dict[flag](path=args[0], av=args[1], rr=args[2], rpm=args[3], axis=args[4], vel=args[5], trq=args[6], w2t=self.write2textbox) elif flag == 2: # tkinter.messagebox.showinfo(title="TBD", message="功能待实现......") - func_dict[flag](path=args[0], sub=args[1], rc=args[2], vel=args[3], trq=args[4], dur=args[5], w2t=self.write2textbox) + func_dict[flag](path=args[0], sub=args[1], rcs=args[2], vel=args[3], trq=args[4], trqh=args[5], dur=args[6], w2t=self.write2textbox) elif flag == 3: func_dict[flag](path=args[0], w2t=self.write2textbox) else: @@ -382,12 +461,8 @@ class App(customtkinter.CTk): def func_end_call_back(self): if tkinter.messagebox.askyesno(title="关闭程序", message="相关数据可能未保存,正在运行程序时有概率会损坏数据文件,确定要终止程序运行吗?"): self.destroy() - else: - pass - pass if __name__ == "__main__": - aio = App() aio.mainloop() diff --git a/aio/current.py b/aio/current.py index 9d38c7d..b93240d 100644 --- a/aio/current.py +++ b/aio/current.py @@ -3,6 +3,37 @@ from os import scandir from os.path import exists from sys import argv from pandas import read_csv +from re import match +from threading import Thread +from time import sleep + +class GetThreadResult(Thread): + def __init__(self, func, args=()): + super(GetThreadResult, self).__init__() + self.func = func + self.args = args + self.result = 0 + + def run(self): + sleep(1) + self.result = self.func(*self.args) + + def get_result(self): + Thread.join(self) # 等待线程执行完毕 + try: + return self.result + except Exception as Err: + return None + + +def w2t_local(msg, wait, w2t): + while True: + global stop + if stop == 0 and wait != 0: + sleep(1) + w2t(msg, wait) + else: + break def traversal_files(path, w2t): @@ -27,16 +58,18 @@ def traversal_files(path, w2t): def initialization(path, sub, w2t): _, data_files = traversal_files(path, w2t) count = 0 + for data_file in data_files: + filename = data_file.split('\\')[-1] if sub != 'cycle': - if not (data_file.endswith('.data') or data_file.endswith('.csv')): - msg = f"所有文件必须以 .data 结尾,请检查后重新运行。" + if not (match('j[1-7].*\\.data', filename) or match('j[1-7].*\\.csv', filename)): + msg = f"所有文件必须以 jx_ 开头,以 .data/csv 结尾(x取值1-7),请检查后重新运行。" w2t(msg, 0, 2) else: - if data_file.endswith('.xlsx'): + if filename.endswith('.xlsx'): count += 1 - elif not (data_file.endswith('.data') or data_file.endswith('.csv')): - msg = f"所有文件必须以 .data 结尾,请检查后重新运行。" + elif not (match('j[1-7].*\\.data', filename) or match('j[1-7].*\\.csv', filename)): + msg = f"所有文件必须以 jx_ 开头,以 .data/csv 结尾(x取值1-7),请检查后重新运行。" w2t(msg, 0, 3) if sub == 'cycle' and count != 1: @@ -45,7 +78,7 @@ def initialization(path, sub, w2t): return data_files -def current_max(data_files, rc, trq, w2t): +def current_max(data_files, rcs, trqh, w2t): current = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0} for data_file in data_files: if data_file.endswith('.data'): @@ -54,9 +87,9 @@ def current_max(data_files, rc, trq, w2t): df = read_csv(data_file, sep=',', encoding='gbk', header=8) axis = int(data_file.split('\\')[-1].split('_')[0].removeprefix('j')) - rca = rc[axis-1] + rca = rcs[axis-1] - col = df.columns.values[trq-1] + col = df.columns.values[trqh-1] c_max = df[col].max() scale = 1 if data_file.endswith('.csv') else 1000 @@ -68,7 +101,7 @@ def current_max(data_files, rc, trq, w2t): return current -def current_avg(data_files, rc, trq, w2t): +def current_avg(data_files, rcs, trqh, w2t): current = {1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0} for data_file in data_files: if data_file.endswith('.data'): @@ -77,9 +110,9 @@ def current_avg(data_files, rc, trq, w2t): df = read_csv(data_file, sep=',', encoding='gbk', header=8) axis = int(data_file.split('\\')[-1].split('_')[0].removeprefix('j')) - rca = rc[axis-1] + rca = rcs[axis-1] - col = df.columns.values[trq - 1] + col = df.columns.values[trqh - 1] c_std = df[col].std() c_avg = df[col].mean() @@ -92,46 +125,153 @@ def current_avg(data_files, rc, trq, w2t): return current -def current_cycle(dur, data_files, rc, vel, trq, w2t): +def current_cycle(dur, data_files, rcs, vel, trq, trqh, w2t): result = None hold = [] single = [] for data_file in data_files: + filename = data_file.split('\\')[-1] if data_file.endswith('.xlsx'): result = data_file - elif (data_file.endswith('.csv') or data_file.endswith('.data')) and data_file.startswith('hold', 3, 10): + elif match('j[1-7]_hold_.*\\.data', filename) or match('j[1-7]_hold_.*\\.csv', filename): hold.append(data_file) else: single.append(data_file) + w2t(f"正在打开文件 {result},需要 10s 左右", 1) + + global stop + stop = 0 + t_excel = GetThreadResult(load_workbook, args=(result, )) + t_wait = Thread(target=w2t_local, args=('.', 1, w2t)) + t_excel.start() + t_wait.start() + t_excel.join() + wb = t_excel.get_result() + stop = 1 + sleep(1.1) + w2t('') + if hold != []: - avg = current_avg(hold, rc, trq, w2t) - wb = load_workbook(result) - for k, v in avg.items(): + avg = current_avg(hold, rcs, trqh, w2t) + for axis, cur_value in avg.items(): try: - shtname = f"J{k}" - wb[shtname]["J4"].value = v + shtname = f"J{axis}" + wb[shtname]["J4"].value = float(cur_value) except: pass + if dur == 0: + p_single(wb, single, vel, trq, w2t) + else: + p_scenario() + + w2t(f"正在保存文件 {result},需要 10s 左右", 1) + stop = 0 + t_excel = Thread(target=wb.save, args=(result, )) + t_wait = Thread(target=w2t_local, args=('.', 1, w2t)) + t_excel.start() + t_wait.start() + t_excel.join() + stop = 1 + sleep(1.1) + w2t('\n') + w2t("----------------------------------------------------------") + w2t("全部处理完毕") + + +def p_single(wb, single, vel, trq, w2t): + # 1. 先找到第一个速度为零的点,数据从后往前找,一开始就是零的情况不予考虑 + # 2. 记录第一个点的位置,继续向前查找第二个速度为零的点,同理,一开始为零的点不予考虑 + # 3. 记录第二个点的位置,并将其中的数据拷贝至对应位置 for data_file in single: axis = int(data_file.split('\\')[-1].split('_')[0].removeprefix('j')) - rcs = rc[axis-1] - pass + shtname = f"J{axis}" + ws = wb[shtname] + + if data_file.endswith('.data'): + df = read_csv(data_file, sep='\t') + elif data_file.endswith('.csv'): + df = read_csv(data_file, sep=',', encoding='gbk', header=8) + + # 过滤尾部无效数据 + _row_e = df.index[-1] + _row_s = _row_e - 200 + while _row_e > 200: + speed_avg = df.iloc[_row_s:_row_e, vel-1].abs().mean() + if speed_avg > 2: + _row_e -= 50 + _row_s -= 50 + continue + else: + break + else: + w2t("数据有误,需要检查,无法找到第一个有效起始点...", 0, 1) + + # 找到第一个起始点 row_end,继续找到有数据的部分 + row_end = _row_e - 100 + _row_e -= 200 + _row_s -= 200 + while _row_e > 200: + speed_avg = df.iloc[_row_s:_row_e, vel-1].abs().mean() + if speed_avg < 2: + _row_e -= 50 + _row_s -= 50 + continue + else: + break + else: + w2t("数据有误,需要检查,无法找到第二个有效起始点...", 0, 2) + + # 目前已经有一点的速度值了,继续往前搜寻下一个速度为零的点 + _row_e -= 200 + _row_s -= 200 + while _row_e > 200: + speed_avg = df.iloc[_row_s:_row_e, vel-1].abs().mean() + if speed_avg > 2: + _row_e -= 50 + _row_s -= 50 + continue + else: + break + else: + w2t("数据有误,需要检查,无法找到第三个有效起始点...", 0, 3) + + row_start = _row_s + 180 + data = [] + for row in range(row_start, row_end): + data.append(df.iloc[row, vel-1]) + data.append(df.iloc[row, trq-1]) + + i = 0 + for row in ws.iter_rows(min_row=2, min_col=2, max_row=15000, max_col=3): + for cell in row: + try: + cell.value = data[i] + i += 1 + except: + cell.value = None + + +def p_scenario(): + pass + + # ======================================= -def main(path, sub, rc, vel, trq, dur, w2t): +def main(path, sub, rcs, vel, trq, trqh, dur, w2t): data_files = initialization(path, sub, w2t) if sub == 'max': - current_max(data_files, rc, trq, w2t) + current_max(data_files, rcs, trqh, w2t) elif sub == 'avg': - current_avg(data_files, rc, trq, w2t) + current_avg(data_files, rcs, trqh, w2t) elif sub == 'cycle': - current_cycle(dur, data_files, rc, vel, trq, w2t) + current_cycle(dur, data_files, rcs, vel, trq, trqh, w2t) else: pass if __name__ == '__main__': + stop = 0 main(*argv[1:]) diff --git a/aio/layout.xlsx b/aio/layout.xlsx index 7af97d87e4a52d64c4328d08f8d04beae515c7b0..ac11973f023dda75e940e1c125d2a20351ceae76 100644 GIT binary patch delta 4972 zcmZ`-cTm&awoM2SdXwG>p;s{=@PR}L9R%qmpzulWNN+!S@1a)-y-5pAK>p}T@Zn*_rAIF-ko>PA8YpPbJjY0&;Do4p4NM+*OUP!(wADbm&fFQxd7+a-1ITu zp%>JB7bqPi=8W>)NUH`(Q`MnwC|wIP1lG;*`qCxej)Uz*=8uB|#UY#Kd7VSj@w&Op zI6FeVM<|i3#q6yLtIFGg2jOhP1#`%Fs*jV{=P!k$Y_UH38|LKVg8Lc>7JQW0q&VS- zdED{=>ai5hK=>E)wl=Zdc3NOsWEyeYgF>l_$P&&)dU zC}Idvc2+?75qEubuLPZD9vzu{i_%A8S--G9eI-ab!gAhrxxA6~!r<5Qz~FCcI$3hx zG(oi~7ml6Ob)D~$2?G48-71V#&p-M*ScU_TX!;Npe)fHkRD5cSf!yGemf{aeGg^k5 z@RIV!*;Cz>nUgHM8x6hoPMr^v?^wSyrdNe)dKAc>|(2* z<}B{WD%pDCYVLS1q*h^um(OVU)KpOZqtD{g-8zQlWu{Kv^W0&CsWW~ri&!f8o?)

@J+wFSu+t#A_F+GK;Uy4FG=V+>j>XkD? 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 delta 5007 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 Date: Thu, 6 Jun 2024 19:04:55 +0800 Subject: [PATCH 4/4] =?UTF-8?q?v0.1.4(2024/06/06)=201.=20AV/RR=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=B0=8F=E6=95=B0=202.=20=E5=8F=AF=E5=A4=84=E7=90=86?= =?UTF-8?q?=E7=94=B5=E6=9C=BA=E7=94=B5=E6=B5=81=E5=8D=95=E8=BD=B4=E4=BB=A5?= =?UTF-8?q?=E5=8F=8A=E5=A4=9A=E8=BD=B4=E6=95=B0=E6=8D=AE=EF=BC=8C=E5=8F=AF?= =?UTF-8?q?=E6=A0=B9=E6=8D=AE=E9=9C=80=E8=A6=81=E8=BF=9B=E8=A1=8C=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E8=AE=BE=E5=AE=9A=E5=A4=84=E7=90=86=E4=B8=8D=E5=90=8C?= =?UTF-8?q?=E8=BD=B4=E7=9A=84=E6=95=B0=E6=8D=AE=203.=20=E7=95=8C=E9=9D=A2?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E4=BD=8D=E7=BD=AE=E4=BF=AE=E6=94=B9=EF=BC=8C?= =?UTF-8?q?=E4=BB=A5=E5=8F=8A=E5=88=A0=E9=99=A4=E6=89=80=E6=9C=89entry?= =?UTF-8?q?=E7=9A=84=E9=95=BF=E5=BA=A6=E8=AE=BE=E5=AE=9A=EF=BC=8C=E5=9B=A0?= =?UTF-8?q?=E4=B8=BA=E8=AE=BE=E5=AE=9A=E6=97=A0=E6=95=88=204.=20=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E4=BA=86layout.xlsx=E5=B8=83=E5=B1=80=EF=BC=8C?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BA=86duration/trqH/STO=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=EF=BC=8C=E4=BB=A5=E5=8F=8A=E9=A2=9D=E5=A4=96=E7=9A=84RC?= =?UTF-8?q?=E8=A1=8C=EF=BC=8C=E6=95=B4=E4=BD=93=E6=89=A9=E5=B1=95=E4=BA=86?= =?UTF-8?q?=E5=8C=BA=E5=9F=9F=205.=20=E6=9B=B4=E6=94=B9label/entry/optionm?= =?UTF-8?q?enu=E7=AD=89=E6=8E=A7=E4=BB=B6=E7=9A=84=E7=94=9F=E6=88=90?= =?UTF-8?q?=E6=96=B9=E5=BC=8F=EF=BC=8C=E4=BD=BF=E7=94=A8=E5=BE=AA=E7=8E=AF?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=EF=BC=8C=E6=9B=B4=E5=8A=A0=E7=AE=80=E6=B4=81?= =?UTF-8?q?=E5=92=8C=E5=AE=B9=E6=98=93=E7=BB=B4=E6=8A=A4=EF=BC=88=E6=9A=82?= =?UTF-8?q?=E6=9C=AA=E5=AE=9E=E7=8E=B0=EF=BC=89=206.=20=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E5=B7=A5=E4=B8=9A/=E5=8D=8F=E4=BD=9C=E4=B8=A4=E6=9D=A1?= =?UTF-8?q?=E4=BA=A7=E5=93=81=E7=BA=BF=E7=9A=84=E7=94=B5=E6=9C=BA=E7=94=B5?= =?UTF-8?q?=E6=B5=81=E6=95=B0=E6=8D=AE=E5=A4=84=E7=90=86=EF=BC=8C=E5=8C=85?= =?UTF-8?q?=E6=8B=AC=E5=8D=95=E8=BD=B4=EF=BC=8C=E5=9C=BA=E6=99=AF=EF=BC=8C?= =?UTF-8?q?max/avg=E8=AE=A1=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- aio/README.md | 8 +- aio/aio.py | 43 ++++++++--- aio/current.py | 195 ++++++++++++++++++++++++++++++++++--------------- aio/vers | 2 +- 4 files changed, 172 insertions(+), 76 deletions(-) diff --git a/aio/README.md b/aio/README.md index 1240c30..a542287 100644 --- a/aio/README.md +++ b/aio/README.md @@ -167,10 +167,10 @@ v0.1.2(2024/06/01) 2. 重新修改了README.md 3. 单独将rokae拉出来,作为一个独立的repo进行维护,与scripts分离 -v0.1.3(预计2024/06/06)-准备实现如下 +v0.1.4(2024/06/06) 1. AV/RR支持小数 2. 可处理电机电流单轴以及多轴数据,可根据需要进行参数设定处理不同轴的数据 3. 界面初始位置修改,以及删除所有entry的长度设定,因为设定无效 -4. 修改了layout.xlsx布局,增加了duration字段,以及额外的RC行,整体扩展了区域 -5. 更改label/entry/optionmenu等控件的生成方式,使用循环实现,更加简洁和容易维护 -6. 支持工业/协作两条产品线的数据处理 \ No newline at end of file +4. 修改了layout.xlsx布局,增加了duration/trqH/STO字段,以及额外的RC行,整体扩展了区域 +5. 更改label/entry/optionmenu等控件的生成方式,使用循环实现,更加简洁和容易维护(暂未实现) +6. 支持工业/协作两条产品线的电机电流数据处理,包括单轴,场景,max/avg计算 \ No newline at end of file diff --git a/aio/aio.py b/aio/aio.py index 93e14eb..64af908 100644 --- a/aio/aio.py +++ b/aio/aio.py @@ -24,7 +24,7 @@ class App(customtkinter.CTk): # configure window self.title("AIO - All in one automatic toolbox") # self.iconbitmap('./icon.ico') - self.geometry("1180x550+100+100") + self.geometry("1180x550+30+30") self.protocol("WM_DELETE_WINDOW", self.func_end_call_back) self.grid_rowconfigure(4, weight=1) @@ -136,31 +136,37 @@ class App(customtkinter.CTk): self.label_rc_1.grid(row=3, column=2, sticky='e', pady=(5, 5)) self.entry_rc_1 = customtkinter.CTkEntry(self.frame_param, width=self.w_param, placeholder_text=f"optional", font=self.my_font) self.entry_rc_1.grid(row=3, column=3, padx=(5, 10), pady=(5, 5), sticky='w') + self.entry_rc_1.configure(state='disabled') self.label_rc_2 = customtkinter.CTkLabel(self.frame_param, text="RC2", font=self.my_font) self.label_rc_2.grid(row=3, column=4, sticky='e', pady=(5, 5)) self.entry_rc_2 = customtkinter.CTkEntry(self.frame_param, width=self.w_param, placeholder_text=f"optional", font=self.my_font) self.entry_rc_2.grid(row=3, column=5, padx=(5, 10), pady=(5, 5), sticky='w') + self.entry_rc_2.configure(state='disabled') self.label_rc_3 = customtkinter.CTkLabel(self.frame_param, text="RC3", font=self.my_font) self.label_rc_3.grid(row=3, column=6, sticky='e', pady=(5, 5)) self.entry_rc_3 = customtkinter.CTkEntry(self.frame_param, width=self.w_param, placeholder_text=f"optional", font=self.my_font) self.entry_rc_3.grid(row=3, column=7, padx=(5, 10), pady=(5, 5), sticky='w') + self.entry_rc_3.configure(state='disabled') self.label_rc_4 = customtkinter.CTkLabel(self.frame_param, text="RC4", font=self.my_font) self.label_rc_4.grid(row=3, column=8, sticky='e', pady=(5, 5)) self.entry_rc_4 = customtkinter.CTkEntry(self.frame_param, width=self.w_param, placeholder_text=f"optional", font=self.my_font) self.entry_rc_4.grid(row=3, column=9, padx=(5, 10), pady=(5, 5), sticky='w') + self.entry_rc_4.configure(state='disabled') self.label_rc_5 = customtkinter.CTkLabel(self.frame_param, text="RC5", font=self.my_font) self.label_rc_5.grid(row=3, column=10, sticky='e', pady=(5, 5)) self.entry_rc_5 = customtkinter.CTkEntry(self.frame_param, width=self.w_param, placeholder_text=f"optional", font=self.my_font) self.entry_rc_5.grid(row=3, column=11, padx=(5, 10), pady=(5, 5), sticky='w') + self.entry_rc_5.configure(state='disabled') self.label_rc_6 = customtkinter.CTkLabel(self.frame_param, text="RC6", font=self.my_font) self.label_rc_6.grid(row=3, column=12, sticky='e', pady=(5, 5)) self.entry_rc_6 = customtkinter.CTkEntry(self.frame_param, width=self.w_param, placeholder_text=f"optional", font=self.my_font) self.entry_rc_6.grid(row=3, column=13, padx=(5, 10), pady=(5, 5), sticky='w') + self.entry_rc_6.configure(state='disabled') # ===================================================================== # create textbox self.textbox = customtkinter.CTkTextbox(self, wrap='none', font=customtkinter.CTkFont(family="consolas", size=14), text_color="blue") @@ -287,6 +293,8 @@ class App(customtkinter.CTk): self.label_rpm.configure(text="RPM", text_color='black') self.entry_rpm.configure(state="disabled") elif func_name == "max": + self.label_rpm.configure(text="RPM", text_color='black') + self.entry_rpm.configure(state="disabled", placeholder_text='额定转速') self.label_dur.configure(text="Dur", text_color='black') self.entry_dur.configure(state="disabled") self.label_vel.configure(text="Vel", text_color='black') @@ -294,6 +302,8 @@ class App(customtkinter.CTk): self.label_trq.configure(text="Trq", text_color='black') self.option_trq.configure(state="disabled") elif func_name == 'avg': + self.label_rpm.configure(text="RPM", text_color='black') + self.entry_rpm.configure(state="disabled", placeholder_text='额定转速') self.label_dur.configure(text="Dur", text_color='black') self.entry_dur.configure(state="disabled") self.label_vel.configure(text="Vel", text_color='black') @@ -301,6 +311,8 @@ class App(customtkinter.CTk): self.label_trq.configure(text="Trq", text_color='black') self.option_trq.configure(state="disabled") elif func_name == 'cycle': + self.label_rpm.configure(text="RPM", text_color='blue') + self.entry_rpm.configure(state="normal", placeholder_text='cycle') self.label_dur.configure(text="Dur", text_color='blue') self.entry_dur.configure(state="normal", placeholder_text='scenario') self.label_vel.configure(text="Vel", text_color='red') @@ -308,7 +320,6 @@ class App(customtkinter.CTk): self.label_trq.configure(text="Trq", text_color='red') self.option_trq.configure(state="normal") - def write2textbox(self, text, wait=0, exitcode=0): if wait != 0: self.textbox.configure(text_color='blue') @@ -337,8 +348,8 @@ class App(customtkinter.CTk): elif flag == 'required': _ = float(item) except Exception as Err: - self.write2textbox(str(Err)) - self.write2textbox("参数数据缺失,或者数据类型错误,更正后重新运行...", 0, 3) + tkinter.messagebox.showerror(title="参数错误", message="请检查对应参数是否填写正确!", ) + self.write2textbox(f"错误信息:{Err}\n参数数据缺失,或者数据类型错误,更正后重新运行...", 0, 3) return True def check_param(self): @@ -353,7 +364,7 @@ class App(customtkinter.CTk): sub_func = self.menu_sub.get() c1 = exists(path) - c2 = self.is_float(av, rr) + c2 = self.is_float('required', av, rr) c3 = rpm = 1 c4 = sub_func in ['industrial', 'cobot'] c5 = True if vel != trq else False @@ -374,6 +385,7 @@ class App(customtkinter.CTk): elif func_name == 'current': path = self.entry_path.get() rc = self.entry_rc.get() + rpm = self.entry_rpm.get() dur = self.entry_dur.get() vel = self.option_vel.get() trq = self.option_trq.get() @@ -386,9 +398,10 @@ class App(customtkinter.CTk): rc5 = self.entry_rc_5.get() rc6 = self.entry_rc_6.get() - c1 = exists(path) - c2 = sub in ['max', 'avg', 'cycle'] - c3 = self.is_float('optional', rc) + c0 = exists(path) + c1 = sub in ['max', 'avg', 'cycle'] + c2 = self.is_float('optional', rc) + c3 = self.is_float('optional', rpm) _ = [rc1, rc2, rc3, rc4, rc5, rc6] c4 = self.is_float('required', *_) @@ -397,12 +410,15 @@ class App(customtkinter.CTk): c5 = True if vel != trq else False c6 = self.is_float('optional', dur) - if c1 and c2 and c3 and c4 and c5 and c6: + if c0 and c1 and c2 and c3 and c4 and c5 and c6: rcs = [] for x in _: rcs.append(float(x)) + rc = 0 if rc == '' else rc dur = 0 if sub != 'cycle' or dur == '' else dur - return 2, path, sub, rcs, int(vel), int(trq), int(trqh), float(dur) + rpm = 0 if sub != 'cycle' or rpm == '' else rpm + rcs.append(float(rc)) + return 2, path, sub, rcs, int(vel), int(trq), int(trqh), float(dur), float(rpm) else: return 0, 0 # ======================================================= @@ -427,7 +443,7 @@ class App(customtkinter.CTk): func_dict[flag](path=args[0], av=args[1], rr=args[2], rpm=args[3], axis=args[4], vel=args[5], trq=args[6], w2t=self.write2textbox) elif flag == 2: # tkinter.messagebox.showinfo(title="TBD", message="功能待实现......") - func_dict[flag](path=args[0], sub=args[1], rcs=args[2], vel=args[3], trq=args[4], trqh=args[5], dur=args[6], w2t=self.write2textbox) + func_dict[flag](path=args[0], sub=args[1], rcs=args[2], vel=args[3], trq=args[4], trqh=args[5], dur=args[6], rpm=args[7], w2t=self.write2textbox) elif flag == 3: func_dict[flag](path=args[0], w2t=self.write2textbox) else: @@ -436,11 +452,14 @@ class App(customtkinter.CTk): self.textbox.configure(state='disabled') def func_check_callback(self): + self.textbox.configure(state='normal') + self.textbox.delete(index1='1.0', index2='end') flag, *args = self.check_param() if flag: tkinter.messagebox.showinfo(title="参数正确", message="所有参数形式上填写无误,可以开始运行!") else: tkinter.messagebox.showerror(title="参数错误", message="需要检查对应参数是否填写正确!", ) + self.textbox.configure(state='disabled') def func_log_callback(self): content = self.textbox.get(index1='1.0', index2='end') @@ -453,7 +472,7 @@ class App(customtkinter.CTk): tkinter.messagebox.showinfo(title="保存成功", message=f'{log_name}已被保存存至↓↓↓\n{getcwd()}') except Exception as Err: - print(Err) + self.write2textbox(Err) tkinter.messagebox.showerror(title="保存失败", message="未能保存本次日志,或未能完整保存,请准备好相关数据,联系fanmingfu@rokae.com查看详细信息!", ) else: tkinter.messagebox.showwarning(title="未能保存", message="日志数据为空,不可保存!") diff --git a/aio/current.py b/aio/current.py index b93240d..422d384 100644 --- a/aio/current.py +++ b/aio/current.py @@ -2,11 +2,11 @@ from openpyxl import load_workbook from os import scandir from os.path import exists from sys import argv -from pandas import read_csv +from pandas import read_csv, concat, set_option from re import match from threading import Thread from time import sleep - +from csv import reader class GetThreadResult(Thread): def __init__(self, func, args=()): super(GetThreadResult, self).__init__() @@ -42,7 +42,7 @@ def traversal_files(path, w2t): # 返回值:路径下的文件夹列表 路径下的文件列表 if not exists(path): msg = f'数据文件夹{path}不存在,请确认后重试......' - w2t(msg, 0, 1) + w2t(msg, 0, 8) else: dirs = [] files = [] @@ -64,16 +64,16 @@ def initialization(path, sub, w2t): if sub != 'cycle': if not (match('j[1-7].*\\.data', filename) or match('j[1-7].*\\.csv', filename)): msg = f"所有文件必须以 jx_ 开头,以 .data/csv 结尾(x取值1-7),请检查后重新运行。" - w2t(msg, 0, 2) + w2t(msg, 0, 6) else: if filename.endswith('.xlsx'): count += 1 elif not (match('j[1-7].*\\.data', filename) or match('j[1-7].*\\.csv', filename)): msg = f"所有文件必须以 jx_ 开头,以 .data/csv 结尾(x取值1-7),请检查后重新运行。" - w2t(msg, 0, 3) + w2t(msg, 0, 7) if sub == 'cycle' and count != 1: - w2t("未找到电机电流数据处理excel表格,确认后重新运行!", 0, 4) + w2t("未找到电机电流数据处理excel表格,确认后重新运行!", 0, 5) return data_files @@ -125,7 +125,7 @@ def current_avg(data_files, rcs, trqh, w2t): return current -def current_cycle(dur, data_files, rcs, vel, trq, trqh, w2t): +def current_cycle(dur, data_files, rcs, vel, trq, trqh, rpm, w2t): result = None hold = [] single = [] @@ -162,9 +162,9 @@ def current_cycle(dur, data_files, rcs, vel, trq, trqh, w2t): pass if dur == 0: - p_single(wb, single, vel, trq, w2t) + p_single(wb, single, vel, trq, rpm, w2t) else: - p_scenario() + p_scenario(wb, single, vel, trq, rpm, dur, w2t) w2t(f"正在保存文件 {result},需要 10s 左右", 1) stop = 0 @@ -180,94 +180,171 @@ def current_cycle(dur, data_files, rcs, vel, trq, trqh, w2t): w2t("全部处理完毕") -def p_single(wb, single, vel, trq, w2t): +def find_point(flag, df, _row_s, _row_e, w2t, exitcode, threshold, step, end_point): + if flag == 'lt': + while _row_e > end_point: + speed_avg = df.iloc[_row_s:_row_e, 0].abs().mean() + if speed_avg < threshold: + _row_e -= step + _row_s -= step + continue + else: + return _row_s, _row_e + else: + w2t(f"数据有误,需要检查,无法找到第{exitcode}个有效点...", 0, exitcode) + elif flag == 'gt': + while _row_e > end_point: + speed_avg = df.iloc[_row_s:_row_e, 0].abs().mean() + if speed_avg > threshold: + _row_e -= step + _row_s -= step + continue + else: + return _row_s, _row_e + else: + w2t(f"数据有误,需要检查,无法找到有效起始点或结束点...", 0, exitcode) + + +def p_single(wb, single, vel, trq, rpm, w2t): # 1. 先找到第一个速度为零的点,数据从后往前找,一开始就是零的情况不予考虑 # 2. 记录第一个点的位置,继续向前查找第二个速度为零的点,同理,一开始为零的点不予考虑 # 3. 记录第二个点的位置,并将其中的数据拷贝至对应位置 for data_file in single: + rpm = 1 if rpm == 0 else rpm + scale = 1000 if data_file.endswith('.csv') else 1 axis = int(data_file.split('\\')[-1].split('_')[0].removeprefix('j')) shtname = f"J{axis}" ws = wb[shtname] + set_option("display.precision", 2) if data_file.endswith('.data'): df = read_csv(data_file, sep='\t') elif data_file.endswith('.csv'): df = read_csv(data_file, sep=',', encoding='gbk', header=8) + csv_reader = reader(open(data_file)) + i = 0 + cycle = 0.001 + for row in csv_reader: + i += 1 + if i == 3: + cycle = float(row[0].split(':')[1].split('ms')[0]) / 1000 + break + ws["H11"] = cycle - # 过滤尾部无效数据 + col_names = list(df.columns) + df_1 = df[col_names[vel-1]].multiply(rpm) + df_2 = df[col_names[trq-1]].multiply(scale) + df = concat([df_1, df_2], axis=1) + + _step = 5 if data_file.endswith('.csv') else 50 + _end_point = 30 if data_file.endswith('.csv') else 200 + _adjust = 0 if data_file.endswith('.csv') else 150 _row_e = df.index[-1] - _row_s = _row_e - 200 - while _row_e > 200: - speed_avg = df.iloc[_row_s:_row_e, vel-1].abs().mean() - if speed_avg > 2: - _row_e -= 50 - _row_s -= 50 - continue - else: - break - else: - w2t("数据有误,需要检查,无法找到第一个有效起始点...", 0, 1) + _row_s = _row_e - _end_point + speed_avg = df.iloc[_row_s:_row_e, 0].abs().mean() + if speed_avg < 2: + # 过滤尾部为零无效数据 + _row_s, _row_e = find_point('lt', df, _row_s, _row_e, w2t, 1, threshold=2, step=_step, end_point=_end_point) + # 找到第一个起始点 row_end,继续找到有数据的部分,后面有一段有效数据区 + row_end = _row_e - _adjust + _row_e -= _end_point + _row_s -= _end_point + _row_s, _row_e = find_point('gt', df, _row_s, _row_e, w2t, 3, threshold=2, step=_step, end_point=_end_point) + # 速度已经快要降为零了,继续寻找下一个速度上升点 + _row_e -= _end_point + _row_s -= _end_point + _row_s, _row_e = find_point('lt', df, _row_s, _row_e, w2t, 3, threshold=2, step=_step, end_point=_end_point) + elif speed_avg > 2: + # 过滤尾部非零无效数据 + _row_s, _row_e = find_point('gt', df, _row_s, _row_e, w2t, 2, threshold=2, step=_step, end_point=_end_point) + # 找到第一个起始点 row_end,继续找到有数据的部分,后面有一段零数据区 + row_end = _row_e - _adjust + _row_e -= _end_point + _row_s -= _end_point + _row_s, _row_e = find_point('lt', df, _row_s, _row_e, w2t, 4, threshold=2, step=_step, end_point=_end_point) + #目前已经有一点的速度值了,继续往前搜寻下一个速度为零的点 + _row_e -= _end_point + _row_s -= _end_point + _row_s, _row_e = find_point('gt', df, _row_s, _row_e, w2t, 4, threshold=2, step=_step, end_point=_end_point) - # 找到第一个起始点 row_end,继续找到有数据的部分 - row_end = _row_e - 100 - _row_e -= 200 - _row_s -= 200 - while _row_e > 200: - speed_avg = df.iloc[_row_s:_row_e, vel-1].abs().mean() - if speed_avg < 2: - _row_e -= 50 - _row_s -= 50 - continue - else: - break - else: - w2t("数据有误,需要检查,无法找到第二个有效起始点...", 0, 2) - - # 目前已经有一点的速度值了,继续往前搜寻下一个速度为零的点 - _row_e -= 200 - _row_s -= 200 - while _row_e > 200: - speed_avg = df.iloc[_row_s:_row_e, vel-1].abs().mean() - if speed_avg > 2: - _row_e -= 50 - _row_s -= 50 - continue - else: - break - else: - w2t("数据有误,需要检查,无法找到第三个有效起始点...", 0, 3) - - row_start = _row_s + 180 + row_start = _row_s + _adjust data = [] for row in range(row_start, row_end): - data.append(df.iloc[row, vel-1]) - data.append(df.iloc[row, trq-1]) + data.append(df.iloc[row, 0]) + data.append(df.iloc[row, 1]) i = 0 for row in ws.iter_rows(min_row=2, min_col=2, max_row=15000, max_col=3): for cell in row: try: - cell.value = data[i] + _ = f"{data[i]:.2f}" + cell.value = float(_) i += 1 except: cell.value = None -def p_scenario(): - pass +def p_scenario(wb, single, vel, trq, rpm, dur, w2t): + for data_file in single: + cycle = 0.001 + rpm = 1 if rpm == 0 else rpm + scale = 1000 if data_file.endswith('.csv') else 1 + axis = int(data_file.split('\\')[-1].split('_')[0].removeprefix('j')) + shtname = f"J{axis}" + ws = wb[shtname] + + set_option("display.precision", 2) + if data_file.endswith('.data'): + df = read_csv(data_file, sep='\t') + elif data_file.endswith('.csv'): + df = read_csv(data_file, sep=',', encoding='gbk', header=8) + csv_reader = reader(open(data_file)) + i = 0 + for row in csv_reader: + i += 1 + if i == 3: + cycle = float(row[0].split(':')[1].split('ms')[0]) / 1000 + break + + ws["H11"] = cycle + + col_names = list(df.columns) + df_1 = df[col_names[vel-1]].multiply(rpm) + df_2 = df[col_names[trq-1]].multiply(scale) + df = concat([df_1, df_2], axis=1) + + row_start = 300 + row_end = row_start + int(dur/cycle) + if row_end > df.index[-1]: + w2t(f"位置超限:{data_file} 共有 {df.index[-1]} 条数据,无法取到第 {row_end} 条数据...", 0, 9) + + data = [] + for row in range(row_start, row_end): + data.append(df.iloc[row, 0]) + data.append(df.iloc[row, 1]) + + i = 0 + for row in ws.iter_rows(min_row=2, min_col=2, max_row=15000, max_col=3): + for cell in row: + try: + _ = f"{data[i]:.2f}" + cell.value = float(_) + i += 1 + except: + cell.value = None # ======================================= -def main(path, sub, rcs, vel, trq, trqh, dur, w2t): +def main(path, sub, rcs, vel, trq, trqh, dur, rpm, w2t): data_files = initialization(path, sub, w2t) if sub == 'max': current_max(data_files, rcs, trqh, w2t) elif sub == 'avg': current_avg(data_files, rcs, trqh, w2t) elif sub == 'cycle': - current_cycle(dur, data_files, rcs, vel, trq, trqh, w2t) + current_cycle(dur, data_files, rcs, vel, trq, trqh, rpm, w2t) else: pass diff --git a/aio/vers b/aio/vers index 655cf7a..8e63fba 100644 --- a/aio/vers +++ b/aio/vers @@ -1 +1 @@ -0.1.2 @ 06/01/2024 +0.1.4 @ 06/06/2024 \ No newline at end of file