From 49d5f6c3db6ab0c7847aacbd7032d5e43835f0db Mon Sep 17 00:00:00 2001 From: gitea Date: Thu, 23 Jan 2025 11:20:16 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A5=E5=85=85readme=E4=BB=A5=E5=8F=8Arelea?= =?UTF-8?q?se=20change=E7=9B=B8=E5=85=B3=E4=BF=A1=E6=81=AF=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E6=94=B9clibs.running=E7=9A=84=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/files/version/release_change.md | 476 +++++++++++++++++++++++++ assets/files/version/requirements.txt | 10 + code/aio.py | 36 +- code/automatic_test/do_brake.py | 7 +- code/automatic_test/do_current.py | 1 + code/common/clibs.py | 2 +- code/data_process/brake.py | 1 + code/data_process/current.py | 1 + code/data_process/iso.py | 1 + code/data_process/wavelogger.py | 1 + code/durable_docs/create_plot.py | 20 +- code/durable_docs/factory_test.py | 8 +- readme.md | 83 ++++- 13 files changed, 599 insertions(+), 48 deletions(-) create mode 100644 assets/files/version/release_change.md create mode 100644 assets/files/version/requirements.txt diff --git a/assets/files/version/release_change.md b/assets/files/version/release_change.md new file mode 100644 index 0000000..39cc447 --- /dev/null +++ b/assets/files/version/release_change.md @@ -0,0 +1,476 @@ +v0.0.1(2024/05/18) +Draft + +v0.0.2(2024/05/20) +1. 功能模块化,为后面其他功能奠定一个基本的框架 +2. 使用了多线程提高效率 +3. 优化了准备工作中的细节 +4. 运行初始化时自动删除 raw_data_dir 中的 .xlsx 文件 +5. 优化了输出格式 +6. 使用 pyinstaller 库进行代码冻结并调试成功 + +v0.0.3(2024/05/21) +1. just_open函数打开失败的信息中,添加文件名 +2. 删除global变量,函数全部通过传参实现 +3. configuration.xlsx配置文件增加AXIS常量,表示那个轴,取值为 j1/j2/j3/j4/j5/j6/j7 +4. [bugfix] 增加get_threshold_step函数,用来获取在计算row_start时合适的阈值和步长,主要是解决了二轴最差工况下,最大速度是个尖端的问题: + a. load100_speed100_reachxxx 二轴 threshold = 50 step = 20 + b. 其他 threshold = 50 step = 100 + 如上是一个比较保守的设定,因为设定的step比较小,找到点之后要往后延200最好 +5. 在find_row_start_dp函数中新增一个参数data_file,方便后续调试 + +v0.0.4(2024/05/22) +1. 重新标定了get_threshold_step函数,让处理更加准确 +2. 新定义了now_doing_msg函数,实时输出处理信息 +3. 修改了find_row_start和find_row_start_dp函数,增加的部分相同,处理数据的时候,先判断是否是空值,或者是0,此时可以加快步进 +4. 修改了just_open函数,不在做重试 + +v0.0.5(2024/05/23) +1. 完善了函数注释 +2. 调整了阈值和步长 +3. 删除了just_open函数,以及对应的win32com库(Thank GOD!终于可以不用这个库了) +4. 重写了获取开始点位的代码,直接使用speed来判断,而不用角度,所以find_row_start_dp以及copy_data_to_excel_file函数也被一并删除 +5. 修改了配置文件configs.xlsx的初始参数顺序及结构,使程序通用性更强 +6. 将initialazation中的预定义变量赋值调整到try...except...之外,更方便排查问题 +7. 修改结束时间的格式,精确到秒 + +v0.0.6(2024/05/23) +1. 为了调整多功能框架,aio.py文件将会作为入口程序存在,不实现具体功能,功能的实现将由具体的功能脚本实现,aio.py只负责条件调用 +2. 新增了自动化处理电流数据(电机/过载)的功能 + +v0.1.0(2024/05/29) +1. 修改为customtkinter图形化界面 +2. 支持工业机器人制动数据处理(理论上支持,测试数据有问题,待验证) +3. 删除configs.xlsx配置表格,直接在界面配置,新增layout.xlsx文件,存储customtkinter布局 +4. 电流尚未支持 + +v0.1.1(2024/05/30) +1. 增加版本检测功能 +2. 修改了无效数据下的动作 +3. textbox只在开始和结束时改变状态,而不是每次写入都更改 +4. 调整了brake的结构 +5. 重新在write2textbox中添加exitcode参数,并补齐相关逻辑和修改brake中的调用方式 +6. 修复参数检查无效的情况 +7. 屏蔽电流相关的功能 + +v0.1.2(2024/06/01) +1. 增加iso数据处理功能 +2. 重新修改了README.md +3. 单独将rokae拉出来,作为一个独立的repo进行维护,与scripts分离 + +v0.1.3(2024/06/01) +1. 完成电流处理的基本功能 +2. 修复了一些已知bugs + +v0.1.4(2024/06/06) +1. AV/RR支持小数 +2. 可处理电机电流单轴以及多轴数据,可根据需要进行参数设定处理不同轴的数据 +3. 界面初始位置修改,以及删除所有entry的长度设定,因为设定无效 +4. 修改了layout.xlsx布局,增加了duration/trqH/STO字段,以及额外的RC行,整体扩展了区域 +5. 更改label/entry/optionmenu等控件的生成方式,使用循环实现,更加简洁和容易维护(暂未实现) +6. 支持工业/协作两条产品线的电机电流数据处理,包括单轴,场景,max/avg计算 + +v0.1.5(2024/06/12) +1. [aio.py] 主界面切换不同功能时保持placehold一致 +2. [brake.py] 由于制动采集模板和内容的更改,适配了新的数据,更新了算法 +3. [aio.py] 新增tabview组件,区分数据处理和自动化测试功能 +4. [aio.py] 重新调整界面配色 +5. [aio.py] 修改了write2textbox函数,定制化显示每一行的颜色,针对每一行可自定义输出内容颜色 +6. [brake.py/iso.py/current.py] 由于第 5 点的更改,同时修改了其他文件相关引用的部分 +7. [aio.py] 更改label/entry/optionmenu等控件的生成方式,使用循环实现,更加简洁和容易维护 +8. [aio.py] 修改customtkinter库中C:\Users\Administrator\AppData\Local\Programs\Python\Python312\Lib\site-packages\customtkinter\windows\widgets\ctk_tabview.py文件,参考https://github.com/TomSchimansky/CustomTkinter/issues/2296,实现修改tabview组件的字体大小 +9. [aio.py] 修改menu_main->menu_main_dp,menu_sub->menu_sub_dp,为后续其他tab功能按钮做扩展,是针对第三点做出的相应调整 +10. [layout.xlsx] 添加了各个功能的流程图 + +v0.1.5.1(2024/06/12) +1. [current.py] 修改cycle功能中,数据清理范围为70000行,并将threshold从2调整为5 +2. [current.py] 修改位置超限提示,使更清楚了解问题原因 +3. [current.py] 修改find_point函数中错误提示,增加定位信息 +4. [README.md] 精简打包命令 +5. [requirements.txt] 新增必要库配置文件 + +v0.1.5.2(2024/06/13) +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] 提高了输出提示语的明确性,删除了不必要的省略号 +5. [brake.py] 更正了之前的数据copy错误,重新优化了estop处是否达到指定百分比的判定逻辑 + +v0.1.5.3(2024/06/14) +1. [aio.py] 修改w_param为84,适配14寸电脑屏幕 +2. [brake.py] 将判定合规逻辑修改为角速度超过指定角速度的95% +3. [README.md] 稍作修改,包括打包方式,功能特性等 + +v0.1.6.0(2024/06/15) +1. [aio.py] 新增wavelogger处理界面 +2. [wavelogger.py] 新增精度数据处理模块 + +v0.1.6.1(2024/06/16) +1. [wavelogger.py] bugfix single_file_proc函数中,修改_start起始点的计算逻辑 +2. [wavelogger.py] bugfix find_point函数中,当判断条件为临界值 2.0 的时候,针对forward和backward两种情况,对row_target做与判断逻辑相同的处理,目的是避免形成死循环 + +v0.1.6.2(2024/06/16) +1. [current.py] 修改了max/avg相关功能中对于返回值的处理逻辑,并在输出框以行的形式打印出来 + +v0.1.6.3(2024/06/18) +1. [current.py] 适配电机电流中速度使用hw_joint_vel_feedback的数据,取消对device_servo_vel_feedback的支持,后续所有涉及到速度相关的数据均已前者为准,现已完成对单轴和场景的适配 + +> !!WARNING:目前版本的电机电流程序还支持DriverMaster采集的数据处理,等明确后,将不再支持,也即所有的电机电流数据(工业+协作),都是用诊断曲线来采集 + +v0.1.7.0(2024/06/19)-未发布 +1. [openapi.py] 初步搭建起框架,完成了新老协议的封包/解包/异步采集日志的操作(未充分测试,但基本无问题) +2. [openapi.py] 修改了封包的规则,使之更加明晰,封包操作没有实现分包功能,目前看实际场景用不到 + +v0.1.7.0(2024/06/21)-未发布 +1. [openapi.py] 定义 MAX_FRAME_SIZE 常量(1024),替换socket接收以及响应数据处理相关部分 +2. [openapi.py] 使用 int.to_bytes 和 int.from_bytes 替换 binascii 模块的功能 +3. [aio.py] 修改了Data Process中初始化的动作,使得初始化时的状态统一成程序刚启动时的样子 + +v0.1.7.0(2024/06/23)-未发布 +1. [aio.py] 增加了tabview的点击行为函数,每次点击tab都会初始化 +2. [aio.py] 增加了Automatic Test界面元素,包括如下,并完成了功能框架的搭建 + - 标签:文件/角速度/减速比 + - 按钮:急停及恢复 + - 输入框:文件路径/角速度/减速比 + - OptionMenu:负载 + - 进度条 +3. [openapi.py] 增加心跳检测函数,并开启线程执行;取消在该文件中生成实例 +4. [aio.py] 完成detect_network,并在main函数开启线程 +5. 将templates文件夹移动到assets内 + +v0.1.7.0(2024/06/24)-未发布 +1. [openapi.py] 建联部分做容错逻辑,并将读写文件做自适应处理 +2. [aio.py] 将读写文件做自适应处理,引入openapi模块并生成实例,做心跳检测,将socket超时时间修改为3s + +v0.1.7.0(2024/06/25)-未发布 +1. [aio.py] 取消了在本文件中开启openapi线程的做法,并修改如下: + - 通过包的方式导入其他模块 + - 使用current_path来规避文件路径问题 + - 声名了 self.hr 变量,用来接收openapi的实例化 + - 修改了对于segment button的错误调用 + - 设定progress bar的长度是10 + - 完善了segmented_button_callback函数 + - 在detect_network函数中增加heartbeat初始化 + - tabview_click函数中新增textbox清屏功能,以及实例化openapi,并做检测 +2. [openapi.py] 取消了初始化中无限循环检测,因为阻塞了aio主界面进程!!!socket也无法多次连接!!!浪费了好多时间!!!很生气!!!! + - 通过tabview切换来实现重新连接,并保留了异常处理部分 + - 将所有的 __xxxx 函数都替换成 xxxx 函数,去掉了 __ + - 使用current_path来规避文件路径问题 +3. [do_brake.py] 初步完成了机器状态收集的功能,还需要完善 + - 使用current_path来规避文件路径问题 + - 新增validate_resp函数,校验数据 + - 完善了调用接口 + +> **关于HMI接口** +> - 封包解包顺序:帧长度二字节/包长度四字节/协议二字节/预留二字节,\x04\x00:\x00\x00\tR:\x02:\x00 +> - 帧长度和包长度没有必然关系,单帧的时候是帧长度减去包长度等于6,包长度指的是所有内容的长度 +> - 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函数中对于实例化HmiRequest的动作,使每次切换标签都会重新实例化,也就是每次都会重新连接,修复显示不正确的问题 +7. [openapi.py] 新增了socket关闭的函数,并增加msg_id为None的处理逻辑 +8. [btn_functions.py] 完善了状态获取的功能,新增告警获取以及功能切换的逻辑 +9. [aio.py] 修改了版本 +10. [current.py] max/avg功能结束之前会将结果数据追加写入源文件,avg算法更改为average+3×std +11. [wavelogger.py] 算法更改为 average+3×std + +v0.1.7.1.0(2024/06/29) +1. [APIs: aio.py] + - 对于automatic test删除了输入框,使用configs.xlsx配置文件作为参数输入 + - 完善initialization/param_check/func_start_callback函数中对于automatic test的处理 + - 将textbox组件一直设置为normal状态,不再频繁切换disabled + - 将所有的f_h文件对象修改为f_hb,并将connection_state修改为c_state + - 在detect_network函数中,实例化HmiRequest,并在无限循环中检测心跳是否正常,如异常,则销毁hr,重新生成 + - 取消在tabview切换时,检测心跳的逻辑,这样做无法保证实时性 +2. [APIs: openapi.py] + - 将sock_conn函数移出__init__,单独作为连接函数存在 + - 新增全局变量self.t_bool,控制所有的线程中无限循环的启停,也就是可以人为的退出线程 + - 移除close_sock函数 + - heartbeat函数中新增打印所有消息的代码,调试时打开,平常关闭 + - execution函数中,新增对overview.set_autoload和overview.reload的支持 + - execution函数中,对send动作增加异常处理逻辑 +3. [APIs: do_brake.py] + - 新增文件,处理制动测试流程,建立连接,导入project,pp2main,run,采集并处理曲线数据,本地修改RL程序,推送至控制器等 + - 目前完成: + - 文件合规性检查 + - 导入工程并设置为运行工程 +4. [APIs: current.py] 修改scenario/single电机电流最大长度为150s +5. 在本文件中更新关于制动自动化测试的相关内容 +6. [t_change_ui: aio.py/brake.py/current.py] 整体修改了操作界面,删除了大部分的配置输入框,改用 configs.xlsx 配置文件替代,并优化了max/avg功能中写入结果数据的方式 + +v0.1.7.1.1(2024/06/29) +1. [APIs: aio.py] + - 修改detect_network函数中sleep语句放到最后,重新生成HmiRequest实例中增加sleep(4),这个停顿时间一定是比openapi中heartbeat函数的sleep要长1s以上才能正常工作 + - 修改write2textbox函数,新增默认参数tab_name,只有当该值与当前tab一致时,函数才会有输出 + - 第二条改动影响到了automatic_test文件夹下所有的文件 +2. [APIs: openapi.py] + - 规定了所有的网络异常均由heartbeat函数来定义,其他异常不做中断处理 + - execution函数中合并了case条件 + - 增加了N多指令,多为诊断曲线和rl程序相关 + - 日志保留条数修改为20000 +3. [APIs: do_brake.py] + - 实现自动推送工程到xCore并自动运行 + - 初步实现了Modbus发送消息和检测状态 +4. [APIs: do_current.py] + - 将do_brake.py的内容完全拷贝到此文件,待修改 + +v0.1.7.2(2024/06/30) +1. 初步完成NB4h_R580_3BH7.zip工程的设计 +2. 重新研究了解包操作,重新实现了一版 +3. 修改openapi.pi中excution为execution函数 +4. 增加了解包原理性文档 + +v0.1.7.3(2024/07/01) +1. [APIs: openapi.py] + - 继续完善封包解包操作,并优化了所有调试信息,默认打开状态,直到bug数量明显减少 + - 修复了两个bug,删除了一个多余的break,另一个是补齐了self.broke的重置 +2. [APIs: do_current.py] 使用原工程的工程名进行move操作,语义更加明确 + +> 目前看openapi.py封包解包没有任何问题了,但是所有的调试信息都默认打开,以便可以第一时间保留现场 +> 打开诊断,跑了10多分钟,共计解包没有报错,应该是没有问题了 + +v0.1.7.4(2024/07/02) +1. [APIs: openapi.py] + - 增加了modbus的python实现 + - heartbeat函数修改发送间隔为1s + - 清除了绝大部分调试性输出,发现太多的这种输出也会导致心跳丢包...,不清楚这个原理是什么 + - 在get_response函数中的while self.pkg > 0循环中,删除了else语句,因为它永不会被执行到 + - 在get_response函数中,修复一个bug,在flag==0的else语句中,补齐了index==6的情况 +2. [APIs: do_current.py] + - 完成了六个轴的电机电流动作的执行,以及数据采集 + - 完成了对应的RL程序的编写 +3[APIs: aio.py] + - 引入modbus实例化,并以参数的形式,传递给相应的tabview + - 新增pre_warning函数,在做自动化测试之前,确保所有条件皆具备 + +v0.1.7.5(2024/07/03) +1. [APIs: aio.py] + - 增加触发急停和恢复急停功能逻辑 +2. [APIs: do_current.py] + - 重新调整运行顺序,增加数据处理的逻辑(惯量负载逻辑暂不实现,等待软件部解决了修改工程之后不生效的问题再考虑) +3. [APIs: btn_functions.py] + - 增加触发急停和恢复急停的modbus实现,仅适用于自动化测试 + +v0.1.7.6(2024/07/04) +1. [APIs: aio.py] + - Automatic Test逻辑中增加选择current时,需要选负载类型的逻辑 +2. [APIs: do_current.py] + - 单轴/场景电机电流的采集已完成 +3. [APIs: openapi.py] + - 增加了modbus读取浮点数的功能 + - 优化了get_from_id的逻辑 +4. [autotest.xml]: 新增了scenario_time只写寄存器 + +v0.1.8.0(2024/07/04) +1. [APIs: do_current.py]: 完成了堵转电流和惯量负载电机电流的采集和处理,至此,电机电流的自动化工作基本完成 + +v0.1.8.1(2024/07/05) +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 +2. [APIs: do_current.py]: 修改曲线数据时序,主要是value data取反即可,解决了波形锯齿明细的问题 +3. [APIs: openapi.py]: modbus新增了触发急停信号的寄存器 stop0_signal,并重写了解除急停,socket新增了register.set_value协议 + +v0.1.9.0(2024/07/10) +1. 完成了制动性能的自动化采集 +2. 完善了modbus浮点数读写相关的功能 +3. 修改了target.zip工程,该工程目前适配电机电流和制动性能 + +v0.1.9.1(2024/07/12) +1. [APIs: do_brake.py] + - 修改正负方向拍急停的逻辑,基本原理为:运行之前发送正负方向信号pon给RL,RL根据信号以及速度正负号运作 + - 由于上述修改,正负方向急停准确率可达100% +2. [APIs: aio.py] + - 修改write2textbox的输出逻辑,实现更加灵活的自定义输出,同时修改相关部分 +3. [APIs: openapi.py] + - modbus类新增指示政府方向急停的信号pon,将modbus类入参中的tab_name删除,并修改tab_name的值为'openapi' + - socket类种修改tab_name的值为'openapi' + +v0.1.9.2(2024/07/13) +1. [APIs: do_brake.py] + - 修改ready_to_go信号的接收逻辑,适配大负载机型 +2. [APIs: do_current.py] + - 修改ready_to_go信号的接收逻辑,适配大负载机型 + - 调整单轴测试时间为35s,适配大负载机型,调整堵转电流持续时间15s,适当减少测试时间 + - 将act信号置为False的动作放在初始化,增加程序健壮性 + - 修改所有输出文件的命名,在扩展名之前加入时间戳 + - 删除多余的时序矫正语句——item['value'].reverse(),使输出的曲线为平滑的自然顺序 +3. [current: current.py] + - 在find_point函数种,当无法找到正确点位时,继续执行,而不是直接终止执行 + - max功能计算逻辑矫正,应该是取绝对值的最大值 + - 整体梳理了trq/trqh的传递路径,现已修正完毕 + - 减速比rr数据源修改为configs.xlsx +4. 在current工程main函数增加 VelSet 100语句 + +v0.1.9.3(2024/07/15) +1. [APIs: openapi.py] + - 修改modbus连接失败报错输出形式,使之只在automatic test页面显示 + - 将该文件移动至toplevel,为后面扩展做准备 + - 修改heartbeat文件路径,使后续打包的时候更方便 +2. [APIs: aio.py] + - 修改heartbeat文件路径,使后续打包的时候更方便 + - 修改write2textbox函数的打印逻辑,先判断网络相关 + +v0.1.9.4(2024/07/15) +1. [profile: aio.py]:完善durable text相关逻辑 +2. [profile: do_brake/do_current/btn_functions.py]:删除validate_resp函数,修改execution函数 +3. [profile: factory_test.py] + - 新增耐久/老化测试程序 + - 实现六轴折线图显示 +4. [profile: openapi.py]:多次合并遗留问题处理 +5. templates文件夹组织架构调整 + +v0.2.0.0(2024/07/17) +1. [profile: aio.py] + - 增加velocity相关逻辑 + - 修改负载信息为曲线信息 +2. [profile: factory_test.py] + - 增加velocity相关逻辑 +3. [profile: current.py] + - 修正减速比获取的规则 +4. [profile: openapi.py] + - HmiRequest模块:日志取消记录move.monitor相关 + - HmiRequest模块:增加了durable_lock变量,控制文件读写互斥 + +v0.2.0.1(2024/07/19) +1. [main: aio.py] + - 修改了x轴显示,使之为时间刻度 + - 修改pre_warning函数,增加了durable test的初始化 +2. [main: factory_test.py] + - 增加了数据计算错误的判断逻辑 + - 增加了历史数据保存的逻辑 + - 增加了文件读写互斥的逻辑 + - 修改功能为输出有效电流和最大电流,并将数据结构简化 + +v0.2.0.2(2024/07/26) +1. [main: current.py] + - 修正堵转电流无法正确写入结果文件的问题 +2. [main: do_brake.py] + - 初始速度采集等待时间设置为可通过configs.xlsx配置文件调整的 + - 初次速度采集停止逻辑修改为tasks.stop指令(未验证) + - 急停信号触发前,pending时间设置为固定值10s + - 实现正负方向速度采集逻辑 + - 工程名变更逻辑实现修改为通配符,方便后续根据机型保存文件 + - 增加超差后写诊断的逻辑,并可以通过configs.xlsx配置文件调整 + - 程序输出中增加时间戳,方便调试定位日志时间 +3. [main: do_current.py] + - 工程名变更逻辑实现修改为通配符,方便后续根据机型保存文件 +4. 为工程文件添加更详细的注释 +5. 补充了do_current/do_brake的流程图 +6. [main: openapi.py] + - 将modbus motor_on/off的实现方法改为高电平脉冲触发 +7. configs.xlsx配置表新增write_diagnosis/get_init_speed两个参数 + +v0.2.0.3(2024/07/27) +1. [APIs: do_brake.py]: 精简程序,解决 OOM 问题 +2. [APIs: do_current.py]: 精简程序,解决 OOM 问题 +3. [APIs: factory_test.py]: 精简程序,解决 OOM 问题 +4. [APIsL openapi.py] + - 心跳修改为 1 s,因为 OOM 问题的解决依赖于长久的打开曲线开关,此时对于 hr.c_msg 的定时清理是个挑战,将心跳缩短,有利于清理日志后,避免丢失心跳 + - 新增 diagnosis.save 命令,但是执行时,有问题,待解决 + +v0.2.0.4(2024/07/30) +1. [APIs: do_brake.py]: 修复制动数据处理过程中,只取曲线的最后 240 个数据 +2. [APIs: aio.py]: 判定版本处,删除 self.destroy(),因为该语句会导致异常发生 + - 心跳修改为 1s,因为 OOM 问题的解决依赖于长久的打开曲线开关,此时对于 hr.c_msg 的定时清理是个挑战,将心跳缩短,有利于清理日志后,避免丢失心跳 + - 新增 diagnosis.save 命令,但是执行时,有问题,待解决 + +v0.2.0.5(2024/07/31) +此版本改动较大,公共部分做了规整,放置到新建文件夹 commons 当中,并所有自定义模块引入 logging 模块,记录重要信息 +1. [t_change_ui: clibs.py] + - 调整代码组织结构,新增模块,将公共函数以及类合并入此 + - 将一些常量放入该模块 + - 引入logging/concurrent_log_handler模块,并作初始化操作,供其他模块使用,按50M切割,最多保留10份 + - prj_to_xcore函数设置工程名部分重写,修复了多个prj工程可能不能执行的问题,并优化输入密码的部分 +2. [t_change_ui: openapi.py] + - 完全重写了 get_from_id 函数,使更精准 + - 在 msg_storage 函数中,增加 logger,保留所有响应消息 + - 删除 heartbeat 函数中的日志保存功能部分 + - 心跳再次修改为 2s... +3. [t_change_ui: aio.py] + - 增加了日志初始化部分 + - detect_network 函数中修改重新实例化HR间隔为 4s,对应心跳 + - create_plot 函数中增加 close('all'),解决循环画图不销毁占用内存的问题 +4. [t_change_ui: do_brake.py] + - 使用一直打开曲线的方法规避解决了 OOM 的问题,同时修改数据处理方式,只取最后 12s + - 优化 ssh 输入密码的部分 +5. [t_change_ui: do_current.py] + - 保持电流,只取最后 15s + - 优化 ssh 输入密码的部分 +6. [t_change_ui: all the part]: 引入 commons 包,并定制了 logging 输出,后续持续优化 +7. [APIs: btn_functions.py]: 重写了告警输出函数,从日志中拿数据 +8. [APIs: aio.py]: 将日志框输出的内容,也保存至日志文件 +9. [APIs: do_brake.py] + - 修改获取初始速度的逻辑,只获取configs文件中配置的时间内的速度 + - 新增 configs 参数 single_brake,可针对特定条件做测试 +10. [APIs: all]: 添加了 logger.setLevel(INFO),只有添加这个,单个模块内才生效 + +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 + +v0.2.1.1(2024/12/16) +1. [main: do_brake.py] 修改了 SSH 的固定 IP 为 clibs 中读取的内容,并删除了每次都 reload 工程的动作,改为只在修改 RL 工程时 reload 一次,旨在减少最近频繁出现的“无法获取overview.reload-xxxxxx”请求的响应,初步判断是 xCore 的问题,非 AIO 问题,已反馈待版本修复 +2. [main: wavelogger.py] 新增异常数据校验功能 + +v0.3.0.0(2025/01/09) +1. 重构了 AIO 工具: + - UI 界面 + - 电机电流数据处理功能 + - xCore 通讯协议实现 +2. 将之前的功能迁移到新代码 + +v0.3.1.0(2025/01/23) +1. 实现了从机型文件读取相关测试参数,并用于自动化测试或者数据处理 +2. 完整实现了所有功能的迁移,并自测验证通过 +3. 重新实现并优化了如下功能: + - 电机电流数据采集,优化代码,提高执行效率,并适配新的报告文件 + - 制动数据采集,比之前采集正确率提高 30%,基本可以做到 100% 的数据准确度 + - 耐久数据采集并记录,优化了执行以及数据展示 + - 基恩士数据采集处理,适配任意编码格式的文件处理 + + + + diff --git a/assets/files/version/requirements.txt b/assets/files/version/requirements.txt new file mode 100644 index 0000000..617ee82 --- /dev/null +++ b/assets/files/version/requirements.txt @@ -0,0 +1,10 @@ +chardet==5.2.0 +customtkinter==5.2.2 +matplotlib==3.10.0 +numpy==2.2.2 +openpyxl==3.1.5 +pandas==2.2.3 +paramiko==3.5.0 +pdfplumber==0.11.5 +Pillow==11.1.0 +pymodbus==3.8.3 diff --git a/code/aio.py b/code/aio.py index 217aa51..e744736 100644 --- a/code/aio.py +++ b/code/aio.py @@ -151,7 +151,7 @@ class App: if self.server_vers is None: return image = ctk.CTkImage(Image.open(f"{clibs.PREFIX}/media/upgrade.png"), size=(16, 16)) - var_tips.set(f" {self.server_vers.split("@")[0]}已经发布,尽快更新至最新版本! ") + var_tips.set(f" {self.server_vers.split('@')[0]}已经发布,尽快更新至最新版本! ") self.label_tips.configure(text_color="#D81E06", image=image, cursor="hand2") self.label_tips.bind("", self.__goto_update) @@ -274,26 +274,35 @@ class App: def __trig_estop(self): def trig_estop(): self.tabview_bottom.set("输出") - self.__w2t("触发软急停信号已发送...\n") - clibs.c_md.r_soft_estop(0) + t = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + try: + clibs.c_md.r_soft_estop(0) + self.__w2t(f"{t} - 触发软急停信号已发送...\n") + except Exception as Err: + clibs.insert_logdb("WARNING", "aio", f"触发软急停失败 - {Err}") + return try: clibs.c_hr.execution("diagnosis.open", open=False, display_open=False, overrun=True, turn_area=True, delay_motion=False) clibs.c_hr.execution("diagnosis.set_params", display_pdo_params=[], frequency=50, version="1.4.1") except Exception as Err: clibs.insert_logdb("WARNING", "aio", f"关闭诊断曲线失败 - {Err}") - if clibs.running: - clibs.running = False - self.__w2t("程序已停止运行,执行过程中停止时需要清零后台数据,大约一分钟左右后再重新运行!!!\n", "red", "TerminateProgram") + if clibs.running > 20: + self.__w2t("程序已停止运行,!!执行过程中停止时需要清零后台数据!!:\n- 制动/电机电流测试大约一分钟左右\n- 耐久数据采集需至多等待一个轮次的时间\n\n下次提示出现之后才可重新运行,否则有可能会出现数据错乱的情况!!!\n", "red", "TerminateProgram") + clibs.running = 0 self.__thread_it(trig_estop) def __reset_estop(self): def reset_estop(): self.tabview_bottom.set("输出") - # self.text_output.delete("1.0", "end") - self.__w2t("解除软急停信号已发送...\n") - clibs.c_md.r_soft_estop(1) - clibs.c_md.r_clear_alarm() + t = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + try: + clibs.c_md.r_soft_estop(1) + clibs.c_md.r_clear_alarm() + self.__w2t(f"{t} - 解除软急停信号已发送...\n") + except Exception as Err: + clibs.insert_logdb("WARNING", "aio", f"触发解除软急停失败 - {Err}") + self.__thread_it(reset_estop) @staticmethod @@ -342,12 +351,12 @@ class App: self.text_output.insert(ctk.END, text, tags=color) self.text_output.see(ctk.END) if desc: - clibs.running = False + clibs.running = 0 raise Exception(desc) @staticmethod def __is_running(operation): - if clibs.running: + if clibs.running > 0: messagebox.showerror(title="处理中", message=f"有程序正在运行,需等待结束后,在执行{operation}操作!") return "running" @@ -401,7 +410,6 @@ class App: if init_op() == "running": return - clibs.running = True try: if self.tabview_top.get() == "数据处理": clibs.data_dp = get_data_dp() @@ -415,7 +423,7 @@ class App: except Exception as Err: self.__w2t(f"程序执行过程中出现异常,{Err}\n", "red") finally: - clibs.running = False + clibs.running = 0 clibs.stop = False exec_function() diff --git a/code/automatic_test/do_brake.py b/code/automatic_test/do_brake.py index 20e110d..2fa773c 100644 --- a/code/automatic_test/do_brake.py +++ b/code/automatic_test/do_brake.py @@ -36,7 +36,7 @@ def initialization(path, sub, data_dirs, data_files, hr, w2t): os.mkdir(f"{path}/j2") os.mkdir(f"{path}/j3") - load = f"load{sub.removeprefix("tool")}" + load = f"load{sub.removeprefix('tool')}" for reach in ["reach33", "reach66", "reach100"]: for speed in ["speed33", "speed66", "speed100"]: dir_name = "_".join([reach, load, speed]) @@ -211,7 +211,7 @@ def run_rl(path, sub, hr, md, config_file, prj_file, result_dirs, avs, w2t): elif pon == "negative": rl_cmd = f"brake_E(j{axis}_{reach}_n, j{axis}_{reach}_p, p_speed, p_tool)" rl_speed = f"VelSet {speed}" - rl_tool = f"tool p_tool = tool{sub.removeprefix("tool")}" + rl_tool = f"tool p_tool = tool{sub.removeprefix('tool')}" cmd = "cd /home/luoshi/bin/controller/; " cmd += f'sudo sed -i "/brake_E/d" projects/{prj_name}/_build/brake/main.mod; ' cmd += f'sudo sed -i "/DONOTDELETE/i {rl_cmd}" projects/{prj_name}/_build/brake/main.mod; ' @@ -338,7 +338,7 @@ def run_rl(path, sub, hr, md, config_file, prj_file, result_dirs, avs, w2t): clibs.count = 0 break else: - w2t(f"\n{sub.removeprefix("tool")}%负载的制动性能测试执行完毕,如需采集其他负载,须切换负载类型,并更换其他负载,重新执行。\n", "green") + w2t(f"\n{sub.removeprefix('tool')}%负载的制动性能测试执行完毕,如需采集其他负载,须切换负载类型,并更换其他负载,重新执行。\n", "green") def main(): @@ -348,6 +348,7 @@ def main(): w2t = clibs.w2t hr = clibs.c_hr md = clibs.c_md + clibs.running = 21 data_dirs, data_files = clibs.traversal_files(path, w2t) config_file, prj_file, result_dirs, avs = initialization(path, sub, data_dirs, data_files, hr, w2t) diff --git a/code/automatic_test/do_current.py b/code/automatic_test/do_current.py index e2cd2d7..605b517 100644 --- a/code/automatic_test/do_current.py +++ b/code/automatic_test/do_current.py @@ -255,6 +255,7 @@ def main(): w2t = clibs.w2t hr = clibs.c_hr md = clibs.c_md + clibs.running = 22 data_dirs, data_files = clibs.traversal_files(path, w2t) prj_file = initialization(path, sub, data_dirs, data_files, hr, w2t) diff --git a/code/common/clibs.py b/code/common/clibs.py index e0f67f0..99d2715 100644 --- a/code/common/clibs.py +++ b/code/common/clibs.py @@ -72,7 +72,7 @@ log_path = f"{PREFIX}/logs" levels = ["DEBUG", "INFO", "WARNING", "ERROR"] db_state = "readwrite" data_dp, data_at, data_dd = {}, {}, {} -conn, cursor, w2t, tl_prg, f_records, stop, running = None, None, None, None, None, True, False +conn, cursor, w2t, tl_prg, f_records, stop, running = None, None, None, None, None, True, 0 ip_addr = "192.168.0.160" ssh_port, socket_port, xService_port, external_port, modbus_port, upgrade_port = 22, 5050, 6666, 8080, 502, 4567 diff --git a/code/data_process/brake.py b/code/data_process/brake.py index db65dc6..c2b4d54 100644 --- a/code/data_process/brake.py +++ b/code/data_process/brake.py @@ -196,6 +196,7 @@ def main(): trq = int(clibs.data_dp["_trq"]) estop = int(clibs.data_dp["_estop"]) w2t = clibs.w2t + clibs.running = 1 rawdata_dirs, result_files = clibs.traversal_files(path, w2t) config_file, result_files = check_files(rawdata_dirs, result_files, w2t) diff --git a/code/data_process/current.py b/code/data_process/current.py index 7142fd4..de1deba 100644 --- a/code/data_process/current.py +++ b/code/data_process/current.py @@ -412,6 +412,7 @@ def main(): trqh = int(clibs.data_dp["_trqh"]) sensor = int(clibs.data_dp["_sensor"]) w2t = clibs.w2t + clibs.running = 2 insert_logdb = clibs.insert_logdb insert_logdb("INFO", "current", "current: 参数初始化成功") diff --git a/code/data_process/iso.py b/code/data_process/iso.py index 867999e..2a66ecf 100644 --- a/code/data_process/iso.py +++ b/code/data_process/iso.py @@ -135,6 +135,7 @@ def p_iso_1000(file, p_files, ws, tmpfile): def main(): path = clibs.data_dp["_path"] w2t = clibs.w2t + clibs.running = 3 dirs, files = clibs.traversal_files(path, 1) filename = f"{path}/iso-results.xlsx" diff --git a/code/data_process/wavelogger.py b/code/data_process/wavelogger.py index 7e31daf..5680812 100644 --- a/code/data_process/wavelogger.py +++ b/code/data_process/wavelogger.py @@ -145,6 +145,7 @@ def execution(data_files, w2t): def main(): path = clibs.data_dp["_path"] w2t = clibs.w2t + clibs.running = 4 data_files = initialization(path, w2t) execution(data_files, w2t) diff --git a/code/durable_docs/create_plot.py b/code/durable_docs/create_plot.py index ec4c00b..046a4a9 100644 --- a/code/durable_docs/create_plot.py +++ b/code/durable_docs/create_plot.py @@ -60,23 +60,15 @@ def main(): for curve in curves: data_plot(path, curve) - plt.rcParams['font.sans-serif'] = ['SimHei'] - plt.rcParams['axes.unicode_minus'] = False - plt.rcParams['figure.dpi'] = 100 - plt.rcParams['font.size'] = 14 - plt.rcParams['lines.marker'] = 'o' - plt.rcParams["figure.autolayout"] = True plt.show() - # threads = [threading.Thread(target=data_plot, args=(path, curve)) for curve in curves] - # for t in threads: - # t.daemon = True - # t.start() - # for curve in curves: - # t = threading.Thread(target=data_plot, args=(path, curve)) - # t.daemon = True - # t.start() +plt.rcParams['font.sans-serif'] = ['SimHei'] +plt.rcParams['axes.unicode_minus'] = False +plt.rcParams['figure.dpi'] = 100 +plt.rcParams['font.size'] = 14 +plt.rcParams['lines.marker'] = 'o' +plt.rcParams["figure.autolayout"] = True if __name__ == '__main__': main() diff --git a/code/durable_docs/factory_test.py b/code/durable_docs/factory_test.py index 6425998..292e862 100644 --- a/code/durable_docs/factory_test.py +++ b/code/durable_docs/factory_test.py @@ -140,10 +140,6 @@ def run_rl(path, params, curves, hr, md, w2t): # 7. 开始采集 count = 0 while clibs.running: - if not clibs.running: - w2t("后台数据清零完成,现在可以重新运行之前停止的程序。\n", "red") - exit() - this_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())) next_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()+scenario_time+interval+1)) w2t(f"[{this_time}] 当前次数:{count:09d} | 预计下次数据更新时间:{next_time}\n", "#008B8B") @@ -157,6 +153,9 @@ def run_rl(path, params, curves, hr, md, w2t): change_curve_state(hr, curves, False, False) # 保留数据并处理输出 gen_results(params, curves, start_time, end_time, w2t) + else: + w2t("后台数据清零完成,现在可以重新运行之前停止的程序。\n", "red") + exit() def gen_results(params, curves, start_time, end_time, w2t): @@ -255,6 +254,7 @@ def main(): hr = clibs.c_hr md = clibs.c_md w2t = clibs.w2t + clibs.running = 23 data_dirs, data_files = clibs.traversal_files(path, w2t) params = initialization(path, hr, data_dirs, data_files, interval, curves, w2t) diff --git a/readme.md b/readme.md index 13c895e..47cab1b 100644 --- a/readme.md +++ b/readme.md @@ -1,41 +1,97 @@ # 珞石测试部自动化工具 +针对珞石工业协作六轴机器人的整机测试,该工具可以执行如下自动化操作,以减少人工处理时长,提高测试数据处理的效率和准确度: + +1. 制动数据,单轴数据处理 5min 以内 +2. 电机电流数据,全部轴数据处理 3min 以内 +3. ISO 激光数据整理,1min 以内 +4. wavelogger 波形处理,几乎不花费时间 +5. 制动自动化测试,40min 左右 +6. 电机电流自动化测试,15min 左右 +7. 耐久工程相关指标采集记录,可定制曲线并绘图 + ## 一、处理逻辑以及原理 +该部分简要介绍了工具实现的核心逻辑原理,以及执行的必要条件。 + ### 1. 数据处理 #### A. 制动数据 +- 原理:找到 `device_safety_estop` 曲线值由 1 -> 0 的位置,并预留 20 个数据余量截取 1000 个点 +- 必要条件: + - 根目录命名为 j1/2/3 + - 数据文件夹命名参照执行制动数据采集 + - 需要有三个结果文件,命名为 reach33/66/100_xxxxxxxx.xlsx + - 需要有一个机型文件,比如 NB4h-R580-3G.cfg,此文件会在执行制动测试的时候自动生成,注意保存 + #### B. 电机电流 +- 单轴原理:找到一个周期的起点和终点 +- 堵转原理:求平均均值 +- 场景原理:获取场景的执行周期时间,并做数据截取 +- 必要条件: + - 数据文件命名参照电机电流测试生成的格式 + - 需要有一个结果文件,命名为 T_电机电流.xlsx + - 需要有一个机型文件,比如 NB4h-R580-3G.cfg,此文件会在执行制动测试的时候自动生成,注意保存 + #### C. 激光 +- 原理:根据要获取的数据所在位置的特征,过滤提取 +- 必要条件: + - 数据文件命名必须参照如下: + - ISO-.pdf + - ISO-V100.pdf + - ISO-V1000.pdf + - 需要有一个结果文件,iso-results.xlsx + #### D. 基恩士数据 +- 原理:根据数据大小以及出现的周期规律,进行相应的处理,处理完成之后结果文件会自动生成 +- 必要条件:需要提前将 `.xdt` 波形数据转换成 `.csv` 文件,数据文件命名必须以 `.csv` 结尾 + ## 二、自动测试 ### 1. 协议封包解包 +详见 `assets/files/protocols/` + ### 2. 制动测试 +- 原理:使用 xCore socket 协议获取诊断数据,包括速度,力矩等信息,结合 modbus 和外部通信执行急停等动作 +- 必要条件: + - RL 工程,参考 `assets/files/projects/`,需要详细阅读对应的注释 + - 需要有一个配置文件,命名为 configs.xlsx + - 需要有三个结果文件,命名为 reach33/66/100_xxxxxxxx.xlsx + ### 3. 电机电流测试 +- 原理:使用 xCore socket 协议获取诊断数据,包括速度,力矩等信息,结合 modbus 和外部通信执行急停等动作 +- 必要条件: + - RL 工程,参考 `assets/files/projects/`,需要详细阅读对应的注释 + - 需要有一个结果文件,命名为 T_电机电流.xlsx + ## 三、注意事项 1. 仅适用于 xCore 2.3.0.7 及以上的版本 -2. 单轴电机电流数据处理,至少需要三个完整周期 -3. 执行制动测试/电机电流采集/耐久测试的时候,执行过程中停止,再次运行需要等待一分钟左右,输出框会有提示 -4. 其他使用方法和之前工具一致 +2. 仅适配了六轴工业/协作机型,其他机型可能会存在使用上的问题,具体可以找fanmingfu@rokae.com确认 +3. 单轴电机电流数据处理,至少需要三个完整周期,使用本工具采集一般不会有问题,主要是针对手动采集命名的数据 +4. 执行制动测试/电机电流采集/耐久测试的时候,执行过程中停止,再次运行需要等待一分钟左右,输出框会有提示 +5. RL工程/寄存器文件/configs.xlsx文件已更新,需要使用新版,其他使用方法和之前工具一致 +6. 基恩士采集数据时,不同轮次(每5次测试)数据时间间隔最好大于 2 倍的周期时间,否则会出现采集的轮数不正确的情况,但数据是完整的 +7. 激光数据处理只支持英文版本的数据文件 > **需要使用 assets/files/projects/ 下的工程,寄存器文件以及配置文件等!!!** ## 四、发版记录 +详见 `assets/files/version/release_change.txt` 文件 + ## 五、其他 ### 1. 打包命令 -打包时,只需要修改 clibs.py 中的 PREFIX 即可,调试时再修改回来 +打包时,只需要修改 clibs.py 中的 PREFIX 即可,调试时再修改回来,第三方库依赖详见 `assets/files/version/requirements.txt` 文件 ``` pyinstaller --noconfirm --onedir --windowed --optimize 2 --contents-directory . --upx-dir "D:/Syncthing/common/A_Program/upx-4.2.4-win64/" --add-data "../.venv/Lib/site-packages/customtkinter;customtkinter/" --add-data "../assets:assets" --version-file ../assets/files/version/file_version_info.txt -i ../assets/media/icon.ico ../code/aio.py -p ../code/common/clibs.py -p ../code/commom/openapi.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/automatic_test/do_current.py -p ../code/automatic_test/do_brake.py -p ../code/durable_docs/factory_test.py -p ../code/durable_docs/create_plot.py --exclude-module=scipy @@ -45,17 +101,20 @@ pyinstaller --noconfirm --onedir --windowed --optimize 2 --contents-directory . customtkinter的tabview组件不支持修改字体大小,解决方法可参考如下: -Method 1:可以参考 [Changing Font of a Tabview](https://github.com/TomSchimansky/CustomTkinter/issues/2296) 进行手动修改源码实现: +- Method 1:可以参考 [Changing Font of a Tabview](https://github.com/TomSchimansky/CustomTkinter/issues/2296) 进行手动修改源码实现: -a. 运行 `pip show customtkinter`,获取到库的路径 -b. 修改.../windows/widgets/ctk_tabview.py -c. 增加 from .font.ctk_font import CTkFont -d. 在大概 78 行的位置,增加 font=CTkFont(family="Consolas", size=18, weight='bold') + + 运行 `pip show customtkinter`,获取到库的路径 + + 修改.../windows/widgets/ctk_tabview.py + + 增加 from .font.ctk_font import CTkFont + + 在大概 78 行的位置,增加 font=CTkFont(family="Consolas", size=18, weight='bold') -Method 2: +- Method 2: -self.tabview_bottom._segmented_button.configure(font=ctk.CTkFont(family="Consolas", size=18, weight="bold")) + 直接在源码中修改:`self.tabview_bottom._segmented_button.configure(font=ctk.CTkFont(family="Consolas", size=18, weight="bold"))` ### 3. scroll frame 不支持修改高度和宽度 -https://github.com/TomSchimansky/CustomTkinter/pull/1765/files \ No newline at end of file +https://github.com/TomSchimansky/CustomTkinter/pull/1765/files + + +---