diff --git a/assets/files/projects/registers.json b/assets/files/projects/registers.json new file mode 100644 index 0000000..f4539a1 --- /dev/null +++ b/assets/files/projects/registers.json @@ -0,0 +1,592 @@ +{ + "MODBUS": [ + { + "property": { + "device_name": "autotest", + "endian": 1 + }, + "regs": { + "rd": [ + { + "addr": 40000, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_clear_alarm", + "len": 1, + "name": "r_clear_alarm", + "retain": false, + "type": "bool" + }, + { + "addr": 40001, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_estop_reset", + "len": 1, + "name": "r_estop_reset", + "retain": false, + "type": "bool" + }, + { + "addr": 40002, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_estop_reset_clear_alarm", + "len": 1, + "name": "r_onekey_reset", + "retain": false, + "type": "bool" + }, + { + "addr": 40003, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_motor_off", + "len": 1, + "name": "r_motor_off", + "retain": false, + "type": "bool" + }, + { + "addr": 40004, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_motor_on", + "len": 1, + "name": "r_motor_on", + "retain": false, + "type": "bool" + }, + { + "addr": 40005, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_motoron_pptomain_start", + "len": 1, + "name": "r_onekey_start", + "retain": false, + "type": "bool" + }, + { + "addr": 40006, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_motoron_start", + "len": 1, + "name": "r_motoron_start", + "retain": false, + "type": "bool" + }, + { + "addr": 40007, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_pause_motoroff", + "len": 1, + "name": "r_pause_motoroff", + "retain": false, + "type": "bool" + }, + { + "addr": 40008, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_pptomain", + "len": 1, + "name": "r_pp2main", + "retain": false, + "type": "bool" + }, + { + "addr": 40009, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_program_start", + "len": 1, + "name": "r_prog_start", + "retain": false, + "type": "bool" + }, + { + "addr": 40010, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_program_stop", + "len": 1, + "name": "r_prog_stop", + "retain": false, + "type": "bool" + }, + { + "addr": 40011, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_reduced_mode", + "len": 1, + "name": "r_reduced_mode", + "retain": false, + "type": "bool" + }, + { + "addr": 40012, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_soft_estop", + "len": 1, + "name": "r_soft_estop", + "retain": false, + "type": "bool" + }, + { + "addr": 40013, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_switch_auto_motoron", + "len": 1, + "name": "r_auto_motoron", + "retain": false, + "type": "bool" + }, + { + "addr": 40014, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_switch_operation_auto", + "len": 1, + "name": "r_switch_auto", + "retain": false, + "type": "bool" + }, + { + "addr": 40015, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "ctrl_switch_operation_manu", + "len": 1, + "name": "r_switch_manual", + "retain": false, + "type": "bool" + }, + { + "addr": 40016, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "enable_safe_region01", + "len": 1, + "name": "r_safe_region01", + "retain": false, + "type": "bool" + }, + { + "addr": 40017, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "enable_safe_region02", + "len": 1, + "name": "r_safe_region02", + "retain": false, + "type": "bool" + }, + { + "addr": 40018, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "enable_safe_region03", + "len": 1, + "name": "r_safe_region03", + "retain": false, + "type": "bool" + }, + { + "addr": 40100, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "", + "len": 1, + "name": "signal_0", + "retain": false, + "type": "bool" + }, + { + "addr": 40101, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "", + "len": 1, + "name": "signal_1", + "retain": false, + "type": "bool" + }, + { + "addr": 40102, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "", + "len": 1, + "name": "signal_2", + "retain": false, + "type": "bool" + }, + { + "addr": 40103, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "", + "len": 1, + "name": "signal_3", + "retain": false, + "type": "bool" + }, + { + "addr": 40104, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "", + "len": 1, + "name": "signal_4", + "retain": false, + "type": "bool" + }, + { + "addr": 40105, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "", + "len": 1, + "name": "signal_5", + "retain": false, + "type": "bool" + }, + { + "addr": 40106, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "", + "len": 1, + "name": "signal_6", + "retain": false, + "type": "bool" + }, + { + "addr": 40107, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "", + "len": 1, + "name": "signal_7", + "retain": false, + "type": "bool" + }, + { + "addr": 40108, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "", + "len": 1, + "name": "signal_8", + "retain": false, + "type": "bool" + }, + { + "addr": 40109, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "", + "len": 1, + "name": "signal_9", + "retain": false, + "type": "bool" + } + ], + "rdwr": [ + { + "addr": 40500, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_alarm", + "len": 1, + "name": "w_alarm_state", + "retain": false, + "type": "bool" + }, + { + "addr": 40501, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_collision", + "len": 1, + "name": "w_clsn_alarm_stat", + "retain": false, + "type": "bool" + }, + { + "addr": 40502, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_collision_open", + "len": 1, + "name": "w_clsn_open_stat", + "retain": false, + "type": "bool" + }, + { + "addr": 40503, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_controller_is_running", + "len": 1, + "name": "w_controller_running", + "retain": false, + "type": "bool" + }, + { + "addr": 40504, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_encoder_low_battery", + "len": 1, + "name": "w_encoder_low", + "retain": false, + "type": "bool" + }, + { + "addr": 40505, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_estop", + "len": 1, + "name": "w_estop_stat", + "retain": false, + "type": "bool" + }, + { + "addr": 40506, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_motor", + "len": 1, + "name": "w_motor_stat", + "retain": false, + "type": "bool" + }, + { + "addr": 40507, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_operation_mode", + "len": 1, + "name": "w_operation_mode", + "retain": false, + "type": "bool" + }, + { + "addr": 40508, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_program", + "len": 1, + "name": "w_prog_stat", + "retain": false, + "type": "bool" + }, + { + "addr": 40509, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_program_not_run", + "len": 1, + "name": "w_prog_not_run", + "retain": false, + "type": "bool" + }, + { + "addr": 40510, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_program_reset", + "len": 1, + "name": "w_prog_reset", + "retain": false, + "type": "bool" + }, + { + "addr": 40511, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_reduced_mode", + "len": 1, + "name": "w_reduced_mode_stat", + "retain": false, + "type": "bool" + }, + { + "addr": 40512, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_robot_is_busy", + "len": 1, + "name": "w_robot_is_busy", + "retain": false, + "type": "bool" + }, + { + "addr": 40513, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_robot_moving", + "len": 1, + "name": "w_robot_moving", + "retain": false, + "type": "bool" + }, + { + "addr": 40514, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_safe_door", + "len": 1, + "name": "w_safe_door", + "retain": false, + "type": "bool" + }, + { + "addr": 40515, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_safe_region01", + "len": 1, + "name": "w_safe_region01", + "retain": false, + "type": "bool" + }, + { + "addr": 40516, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_safe_region02", + "len": 1, + "name": "w_safe_region02", + "retain": false, + "type": "bool" + }, + { + "addr": 40517, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_safe_region03", + "len": 1, + "name": "w_safe_region03", + "retain": false, + "type": "bool" + }, + { + "addr": 40518, + "addr_1st": 0, + "addr_2nd": 0, + "bit_bias": 0, + "byte_bias": 0, + "function": "sta_soft_estop", + "len": 1, + "name": "w_soft_estop_stat", + "retain": false, + "type": "bool" + } + ] + } + } + ] +} diff --git a/assets/files/projects/registers.xml b/assets/files/projects/registers.xml new file mode 100644 index 0000000..4d079df --- /dev/null +++ b/assets/files/projects/registers.xml @@ -0,0 +1,915 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/files/protocols/原理/协议原理.xlsx b/assets/files/protocols/原理/协议原理.xlsx new file mode 100644 index 0000000..7f1dcbb Binary files /dev/null and b/assets/files/protocols/原理/协议原理.xlsx differ diff --git a/assets/files/protocols/原理/解包示例.txt b/assets/files/protocols/原理/解包示例.txt new file mode 100644 index 0000000..17029a8 --- /dev/null +++ b/assets/files/protocols/原理/解包示例.txt @@ -0,0 +1,56 @@ +b'\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340\x01o429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17\n\t\t\t]\n\t\t}\n\t],\n\t"module" : "robot"\n}\x04\x00\x00\x00-h\x02\x00{\n\t"command" : "diagnosis.result",\n\t"data" : \n\t[\n\t\t{\n\t\t\t"channel" : 0,\n\t\t\t"name" : "hw_joint_vel_feedback",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0' +b'.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 1,\n\t\t\t"name" : "hw_joint_vel_feedback",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t6.7411265092630715e-06,\n\t\t\t\t0.00049929277011941824,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0027270103772138884,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t0.00012044146029883355,\n\t\t\t\t-0.0022272681986605192,\n\t\t\t\t-0.0027270103772138884,\n\t\t\t\t0.0020686270214758614,\n\t\t\t\t-0.0027270103772138884,\n\t\t\t\t0.0020686270214758614,\n\t\t\t\t1.3482253018526145e-06,\n\t\t\t\t-0.002697798\x04\x008290070812,\n\t\t\t\t0.00050648330506263212,\n\t\t\t\t-0.0,\n\t\t\t\t0.0020753681479851243,\n\t\t\t\t2.8762139772855775e-05,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t3.5952674716069715e-05,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t0.0001496530085056402,\n\t\t\t\t0.0001276319952420475,\n\t\t\t\t-0.0027252127434780845,\n\t\t\t\t6.7411265092630715e-06,\n\t\t\t\t-0.0026977988290070812,\n\t\t\t\t8.5387602450665581e-06,\n\t\t\t\t0.0020686270214758614,\n\t\t\t\t0.00206862702147' +b'58614,\n\t\t\t\t-0.0,\n\t\t\t\t7.1905349432139438e-06,\n\t\t\t\t1.3482253018526145e-06,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t2.8762139772855775e-05,\n\t\t\t\t-0.0,\n\t\t\t\t6.7411265092630715e-06,\n\t\t\t\t-0.0,\n\t\t\t\t0.00049929277011941824,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 2,\n\t\t\t"name" : "hw_joint_vel_feedback",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t1.1984224905356572e-06,\n\t\t\t\t0.00010705907582118537,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0024236097500266104,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0024240092241901226,\n\t\t\x04\x00\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t0.0018387795746452099,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t0.00010705907582118537,\n\t\t\t\t-0.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 3,\n\t\t\t"name" : "hw_joint_vel_feedback",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t' +b'-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.00021840051467521813,\n\t\t\t\t-0.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 4,\n\t\t\t"name" : "hw_joint_vel_feedback",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t-0.0,\n\t\t\t\t-0.0\x04\x00,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n' +b'\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 5,\n\t\t\t"name" : "hw_joint_vel_feedback",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-\x04\x000.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 0,\n\t\t\t"name" : "device_servo_trq_feedback",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t' +b'\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 1,\n\t\t\t"name" : "device_servo_trq_feedback",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0\x04\x00.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 2,\n\t\t\t"name" : "device_servo_trq_feedback",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.' +b'0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 3,\n\t\t\t"name" : "device_servo_trq_feedback",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\x04\x00\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 4,\n\t\t\t"name" : "device_servo_trq_feedback",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n' +b'\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 5,\n\t\t\t"name" : "device_servo_trq_feedback",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.\x04\x000,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 0,\n\t\t\t"name" : "device_safety_estop",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n' +b'\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 1,\n\t\t\t"name" : "device_safety_estop",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1\x04\x00.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 2,\n\t\t\t"name" : "device_safety_estop",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.' +b'0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 3,\n\t\t\t"name" : "device_safety_estop",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t\x04\x001.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0,\n\t\t\t\t1.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 4,\n\t\t\t"name" : "device_safety_estop",\n\t\t\t"value" : ' +b'\n\t\t\t[\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 5,\n\t\t\t"name" : "device_safety_estop",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5\x04\x00.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429' +b'065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.55163404\x01n29065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17\n\t\t\t]\n\t\t}\n\t],\n\t"module" : "robot"\n}\x04\x00\x00\x00-\x8f\x02\x00{\n\t"command"' + + + +> - 封包解包顺序:帧长度二字节/包长度四字节/协议二字节/预留二字节,\x04\x00:\x00\x00\tR:\x02:\x00 +> - 帧长度和包长度没有必然关系,单帧的时候是帧长度减去包长度等于6,包长度指的是所有内容的长度 +> - HMI内部每次发送1024个字节,进行分包,有效内容长度规则是:第一帧 frm_value-6(帧大小减去包头长度),第二帧(包含)及之后的帧,帧大小即是数据长度 + + +================================================================================================== +单包多帧示例 +\x04\x00\x00\x00-h\x02\x00 +frm_value = int.from_bytes(b"\x04\x00") = 1024 | 每次发送的帧的报文总长度,包括包头(如果有),但不包括帧头 +pkg_value = int.from_bytes(b"\x00\x00-h") = 11624 | 包长度是不包括所有的帧和包报文头的,单包单帧的情况也是一样的 +pkg_size = 6 字节 +有效数据长度 = 10240 + 402 + 1004 - 20 - 2(首个帧头) = 11624 +有效数据长度+包报文头 = 11624 + 6 = 11630 +有效数据长度+包报文头+帧报文头 = 11624 + 6 + 22 = 11652 +首帧长度 1018=frm_value-pkg_size=1024-6:如下是第一帧和第二帧的拼接 +b'{\n\t"command" : "diagnosis.result",\n\t"data" : \n\t[\n\t\t{\n\t\t\t"channel" : 0,\n\t\t\t"name" : "hw_joint_vel_feedback",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 1,\n\t\t\t"name" : "hw_joint_vel_feedback",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t6.7411265092630715e-06,\n\t\t\t\t0.00049929277011941824,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0027270103772138884,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t0.00012044146029883355,\n\t\t\t\t-0.0022272681986605192,\n\t\t\t\t-0.0027270103772138884,\n\t\t\t\t0.0020686270214758614,\n\t\t\t\t-0.0027270103772138884,\n\t\t\t\t0.0020686270214758614,\n\t\t\t\t1.3482253018526145e-06,\n\t\t\t\t-0.002697798' +单帧长度 1024:如下是第二帧和第三帧的拼接 +b'8290070812,\n\t\t\t\t0.00050648330506263212,\n\t\t\t\t-0.0,\n\t\t\t\t0.0020753681479851243,\n\t\t\t\t2.8762139772855775e-05,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t3.5952674716069715e-05,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t0.0001496530085056402,\n\t\t\t\t0.0001276319952420475,\n\t\t\t\t-0.0027252127434780845,\n\t\t\t\t6.7411265092630715e-06,\n\t\t\t\t-0.0026977988290070812,\n\t\t\t\t8.5387602450665581e-06,\n\t\t\t\t0.0020686270214758614,\n\t\t\t\t0.0020686270214758614,\n\t\t\t\t-0.0,\n\t\t\t\t7.1905349432139438e-06,\n\t\t\t\t1.3482253018526145e-06,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t2.8762139772855775e-05,\n\t\t\t\t-0.0,\n\t\t\t\t6.7411265092630715e-06,\n\t\t\t\t-0.0,\n\t\t\t\t0.00049929277011941824,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 2,\n\t\t\t"name" : "hw_joint_vel_feedback",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t1.1984224905356572e-06,\n\t\t\t\t0.00010705907582118537,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0024236097500266104,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0024240092241901226,\n\t\t' + +--------------------------------------------------------------------------------------------------- +第一帧有效 - 402 +b'{\n\t"command" : "diagnosis.result",\n\t"data" : \n\t[\n\t\t{\n\t\t\t"channel" : 0,\n\t\t\t"name" : "hw_joint_vel_feedback",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0.0,\n\t\t\t\t0' +--------------------------------------------------------------------------------------------------- +中间有 10 帧,共计 10240 个字节,也有 10 个 \x04\x00,共计 20 个字节 +--------------------------------------------------------------------------------------------------- +最后一帧有效 - 1004 +b'065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.55163404\x01n29065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17,\n\t\t\t\t-5.5516340429065717e-17\n\t\t\t]\n\t\t}\n\t],\n\t"module" : "robot"\n}' +--------------------------------------------------------------------------------------------------- + +================================================================================================== +单包单帧示例 +\x00\\\x00\x00\x00V\x02\x00 +frm_value = int.from_bytes(b"\x00\\") = 92 | 每次发送的帧的报文总长度,包括包头(如果有),但不包括帧头 +pkg_value = int.from_bytes(b"\x00\x00\x00V") = 86 | 包长度是不包括所有的帧和包报文头的,单包单帧的情况也是一样的 +pkg_size = 6 +有效数据长度 = 86 +有效数据长度+包报文头 = 86 + 6 = 92 +有效数据长度+包报文头+帧报文头 = 86 + 6 +2 = 94 +帧长度 86=frm_value-pkg_size=92-6 + +b'\x00\\\x00\x00\x00V\x02\x00{\n\t"data" : \n\t{\n\t\t"name" : "xCore"\n\t},\n\t"id" : "controller.heart-1719734550.9790015"\n}' diff --git a/code/aio.py b/code/aio.py index 6c63df6..b798d71 100644 --- a/code/aio.py +++ b/code/aio.py @@ -13,7 +13,7 @@ import webbrowser import sqlite3 from datetime import datetime import os -from common import clibs +from common import clibs, openapi from data_process import current, brake, iso, wavelogger import threading import re @@ -76,14 +76,15 @@ class App: self.om_sub_at = ctk.CTkOptionMenu(self.tabview_top.tab("自动测试"), width=160, dynamic_resizing=False, values=["tool33", "tool66", "tool100", "inertia"], font=self.f_common, text_color="#3C3C3C", button_color="#7B6B5B", fg_color="#8D8D8D") self.label_ip_at = ctk.CTkLabel(self.tabview_top.tab("自动测试"), anchor="e", text="IP", font=self.f_common) self.entry_ip_at = ctk.CTkEntry(self.tabview_top.tab("自动测试"), width=160, textvariable=self.entry_ip_atv, font=self.f_entry, text_color="#818181") - self.btn_conn = ctk.CTkButton(self.tabview_top.tab("自动测试"), text="连接", width=60, font=self.f_segbtn, fg_color="#979DA2", corner_radius=0) + self.btn_conn = ctk.CTkButton(self.tabview_top.tab("自动测试"), text="连接", width=60, font=self.f_segbtn, fg_color="#979DA2", corner_radius=0, command=lambda: self.__thread_it(self.__conn_xcore)) self.progressbar_at = ctk.CTkProgressBar(self.tabview_top.tab("自动测试"), width=160, mode="indeterminate") self.label_path_at = ctk.CTkLabel(self.tabview_top.tab("自动测试"), width=50, anchor="e", text="Path", font=self.f_common) self.entry_path_at = ctk.CTkEntry(self.tabview_top.tab("自动测试"), width=80, state="disabled", textvariable=self.entry_path_atv, font=self.f_entry, text_color="#818181") self.frame_top = ctk.CTkFrame(self.tabview_top.tab("自动测试"), width=120, height=10, fg_color="#E9E9E9") - self.btn_trig_estop = ctk.CTkButton(self.frame_top, width=100, text="触发急停", font=self.f_segbtn, fg_color="#979DA2", corner_radius=0, command=print) - self.btn_reset_estop = ctk.CTkButton(self.frame_top, width=100, text="恢复急停", font=self.f_segbtn, fg_color="#979DA2", corner_radius=0, command=print) self.btn_robot_state = ctk.CTkButton(self.frame_top, width=100, text="机器信息", font=self.f_segbtn, fg_color="#979DA2", corner_radius=0, command=self.__robot_info) + self.btn_robot_init = ctk.CTkButton(self.frame_top, width=100, text="初始操作", font=self.f_segbtn, fg_color="#979DA2", corner_radius=0, command=self.__robot_init) + self.btn_trig_estop = ctk.CTkButton(self.frame_top, width=100, text="触发急停", font=self.f_segbtn, fg_color="#979DA2", corner_radius=0, command=self.__trig_estop) + self.btn_reset_estop = ctk.CTkButton(self.frame_top, width=100, text="恢复急停", font=self.f_segbtn, fg_color="#979DA2", corner_radius=0, command=self.__reset_estop) self.popupmenu_ip = tk.Menu(self.entry_ip_at, tearoff=False) self.popupmenu_ip.add_command(label="复制", accelerator="Ctrl+C", font=self.f_treeview, command=lambda: self.__copy(self.entry_ip_at)) self.popupmenu_ip.add_command(label="剪切", accelerator="Ctrl+X", font=self.f_treeview, command=lambda: self.__cut(self.entry_ip_at)) @@ -130,15 +131,57 @@ class App: # ======================================================================== self.__draw() - clibs.insert_logdb("INFO", "aio", "AIO starts running......") + + def detect_network(self): + while True: + try: + if clibs.c_hr.status: + self.btn_conn.configure(fg_color="#2E8B57") + else: + self.btn_conn.configure(fg_color="#979DA2") + except Exception as Err: + self.btn_conn.configure(fg_color="#979DA2") + time.sleep(2) + + def __conn_xcore(self): + if self.btn_conn.cget("fg_color") == "#979DA2": + try: + if clibs.c_hr.status: + self.btn_conn.configure(fg_color="#2E8B57") + return + except Exception as Err: + ... + + clibs.ip_addr = self.entry_ip_atv.get().strip() + ip_pattern = re.compile(r'(([1-9]?\d|1\d\d|2[0-4]\d|25[0-5])\.){3}([1-9]?\d|1\d\d|2[0-4]\d|25[0-5])') + if not ip_pattern.fullmatch(clibs.ip_addr): + messagebox.showerror(title="非法地址", message=f"{clibs.ip_addr} 不是一个有效的 IP 地址") + clibs.insert_logdb("ERROR", "aio", f"connection: {clibs.ip_addr} 不是一个有效的 IP 地址") + return + # clibs.c_md = openapi.ModbusRequest(clibs.ip_addr, clibs.modbus_port) + clibs.c_hr = openapi.HmiRequest(clibs.ip_addr, clibs.socket_port, clibs.xService_port) + else: + try: + # clibs.c_md.close() + clibs.c_hr.close() + except Exception as Err: + ... + self.btn_conn.configure(fg_color="#979DA2") def __robot_info(self): - clibs.cursor.execute("select * from logs") - records = clibs.cursor.fetchall() - self.text_output.insert(ctk.END, records) + ... + + def __robot_init(self): + ... + + def __trig_estop(self): + ... + + def __reset_estop(self): + ... def __thread_it(self, func, *args): - """ 将函数打包进线程 """ + """ 将函数打包进线程,必须使用 lambda """ self.myThread = threading.Thread(target=func, args=args) self.myThread.daemon = True # 主线程退出就直接让子线程跟随退出,不论是否运行完成。 self.myThread.start() @@ -208,7 +251,6 @@ class App: return data def init_op(): - clibs.w2t = self.__w2t self.text_output.delete("1.0", ctk.END) self.tabview_bottom.set("输出") if clibs.db_state != "readwrite": @@ -241,6 +283,7 @@ class App: exec_function() + @clibs.db_lock def __reset_state(self): def reset_methods(): self.btn_load.configure(fg_color="#979DA2") @@ -272,8 +315,9 @@ class App: reset_methods() # TBD: something signifies status of program and terminate some thread ect. + @clibs.db_lock def __get_realtime_log(self): - clibs.cursor.execute("select * from logs order by id desc") + clibs.cursor.execute("select id from logs") len_records = len(clibs.cursor.fetchall()) pages_all = len_records // 100 if len_records % 100 == 0 else len_records // 100 + 1 self.label_pages_logs.set(f"{pages_all} / {pages_all}") @@ -292,6 +336,7 @@ class App: self.__reset_entry_keyword() + @clibs.db_lock def __get_previous_log(self): if self.btn_find.cget("fg_color") == "#979DA2": try: @@ -334,47 +379,56 @@ class App: self.label_pages_logs.set(f"{previous_page} / {pages_all}") def __get_next_log(self): - if self.btn_find.cget("fg_color") == "#979DA2": - try: - clibs.cursor.execute("select * from logs order by id desc") - len_records = len(clibs.cursor.fetchall()) + @clibs.db_lock + def get_next_page(): + if self.btn_find.cget("fg_color") == "#979DA2": + try: + clibs.cursor.execute("select id from logs") + len_records = len(clibs.cursor.fetchall()) - row = self.treeview_logs.get_children() - last_id = self.treeview_logs.item(row[-1], "values")[0] - start = int(last_id) + 1 - end = int(last_id) + 100 - if int(start) <= len_records: - clibs.cursor.execute(f"select * from logs where id between {start} and {end}") - records = clibs.cursor.fetchall() + row = self.treeview_logs.get_children() + last_id = self.treeview_logs.item(row[-1], "values")[0] + start = int(last_id) + 1 + end = int(last_id) + 100 + if int(start) <= len_records: + clibs.cursor.execute(f"select * from logs where id between {start} and {end}") + records = clibs.cursor.fetchall() + self.treeview_logs.delete(*self.treeview_logs.get_children()) + for record in records: + self.treeview_logs.insert("", "end", values=record, tags=record[2]) + # self.treeview_logs.yview_moveto(1) + + pages_all = len_records // 100 if len_records % 100 == 0 else len_records // 100 + 1 + current_page = int(start) // 100 if int(start) % 100 == 0 else int(start) // 100 + 1 + self.label_pages_logs.set(f"{current_page} / {pages_all}") + except Exception as ERR: + ... + else: + len_records = len(clibs.f_records) + pages_all = int(self.label_pages_logs.get().split("/")[1].strip()) + current_page = int(self.label_pages_logs.get().split("/")[0].strip()) + if current_page < pages_all: + row = self.treeview_logs.get_children() + last_one = list(self.treeview_logs.item(row[-1], "values")) + last_one[0] = int(last_one[0]) + index_start = clibs.f_records.index(tuple(last_one))+1 self.treeview_logs.delete(*self.treeview_logs.get_children()) - for record in records: - self.treeview_logs.insert("", "end", values=record, tags=record[2]) - # self.treeview_logs.yview_moveto(1) + if index_start+100 <= len_records: + for record in clibs.f_records[index_start:index_start+100]: + self.treeview_logs.insert("", "end", values=record, tags=record[2]) + else: + for record in clibs.f_records[index_start:]: + self.treeview_logs.insert("", "end", values=record, tags=record[2]) - pages_all = len_records // 100 if len_records % 100 == 0 else len_records // 100 + 1 - current_page = int(start) // 100 if int(start) % 100 == 0 else int(start) // 100 + 1 - self.label_pages_logs.set(f"{current_page} / {pages_all}") - except Exception as ERR: - ... - else: - len_records = len(clibs.f_records) - pages_all = int(self.label_pages_logs.get().split("/")[1].strip()) - current_page = int(self.label_pages_logs.get().split("/")[0].strip()) - if current_page < pages_all: - row = self.treeview_logs.get_children() - last_one = list(self.treeview_logs.item(row[-1], "values")) - last_one[0] = int(last_one[0]) - index_start = clibs.f_records.index(tuple(last_one))+1 - self.treeview_logs.delete(*self.treeview_logs.get_children()) - if index_start+100 <= len_records: - for record in clibs.f_records[index_start:index_start+100]: - self.treeview_logs.insert("", "end", values=record, tags=record[2]) - else: - for record in clibs.f_records[index_start:]: - self.treeview_logs.insert("", "end", values=record, tags=record[2]) + next_page = current_page + 1 + self.label_pages_logs.set(f"{next_page} / {pages_all}") - next_page = current_page + 1 - self.label_pages_logs.set(f"{next_page} / {pages_all}") + current_page = int(self.label_pages_logs.get().split("/")[0].strip()) + pages_all = int(self.label_pages_logs.get().split("/")[1].strip()) + if current_page == pages_all: + self.__get_realtime_log() + return + get_next_page() def __load_log_db(self): db_file = filedialog.askopenfilename(title="加载数据库文件", defaultextension=".db", initialdir=f"{clibs.PREFIX}/logs") @@ -589,13 +643,14 @@ class App: except Exception as ERR: ... + @clibs.db_lock def jump2page(): try: number = int(self.entry_tips_v) if number > 0: start = number * 100 - 99 end = number * 100 - clibs.cursor.execute("select * from logs order by id desc") + clibs.cursor.execute("select id from logs") len_records = len(clibs.cursor.fetchall()) if start <= len_records: clibs.cursor.execute(f"select * from logs where id between {start} and {end}") @@ -649,6 +704,7 @@ class App: label_tips.grid(row=0, column=0, padx=10, pady=10, sticky="w") entry_tips.grid(row=0, column=1, padx=(0, 10), pady=10, sticky="w") + @clibs.db_lock def find_log(event): def find_error(cdt): clibs.insert_logdb("WARNING", "aio", f"查询条件 [{cdt}] 书写规则错误!") @@ -863,8 +919,9 @@ class App: self.entry_path_at.grid(row=1, column=2, columnspan=3, padx=(0, 10), pady=(0, 10), sticky="we") self.frame_top.grid(row=2, column=0, columnspan=5, padx=0, pady=0, sticky="we") self.btn_robot_state.grid(row=0, column=0, padx=10, pady=0) - self.btn_trig_estop.grid(row=0, column=1, padx=(0, 10), pady=0) - self.btn_reset_estop.grid(row=0, column=2, padx=(0, 10), pady=0) + self.btn_robot_init.grid(row=0, column=1, padx=(0, 10), pady=0) + self.btn_trig_estop.grid(row=0, column=2, padx=(0, 10), pady=0) + self.btn_reset_estop.grid(row=0, column=3, padx=(0, 10), pady=0) self.progressbar_at.start() self.progressbar_at.configure(progress_color="red", fg_color="gray") @@ -913,9 +970,15 @@ class App: self.om_sub_dp.configure(state="disabled") self.om_trqh_dp.configure(state="disabled") self.om_sensor_dp.configure(state="disabled") + # ======================================================================== + clibs.w2t = self.__w2t + clibs.insert_logdb("INFO", "aio", "AIO starts running......") def show(self): if self.server_vers: + t = threading.Thread(target=self.detect_network) + t.daemon = True + t.start() self.root.mainloop() diff --git a/code/common/clibs.py b/code/common/clibs.py index fcbda23..00c19bc 100644 --- a/code/common/clibs.py +++ b/code/common/clibs.py @@ -2,16 +2,17 @@ import os import os.path import sqlite3 import threading +import json -def traversal_files(path, w2t): +def traversal_files(_path, _w2t): # 功能:以列表的形式分别返回指定路径下的文件和文件夹,不包含子目录 # 参数:路径 # 返回值:路径下的文件夹列表 路径下的文件列表 - if not os.path.exists(path): - w2t(f"数据文件夹{path}不存在,请确认后重试......", "red", "PathNotExistError") + if not os.path.exists(_path): + _w2t(f"数据文件夹{_path}不存在,请确认后重试......", "red", "PathNotExistError") else: dirs, files = [], [] - for item in os.scandir(path): + for item in os.scandir(_path): if item.is_dir(): dirs.append(item.path.replace("\\", "/")) elif item.is_file(): @@ -20,13 +21,17 @@ def traversal_files(path, w2t): return dirs, files -def init_logdb(connect, cur): - connect = sqlite3.connect(":memory:", isolation_level=None, check_same_thread=False, cached_statements=256) +def init_logdb(conn, cursor): + conn = sqlite3.connect(":memory:", isolation_level=None, check_same_thread=False, cached_statements=4096) # connect = sqlite3.connect("log.db", isolation_level=None, check_same_thread=False, cached_statements=256) # time text default (datetime('now', 'localtime')), - - cur = connect.cursor() - cur.execute( + cursor = conn.cursor() + cursor.execute("PRAGMA journal_mode=wal") + cursor.execute("PRAGMA wal_checkpoint=TRUNCATE") + cursor.execute("PRAGMA synchronous=normal") + cursor.execute("PRAGMA temp_store=memory") + cursor.execute("PRAGMA mmap_size=30000000000") + cursor.execute( """ create table if not exists logs( id integer primary key autoincrement, @@ -37,16 +42,41 @@ def init_logdb(connect, cur): ) """ ) - return connect, cur + return conn, cursor +def db_lock(func): + def wrapper(*args, **kwargs): + try: + lock.acquire(True) + ret = func(*args, **kwargs) + finally: + lock.release() + return ret + return wrapper + + +@db_lock def insert_logdb(_level, _module, _content): if db_state == "readwrite": - global conn, cursor + global conn, cursor, lock data = [_level, _module, repr(_content)] cursor.execute("insert into logs (level, module, content) values (?, ?, ?)", data) + +def insert_logdb_multi(data): + if db_state == "readwrite": + global conn, cursor, lock + # data = [_level, _module, repr(_content)] + # cursor.execute("insert into logs (level, module, content) values (?, ?, ?)", data) + try: + lock.acquire(True) + cursor.executemany("insert into logs (level, module, content) values (?, ?, ?)", data) + finally: + lock.release() + + class GetThreadResult(threading.Thread): def __init__(self, func, args=()): super(GetThreadResult, self).__init__() @@ -79,15 +109,39 @@ running = False stop = True tl_prg = None f_records = None + +ip_addr = "192.168.0.160" +ssh_port = 22 +socket_port = 5050 +xService_port = 6666 +external_port = 8080 +modbus_port = 502 +upgrade_port = 4567 +username = "luoshi" +password = "luoshi2019" # for real robot +# password = "forpqart" # for robot vm +interval = 0.5 # interval after actions being triggered, such as modbus/socket/external communication operations +RADIAN = 57.3 # 180 / 3.1415926 +MAX_FRAME_SIZE = 1024 +c_md = None +c_hr = None +c_ec = None +c_pd = None +lock = threading.Lock() + conn, cursor = init_logdb(conn, cursor) -for i in range(100): - insert_logdb("DEBUG", "clibs", 'this is a DEBUG log -0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.00021840051467521813,\n\t\t\t\t-0.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 4,\n\t\t\t"name" : "hw_joint_vel_feedback",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t-0.0,\n\t\t\t\t-0.0\x04\x00,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n') - insert_logdb("INFO", "clibs", 'this is a INFO log -0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.00021840051467521813,\n\t\t\t\t-0.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 4,\n\t\t\t"name" : "hw_joint_vel_feedback",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t-0.0,\n\t\t\t\t-0.0\x04\x00,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n') - insert_logdb("WARNING", "clibs", 'this is a WARNING log -0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.00021840051467521813,\n\t\t\t\t-0.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 4,\n\t\t\t"name" : "hw_joint_vel_feedback",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t-0.0,\n\t\t\t\t-0.0\x04\x00,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n') - insert_logdb("ERROR", "clibs", 'this is a ERROR log -0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.00021840051467521813,\n\t\t\t\t-0.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 4,\n\t\t\t"name" : "hw_joint_vel_feedback",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t-0.0,\n\t\t\t\t-0.0\x04\x00,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n') - -insert_logdb("DEBUG", "clibs", 'running') -insert_logdb("INFO", "clibs", 'running') -insert_logdb("WARNING", "clibs", 'running') -insert_logdb("ERROR", "clibs", 'running') +# for i in range(100): +# insert_logdb("DEBUG", "clibs", 'this is a DEBUG log -0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.00021840051467521813,\n\t\t\t\t-0.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 4,\n\t\t\t"name" : "hw_joint_vel_feedback",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t-0.0,\n\t\t\t\t-0.0\x04\x00,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n') +# insert_logdb("INFO", "clibs", 'this is a INFO log -0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.00021840051467521813,\n\t\t\t\t-0.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 4,\n\t\t\t"name" : "hw_joint_vel_feedback",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t-0.0,\n\t\t\t\t-0.0\x04\x00,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n') +# insert_logdb("WARNING", "clibs", 'this is a WARNING log -0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.00021840051467521813,\n\t\t\t\t-0.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 4,\n\t\t\t"name" : "hw_joint_vel_feedback",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t-0.0,\n\t\t\t\t-0.0\x04\x00,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n') +# insert_logdb("ERROR", "clibs", 'this is a ERROR log -0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.00021840051467521813,\n\t\t\t\t-0.0\n\t\t\t]\n\t\t},\n\t\t{\n\t\t\t"channel" : 4,\n\t\t\t"name" : "hw_joint_vel_feedback",\n\t\t\t"value" : \n\t\t\t[\n\t\t\t\t-0.0,\n\t\t\t\t-0.0\x04\x00,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n\t\t\t\t-0.0,\n') +# +# insert_logdb("DEBUG", "clibs", 'running') +# insert_logdb("INFO", "clibs", 'running') +# insert_logdb("WARNING", "clibs", 'running') +# insert_logdb("ERROR", "clibs", 'running') +with open(f"{log_path}/response.txt", mode="w", encoding="utf-8") as f_res: + f_res.write("") +with open(f"{log_path}/logs.txt", mode="w", encoding="utf-8") as f_res: + f_res.write("") \ No newline at end of file diff --git a/code/common/openapi.py b/code/common/openapi.py new file mode 100644 index 0000000..486f09c --- /dev/null +++ b/code/common/openapi.py @@ -0,0 +1,2467 @@ +import json +import socket +import inspect +from inspect import currentframe +import threading +import functools +from paramiko import SSHClient, AutoAddPolicy +from pymodbus.client.tcp import ModbusTcpClient +import selectors +import time +from common import clibs + +from os import listdir +from threading import Thread +# from pymodbus.payload import BinaryPayloadDecoder, BinaryPayloadBuilder +# from pymodbus.constants import Endian +import os.path +from ctypes import * +import hashlib +import struct + + +class ModbusRequest(object): + def __init__(self, ip, port): + self.__c = ModbusTcpClient(host=ip, port=port) + if self.__c.connect(): + clibs.insert_logdb("INFO", "openapi", f"Modbus connection({clibs.ip_addr}:{clibs.modbus_port}) success...") + else: + clibs.insert_logdb("ERROR", "openapi", f"Modbus connection({clibs.ip_addr}:{clibs.modbus_port}) failed...") + clibs.w2t(f"Modbus connection({clibs.ip_addr}:{clibs.modbus_port}) failed...\n", "red", "ModbusConnError") + + def close(self): + try: + self.__c.close() + except Exception as Err: + ... + + def __reg_high_pulse(self, addr: int) -> None: + self.__c.write_register(addr, 0) + time.sleep(clibs.interval) + self.__c.write_register(addr, 1) + time.sleep(clibs.interval+1) + self.__c.write_register(addr, 0) + + def r_clear_alarm(self): # OK + self.__reg_high_pulse(40000) + clibs.insert_logdb("INFO", "openapi", "modbus: 40000-010 执行清除告警信息") + + def r_reset_estop(self): # OK + self.__reg_high_pulse(40001) + clibs.insert_logdb("INFO", "openapi", "modbus: 40001-010 执行复位急停状态(非软急停)") + + def r_reset_estop_clear_alarm(self): # OK + self.__reg_high_pulse(40002) + clibs.insert_logdb("INFO", "openapi", "modbus: 40002-010 执行复位急停状态(非软急停),并清除告警信息") + + def r_motor_off(self): # OK + self.__reg_high_pulse(40003) + clibs.insert_logdb("INFO", "openapi", "modbus: 40003-010 执行机器人下电") + + def r_motor_on(self): # OK + self.__reg_high_pulse(40004) + clibs.insert_logdb("INFO", "openapi", "modbus: 40004-010 执行机器人上电") + + def r_motoron_pp2main_start(self): # OK + self.__reg_high_pulse(40005) + clibs.insert_logdb("INFO", "openapi", "modbus: 40005-010 执行机器人上电/pp2main/开始运行程序,需自动模式执行,若运行失败,可清除告警后再次尝试") + + def r_motoron_start(self): # OK + self.__reg_high_pulse(40006) + clibs.insert_logdb("INFO", "openapi", "modbus: 40006-010 执行机器人上电/开始运行程序,需自动模式执行,若运行失败,可清除告警、执行pp2main后再次尝试") + + def r_pulse_motoroff(self): # OK + self.__reg_high_pulse(40007) + clibs.insert_logdb("INFO", "openapi", "modbus: 40007-010 执行机器人停止,并下电,手动模式下可停止程序运行,但不能下电,若运行失败,可清除告警后再次尝试") + + def r_pp2main(self): # OK + self.__reg_high_pulse(40008) + clibs.insert_logdb("INFO", "openapi", "modbus: 40008-010 执行机器人 pp2main,需自动模式执行,若运行失败,可清除告警后再次尝试") + + def r_program_start(self): # OK + self.__reg_high_pulse(40009) + clibs.insert_logdb("INFO", "openapi", "modbus: 40009-010 执行机器人默认程序运行,需有 pp2main 前置操作,若运行失败,可清除告警后再次尝试") + + def r_program_stop(self): # OK + self.__reg_high_pulse(40010) + clibs.insert_logdb("INFO", "openapi", "modbus: 40010-010 执行机器人默认程序停止,需有 pp2main 前置操作,若运行失败,可清除告警后再次尝试") + + def r_reduced_mode(self, action: int): # OK + self.__c.write_register(40011, action) + actions = "进入" if action == 1 else "退出" + clibs.insert_logdb("INFO", "openapi", f"modbus: 40011-{action} 执行机器人{actions}缩减模式") + time.sleep(clibs.interval) + + def r_soft_estop(self, action: int): # OK + self.__c.write_register(40012, action) + actions = "解除" if action == 1 else "触发" + clibs.insert_logdb("INFO", "openapi", f"modbus: 40012-{action} 执行{actions}急停动作") + time.sleep(clibs.interval) + + def r_switch_auto_motoron(self): # OK + self.__reg_high_pulse(40013) + clibs.insert_logdb("INFO", "openapi", "modbus: 40013-010 执行切换为自动模式,并上电,初始状态 !!不能是!! 手动上电模式") + + def r_switch_auto(self): # OK + self.__reg_high_pulse(40014) + clibs.insert_logdb("INFO", "openapi", "modbus: 40014-010 执行切换为自动模式") + + def r_switch_manual(self): # OK + self.__reg_high_pulse(40015) + clibs.insert_logdb("INFO", "openapi", "modbus: 40015-010 执行切换为手动模式") + + def r_switch_safe_region01(self, action: bool): # OK | 上升沿打开,下降沿关闭 + if action: + self.__c.write_register(40016, False) + time.sleep(clibs.interval) + self.__c.write_register(40016, True) + else: + self.__c.write_register(40016, True) + time.sleep(clibs.interval) + self.__c.write_register(40016, False) + actions = "打开" if action else "关闭" + clibs.insert_logdb("INFO", "openapi", f"modbus: 40016-{action} 执行{actions}安全区 safe region 01") + time.sleep(clibs.interval) + + def r_switch_safe_region02(self, action: bool): # OK | 上升沿打开,下降沿关闭 + if action: + self.__c.write_register(40017, False) + time.sleep(clibs.interval) + self.__c.write_register(40017, True) + else: + self.__c.write_register(40017, True) + time.sleep(clibs.interval) + self.__c.write_register(40017, False) + actions = "打开" if action else "关闭" + clibs.insert_logdb("INFO", "openapi", f"modbus: 40017-{action} 执行{actions}安全区 safe region 02") + time.sleep(clibs.interval) + + def r_switch_safe_region03(self, action: bool): # OK | 上升沿打开,下降沿关闭 + if action: + self.__c.write_register(40018, False) + time.sleep(clibs.interval) + self.__c.write_register(40018, True) + else: + self.__c.write_register(40018, True) + time.sleep(clibs.interval) + self.__c.write_register(40018, False) + actions = "打开" if action else "关闭" + clibs.insert_logdb("INFO", "openapi", f"modbus: 40018-{action} 执行{actions}安全区 safe region 03") + time.sleep(clibs.interval) + + def r_write_signals(self, addr: int, value): # OK | 40100 - 40109: signal_0 ~ signal_9 + if -1 < addr < 10 and addr.is_integer(): + self.__c.write_register(40100+addr, value) + clibs.insert_logdb("INFO", "openapi", f"modbus: {40100+addr}-{value} 将寄存器 signal_{addr} 赋值为 {value}") + else: + clibs.insert_logdb("INFO", "openapi", f"modbus: {40100+addr}-{value} 地址错误,无法赋值!") + + @property + def w_alarm_state(self): # OK + res = self.__c.read_holding_registers(40500, count=1).registers[0] + clibs.insert_logdb("INFO", "openapi", f"modbus: 40500 获取告警状态,结果为 {res} :--: 0 表示无告警,,1 表示有告警") + return res + + @property + def w_collision_alarm_state(self): # OK + res = self.__c.read_holding_registers(40501, count=1).registers[0] + clibs.insert_logdb("INFO", "openapi", f"modbus: 40501 获取碰撞告警状态,结果为 {res} :--: 0 表示未触发,1 表示已触发") + return res + + @property + def w_collision_open_state(self): # OK + res = self.__c.read_holding_registers(40502, count=1).registers[0] + clibs.insert_logdb("INFO", "openapi", f"modbus: 40502 获取碰撞检测开启状态,结果为 {res} :--: 0 表示关闭,1 表示开启") + return res + + @property + def w_controller_is_running(self): # OK + res = self.__c.read_holding_registers(40503, count=1).registers[0] + clibs.insert_logdb("INFO", "openapi", f"modbus: 40503 获取控制器运行状态,结果为 {res} :--: 0 表示运行异常,1 表示运行正常") + return res + + @property + def w_encoder_low_battery(self): # OK + res = self.__c.read_holding_registers(40504, count=1).registers[0] + clibs.insert_logdb("INFO", "openapi", f"modbus: 40504 获取编码器低电压状态,结果为 {res} :--: 0 表示非低电压,1 表示低电压 需关注") + return res + + @property + def w_estop_state(self): # OK + res = self.__c.read_holding_registers(40505, count=1).registers[0] + clibs.insert_logdb("INFO", "openapi", f"modbus: 40505 获取机器人急停状态(非软急停),结果为 {res} :--: 0 表示未触发,1 表示已触发") + return res + + @property + def w_motor_state(self): # OK + res = self.__c.read_holding_registers(40506, count=1).registers[0] + clibs.insert_logdb("INFO", "openapi", f"modbus: 40506 获取机器人上电状态,结果为 {res} :--: 0 表示未上电,1 表示已上电") + return res + + @property + def w_operation_mode(self): # OK + res = self.__c.read_holding_registers(40507, count=1).registers[0] + clibs.insert_logdb("INFO", "openapi", f"modbus: 40507 获取机器人操作模式,结果为 {res} :--: 0 表示手动模式,1 表示自动模式") + return res + + @property + def w_program_state(self): # OK + res = self.__c.read_holding_registers(40508, count=1).registers[0] + clibs.insert_logdb("INFO", "openapi", f"modbus: 40508 获取程序的运行状态,结果为 {res} :--: 0 表示未运行,1 表示正在运行") + return res + + @property + def w_program_not_run(self): # OK + res = self.__c.read_holding_registers(40509, count=1).registers[0] + clibs.insert_logdb("INFO", "openapi", f"modbus: 40509 判定程序为未运行状态,结果为 {res} :--: 0 表示正在运行,1 表示未运行") + return res + + @property + def w_program_reset(self): # OK + res = self.__c.read_holding_registers(40510, count=1).registers[0] + clibs.insert_logdb("INFO", "openapi", f"modbus: 40510 判定程序指针为 pp2main 状态,结果为 {res} :--: 0 表示指针不在 main 函数,1 表示指针在 main 函数") + return res + + @property + def w_reduce_mode_state(self): # OK + res = self.__c.read_holding_registers(40511, count=1).registers[0] + clibs.insert_logdb("INFO", "openapi", f"modbus: 40511 获取机器人缩减模式状态,结果为 {res} :--: 0 表示非缩减模式,1 表示缩减模式") + return res + + @property + def w_robot_is_busy(self): # OK + res = self.__c.read_holding_registers(40512, count=1).registers[0] + clibs.insert_logdb("INFO", "openapi", f"modbus: 40512 获取机器人是否处于 busy 状态,结果为 {res} :--: 0 表示未处于 busy 状态,1 表示处于 busy 状态") + return res + + @property + def w_robot_is_moving(self): # OK + res = self.__c.read_holding_registers(40513, count=1).registers[0] + clibs.insert_logdb("INFO", "openapi", f"modbus: 40513 获取机器人是否处于运动状态,结果为 {res} :--: 0 表示未运动,1 表示正在运动") + return res + + @property + def w_safe_door_state(self): # OK + res = self.__c.read_holding_registers(40514, count=1).registers[0] + clibs.insert_logdb("INFO", "openapi", f"modbus: 40514 获取机器人是否处于安全门打开状态,需自动模式下执行,结果为 {res} :--: 0 表示未触发安全门,1 表示已触发安全门") + return res + + @property + def w_safe_region01_trig_state(self): # OK + res = self.__c.read_holding_registers(40515, count=1).registers[0] + clibs.insert_logdb("INFO", "openapi", f"modbus: 40515 获取安全区域 safe region01 的触发状态,结果为 {res} :--: 0 表示未触发,1 表示已触发") + return res + + @property + def w_safe_region02_trig_state(self): # OK + res = self.__c.read_holding_registers(40516, count=1).registers[0] + clibs.insert_logdb("INFO", "openapi", f"modbus: 40516 获取安全区域 safe region02 的触发状态,结果为 {res} :--: 0 表示未触发,1 表示已触发") + return res + + @property + def w_safe_region03_trig_state(self): # OK + res = self.__c.read_holding_registers(40517, count=1).registers[0] + clibs.insert_logdb("INFO", "openapi", f"modbus: 40517 获取安全区域 safe region03 的触发状态,结果为 {res} :--: 0 表示未触发,1 表示已触发") + return res + + @property + def w_soft_estop_state(self): # OK + res = self.__c.read_holding_registers(40518, count=1).registers[0] + clibs.insert_logdb("INFO", "openapi", f"modbus: 40518 获取机器人软急停状态,结果为 {res} :--: 0 表示未触发软急停,1 表示已触发软急停") + return res + + def io_write_coils(self, addr, action): # OK | 名字叫写线圈,其实是写 modbus 的 discrete inputs(DI) + # e.g. io_write_coils(0, 1) + # e.g. io_write_coils(1, 1) + # e.g. io_write_coils(0, [1, 1, 1]) + self.__c.write_coils(addr, action) + clibs.insert_logdb("INFO", "openapi", f"modbus: 执行给 DI 地址 {addr} 赋值为 {action},可根据情况传递列表,实现一次性赋值多个") + time.sleep(clibs.interval) + + def io_read_coils(self): # OK | 读 modbus 的 16 个 discrete inputs(DI) + res = self.__c.read_coils(0, count=16).bits + clibs.insert_logdb("INFO", "openapi", f"modbus: 执行读取所有 DI 的结果为 {res}") + return res + + def io_read_discretes(self): # OK | 读 modbus 的 coil outputs(DO) + res = self.__c.read_discrete_inputs(0, count=16).bits + clibs.insert_logdb("INFO", "openapi", f"modbus: 执行读取所有 DO 的结果为 {res}") + return res + + +class HmiRequest(object): + socket.setdefaulttimeout(clibs.interval * 10) + + def __init__(self, ip, port, port_xs): + self.__ip = ip + self.__port = port + self.__port_xs = port_xs + self.__close_hmi = False + self.__is_connected = False + self.__index = 0 + self.__previous_data = b"" + self.__valid_data_length = 0 + self.__leftovers = 0 + self.__response = b"" + self.__response_xs = "" + self.__half_frm = b"" + self.__half_frm_flag = -1 + self.__half_pkg = b"" + self.__half_pkg_flag = False + self.__is_first_frame = True + self.__is_very_first_frame = True + + self.__t_heartbeat = None + self.__t_unpackage = None + self.__t_unpackage_xs = None + self.__t_is_alive = Thread(target=self.__is_alive) + self.__t_is_alive.daemon = True + self.__t_is_alive.start() + time.sleep(3) + + def __is_alive(self): + while not self.__close_hmi: + if not self.__is_connected: + self.__socket_conn() + if self.__is_connected: + self.__t_heartbeat = Thread(target=self.__heartbeat) + self.__t_heartbeat.daemon = True + self.__t_heartbeat.start() + self.__t_unpackage = Thread(target=self.__unpackage, args=(self.__c,)) + self.__t_unpackage.daemon = True + self.__t_unpackage.start() + self.__t_unpackage_xs = Thread(target=self.__unpackage_xs, args=(self.__c_xs,)) + self.__t_unpackage_xs.daemon = True + self.__t_unpackage_xs.start() + time.sleep(3) + + @property + def status(self): + return self.__is_connected + + def close(self): + try: + self.__close_hmi = True + self.__is_connected = False + time.sleep(clibs.interval) + self.__c.close() + self.__c_xs.close() + except: + ... + + def __socket_conn(self): + self.close() + try: + self.__c = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.__c.connect((self.__ip, self.__port)) + self.__c_xs = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.__c_xs.connect((self.__ip, self.__port_xs)) + # 尝试连续三次发送心跳包,确认建联成功 + state = None + for i in range(3): + _, state = self.execution.__wrapped__(self, "controller.heart") + time.sleep(clibs.interval/5) + if state is not None: + self.__is_connected = True + clibs.insert_logdb("INFO", "openapi", "hr: HMI connection success...") + else: + clibs.insert_logdb("ERROR", "openapi", "hr: HMI connection failed...") + except Exception as Err: + clibs.insert_logdb("ERROR", "openapi", "hr: HMI connection timeout...") + clibs.w2t(f"无法连接至 {self.__ip}...\n报错信息 {Err}", "red", "NetworkUnreachable") + + def __heartbeat(self): + while self.__is_connected: + self.execution("controller.heart") + time.sleep(clibs.interval*4) + + @staticmethod + def __package(cmd): + frm_value = (len(cmd) + 6).to_bytes(length=2, byteorder="big") + pkg_value = len(cmd).to_bytes(length=4, byteorder="big") + protocol = int(2).to_bytes(length=1, byteorder="big") + reserved = int(0).to_bytes(length=1, byteorder="big") + return frm_value + pkg_value + protocol + reserved + cmd.encode() + + def __unpackage(self, sock): + def to_read(conn, mask): + data = conn.recv(clibs.MAX_FRAME_SIZE) + if data: + # print(f"data = {data}") + with open(f"{clibs.log_path}/logs.txt", mode="a", encoding="utf-8") as f_logs: + f_logs.write(str(data) + "\n") + self.__get_response(data) + else: + sel.unregister(conn) + conn.close() + + try: + sel = selectors.DefaultSelector() + sel.register(sock, selectors.EVENT_READ, to_read) + while self.__is_connected: + events = sel.select() + for key, mask in events: + callback = key.data + callback(key.fileobj, mask) + except Exception as Err: + clibs.insert_logdb("ERROR", "openapi", f"hr-unpackage: 报错信息 {Err}") + + def __get_headers(self, index, data): + print(f"index = {index}") + if index + 8 < len(data): + frm_value = int.from_bytes(data[index:index + 2], byteorder="big") + pkg_value = int.from_bytes(data[index + 2:index + 6], byteorder="big") + protocol = int.from_bytes(data[index + 6:index + 7], byteorder="big") + reserved = int.from_bytes(data[index + 7:index + 8], byteorder="big") + print(f"reserved = {reserved}") + print(f"protocol = {protocol}") + print(f"frm_value = {frm_value}") + print(f"pkg_value = {pkg_value}") + if reserved == 0 and protocol == 2: + return index + 8, frm_value, pkg_value + else: + print("hr-get_headers: 解包数据有误,需要确认!") + print(data) + clibs.insert_logdb("ERROR", "openapi", "hr-get_headers: 解包数据有误,需要确认!") + else: + self.__half_pkg = data[index:] + self.__half_pkg_flag = True + index += clibs.MAX_FRAME_SIZE + return index, 0, 0 + + def __get_response(self, data): + if self.__half_pkg_flag: + print(f"self.__half_pkg = {self.__half_pkg}") + len_one = len(self.__half_pkg) + len_another = 8 - len_one + headers = self.__half_pkg + data[:len_another] + self.__index = len_another + frm_value = int.from_bytes(headers[0:2], byteorder="big") + pkg_value = int.from_bytes(headers[2:6], byteorder="big") + print(f"headers = {headers}") + + while self.__index < len(data): + print(f"top valid data = {self.__valid_data_length}") + if self.__valid_data_length < 0: + print(f"invalid data: {data}") + raise Exception() + if self.__is_first_frame: + if self.__half_pkg_flag: + self.__half_pkg_flag = False + else: + self.__index, frm_value, pkg_value = self.__get_headers(self.__index, data) + + if frm_value - pkg_value == 6: + if len(data[self.__index:]) >= pkg_value: + self.__response = data[self.__index:self.__index + pkg_value] + self.__index += pkg_value + with open(f"{clibs.log_path}/response.txt", mode="a", encoding="utf-8") as f_res: + f_res.write(f"{json.loads(self.__response.decode())}" + "\n") + clibs.insert_logdb("DEBUG", "openapi", self.__response.decode()) + self.__response = b"" + self.__leftovers = 0 + self.__is_first_frame = True + elif len(data[self.__index:]) < pkg_value: + self.__response = data[self.__index:] + self.__leftovers = pkg_value - len(data[self.__index:]) + self.__index += clibs.MAX_FRAME_SIZE # whatever + self.__is_first_frame = False + elif frm_value < pkg_value: + self.__valid_data_length = pkg_value + if len(data[self.__index:]) >= frm_value - 6: + self.__is_first_frame = False + self.__leftovers = 0 + self.__response = data[self.__index:self.__index + frm_value - 6] + self.__index += (frm_value - 6) + self.__valid_data_length -= (frm_value - 6) + if len(data[self.__index:]) == 2: + self.__half_frm = data[self.__index:] + self.__index += clibs.MAX_FRAME_SIZE + self.__half_frm_flag = 2 + elif len(data[self.__index:]) == 1: + self.__half_frm = data[self.__index:] + self.__index += clibs.MAX_FRAME_SIZE + self.__half_frm_flag = 1 + elif len(data[self.__index:]) == 0: + self.__index += clibs.MAX_FRAME_SIZE + self.__half_frm_flag = 0 + else: + self.__half_frm_flag = -1 + elif len(data[self.__index:]) < frm_value - 6: + self.__response = data[self.__index:] + self.__leftovers = frm_value - 6 - len(data[self.__index:]) + self.__valid_data_length -= len(data[self.__index:]) + self.__index += clibs.MAX_FRAME_SIZE + self.__is_first_frame = False + elif not self.__is_first_frame: # 不是首帧 + if self.__leftovers > 0 and self.__valid_data_length > 0: + self.__is_first_frame = False + self.__response += data[:self.__leftovers] + self.__index = self.__leftovers + self.__valid_data_length -= self.__leftovers + self.__leftovers = 0 + if self.__valid_data_length == 0: + with open(f"{clibs.log_path}/response.txt", mode="a", encoding="utf-8") as f_res: + f_res.write(f"{json.loads(self.__response.decode())}" + "\n") + clibs.insert_logdb("DEBUG", "openapi", self.__response.decode()) + self.__response = b"" + self.__is_first_frame = True + if len(data[self.__index:]) == 2: + self.__half_frm = data[self.__index:] + self.__index += clibs.MAX_FRAME_SIZE + self.__half_frm_flag = 2 + elif len(data[self.__index:]) == 1: + self.__half_frm = data[self.__index:] + self.__index += clibs.MAX_FRAME_SIZE + self.__half_frm_flag = 1 + elif len(data[self.__index:]) == 0: + self.__index += clibs.MAX_FRAME_SIZE + self.__half_frm_flag = 0 + else: + self.__half_frm_flag = -1 + + elif self.__leftovers > 0 and self.__valid_data_length == 0: + self.__response += data[:self.__leftovers] + self.__index = self.__leftovers + self.__leftovers = 0 + with open(f"{clibs.log_path}/response.txt", mode="a", encoding="utf-8") as f_res: + f_res.write(f"{json.loads(self.__response.decode())}" + "\n") + clibs.insert_logdb("DEBUG", "openapi", self.__response.decode()) + self.__response = b"" + self.__is_first_frame = True + + elif self.__leftovers == 0 and self.__valid_data_length > 0: + # 1. len(data[self.__index:]) > 2 + # 2. len(data[self.__index:]) = 2 + # 3. len(data[self.__index:]) = 1 + # 4. len(data[self.__index:]) = 0 + if self.__half_frm_flag != -1: + if self.__half_frm_flag == 2: + self.__index = int.from_bytes(self.__half_frm) + self.__response += data[:self.__index] + self.__valid_data_length -= len(data[:self.__index]) + self.__half_frm_flag = -1 + elif self.__half_frm_flag == 1: + frm_value = int.from_bytes(self.__half_frm + data[0:1]) + if len(data[1:]) >= frm_value: + self.__response += data[1:frm_value+1] + self.__leftovers = 0 + self.__valid_data_length -= len(data[1:frm_value+1]) + self.__index = frm_value + 1 + elif len(data[1:]) < frm_value: + self.__response += data[1:] + self.__leftovers = frm_value - len(data[1:]) + self.__valid_data_length -= len(data[1:]) + self.__index += clibs.MAX_FRAME_SIZE + self.__half_frm_flag = -1 + elif self.__half_frm_flag == 0: + frm_value = int.from_bytes(data[0:2]) + if len(data[2:]) >= frm_value: + self.__response += data[2:frm_value+2] + self.__leftovers = 0 + self.__valid_data_length -= len(data[2:frm_value+2]) + self.__index = frm_value + 2 + elif len(data[2:]) < frm_value: + self.__response += data[2:] + self.__leftovers = frm_value - len(data[2:]) + self.__valid_data_length -= len(data[2:]) + self.__index += clibs.MAX_FRAME_SIZE + self.__half_frm_flag = -1 + + if self.__valid_data_length == 0: + with open(f"{clibs.log_path}/response.txt", mode="a", encoding="utf-8") as f_res: + f_res.write(f"{json.loads(self.__response.decode())}" + "\n") + clibs.insert_logdb("DEBUG", "openapi", self.__response.decode()) + self.__response = b"" + self.__is_first_frame = True + if len(data[self.__index:]) == 2: + self.__half_frm = data[self.__index:] + self.__index += clibs.MAX_FRAME_SIZE + self.__half_frm_flag = 2 + elif len(data[self.__index:]) == 1: + self.__half_frm = data[self.__index:] + self.__index += clibs.MAX_FRAME_SIZE + self.__half_frm_flag = 1 + elif len(data[self.__index:]) == 0: + self.__index += clibs.MAX_FRAME_SIZE + self.__half_frm_flag = 0 + else: + self.__half_frm_flag = -1 + + else: + frm_value = int.from_bytes(data[self.__index:self.__index + 2]) + self.__index += 2 + if len(data[self.__index:]) >= frm_value: + self.__leftovers = 0 + self.__response += data[self.__index:self.__index + frm_value] + self.__index += frm_value + self.__valid_data_length -= frm_value + if self.__valid_data_length == 0: + with open(f"{clibs.log_path}/response.txt", mode="a", encoding="utf-8") as f_res: + f_res.write(f"{json.loads(self.__response.decode())}" + "\n") + clibs.insert_logdb("DEBUG", "openapi", self.__response.decode()) + self.__response = b"" + self.__is_first_frame = True + if len(data[self.__index:]) == 2: + self.__index += clibs.MAX_FRAME_SIZE + self.__half_frm = data[self.__index:] + self.__half_frm_flag = 2 + elif len(data[self.__index:]) == 1: + self.__index += clibs.MAX_FRAME_SIZE + self.__half_frm = data[self.__index:] + self.__half_frm_flag = 1 + elif len(data[self.__index:]) == 0: + self.__half_frm_flag = 0 + else: + self.__half_frm_flag = -1 + + elif len(data[self.__index:]) < frm_value: + self.__response += data[self.__index:] + self.__leftovers = frm_value - len(data[self.__index:]) + self.__valid_data_length -= len(data[self.__index:]) + self.__index += clibs.MAX_FRAME_SIZE + else: + self.__index += 1 + else: + self.__index = 0 + + @staticmethod + def __package_xs(cmd): + return "".join([json.dumps(cmd, separators=(",", ":")), "\r"]).encode() + + def __unpackage_xs(self, sock): + def to_read(conn, mask): + data = conn.recv(1024) # Should be ready + if data: + # print(data) + self.__get_response_xs(data) + else: + sel.unregister(conn) + conn.close() + + try: + sel = selectors.DefaultSelector() + sel.register(sock, selectors.EVENT_READ, to_read) + + while self.__is_connected: + events = sel.select() + for key, mask in events: + callback = key.data + callback(key.fileobj, mask) + except Exception as Err: + clibs.insert_logdb("ERROR", "openapi", f"hr-unpackage_xs: 报错信息 {Err}") + + def __get_response_xs(self, data): + char, response = "", self.__response_xs + for char in data.decode(): + if char != "\r": + response = "".join([response, char]) + else: + clibs.insert_logdb("DEBUG", "openapi", response) + response = "" + else: + self.__response_xs = response + + def get_from_id(self, msg_id, state): + f_text = f"%{msg_id}%" + if state is None: + self.close() + clibs.w2t(f"请求 {msg_id} 发送失败......", "red", "ReqSendFailed") + for _ in range(60): + try: + clibs.lock.acquire(True) + clibs.cursor.execute(f"select * from logs where content like '{f_text}'") + res = len(clibs.cursor.fetchall()) + finally: + clibs.lock.release() + if res >= 2: + break + else: + time.sleep(clibs.interval*2) + continue + else: + clibs.insert_logdb("ERROR", "openapi", f"hr: 无法找到请求 {msg_id} 的响应") + self.close() + clibs.w2t(f"无法找到请求 {msg_id} 的响应......\n", "red", "RespondNotFound") + + @staticmethod + def validate_req(func): + @functools.wraps(func) + def wrapper(self, *args, **kwargs): + msg_id, state = func(self, *args, **kwargs) + t = threading.Thread(target=self.get_from_id, args=(msg_id, state)) + t.daemon = True + t.start() + # self.get_from_id(msg_id, state) + return msg_id, state + return wrapper + + @validate_req + def execution(self, command, p_flag=0, **kwargs): + req, state = None, None + try: + with open(f"{clibs.PREFIX}/files/protocols/{command}.json", encoding="utf-8", mode="r") as f_json: + req = json.load(f_json) + except Exception as Err: + clibs.insert_logdb("ERROR", "openapi", f"hr: 暂不支持 {command} 功能,或确认该功能存在... {Err}") + + if p_flag == 0: # for old protocols + match command: + case "state.set_tp_mode": + req["data"]["tp_mode"] = kwargs["tp_mode"] + case "overview.set_autoload": + req["data"]["autoload_prj_path"] = kwargs["autoload_prj_path"] + case "overview.reload": + req["data"]["prj_path"] = kwargs["prj_path"] + req["data"]["tasks"] = kwargs["tasks"] + case "rl_task.pp_to_main" | "rl_task.run" | "rl_task.stop": + req["data"]["tasks"] = kwargs["tasks"] + case "rl_task.set_run_params": + req["data"]["loop_mode"] = kwargs["loop_mode"] + req["data"]["override"] = kwargs["override"] + case "diagnosis.set_params": + req["data"]["display_pdo_params"] = kwargs["display_pdo_params"] + req["data"]["frequency"] = kwargs["frequency"] + req["data"]["version"] = kwargs["version"] + case "diagnosis.open": + req["data"]["open"] = kwargs["open"] + req["data"]["display_open"] = kwargs["display_open"] + req["data"]["overrun"] = kwargs["overrun"] + req["data"]["turn_area"] = kwargs["turn_area"] + req["data"]["delay_motion"] = kwargs["delay_motion"] + case "register.set_value": + req["data"]["name"] = kwargs["name"] + req["data"]["type"] = kwargs["type"] + req["data"]["bias"] = kwargs["bias"] + req["data"]["value"] = kwargs["value"] + case "diagnosis.save": + req["data"]["save"] = kwargs["save"] + case "socket.set_params": + req["data"] = kwargs["data"] + case "fieldbus_device.set_params": + req["data"]["device_name"] = kwargs["device_name"] + req["data"]["enable"] = kwargs["enable"] + case "soft_limit.set_params": + req["data"] = kwargs["data"] + case "move.set_quickturn_pos": + req["data"]["enable_home"] = kwargs["enable_home"] + req["data"]["enable_drag"] = kwargs["enable_drag"] + req["data"]["enable_transport"] = kwargs["enable_transport"] + req["data"]["end_posture"] = kwargs["end_posture"] + case "move.quick_turn": + req["data"]["name"] = kwargs["name"] + case "move.stop": + req["data"]["stoptype"] = kwargs["stoptype"] + case "jog.start": + req["data"]["index"] = kwargs["index"] + req["data"]["direction"] = kwargs["direction"] + req["data"]["is_ext"] = kwargs["is_ext"] + case "jog.set_params": + req["data"]["step"] = kwargs["step"] + req["data"]["override"] = kwargs["override"] + req["data"]["space"] = kwargs["space"] + case "diagnosis.get_params": + req["data"]["version"] = kwargs["version"] + case "system_io.update_configuration": + req["data"]["input_system_io"] = kwargs["input_system_io"] + req["data"]["output_system_io"] = kwargs["output_system_io"] + case "modbus.set_params": + req["data"]["enable_slave"] = kwargs["enable_slave"] + req["data"]["ip"] = kwargs["ip"] + req["data"]["port"] = kwargs["port"] + req["data"]["slave_id"] = kwargs["slave_id"] + req["data"]["enable_master"] = kwargs["enable_master"] + case "modbus.get_values": + req["data"]["mode"] = kwargs["mode"] + case "move.set_monitor_cfg": + req["data"]["ref_coordinate"] = kwargs["ref_coordinate"] + case "move.set_params": + req["data"]["MOTION"] = kwargs["data"] + case "move.set_quickstop_distance": + req["data"]["distance"] = kwargs["distance"] + case "collision.set_params": + req["data"] = kwargs["data"] + case "collision.set_state": + req["data"]["collision_state"] = kwargs["collision_state"] + case "controller.set_params": + req["data"]["time"] = kwargs["time"] + case "drag.set_params": + req["data"]["enable"] = kwargs["enable"] + req["data"]["space"] = kwargs["space"] + req["data"]["type"] = kwargs["type"] + case _: + pass + + req["id"] = f"{command}-{time.time()}" + cmd = json.dumps(req, separators=(",", ":")) + try: + self.__c.send(self.__package(cmd)) + clibs.insert_logdb("INFO", "openapi", f"hr: 请求发送成功 {cmd}") + state = "done" + except Exception as Err: + clibs.insert_logdb("ERROR", "openapi", f"hr: 请求发送失败 {cmd}\n报错信息 {Err}") + return req["id"], state + elif p_flag == 1: # for xService + match command: + case "safety.safety_area.signal_enable": + req["c"]["safety.safety_area.signal_enable"]["signal"] = kwargs["signal"] + case "safety.safety_area.overall_enable": + req["c"]["safety.safety_area.overall_enable"]["enable"] = kwargs["enable"] + case "log_code.data.code_list": + req["s"]["log_code.data"]["code_list"] = kwargs["code_list"] + case "safety.safety_area.safety_area_enable": + req["c"]["safety.safety_area.safety_area_enable"]["id"] = kwargs["id"] + req["c"]["safety.safety_area.safety_area_enable"]["enable"] = kwargs["enable"] + case "safety.safety_area.set_param": + req["c"]["safety.safety_area.set_param"] = kwargs["data"] + case _: + pass + + try: + self.__c_xs.send(self.__package_xs(req)) + clibs.insert_logdb("INFO", "openapi", f"hr: 请求发送成功 {req}") + state = "done" + except Exception as Err: + clibs.insert_logdb("ERROR", "openapi", f"hr: 请求发送失败 {req}\n报错信息 {Err}") + return command, state + + # =================================== ↓↓↓ specific functions ↓↓↓ =================================== + + # def switch_motor_state(self, state: str): # OK + # """ + # 切换上电/下电的状态 + # :param state: on/off + # :return: None + # """ + # match state: + # case "on": + # self.execution("state.switch_motor_on") + # case "off": + # self.execution("state.switch_motor_off") + # case _: + # clibs.insert_logdb("ERROR", "openapi", f"hr: switch_motor_state 参数错误 {state}: 非法参数,只接受 on/off") + # + # def switch_operation_mode(self, mode: str): # OK + # """ + # 切换自动/手动操作模式 + # :param mode: auto/manual + # :return: None + # """ + # match mode: + # case "auto": + # self.execution("state.switch_auto") + # case "manual": + # self.execution("state.switch_manual") + # case _: + # clibs.insert_logdb("ERROR", "openapi", "hr: switch_operation_mode 参数错误 非法参数,只接受 auto/manual") + # + # def reload_project(self, prj_name: str, tasks: list): # OK + # """ + # 重新加载指定工程 + # :param prj_name: 工程名,也即 zip 文件的名字 + # :param tasks: 要加载的任务列表 + # :return: None + # """ + # prj_path = f"{prj_name}/_build/{prj_name}.prj" + # self.execution("overview.reload", prj_path=prj_path, tasks=tasks) + # + # def set_project_auto_reload(self, prj_name: str): # OK + # """ + # 将指定工程设置为开机自动加载,也即默认工程 + # :param prj_name: 工程名,也即 zip 文件的名字 + # :return: None + # """ + # autoload_prj_path = f"{prj_name}/_build/{prj_name}.prj" + # self.execution("overview.set_autoload", autoload_prj_path=autoload_prj_path) + # + # def pp_to_main(self, tasks: list): # OK + # """ + # 将指定的任务列表的指针,指向 main 函数 + # :param tasks: 任务列表 + # :return: None + # """ + # self.execution("rl_task.pp_to_main", tasks=tasks) + # + # def program_start(self, tasks: list): # OK + # """ + # 开始执行程序任务,必须是自动模式下执行 + # :param tasks: 任务列表 + # :return: None + # """ + # self.execution("rl_task.run", tasks=tasks) + # + # def program_stop(self, tasks: list): # OK + # """ + # 停止执行程序任务 + # :param tasks: 人物列表 + # :return: None + # """ + # self.execution("rl_task.stop", tasks=tasks) + # + # def set_program_loop_speed(self, loop_mode: bool = True, override: float = 0.5): # OK + # """ + # :param loop_mode: True为循环模式,False为单次模式 + # :param override: HMI 左下方的速度滑块,取值范围 [0, 1] + # :return: None + # """ + # self.execution("rl_task.set_run_params", loop_mode=loop_mode, override=override) + # + # def clear_alarm(self): # OK + # """ + # 清除伺服告警 + # :return: None + # """ + # self.execution("servo.clear_alarm") + # + # def reboot_robot(self): # OK + # """ + # 重启控制器 + # :return: None + # """ + # self.execution("controller.reboot") + # clibs.insert_logdb("INFO", "openapi", f"hr: 控制器重启中,重连预计需要等待 100s 左右...") + # ts = time() + # time.sleep(30) + # while True: + # time.sleep(5) + # te = time() + # if te - ts > 180: + # self.__silence = False + # self.__sth_wrong("3min 内未能完成重新连接,需要查看后台控制器是否正常启动,或者 ip/port 是否正确") + # break + # for _ in range(3): + # if not self.__is_connected: + # break + # time.sleep(2) + # else: + # clibs.insert_logdb("INFO", "openapi", "hr: HMI 重新连接成功...") + # break + # + # def reload_io(self): + # """ + # 触发控制器重新加载 IO 设备列表 + # :return: None + # """ + # self.execution("io_device.load_cfg") + # + # @property + # def get_quickturn_pos(self): # OK + # """ + # 获取机器人的home位姿、拖动位姿和发货位姿,轴关节角度,end_posture 取值如下: + # 0 法兰平面与地面平行 + # 1 工具坐标系X轴与地面垂直,正向朝下 + # 2 工具坐标系X轴与地面垂直,正向朝上 + # 3 工具坐标系Y轴与地面垂直,正向朝下 + # 4 工具坐标系Y轴与地面垂直,正向朝上 + # 5 工具坐标系Z轴与地面垂直,正向朝下 + # 6 工具坐标系Z轴与地面垂直,正向朝上 + # :return: as below + # { + # "enable_home": false, // 是否开启 home 点快速调整 + # "enable_drag": false, // 是否开启拖动位姿点快速调整 + # "enable_transport": false, // 是否开启发货位姿点快速调整 + # "joint_home": [0.0,0.0,0.0,0.0,0.0,0.0,0.0], // home 位姿的关节角度 + # "joint_drag": [0.0,0.0,0.0,0.0,0.0,0.0,0.0], // 拖动位姿的关节角度 + # "joint_transport": [0.0,0.0,0.0,0.0,0.0,0.0,0.0], // 发货位姿的关节角度 + # "end_posture":0, // 末端姿态的调整方式,取值 0-6 + # "home_error_range":[0.0,0.0,0.0,0.0,0.0,0.0,0.0] // home点误差范围 + # } + # """ + # return self.__get_data(currentframe().f_code.co_name, "move.get_quickturn_pos") + # + # def set_quickturn_pos(self, enable_home: bool = False, enable_drag: bool = False, enable_transport: bool = False, end_posture: int = 0): # OK + # """ + # 设置机器人的home位姿、拖动位姿、发货位姿,轴关节角度,Home点误差范围,详见上一个 get_quickturn_pos 功能实现 + # :param enable_home: 是否开启 home 点快速调整 + # :param enable_drag: 是否开启拖动位姿点快速调整 + # :param enable_transport:是否开启发货位姿点快速调整 + # :param end_posture: 末端姿态的调整方式,取值 0-6,详见 get_quickturn_pos 注释 + # :return: None + # """ + # self.execution("move.set_quickturn_pos", enable_home=enable_home, enable_drag=enable_drag, enable_transport=enable_transport, end_posture=end_posture) + # + # def move2quickturn(self, name: str): # OK + # """ + # 运动到指定的快速调整位姿 + # :param name: 指定快速调整的名称,home/drag/transport + # :return: None + # """ + # self.execution("move.quick_turn", name=name) + # + # def stop_move(self, stoptype=0): # OK + # """ + # 停止运动 + # TS_READY | TS_JOG | TS_LOADIDENTIFY | TS_DYNAMICIDENTIFY | TS_DRAG | TS_PROGRAM | TS_DEMO | TS_RCI | TS_DEBUG | TS_FRICTIONIDENTIFY + # :param stoptype: 对应控制器的任务空间类型TaskSpace的枚举值,0-7 + # :return: None + # """ + # self.execution("move.stop", stoptype=stoptype) + # + # @property + # def get_jog_params(self): # OK + # """ + # 获取JOG的参数 + # 世界坐标系 WORLD_COORDINATE 0 + # 法兰盘坐标系 FLANGE_COORDINATE 1 + # 基坐标系 BASE_COORDINATE 2 + # 工具坐标系 TOOL_COORDINATE 3 + # 工件坐标系 FRAME_COORDINATE 4 + # 关节空间 JOINT_SPACE 5 + # :return: + # { + # "step": 1000 [1000-连续] [10/1/0.1/0.001-点动] + # "override": 0.2 速度比率 + # "space": 5 JOG的空间 + # } + # """ + # return self.__get_data(currentframe().f_code.co_name, "jog.get_params") + # + # def set_jog_params(self, step, override, space): # OK + # """ + # 设置JOG的参数,包含步长,空间,速度倍率 + # :param step: [1000-连续] [10/1/0.1/0.001-点动] + # :param override: 速度比率 + # :param space: JOG的空间 + # :return: None + # """ + # self.execution("jog.set_params", step=step, override=override, space=space) + # + # def start_jog(self, index: int, direction: bool = False, is_ext: bool = False): # OK + # """ + # 开始 JOG 运动 + # :param index: 0-6,若选轴空间,则 0-6 对应 1-7 轴,若选笛卡尔空间,则 0-6 对应 xyzabc elb + # :param direction: True 正方向,False 反方向 + # :param is_ext: 是否是外部轴 jog + # :return: None + # """ + # self.execution("jog.start", index=index, direction=direction, is_ext=is_ext) + # + # @property + # def get_socket_params(self): # OK + # """ + # 获取socket参数 + # :return: + # { + # "auto_connect": true, // True 开机启动,False 不开机启动 + # "disconnection_detection_time": 10, // 链接断开检测周期(s) + # "disconnection_triggering_behavior": 0, // 断开连接触发行为 0无动作 1暂停程序 2暂停并下电 + # "enable": true, // True 开启或者 False 关闭 + # "ip": "", // 仅限于客户端,用于指定服务端 IP;当作为服务端时,该参数设置为空字符串,否则会报错!!! + # "name": "name", // 连接名称 + # "port": "8080", // 连接端口 + # "reconnect_flag": true, // True 自动重连,False 不自动重连 + # "suffix": "\r", // 指定发送分隔符 + # "type": 1 // 连接类型 0 client | 1 server + # } + # """ + # return self.__get_data(currentframe().f_code.co_name, "socket.get_params") + # + # def set_socket_params(self, enable: bool, port: str, suffix: str, type: int = 1, **kwargs): # OK + # """ + # 设置 socket 参数,一般作为服务器使用 + # :param enable: True 开启或者 False 关闭 + # :param port: 连接端口 + # :param suffix: 指定发送分隔符 + # :param type: 0 client | 1 server + # :return: None + # """ + # data = self.get_socket_params + # keys = data.keys() + # kwargs.update({"enable": enable, "port": port, "suffix": suffix, "type": type}) + # for _ in keys: + # if _ in kwargs.keys(): + # data[_] = kwargs[_] + # self.execution("socket.set_params", data=data) + # + # @property + # def get_diagnosis_params(self, version="1.4.1"): # OK + # """ + # 获取诊断功能开启状态,以及相应其他信息 + # :param version: 指定诊断工具版本 + # :return: + # { + # "delay_motion": false, // - + # "display_open": false, // 诊断显示功能开启状态 + # "ecat_diagnosis_state": false, // - + # "overrun": false, // 是否开启实时线程超时监控上报 + # "pdo_params": [...], // 指定版本支持的所有曲线信息 + # "state": true, // 诊断功能的开启状态 + # "turn_area": false // 转弯区是否上报 + # } + # """ + # return self.__get_data(currentframe().f_code.co_name, "diagnosis.get_params", version=version) + # + # def set_diagnosis_params(self, display_pdo_params: list, frequency: int = 50, version: str = "1.4.1"): # OK + # """ + # 设置诊断功能显示参数 [{"name": "hw_joint_vel_feedback", "channel": 0}, ] + # :param display_pdo_params: 指定要采集的曲线名称,具体可通过 get_diagnosis_params 函数功能获取所有目前已支持的曲线 + # :param frequency: 采样频率,默认 50ms + # :param version: xDiagnose的版本号 + # :return: None + # """ + # self.execution("diagnosis.set_params", display_pdo_params=display_pdo_params, frequency=frequency, version=version) + # + # def open_diagnosis(self, open: bool, display_open: bool, overrun: bool = False, turn_area: bool = False, delay_motion: bool = False): # OK + # """ + # 打开或者关闭诊断曲线,并定义其他功能的开关(调试相关功能,比如是否开启线程超时监控和上报,转弯区以及运动延迟等) + # :param open: 诊断功能,控制HMI->日志->诊断设置->私服诊断开关,一般设置成 True + # :param display_open: 诊断显示功能,指的是在线诊断插件中的打开 switch 的状态,需要诊断数据的情况,设置成 True + # :param overrun: 实时线程超时监控上报 + # :param turn_area: 转弯区上报 + # :param delay_motion: 延迟运动 + # :return: None + # """ + # self.execution("diagnosis.open", open=open, display_open=display_open, overrun=overrun, turn_area=turn_area, delay_motion=delay_motion) + # + # def save_diagnosis(self, save: bool = True): # OK + # """ + # 保存诊断数据,也就是主动写诊断动作,HMI日志->诊断设置->保存诊断数据 + # :param save: 保存数据开关 + # :return: None + # """ + # self.execution("diagnosis.save", save=save) + # + # @property + # def qurry_system_io_configuration(self): # OK + # """ + # 系统IO配置的查询协议,trigger 参数取值参照如下: + # FLANKS 0, //边缘触发 + # POS_FLANK 1, //上升沿 + # NEG_FLANK 2, //下降沿 + # HIGH_LEVEL 3, //高电平 + # LOW_LEVEL 4 //低电平 + # :return: + # { + # "input_system_io": { + # "motor_on": { + # "signal":"DI0_0", + # "trigger":1 + # }, + # "motor_off": { + # "signal":"DI0_0", + # "trigger":2 + # } + # }, + # "output_system_io": { + # "sta_motor_on": { + # "signal":"DO0_0" + # }, + # "sta_robot_running": { + # "signal":"DO0_1" + # } + # } + # } + # """ + # return self.__get_data(currentframe().f_code.co_name, "system_io.query_configuration") + # + # @property + # def qurry_system_io_event_configuration(self): # OK + # """ + # 查询当前系统支持的系统IO事件列表,包括事件key、名称、支持的触发方式等配置 + # :return: + # { + # "input_system_event": [ + # { + # "key": "ctrl_motor_on", + # "name": "上电", + # "trigger_types": [ + # 1, + # 2 + # ] + # }, + # { + # "key": "ctrl_motor_off", + # "name": "下电", + # "trigger_types": [ + # 1, + # 2 + # ] + # } + # ], + # "output_system_event": [ + # { + # "key": "sta_motor_on", + # "name": "上下电状态" + # }, + # { + # "key": "sta_program", + # "name": "运行状态" + # } + # ], + # "input_mutex_event": [ + # { + # "key0": "ctrl_motor_on", + # "key1": "ctrl_motor_off" + # }, + # { + # "key0": "ctrl_switch_auto", + # "key1": "ctrl_switch_manu" + # } + # ] + # } + # """ + # return self.__get_data(currentframe().f_code.co_name, "system_io.query_configuration") + # + # def update_system_io_configuration(self, i_funcs: list, o_funcs: list, i_signals: list, o_signals: list, trig_types: list): # OK + # """ + # 配置系统 IO + # :param i_funcs: 输入,只写功能码列表 + # :param o_funcs: 输出,只读功能码列表 + # :param i_signals: DI 信号列表 + # :param o_signals: DO 信号列表 + # :param trig_types: 触发条件列表,可参考 qurry_system_io_configuration 中的触发条件 + # :return: None + # """ + # input_system_io, output_system_io = {}, {} + # for i_func in i_funcs: + # _index = i_funcs.index(i_func) + # input_system_io[i_func] = {"signal": i_signals[_index], "trigger": trig_types[_index]} + # for o_func in o_funcs: + # _index = o_funcs.index(o_func) + # output_system_io[o_func] = {"signal": o_signals[_index]} + # self.execution("system_io.update_configuration", input_system_io=input_system_io, output_system_io=output_system_io) + # + # @property + # def get_fieldbus_device_params(self): # OK + # """ + # 获取的是 HMI通讯->总线设备列表的信息,以及开关状态 + # :return: + # { + # "device_list": [ + # { + # "device_name": "modbus_1", + # "enable": true + # }, { + # "device_name": "modbus_2", + # "enable": false + # } + # ] + # } + # """ + # return self.__get_data(currentframe().f_code.co_name, "fieldbus_device.get_params") + # + # def set_fieldbus_device_params(self, device_name: str, enable: bool): # OK + # """ + # 定义开关设备的协议,一次只能打开一个设备 + # :param device_name: 设备列表中的名称 + # :param enable: 是否开启,这里操作的是 HMI通信->IO设备里面的开关状态 + # :return: None + # """ + # self.execution("fieldbus_device.set_params", device_name=device_name, enable=enable) + # + # def reload_fieldbus(self): # OK + # """ + # 触发控制器重新加载总线设备 + # :return: None + # """ + # self.execution("fieldbus_device.load_cfg") + # + # @property + # def get_modbus_params(self): # OK + # """ + # 获取modbus参数 + # :return: + # { + # "connect_state": true, + # "enable_master": false, + # "enable_slave": false, + # "ip": "192.168.0.160", + # "is_convert": true, + # "port": 502, + # "slave_id": 1 + # } + # """ + # return self.__get_data(currentframe().f_code.co_name, "modbus.get_params") + # + # def set_modbus_params(self, enable_slave: bool, ip: str, port: int, slave_id: int, enable_master: bool): # OK + # """ + # 设置modbus参数,相当于新建 + # :param enable_slave: Modbus从站是否自动开启 + # :param ip: ip 地址 + # :param port: 端口 + # :param slave_id: 从站 ID + # :param enable_master: Modbus主站是否自动开启 + # :return: + # """ + # self.execution("modbus.set_params", enable_slave=enable_slave, ip=ip, port=port, slave_id=slave_id, enable_master=enable_master) + # + # def reload_registers(self): # OK + # """ + # 触发控制器重新加载寄存器列表 + # :return: None + # """ + # self.execution("modbus.load_cfg") + # + # def get_modbus_values(self, mode: str = "all"): # OK + # """ + # 用于获取 modbus 寄存器变量值的更新信息,展示在状态监控界面 + # :param mode: all/change + # :return: + # """ + # return self.__get_data(currentframe().f_code.co_name, "modbus.get_values", mode=mode) + # + # @property + # def get_soft_limit_params(self): # OK + # """ + # 获取软限位参数 + # :return: + # { + # "enable":true + # "upper":[0,0,0,0,0,0,0], + # "lower":[0,0,0,0,0,0,0], + # "reduced_upper":[0,0,0,0,0,0,0], + # "reduced_lower":[0,0,0,0,0,0,0] + # } + # """ + # return self.__get_data(currentframe().f_code.co_name, "soft_limit.get_params") + # + # def set_soft_limit_params(self, **kwargs): # OK + # """ + # 设定软限位参数 enable: bool, upper: list, lower: list, reduced_upper: list, reduced_lower: list + # :enable: 是否启用软限位 + # :upper: 软限位上限 + # :lower: 软限位下限 + # :reduced_upper: 缩减模式软限位上限 + # :reduced_lower: 缩减模式软限位下限 + # :return: None + # """ + # data = self.get_soft_limit_params + # keys = data.keys() + # for _ in keys: + # if _ in kwargs.keys(): + # data[_] = kwargs[_] + # self.execution("soft_limit.set_params", data=data) + # + # @property + # def get_device_params(self): # OK + # """ + # 获取设备信息 + # :return: + # """ + # return self.__get_data(currentframe().f_code.co_name, "device.get_params") + # + # @property + # def get_cart_pos(self): # OK + # """ + # 获取机器人的当前位姿:包括轴关节角度,笛卡尔关节角度,四元数,欧拉角(臂角) + # :return: + # { + # "joint":[0.0,0.0,0.0,0.0,0.0,0.0], + # "position":[0.0,0.0,0.0,0.0,0.0,0.0], + # "euler":[0.0,0.0,0.0], + # "quaternion"[0.0,0.0,0.0,0.0], + # "elb":0.0, // 可缺省 + # "ext_joint":[0.0,0.0,0.0,0.0,0.0] + # } + # """ + # return self.__get_data(currentframe().f_code.co_name, "move.get_pos") + # + # @property + # def get_joint_pos(self): # OK + # """ + # 获取机器人的当前关节角度:包括内部轴和外部轴 + # :return: + # { + # "inner_pos": [0,0,0,0,0,0,0], + # "extern_pos": [0,0,0,0,0,0,0] + # } + # """ + # return self.__get_data(currentframe().f_code.co_name, "move.get_joint_pos") + # + # @property + # def get_monitor_cfg(self): # OK + # """ + # 获取机器人的监控配置参数,RefCoordinateType 类型数据,表示当前控制器位置监测的相对坐标系 + # 基坐标系 REF_COORDINATE_BASE 0 + # 世界坐标系 REF_COORDINATE_WORLD 1 + # 工件坐标系 REF_COORDINATE_WOBJ 2 + # :return: + # { + # "ref_coordinate": 0 + # } + # """ + # return self.__get_data(currentframe().f_code.co_name, "move.get_monitor_cfg") + # + # def set_monitor_cfg(self, ref_coordinate): # OK + # """ + # 设置机器人的监控配置参数 + # :ref_coordinate: RefCoordinateType类型数据,用来设置当前控制器位置监测的相对坐标系 + # :return: None + # """ + # self.execution("move.set_monitor_cfg", ref_coordinate=ref_coordinate) + # + # @property + # def get_move_params(self): # OK + # """ + # 获取机器人的运动参数:包括减速比、耦合比、最大速度、加速度、加加速度、acc ramp time、规划步长等信息 + # :return: + # { + # "MOTION": { + # "ACC_RAMPTIME_JOG": 0.5, + # "ACC_RAMPTIME_STOP": 0.5, + # "DEFAULT_ACC_PARAMS": [1.0, 0.5], + # "JERK_LIMIT_CART": 0, + # "JERK_LIMIT_JOINT": 0, + # "JERK_LIMIT_ROT": 0, + # "JOINT_MAX_ACC": [500, 500, 1000, 1000, 1000], + # "JOINT_MAX_JERK": [2000, 2000, 2000, 4000, 4000, 4000], + # "JOINT_MAX_SPEED": [120.0, 120.0, 180.0, 180.0, 180.0, 180.0], + # "MAX_ACC_PARAMS": [1.0, 1], + # "MIN_ACC_PARAMS": [0.3, 0.05], + # "TCP_MAX_ACC": 5000, + # "TCP_MAX_JERK": 10000, + # "TCP_MAX_SPEED": 1000, + # "TCP_ROTATE_MAX_ACC": 1800, + # "TCP_ROTATE_MAX_JERK": 3600, + # "TCP_ROTATE_MAX_SPEED": 180, + # "VEL_SMOOTH_FACTOR": 1.0, + # "VEL_SMOOTH_FACTOR_RANGE": [1.0, 10.0] + # } + # } + # """ + # return self.__get_data(currentframe().f_code.co_name, "move.get_params") + # + # def set_move_params(self, **kwargs): # OK + # """ + # 设置机器人的运动参数:轴最大速度、轴最大加加速度、速度、加加速度、加速度、加加速度、acc ramp time、规划步长等信息 + # 可选参数:参考 get_move_params 函数返回值 MOTION 里面的选项 + # :return: None + # """ + # data = self.get_move_params["MOTION"] + # print(f"res = {data}") + # keys = data.keys() + # for _ in keys: + # if _ in kwargs.keys(): + # data[_] = kwargs[_] + # self.execution("move.set_params", data=data) + # + # @property + # def get_quick_stop_distance(self): # OK + # """ + # 获取机器人 search 指令最大停止距离 + # :return: + # { + # "distance":2.0 + # } + # """ + # return self.__get_data(currentframe().f_code.co_name, "move.get_quickstop_distance") + # + # def set_quick_stop_distance(self, distance: float): # OK + # """ + # 设置机器人 search 指令最大停止距离 + # :param distance: 停止距离,单位 mm + # :return: None + # """ + # self.execution("move.set_quickstop_distance", distance=distance) + # + # @property + # def get_collision_params(self): # OK + # """ + # 获取碰撞检测相关参数 + # :return: + # { + # "action": 1, // 触发行为:1-安全停止;2-触发暂停;3-柔顺停止 + # "coeff": [100, 100, 100, 100, 100, 100], // 0-整机灵敏度百分比,1-单轴灵敏度百分比,2-单轴和整机灵敏度百分比 + # "coeff_level": 0, // 灵敏度等级:0-低,1-中,2-高 + # "compliance": 0, // 柔顺功能比例系数,[0-1] + # "enable": true, // 功能使能开关 + # "fallback_distance": 3, // 回退距离 + # "mode": 0, // 力传感器系数,0 整机 1 单轴 + # "percent": 100, // 0-200,整机灵敏度百分比 + # "percent_axis": [100, 100, 100, 100, 100, 100], // 0-200,单轴灵敏度百分比 + # "reduced_percent": 100, // 0-200,整机缩减模式灵敏度百分比 + # "reduced_percent_axis": [100, 100, 100, 100, 100, 100] // 0-200,单轴缩减模式灵敏度百分比 + # } + # """ + # return self.__get_data(currentframe().f_code.co_name, "collision.get_params") + # + # def set_collision_params(self, enable, mode, action, percent, **kwargs): # OK + # """ + # 设置碰撞检测相关参数 + # :param enable: 功能使能开关 + # :param mode: 力传感器系数,0 整机 1 单轴 + # :param action: 触发行为:1-安全停止;2-触发暂停;3-柔顺停止 + # :param percent: 0-200,整机灵敏度百分比 + # :return: + # """ + # data = self.get_collision_params + # keys = data.keys() + # kwargs.update({"enable": enable, "mode": mode, "action": action, "percent": percent}) + # for _ in keys: + # if _ in kwargs.keys(): + # data[_] = kwargs[_] + # self.execution("collision.set_params", data=data) + # + # def set_collision_state(self, collision_state: bool): # NG + # """ + # 开启或者关闭虚拟墙碰撞检测,测试该函数功能无效!!! + # :param collision_state: 碰撞检测的开关状态 + # :return: None + # """ + # self.execution("collision.set_state", collision_state=collision_state) + # + # @property + # def get_robot_state(self): # OK + # """ + # { + # "rc_state":"normal", # "fatal" 、"error"、"block"、"normal" + # "engine":"on", # "fatal" 、"error"、"GStop"、"EStop"、"on"、"off" + # "servo_mode":"position", # "torque"、"position" + # "operate": "auto", # "auto"、"manual" + # "task_space": "program", # "jog"、"drag"、"ready"、"load_identify"、"demo"、"rci"、"dynamic_identify"、"program"、"debug" + # "robot_action": "idle", # "idle"、"busy" + # "safety_mode": "collision" # "normal"、"collision"、"collaboration" + # } + # """ + # return self.__get_data(currentframe().f_code.co_name, "state.get_state") + # + # def set_controller_params(self, robot_time: str): # OK + # """ + # 设置控制器系统时间 + # :param robot_time: 系统时间,"2020-02-28 15:28:30" + # :return: None + # """ + # self.execution("controller.set_params", time=robot_time) + # + # @property + # def get_robot_params(self): # OK + # """ + # "alias": "", + # "auth_state": + # "controller_type": "XBC_XMATE", + # "controller_types": ["XBC_3", "XBC_5", "XBC_XMATE"], + # "disk_serial_number": "2338020401535", + # "mac_addr": "34:df:20:03:1b:45", + # "model":, + # "nic_list": ["enp1s0", "enp2s0"], + # "occupied_addr": "192.168.2.123:49269", + # "period": 0.002, + # "period_types": [0.001, 0.002, 0.003, 0.004], + # "robot_template": 10, + # "robot_type": "XMC12-R1300-W7G3B1C", + # "robot_types": ["XMC12-R1300-B7S3B0C", "XMC12-R1300-W7G3B1C", "XMC17_5-R1900-W7G3B1C", "XMC20-R1650-B7G3Z0C"], + # "security_type": "ROKAE_RSC", + # "security_types": ["ROKAE_MINI", "ROKAE_RSC"], + # "time": "2024-09-13 12:36:38", + # "version": "2.3.0.4" + # """ + # return self.__get_data(currentframe().f_code.co_name, "controller.get_params") + # + # def switch_tp_mode(self, mode: str): # OK + # """ + # 切换示教器模式 + # :param mode: with/without + # :return: None + # """ + # match mode: + # case "with": + # self.execution("state.set_tp_mode", tp_mode="with") + # case "without": + # self.execution("state.set_tp_mode", tp_mode="without") + # case _: + # clibs.insert_logdb("ERROR", "openapi", "hr: switch_tp_mode 参数错误 非法参数,只接受 with/without") + # + # @property + # def get_tp_mode(self): # OK + # """ + # 获取示教器连接状态 + # :return: + # { + # "tp_mode":"with" + # } + # """ + # return self.__get_data(currentframe().f_code.co_name, "state.get_tp_mode") + # + # @property + # def get_drag_params(self): # OK + # """ + # 获取拖动模式参数 + # :return: + # { + # "enable": true, + # "space": 0, + # "type": 0 + # } + # """ + # return self.__get_data(currentframe().f_code.co_name, "drag.get_params") + # + # def set_drag_params(self, enable: bool, space: int = 1, type: int = 2): # OK + # """ + # 设置拖动模式开关以及参数 + # :param enable: 是否启用拖动 + # :param space: 拖动空间 - 0 代表关节 1 代表笛卡尔 + # :param type: 拖动类型 - 0 只平移 1 只旋转 2 自由拖动 + # :return: None + # """ + # self.execution("drag.set_params", enable=enable, space=space, type=type) + # + # def set_safety_area_signal(self, signal: bool): # OK + # """ + # 设置安全区域信号控制使能开关 + # :param signal: True 打开 False 关闭 + # :return: None + # """ + # self.execution("safety.safety_area.signal_enable", protocol_flag=1, signal=signal) + # + # def set_safety_area_overall(self, enable: bool): # OK + # """ + # 设置安全区域整体控制使能开关 + # :param enable: True 打开 False 关闭 + # :return: None + # """ + # self.execution("safety.safety_area.overall_enable", protocol_flag=1, enable=enable) + # + # @property + # def get_safety_area_params(self): # OK + # """ + # 获取安全区所有的配置信息 + # :return: + # "g": { + # "safety_area_data": { + # "overall_enable": true, + # "safety_area_setting": [ + # { + # "box": { + # "Lx": 100.0, + # "Ly": 100.0, + # "Lz": 100.0, + # "direction": false, + # "ori": { + # "euler": { + # "a": 179.9963851353547, + # "b": -0.006653792532429416, + # "c": 179.9934560302729 + # }, + # "quaternion": { + # "q1": 0.0, + # "q2": 0.0, + # "q3": 0.0, + # "q4": 0.0 + # } + # }, + # "pos": { + # "x": 0.0, + # "y": 0.0, + # "z": 0.0 + # } + # }, + # "enable": false, + # "id": 0, + # "name": "region1", + # "plane": { + # "direction": true, + # "point": { + # "x": 0.0, + # "y": 0.0, + # "z": 0.0 + # }, + # "vector": { + # "x": 0.0, + # "y": 0.0, + # "z": 0.0 + # } + # }, + # "shape": 0, + # "shared_bind_di": "", + # "shared_bind_do": "", + # "sphere": { + # "ori": { + # "euler": { + # "a": 0.0, + # "b": 0.0, + # "c": 0.0 + # }, + # "quaternion": { + # "q1": 0.0, + # "q2": 0.0, + # "q3": 0.0, + # "q4": 0.0 + # } + # }, + # "pos": { + # "x": 0.0, + # "y": 0.0, + # "z": 0.0 + # }, + # "radius": 0.0 + # }, + # "state": true, + # "trigger": 0, + # "type": 0, + # "vertebral": { + # "high": 0.0, + # "ori": { + # "euler": { + # "a": 0.0, + # "b": 0.0, + # "c": 0.0 + # }, + # "quaternion": { + # "q1": 0.0, + # "q2": 0.0, + # "q3": 0.0, + # "q4": 0.0 + # } + # }, + # "pos": { + # "x": 0.0, + # "y": 0.0, + # "z": 0.0 + # }, + # "radius": 0.0 + # } + # }, + # ... // 剩余 9 个安全区域的配置信息 + # ], + # "signal_enable": true + # } + # } + # } + # """ + # return self.__get_data(currentframe().f_code.co_name, "safety_area_data", flag=1) + # + # def set_safety_area_enable(self, id: int, enable: bool): # OK + # """ + # 设置每个安全区域的开关 + # :param id: 安全区域开关,0-9 + # :param enable: True 打开,False 关闭 + # :return: None + # """ + # self.execution("safety.safety_area.safety_area_enable", protocol_flag=1, id=id, enable=enable) + # + # def set_safety_area_param(self, id: int, enable: bool, **kwargs): # OK + # """ + # 设定单独安全区的参数 + # :param id: 安全区 id + # :param enable: 是否开启 + # :param kwargs: 其他参数,参考 get_safety_area_params 的返回值形式 + # :return: None + # """ + # data = self.get_safety_area_params["g"]["safety_area_data"]["safety_area_setting"][id] + # keys = data.keys() + # kwargs.update({"id": id, "enable": enable}) + # for _ in keys: + # if _ in kwargs.keys(): + # data[_] = kwargs[_] + # self.execution("safety.safety_area.set_param", protocol_flag=1, data=data) + # self.execution("safety.safety_area.safety_area_enable", protocol_flag=1, id=id, enable=enable) + # + # @property + # def get_filtered_error_code(self): # OK + # """ + # 获取已设定的错误码过滤列表 + # :return: + # { + # "g": { + # "log_code.data": { + # "code_list": [ + # { + # "id": 100, + # "title": "DEMO\\u610f\\u5916\\u505c\\u6b62" + # }, + # { + # "id": 10000, + # "title": "HMI\\u8bf7\\u6c42\\u5305\\u89e3\\u6790\\u9519\\u8bef" + # }, + # { + # "id": 10002, + # "title": "\\u5feb\\u901f\\u8c03\\u6574\\u542f\\u52a8\\u5931\\u8d25" + # } + # ], + # "version": 1 + # } + # } + # } + # """ + # return self.__get_data(currentframe().f_code.co_name, "log_code.data", flag=1) + # + # def set_filtered_error_code(self, action: str, code_list: list): # OK + # """ + # 清空,增加,删除错误过滤码 + # :param action: 支持 add/remove/clear,当为 clear 时,code_list 可为任意列表 + # :param code_list: 需要添加/删除的过滤码列表 + # :return: None + # """ + # origin_code_list = self.get_filtered_error_code["g"]["log_code.data"]["code_list"] + # # [{"id": 10000, "title": "HMI请求包解析错误"}, {"id": 10002, "title": "快速调整启动失败"}] + # if action == "clear": + # code_list = [] + # elif action == "add": + # for error_code in code_list: + # for item in origin_code_list: + # if error_code == item["id"]: + # break + # else: + # origin_code_list.append({"id": error_code, "title": ""}) + # code_list = origin_code_list + # elif action == "remove": + # for error_code in code_list: + # for item in origin_code_list: + # if error_code == item["id"]: + # origin_code_list.remove(item) + # code_list = origin_code_list + # + # self.execution("log_code.data.code_list", protocol_flag=1, code_list=code_list) + # + # @staticmethod + # def __cannot_find_response(func_name, req_id): + # # 无法获取响应信息时,记录错误信息,并退出 + # clibs.insert_logdb("ERROR", "openapi", f"hr: [{func_name}] 无法找到 {req_id} 的响应信息,执行失败,退出...") + # exit() + # + # def __get_data(self, upper_func, command, flag=0, **kwargs): + # r_id = self.execution(command, protocol_flag=flag, **kwargs) + # res = self.get_from_id(r_id, flag=flag) + # if res is not None: + # return res + # else: + # self.__cannot_find_response(upper_func, r_id) + # =================================== ↑↑↑ specific functions ↑↑↑ =================================== + + +class ExternalCommunication(object): + def __init__(self): + self.__c = None + self.suffix = "\r" + self.socket_client() + self.exec_desc = " :--: 返回 true 表示执行成功,false 失败" + + def socket_client(self): + self.__c = socket(AF_INET, SOCK_STREAM) + try: + self.__c.connect((clibs.ip_addr, clibs.external_port)) + clibs.insert_logdb("INFO", "openapi", f"ec: 外部通信连接成功...") + return self.__c + except Exception as Err: + clibs.insert_logdb("ERROR", "openapi", f"ec: 外部通信连接失败... {Err}") + + def s_string(self, directive): + order = "".join([directive, self.suffix]) + self.__c.send(order.encode()) + time.sleep(clibs.interval) + + def r_string(self, directive): + result, char = "", "" + while char != self.suffix: + try: + char = self.__c.recv(1).decode(encoding="unicode_escape") + except TimeoutError: + clibs.insert_logdb("ERROR", "openapi", f"ec: 获取请求指令 {directive} 的返回数据超时,需确认指令发送格式以及内容正确!") + exit(101) + result = "".join([result, char]) + time.sleep(clibs.interval) + return result + + # =================================== ↓↓↓ specific functions ↓↓↓ =================================== + def motor_on(self): # OK + return self.__exec_cmd("motor_on", "电机上电", self.exec_desc) + + def motor_off(self): # OK + return self.__exec_cmd("motor_off", "电机下电", self.exec_desc) + + def pp_to_main(self): # OK + return self.__exec_cmd("pp_to_main", "程序指针到", self.exec_desc) + + def program_start(self): # OK + return self.__exec_cmd("start", "程序启动(可能需先清告警)", self.exec_desc) + + def program_stop(self): # OK + return self.__exec_cmd("stop", "程序停止", self.exec_desc) + + def clear_alarm(self): # OK + return self.__exec_cmd("clear_alarm", "清除伺服报警", self.exec_desc) + + def switch_operation_auto(self): # OK + return self.__exec_cmd("switch_mode:auto", "切换到自动模式", self.exec_desc) + + def switch_operation_manual(self): # OK + return self.__exec_cmd("switch_mode:manual", "切换到手动模式", self.exec_desc) + + def open_drag_mode(self): # OK + return self.__exec_cmd("open_drag", "打开拖动", self.exec_desc) + + def close_drag_mode(self): # OK + return self.__exec_cmd("close_drag", "关闭拖动", self.exec_desc) + + def get_program_list(self): # OK + return self.__exec_cmd("list_prog", "获取工程列表") + + def get_current_program(self): # OK + return self.__exec_cmd("current_prog", "当前工程") + + def load_program(self, program_name): # OK + return self.__exec_cmd(f"load_prog:{program_name}", "加载工程", self.exec_desc) + + def estop_reset(self): # OK | 复原外部 IO 急停和安全门急停,前提是硬件已复原 + return self.__exec_cmd("estop_reset", "急停复位", self.exec_desc) + + def estopreset_and_clearalarm(self): # OK | 外部 IO/安全门急停/安全碰撞告警都可以清除,前提是硬件已复原 + return self.__exec_cmd("estopreset_and_clearalarm", "急停复位并清除报警", self.exec_desc) + + def motoron_pp2main_start(self): # OK + return self.__exec_cmd("motoron_pptomain_start", "依次执行上电,程序指针到main,启动程序(可以是手动模式,必要时需清告警)", self.exec_desc) + + def motoron_start(self): # OK + return self.__exec_cmd("motoron_start", "依次执行上电,启动程序(可以是手动模式,必要时需清告警)", self.exec_desc) + + def pause_motoroff(self): # OK + return self.__exec_cmd("pause_motoroff", "暂停程序并下电", self.exec_desc) + + def set_program_speed(self, speed: int): # OK | 1-100 + return self.__exec_cmd(f"set_program_speed:{speed}", "设置程序运行速率(滑块)", self.exec_desc) + + def set_soft_estop(self, enable: str): # OK + return self.__exec_cmd(f"set_soft_estop:{enable}", "触发(true)/解除(false)机器人软急停", self.exec_desc) + + def switch_auto_motoron(self): # OK + return self.__exec_cmd("switch_auto_motoron", "切换自动模式并上电", self.exec_desc) + + def open_safe_region(self, number: int): # OK | 1-10 + return self.__exec_cmd(f"open_safe_region:{number}", f"打开第 {number} 个安全区域(1-10,信号控制开关需打开,不限操作模式)", self.exec_desc) + + def close_safe_region(self, number: int): # OK | 1-10 + return self.__exec_cmd(f"close_safe_region:{number}", f"关闭第 {number} 个安全区域(1-10,信号控制开关需打开,不限操作模式)", self.exec_desc) + + def open_reduced_mode(self): # OK + return self.__exec_cmd("open_reduced_mode", "开启缩减模式(不限操作模式)", self.exec_desc) + + def close_reduced_mode(self): # OK + return self.__exec_cmd("close_reduced_mode", "关闭缩减模式(不限操作模式)", self.exec_desc) + + def setdo_value(self, do_name: str, do_value: str): # OK | do_value 为 true/false + return self.__exec_cmd(f"setdo:{do_name},{do_value}", f"设置 {do_name} 的值为 {do_value} ", self.exec_desc) + + def modify_system_time(self, robot_time): # OK + return self.__exec_cmd(f"set_robot_time:{robot_time}", f"修改控制器和示教器的时间为 {robot_time} 的", self.exec_desc) + + # -------------------------------------------------------------------------------------------------- + @property + def motor_on_state(self): # OK + return self.__exec_cmd("motor_on_state", "获取上电状态", " :--: 返回 true 表示已上电,false 已下电") + + @property + def robot_running_state(self): # OK + return self.__exec_cmd("robot_running_state", "获取程序运行状态", " :--: 返回 true 表示正在运行,false 未运行") + + @property + def estop_state(self): # OK | 只表示外部急停,安全门触发不会返回 true,只要有急停标识 E 字母,就会返回 true + return self.__exec_cmd("estop_state", "急停状态", " :--: 返回 true 表示处于急停状态,false 非急停") + + @property + def operation_mode(self): # OK + return self.__exec_cmd("operating_mode", "获取工作模式", " :--: 返回 true 表示自动模式,false 手动模式") + + @property + def home_state(self): # OK | 需要设置一下 "HMI 设置->快速调整" + return self.__exec_cmd("home_state", "获取 HOME 输出状态", " :--: 返回 true 表示法兰中心处于 HOME 点,false 未处于 HOME 点") + + @property + def fault_state(self): # OK + return self.__exec_cmd("fault_state", "获取 故障状态", " :--: 返回 true 表示处于故障状态,false 非故障状态") + + @property + def collision_state(self): # OK | 但是触发后,无法清除? + return self.__exec_cmd("collision_state", "获取碰撞触发状态", " :--: 返回 true 表示碰撞已触发,false 未触发") + + @property + def task_state(self): # OK + return self.__exec_cmd("task_state", "获取机器人运行任务状态", " :--: 返回 program 表示任务正在运行,ready 未运行") + + @property + def get_cart_pos(self): # OK | cart_pos/cart_pos_name 都可以正常返回,区别在返回的前缀,可测试辨别 + return self.__exec_cmd("cart_pos", "获取笛卡尔位置") + + @property + def get_joint_pos(self): # OK | jnt_pos/jnt_pos_name 都可以正常返回,区别在返回的前缀,可测试辨别 + return self.__exec_cmd("jnt_pos", "获取轴位置") + + @property + def get_axis_vel(self): # OK | jnt_vel/jnt_vel_name 都可以正常返回,区别在返回的前缀,可测试辨别 + return self.__exec_cmd("jnt_vel", "获取轴速度") + + @property + def get_axis_trq(self): # OK | jnt_trq/jnt_trq_name 都可以正常返回,区别在返回的前缀,可测试辨别 + return self.__exec_cmd("jnt_trq", "获取轴力矩") + + @property + def reduced_mode_state(self): # OK + return self.__exec_cmd("reduced_mode_state", "获取缩减模式状态", " :--: 返回 true 表示缩减模式,false 非缩减模式") + + def get_io_state(self, io_list: str): # OK | DO0_0,DI1_3,DO2_5,不能有空格 + return self.__exec_cmd(f"io_state:{io_list}", "获取 IO 状态值") + + @property + def alarm_state(self): # OK + return self.__exec_cmd("alarm_state", "获取报警状态", " :--: 返回 true 表示当前有告警,false 没有告警") + + @property + def collision_alarm_state(self): # OK + return self.__exec_cmd("collision_alarm_state", "获取碰撞报警状态", " :--: 返回 true 表示有碰撞告警,false 没有碰撞告警") + + @property + def collision_open_state(self): # OK + return self.__exec_cmd("collision_open_state", "获取碰撞检测开启状态", " :--: 返回 true 表示已开启碰撞检测,false 未开启") + + @property + def controller_is_running(self): # OK + return self.__exec_cmd("controller_is_running", "判断控制器是否开机", " :--: 返回 true 表示控制器正在运行,false 未运行") + + @property + def encoder_low_battery_state(self): # OK + return self.__exec_cmd("encoder_low_battery_state", "编码器低电压报警状态", " :--: 返回 true 表示编码器处于低电压状态,false 电压正常") + + @property + def robot_error_code(self): # OK + return self.__exec_cmd("robot_error_code", "获取机器人错误码") + + @property + def rl_pause_state(self): # OK + # 0 -- 初始化状态,刚开机上电时 + # 1 -- RL 运行中 + # 2 -- HMI 暂停 + # 3 -- 系统 IO 暂停 + # 4 -- 寄存器功能码暂停 + # 5 -- 外部通讯暂停 + # 6 -- + # 7 -- Pause 指令暂停 + # 8 -- + # 9 -- + # 10 -- 外部 IO 急停 + # 11 -- 安全门急停 + # 12 -- 其他因素停止,比如碰撞检测 + return self.__exec_cmd("program_full", "获取 RL 的暂停状态", " :--: 返回值含义详见功能定义") + + @property + def program_reset_state(self): # OK + return self.__exec_cmd("program_reset_state", "获取程序复位状态", " :--: 返回 true 表示指针指向 main,false 未指向 main") + + @property + def program_speed_value(self): # OK | 速度滑块 + return self.__exec_cmd("program_speed", "获取程序运行速度") + + @property + def robot_is_busy(self): # OK | 触发条件为 pp2main/重载工程/推送到控制器,最好测试工程大一些,比较容易触发 + return self.__exec_cmd("robot_is_busy", "获取程序忙碌状态", " :--: 返回 1 表示控制器忙碌,0 非忙碌状态") + + @property + def robot_is_moving(self): # OK + return self.__exec_cmd("robot_is_moving", "获取程序运行状态", " :--: 返回 true 表示机器人正在运动,false 未运动") + + @property + def safe_door_state(self): # OK + return self.__exec_cmd("safe_door_state", "获取安全门状态", " :--: 返回 true 表示安全门已触发,false 未触发") + + @property + def soft_estop_state(self): # OK + return self.__exec_cmd("soft_estop_state", "获取软急停状态", " :--: 返回 true 表示软急停已触发,false 未触发") + + @property + def get_cart_vel(self): # OK + return self.__exec_cmd("cart_vel", "获取笛卡尔速度") + + @property + def get_tcp_pos(self): # OK + return self.__exec_cmd("tcp_pose", "获取 TCP 位姿") + + @property + def get_tcp_vel(self): # OK + return self.__exec_cmd("tcp_vel", "获取 TCP 速度") + + @property + def get_tcp_vel_mag(self): # OK + return self.__exec_cmd("tcp_vel_mag", "获取 TCP 合成线速度") + + @property + def ext_estop_state(self): # OK + return self.__exec_cmd("ext_estop_state", "获取外部轴急停状态", " :--: 返回 true 表示外部轴急停已触发,false 未触发") + + @property + def hand_estop_state(self): # OK + return self.__exec_cmd("hand_estop_state", "获取手持急停状态", " :--: 返回 true 表示手持急停已触发,false 未触发") + + @property + def collaboration_state(self): # OK + return self.__exec_cmd("collaboration_state", "获取协作模式状态(其实就是缩减模式)", " :--: 返回 true 表示协作模式,false 非协作模式") + + def __exec_cmd(self, directive, description, more_desc=""): + self.s_string(directive) + result = self.r_string(directive).strip() + clibs.insert_logdb("INFO", "openapi", f"ec: 执行{description}指令是 {directive},返回值为 {result}{more_desc}") + return result + + +class PreDos(object): + def __init__(self): + self.__ssh = None + self.__sftp = None + + def __ssh2server(self): + try: + self.__ssh = SSHClient() + self.__ssh.set_missing_host_key_policy(AutoAddPolicy()) + self.__ssh.connect(clibs.ip_addr, clibs.ssh_port, username=clibs.username, password=clibs.password) + self.__sftp = self.__ssh.open_sftp() + except Exception as Err: + msg = f"predos: SSH 无法连接到 {clibs.ip_addr}:{clibs.ssh_port},需检查网络连通性或者登录信息是否正确 {Err}" + clibs.insert_logdb("ERROR", "openapi", msg) + clibs.w2t(msg, "red", f"SSHError: cannot connected to {clibs.ip_addr}:{clibs.ssh_port}") + + def push_prj_to_server(self, prj_file): + # prj_file:本地工程完整路径 + self.__ssh2server() + prj_name = prj_file.split("\\")[-1].split("/")[-1].split(".")[0] + self.__sftp.put(prj_file, f"/tmp/{prj_name}.zip") + cmd = f"cd /tmp; mkdir {prj_name}; unzip -d {prj_name} -q {prj_name}.zip; rm -rf /tmp/{prj_name}.zip; " + cmd += f"sudo rm -rf /home/luoshi/bin/controller/projects/{prj_name}; " + cmd += f"sudo mv /tmp/{prj_name}/ /home/luoshi/bin/controller/projects/" + stdin, stdout, stderr = self.__ssh.exec_command(cmd, get_pty=True) + stdin.write(clibs.password + "\n") + stdout.read().decode() # 需要read一下才能正常执行 + stderr.read().decode() + self.__ssh.close() + + def pull_prj_from_server(self, prj_name, local_prj_path): # NG | 可以拉取文件,但是导入之后,有问题 + # prj_name:要拉取的服务端工程名 + # local_prj_path:本地工程文件的完整路径 + self.__ssh2server() + cmd = f"cd /tmp/; sudo rm -rf {prj_name}*; sudo cp -rf /home/luoshi/bin/controller/projects/{prj_name} .; " + cmd += f"sudo zip -q -r {prj_name}.zip {prj_name}/; sudo rm -rf {prj_name}" + stdin, stdout, stderr = self.__ssh.exec_command(cmd, get_pty=True) + stdin.write(clibs.password + "\n") + print(stdout.read().decode()) # 需要read一下才能正常执行 + print(stderr.read().decode()) + + self.__sftp.get(f"/tmp/{prj_name}.zip", local_prj_path) + cmd = f"sudo rm -rf /tmp/{prj_name}.zip" + stdin, stdout, stderr = self.__ssh.exec_command(cmd, get_pty=True) + stdin.write(clibs.password + "\n") + print(stdout.read().decode()) # 需要read一下才能正常执行 + print(stderr.read().decode()) + + self.__ssh.close() + + def push_file_to_server(self, local_file, server_file): + # local_file:本地文件完整路径 + # server_file:服务端文件完整路径 + self.__ssh2server() + filename = local_file.split("\\")[-1].split("/")[-1] + self.__sftp.put(local_file, f"/tmp/{filename}") + cmd = f"sudo mv /tmp/{filename} {server_file}" + stdin, stdout, stderr = self.__ssh.exec_command(cmd, get_pty=True) + stdin.write(clibs.password + "\n") + stdout.read().decode() # 需要read一下才能正常执行 + stderr.read().decode() + self.__ssh.close() + + def pull_file_from_server(self, server_file, local_file): + # local_file:本地文件完整路径 + # server_file:服务端文件完整路径 + self.__ssh2server() + cmd = f"sudo cp {server_file} /tmp/" + stdin, stdout, stderr = self.__ssh.exec_command(cmd, get_pty=True) + stdin.write(clibs.password + "\n") + stdout.read().decode() # 需要read一下才能正常执行 + stderr.read().decode() + filename = server_file.split("/")[-1] + self.__sftp.get(f"/tmp/{filename}", f"{local_file}") + cmd = f"sudo rm -rf /tmp/{filename}" + stdin, stdout, stderr = self.__ssh.exec_command(cmd, get_pty=True) + stdin.write(clibs.password + "\n") + stdout.read().decode() # 需要read一下才能正常执行 + stderr.read().decode() + self.__ssh.close() + + +def robot_init(): + hr = HmiRequest() + pd = PreDos() + # 推送配置文件 + clibs.insert_logdb("INFO", "openapi", "init: 推送配置文件 fieldbus_device.json/registers.json/registers.xml 到控制器,并配置 IO 设备,设备号为 7...") + robot_params = hr.get_robot_params + robot_type = robot_params["robot_type"] + security_type = robot_params["security_type"] + controller_type = robot_params["controller_type"] + io_device_file = "_".join(["io_device", controller_type, security_type, "1"]) + + user_settings = "/home/luoshi/bin/controller/user_settings" + interactive_data = f"/home/luoshi/bin/controller/interactive_data/{robot_type}" + + config_files = [ + "..\\assets\\configs\\fieldbus_device.json", + "..\\assets\\configs\\registers.json", + "..\\assets\\configs\\registers.xml" + ] + for config_file in config_files: + filename = config_file.split("\\")[-1] + pd.push_file_to_server(config_file, f"{user_settings}/{filename}") + pd.push_file_to_server(config_file, f"{interactive_data}/{filename}") + + io_device_autotest = {"ai_num": 0, "ao_num": 0, "di_num": 16, "do_num": 16, "extend_attr": {"mode": "slaver", "name": "autotest", "type": "MODBUS"}, "id": 7, "name": "autotest", "type": 6} + io_device_file_local = f"..\\assets\\configs\\{io_device_file}" + io_device_file_local_tmp = f"..\\assets\\configs\\{io_device_file}_tmp" + io_device_file_remote = f"{user_settings}/{io_device_file}" + pd.pull_file_from_server(io_device_file_remote, io_device_file_local) + with open(io_device_file_local, mode="r", encoding="utf-8") as f: + data = json.load(f) + for _ in data["device_list"]: + if _["extend_attr"].get("name", None) == "autotest": + break + else: + data["device_list"].append(io_device_autotest) + with open(io_device_file_local_tmp, mode="w", encoding="utf-8") as f_tmp: + json.dump(data, f_tmp, indent=4) + pd.push_file_to_server(io_device_file_local_tmp, f"{user_settings}/{io_device_file}") + pd.push_file_to_server(io_device_file_local_tmp, f"{interactive_data}/{io_device_file}") + + hr.reload_io() + hr.reload_registers() + hr.reload_fieldbus() + hr.set_fieldbus_device_params("autotest", True) + + md = ModbusRequest() + # 触发急停并恢复 + md.r_soft_estop(0) + md.r_soft_estop(1) + + # 断开示教器连接 + clibs.insert_logdb("INFO", "openapi", "init: 断开示教器连接...") + hr.switch_tp_mode("without") + + # 清空 system IO 配置 + clibs.insert_logdb("INFO", "openapi", "init: 清空所有的 System IO 功能配置...") + hr.update_system_io_configuration([], [], [], [], []) + + # 关闭缩减模式 + md.r_reduced_mode(0) + + # 打开软限位 + clibs.insert_logdb("INFO", "openapi", "init: 打开软限位开关...") + hr.set_soft_limit_params(enable=True) + + # 关闭安全区域 + clibs.insert_logdb("INFO", "openapi", "init: 正在关闭所有的安全区,并关闭总使能开关...") + hr.set_safety_area_overall(False) + hr.set_safety_area_signal(False) + for i in range(10): + hr.set_safety_area_enable(i, False) + + # 打开外部通信,并设置控制器时间同步 + clibs.insert_logdb("INFO", "openapi", "init: 配置并打开外部通信,默认服务器,8080端口,后缀为 \"\\r\"...") + hr.set_socket_params(True, "8080", "\r", 1) + ec = ExternalCommunication() + ec.modify_system_time(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))) + + # 关闭拖动 + if robot_type.upper()[:2] not in ["XB", "NB"]: + clibs.insert_logdb("INFO", "openapi", "init: 关闭拖动模式...") + hr.set_drag_params(False, 1, 2) + + # 关闭碰撞检测 + clibs.insert_logdb("INFO", "openapi", "init: 关闭碰撞检测...") + hr.set_collision_params(False, 0, 1, 100) + + # 清除所有过滤错误码 + clibs.insert_logdb("INFO", "openapi", "init: 清除所有过滤错误码设定...") + hr.set_filtered_error_code("clear", []) + + # 回拖动位姿 + clibs.insert_logdb("INFO", "openapi", "init: 正在回拖动位姿...") + hr.switch_operation_mode("manual") + hr.switch_motor_state("on") + hr.set_quickturn_pos(enable_drag=True) + hr.move2quickturn("drag") + while True: + if md.w_robot_is_moving: + time.sleep(1) + else: + break + hr.stop_move(1) + hr.switch_motor_state("off") + hr.close() + + # 清除所有告警 + md.r_clear_alarm() + + +def fw_updater(local_file_path): + fw_size = os.path.getsize(local_file_path) + if fw_size > 10000000: + # get previous version of xCore + hr = HmiRequest() + version_previous = hr.get_robot_params["version"] + hr.close() + + # var def + remote_file_path = './upgrade/lircos.zip' + fw_content = bytearray() + package_data = bytearray() + package_data_with_head = bytearray() + + # socket connect + clibs.insert_logdb("INFO", "openapi", f"update firmware: 正在连接 {clibs.ip_addr}:{clibs.upgrade_port}...") + try: + tcp_socket = socket(AF_INET, SOCK_STREAM) + tcp_socket.connect((clibs.ip_addr, clibs.upgrade_port)) + tcp_socket.setblocking(True) + except Exception as Err: + clibs.insert_logdb("ERROR", "openapi", f"update firmware: {Err} | 连接 {clibs.ip_addr}:{clibs.upgrade_port} 失败...") + exit(1) + + # get firmware content of binary format + clibs.insert_logdb("INFO", "openapi", f"update firmware: 正在读取 {local_file_path} 文件内容...") + with open(local_file_path, 'rb') as f_fw: + fw_content += f_fw.read() + + # construct package data: http://confluence.i.rokae.com/pages/viewpage.action?pageId=15634148 + clibs.insert_logdb("INFO", "openapi", "update firmware: 正在构造数据包,以及包头...") + # 1 protocol id + protocol_id = c_ushort(htons(0)) # 2 bytes + package_data += protocol_id + + # 2 write type + write_type = c_ubyte(0) + package_data += bytes(write_type) + + # 3 md5 + md5_hash = hashlib.md5() + md5_hash.update(fw_content) + fw_md5 = md5_hash.hexdigest() + i = 0 + while i < len(fw_md5): + _ = (fw_md5[i:i + 2]) + package_data += bytes.fromhex(_) + i += 2 + + # 4 remote path len + remote_file_path_len = c_ushort(htons(len(remote_file_path))) + package_data += remote_file_path_len + + # 5 remote path + package_data += remote_file_path.encode("ascii") + + # 6 file + package_data += fw_content + + # construct communication protocol: http://confluence.i.rokae.com/pages/viewpage.action?pageId=15634045 + # 1 get package data with header + package_size = c_uint(htonl(len(package_data))) + package_type = c_ubyte(1) # 0-无协议 1-文件 2-json + package_reserve = c_ubyte(0) # 预留位 + + package_data_with_head += package_size + package_data_with_head += package_type + package_data_with_head += package_reserve + package_data_with_head += package_data + + # 2 send data to server + clibs.insert_logdb("INFO", "openapi", "update firmware: 正在发送数据到 xCore,升级控制器无需重启,升级配置文件会自动软重启...") + start = 0 + len_of_package = len(package_data_with_head) + while start < len_of_package: + end = 10240 + start + if end > len_of_package: + end = len_of_package + sent = tcp_socket.send((package_data_with_head[start:end])) + time.sleep(0.01) + if sent == 0: + raise RuntimeError("socket connection broken") + else: + start += sent + + waited = 5 if fw_size > 10000000 else 25 + time.sleep(waited) + + if fw_size > 10000000: + # get current version of xCore + hr = HmiRequest() + version_current = hr.get_robot_params["version"] + hr.close() + + clibs.insert_logdb("INFO", "openapi", f"update firmware: 控制器升级成功:from {version_previous} to {version_current} :)") + else: + clibs.insert_logdb("INFO", "openapi", f"update firmware: 配置文件升级成功 :)") + + tcp_socket.close() + + +class UpgradeJsonCmd(object): + def __init__(self): + self.__c = None + self.__sock_conn() + + def __sock_conn(self): + # socket connect + clibs.insert_logdb("INFO", "clibs", f"正在连接 {clibs.ip_addr}:{clibs.upgrade_port}...") + try: + self.__c = socket(AF_INET, SOCK_STREAM) + self.__c.connect((clibs.ip_addr, clibs.upgrade_port)) + self.__c.setblocking(True) + self.__c.settimeout(3) + except Exception as Err: + clibs.insert_logdb("ERROR", "openapi", f"upgrade: {Err} | 连接 {clibs.ip_addr}:{clibs.upgrade_port} 失败...") + exit(1) + + @staticmethod + def __do_package(cmd): + package_size = struct.pack('!I', len(cmd)) + package_type = struct.pack('B', 2) + reserved_byte = struct.pack('B', 0) + return package_size + package_type + reserved_byte + cmd + + def __recv_result(self, cmd): + time.sleep(2) + try: + res = self.__c.recv(10240).decode() + except timeout: + res = "ResponseNone" + clibs.insert_logdb("INFO", "openapi", f"upgrade: 请求命令 {cmd.decode()} 的返回信息:\n{res[8:]}") + self.__c.close() + time.sleep(2) + + def __exec(self, command: dict): + try: + self.__c.recv(10240) + except timeout: + pass + cmd = json.dumps(command, separators=(",", ":")).encode("utf-8") + self.__c.sendall(self.__do_package(cmd)) + self.__recv_result(cmd) + + def erase_cfg(self): + # 一键抹除机器人配置(.rc_cfg)、交互数据配置(interactive_data),但保留用户日志 + # 场景:如果xCore版本升级跨度过大,配置文件可能不兼容导致无法启动,可以使用该功能抹除配置,重新生成配置。 + # 机器人参数、零点等会丢失! + self.__exec({"cmd": "erase"}) + + def clear_rubbish(self): + self.__exec({"cmd": "clearRubbish"}) + + def soft_reboot(self): + self.__exec({"cmd": "soft_reboot"}) + + def version_query(self): + self.__exec({"query": "version"}) + + def robot_reboot(self): + self.__exec({"cmd": "reboot"}) + + def reset_passwd(self): + # 不生效,有问题 + self.__exec({"cmd": "passwd"}) + + def backup_origin(self): + # xCore + # .rc_cfg / + # interactive_data / + # module / + # demo_project / + # robot_cfg / + # dev_eni.xml + # ecat_license + # libemllI8254x.so & libemllI8254x_v3.so + # set_network_parameters + self.__exec({"cmd": "backup_origin"}) + + def origin_recovery(self): + self.__exec({"cmd": "recover"}) +